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