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