static void procRtsOpts()

in rts/RtsFlags.c [764:1602]


static void procRtsOpts (int rts_argc0,
                         RtsOptsEnabledEnum rtsOptsEnabled)
{
    bool error = false;
    int arg;
    int unchecked_arg_start;

    if (!(rts_argc0 < rts_argc)) return;

    if (rtsOptsEnabled == RtsOptsNone) {
        errorRtsOptsDisabled("RTS options are disabled. %s");
        stg_exit(EXIT_FAILURE);
    }

    checkSuid(rtsOptsEnabled);

    // Process RTS (rts_argv) part: mainly to determine statsfile
    for (arg = rts_argc0; arg < rts_argc; arg++) {

        /* We handle RtsOptsSafeOnly mode by declaring each option as
           either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
           every branch we use an option_checked flag which is reset
           at the start each iteration and checked at the end. */
        bool option_checked = false;

// See Note [OPTION_SAFE vs OPTION_UNSAFE].
#define OPTION_SAFE option_checked = true;
#define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = true;

        if (rts_argv[arg][0] != '-') {
            fflush(stdout);
            errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
            error = true;

        } else {
            /* 0 is dash, 1 is first letter */
            /* see Trac #9839 */
            unchecked_arg_start = 1;
            switch(rts_argv[arg][1]) {

              /* process: general args, then PROFILING-only ones, then
                 CONCURRENT-only, TICKY-only (same order as defined in
                 RtsFlags.lh); within those groups, mostly in
                 case-insensitive alphabetical order.  Final group is
                 x*, which allows for more options.
              */

#if defined(TICKY_TICKY)
# define TICKY_BUILD_ONLY(x) x
#else
# define TICKY_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -ticky", \
           rts_argv[arg]);                                             \
error = true;
#endif

#if defined(PROFILING)
# define PROFILING_BUILD_ONLY(x)   x
#else
# define PROFILING_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -prof", \
           rts_argv[arg]);                                            \
error = true;
#endif

#if defined(TRACING)
# define TRACING_BUILD_ONLY(x)   x
#else
# define TRACING_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -eventlog or -debug", \
           rts_argv[arg]);                                              \
error = true;
#endif

#if defined(THREADED_RTS)
# define THREADED_BUILD_ONLY(x)      x
#else
# define THREADED_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -threaded", \
           rts_argv[arg]);                                              \
error = true;
#endif

#if defined(DEBUG)
# define DEBUG_BUILD_ONLY(x) x
#else
# define DEBUG_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -debug", \
           rts_argv[arg]);                                             \
