1 /*
2  * mpatrol
3  * A library for controlling and tracing dynamic memory allocations.
4  * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307, USA.
20  */
21 
22 
23 /*
24  * A tool for setting various mpatrol library options when running a program
25  * that has been linked with the mpatrol library.
26  */
27 
28 
29 #include "getopt.h"
30 #include "version.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <errno.h>
36 #if TARGET == TARGET_UNIX
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #include <unistd.h>
41 #elif TARGET == TARGET_WINDOWS
42 #include <process.h>
43 #endif /* TARGET */
44 
45 
46 #if MP_IDENT_SUPPORT
47 #ident "$Id: mpatrol.c,v 1.45 2002/01/08 20:13:59 graeme Exp $"
48 #else /* MP_IDENT_SUPPORT */
49 static MP_CONST MP_VOLATILE char *mpatrol_id = "$Id: mpatrol.c,v 1.45 2002/01/08 20:13:59 graeme Exp $";
50 #endif /* MP_IDENT_SUPPORT */
51 
52 
53 #define PROGVERSION "2.7" /* the current version of this program */
54 
55 
56 /* The flags used to parse the command line options.
57  */
58 
59 typedef enum options_flags
60 {
61     OF_ALLOCSTOP      = 'A',
62     OF_ALLOCBYTE      = 'a',
63     OF_PAGEALLOCUPPER = 'B',
64     OF_PAGEALLOCLOWER = 'b',
65     OF_CHECKALL       = 'C',
66     OF_CHECK          = 'c',
67     OF_DEFALIGN       = 'D',
68     OF_DYNAMIC        = 'd',
69     OF_SHOWENV        = 'E',
70     OF_EDIT           = 'e',
71     OF_FREESTOP       = 'F',
72     OF_FREEBYTE       = 'f',
73     OF_SAFESIGNALS    = 'G',
74     OF_USEDEBUG       = 'g',
75     OF_HTML           = 'H',
76     OF_HELP           = 'h',
77     OF_READENV        = 'I',
78     OF_LIST           = 'i',
79     OF_THREADS        = 'j',
80     OF_LOGALL         = 'L',
81     OF_LOGFILE        = 'l',
82     OF_ALLOWOFLOW     = 'M',
83     OF_USEMMAP        = 'm',
84     OF_NOPROTECT      = 'N',
85     OF_NOFREE         = 'n',
86     OF_OFLOWSIZE      = 'O',
87     OF_OFLOWBYTE      = 'o',
88     OF_PROFFILE       = 'P',
89     OF_PROF           = 'p',
90     OF_FAILSEED       = 'Q',
91     OF_FAILFREQ       = 'q',
92     OF_REALLOCSTOP    = 'R',
93     OF_PROGFILE       = 'r',
94     OF_SHOWALL        = 'S',
95     OF_AUTOSAVE       = 's',
96     OF_TRACEFILE      = 'T',
97     OF_TRACE          = 't',
98     OF_UNFREEDABORT   = 'U',
99     OF_LIMIT          = 'u',
100     OF_VERSION        = 'V',
101     OF_PRESERVE       = 'v',
102     OF_OFLOWWATCH     = 'w',
103     OF_CHECKALLOCS    = SHORTOPT_MAX + 1,
104     OF_CHECKFORK,
105     OF_CHECKFREES,
106     OF_CHECKMEMORY,
107     OF_CHECKREALLOCS,
108     OF_LARGEBOUND,
109     OF_LEAKTABLE,
110     OF_LOGALLOCS,
111     OF_LOGFREES,
112     OF_LOGMEMORY,
113     OF_LOGREALLOCS,
114     OF_MEDIUMBOUND,
115     OF_SHOWFREE,
116     OF_SHOWFREED,
117     OF_SHOWMAP,
118     OF_SHOWSYMBOLS,
119     OF_SHOWUNFREED,
120     OF_SMALLBOUND
121 }
122 options_flags;
123 
124 
125 /* The buffer used to build up the environment variable containing options
126  * for the mpatrol library.
127  */
128 
129 static char options[1024];
130 
131 
132 /* The current length of the options buffer.
133  */
134 
135 static size_t optlen;
136 
137 
138 /* The filename used to invoke this tool.
139  */
140 
141 static char *progname;
142 
143 
144 /* The following string options correspond to their uppercase equivalents when
145  * setting the environment variable containing mpatrol library options.
146  */
147 
148 static char *allocstop, *reallocstop, *freestop;
149 static char *allocbyte, *freebyte;
150 static char *oflowbyte, *oflowsize;
151 static char *defalign, *limit;
152 static char *failfreq, *failseed, *unfreedabort;
153 static char *logfile, *proffile;
154 static char *tracefile, *progfile;
155 static char *autosave, *check;
156 static char *nofree, *pagealloc;
157 static char *smallbound, *mediumbound, *largebound;
158 
159 
160 /* The following boolean options correspond to their uppercase equivalents when
161  * setting the environment variable containing mpatrol library options.
162  */
163 
164 static int checkallocs, checkreallocs;
165 static int checkfrees, checkmemory;
166 static int showmap, showsymbols;
167 static int showfree, showfreed;
168 static int showunfreed, leaktable;
169 static int logallocs, logreallocs;
170 static int logfrees, logmemory;
171 static int allowoflow, prof, trace;
172 static int safesignals, noprotect;
173 static int checkfork, preserve;
174 static int oflowwatch, usemmap;
175 static int usedebug, editlist, html;
176 
177 
178 /* The table describing all recognised options.
179  */
180 
181 static option options_table[] =
182 {
183     {"alloc-byte", OF_ALLOCBYTE, "unsigned integer",
184      "\tSpecifies an 8-bit byte pattern with which to prefill newly-allocated\n"
185      "\tmemory.\n"},
186     {"alloc-stop", OF_ALLOCSTOP, "unsigned integer",
187      "\tSpecifies an allocation index at which to stop the program when it is\n"
188      "\tbeing allocated.\n"},
189     {"allow-oflow", OF_ALLOWOFLOW, NULL,
190      "\tSpecifies that a warning rather than an error should be produced if\n"
191      "\tany memory operation function overflows the boundaries of a memory\n"
192      "\tallocation, and that the operation should still be performed.\n"},
193     {"auto-save", OF_AUTOSAVE, "unsigned integer",
194      "\tSpecifies the frequency at which to periodically write the profiling\n"
195      "\tdata to the profiling output file.\n"},
196     {"check", OF_CHECK, "unsigned range",
197      "\tSpecifies a range of allocation indices at which to check the\n"
198      "\tintegrity of free memory and overflow buffers.\n"},
199     {"check-all", OF_CHECKALL, NULL,
200      "\tEquivalent to the --check-allocs, --check-reallocs, --check-frees and\n"
201      "\t--check-memory options specified together.\n"},
202     {"check-allocs", OF_CHECKALLOCS, NULL,
203      "\tChecks that no attempt is made to allocate a block of memory of size\n"
204      "\tzero.\n"},
205     {"check-fork", OF_CHECKFORK, NULL,
206      "\tChecks at every call to see if the process has been forked in case\n"
207      "\tnew log, profiling and tracing output files need to be started.\n"},
208     {"check-frees", OF_CHECKFREES, NULL,
209      "\tChecks that no attempt is made to deallocate a NULL pointer.\n"},
210     {"check-memory", OF_CHECKMEMORY, NULL,
211      "\tChecks that no attempt is made to perform a zero-length memory\n"
212      "\toperation on a NULL pointer.\n"},
213     {"check-reallocs", OF_CHECKREALLOCS, NULL,
214      "\tChecks that no attempt is made to reallocate a NULL pointer or resize\n"
215      "\tan existing block of memory to size zero.\n"},
216     {"def-align", OF_DEFALIGN, "unsigned integer",
217      "\tSpecifies the default alignment for general-purpose memory\n"
218      "\tallocations, which must be a power of two.\n"},
219     {"dynamic", OF_DYNAMIC, NULL,
220      "\tSpecifies that programs which were not linked with the mpatrol\n"
221      "\tlibrary should also be traced, but only if they were dynamically\n"
222      "\tlinked.\n"},
223     {"edit", OF_EDIT, NULL,
224      "\tSpecifies that a text editor should be invoked to edit any relevant\n"
225      "\tsource files that are associated with any warnings or errors when\n"
226      "\tthey occur.\n"},
227     {"fail-freq", OF_FAILFREQ, "unsigned integer",
228      "\tSpecifies the frequency at which all memory allocations will randomly\n"
229      "\tfail.\n"},
230     {"fail-seed", OF_FAILSEED, "unsigned integer",
231      "\tSpecifies the random number seed which will be used when determining\n"
232      "\twhich memory allocations will randomly fail.\n"},
233     {"free-byte", OF_FREEBYTE, "unsigned integer",
234      "\tSpecifies an 8-bit byte pattern with which to prefill newly-freed\n"
235      "\tmemory.\n"},
236     {"free-stop", OF_FREESTOP, "unsigned integer",
237      "\tSpecifies an allocation index at which to stop the program when it is\n"
238      "\tbeing freed.\n"},
239     {"help", OF_HELP, NULL,
240      "\tDisplays this quick-reference option summary.\n"},
241     {"html", OF_HTML, NULL,
242      "\tSpecifies that the log file should be formatted in HTML.\n"},
243     {"large-bound", OF_LARGEBOUND, "unsigned integer",
244      "\tSpecifies the limit in bytes up to which memory allocations should be\n"
245      "\tclassified as large allocations for profiling purposes.\n"},
246     {"leak-table", OF_LEAKTABLE, NULL,
247      "\tSpecifies that the leak table should be automatically used and a leak\n"
248      "\ttable summary should be displayed at the end of program execution.\n"},
249     {"limit", OF_LIMIT, "unsigned integer",
250      "\tSpecifies the limit in bytes at which all memory allocations should\n"
251      "\tfail if the total allocated memory should increase beyond this.\n"},
252     {"list", OF_LIST, NULL,
253      "\tSpecifies that a context listing should be shown for any relevant\n"
254      "\tsource files that are associated with any warnings or errors when\n"
255      "\tthey occur.\n"},
256     {"log-all", OF_LOGALL, NULL,
257      "\tEquivalent to the --log-allocs, --log-reallocs, --log-frees and\n"
258      "\t--log-memory options specified together.\n"},
259     {"log-allocs", OF_LOGALLOCS, NULL,
260      "\tSpecifies that all memory allocations are to be logged and sent to\n"
261      "\tthe log file.\n"},
262     {"log-file", OF_LOGFILE, "string",
263      "\tSpecifies an alternative file in which to place all diagnostics from\n"
264      "\tthe mpatrol library.\n"},
265     {"log-frees", OF_LOGFREES, NULL,
266      "\tSpecifies that all memory deallocations are to be logged and sent to\n"
267      "\tthe log file.\n"},
268     {"log-memory", OF_LOGMEMORY, NULL,
269      "\tSpecifies that all memory operations are to be logged and sent to the\n"
270      "\tlog file.\n"},
271     {"log-reallocs", OF_LOGREALLOCS, NULL,
272      "\tSpecifies that all memory reallocations are to be logged and sent to\n"
273      "\tthe log file.\n"},
274     {"medium-bound", OF_MEDIUMBOUND, "unsigned integer",
275      "\tSpecifies the limit in bytes up to which memory allocations should be\n"
276      "\tclassified as medium allocations for profiling purposes.\n"},
277     {"no-free", OF_NOFREE, "unsigned integer",
278      "\tSpecifies that a number of recently-freed memory allocations should\n"
279      "\tbe prevented from being returned to the free memory pool.\n"},
280     {"no-protect", OF_NOPROTECT, NULL,
281      "\tSpecifies that the mpatrol library's internal data structures should\n"
282      "\tnot be made read-only after every memory allocation, reallocation or\n"
283      "\tdeallocation.\n"},
284     {"oflow-byte", OF_OFLOWBYTE, "unsigned integer",
285      "\tSpecifies an 8-bit byte pattern with which to fill the overflow\n"
286      "\tbuffers of all memory allocations.\n"},
287     {"oflow-size", OF_OFLOWSIZE, "unsigned integer",
288      "\tSpecifies the size in bytes to use for all overflow buffers, which\n"
289      "\tmust be a power of two.\n"},
290     {"oflow-watch", OF_OFLOWWATCH, NULL,
291      "\tSpecifies that watch point areas should be used for overflow buffers\n"
292      "\trather than filling with the overflow byte.\n"},
293     {"page-alloc-lower", OF_PAGEALLOCLOWER, NULL,
294      "\tSpecifies that each individual memory allocation should occupy at\n"
295      "\tleast one page of virtual memory and should be placed at the lowest\n"
296      "\tpoint within these pages.\n"},
297     {"page-alloc-upper", OF_PAGEALLOCUPPER, NULL,
298      "\tSpecifies that each individual memory allocation should occupy at\n"
299      "\tleast one page of virtual memory and should be placed at the highest\n"
300      "\tpoint within these pages.\n"},
301     {"preserve", OF_PRESERVE, NULL,
302      "\tSpecifies that any reallocated or freed memory allocations should\n"
303      "\tpreserve their original contents.\n"},
304     {"prof", OF_PROF, NULL,
305      "\tSpecifies that all memory allocations are to be profiled and sent to\n"
306      "\tthe profiling output file.\n"},
307     {"prof-file", OF_PROFFILE, "string",
308      "\tSpecifies an alternative file in which to place all memory allocation\n"
309      "\tprofiling information from the mpatrol library.\n"},
310     {"prog-file", OF_PROGFILE, "string",
311      "\tSpecifies an alternative filename with which to locate the executable\n"
312      "\tfile containing the program's symbols.\n"},
313     {"read-env", OF_READENV, NULL,
314      "\tReads and passes through the contents of the " MP_OPTIONS "\n"
315      "\tenvironment variable.\n"},
316     {"realloc-stop", OF_REALLOCSTOP, "unsigned integer",
317      "\tSpecifies an allocation index at which to stop the program when a\n"
318      "\tmemory allocation is being reallocated.\n"},
319     {"safe-signals", OF_SAFESIGNALS, NULL,
320      "\tInstructs the library to save and replace certain signal handlers\n"
321      "\tduring the execution of library code and to restore them\n"
322      "\tafterwards.\n"},
323     {"show-all", OF_SHOWALL, NULL,
324      "\tEquivalent to the --show-free, --show-freed, --show-unfreed,\n"
325      "\t--show-map and --show-symbols options specified together.\n"},
326     {"show-env", OF_SHOWENV, NULL,
327      "\tDisplays the contents of the " MP_OPTIONS " environment variable.\n"},
328     {"show-free", OF_SHOWFREE, NULL,
329      "\tSpecifies that a summary of all of the free memory blocks should be\n"
330      "\tdisplayed at the end of program execution.\n"},
331     {"show-freed", OF_SHOWFREED, NULL,
332      "\tSpecifies that a summary of all of the freed memory allocations\n"
333      "\tshould be displayed at the end of program execution.\n"},
334     {"show-map", OF_SHOWMAP, NULL,
335      "\tSpecifies that a memory map of the entire heap should be displayed at\n"
336      "\tthe end of program execution.\n"},
337     {"show-symbols", OF_SHOWSYMBOLS, NULL,
338      "\tSpecifies that a summary of all of the function symbols read from\n"
339      "\tthe program's executable file should be displayed at the end of\n"
340      "\tprogram execution.\n"},
341     {"show-unfreed", OF_SHOWUNFREED, NULL,
342      "\tSpecifies that a summary of all of the unfreed memory allocations\n"
343      "\tshould be displayed at the end of program execution.\n"},
344     {"small-bound", OF_SMALLBOUND, "unsigned integer",
345      "\tSpecifies the limit in bytes up to which memory allocations should be\n"
346      "\tclassified as small allocations for profiling purposes.\n"},
347     {"threads", OF_THREADS, NULL,
348      "\tSpecifies that the program to be run is multithreaded if the\n"
349      "\t--dynamic option is used.\n"},
350     {"trace", OF_TRACE, NULL,
351      "\tSpecifies that all memory allocations are to be traced and sent to\n"
352      "\tthe tracing output file.\n"},
353     {"trace-file", OF_TRACEFILE, "string",
354      "\tSpecifies an alternative file in which to place all memory allocation\n"
355      "\ttracing information from the mpatrol library.\n"},
356     {"unfreed-abort", OF_UNFREEDABORT, "unsigned integer",
357      "\tSpecifies the minimum number of unfreed allocations at which to abort\n"
358      "\tthe program just before program termination.\n"},
359     {"use-debug", OF_USEDEBUG, NULL,
360      "\tSpecifies that any debugging information in the executable file\n"
361      "\tshould be used to obtain additional source-level information.\n"},
362     {"use-mmap", OF_USEMMAP, NULL,
363      "\tSpecifies that the library should use mmap() instead of sbrk() to\n"
364      "\tallocate user memory.\n"},
365     {"version", OF_VERSION, NULL,
366      "\tDisplays the version number of this program.\n"},
367     NULL
368 };
369 
370 
371 /* Add an option and possibly an associated value to the options buffer.
372  */
373 
374 static
375 void
addoption(char * o,char * v,int s)376 addoption(char *o, char *v, int s)
377 {
378     size_t l;
379     int q;
380 
381     q = 0;
382     l = strlen(o) + (s == 0);
383     if (v != NULL)
384     {
385         l += strlen(v) + 1;
386         if (strchr(v, ' '))
387         {
388             l += 2;
389             q = 1;
390         }
391     }
392     if (optlen + l >= sizeof(options))
393     {
394         fprintf(stderr, "%s: Environment variable too long\n", progname);
395         exit(EXIT_FAILURE);
396     }
397     if (q == 1)
398         sprintf(options + optlen, "%s%s=\"%s\"", (s == 0) ? " " : "", o, v);
399     else if (v != NULL)
400         sprintf(options + optlen, "%s%s=%s", (s == 0) ? " " : "", o, v);
401     else
402         sprintf(options + optlen, "%s%s", (s == 0) ? " " : "", o);
403     optlen += l;
404 }
405 
406 
407 /* Build the environment variable containing mpatrol library options.
408  */
409 
410 static
411 void
setoptions(int r,int s)412 setoptions(int r, int s)
413 {
414     char *t;
415 
416     sprintf(options, "%s=", MP_OPTIONS);
417     optlen = strlen(options);
418     if (r != 0)
419         if (((t = getenv(MP_OPTIONS)) != NULL) && (*t != '\0'))
420         {
421             strcpy(options + optlen, t);
422             optlen += strlen(t);
423         }
424         else
425             r = 0;
426     addoption("LOGFILE", logfile, (r == 0));
427     if (allocbyte)
428         addoption("ALLOCBYTE", allocbyte, 0);
429     if (allocstop)
430         addoption("ALLOCSTOP", allocstop, 0);
431     if (allowoflow)
432         addoption("ALLOWOFLOW", NULL, 0);
433     if (autosave)
434         addoption("AUTOSAVE", autosave, 0);
435     if (check)
436         addoption("CHECK", check, 0);
437     if (checkallocs && checkfrees && checkmemory && checkreallocs)
438         addoption("CHECKALL", NULL, 0);
439     else
440     {
441         if (checkallocs)
442             addoption("CHECKALLOCS", NULL, 0);
443         if (checkfrees)
444             addoption("CHECKFREES", NULL, 0);
445         if (checkmemory)
446             addoption("CHECKMEMORY", NULL, 0);
447         if (checkreallocs)
448             addoption("CHECKREALLOCS", NULL, 0);
449     }
450     if (checkfork)
451         addoption("CHECKFORK", NULL, 0);
452     if (defalign)
453         addoption("DEFALIGN", defalign, 0);
454     if (editlist == 1)
455         addoption("EDIT", NULL, 0);
456     if (failfreq)
457         addoption("FAILFREQ", failfreq, 0);
458     if (failseed)
459         addoption("FAILSEED", failseed, 0);
460     if (freebyte)
461         addoption("FREEBYTE", freebyte, 0);
462     if (freestop)
463         addoption("FREESTOP", freestop, 0);
464     if (html)
465         addoption("HTML", NULL, 0);
466     if (largebound)
467         addoption("LARGEBOUND", largebound, 0);
468     if (leaktable)
469         addoption("LEAKTABLE", NULL, 0);
470     if (limit)
471         addoption("LIMIT", limit, 0);
472     if (editlist == 2)
473         addoption("LIST", NULL, 0);
474     if (logallocs && logfrees && logmemory && logreallocs)
475         addoption("LOGALL", NULL, 0);
476     else
477     {
478         if (logallocs)
479             addoption("LOGALLOCS", NULL, 0);
480         if (logfrees)
481             addoption("LOGFREES", NULL, 0);
482         if (logmemory)
483             addoption("LOGMEMORY", NULL, 0);
484         if (logreallocs)
485             addoption("LOGREALLOCS", NULL, 0);
486     }
487     if (mediumbound)
488         addoption("MEDIUMBOUND", mediumbound, 0);
489     if (nofree)
490         addoption("NOFREE", nofree, 0);
491     if (noprotect)
492         addoption("NOPROTECT", NULL, 0);
493     if (oflowbyte)
494         addoption("OFLOWBYTE", oflowbyte, 0);
495     if (oflowsize)
496         addoption("OFLOWSIZE", oflowsize, 0);
497     if (oflowwatch)
498         addoption("OFLOWWATCH", NULL, 0);
499     if (pagealloc)
500         addoption("PAGEALLOC", pagealloc, 0);
501     if (preserve)
502         addoption("PRESERVE", NULL, 0);
503     if (prof)
504         addoption("PROF", NULL, 0);
505     if (proffile)
506         addoption("PROFFILE", proffile, 0);
507     if (progfile)
508         addoption("PROGFILE", progfile, 0);
509     if (reallocstop)
510         addoption("REALLOCSTOP", reallocstop, 0);
511     if (safesignals)
512         addoption("SAFESIGNALS", NULL, 0);
513     if (showfree && showfreed && showmap && showsymbols && showunfreed)
514         addoption("SHOWALL", NULL, 0);
515     else
516     {
517         if (showfree)
518             addoption("SHOWFREE", NULL, 0);
519         if (showfreed)
520             addoption("SHOWFREED", NULL, 0);
521         if (showmap)
522             addoption("SHOWMAP", NULL, 0);
523         if (showsymbols)
524             addoption("SHOWSYMBOLS", NULL, 0);
525         if (showunfreed)
526             addoption("SHOWUNFREED", NULL, 0);
527     }
528     if (smallbound)
529         addoption("SMALLBOUND", smallbound, 0);
530     if (trace)
531         addoption("TRACE", NULL, 0);
532     if (tracefile)
533         addoption("TRACEFILE", tracefile, 0);
534     if (unfreedabort)
535         addoption("UNFREEDABORT", unfreedabort, 0);
536     if (usedebug)
537         addoption("USEDEBUG", NULL, 0);
538     if (usemmap)
539         addoption("USEMMAP", NULL, 0);
540     if (s != 0)
541         fprintf(stdout, "%s\n", strchr(options, '=') + 1);
542     else if (putenv(options))
543     {
544         fprintf(stderr, "%s: Cannot set environment variable `%s'\n", progname,
545                 MP_OPTIONS);
546         exit(EXIT_FAILURE);
547     }
548 }
549 
550 
551 #if MP_PRELOAD_SUPPORT
552 /* Build the environment variable containing the list of libraries to preload.
553  */
554 
555 static
556 char *
addlibraries(char * v,...)557 addlibraries(char *v, ...)
558 {
559     static char p[256];
560     char *s, *t;
561     va_list l;
562 
563     t = p;
564     sprintf(t, "%s=%s", MP_PRELOAD_NAME, v);
565     t += strlen(t);
566     va_start(l, v);
567     while ((s = va_arg(l, char *)) != NULL)
568     {
569         sprintf(t, "%s%s", MP_PRELOAD_SEP, s);
570         t += strlen(t);
571     }
572     va_end(l);
573     return p;
574 }
575 #endif /* MP_PRELOAD_SUPPORT */
576 
577 
578 #if TARGET == TARGET_UNIX
579 /* Search for an executable file in the current search path.
580  */
581 
582 static
583 char *
execpath(char * s)584 execpath(char *s)
585 {
586     static char t[MAXPATHLEN];
587     char *p, *x, *y;
588 
589     if (strchr(s, '/'))
590         return s;
591     if ((p = getenv("PATH")) == NULL)
592         p = "";
593     if ((p = strdup(p)) == NULL)
594     {
595         fprintf(stderr, "%s: Out of memory\n", progname);
596         exit(EXIT_FAILURE);
597     }
598     for (x = y = p; y != NULL; x = y + 1)
599     {
600         if (y = strchr(x, ':'))
601             *y = '\0';
602         if (*x == '\0')
603             x = ".";
604         sprintf(t, "%s/%s", x, s);
605         if (access(t, X_OK) == 0)
606         {
607             s = t;
608             break;
609         }
610     }
611     free(p);
612     return s;
613 }
614 #endif /* TARGET */
615 
616 
617 /* Convert the command line options to mpatrol library options and run the
618  * specified command and arguments.
619  */
620 
621 int
main(int argc,char ** argv)622 main(int argc, char **argv)
623 {
624     char b[256];
625     char *a;
626 #if MP_PRELOAD_SUPPORT
627     char *p;
628 #endif /* MP_PRELOAD_SUPPORT */
629 #if TARGET == TARGET_UNIX
630     pid_t f;
631 #else /* TARGET */
632 #if TARGET == TARGET_WINDOWS
633     char **s;
634 #else /* TARGET */
635     char *s;
636 #endif /* TARGET */
637     size_t i, l;
638 #endif /* TARGET */
639     int c, d, e, h, r, t, v, w, x;
640 
641     d = e = h = r = t = v = w = x = 0;
642     progname = __mp_basename(argv[0]);
643     if ((a = getenv(MP_LOGDIR)) && (*a != '\0'))
644         logfile = "%n.%p.log";
645     else
646         logfile = "mpatrol.%n.log";
647     if ((a = getenv(MP_PROFDIR)) && (*a != '\0'))
648         proffile = "%n.%p.out";
649     else
650         proffile = "mpatrol.%n.out";
651     if ((a = getenv(MP_TRACEDIR)) && (*a != '\0'))
652         tracefile = "%n.%p.trace";
653     else
654         tracefile = "mpatrol.%n.trace";
655     while ((c = __mp_getopt(argc, argv, __mp_shortopts(b, options_table),
656              options_table)) != EOF)
657         switch (c)
658         {
659           case OF_ALLOCBYTE:
660             allocbyte = __mp_optarg;
661             break;
662           case OF_ALLOCSTOP:
663             allocstop = __mp_optarg;
664             break;
665           case OF_ALLOWOFLOW:
666             allowoflow = 1;
667             break;
668           case OF_AUTOSAVE:
669             autosave = __mp_optarg;
670             break;
671           case OF_CHECK:
672             check = __mp_optarg;
673             break;
674           case OF_CHECKALL:
675             checkallocs = 1;
676             checkreallocs = 1;
677             checkfrees = 1;
678             checkmemory = 1;
679             break;
680           case OF_CHECKALLOCS:
681             checkallocs = 1;
682             break;
683           case OF_CHECKFORK:
684             checkfork = 1;
685             break;
686           case OF_CHECKFREES:
687             checkfrees = 1;
688             break;
689           case OF_CHECKMEMORY:
690             checkmemory = 1;
691             break;
692           case OF_CHECKREALLOCS:
693             checkreallocs = 1;
694             break;
695           case OF_DEFALIGN:
696             defalign = __mp_optarg;
697             break;
698           case OF_DYNAMIC:
699             d = 1;
700             break;
701           case OF_EDIT:
702             editlist = 1;
703             break;
704           case OF_FAILFREQ:
705             failfreq = __mp_optarg;
706             break;
707           case OF_FAILSEED:
708             failseed = __mp_optarg;
709             break;
710           case OF_FREEBYTE:
711             freebyte = __mp_optarg;
712             break;
713           case OF_FREESTOP:
714             freestop = __mp_optarg;
715             break;
716           case OF_HELP:
717             h = 1;
718             break;
719           case OF_HTML:
720             html = 1;
721             break;
722           case OF_LARGEBOUND:
723             largebound = __mp_optarg;
724             break;
725           case OF_LEAKTABLE:
726             leaktable = 1;
727             break;
728           case OF_LIST:
729             editlist = 2;
730             break;
731           case OF_LIMIT:
732             limit = __mp_optarg;
733             break;
734           case OF_LOGALL:
735             logallocs = 1;
736             logreallocs = 1;
737             logfrees = 1;
738             logmemory = 1;
739             break;
740           case OF_LOGALLOCS:
741             logallocs = 1;
742             break;
743           case OF_LOGFILE:
744             logfile = __mp_optarg;
745             break;
746           case OF_LOGFREES:
747             logfrees = 1;
748             break;
749           case OF_LOGMEMORY:
750             logmemory = 1;
751             break;
752           case OF_LOGREALLOCS:
753             logreallocs = 1;
754             break;
755           case OF_MEDIUMBOUND:
756             mediumbound = __mp_optarg;
757             break;
758           case OF_NOFREE:
759             nofree = __mp_optarg;
760             break;
761           case OF_NOPROTECT:
762             noprotect = 1;
763             break;
764           case OF_OFLOWBYTE:
765             oflowbyte = __mp_optarg;
766             break;
767           case OF_OFLOWSIZE:
768             oflowsize = __mp_optarg;
769             break;
770           case OF_OFLOWWATCH:
771             oflowwatch = 1;
772             break;
773           case OF_PAGEALLOCLOWER:
774             pagealloc = "LOWER";
775             break;
776           case OF_PAGEALLOCUPPER:
777             pagealloc = "UPPER";
778             break;
779           case OF_PRESERVE:
780             preserve = 1;
781             break;
782           case OF_PROF:
783             prof = 1;
784             break;
785           case OF_PROFFILE:
786             proffile = __mp_optarg;
787             break;
788           case OF_PROGFILE:
789             progfile = __mp_optarg;
790             break;
791           case OF_READENV:
792             x = 1;
793             break;
794           case OF_REALLOCSTOP:
795             reallocstop = __mp_optarg;
796             break;
797           case OF_SAFESIGNALS:
798             safesignals = 1;
799             break;
800           case OF_SHOWALL:
801             showmap = 1;
802             showsymbols = 1;
803             showfree = 1;
804             showfreed = 1;
805             showunfreed = 1;
806             break;
807           case OF_SHOWENV:
808             w = 1;
809             break;
810           case OF_SHOWFREE:
811             showfree = 1;
812             break;
813           case OF_SHOWFREED:
814             showfreed = 1;
815             break;
816           case OF_SHOWMAP:
817             showmap = 1;
818             break;
819           case OF_SHOWSYMBOLS:
820             showsymbols = 1;
821             break;
822           case OF_SHOWUNFREED:
823             showunfreed = 1;
824             break;
825           case OF_SMALLBOUND:
826             smallbound = __mp_optarg;
827             break;
828           case OF_THREADS:
829             t = 1;
830             break;
831           case OF_TRACE:
832             trace = 1;
833             break;
834           case OF_TRACEFILE:
835             tracefile = __mp_optarg;
836             break;
837           case OF_UNFREEDABORT:
838             unfreedabort = __mp_optarg;
839             break;
840           case OF_USEDEBUG:
841             usedebug = 1;
842             break;
843           case OF_USEMMAP:
844             usemmap = 1;
845             break;
846           case OF_VERSION:
847             v = 1;
848             break;
849           default:
850             e = 1;
851             break;
852         }
853     argc -= __mp_optindex;
854     argv += __mp_optindex;
855     if (v == 1)
856     {
857         fprintf(stdout, "%s %s\n%s %s\n\n", progname, PROGVERSION,
858                 __mp_copyright, __mp_author);
859         fputs("This is free software, and you are welcome to redistribute it "
860               "under certain\n", stdout);
861         fputs("conditions; see the GNU Library General Public License for "
862               "details.\n\n", stdout);
863         fputs("For the latest mpatrol release and documentation,\n", stdout);
864         fprintf(stdout, "visit %s.\n\n", __mp_homepage);
865     }
866     else if ((argc == 0) && (h == 0) && (w == 0))
867         e = 1;
868     if ((argc == 0) || (e == 1) || (h == 1) || (w == 1))
869     {
870         if ((e == 1) || (h == 1))
871         {
872             fprintf(stdout, "Usage: %s [options] <command> [arguments]\n\n",
873                     progname);
874             if (h == 0)
875                 fprintf(stdout, "Type `%s --help' for a complete list of "
876                         "options.\n", progname);
877             else
878                 __mp_showopts(options_table);
879         }
880         if (w == 1)
881             setoptions(x, 1);
882         if (e == 1)
883             exit(EXIT_FAILURE);
884         exit(EXIT_SUCCESS);
885     }
886     setoptions(x, 0);
887 #if MP_PRELOAD_SUPPORT
888     /* The dynamic linker on some UNIX systems supports requests for it to
889      * preload a specified list of shared libraries before running a process,
890      * via the MP_PRELOAD_NAME environment variable.  If any of the specified
891      * libraries only exist as archive libraries then the mpatrol library
892      * should be built to contain them since there is no way to preload an
893      * archive library.  However, this may have repercussions when building a
894      * shared library from position-dependent code.
895      */
896     if (d == 1)
897     {
898         if (t == 1)
899             p = addlibraries(MP_PRELOADMT_LIBS, NULL);
900         else
901             p = addlibraries(MP_PRELOAD_LIBS, NULL);
902         if (putenv(p))
903         {
904             fprintf(stderr, "%s: Cannot set environment variable `%s'\n",
905                     progname, MP_PRELOAD_NAME);
906             exit(EXIT_FAILURE);
907         }
908     }
909 #endif /* MP_PRELOAD_SUPPORT */
910     /* Prepare to run the command that is to be tested.  We return the exit
911      * status from the command after it has been run in case it was originally
912      * run from a script.
913      */
914     fflush(NULL);
915 #if TARGET == TARGET_UNIX
916     /* We need to use the fork() and execvp() combination on UNIX platforms
917      * in case we are using the -d option, in which case we cannot use system()
918      * since that will use the shell to invoke the command, possibly resulting
919      * in an extra log file tracing the shell itself.
920      */
921     if ((f = fork()) < 0)
922     {
923         fprintf(stderr, "%s: Cannot create process\n", progname);
924         exit(EXIT_FAILURE);
925     }
926     if (f == 0)
927     {
928         /* Programs invoked with the execvp() function will not contain the
929          * full path that they were run with in argv[0].  We need to patch
930          * this here since otherwise the mpatrol library is unlikely to find
931          * the executable file to read symbols from.  Hopefully argv is located
932          * on the stack, otherwise it may be read-only and cause the following
933          * assignment to crash.
934          */
935         argv[0] = execpath(argv[0]);
936         execvp(argv[0], argv);
937         fprintf(stderr, "%s: Cannot execute command `%s'\n", progname, argv[0]);
938         exit(EXIT_FAILURE);
939     }
940     while (waitpid(f, &r, 0) < 0)
941         if (errno != EINTR)
942         {
943             fprintf(stderr, "%s: Process could not be created\n", progname);
944             exit(EXIT_FAILURE);
945         }
946     if (!WIFEXITED(r))
947         exit(EXIT_FAILURE);
948     r = WEXITSTATUS(r);
949 #elif TARGET == TARGET_WINDOWS
950     /* To avoid extra overhead we call the spawnvp() function on Windows
951      * platforms.  However, for some strange reason, it concatenates all
952      * of its arguments into a single string with spaces in between arguments,
953      * but does NOT quote arguments with spaces in them!  For that reason,
954      * we'll have to do some extra work here.
955      */
956     if ((s = (char **) calloc(argc + 1, sizeof(char *))) == NULL)
957     {
958         fprintf(stderr, "%s: Out of memory\n", progname);
959         exit(EXIT_FAILURE);
960     }
961     for (i = 0; i < argc; i++)
962         if (strchr(argv[i], ' '))
963         {
964             l = strlen(argv[i]) + 3;
965             if ((s[i] = (char *) malloc(l)) == NULL)
966             {
967                 fprintf(stderr, "%s: Out of memory\n", progname);
968                 exit(EXIT_FAILURE);
969             }
970             sprintf(s[i], "\"%s\"", argv[i]);
971         }
972         else if ((s[i] = strdup(argv[i])) == NULL)
973         {
974             fprintf(stderr, "%s: Out of memory\n", progname);
975             exit(EXIT_FAILURE);
976         }
977     if ((r = spawnvp(_P_WAIT, s[0], s)) == -1)
978     {
979         fprintf(stderr, "%s: Cannot execute command `%s'\n", progname, argv[0]);
980         exit(EXIT_FAILURE);
981     }
982     for (i = 0; i < argc; i++)
983         free(s[i]);
984     free(s);
985 #else /* TARGET */
986     /* Because we are using system() to run the command, we need to ensure
987      * that all arguments that contain spaces are correctly quoted.  We also
988      * need to convert the argument array to a string, so we perform two
989      * passes.  The first pass counts the number of characters required for
990      * the final command string and allocates that amount of memory from the
991      * heap.  The second pass then fills in the command string and executes
992      * the command.
993      */
994     for (i = l = 0; i < argc; i++)
995     {
996         l += strlen(argv[i]) + 1;
997         if (strchr(argv[i], ' '))
998             l += 2;
999     }
1000     if ((s = (char *) malloc(l)) == NULL)
1001     {
1002         fprintf(stderr, "%s: Out of memory\n", progname);
1003         exit(EXIT_FAILURE);
1004     }
1005     for (i = l = 0; i < argc; i++)
1006         if (strchr(argv[i], ' '))
1007         {
1008             sprintf(s + l, "%s\"%s\"", (i > 0) ? " " : "", argv[i]);
1009             l += strlen(argv[i]) + (i > 0) + 2;
1010         }
1011         else
1012         {
1013             sprintf(s + l, "%s%s", (i > 0) ? " " : "", argv[i]);
1014             l += strlen(argv[i]) + (i > 0);
1015         }
1016     if ((r = system(s)) == -1)
1017     {
1018         fprintf(stderr, "%s: Cannot execute command `%s'\n", progname, argv[0]);
1019         exit(EXIT_FAILURE);
1020     }
1021     free(s);
1022 #if (TARGET == TARGET_AMIGA && defined(__GNUC__))
1023     /* When gcc is used on AmigaOS, the return value from system() is similar
1024      * to that on UNIX, so we need to modify it here.
1025      */
1026     r = ((unsigned int) r >> 8) & 0xFF;
1027 #endif /* TARGET && __GNUC__ */
1028 #endif /* TARGET */
1029     return r;
1030 }
1031