m_options.c revision d898bf0e1479ec87e86e2e875a6dc9040ee22e11
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-2013 Nicholas Nethercote
11      njn@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
42// See pub_{core,tool}_options.h for explanations of all these.
43
44
45/* Define, and set defaults. */
46VexControl VG_(clo_vex_control);
47Bool   VG_(clo_error_limit)    = True;
48Int    VG_(clo_error_exitcode) = 0;
49
50#if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
51    || defined(VGPV_mips32_linux_android) \
52    || defined(VGP_arm64_linux) // temporarily disabled on arm64-linux
53VgVgdb VG_(clo_vgdb)           = Vg_VgdbNo; // currently disabled on Android
54#else
55VgVgdb VG_(clo_vgdb)           = Vg_VgdbYes;
56#endif
57Int    VG_(clo_vgdb_poll)      = 5000;
58Int    VG_(clo_vgdb_error)     = 999999999;
59UInt   VG_(clo_vgdb_stop_at)   = 0;
60const HChar *VG_(clo_vgdb_prefix)    = NULL;
61const HChar *VG_(arg_vgdb_prefix)    = NULL;
62Bool   VG_(clo_vgdb_shadow_registers) = False;
63
64Bool   VG_(clo_db_attach)      = False;
65const HChar*  VG_(clo_db_command)     = GDB_PATH " -nw %f %p";
66Int    VG_(clo_gen_suppressions) = 0;
67Int    VG_(clo_sanity_level)   = 1;
68Int    VG_(clo_verbosity)      = 1;
69Bool   VG_(clo_stats)          = False;
70Bool   VG_(clo_xml)            = False;
71const HChar* VG_(clo_xml_user_comment) = NULL;
72Bool   VG_(clo_demangle)       = True;
73const HChar* VG_(clo_soname_synonyms)    = NULL;
74Bool   VG_(clo_trace_children) = False;
75const HChar* VG_(clo_trace_children_skip) = NULL;
76const HChar* VG_(clo_trace_children_skip_by_arg) = NULL;
77Bool   VG_(clo_child_silent_after_fork) = False;
78HChar* VG_(clo_log_fname_expanded) = NULL;
79HChar* VG_(clo_xml_fname_expanded) = NULL;
80Bool   VG_(clo_time_stamp)     = False;
81Int    VG_(clo_input_fd)       = 0; /* stdin */
82Int    VG_(clo_n_suppressions) = 0;
83const HChar* VG_(clo_suppressions)[VG_CLO_MAX_SFILES];
84Int    VG_(clo_n_fullpath_after) = 0;
85const HChar* VG_(clo_fullpath_after)[VG_CLO_MAX_FULLPATH_AFTER];
86const HChar* VG_(clo_extra_debuginfo_path) = NULL;
87const HChar* VG_(clo_debuginfo_server) = NULL;
88Bool   VG_(clo_allow_mismatched_debuginfo) = False;
89UChar  VG_(clo_trace_flags)    = 0; // 00000000b
90Bool   VG_(clo_profyle_sbs)    = False;
91UChar  VG_(clo_profyle_flags)  = 0; // 00000000b
92ULong  VG_(clo_profyle_interval) = 0;
93Int    VG_(clo_trace_notbelow) = -1;  // unspecified
94Int    VG_(clo_trace_notabove) = -1;  // unspecified
95Bool   VG_(clo_trace_syscalls) = False;
96Bool   VG_(clo_trace_signals)  = False;
97Bool   VG_(clo_trace_symtab)   = False;
98const HChar* VG_(clo_trace_symtab_patt) = "*";
99Bool   VG_(clo_trace_cfi)      = False;
100Bool   VG_(clo_debug_dump_syms) = False;
101Bool   VG_(clo_debug_dump_line) = False;
102Bool   VG_(clo_debug_dump_frames) = False;
103Bool   VG_(clo_trace_redir)    = False;
104enum FairSchedType
105       VG_(clo_fair_sched)     = disable_fair_sched;
106Bool   VG_(clo_trace_sched)    = False;
107Bool   VG_(clo_profile_heap)   = False;
108Int    VG_(clo_core_redzone_size) = CORE_REDZONE_DEFAULT_SZB;
109// A value != -1 overrides the tool-specific value
110// VG_(needs_malloc_replacement).tool_client_redzone_szB
111Int    VG_(clo_redzone_size)   = -1;
112Int    VG_(clo_dump_error)     = 0;
113Int    VG_(clo_backtrace_size) = 12;
114Int    VG_(clo_merge_recursive_frames) = 0; // default value: no merge
115const HChar* VG_(clo_sim_hints)      = NULL;
116Bool   VG_(clo_sym_offsets)    = False;
117Bool   VG_(clo_read_var_info)  = False;
118Int    VG_(clo_n_req_tsyms)    = 0;
119const HChar* VG_(clo_req_tsyms)[VG_CLO_MAX_REQ_TSYMS];
120HChar* VG_(clo_require_text_symbol) = NULL;
121Bool   VG_(clo_run_libc_freeres) = True;
122Bool   VG_(clo_track_fds)      = False;
123Bool   VG_(clo_show_below_main)= False;
124Bool   VG_(clo_show_emwarns)   = False;
125Word   VG_(clo_max_stackframe) = 2000000;
126Word   VG_(clo_main_stacksize) = 0; /* use client's rlimit.stack */
127Bool   VG_(clo_wait_for_gdb)   = False;
128VgSmc  VG_(clo_smc_check)      = Vg_SmcStack;
129const HChar* VG_(clo_kernel_variant) = NULL;
130Bool   VG_(clo_dsymutil)       = False;
131Bool   VG_(clo_sigill_diag)    = True;
132UInt   VG_(clo_unw_stack_scan_thresh) = 0; /* disabled by default */
133UInt   VG_(clo_unw_stack_scan_frames) = 5;
134
135
136/*====================================================================*/
137/*=== File expansion                                               ===*/
138/*====================================================================*/
139
140// Copies the string, prepending it with the startup working directory, and
141// expanding %p and %q entries.  Returns a new, malloc'd string.
142HChar* VG_(expand_file_name)(const HChar* option_name, const HChar* format)
143{
144   static HChar base_dir[VKI_PATH_MAX];
145   Int len, i = 0, j = 0;
146   HChar* out;
147
148   Bool ok = VG_(get_startup_wd)(base_dir, VKI_PATH_MAX);
149   tl_assert(ok);
150
151   if (VG_STREQ(format, "")) {
152      // Empty name, bad.
153      VG_(fmsg)("%s: filename is empty", option_name);
154      goto bad;
155   }
156
157   // If 'format' starts with a '~', abort -- the user probably expected the
158   // shell to expand but it didn't (see bug 195268 for details).  This means
159   // that we don't allow a legitimate filename beginning with '~' but that
160   // seems very unlikely.
161   if (format[0] == '~') {
162      VG_(fmsg)(
163         "%s: filename begins with '~'\n"
164         "You probably expected the shell to expand the '~', but it\n"
165         "didn't.  The rules for '~'-expansion vary from shell to shell.\n"
166         "You might have more luck using $HOME instead.\n",
167         option_name
168      );
169      goto bad;
170   }
171
172   len = VG_(strlen)(format) + 1;
173   out = VG_(malloc)( "options.efn.1", len );
174
175#define ENSURE_THIS_MUCH_SPACE(x) \
176   if (j + x >= len) { \
177      len += (10 + x); \
178      out = VG_(realloc)("options.efn.2(multiple)", out, len); \
179   }
180
181   while (format[i]) {
182      if (format[i] != '%') {
183         ENSURE_THIS_MUCH_SPACE(1);
184         out[j++] = format[i++];
185
186      } else {
187         // We saw a '%'.  What's next...
188         i++;
189         if      ('%' == format[i]) {
190            // Replace '%%' with '%'.
191            ENSURE_THIS_MUCH_SPACE(1);
192            out[j++] = format[i++];
193         }
194         else if ('p' == format[i]) {
195            // Print the PID.  Assume that it's not longer than 10 chars --
196            // reasonable since 'pid' is an Int (ie. 32 bits).
197            Int pid = VG_(getpid)();
198            ENSURE_THIS_MUCH_SPACE(10);
199            j += VG_(sprintf)(&out[j], "%d", pid);
200            i++;
201         }
202         else if ('q' == format[i]) {
203            i++;
204            if ('{' == format[i]) {
205               // Get the env var name, print its contents.
206               const HChar* qualname;
207               HChar* qual;
208               i++;
209               qualname = &format[i];
210               while (True) {
211                  if (0 == format[i]) {
212                     VG_(fmsg)("%s: malformed %%q specifier\n", option_name);
213                     goto bad;
214                  } else if ('}' == format[i]) {
215                     // Temporarily replace the '}' with NUL to extract var
216                     // name.
217                     // FIXME: this is not safe as FORMAT is sometimes a
218                     // string literal which may reside in read-only memory
219                    ((HChar *)format)[i] = 0;
220                     qual = VG_(getenv)(qualname);
221                     if (NULL == qual) {
222                        VG_(fmsg)("%s: environment variable %s is not set\n",
223                                  option_name, qualname);
224                     // FIXME: this is not safe as FORMAT is sometimes a
225                     // string literal which may reside in read-only memory
226                        ((HChar *)format)[i] = '}';  // Put the '}' back.
227                        goto bad;
228                     }
229                     // FIXME: this is not safe as FORMAT is sometimes a
230                     // string literal which may reside in read-only memory
231                     ((HChar *)format)[i] = '}';     // Put the '}' back.
232                     i++;
233                     break;
234                  }
235                  i++;
236               }
237               ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual));
238               j += VG_(sprintf)(&out[j], "%s", qual);
239            } else {
240               VG_(fmsg)("%s: expected '{' after '%%q'\n", option_name);
241               goto bad;
242            }
243         }
244         else {
245            // Something else, abort.
246            VG_(fmsg)("%s: expected 'p' or 'q' or '%%' after '%%'\n",
247                      option_name);
248            goto bad;
249         }
250      }
251   }
252   ENSURE_THIS_MUCH_SPACE(1);
253   out[j++] = 0;
254
255   // If 'out' is not an absolute path name, prefix it with the startup dir.
256   if (out[0] != '/') {
257      len = VG_(strlen)(base_dir) + 1 + VG_(strlen)(out) + 1;
258
259      HChar *absout = VG_(malloc)("options.efn.4", len);
260      VG_(strcpy)(absout, base_dir);
261      VG_(strcat)(absout, "/");
262      VG_(strcat)(absout, out);
263      VG_(free)(out);
264      out = absout;
265   }
266
267   return out;
268
269  bad: {
270   HChar* opt =    // 2:  1 for the '=', 1 for the NUL.
271      VG_(malloc)( "options.efn.3",
272                   VG_(strlen)(option_name) + VG_(strlen)(format) + 2 );
273   VG_(strcpy)(opt, option_name);
274   VG_(strcat)(opt, "=");
275   VG_(strcat)(opt, format);
276   VG_(fmsg_bad_option)(opt, "");
277  }
278}
279
280/*====================================================================*/
281/*=== --trace-children= support                                    ===*/
282/*====================================================================*/
283
284static HChar const* consume_commas ( HChar const* c ) {
285   while (*c && *c == ',') {
286      ++c;
287   }
288   return c;
289}
290
291static HChar const* consume_field ( HChar const* c ) {
292   while (*c && *c != ',') {
293      ++c;
294   }
295   return c;
296}
297
298/* Should we trace into this child executable (across execve etc) ?
299   This involves considering --trace-children=,
300   --trace-children-skip=, --trace-children-skip-by-arg=, and the name
301   of the executable.  'child_argv' must not include the name of the
302   executable itself; iow child_argv[0] must be the first arg, if any,
303   for the child. */
304Bool VG_(should_we_trace_this_child) ( HChar* child_exe_name,
305                                       HChar** child_argv )
306{
307   // child_exe_name is pulled out of the guest's space.  We
308   // should be at least marginally cautious with it, lest it
309   // explode or burst into flames unexpectedly.
310   if (child_exe_name == NULL || VG_(strlen)(child_exe_name) == 0)
311      return VG_(clo_trace_children);  // we know narfink
312
313   // If --trace-children=no, the answer is simply NO.
314   if (! VG_(clo_trace_children))
315      return False;
316
317   // Otherwise, look for other reasons to say NO.  First,
318   // see if the exe name matches any of the patterns specified
319   // by --trace-children-skip=.
320   if (VG_(clo_trace_children_skip)) {
321      HChar const* last = VG_(clo_trace_children_skip);
322      HChar const* name = child_exe_name;
323      while (*last) {
324         Bool   matches;
325         HChar* patt;
326         HChar const* first = consume_commas(last);
327         last = consume_field(first);
328         if (first == last)
329            break;
330         vg_assert(last > first);
331         /* copy the candidate string into a temporary malloc'd block
332            so we can use VG_(string_match) on it. */
333         patt = VG_(calloc)("m_options.swttc.1", last - first + 1, 1);
334         VG_(memcpy)(patt, first, last - first);
335         vg_assert(patt[last-first] == 0);
336         matches = VG_(string_match)(patt, name);
337         VG_(free)(patt);
338         if (matches)
339            return False;
340      }
341   }
342
343   // Check if any of the args match any of the patterns specified
344   // by --trace-children-skip-by-arg=.
345   if (VG_(clo_trace_children_skip_by_arg) && child_argv != NULL) {
346      HChar const* last = VG_(clo_trace_children_skip_by_arg);
347      while (*last) {
348         Int    i;
349         Bool   matches;
350         HChar* patt;
351         HChar const* first = consume_commas(last);
352         last = consume_field(first);
353         if (first == last)
354            break;
355         vg_assert(last > first);
356         /* copy the candidate string into a temporary malloc'd block
357            so we can use VG_(string_match) on it. */
358         patt = VG_(calloc)("m_options.swttc.1", last - first + 1, 1);
359         VG_(memcpy)(patt, first, last - first);
360         vg_assert(patt[last-first] == 0);
361         for (i = 0; child_argv[i]; i++) {
362            matches = VG_(string_match)(patt, child_argv[i]);
363            if (matches) {
364               VG_(free)(patt);
365               return False;
366            }
367         }
368         VG_(free)(patt);
369      }
370   }
371
372   // --trace-children=yes, and this particular executable isn't
373   // excluded
374   return True;
375}
376
377
378/*--------------------------------------------------------------------*/
379/*--- end                                                          ---*/
380/*--------------------------------------------------------------------*/
381