error = true;
#endif

              /* =========== GENERAL ========================== */
              case '?':
                OPTION_SAFE;
                error = true;
                break;

              /* This isn't going to allow us to keep related options
                 together as we add more --* flags. We really need a
                 proper options parser. */
              case '-':
                  if (strequal("install-signal-handlers=yes",
                               &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.install_signal_handlers = true;
                  }
                  else if (strequal("install-signal-handlers=no",
                               &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.install_signal_handlers = false;
                  }
                  else if (strequal("install-seh-handlers=yes",
                              &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.install_seh_handlers = true;
                  }
                  else if (strequal("install-seh-handlers=no",
                              &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.install_seh_handlers = false;
                  }
                  else if (strequal("generate-stack-traces=yes",
                               &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.generate_stack_trace = true;
                  }
                  else if (strequal("generate-stack-traces=no",
                              &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.generate_stack_trace = false;
                  }
                  else if (strequal("generate-crash-dumps",
                              &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.generate_dump_file = true;
                  }
                  else if (strequal("machine-readable",
                               &rts_argv[arg][2])) {
                      OPTION_UNSAFE;
                      RtsFlags.MiscFlags.machineReadable = true;
                  }
                  else if (strequal("internal-counters",
                                    &rts_argv[arg][2])) {
                      OPTION_SAFE;
                      RtsFlags.MiscFlags.internalCounters = true;
                  }
                  else if (strequal("info",
                               &rts_argv[arg][2])) {
                      OPTION_SAFE;
                      printRtsInfo(rtsConfig);
                      stg_exit(0);
                  }
#if defined(THREADED_RTS)
                  else if (!strncmp("numa", &rts_argv[arg][2], 4)) {
                      if (!osBuiltWithNumaSupport()) {
                          errorBelch("%s: This GHC build was compiled without NUMA support.",
                                     rts_argv[arg]);
                          error = true;
                          break;
                      }
                      OPTION_SAFE;
                      StgWord mask;
                      if (rts_argv[arg][6] == '=') {
                          mask = (StgWord)strtol(rts_argv[arg]+7,
                                                 (char **) NULL, 10);
                      } else {
                          mask = (StgWord)~0;
                      }
                      if (!osNumaAvailable()) {
                          errorBelch("%s: OS reports NUMA is not available",
                                     rts_argv[arg]);
                          error = true;
                          break;
                      }

                      RtsFlags.GcFlags.numa = true;
                      RtsFlags.GcFlags.numaMask = mask;
                  }
#endif
#if defined(DEBUG) && defined(THREADED_RTS)
                  else if (!strncmp("debug-numa", &rts_argv[arg][2], 10)) {
                      OPTION_SAFE;
                      size_t nNodes;
                      if (rts_argv[arg][12] == '=' &&
                          isdigit(rts_argv[arg][13])) {
                          nNodes = (StgWord)strtol(rts_argv[arg]+13,
                                                 (char **) NULL, 10);
                      } else {
                          errorBelch("%s: missing number of nodes",
                                     rts_argv[arg]);
                          error = true;
                          break;
                      }
                      if (nNodes > MAX_NUMA_NODES) {
                          errorBelch("%s: Too many NUMA nodes (max %d)",
                                     rts_argv[arg], MAX_NUMA_NODES);
                          error = true;
                      } else {
                          RtsFlags.GcFlags.numa = true;
                          RtsFlags.DebugFlags.numa = true;
                          RtsFlags.GcFlags.numaMask = (1<<nNodes) - 1;
                      }
                  }
#endif
                  else if (!strncmp("long-gc-sync=", &rts_argv[arg][2], 13)) {
                      OPTION_SAFE;
                      if (rts_argv[arg][2] == '\0') {
                          /* use default */
                      } else {
                          RtsFlags.GcFlags.longGCSync =
                              fsecondsToTime(atof(rts_argv[arg]+16));
                      }
                      break;
                  }
                  else {
                      OPTION_SAFE;
                      errorBelch("unknown RTS option: %s",rts_argv[arg]);
                      error = true;
                  }
                  break;
              case 'A':
                  OPTION_UNSAFE;
                  if (rts_argv[arg][2] == 'L') {
                      RtsFlags.GcFlags.largeAllocLim
                          = decodeSize(rts_argv[arg], 3, 2*BLOCK_SIZE,
                                       HS_INT_MAX) / BLOCK_SIZE;
                  } else {
                      // minimum two blocks in the nursery, so that we have one
                      // to grab for allocate().
                      RtsFlags.GcFlags.minAllocAreaSize
                          = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE,
                                       HS_INT_MAX) / BLOCK_SIZE;
                  }
                  break;
              case 'n':
                  OPTION_UNSAFE;
                  RtsFlags.GcFlags.nurseryChunkSize
                      = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE, HS_INT_MAX)
                           / BLOCK_SIZE;
                  break;

              case 'B':
                OPTION_UNSAFE;
                RtsFlags.GcFlags.ringBell = true;
                unchecked_arg_start++;
                goto check_rest;

              case 'c':
                  OPTION_UNSAFE;
                  if (rts_argv[arg][2] != '\0') {
                      RtsFlags.GcFlags.compactThreshold =
                          atof(rts_argv[arg]+2);
                  } else {
                      RtsFlags.GcFlags.compact = true;
                  }
                  break;

              case 'w':
                OPTION_UNSAFE;
                RtsFlags.GcFlags.sweep = true;
                unchecked_arg_start++;
                goto check_rest;

              case 'F':
                OPTION_UNSAFE;
                RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);

                if (RtsFlags.GcFlags.oldGenFactor < 0)
                  bad_option( rts_argv[arg] );
                break;

              case 'D':
              OPTION_SAFE;
              DEBUG_BUILD_ONLY(read_debug_flags(rts_argv[arg]);)
              break;

              case 'K':
                  OPTION_UNSAFE;
                  RtsFlags.GcFlags.maxStkSize =
                      decodeSize(rts_argv[arg], 2, 0, HS_WORD_MAX)
                      / sizeof(W_);
                  break;

              case 'k':
                OPTION_UNSAFE;
                switch(rts_argv[arg][2]) {
                case 'c':
                  RtsFlags.GcFlags.stkChunkSize =
                      decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
                      / sizeof(W_);
                  break;
                case 'b':
                  RtsFlags.GcFlags.stkChunkBufferSize =
                      decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
                      / sizeof(W_);
                  break;
                case 'i':
                  RtsFlags.GcFlags.initialStkSize =
                      decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
                      / sizeof(W_);
                  break;
                default:
                  RtsFlags.GcFlags.initialStkSize =
                      decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
                      / sizeof(W_);
                  break;
                }
                break;

              case 'M':
                  OPTION_UNSAFE;
                  if (0 == strncmp("grace=", rts_argv[arg] + 2, 6)) {
                      RtsFlags.GcFlags.heapLimitGrace =
                          decodeSize(rts_argv[arg], 8, BLOCK_SIZE, HS_WORD_MAX);
                  } else {
                      RtsFlags.GcFlags.maxHeapSize =
                          decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
                          / BLOCK_SIZE;
                      // user give size in *bytes* but "maxHeapSize" is in
                      // *blocks*
                  }
                  break;

              case 'm':
                /* Case for maxN feature request ticket #10728, it's a little
                   odd being so far from the N case. */
#if !defined(NOSMP)
                if (strncmp("maxN", &rts_argv[arg][1], 4) == 0) {
                  OPTION_SAFE;
                  THREADED_BUILD_ONLY(
                    int nCapabilities;
                    int proc = (int)getNumberOfProcessors();

                    nCapabilities = strtol(rts_argv[arg]+5, (char **) NULL, 10);
                    if (nCapabilities > proc) { nCapabilities = proc; }

                    if (nCapabilities <= 0) {
                      errorBelch("bad value for -maxN");
                      error = true;
                    }
#if defined(PROFILING)
                    RtsFlags.ParFlags.nCapabilities = 1;
#else
                    RtsFlags.ParFlags.nCapabilities = (uint32_t)nCapabilities;
#endif
                  ) break;
                } else {
#endif
                    OPTION_UNSAFE;
                    RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);

                    /* -m was allowing bad flags to go unreported */
                    if (RtsFlags.GcFlags.pcFreeHeap == 0.0 &&
                           rts_argv[arg][2] != '0')
                      bad_option( rts_argv[arg] );

                    if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
                        RtsFlags.GcFlags.pcFreeHeap > 100)
                        bad_option( rts_argv[arg] );
                    break;
#if !defined(NOSMP)
                }
#endif
              case 'G':
                  OPTION_UNSAFE;
                  RtsFlags.GcFlags.generations =
                      decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
                  break;

              case 'H':
                  OPTION_UNSAFE;
                  if (rts_argv[arg][2] == '\0') {
                      RtsFlags.GcFlags.heapSizeSuggestionAuto = true;
                  } else {
                      RtsFlags.GcFlags.heapSizeSuggestion = (uint32_t)
                          (decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
                          / BLOCK_SIZE);
                  }
                  break;

              case 'O':
                  OPTION_UNSAFE;
                  RtsFlags.GcFlags.minOldGenSize =
                      (uint32_t)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE,
                                       HS_WORD_MAX)
                            / BLOCK_SIZE);
                  break;

              case 'I': /* idle GC delay */
                OPTION_UNSAFE;
                if (rts_argv[arg][2] == '\0') {
                  /* use default */
                } else {
                    Time t = fsecondsToTime(atof(rts_argv[arg]+2));
                    if (t == 0) {
                        RtsFlags.GcFlags.doIdleGC = false;
                    } else {
                        RtsFlags.GcFlags.doIdleGC = true;
                        RtsFlags.GcFlags.idleGCDelayTime = t;
                    }
                }
                break;

              case 'T':
                  OPTION_SAFE;
                  RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
                  unchecked_arg_start++;
                  goto check_rest; /* Don't initialize statistics file. */

              case 'S':
                  OPTION_SAFE; /* but see below */
                  RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
                  goto stats;

              case 's':
                  OPTION_SAFE; /* but see below */
                  RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
                  goto stats;

              case 't':
                  OPTION_SAFE; /* but see below */
                  RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
                  goto stats;

            stats:
                {
                    int r;
                    if (rts_argv[arg][2] != '\0') {
                      OPTION_UNSAFE;
                    }
                    r = openStatsFile(rts_argv[arg]+2, NULL,
                                      &RtsFlags.GcFlags.statsFile);
                    if (r == -1) { error = true; }
                }
                break;

              case 'Z':
                OPTION_UNSAFE;
                RtsFlags.GcFlags.squeezeUpdFrames = false;
                unchecked_arg_start++;
                goto check_rest;

              /* =========== PROFILING ========================== */

              case 'P': /* detailed cost centre profiling (time/alloc) */
              case 'p': /* cost centre profiling (time/alloc) */
                OPTION_SAFE;
                PROFILING_BUILD_ONLY(
                switch (rts_argv[arg][2]) {
                  case 'a':
                    RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
                    if (rts_argv[arg][3] != '\0') {
                      errorBelch("flag -Pa given an argument"
                                 " when none was expected: %s"
                                ,rts_argv[arg]);
                      error = true;
                    }
                    break;
                  case 'j':
                      RtsFlags.CcFlags.doCostCentres = COST_CENTRES_JSON;
                      break;
                  case 'o':
                      if (rts_argv[arg][3] == '\0') {
                        errorBelch("flag -po expects an argument");
                        error = true;
                        break;
                      }
                      RtsFlags.CcFlags.outputFileNameStem = rts_argv[arg]+3;
                      break;
                  case '\0':
                      if (rts_argv[arg][1] == 'P') {
                          RtsFlags.CcFlags.doCostCentres = COST_CENTRES_VERBOSE;
                      } else {
                          RtsFlags.CcFlags.doCostCentres = COST_CENTRES_SUMMARY;
                      }
                      break;
                  default:
                    unchecked_arg_start++;
                    goto check_rest;
                }
                ) break;

              case 'R':
                  OPTION_SAFE;
                  PROFILING_BUILD_ONLY(
                      RtsFlags.ProfFlags.maxRetainerSetSize =
                        atof(rts_argv[arg]+2);
                  ) break;
              case 'L':
                  OPTION_SAFE;
                  PROFILING_BUILD_ONLY(
                      RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
                      if(RtsFlags.ProfFlags.ccsLength <= 0) {
                        bad_option(rts_argv[arg]);
                      }
                  ) break;
              case 'h': /* serial heap profile */
