Home | History | Annotate | Download | only in coregrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Command line options.                            m_options.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2000-2015 Nicholas Nethercote
     11       njn (at) valgrind.org
     12 
     13    This program is free software; you can redistribute it and/or
     14    modify it under the terms of the GNU General Public License as
     15    published by the Free Software Foundation; either version 2 of the
     16    License, or (at your option) any later version.
     17 
     18    This program is distributed in the hope that it will be useful, but
     19    WITHOUT ANY WARRANTY; without even the implied warranty of
     20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21    General Public License for more details.
     22 
     23    You should have received a copy of the GNU General Public License
     24    along with this program; if not, write to the Free Software
     25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     26    02111-1307, USA.
     27 
     28    The GNU General Public License is contained in the file COPYING.
     29 */
     30 
     31 #include "pub_core_basics.h"
     32 #include "pub_core_vki.h"
     33 #include "pub_core_options.h"
     34 #include "pub_core_libcassert.h"
     35 #include "pub_core_libcbase.h"
     36 #include "pub_core_libcfile.h"
     37 #include "pub_core_libcprint.h"
     38 #include "pub_core_libcproc.h"
     39 #include "pub_core_mallocfree.h"
     40 #include "pub_core_seqmatch.h"     // VG_(string_match)
     41 #include "pub_core_aspacemgr.h"
     42 
     43 // See pub_{core,tool}_options.h for explanations of all these.
     44 
     45 
     46 /* Define, and set defaults. */
     47 
     48 VexControl VG_(clo_vex_control);
     49 VexRegisterUpdates VG_(clo_px_file_backed) = VexRegUpd_INVALID;
     50 
     51 Bool   VG_(clo_error_limit)    = True;
     52 Int    VG_(clo_error_exitcode) = 0;
     53 HChar *VG_(clo_error_markers)[2] = {NULL, NULL};
     54 
     55 #if defined(VGPV_arm_linux_android) \
     56     || defined(VGPV_x86_linux_android) \
     57     || defined(VGPV_mips32_linux_android) \
     58     || defined(VGPV_arm64_linux_android)
     59 VgVgdb VG_(clo_vgdb)           = Vg_VgdbNo; // currently disabled on Android
     60 #else
     61 VgVgdb VG_(clo_vgdb)           = Vg_VgdbYes;
     62 #endif
     63 Int    VG_(clo_vgdb_poll)      = 5000;
     64 Int    VG_(clo_vgdb_error)     = 999999999;
     65 UInt   VG_(clo_vgdb_stop_at)   = 0;
     66 const HChar *VG_(clo_vgdb_prefix)    = NULL;
     67 const HChar *VG_(arg_vgdb_prefix)    = NULL;
     68 Bool   VG_(clo_vgdb_shadow_registers) = False;
     69 
     70 Int    VG_(clo_gen_suppressions) = 0;
     71 Int    VG_(clo_sanity_level)   = 1;
     72 Int    VG_(clo_verbosity)      = 1;
     73 Bool   VG_(clo_stats)          = False;
     74 Bool   VG_(clo_xml)            = False;
     75 const HChar* VG_(clo_xml_user_comment) = NULL;
     76 Bool   VG_(clo_demangle)       = True;
     77 const HChar* VG_(clo_soname_synonyms)    = NULL;
     78 Bool   VG_(clo_trace_children) = False;
     79 const HChar* VG_(clo_trace_children_skip) = NULL;
     80 const HChar* VG_(clo_trace_children_skip_by_arg) = NULL;
     81 Bool   VG_(clo_child_silent_after_fork) = False;
     82 const HChar* VG_(clo_log_fname_expanded) = NULL;
     83 const HChar* VG_(clo_xml_fname_expanded) = NULL;
     84 Bool   VG_(clo_time_stamp)     = False;
     85 Int    VG_(clo_input_fd)       = 0; /* stdin */
     86 Bool   VG_(clo_default_supp)   = True;
     87 XArray *VG_(clo_suppressions);   // array of strings
     88 XArray *VG_(clo_fullpath_after); // array of strings
     89 const HChar* VG_(clo_extra_debuginfo_path) = NULL;
     90 const HChar* VG_(clo_debuginfo_server) = NULL;
     91 Bool   VG_(clo_allow_mismatched_debuginfo) = False;
     92 UChar  VG_(clo_trace_flags)    = 0; // 00000000b
     93 Bool   VG_(clo_profyle_sbs)    = False;
     94 UChar  VG_(clo_profyle_flags)  = 0; // 00000000b
     95 ULong  VG_(clo_profyle_interval) = 0;
     96 Int    VG_(clo_trace_notbelow) = -1;  // unspecified
     97 Int    VG_(clo_trace_notabove) = -1;  // unspecified
     98 Bool   VG_(clo_trace_syscalls) = False;
     99 Bool   VG_(clo_trace_signals)  = False;
    100 Bool   VG_(clo_trace_symtab)   = False;
    101 const HChar* VG_(clo_trace_symtab_patt) = "*";
    102 Bool   VG_(clo_trace_cfi)      = False;
    103 Bool   VG_(clo_debug_dump_syms) = False;
    104 Bool   VG_(clo_debug_dump_line) = False;
    105 Bool   VG_(clo_debug_dump_frames) = False;
    106 Bool   VG_(clo_trace_redir)    = False;
    107 enum FairSchedType
    108        VG_(clo_fair_sched)     = disable_fair_sched;
    109 Bool   VG_(clo_trace_sched)    = False;
    110 Bool   VG_(clo_profile_heap)   = False;
    111 Int    VG_(clo_core_redzone_size) = CORE_REDZONE_DEFAULT_SZB;
    112 // A value != -1 overrides the tool-specific value
    113 // VG_(needs_malloc_replacement).tool_client_redzone_szB
    114 Int    VG_(clo_redzone_size)   = -1;
    115 Int    VG_(clo_dump_error)     = 0;
    116 Int    VG_(clo_backtrace_size) = 12;
    117 Int    VG_(clo_merge_recursive_frames) = 0; // default value: no merge
    118 UInt   VG_(clo_sim_hints)      = 0;
    119 Bool   VG_(clo_sym_offsets)    = False;
    120 Bool   VG_(clo_read_inline_info) = False; // Or should be put it to True by default ???
    121 Bool   VG_(clo_read_var_info)  = False;
    122 XArray *VG_(clo_req_tsyms);  // array of strings
    123 Bool   VG_(clo_run_libc_freeres) = True;
    124 Bool   VG_(clo_track_fds)      = False;
    125 Bool   VG_(clo_show_below_main)= False;
    126 Bool   VG_(clo_show_emwarns)   = False;
    127 Word   VG_(clo_max_stackframe) = 2000000;
    128 UInt   VG_(clo_max_threads)    = MAX_THREADS_DEFAULT;
    129 Word   VG_(clo_main_stacksize) = 0; /* use client's rlimit.stack */
    130 Word   VG_(clo_valgrind_stacksize) = VG_DEFAULT_STACK_ACTIVE_SZB;
    131 Bool   VG_(clo_wait_for_gdb)   = False;
    132 UInt   VG_(clo_kernel_variant) = 0;
    133 Bool   VG_(clo_dsymutil)       = True;
    134 Bool   VG_(clo_sigill_diag)    = True;
    135 UInt   VG_(clo_unw_stack_scan_thresh) = 0; /* disabled by default */
    136 UInt   VG_(clo_unw_stack_scan_frames) = 5;
    137 
    138 // Set clo_smc_check so that it provides transparent self modifying
    139 // code support for "correct" programs at the smallest achievable
    140 // expense for this arch.
    141 #if defined(VGA_x86) || defined(VGA_amd64) || defined(VGA_s390x)
    142 VgSmc VG_(clo_smc_check) = Vg_SmcAllNonFile;
    143 #elif defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le) \
    144       || defined(VGA_arm) || defined(VGA_arm64) \
    145       || defined(VGA_mips32) || defined(VGA_mips64) \
    146       || defined(VGA_tilegx)
    147 VgSmc VG_(clo_smc_check) = Vg_SmcStack;
    148 #else
    149 #  error "Unknown arch"
    150 #endif
    151 
    152 #if defined(VGO_darwin)
    153 UInt VG_(clo_resync_filter) = 1; /* enabled, but quiet */
    154 #else
    155 UInt VG_(clo_resync_filter) = 0; /* disabled */
    156 #endif
    157 
    158 
    159 /*====================================================================*/
    160 /*=== File expansion                                               ===*/
    161 /*====================================================================*/
    162 
    163 // Copies the string, prepending it with the startup working directory, and
    164 // expanding %p and %q entries.  Returns a new, malloc'd string.
    165 HChar* VG_(expand_file_name)(const HChar* option_name, const HChar* format)
    166 {
    167    const HChar *base_dir;
    168    Int len, i = 0, j = 0;
    169    HChar* out;
    170    const HChar *message = NULL;
    171 
    172    base_dir = VG_(get_startup_wd)();
    173 
    174    if (VG_STREQ(format, "")) {
    175       // Empty name, bad.
    176       message = "No filename given\n";
    177       goto bad;
    178    }
    179 
    180    // If 'format' starts with a '~', abort -- the user probably expected the
    181    // shell to expand but it didn't (see bug 195268 for details).  This means
    182    // that we don't allow a legitimate filename beginning with '~' but that
    183    // seems very unlikely.
    184    if (format[0] == '~') {
    185       message =
    186          "Filename begins with '~'\n"
    187          "You probably expected the shell to expand the '~', but it\n"
    188          "didn't.  The rules for '~'-expansion vary from shell to shell.\n"
    189          "You might have more luck using $HOME instead.\n";
    190       goto bad;
    191    }
    192 
    193    len = VG_(strlen)(format) + 1;
    194    out = VG_(malloc)( "options.efn.1", len );
    195 
    196 #define ENSURE_THIS_MUCH_SPACE(x) \
    197    if (j + x >= len) { \
    198       len += (10 + x); \
    199       out = VG_(realloc)("options.efn.2(multiple)", out, len); \
    200    }
    201 
    202    while (format[i]) {
    203       if (format[i] != '%') {
    204          ENSURE_THIS_MUCH_SPACE(1);
    205          out[j++] = format[i++];
    206 
    207       } else {
    208          // We saw a '%'.  What's next...
    209          i++;
    210          if      ('%' == format[i]) {
    211             // Replace '%%' with '%'.
    212             ENSURE_THIS_MUCH_SPACE(1);
    213             out[j++] = format[i++];
    214          }
    215          else if ('p' == format[i]) {
    216             // Print the PID.  Assume that it's not longer than 10 chars --
    217             // reasonable since 'pid' is an Int (ie. 32 bits).
    218             Int pid = VG_(getpid)();
    219             ENSURE_THIS_MUCH_SPACE(10);
    220             j += VG_(sprintf)(&out[j], "%d", pid);
    221             i++;
    222          }
    223          else if ('q' == format[i]) {
    224             i++;
    225             if ('{' == format[i]) {
    226                // Get the env var name, print its contents.
    227                HChar *qual;
    228                Int begin_qualname = ++i;
    229                while (True) {
    230                   if (0 == format[i]) {
    231                      message = "Missing '}' in %q specifier\n";
    232                      goto bad;
    233                   } else if ('}' == format[i]) {
    234                      Int qualname_len = i - begin_qualname;
    235                      HChar qualname[qualname_len + 1];
    236                      VG_(strncpy)(qualname, format + begin_qualname,
    237                                   qualname_len);
    238                      qualname[qualname_len] = '\0';
    239                      qual = VG_(getenv)(qualname);
    240                      if (NULL == qual) {
    241                         // This memory will leak, But we don't care because
    242                         // VG_(fmsg_bad_option) will terminate the process.
    243                         HChar *str = VG_(malloc)("options.efn.3",
    244                                                  100 + qualname_len);
    245                         VG_(sprintf)(str,
    246                                      "Environment variable '%s' is not set\n",
    247                                      qualname);
    248                         message = str;
    249                         goto bad;
    250                      }
    251                      i++;
    252                      break;
    253                   }
    254                   i++;
    255                }
    256                ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual));
    257                j += VG_(sprintf)(&out[j], "%s", qual);
    258             } else {
    259                message = "Expected '{' after '%q'\n";
    260                goto bad;
    261             }
    262          }
    263          else {
    264             // Something else, abort.
    265             message = "Expected 'p' or 'q' or '%' after '%'\n";
    266             goto bad;
    267          }
    268       }
    269    }
    270    ENSURE_THIS_MUCH_SPACE(1);
    271    out[j++] = 0;
    272 
    273    // If 'out' is not an absolute path name, prefix it with the startup dir.
    274    if (out[0] != '/') {
    275       len = VG_(strlen)(base_dir) + 1 + VG_(strlen)(out) + 1;
    276 
    277       HChar *absout = VG_(malloc)("options.efn.4", len);
    278       VG_(strcpy)(absout, base_dir);
    279       VG_(strcat)(absout, "/");
    280       VG_(strcat)(absout, out);
    281       VG_(free)(out);
    282       out = absout;
    283    }
    284 
    285    return out;
    286 
    287   bad: {
    288    vg_assert(message != NULL);
    289    // 2:  1 for the '=', 1 for the NUL.
    290    HChar opt[VG_(strlen)(option_name) + VG_(strlen)(format) + 2];
    291    VG_(sprintf)(opt, "%s=%s", option_name, format);
    292    VG_(fmsg_bad_option)(opt, "%s", message);
    293   }
    294 }
    295 
    296 /*====================================================================*/
    297 /*=== --trace-children= support                                    ===*/
    298 /*====================================================================*/
    299 
    300 static HChar const* consume_commas ( HChar const* c ) {
    301    while (*c && *c == ',') {
    302       ++c;
    303    }
    304    return c;
    305 }
    306 
    307 static HChar const* consume_field ( HChar const* c ) {
    308    while (*c && *c != ',') {
    309       ++c;
    310    }
    311    return c;
    312 }
    313 
    314 /* Should we trace into this child executable (across execve, spawn etc) ?
    315    This involves considering --trace-children=,
    316    --trace-children-skip=, --trace-children-skip-by-arg=, and the name
    317    of the executable.  'child_argv' must not include the name of the
    318    executable itself; iow child_argv[0] must be the first arg, if any,
    319    for the child. */
    320 Bool VG_(should_we_trace_this_child) ( const HChar* child_exe_name,
    321                                        const HChar** child_argv )
    322 {
    323    // child_exe_name is pulled out of the guest's space.  We
    324    // should be at least marginally cautious with it, lest it
    325    // explode or burst into flames unexpectedly.
    326    if (child_exe_name == NULL || VG_(strlen)(child_exe_name) == 0)
    327       return VG_(clo_trace_children);  // we know narfink
    328 
    329    // If --trace-children=no, the answer is simply NO.
    330    if (! VG_(clo_trace_children))
    331       return False;
    332 
    333    // Otherwise, look for other reasons to say NO.  First,
    334    // see if the exe name matches any of the patterns specified
    335    // by --trace-children-skip=.
    336    if (VG_(clo_trace_children_skip)) {
    337       HChar const* last = VG_(clo_trace_children_skip);
    338       HChar const* name = child_exe_name;
    339       while (*last) {
    340          Bool   matches;
    341          HChar* patt;
    342          HChar const* first = consume_commas(last);
    343          last = consume_field(first);
    344          if (first == last)
    345             break;
    346          vg_assert(last > first);
    347          /* copy the candidate string into a temporary malloc'd block
    348             so we can use VG_(string_match) on it. */
    349          patt = VG_(calloc)("m_options.swttc.1", last - first + 1, 1);
    350          VG_(memcpy)(patt, first, last - first);
    351          vg_assert(patt[last-first] == 0);
    352          matches = VG_(string_match)(patt, name);
    353          VG_(free)(patt);
    354          if (matches)
    355             return False;
    356       }
    357    }
    358 
    359    // Check if any of the args match any of the patterns specified
    360    // by --trace-children-skip-by-arg=.
    361    if (VG_(clo_trace_children_skip_by_arg) && child_argv != NULL) {
    362       HChar const* last = VG_(clo_trace_children_skip_by_arg);
    363       while (*last) {
    364          Int    i;
    365          Bool   matches;
    366          HChar* patt;
    367          HChar const* first = consume_commas(last);
    368          last = consume_field(first);
    369          if (first == last)
    370             break;
    371          vg_assert(last > first);
    372          /* copy the candidate string into a temporary malloc'd block
    373             so we can use VG_(string_match) on it. */
    374          patt = VG_(calloc)("m_options.swttc.1", last - first + 1, 1);
    375          VG_(memcpy)(patt, first, last - first);
    376          vg_assert(patt[last-first] == 0);
    377          for (i = 0; child_argv[i]; i++) {
    378             matches = VG_(string_match)(patt, child_argv[i]);
    379             if (matches) {
    380                VG_(free)(patt);
    381                return False;
    382             }
    383          }
    384          VG_(free)(patt);
    385       }
    386    }
    387 
    388    // --trace-children=yes, and this particular executable isn't
    389    // excluded
    390    return True;
    391 }
    392 
    393 
    394 /*--------------------------------------------------------------------*/
    395 /*--- end                                                          ---*/
    396 /*--------------------------------------------------------------------*/
    397