#if !defined(PROFILING)
                switch (rts_argv[arg][2]) {
                  case '\0':
                  case 'T':
                    OPTION_UNSAFE;
                    RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
                    break;
                  default:
                    OPTION_SAFE;
                    PROFILING_BUILD_ONLY();
                }
#else
                OPTION_SAFE;
                PROFILING_BUILD_ONLY(
                    error = read_heap_profiling_flag(rts_argv[arg]);
                );
#endif /* PROFILING */
                break;

              case 'i': /* heap sample interval */
                OPTION_UNSAFE;
                if (rts_argv[arg][2] == '\0') {
                  /* use default */
                } else {
                    RtsFlags.ProfFlags.heapProfileInterval =
                        fsecondsToTime(atof(rts_argv[arg]+2));
                }
                break;

              /* =========== CONCURRENT ========================= */
              case 'C': /* context switch interval */
                OPTION_UNSAFE;
                if (rts_argv[arg][2] == '\0')
                    RtsFlags.ConcFlags.ctxtSwitchTime = 0;
                else {
                    RtsFlags.ConcFlags.ctxtSwitchTime =
                        fsecondsToTime(atof(rts_argv[arg]+2));
                }
                break;

              case 'V': /* master tick interval */
                OPTION_UNSAFE;
                if (rts_argv[arg][2] == '\0') {
                    // turns off ticks completely
                    RtsFlags.MiscFlags.tickInterval = 0;
                } else {
                    RtsFlags.MiscFlags.tickInterval =
                        fsecondsToTime(atof(rts_argv[arg]+2));
                }
                break;

#if !defined(NOSMP)
              case 'N':
                OPTION_SAFE;
                THREADED_BUILD_ONLY(
                if (rts_argv[arg][2] == '\0') {
                    RtsFlags.ParFlags.nCapabilities = getNumberOfProcessors();
                } else {
                    int nCapabilities;
                    OPTION_SAFE; /* but see extra checks below... */

                    nCapabilities = strtol(rts_argv[arg]+2, (char **) NULL, 10);

                    if (nCapabilities <= 0) {
                      errorBelch("bad value for -N");
                      error = true;
                    }
                    if (rtsOptsEnabled == RtsOptsSafeOnly &&
                      nCapabilities > (int)getNumberOfProcessors()) {
                      errorRtsOptsDisabled("Using large values for -N is not allowed by default. %s");
                      stg_exit(EXIT_FAILURE);
                    }
                    RtsFlags.ParFlags.nCapabilities = (uint32_t)nCapabilities;
                }
                ) break;

              case 'g':
                OPTION_UNSAFE;
                THREADED_BUILD_ONLY(
                    switch (rts_argv[arg][2]) {
                    case '1':
                        // backwards compat only
                        RtsFlags.ParFlags.parGcEnabled = false;
                        break;
                    default:
                        errorBelch("unknown RTS option: %s",rts_argv[arg]);
                        error = true;
                        break;
                    }
                    ) break;

              case 'q':
                OPTION_UNSAFE;
                THREADED_BUILD_ONLY(
                    switch (rts_argv[arg][2]) {
                    case '\0':
                        errorBelch("incomplete RTS option: %s",rts_argv[arg]);
                        error = true;
                        break;
                    case 'g':
                        if (rts_argv[arg][3] == '\0') {
                            RtsFlags.ParFlags.parGcEnabled = false;
                        } else {
                            RtsFlags.ParFlags.parGcEnabled = true;
                            RtsFlags.ParFlags.parGcGen
                                = strtol(rts_argv[arg]+3, (char **) NULL, 10);
                        }
                        break;
                    case 'b':
                        if (rts_argv[arg][3] == '\0') {
                            RtsFlags.ParFlags.parGcLoadBalancingEnabled =
                                false;
                        }
                        else {
                            RtsFlags.ParFlags.parGcLoadBalancingEnabled =
                                true;
                            RtsFlags.ParFlags.parGcLoadBalancingGen
                                = strtol(rts_argv[arg]+3, (char **) NULL, 10);
                        }
                        break;
                    case 'i':
                        RtsFlags.ParFlags.parGcNoSyncWithIdle
                            = strtol(rts_argv[arg]+3, (char **) NULL, 10);
                        break;
                    case 'n': {
                        int threads;
                        threads = strtol(rts_argv[arg]+3, (char **) NULL, 10);
                        if (threads <= 0) {
                            errorBelch("-qn must be 1 or greater");
                            error = true;
                        } else {
                            RtsFlags.ParFlags.parGcThreads = threads;
                        }
                        break;
                    }
                    case 'a':
                        RtsFlags.ParFlags.setAffinity = true;
                        break;
                    case 'm':
                        RtsFlags.ParFlags.migrate = false;
                        break;
                    case 'w':
                        // -qw was removed; accepted for backwards compat
                        break;
                    default:
                        errorBelch("unknown RTS option: %s",rts_argv[arg]);
                        error = true;
                        break;
                    }
                    ) break;
#endif
              /* =========== PARALLEL =========================== */
              case 'e':
                OPTION_UNSAFE;
                THREADED_BUILD_ONLY(
                if (rts_argv[arg][2] != '\0') {
                    RtsFlags.ParFlags.maxLocalSparks
                      = strtol(rts_argv[arg]+2, (char **) NULL, 10);
                    if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
                      errorBelch("bad value for -e");
                      error = true;
                    }
                }
                ) break;

              /* =========== TICKY ============================== */

              case 'r': /* Basic profiling stats */
                OPTION_SAFE;
                TICKY_BUILD_ONLY(

                RtsFlags.TickyFlags.showTickyStats = true;

                {
                    int r;
                    if (rts_argv[arg][2] != '\0') {
                      OPTION_UNSAFE;
                    }
                    r = openStatsFile(rts_argv[arg]+2,
                                      TICKY_FILENAME_FMT,
                                      &RtsFlags.TickyFlags.tickyFile);
                    if (r == -1) { error = true; }
                }
                ) break;

              /* =========== OUTPUT ============================ */

              case 'o':
                  switch(rts_argv[arg][2]) {
                  case 'l':
                      OPTION_SAFE;
                      TRACING_BUILD_ONLY(
                          if (strlen(&rts_argv[arg][3]) == 0) {
                              errorBelch("-ol expects filename");
                              error = true;
                          } else {
                              RtsFlags.TraceFlags.trace_output =
                                  strdup(&rts_argv[arg][3]);
                          }
                          );
                      break;

                  default:
                      errorBelch("Unknown output flag -o%c", rts_argv[arg][2]);
                      error = true;
                  }
                  break;

              /* =========== TRACING ============================ */

              case 'l':
                  OPTION_SAFE;
                  TRACING_BUILD_ONLY(
                      RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
                      read_trace_flags(&rts_argv[arg][2]);
                      );
                  break;

              case 'v':
                  OPTION_SAFE;
                  DEBUG_BUILD_ONLY(
                      RtsFlags.TraceFlags.tracing = TRACE_STDERR;
                      read_trace_flags(&rts_argv[arg][2]);
                      );
                  break;

              /* =========== EXTENDED OPTIONS =================== */

              case 'x': /* Extend the argument space */
                unchecked_arg_start++;
                switch(rts_argv[arg][2]) {
                  case '\0':
                    OPTION_SAFE;
                    errorBelch("incomplete RTS option: %s",rts_argv[arg]);
                    error = true;
                    break;

                case 'b': /* heapBase in hex; undocumented */
                    OPTION_UNSAFE;
                    if (rts_argv[arg][3] != '\0') {
                        RtsFlags.GcFlags.heapBase
                            = strToStgWord(rts_argv[arg]+3, (char **) NULL, 0);
                    } else {
                        errorBelch("-xb: requires argument");
                        error = true;
                    }
                    break;

#if defined(x86_64_HOST_ARCH)
                case 'p': /* linkerAlwaysPic */
                    OPTION_UNSAFE;
                    RtsFlags.MiscFlags.linkerAlwaysPic = true;
                    break;

                case 'm': /* linkerMemBase */
                    OPTION_UNSAFE;
                    if (rts_argv[arg][3] != '\0') {
                        RtsFlags.MiscFlags.linkerMemBase
                            = strtol(rts_argv[arg]+3, (char **) NULL, 16);
                        if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
                            errorBelch("-xm: value must be <80000000");
                            error = true;
                        }
                    } else {
                        RtsFlags.MiscFlags.linkerMemBase = 0;
                    }
                    break;
#endif

                case 'c': /* Debugging tool: show current cost centre on
                           an exception */
                    OPTION_SAFE;
                    PROFILING_BUILD_ONLY(
                        RtsFlags.ProfFlags.showCCSOnException = true;
                        );
                    unchecked_arg_start++;
                    goto check_rest;

                case 't':  /* Include memory used by TSOs in a heap profile */
                    OPTION_SAFE;
                    PROFILING_BUILD_ONLY(
                        RtsFlags.ProfFlags.includeTSOs = true;
                        );
                    unchecked_arg_start++;
                    goto check_rest;

                  /*
                   * The option prefix '-xx' is reserved for future
                   * extension.  KSW 1999-11.
                   */

                case 'q':
                  OPTION_UNSAFE;
                  RtsFlags.GcFlags.allocLimitGrace
                      = decodeSize(rts_argv[arg], 3, BLOCK_SIZE, HS_INT_MAX)
                          / BLOCK_SIZE;
                  break;

                  default:
                    OPTION_SAFE;
                    errorBelch("unknown RTS option: %s",rts_argv[arg]);
                    error = true;
                    break;
                }
                break;  /* defensive programming */

            /* check the rest to be sure there is nothing afterwards.*/
            /* see Trac #9839 */
            check_rest:
                {
                    /* start checking from the first unchecked position,
                     * not from index 2*/
                    /* see Trac #9839 */
                    if (rts_argv[arg][unchecked_arg_start] != '\0') {
                      errorBelch("flag -%c given an argument"
                                 " when none was expected: %s",
                                 rts_argv[arg][1],rts_argv[arg]);
                      error = true;
                    }
                    break;
                }

              /* =========== OH DEAR ============================ */
              default:
                OPTION_SAFE;
                errorBelch("unknown RTS option: %s",rts_argv[arg]);
                error = true;
                break;
            }

            if (!option_checked) {
                /* Naughty! Someone didn't use OPTION_UNSAFE / OPTION_SAFE for
                   an option above */
                errorBelch("Internal error in the RTS options parser");
                stg_exit(EXIT_FAILURE);
            }
        }
    }

    if (error) errorUsage();
}