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 * Diagnostics. Most of the diagnostics go to a log file which is opened
25 * as soon as possible, but if this fails then the standard error is used.
26 * Many of these functions also deal with the formatting and displaying of
27 * certain data structures used by the mpatrol library.
28 */
29
30
31 #include "diag.h"
32 #if MP_THREADS_SUPPORT
33 #include "mutex.h"
34 #endif /* MP_THREADS_SUPPORT */
35 #include "utils.h"
36 #include "version.h"
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <time.h>
44 #if TARGET == TARGET_UNIX
45 #include <sys/types.h>
46 #include <sys/wait.h>
47 #include <unistd.h>
48 #endif /* TARGET */
49
50
51 #if MP_IDENT_SUPPORT
52 #ident "$Id: diag.c,v 1.104 2002/01/08 20:13:59 graeme Exp $"
53 #else /* MP_IDENT_SUPPORT */
54 static MP_CONST MP_VOLATILE char *diag_id = "$Id: diag.c,v 1.104 2002/01/08 20:13:59 graeme Exp $";
55 #endif /* MP_IDENT_SUPPORT */
56
57
58 #ifdef __cplusplus
59 extern "C"
60 {
61 #endif /* __cplusplus */
62
63
64 MP_API extern errortype __mp_errno;
65
66
67 /* The file pointer to the log file. This should not really be a file scope
68 * variable as it prevents this module from being re-entrant.
69 */
70
71 static FILE *logfile;
72
73
74 /* The byte array used for file buffering purposes. Care must be taken to
75 * ensure that this buffer is not used for more than one file and this should
76 * not really be a file scope variable as it prevents this module from being
77 * re-entrant.
78 */
79
80 static char buffer[256];
81
82
83 /* The current date and time at which the log file is being created. This
84 * must be fixed once it has been determined since it may be used in several
85 * places.
86 */
87
88 static time_t currenttime;
89
90
91 /* The total error and warning counts. These should really be reset after
92 * every initialisation of the library, but as we are not currently allowing
93 * library to be reinitialised, this doesn't matter.
94 */
95
96 static unsigned long errors, warnings;
97
98
99 /* This array should always be kept in step with the errortype enumeration.
100 */
101
102 MP_GLOBAL errorinfo __mp_errordetails[ET_MAX + 1] =
103 {
104 {"NOERR", "no error",
105 "no error has occurred"},
106 {"ALLOVF", "allocation overflow",
107 "allocation " MP_POINTER " has a corrupted overflow buffer at "
108 MP_POINTER},
109 {"ALLZER", "allocation too small",
110 "attempt to create an allocation of size 0"},
111 {"BADALN", "illegal alignment",
112 "alignment %lu is not a power of two"},
113 {"FRDCOR", "freed memory corruption",
114 "freed allocation " MP_POINTER " has memory corruption at " MP_POINTER},
115 {"FRDOPN", "illegal operation on freed memory",
116 "attempt to perform operation on freed memory"},
117 {"FRDOVF", "freed allocation overflow",
118 "freed allocation " MP_POINTER " has a corrupted overflow buffer at "
119 MP_POINTER},
120 {"FRECOR", "free memory corruption",
121 "free memory corruption at " MP_POINTER},
122 {"FREMRK", "freeing a marked allocation",
123 "attempt to free marked memory allocation " MP_POINTER},
124 {"FRENUL", "freeing a NULL pointer",
125 "attempt to free a NULL pointer"},
126 {"FREOPN", "illegal operation on free memory",
127 "attempt to perform operation on free memory\n"},
128 {"ILLMEM", "illegal memory access",
129 NULL},
130 {"INCOMP", "incompatible functions",
131 MP_POINTER " was allocated with %s"},
132 {"MAXALN", "alignment too large",
133 "alignment %lu is greater than the system page size"},
134 {"MISMAT", "allocated pointer mismatch",
135 MP_POINTER " does not match allocation of " MP_POINTER},
136 {"NOTALL", "no such allocation",
137 MP_POINTER " has not been allocated"},
138 {"NULOPN", "illegal operation on a NULL pointer",
139 "attempt to perform operation on a NULL pointer\n"},
140 {"OUTMEM", "out of memory",
141 "out of memory"},
142 {"PRVFRD", "allocation already freed",
143 MP_POINTER " was freed with %s"},
144 {"RNGOVF", "range overflow",
145 "range [" MP_POINTER "," MP_POINTER "] overflows [" MP_POINTER ","
146 MP_POINTER "]"},
147 {"RNGOVL", "range overlap",
148 "range [" MP_POINTER "," MP_POINTER "] overlaps [" MP_POINTER ","
149 MP_POINTER "]"},
150 {"RSZNUL", "reallocating a NULL pointer",
151 "attempt to resize a NULL pointer"},
152 {"RSZZER", "reallocation too small",
153 "attempt to resize an allocation to size 0"},
154 {"STROVF", "string overflow",
155 "string " MP_POINTER " overflows [" MP_POINTER "," MP_POINTER "]"},
156 {"ZERALN", "alignment too small",
157 "alignment 0 is invalid"},
158 {"INTRNL", "internal error",
159 "internal error"}
160 };
161
162
163 /* This array should always be kept in step with the alloctype enumeration.
164 * Note that AT_MAX is used in diagnostic messages to specify that the
165 * message is internal and did not come from a call to a normal memory
166 * allocation function.
167 */
168
169 MP_GLOBAL char *__mp_functionnames[AT_MAX + 1] =
170 {
171 "malloc",
172 "calloc",
173 "memalign",
174 "valloc",
175 "pvalloc",
176 "alloca",
177 "strdup",
178 "strndup",
179 "strsave",
180 "strnsave",
181 "strdupa",
182 "strndupa",
183 "realloc",
184 "reallocf",
185 "recalloc",
186 "expand",
187 "free",
188 "cfree",
189 "dealloca",
190 "xmalloc",
191 "xcalloc",
192 "xstrdup",
193 "xrealloc",
194 "xfree",
195 "operator new",
196 "operator new[]",
197 "operator delete",
198 "operator delete[]",
199 "memset",
200 "bzero",
201 "memccpy",
202 "memcpy",
203 "memmove",
204 "bcopy",
205 "memchr",
206 "memmem",
207 "memcmp",
208 "bcmp",
209 "check"
210 };
211
212
213 /* This array should always be kept in step with the logtype enumeration.
214 * Note that LT_MAX is used to indicate that the variant field of the loginfo
215 * structure is not used.
216 */
217
218 MP_GLOBAL char *__mp_lognames[LT_MAX + 1] =
219 {
220 "ALLOC",
221 "REALLOC",
222 "FREE",
223 "MEMSET",
224 "MEMCOPY",
225 "MEMFIND",
226 "MEMCMP",
227 "LOG"
228 };
229
230
231 /* The flags used to control the diagnostics from the mpatrol library.
232 */
233
234 MP_GLOBAL unsigned long __mp_diagflags;
235
236
237 /* Process a file name, expanding any special characters.
238 */
239
240 static
241 void
processfile(meminfo * m,char * s,char * b,size_t l)242 processfile(meminfo *m, char *s, char *b, size_t l)
243 {
244 char *p, *t;
245 size_t i;
246
247 for (i = 0; (i < l - 1) && (*s != '\0'); i++, s++)
248 if (*s == '%')
249 switch (s[1])
250 {
251 case 'd':
252 /* Replace %d with the current date in the form YYYYMMDD.
253 */
254 if (!currenttime)
255 currenttime = time(NULL);
256 if (currenttime != (time_t) -1)
257 strftime(b + i, l - i, "%Y%m%d", localtime(¤ttime));
258 else
259 strcpy(b + i, "today");
260 i += strlen(b + i) - 1;
261 s++;
262 break;
263 case 'f':
264 /* Replace %f with the program filename, with all path
265 * separation characters replaced by underscores.
266 */
267 if (((p = m->prog) == NULL) || (*p == '\0'))
268 p = "mpatrol";
269 while (*p != '\0')
270 {
271 #if TARGET == TARGET_UNIX
272 if (*p == '/')
273 #elif TARGET == TARGET_AMIGA
274 if ((*p == ':') || (*p == '/'))
275 #else /* TARGET */
276 if ((*p == ':') || (*p == '/') || (*p == '\\'))
277 #endif /* TARGET */
278 b[i++] = '_';
279 else
280 b[i++] = *p;
281 p++;
282 }
283 i--;
284 s++;
285 break;
286 case 'n':
287 /* Replace %n with the current process identifier.
288 */
289 sprintf(b + i, "%lu", __mp_processid());
290 i += strlen(b + i) - 1;
291 s++;
292 break;
293 case 'p':
294 /* Replace %p with the program name.
295 */
296 if (p = m->prog)
297 #if TARGET == TARGET_UNIX
298 while (t = strchr(p, '/'))
299 #elif TARGET == TARGET_AMIGA
300 while (t = strpbrk(p, ":/"))
301 #else /* TARGET */
302 while (t = strpbrk(p, ":/\\"))
303 #endif /* TARGET */
304 p = t + 1;
305 if ((p == NULL) || (*p == '\0'))
306 p = "mpatrol";
307 strcpy(b + i, p);
308 i += strlen(p) - 1;
309 s++;
310 break;
311 case 't':
312 /* Replace %t with the current time in the form HHMMSS.
313 */
314 if (!currenttime)
315 currenttime = time(NULL);
316 if (currenttime != (time_t) -1)
317 strftime(b + i, l - i, "%H%M%S", localtime(¤ttime));
318 else
319 strcpy(b + i, "now");
320 i += strlen(b + i) - 1;
321 s++;
322 break;
323 default:
324 if (s[1] != '\0')
325 b[i++] = *s++;
326 b[i] = *s;
327 break;
328 }
329 else
330 b[i] = *s;
331 b[i] = '\0';
332 }
333
334
335 /* Process the log file name, expanding any special characters.
336 * Note that this function is not currently re-entrant.
337 */
338
339 MP_GLOBAL
340 char *
__mp_logfile(meminfo * m,char * s)341 __mp_logfile(meminfo *m, char *s)
342 {
343 static char b[256];
344 char p[256];
345 char *d;
346
347 if ((s != NULL) && ((strcmp(s, "stderr") == 0) ||
348 (strcmp(s, "stdout") == 0)))
349 return s;
350 if ((d = getenv(MP_LOGDIR)) && (*d != '\0') && ((s == NULL) ||
351 #if TARGET == TARGET_UNIX
352 !strchr(s, '/')))
353 #elif TARGET == TARGET_AMIGA
354 !strpbrk(s, ":/")))
355 #else /* TARGET */
356 !strpbrk(s, ":/\\")))
357 #endif /* TARGET */
358 {
359 /* If the environment variable specified with MP_LOGDIR is set and no
360 * log file name has already been given then we use a special format
361 * for the name of the output file so that all such files will be
362 * written to that directory, which must exist.
363 */
364 if (s == NULL)
365 s = "%n.%p.log";
366 #if TARGET == TARGET_UNIX
367 sprintf(p, "%s/%s", d, s);
368 #elif TARGET == TARGET_AMIGA
369 if ((d[strlen(d) - 1] == ':') || (d[strlen(d) - 1] == '/'))
370 sprintf(p, "%s%s", d, s);
371 else
372 sprintf(p, "%s/%s", d, s);
373 #else /* TARGET */
374 sprintf(p, "%s\\%s", d, s);
375 #endif /* TARGET */
376 processfile(m, p, b, sizeof(b));
377 }
378 else
379 {
380 if (s == NULL)
381 s = MP_LOGFILE;
382 processfile(m, s, b, sizeof(b));
383 }
384 return b;
385 }
386
387
388 /* Process the profiling output file name, expanding any special characters.
389 * Note that this function is not currently re-entrant.
390 */
391
392 MP_GLOBAL
393 char *
__mp_proffile(meminfo * m,char * s)394 __mp_proffile(meminfo *m, char *s)
395 {
396 static char b[256];
397 char p[256];
398 char *d;
399
400 if ((s != NULL) && ((strcmp(s, "stderr") == 0) ||
401 (strcmp(s, "stdout") == 0)))
402 return s;
403 if ((d = getenv(MP_PROFDIR)) && (*d != '\0') && ((s == NULL) ||
404 #if TARGET == TARGET_UNIX
405 !strchr(s, '/')))
406 #elif TARGET == TARGET_AMIGA
407 !strpbrk(s, ":/")))
408 #else /* TARGET */
409 !strpbrk(s, ":/\\")))
410 #endif /* TARGET */
411 {
412 /* If the environment variable specified with MP_PROFDIR is set and no
413 * profiling output file name has already been given then we use a
414 * special format for the name of the output file so that all such
415 * files will be written to that directory, which must exist.
416 */
417 if (s == NULL)
418 s = "%n.%p.out";
419 #if TARGET == TARGET_UNIX
420 sprintf(p, "%s/%s", d, s);
421 #elif TARGET == TARGET_AMIGA
422 if ((d[strlen(d) - 1] == ':') || (d[strlen(d) - 1] == '/'))
423 sprintf(p, "%s%s", d, s);
424 else
425 sprintf(p, "%s/%s", d, s);
426 #else /* TARGET */
427 sprintf(p, "%s\\%s", d, s);
428 #endif /* TARGET */
429 processfile(m, p, b, sizeof(b));
430 }
431 else
432 {
433 if (s == NULL)
434 s = MP_PROFFILE;
435 processfile(m, s, b, sizeof(b));
436 }
437 return b;
438 }
439
440
441 /* Process the tracing output file name, expanding any special characters.
442 * Note that this function is not currently re-entrant.
443 */
444
445 MP_GLOBAL
446 char *
__mp_tracefile(meminfo * m,char * s)447 __mp_tracefile(meminfo *m, char *s)
448 {
449 static char b[256];
450 char p[256];
451 char *d;
452
453 if ((s != NULL) && ((strcmp(s, "stderr") == 0) ||
454 (strcmp(s, "stdout") == 0)))
455 return s;
456 if ((d = getenv(MP_TRACEDIR)) && (*d != '\0') && ((s == NULL) ||
457 #if TARGET == TARGET_UNIX
458 !strchr(s, '/')))
459 #elif TARGET == TARGET_AMIGA
460 !strpbrk(s, ":/")))
461 #else /* TARGET */
462 !strpbrk(s, ":/\\")))
463 #endif /* TARGET */
464 {
465 /* If the environment variable specified with MP_TRACEDIR is set and no
466 * tracing output file name has already been given then we use a
467 * special format for the name of the output file so that all such
468 * files will be written to that directory, which must exist.
469 */
470 if (s == NULL)
471 s = "%n.%p.trace";
472 #if TARGET == TARGET_UNIX
473 sprintf(p, "%s/%s", d, s);
474 #elif TARGET == TARGET_AMIGA
475 if ((d[strlen(d) - 1] == ':') || (d[strlen(d) - 1] == '/'))
476 sprintf(p, "%s%s", d, s);
477 else
478 sprintf(p, "%s/%s", d, s);
479 #else /* TARGET */
480 sprintf(p, "%s\\%s", d, s);
481 #endif /* TARGET */
482 processfile(m, p, b, sizeof(b));
483 }
484 else
485 {
486 if (s == NULL)
487 s = MP_TRACEFILE;
488 processfile(m, s, b, sizeof(b));
489 }
490 return b;
491 }
492
493
494 /* Attempt to open the log file.
495 */
496
497 MP_GLOBAL
498 int
__mp_openlogfile(char * s)499 __mp_openlogfile(char *s)
500 {
501 /* The log file name can also be named as stderr and stdout which will go
502 * to the standard error and standard output streams respectively.
503 */
504 if ((s == NULL) || (strcmp(s, "stderr") == 0))
505 logfile = stderr;
506 else if (strcmp(s, "stdout") == 0)
507 logfile = stdout;
508 else if ((logfile = fopen(s, "w")) == NULL)
509 {
510 /* Because logfile is NULL, the __mp_error() function will open the log
511 * file as stderr, which should always work.
512 */
513 logfile = stderr;
514 __mp_error(ET_MAX, AT_MAX, NULL, 0, "%s: cannot open file\n", s);
515 return 0;
516 }
517 /* Attempt to set the stream buffer for the log file. This is done here so
518 * that we won't get recursive memory allocations if the standard library
519 * tries to allocate space for the stream buffer.
520 */
521 if ((logfile == stderr) ||
522 #if defined(HAVE_CONFIG_H) && defined(SETVBUF_REVERSED)
523 setvbuf(logfile, _IOLBF, buffer, sizeof(buffer)))
524 #else /* HAVE_CONFIG_H && SETVBUF_REVERSED */
525 setvbuf(logfile, buffer, _IOLBF, sizeof(buffer)))
526 #endif /* HAVE_CONFIG_H && SETVBUF_REVERSED */
527 /* If that failed, or the log file is stderr, then we set the buffering
528 * mode for the log file to none. The standard error stream is not
529 * guaranteed to be unbuffered by default on all systems.
530 */
531 #if defined(HAVE_CONFIG_H) && defined(SETVBUF_REVERSED)
532 setvbuf(logfile, _IONBF, NULL, 0);
533 #else /* HAVE_CONFIG_H && SETVBUF_REVERSED */
534 setvbuf(logfile, NULL, _IONBF, 0);
535 #endif /* HAVE_CONFIG_H && SETVBUF_REVERSED */
536 if ((__mp_diagflags & FLG_HTMLNEXT) && (s != NULL))
537 {
538 __mp_diagflags |= FLG_HTML;
539 __mp_diagtag("<HTML>\n");
540 __mp_diagtag("<HEAD>\n");
541 __mp_diagtag("<META NAME=\"GENERATOR\" CONTENT=\"" MP_VERSION "\">\n");
542 __mp_diagtag("<TITLE>");
543 __mp_diag("mpatrol log");
544 __mp_diagtag("</TITLE>\n");
545 __mp_diagtag("</HEAD>\n");
546 __mp_diagtag("<BODY>\n");
547 __mp_diagtag("<H3>");
548 __mp_diag("mpatrol log");
549 __mp_diagtag("</H3>\n");
550 __mp_diagtag("<P>\n");
551 }
552 else
553 __mp_diagflags &= ~FLG_HTML;
554 return 1;
555 }
556
557
558 /* Attempt to close the log file.
559 */
560
561 MP_GLOBAL
562 int
__mp_closelogfile(void)563 __mp_closelogfile(void)
564 {
565 int r;
566
567 r = 1;
568 if (__mp_diagflags & FLG_HTML)
569 {
570 __mp_diagtag("</BODY>\n");
571 __mp_diagtag("</HTML>\n");
572 }
573 if ((logfile == NULL) || (logfile == stderr) || (logfile == stdout))
574 {
575 /* We don't want to close the stderr or stdout file streams so
576 * we just flush them instead. If the log file hasn't been set,
577 * this will just flush all open output files.
578 */
579 if (fflush(logfile))
580 r = 0;
581 }
582 else if (fclose(logfile))
583 r = 0;
584 logfile = NULL;
585 return r;
586 }
587
588
589 /* Sends a diagnostic message to the log file.
590 */
591
592 MP_GLOBAL
593 void
__mp_diag(char * s,...)594 __mp_diag(char *s, ...)
595 {
596 char b[2048];
597 char *t;
598 va_list v;
599 char c;
600
601 if (logfile == NULL)
602 __mp_openlogfile(NULL);
603 va_start(v, s);
604 if (__mp_diagflags & FLG_HTML)
605 vsprintf(b, s, v);
606 else
607 vfprintf(logfile, s, v);
608 va_end(v);
609 /* If we are outputting HTML then we must filter the diagnostics to ensure
610 * that we replace <, >, & and " with <, >, & and " respectively.
611 */
612 if (__mp_diagflags & FLG_HTML)
613 for (s = t = b; t != NULL; s = t + 1)
614 {
615 if (t = strpbrk(s, "<>&\""))
616 {
617 c = *t;
618 *t = '\0';
619 }
620 if (*s != '\0')
621 fputs(s, logfile);
622 if (t != NULL)
623 switch (c)
624 {
625 case '<':
626 fputs("<", logfile);
627 break;
628 case '>':
629 fputs(">", logfile);
630 break;
631 case '&':
632 fputs("&", logfile);
633 break;
634 case '"':
635 fputs(""", logfile);
636 break;
637 default:
638 break;
639 }
640 }
641 }
642
643
644 /* Sends an HTML tag to the log file.
645 */
646
647 MP_GLOBAL
648 void
__mp_diagtag(char * s)649 __mp_diagtag(char *s)
650 {
651 if (logfile == NULL)
652 __mp_openlogfile(NULL);
653 fputs(s, logfile);
654 }
655
656
657 /* Sends a warning message to the log file.
658 */
659
660 MP_GLOBAL
661 void
__mp_warn(errortype e,alloctype f,char * n,unsigned long l,char * s,...)662 __mp_warn(errortype e, alloctype f, char *n, unsigned long l, char *s, ...)
663 {
664 va_list v;
665
666 if (logfile == NULL)
667 __mp_openlogfile(NULL);
668 __mp_diag("WARNING: ");
669 if (e != ET_MAX)
670 __mp_diag("[%s]: ", __mp_errordetails[e].code);
671 if (f != AT_MAX)
672 __mp_diag("%s: ", __mp_functionnames[f]);
673 va_start(v, s);
674 if ((s == NULL) && (__mp_errordetails[e].format != NULL))
675 vfprintf(logfile, __mp_errordetails[e].format, v);
676 else
677 vfprintf(logfile, s, v);
678 va_end(v);
679 __mp_diag("\n");
680 if (((__mp_diagflags & FLG_EDIT) || (__mp_diagflags & FLG_LIST)) &&
681 (n != NULL))
682 {
683 if (logfile != stderr)
684 {
685 fputs("WARNING: ", stderr);
686 if (e != ET_MAX)
687 fprintf(stderr, "[%s]: ", __mp_errordetails[e].code);
688 if (f != AT_MAX)
689 fprintf(stderr, "%s: ", __mp_functionnames[f]);
690 va_start(v, s);
691 if ((s == NULL) && (__mp_errordetails[e].format != NULL))
692 vfprintf(stderr, __mp_errordetails[e].format, v);
693 else
694 vfprintf(stderr, s, v);
695 va_end(v);
696 fputc('\n', stderr);
697 }
698 if (__mp_editfile(n, l, ((__mp_diagflags & FLG_LIST) != 0)) == -1)
699 fprintf(stderr, "ERROR: problems %sing file `%s'\n",
700 (__mp_diagflags & FLG_LIST) ? "list" : "edit", n);
701 }
702 __mp_errno = e;
703 warnings++;
704 }
705
706
707 /* Sends an error message to the log file.
708 */
709
710 MP_GLOBAL
711 void
__mp_error(errortype e,alloctype f,char * n,unsigned long l,char * s,...)712 __mp_error(errortype e, alloctype f, char *n, unsigned long l, char *s, ...)
713 {
714 va_list v;
715
716 if (logfile == NULL)
717 __mp_openlogfile(NULL);
718 __mp_diag("ERROR: ");
719 if (e != ET_MAX)
720 __mp_diag("[%s]: ", __mp_errordetails[e].code);
721 if (f != AT_MAX)
722 __mp_diag("%s: ", __mp_functionnames[f]);
723 va_start(v, s);
724 if ((s == NULL) && (__mp_errordetails[e].format != NULL))
725 vfprintf(logfile, __mp_errordetails[e].format, v);
726 else
727 vfprintf(logfile, s, v);
728 va_end(v);
729 __mp_diag("\n");
730 if (((__mp_diagflags & FLG_EDIT) || (__mp_diagflags & FLG_LIST)) &&
731 (n != NULL))
732 {
733 if (logfile != stderr)
734 {
735 fputs("ERROR: ", stderr);
736 if (e != ET_MAX)
737 fprintf(stderr, "[%s]: ", __mp_errordetails[e].code);
738 if (f != AT_MAX)
739 fprintf(stderr, "%s: ", __mp_functionnames[f]);
740 va_start(v, s);
741 if ((s == NULL) && (__mp_errordetails[e].format != NULL))
742 vfprintf(stderr, __mp_errordetails[e].format, v);
743 else
744 vfprintf(stderr, s, v);
745 va_end(v);
746 fputc('\n', stderr);
747 }
748 if (__mp_editfile(n, l, ((__mp_diagflags & FLG_LIST) != 0)) == -1)
749 fprintf(stderr, "ERROR: problems %sing file `%s'\n",
750 (__mp_diagflags & FLG_LIST) ? "list" : "edit", n);
751 }
752 __mp_errno = e;
753 errors++;
754 }
755
756
757 /* Invoke a text editor on a given source file at a specific line.
758 */
759
760 MP_GLOBAL
761 int
__mp_editfile(char * f,unsigned long l,int d)762 __mp_editfile(char *f, unsigned long l, int d)
763 {
764 #if TARGET == TARGET_UNIX
765 #if MP_PRELOAD_SUPPORT
766 char s[256];
767 #endif /* MP_PRELOAD_SUPPORT */
768 char t[32];
769 char *v[5];
770 pid_t p;
771 int r;
772 #endif /* TARGET */
773
774 #if TARGET == TARGET_UNIX
775 #if MP_PRELOAD_SUPPORT
776 sprintf(s, "%s=", MP_PRELOAD_NAME);
777 #endif /* MP_PRELOAD_SUPPORT */
778 sprintf(t, "%lu", l);
779 if ((p = fork()) < 0)
780 return -1;
781 if (p == 0)
782 {
783 #if MP_PRELOAD_SUPPORT
784 /* We have to ensure that we don't end up debugging the editor and its
785 * child processes as well! Hopefully, if we ensure that the relevant
786 * environment variable is set then putenv() will not use malloc() to
787 * expand the environment.
788 */
789 if (getenv(MP_PRELOAD_NAME))
790 putenv(s);
791 #endif /* MP_PRELOAD_SUPPORT */
792 v[0] = MP_EDITOR;
793 if (d == 0)
794 {
795 v[1] = f;
796 v[2] = t;
797 v[3] = NULL;
798 }
799 else
800 {
801 v[1] = "--listing";
802 v[2] = f;
803 v[3] = t;
804 v[4] = NULL;
805 }
806 execvp(v[0], v);
807 _exit(EXIT_FAILURE);
808 }
809 while (waitpid(p, &r, 0) < 0)
810 if (errno != EINTR)
811 return -1;
812 if (!WIFEXITED(r) || (WEXITSTATUS(r) != 0))
813 return -1;
814 return 1;
815 #else /* TARGET */
816 return 0;
817 #endif /* TARGET */
818 }
819
820
821 /* Calculate the filename to use for an allocation contents file.
822 */
823
824 static
825 char *
allocfile(char * s,unsigned long n)826 allocfile(char *s, unsigned long n)
827 {
828 static char b[1024];
829
830 if (s == NULL)
831 s = MP_CONTENTSFILE;
832 sprintf(b, "%s.%lu", s, n);
833 return b;
834 }
835
836
837 /* Read in an allocation contents file.
838 */
839
840 MP_GLOBAL
841 int
__mp_readalloc(char * s,unsigned long n,void * a,size_t l)842 __mp_readalloc(char *s, unsigned long n, void *a, size_t l)
843 {
844 FILE *f;
845 int r;
846
847 r = 0;
848 if (f = fopen(allocfile(s, n), "rb"))
849 {
850 if (fread(a, sizeof(char), l, f) == l)
851 r = 1;
852 fclose(f);
853 }
854 return r;
855 }
856
857
858 /* Write out an allocation contents file.
859 */
860
861 MP_GLOBAL
862 int
__mp_writealloc(char * s,unsigned long n,void * a,size_t l)863 __mp_writealloc(char *s, unsigned long n, void *a, size_t l)
864 {
865 FILE *f;
866 char *t;
867 int r;
868
869 r = 0;
870 t = allocfile(s, n);
871 if (f = fopen(t, "wb"))
872 {
873 if (fwrite(a, sizeof(char), l, f) == l)
874 r = 1;
875 fclose(f);
876 if (r == 0)
877 remove(t);
878 }
879 return r;
880 }
881
882
883 /* Compare an allocation contents file with the contents currently in memory.
884 */
885
886 MP_GLOBAL
887 long
__mp_cmpalloc(char * s,unsigned long n,void * a,size_t l)888 __mp_cmpalloc(char *s, unsigned long n, void *a, size_t l)
889 {
890 FILE *f;
891 char *p;
892 long r;
893 int c;
894
895 r = -1;
896 if (f = fopen(allocfile(s, n), "rb"))
897 {
898 r = 0;
899 p = (char *) a;
900 while (((c = fgetc(f)) != EOF) && (l != 0))
901 {
902 if ((unsigned char) *p != (unsigned char) c)
903 {
904 if (r == 0)
905 __mp_diag("allocation %lu (" MP_POINTER ") differences:\n",
906 n, a);
907 __mp_diag("\t" MP_POINTER " %02X -> %02X (offset %lu)\n", p,
908 (unsigned char) c, (unsigned char) *p,
909 (unsigned long) (p - (char *) a));
910 r++;
911 }
912 p++;
913 l--;
914 }
915 if (c != EOF)
916 {
917 __mp_diag("allocation %lu (" MP_POINTER ") has decreased in size\n",
918 n, a);
919 r++;
920 }
921 else if (l != 0)
922 {
923 __mp_diag("allocation %lu (" MP_POINTER ") has increased in size\n",
924 n, a);
925 r++;
926 }
927 if (r != 0)
928 __mp_diag("\n");
929 fclose(f);
930 }
931 return r;
932 }
933
934
935 /* Remove an allocation contents file.
936 */
937
938 MP_GLOBAL
939 int
__mp_remalloc(char * s,unsigned long n)940 __mp_remalloc(char *s, unsigned long n)
941 {
942 if (remove(allocfile(s, n)))
943 return 0;
944 return 1;
945 }
946
947
948 /* Display up to sixteen bytes of memory in one line.
949 */
950
951 static
952 void
printline(char * s,size_t l)953 printline(char *s, size_t l)
954 {
955 size_t i;
956
957 __mp_diag("\t" MP_POINTER " ", s);
958 for (i = 0; i < 16; i++)
959 {
960 if (i < l)
961 __mp_diag("%02X", (unsigned char) s[i]);
962 else
963 __mp_diag(" ");
964 if (i % 4 == 3)
965 __mp_diag(" ");
966 }
967 __mp_diag(" ");
968 for (i = 0; i < l; i++)
969 if (isprint(s[i]))
970 __mp_diag("%c", s[i]);
971 else
972 __mp_diag(".");
973 __mp_diag("\n");
974 }
975
976
977 /* Display a hex dump of a specified memory location and length.
978 */
979
980 MP_GLOBAL
981 void
__mp_printmemory(void * p,size_t l)982 __mp_printmemory(void *p, size_t l)
983 {
984 while (l >= 16)
985 {
986 printline((char *) p, 16);
987 p = (char *) p + 16;
988 l -= 16;
989 }
990 if (l > 0)
991 printline((char *) p, l);
992 }
993
994
995 /* Display a size in bytes.
996 */
997
998 MP_GLOBAL
999 void
__mp_printsize(size_t l)1000 __mp_printsize(size_t l)
1001 {
1002 __mp_diag("%lu byte", l);
1003 if (l != 1)
1004 __mp_diag("s");
1005 }
1006
1007
1008 /* Display the type of memory allocation along with the allocation count
1009 * and reallocation count.
1010 */
1011
1012 MP_GLOBAL
1013 void
__mp_printtype(infonode * n)1014 __mp_printtype(infonode *n)
1015 {
1016 __mp_diag("{%s:%lu:%lu}", __mp_functionnames[n->data.type], n->data.alloc,
1017 n->data.realloc);
1018 }
1019
1020
1021 /* Display the function name, file name and line number where a memory
1022 * allocation took place. Also display the thread identifier if the thread
1023 * safe library is being used.
1024 */
1025
1026 MP_GLOBAL
1027 void
__mp_printloc(infonode * n)1028 __mp_printloc(infonode *n)
1029 {
1030 __mp_diag("[");
1031 #if MP_THREADS_SUPPORT
1032 __mp_diag("%lu|", n->data.thread);
1033 #endif /* MP_THREADS_SUPPORT */
1034 if (n->data.func)
1035 __mp_diag("%s", n->data.func);
1036 else
1037 __mp_diag("-");
1038 __mp_diag("|");
1039 if (n->data.file)
1040 __mp_diag("%s", n->data.file);
1041 else
1042 __mp_diag("-");
1043 __mp_diag("|");
1044 if (n->data.line)
1045 __mp_diag("%lu", n->data.line);
1046 else
1047 __mp_diag("-");
1048 __mp_diag("]");
1049 }
1050
1051
1052 /* Display the type of data that is stored in the memory allocation along
1053 * with the number of objects stored.
1054 */
1055
1056 MP_GLOBAL
1057 void
__mp_printtypeinfo(infonode * n,size_t s)1058 __mp_printtypeinfo(infonode *n, size_t s)
1059 {
1060 __mp_diag("(%s", n->data.typestr);
1061 if ((s /= n->data.typesize) > 1)
1062 __mp_diag(" x %lu", s);
1063 __mp_diag(")");
1064 }
1065
1066
1067 /* Display the name of a symbol associated with a particular address.
1068 */
1069
1070 MP_GLOBAL
1071 void
__mp_printsymbol(symhead * y,void * a)1072 __mp_printsymbol(symhead *y, void *a)
1073 {
1074 symnode *n;
1075 char *s, *t;
1076 unsigned long u;
1077
1078 __mp_findsource(y, (char *) a - 1, &s, &t, &u);
1079 if (n = __mp_findsymbol(y, a))
1080 {
1081 if (__mp_diagflags & FLG_HTML)
1082 __mp_diagtag("<TT>");
1083 __mp_diag("%s", n->data.name);
1084 if (__mp_diagflags & FLG_HTML)
1085 __mp_diagtag("</TT>");
1086 if (a != n->data.addr)
1087 __mp_diag("%+ld", (char *) a - (char *) n->data.addr);
1088 }
1089 else if (s != NULL)
1090 {
1091 if (__mp_diagflags & FLG_HTML)
1092 __mp_diagtag("<TT>");
1093 __mp_diag("%s", s);
1094 if (__mp_diagflags & FLG_HTML)
1095 __mp_diagtag("</TT>");
1096 }
1097 else
1098 __mp_diag("???");
1099 if ((t != NULL) && (u != 0))
1100 {
1101 __mp_diag(" at ");
1102 if (__mp_diagflags & FLG_HTML)
1103 __mp_diagtag("<TT>");
1104 __mp_diag("%s", t);
1105 if (__mp_diagflags & FLG_HTML)
1106 __mp_diagtag("</TT>");
1107 __mp_diag(":%lu", u);
1108 }
1109 }
1110
1111
1112 /* Display details of all of the symbols that have been read.
1113 */
1114
1115 MP_GLOBAL
1116 void
__mp_printsymbols(symhead * y)1117 __mp_printsymbols(symhead *y)
1118 {
1119 symnode *n;
1120
1121 if (__mp_diagflags & FLG_HTML)
1122 __mp_diagtag("<HR>");
1123 __mp_diag("\nsymbols read: %lu\n", y->dtree.size);
1124 if (__mp_diagflags & FLG_HTML)
1125 {
1126 __mp_diagtag("<BLOCKQUOTE>\n");
1127 __mp_diagtag("<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=0>\n");
1128 }
1129 for (n = (symnode *) __mp_minimum(y->dtree.root); n != NULL;
1130 n = (symnode *) __mp_successor(&n->data.node))
1131 {
1132 if (__mp_diagflags & FLG_HTML)
1133 __mp_diagtag("<TR>\n");
1134 if (n->data.size == 0)
1135 if (__mp_diagflags & FLG_HTML)
1136 {
1137 __mp_diagtag("<TD>");
1138 __mp_diagtag("</TD>\n");
1139 __mp_diagtag("<TD>");
1140 __mp_diag(MP_POINTER, n->data.addr);
1141 __mp_diagtag("</TD>\n");
1142 }
1143 else
1144 {
1145 #if ENVIRON == ENVIRON_64
1146 __mp_diag("\t");
1147 #endif /* ENVIRON */
1148 __mp_diag("\t " MP_POINTER, n->data.addr);
1149 }
1150 else
1151 if (__mp_diagflags & FLG_HTML)
1152 {
1153 __mp_diagtag("<TD ALIGN=RIGHT>");
1154 __mp_diag(MP_POINTER "-", n->data.addr);
1155 __mp_diagtag("</TD>\n");
1156 __mp_diagtag("<TD>");
1157 __mp_diag(MP_POINTER, (char *) n->data.addr + n->data.size - 1);
1158 __mp_diagtag("</TD>\n");
1159 }
1160 else
1161 __mp_diag(" " MP_POINTER "-" MP_POINTER, n->data.addr,
1162 (char *) n->data.addr + n->data.size - 1);
1163 if (__mp_diagflags & FLG_HTML)
1164 {
1165 __mp_diagtag("<TD>");
1166 __mp_diagtag("<TT>");
1167 }
1168 else
1169 __mp_diag(" ");
1170 __mp_diag("%s", n->data.name);
1171 if (__mp_diagflags & FLG_HTML)
1172 __mp_diagtag("</TT>");
1173 __mp_diag(" [");
1174 if (__mp_diagflags & FLG_HTML)
1175 __mp_diagtag("<TT>");
1176 __mp_diag("%s", n->data.file);
1177 if (__mp_diagflags & FLG_HTML)
1178 __mp_diagtag("</TT>");
1179 __mp_diag("] (");
1180 __mp_printsize(n->data.size);
1181 __mp_diag(")");
1182 if (__mp_diagflags & FLG_HTML)
1183 {
1184 __mp_diagtag("</TT>");
1185 __mp_diagtag("</TD>\n");
1186 __mp_diagtag("</TR>");
1187 }
1188 __mp_diag("\n");
1189 }
1190 if (__mp_diagflags & FLG_HTML)
1191 {
1192 __mp_diagtag("</TABLE>\n");
1193 __mp_diagtag("</BLOCKQUOTE>\n");
1194 }
1195 }
1196
1197
1198 /* Display the call stack details for an address node.
1199 */
1200
1201 MP_GLOBAL
1202 void
__mp_printaddrs(symhead * y,addrnode * n)1203 __mp_printaddrs(symhead *y, addrnode *n)
1204 {
1205 if (__mp_diagflags & FLG_HTML)
1206 {
1207 __mp_diagtag("<BLOCKQUOTE>\n");
1208 __mp_diagtag("<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=0>\n");
1209 }
1210 while (n != NULL)
1211 {
1212 if (__mp_diagflags & FLG_HTML)
1213 {
1214 __mp_diagtag("<TR>\n");
1215 __mp_diagtag("<TD>");
1216 __mp_diag(MP_POINTER, n->data.addr);
1217 __mp_diagtag("</TD>\n");
1218 __mp_diagtag("<TD>");
1219 }
1220 else
1221 __mp_diag("\t" MP_POINTER " ", n->data.addr);
1222 __mp_printsymbol(y, n->data.addr);
1223 if (__mp_diagflags & FLG_HTML)
1224 {
1225 __mp_diagtag("</TD>\n");
1226 __mp_diagtag("</TR>");
1227 }
1228 __mp_diag("\n");
1229 n = n->data.next;
1230 }
1231 if (__mp_diagflags & FLG_HTML)
1232 {
1233 __mp_diagtag("</TABLE>\n");
1234 __mp_diagtag("</BLOCKQUOTE>\n");
1235 }
1236 }
1237
1238
1239 /* Display the call stack details for a call stack handle.
1240 */
1241
1242 MP_GLOBAL
1243 void
__mp_printstack(symhead * y,stackinfo * p)1244 __mp_printstack(symhead *y, stackinfo *p)
1245 {
1246 stackinfo s;
1247
1248 s = *p;
1249 if (__mp_diagflags & FLG_HTML)
1250 {
1251 __mp_diagtag("<BLOCKQUOTE>\n");
1252 __mp_diagtag("<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=0>\n");
1253 }
1254 if ((p->frame != NULL) && (p->addr != NULL))
1255 {
1256 if (__mp_diagflags & FLG_HTML)
1257 {
1258 __mp_diagtag("<TR>\n");
1259 __mp_diagtag("<TD>");
1260 __mp_diag(MP_POINTER, p->addr);
1261 __mp_diagtag("</TD>\n");
1262 __mp_diagtag("<TD>");
1263 }
1264 else
1265 __mp_diag("\t" MP_POINTER " ", p->addr);
1266 __mp_printsymbol(y, p->addr);
1267 if (__mp_diagflags & FLG_HTML)
1268 {
1269 __mp_diagtag("</TD>\n");
1270 __mp_diagtag("</TR>");
1271 }
1272 __mp_diag("\n");
1273 while (__mp_getframe(p) && (p->addr != NULL))
1274 {
1275 if (__mp_diagflags & FLG_HTML)
1276 {
1277 __mp_diagtag("<TR>\n");
1278 __mp_diagtag("<TD>");
1279 __mp_diag(MP_POINTER, p->addr);
1280 __mp_diagtag("</TD>\n");
1281 __mp_diagtag("<TD>");
1282 }
1283 else
1284 __mp_diag("\t" MP_POINTER " ", p->addr);
1285 __mp_printsymbol(y, p->addr);
1286 if (__mp_diagflags & FLG_HTML)
1287 {
1288 __mp_diagtag("</TD>\n");
1289 __mp_diagtag("</TR>");
1290 }
1291 __mp_diag("\n");
1292 }
1293 }
1294 if (__mp_diagflags & FLG_HTML)
1295 {
1296 __mp_diagtag("</TABLE>\n");
1297 __mp_diagtag("</BLOCKQUOTE>\n");
1298 }
1299 *p = s;
1300 }
1301
1302
1303 /* Display the details of an individual allocation node.
1304 */
1305
1306 MP_GLOBAL
1307 void
__mp_printalloc(symhead * y,allocnode * n)1308 __mp_printalloc(symhead *y, allocnode *n)
1309 {
1310 infonode *m;
1311
1312 m = (infonode *) n->info;
1313 __mp_diag(" " MP_POINTER " (", n->block);
1314 __mp_printsize(n->size);
1315 __mp_diag(") ");
1316 __mp_printtype(m);
1317 __mp_diag(" ");
1318 __mp_printloc(m);
1319 if ((m->data.typestr != NULL) && (m->data.typesize != 0))
1320 {
1321 __mp_diag(" ");
1322 __mp_printtypeinfo(m, n->size);
1323 }
1324 __mp_diag("\n");
1325 __mp_printaddrs(y, m->data.stack);
1326 }
1327
1328
1329 /* Log the details of where a function call came from.
1330 */
1331
1332 static
1333 void
logcall(infohead * h,loginfo * i,size_t s)1334 logcall(infohead *h, loginfo *i, size_t s)
1335 {
1336 __mp_diag("[");
1337 #if MP_THREADS_SUPPORT
1338 __mp_diag("%lu|", __mp_threadid());
1339 #endif /* MP_THREADS_SUPPORT */
1340 __mp_diag("%s|%s|", (i->func ? i->func : "-"), (i->file ? i->file : "-"));
1341 if (i->line == 0)
1342 __mp_diag("-");
1343 else
1344 __mp_diag("%lu", i->line);
1345 __mp_diag("]");
1346 if ((i->typestr != NULL) && (i->typesize != 0))
1347 {
1348 __mp_diag(" (%s", i->typestr);
1349 if ((s /= i->typesize) > 1)
1350 __mp_diag(" x %lu", s);
1351 __mp_diag(")");
1352 }
1353 __mp_diag("\n");
1354 __mp_printstack(&h->syms, i->stack);
1355 __mp_diag("\n");
1356 }
1357
1358
1359 /* Log the details of a call to the mpatrol library.
1360 */
1361
1362 MP_GLOBAL
1363 void
__mp_log(infohead * h,loginfo * i)1364 __mp_log(infohead *h, loginfo *i)
1365 {
1366 if ((h->recur == 1) && !i->logged)
1367 {
1368 i->logged = 1;
1369 if (__mp_diagflags & FLG_HTML)
1370 {
1371 __mp_diagtag("<P>\n");
1372 __mp_diagtag("<B>");
1373 }
1374 __mp_diag("%s", __mp_lognames[i->ltype]);
1375 if (__mp_diagflags & FLG_HTML)
1376 __mp_diagtag("</B>");
1377 __mp_diag(": ");
1378 if (__mp_diagflags & FLG_HTML)
1379 __mp_diagtag("<TT>");
1380 __mp_diag("%s", __mp_functionnames[i->type]);
1381 if (__mp_diagflags & FLG_HTML)
1382 __mp_diagtag("</TT>");
1383 switch (i->ltype)
1384 {
1385 case LT_ALLOC:
1386 __mp_diag(" (%lu, ", h->count);
1387 __mp_printsize(i->variant.logalloc.size);
1388 __mp_diag(", ");
1389 if (i->variant.logalloc.align == 0)
1390 __mp_printsize(h->alloc.heap.memory.align);
1391 else
1392 __mp_printsize(i->variant.logalloc.align);
1393 __mp_diag(") ");
1394 logcall(h, i, i->variant.logalloc.size);
1395 break;
1396 case LT_REALLOC:
1397 __mp_diag(" (" MP_POINTER ", ", i->variant.logrealloc.block);
1398 __mp_printsize(i->variant.logrealloc.size);
1399 __mp_diag(", ");
1400 if (i->variant.logrealloc.align == 0)
1401 __mp_printsize(h->alloc.heap.memory.align);
1402 else
1403 __mp_printsize(i->variant.logrealloc.align);
1404 __mp_diag(") ");
1405 logcall(h, i, i->variant.logrealloc.size);
1406 break;
1407 case LT_FREE:
1408 __mp_diag(" (" MP_POINTER ") ", i->variant.logfree.block);
1409 logcall(h, i, 0);
1410 break;
1411 case LT_SET:
1412 __mp_diag(" (" MP_POINTER ", ", i->variant.logmemset.block);
1413 __mp_printsize(i->variant.logmemset.size);
1414 __mp_diag(", 0x%02X) ", i->variant.logmemset.byte);
1415 logcall(h, i, 0);
1416 break;
1417 case LT_COPY:
1418 __mp_diag(" (" MP_POINTER ", " MP_POINTER ", ",
1419 i->variant.logmemcopy.srcblock,
1420 i->variant.logmemcopy.dstblock);
1421 __mp_printsize(i->variant.logmemcopy.size);
1422 __mp_diag(", 0x%02X) ", i->variant.logmemcopy.byte);
1423 logcall(h, i, 0);
1424 break;
1425 case LT_LOCATE:
1426 __mp_diag(" (" MP_POINTER ", ", i->variant.logmemlocate.block);
1427 __mp_printsize(i->variant.logmemlocate.size);
1428 __mp_diag(", " MP_POINTER ", ", i->variant.logmemlocate.patblock);
1429 __mp_printsize(i->variant.logmemlocate.patsize);
1430 __mp_diag(") ");
1431 logcall(h, i, 0);
1432 break;
1433 case LT_COMPARE:
1434 __mp_diag(" (" MP_POINTER ", " MP_POINTER ", ",
1435 i->variant.logmemcompare.block1,
1436 i->variant.logmemcompare.block2);
1437 __mp_printsize(i->variant.logmemcompare.size);
1438 __mp_diag(") ");
1439 logcall(h, i, 0);
1440 break;
1441 case LT_MAX:
1442 __mp_diag(" () ");
1443 logcall(h, i, 0);
1444 break;
1445 }
1446 }
1447 }
1448
1449
1450 /* Display the details of all allocation nodes on the allocation tree.
1451 */
1452
1453 MP_GLOBAL
1454 void
__mp_printallocs(infohead * h,int e)1455 __mp_printallocs(infohead *h, int e)
1456 {
1457 allocnode *n;
1458 treenode *t;
1459 char f;
1460
1461 f = 0;
1462 if (e != 0)
1463 {
1464 /* We are now displaying the allocation nodes for a second
1465 * time, except this time to the standard error stream. If
1466 * the log file is already on standard error then don't bother
1467 * displaying them again.
1468 */
1469 if (logfile == stderr)
1470 {
1471 h->fini = 1;
1472 __mp_abort();
1473 }
1474 __mp_closelogfile();
1475 __mp_diagflags &= ~FLG_HTML;
1476 __mp_diag("\nALLOC:");
1477 if (h->alloc.heap.memory.prog != NULL)
1478 __mp_diag(" %s:", h->alloc.heap.memory.prog);
1479 __mp_diag("\n");
1480 }
1481 __mp_diag("\nunfreed allocations: %lu (", h->alloc.atree.size - h->mcount);
1482 __mp_printsize(h->alloc.asize - h->mtotal);
1483 __mp_diag(")\n");
1484 for (t = __mp_minimum(h->alloc.atree.root); t != NULL;
1485 t = __mp_successor(t))
1486 {
1487 n = (allocnode *) ((char *) t - offsetof(allocnode, tnode));
1488 if (!(((infonode *) n->info)->data.flags & FLG_MARKED))
1489 {
1490 if (f == 0)
1491 f = 1;
1492 else
1493 __mp_diag("\n");
1494 __mp_printalloc(&h->syms, n);
1495 }
1496 }
1497 if (e != 0)
1498 {
1499 h->fini = 1;
1500 __mp_abort();
1501 }
1502 }
1503
1504
1505 /* Display the details of all allocation nodes on the freed tree.
1506 */
1507
1508 MP_GLOBAL
1509 void
__mp_printfreed(infohead * h)1510 __mp_printfreed(infohead *h)
1511 {
1512 allocnode *n;
1513 treenode *t;
1514 char f;
1515
1516 f = 0;
1517 __mp_diag("\nfreed allocations: %lu (", h->alloc.gtree.size);
1518 __mp_printsize(h->alloc.gsize);
1519 __mp_diag(")\n");
1520 for (t = __mp_minimum(h->alloc.gtree.root); t != NULL;
1521 t = __mp_successor(t))
1522 {
1523 n = (allocnode *) ((char *) t - offsetof(allocnode, tnode));
1524 if (f == 0)
1525 f = 1;
1526 else
1527 __mp_diag("\n");
1528 __mp_printalloc(&h->syms, n);
1529 }
1530 }
1531
1532
1533 /* Display the details of all free blocks.
1534 */
1535
1536 MP_GLOBAL
1537 void
__mp_printfree(infohead * h)1538 __mp_printfree(infohead *h)
1539 {
1540 allocnode *n, *p;
1541 treenode *s, *t;
1542 size_t c;
1543
1544 __mp_diag("\nfree blocks: %lu (", h->alloc.ftree.size);
1545 __mp_printsize(h->alloc.fsize);
1546 __mp_diag(")\n");
1547 for (t = __mp_maximum(h->alloc.ftree.root); t != NULL; t = s)
1548 {
1549 n = (allocnode *) ((char *) t - offsetof(allocnode, tnode));
1550 s = t;
1551 c = 0;
1552 do
1553 {
1554 if (s = __mp_predecessor(s))
1555 p = (allocnode *) ((char *) s - offsetof(allocnode, tnode));
1556 else
1557 p = NULL;
1558 c++;
1559 }
1560 while ((p != NULL) && (p->size == n->size));
1561 __mp_diag(" %8lu: %lu\n", n->size, c);
1562 }
1563 }
1564
1565
1566 /* Display the details of a leak table node.
1567 */
1568
1569 static
1570 void
printleakinfo(tablenode * n,size_t * a,size_t * b,int o,int c)1571 printleakinfo(tablenode *n, size_t *a, size_t *b, int o, int c)
1572 {
1573 size_t i, j;
1574
1575 if (o == SOPT_ALLOCATED)
1576 {
1577 i = n->data.acount;
1578 j = n->data.atotal;
1579 }
1580 else if (o == SOPT_FREED)
1581 {
1582 i = n->data.dcount;
1583 j = n->data.dtotal;
1584 }
1585 else
1586 {
1587 i = n->data.acount - n->data.dcount;
1588 j = n->data.atotal - n->data.dtotal;
1589 }
1590 if (c != 0)
1591 __mp_diag(" %6lu %8lu ", i, j);
1592 else
1593 __mp_diag(" %8lu %6lu ", j, i);
1594 if ((n->data.file != NULL) && (n->data.line != 0))
1595 __mp_diag("%s line %lu\n", n->data.file, n->data.line);
1596 else if (n->data.file != NULL)
1597 __mp_diag("%s\n", n->data.file);
1598 else if (n->data.line != 0)
1599 __mp_diag(MP_POINTER "\n", n->data.line);
1600 else
1601 __mp_diag("unknown location\n");
1602 *a += i;
1603 *b += j;
1604 }
1605
1606
1607 /* Display the leak table.
1608 */
1609
1610 MP_GLOBAL
1611 void
__mp_printleaktab(infohead * h,size_t l,int o,unsigned char f)1612 __mp_printleaktab(infohead *h, size_t l, int o, unsigned char f)
1613 {
1614 tablenode *n;
1615 treenode *t;
1616 char *s;
1617 size_t b, c;
1618
1619 __mp_sortleaktab(&h->ltable, o, (f & FLG_COUNTS));
1620 if ((l == 0) || (l > h->ltable.tree.size))
1621 l = h->ltable.tree.size;
1622 if (o == SOPT_ALLOCATED)
1623 s = "allocated";
1624 else if (o == SOPT_FREED)
1625 s = "freed";
1626 else
1627 s = "unfreed";
1628 if (l == 0)
1629 {
1630 __mp_diag("no %s memory entries in leak table\n", s);
1631 return;
1632 }
1633 __mp_diag("%s %lu %s memory %s in leak table:\n\n",
1634 (f & FLG_BOTTOM) ? "bottom" : "top", l, s,
1635 (l == 1) ? "entry" : "entries");
1636 if (f & FLG_COUNTS)
1637 {
1638 __mp_diag(" count bytes location\n");
1639 __mp_diag(" ------ -------- --------\n");
1640 }
1641 else
1642 {
1643 __mp_diag(" bytes count location\n");
1644 __mp_diag(" -------- ------ --------\n");
1645 }
1646 b = c = 0;
1647 if (f & FLG_BOTTOM)
1648 for (t = __mp_minimum(h->ltable.tree.root); (t != NULL) && (l != 0);
1649 t = __mp_successor(t), l--)
1650 {
1651 n = (tablenode *) ((char *) t - offsetof(tablenode, data.tnode));
1652 printleakinfo(n, &c, &b, o, (f & FLG_COUNTS));
1653 }
1654 else
1655 for (t = __mp_maximum(h->ltable.tree.root); (t != NULL) && (l != 0);
1656 t = __mp_predecessor(t), l--)
1657 {
1658 n = (tablenode *) ((char *) t - offsetof(tablenode, data.tnode));
1659 printleakinfo(n, &c, &b, o, (f & FLG_COUNTS));
1660 }
1661 if (f & FLG_COUNTS)
1662 __mp_diag(" %6lu %8lu total\n", c, b);
1663 else
1664 __mp_diag(" %8lu %6lu total\n", b, c);
1665 }
1666
1667
1668 /* Display a complete memory map of the heap.
1669 */
1670
1671 MP_GLOBAL
1672 void
__mp_printmap(infohead * h)1673 __mp_printmap(infohead *h)
1674 {
1675 allocnode *n;
1676 infonode *m;
1677 void *a, *b;
1678 size_t l, s;
1679
1680 a = NULL;
1681 __mp_diag("memory map:\n");
1682 for (n = (allocnode *) h->alloc.list.head; n->lnode.next != NULL;
1683 n = (allocnode *) n->lnode.next)
1684 {
1685 m = (infonode *) n->info;
1686 if ((h->alloc.flags & FLG_PAGEALLOC) && (m != NULL))
1687 {
1688 b = (void *) __mp_rounddown((unsigned long) n->block,
1689 h->alloc.heap.memory.page);
1690 l = __mp_roundup(n->size + ((char *) n->block - (char *) b),
1691 h->alloc.heap.memory.page);
1692 }
1693 else
1694 {
1695 b = n->block;
1696 l = n->size;
1697 }
1698 if (m != NULL)
1699 {
1700 b = (char *) b - h->alloc.oflow;
1701 l += h->alloc.oflow << 1;
1702 }
1703 if ((a != NULL) && (a < b))
1704 {
1705 #if ENVIRON == ENVIRON_64
1706 __mp_diag(" ------------------------------------- gap (");
1707 #else /* ENVIRON */
1708 __mp_diag(" --------------------- gap (");
1709 #endif /* ENVIRON */
1710 __mp_printsize((char *) b - (char *) a);
1711 __mp_diag(")\n");
1712 }
1713 if (m != NULL)
1714 if (h->alloc.oflow > 0)
1715 {
1716 s = (char *) n->block - (char *) b;
1717 __mp_diag(" / " MP_POINTER "-" MP_POINTER " overflow (", b,
1718 (char *) b + s - 1);
1719 __mp_printsize(s);
1720 __mp_diag(")\n |+ ");
1721 }
1722 else
1723 __mp_diag(" + ");
1724 else
1725 __mp_diag("--- ");
1726 __mp_diag(MP_POINTER "-" MP_POINTER, n->block,
1727 (char *) n->block + n->size - 1);
1728 if (m == NULL)
1729 __mp_diag(" free (");
1730 else if (m->data.flags & FLG_FREED)
1731 __mp_diag(" freed (");
1732 else
1733 __mp_diag(" allocated (");
1734 __mp_printsize(n->size);
1735 __mp_diag(")");
1736 if (m != NULL)
1737 {
1738 __mp_diag(" ");
1739 __mp_printtype(m);
1740 __mp_diag(" ");
1741 __mp_printloc(m);
1742 if ((m->data.typestr != NULL) && (m->data.typesize != 0))
1743 {
1744 __mp_diag(" ");
1745 __mp_printtypeinfo(m, n->size);
1746 }
1747 if (h->alloc.oflow > 0)
1748 {
1749 s = l - n->size - s;
1750 __mp_diag("\n \\ " MP_POINTER "-" MP_POINTER " overflow (",
1751 (char *) n->block + n->size, (char *) b + l - 1);
1752 __mp_printsize(s);
1753 __mp_diag(")");
1754 }
1755 }
1756 __mp_diag("\n");
1757 a = (char *) b + l;
1758 }
1759 }
1760
1761
1762 /* Display the version and copyright details.
1763 */
1764
1765 MP_GLOBAL
1766 void
__mp_printversion(void)1767 __mp_printversion(void)
1768 {
1769 __mp_diag("%s\n", __mp_version);
1770 if (__mp_diagflags & FLG_HTML)
1771 {
1772 __mp_diagtag("<BR>\n");
1773 __mp_diag("%s ", __mp_copyright);
1774 __mp_diagtag("<A HREF=\"mailto:");
1775 __mp_diagtag(__mp_email);
1776 __mp_diagtag("\">");
1777 __mp_diag("%s", __mp_author);
1778 __mp_diagtag("</A>\n");
1779 __mp_diagtag("<P>\n");
1780 }
1781 else
1782 __mp_diag("%s %s\n\n", __mp_copyright, __mp_author);
1783 __mp_diag("This is free software, and you are welcome to redistribute it "
1784 "under certain\n");
1785 __mp_diag("conditions; see the GNU Library General Public License for "
1786 "details.\n");
1787 if (__mp_diagflags & FLG_HTML)
1788 __mp_diagtag("<P>");
1789 __mp_diag("\nFor the latest mpatrol release and documentation,\n");
1790 if (__mp_diagflags & FLG_HTML)
1791 {
1792 __mp_diag("visit ");
1793 __mp_diagtag("<A HREF=\"");
1794 __mp_diagtag(__mp_homepage);
1795 __mp_diagtag("\">");
1796 __mp_diag("%s", __mp_homepage);
1797 __mp_diagtag("</A>.\n");
1798 __mp_diagtag("<P>\n");
1799 __mp_diagtag("<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=1>\n");
1800 __mp_diagtag("<TR>\n");
1801 __mp_diagtag("<TD>");
1802 __mp_diag("operating system");
1803 __mp_diagtag("</TD>\n");
1804 __mp_diagtag("<TD>");
1805 __mp_diag("%s", TARGET_STR);
1806 __mp_diagtag("</TD>\n");
1807 __mp_diagtag("</TR>\n");
1808 __mp_diagtag("<TR>\n");
1809 __mp_diagtag("<TD>");
1810 __mp_diag("system variant");
1811 __mp_diagtag("</TD>\n");
1812 __mp_diagtag("<TD>");
1813 __mp_diag("%s", SYSTEM_STR);
1814 __mp_diagtag("</TD>\n");
1815 __mp_diagtag("</TR>\n");
1816 __mp_diagtag("<TR>\n");
1817 __mp_diagtag("<TD>");
1818 __mp_diag("processor architecture");
1819 __mp_diagtag("</TD>\n");
1820 __mp_diagtag("<TD>");
1821 __mp_diag("%s", ARCH_STR);
1822 __mp_diagtag("</TD>\n");
1823 __mp_diagtag("</TR>\n");
1824 __mp_diagtag("<TR>\n");
1825 __mp_diagtag("<TD>");
1826 __mp_diag("processor word size");
1827 __mp_diagtag("</TD>\n");
1828 __mp_diagtag("<TD>");
1829 __mp_diag("%s", ENVIRON_STR);
1830 __mp_diagtag("</TD>\n");
1831 __mp_diagtag("</TR>\n");
1832 __mp_diagtag("<TR>\n");
1833 __mp_diagtag("<TD>");
1834 __mp_diag("object file format");
1835 __mp_diagtag("</TD>\n");
1836 __mp_diagtag("<TD>");
1837 __mp_diag("%s", FORMAT_STR);
1838 __mp_diagtag("</TD>\n");
1839 __mp_diagtag("</TR>\n");
1840 __mp_diagtag("<TR>\n");
1841 __mp_diagtag("<TD>");
1842 __mp_diag("dynamic linker type");
1843 __mp_diagtag("</TD>\n");
1844 __mp_diagtag("<TD>");
1845 __mp_diag("%s", DYNLINK_STR);
1846 __mp_diagtag("</TD>\n");
1847 __mp_diagtag("</TR>\n");
1848 __mp_diagtag("</TABLE>\n");
1849 __mp_diagtag("<P>\n");
1850 }
1851 else
1852 {
1853 __mp_diag("visit %s.\n\n", __mp_homepage);
1854 __mp_diag("operating system: %s\n", TARGET_STR);
1855 __mp_diag("system variant: %s\n", SYSTEM_STR);
1856 __mp_diag("processor architecture: %s\n", ARCH_STR);
1857 __mp_diag("processor word size: %s\n", ENVIRON_STR);
1858 __mp_diag("object file format: %s\n", FORMAT_STR);
1859 __mp_diag("dynamic linker type: %s\n\n", DYNLINK_STR);
1860 }
1861 if (!currenttime)
1862 currenttime = time(NULL);
1863 if (currenttime != (time_t) -1)
1864 {
1865 __mp_diag("Log file generated on %s", ctime(¤ttime));
1866 if (__mp_diagflags & FLG_HTML)
1867 __mp_diagtag("<P>");
1868 __mp_diag("\n");
1869 }
1870 }
1871
1872
1873 /* Display a summary of all mpatrol library settings and statistics.
1874 */
1875
1876 MP_GLOBAL
1877 void
__mp_printsummary(infohead * h)1878 __mp_printsummary(infohead *h)
1879 {
1880 size_t n;
1881
1882 if (__mp_diagflags & FLG_HTML)
1883 {
1884 __mp_diagtag("<TABLE CELLSPACING=0 CELLPADDING=1 BORDER=1>\n");
1885 __mp_diagtag("<TR>\n");
1886 __mp_diagtag("<TD>");
1887 __mp_diag("system page size");
1888 __mp_diagtag("</TD>\n");
1889 __mp_diagtag("<TD>");
1890 __mp_printsize(h->alloc.heap.memory.page);
1891 __mp_diagtag("</TD>\n");
1892 __mp_diagtag("</TR>\n");
1893 __mp_diagtag("<TR>\n");
1894 __mp_diagtag("<TD>");
1895 __mp_diag("default alignment");
1896 __mp_diagtag("</TD>\n");
1897 __mp_diagtag("<TD>");
1898 __mp_printsize(h->alloc.heap.memory.align);
1899 __mp_diagtag("</TD>\n");
1900 __mp_diagtag("</TR>\n");
1901 __mp_diagtag("<TR>\n");
1902 __mp_diagtag("<TD>");
1903 __mp_diag("overflow size");
1904 __mp_diagtag("</TD>\n");
1905 __mp_diagtag("<TD>");
1906 __mp_printsize(h->alloc.oflow);
1907 __mp_diagtag("</TD>\n");
1908 __mp_diagtag("</TR>\n");
1909 __mp_diagtag("<TR>\n");
1910 __mp_diagtag("<TD>");
1911 __mp_diag("overflow byte");
1912 __mp_diagtag("</TD>\n");
1913 __mp_diagtag("<TD>");
1914 __mp_diag("0x%02X", h->alloc.obyte);
1915 __mp_diagtag("</TD>\n");
1916 __mp_diagtag("</TR>\n");
1917 __mp_diagtag("<TR>\n");
1918 __mp_diagtag("<TD>");
1919 __mp_diag("allocation byte");
1920 __mp_diagtag("</TD>\n");
1921 __mp_diagtag("<TD>");
1922 __mp_diag("0x%02X", h->alloc.abyte);
1923 __mp_diagtag("</TD>\n");
1924 __mp_diagtag("</TR>\n");
1925 __mp_diagtag("<TR>\n");
1926 __mp_diagtag("<TD>");
1927 __mp_diag("free byte");
1928 __mp_diagtag("</TD>\n");
1929 __mp_diagtag("<TD>");
1930 __mp_diag("0x%02X", h->alloc.fbyte);
1931 __mp_diagtag("</TD>\n");
1932 __mp_diagtag("</TR>\n");
1933 __mp_diagtag("<TR>\n");
1934 __mp_diagtag("<TD>");
1935 __mp_diag("allocation stop");
1936 __mp_diagtag("</TD>\n");
1937 __mp_diagtag("<TD>");
1938 __mp_diag("%lu", h->astop);
1939 __mp_diagtag("</TD>\n");
1940 __mp_diagtag("</TR>\n");
1941 __mp_diagtag("<TR>\n");
1942 __mp_diagtag("<TD>");
1943 __mp_diag("reallocation stop");
1944 __mp_diagtag("</TD>\n");
1945 __mp_diagtag("<TD>");
1946 __mp_diag("%lu", h->rstop);
1947 __mp_diagtag("</TD>\n");
1948 __mp_diagtag("</TR>\n");
1949 __mp_diagtag("<TR>\n");
1950 __mp_diagtag("<TD>");
1951 __mp_diag("free stop");
1952 __mp_diagtag("</TD>\n");
1953 __mp_diagtag("<TD>");
1954 __mp_diag("%lu", h->fstop);
1955 __mp_diagtag("</TD>\n");
1956 __mp_diagtag("</TR>\n");
1957 __mp_diagtag("<TR>\n");
1958 __mp_diagtag("<TD>");
1959 __mp_diag("unfreed abort");
1960 __mp_diagtag("</TD>\n");
1961 __mp_diagtag("<TD>");
1962 __mp_diag("%lu", h->uabort);
1963 __mp_diagtag("</TD>\n");
1964 __mp_diagtag("</TR>\n");
1965 __mp_diagtag("<TR>\n");
1966 __mp_diagtag("<TD>");
1967 __mp_diag("small boundary");
1968 __mp_diagtag("</TD>\n");
1969 __mp_diagtag("<TD>");
1970 __mp_printsize(h->prof.sbound);
1971 __mp_diagtag("</TD>\n");
1972 __mp_diagtag("</TR>\n");
1973 __mp_diagtag("<TR>\n");
1974 __mp_diagtag("<TD>");
1975 __mp_diag("medium boundary");
1976 __mp_diagtag("</TD>\n");
1977 __mp_diagtag("<TD>");
1978 __mp_printsize(h->prof.mbound);
1979 __mp_diagtag("</TD>\n");
1980 __mp_diagtag("</TR>\n");
1981 __mp_diagtag("<TR>\n");
1982 __mp_diagtag("<TD>");
1983 __mp_diag("large boundary");
1984 __mp_diagtag("</TD>\n");
1985 __mp_diagtag("<TD>");
1986 __mp_printsize(h->prof.lbound);
1987 __mp_diagtag("</TD>\n");
1988 __mp_diagtag("</TR>\n");
1989 __mp_diagtag("<TR>\n");
1990 __mp_diagtag("<TD>");
1991 __mp_diag("lower check range");
1992 __mp_diagtag("</TD>\n");
1993 __mp_diagtag("<TD>");
1994 }
1995 else
1996 {
1997 __mp_diag("system page size: ");
1998 __mp_printsize(h->alloc.heap.memory.page);
1999 __mp_diag("\ndefault alignment: ");
2000 __mp_printsize(h->alloc.heap.memory.align);
2001 __mp_diag("\noverflow size: ");
2002 __mp_printsize(h->alloc.oflow);
2003 __mp_diag("\noverflow byte: 0x%02X", h->alloc.obyte);
2004 __mp_diag("\nallocation byte: 0x%02X", h->alloc.abyte);
2005 __mp_diag("\nfree byte: 0x%02X", h->alloc.fbyte);
2006 __mp_diag("\nallocation stop: %lu", h->astop);
2007 __mp_diag("\nreallocation stop: %lu", h->rstop);
2008 __mp_diag("\nfree stop: %lu", h->fstop);
2009 __mp_diag("\nunfreed abort: %lu", h->uabort);
2010 __mp_diag("\nsmall boundary: ");
2011 __mp_printsize(h->prof.sbound);
2012 __mp_diag("\nmedium boundary: ");
2013 __mp_printsize(h->prof.mbound);
2014 __mp_diag("\nlarge boundary: ");
2015 __mp_printsize(h->prof.lbound);
2016 __mp_diag("\nlower check range: ");
2017 }
2018 if (h->lrange == (size_t) -1)
2019 __mp_diag("-");
2020 else
2021 __mp_diag("%lu", h->lrange);
2022 if (__mp_diagflags & FLG_HTML)
2023 {
2024 __mp_diagtag("</TD>\n");
2025 __mp_diagtag("</TR>\n");
2026 __mp_diagtag("<TR>\n");
2027 __mp_diagtag("<TD>");
2028 __mp_diag("upper check range");
2029 __mp_diagtag("</TD>\n");
2030 __mp_diagtag("<TD>");
2031 }
2032 else
2033 __mp_diag("\nupper check range: ");
2034 if (h->urange == (size_t) -1)
2035 __mp_diag("-");
2036 else
2037 __mp_diag("%lu", h->urange);
2038 if (__mp_diagflags & FLG_HTML)
2039 {
2040 __mp_diagtag("</TD>\n");
2041 __mp_diagtag("</TR>\n");
2042 __mp_diagtag("<TR>\n");
2043 __mp_diagtag("<TD>");
2044 __mp_diag("check frequency");
2045 __mp_diagtag("</TD>\n");
2046 __mp_diagtag("<TD>");
2047 __mp_diag("%lu", h->check);
2048 __mp_diagtag("</TD>\n");
2049 __mp_diagtag("</TR>\n");
2050 __mp_diagtag("<TR>\n");
2051 __mp_diagtag("<TD>");
2052 __mp_diag("failure frequency");
2053 __mp_diagtag("</TD>\n");
2054 __mp_diagtag("<TD>");
2055 __mp_diag("%lu", h->ffreq);
2056 __mp_diagtag("</TD>\n");
2057 __mp_diagtag("</TR>\n");
2058 __mp_diagtag("<TR>\n");
2059 __mp_diagtag("<TD>");
2060 __mp_diag("failure seed");
2061 __mp_diagtag("</TD>\n");
2062 __mp_diagtag("<TD>");
2063 __mp_diag("%lu", h->fseed);
2064 __mp_diagtag("</TD>\n");
2065 __mp_diagtag("</TR>\n");
2066 __mp_diagtag("<TR>\n");
2067 __mp_diagtag("<TD>");
2068 __mp_diag("prologue function");
2069 __mp_diagtag("</TD>\n");
2070 __mp_diagtag("<TD>");
2071 }
2072 else
2073 {
2074 __mp_diag("\ncheck frequency: %lu", h->check);
2075 __mp_diag("\nfailure frequency: %lu", h->ffreq);
2076 __mp_diag("\nfailure seed: %lu", h->fseed);
2077 __mp_diag("\nprologue function: ");
2078 }
2079 if (h->prologue == NULL)
2080 __mp_diag("<unset>");
2081 else
2082 {
2083 __mp_diag(MP_POINTER " [", h->prologue);
2084 __mp_printsymbol(&h->syms, (void *) h->prologue);
2085 __mp_diag("]");
2086 }
2087 if (__mp_diagflags & FLG_HTML)
2088 {
2089 __mp_diagtag("</TD>\n");
2090 __mp_diagtag("</TR>\n");
2091 __mp_diagtag("<TR>\n");
2092 __mp_diagtag("<TD>");
2093 __mp_diag("epilogue function");
2094 __mp_diagtag("</TD>\n");
2095 __mp_diagtag("<TD>");
2096 }
2097 else
2098 __mp_diag("\nepilogue function: ");
2099 if (h->epilogue == NULL)
2100 __mp_diag("<unset>");
2101 else
2102 {
2103 __mp_diag(MP_POINTER " [", h->epilogue);
2104 __mp_printsymbol(&h->syms, (void *) h->epilogue);
2105 __mp_diag("]");
2106 }
2107 if (__mp_diagflags & FLG_HTML)
2108 {
2109 __mp_diagtag("</TD>\n");
2110 __mp_diagtag("</TR>\n");
2111 __mp_diagtag("<TR>\n");
2112 __mp_diagtag("<TD>");
2113 __mp_diag("handler function");
2114 __mp_diagtag("</TD>\n");
2115 __mp_diagtag("<TD>");
2116 }
2117 else
2118 __mp_diag("\nhandler function: ");
2119 if (h->nomemory == NULL)
2120 __mp_diag("<unset>");
2121 else
2122 {
2123 __mp_diag(MP_POINTER " [", h->nomemory);
2124 __mp_printsymbol(&h->syms, (void *) h->nomemory);
2125 __mp_diag("]");
2126 }
2127 if (__mp_diagflags & FLG_HTML)
2128 {
2129 __mp_diagtag("</TD>\n");
2130 __mp_diagtag("</TR>\n");
2131 __mp_diagtag("<TR>\n");
2132 __mp_diagtag("<TD>");
2133 __mp_diag("log file");
2134 __mp_diagtag("</TD>\n");
2135 __mp_diagtag("<TD>");
2136 }
2137 else
2138 __mp_diag("\nlog file: ");
2139 if (h->log == NULL)
2140 __mp_diag("<unset>");
2141 else
2142 {
2143 if (__mp_diagflags & FLG_HTML)
2144 __mp_diagtag("<TT>");
2145 __mp_diag("%s", h->log);
2146 if (__mp_diagflags & FLG_HTML)
2147 __mp_diagtag("</TT>");
2148 }
2149 if (__mp_diagflags & FLG_HTML)
2150 {
2151 __mp_diagtag("</TD>\n");
2152 __mp_diagtag("</TR>\n");
2153 __mp_diagtag("<TR>\n");
2154 __mp_diagtag("<TD>");
2155 __mp_diag("profiling file");
2156 __mp_diagtag("</TD>\n");
2157 __mp_diagtag("<TD>");
2158 }
2159 else
2160 __mp_diag("\nprofiling file: ");
2161 if (h->prof.file == NULL)
2162 __mp_diag("<unset>");
2163 else
2164 {
2165 if (__mp_diagflags & FLG_HTML)
2166 __mp_diagtag("<TT>");
2167 __mp_diag("%s", h->prof.file);
2168 if (__mp_diagflags & FLG_HTML)
2169 __mp_diagtag("</TT>");
2170 }
2171 if (__mp_diagflags & FLG_HTML)
2172 {
2173 __mp_diagtag("</TD>\n");
2174 __mp_diagtag("</TR>\n");
2175 __mp_diagtag("<TR>\n");
2176 __mp_diagtag("<TD>");
2177 __mp_diag("tracing file");
2178 __mp_diagtag("</TD>\n");
2179 __mp_diagtag("<TD>");
2180 }
2181 else
2182 __mp_diag("\ntracing file: ");
2183 if (h->trace.file == NULL)
2184 __mp_diag("<unset>");
2185 else
2186 {
2187 if (__mp_diagflags & FLG_HTML)
2188 __mp_diagtag("<TT>");
2189 __mp_diag("%s", h->trace.file);
2190 if (__mp_diagflags & FLG_HTML)
2191 __mp_diagtag("</TT>");
2192 }
2193 if (__mp_diagflags & FLG_HTML)
2194 {
2195 __mp_diagtag("</TD>\n");
2196 __mp_diagtag("</TR>\n");
2197 __mp_diagtag("<TR>\n");
2198 __mp_diagtag("<TD>");
2199 __mp_diag("program filename");
2200 __mp_diagtag("</TD>\n");
2201 __mp_diagtag("<TD>");
2202 }
2203 else
2204 __mp_diag("\nprogram filename: ");
2205 if (h->alloc.heap.memory.prog == NULL)
2206 __mp_diag("<not found>");
2207 else
2208 {
2209 if (__mp_diagflags & FLG_HTML)
2210 __mp_diagtag("<TT>");
2211 __mp_diag("%s", h->alloc.heap.memory.prog);
2212 if (__mp_diagflags & FLG_HTML)
2213 __mp_diagtag("</TT>");
2214 }
2215 if (__mp_diagflags & FLG_HTML)
2216 {
2217 __mp_diagtag("</TD>\n");
2218 __mp_diagtag("</TR>\n");
2219 __mp_diagtag("<TR>\n");
2220 __mp_diagtag("<TD>");
2221 __mp_diag("symbols read");
2222 __mp_diagtag("</TD>\n");
2223 __mp_diagtag("<TD>");
2224 __mp_diag("%lu", h->syms.dtree.size);
2225 __mp_diagtag("</TD>\n");
2226 __mp_diagtag("</TR>\n");
2227 __mp_diagtag("<TR>\n");
2228 __mp_diagtag("<TD>");
2229 __mp_diag("autosave count");
2230 __mp_diagtag("</TD>\n");
2231 __mp_diagtag("<TD>");
2232 __mp_diag("%lu", h->prof.autosave);
2233 __mp_diagtag("</TD>\n");
2234 __mp_diagtag("</TR>\n");
2235 __mp_diagtag("<TR>\n");
2236 __mp_diagtag("<TD>");
2237 __mp_diag("freed queue size");
2238 __mp_diagtag("</TD>\n");
2239 __mp_diagtag("<TD>");
2240 __mp_diag("%lu", h->alloc.fmax);
2241 __mp_diagtag("</TD>\n");
2242 __mp_diagtag("</TR>\n");
2243 __mp_diagtag("<TR>\n");
2244 __mp_diagtag("<TD>");
2245 __mp_diag("allocation count");
2246 __mp_diagtag("</TD>\n");
2247 __mp_diagtag("<TD>");
2248 __mp_diag("%lu", h->count);
2249 __mp_diagtag("</TD>\n");
2250 __mp_diagtag("</TR>\n");
2251 __mp_diagtag("<TR>\n");
2252 __mp_diagtag("<TD>");
2253 __mp_diag("allocation peak");
2254 __mp_diagtag("</TD>\n");
2255 __mp_diagtag("<TD>");
2256 __mp_diag("%lu (", h->cpeak);
2257 __mp_printsize(h->peak);
2258 __mp_diag(")");
2259 __mp_diagtag("</TD>\n");
2260 __mp_diagtag("</TR>\n");
2261 __mp_diagtag("<TR>\n");
2262 __mp_diagtag("<TD>");
2263 __mp_diag("allocation limit");
2264 __mp_diagtag("</TD>\n");
2265 __mp_diagtag("<TD>");
2266 __mp_printsize(h->limit);
2267 __mp_diagtag("</TD>\n");
2268 __mp_diagtag("</TR>\n");
2269 __mp_diagtag("<TR>\n");
2270 __mp_diagtag("<TD>");
2271 __mp_diag("allocated blocks");
2272 __mp_diagtag("</TD>\n");
2273 __mp_diagtag("<TD>");
2274 __mp_diag("%lu (", h->alloc.atree.size);
2275 __mp_printsize(h->alloc.asize);
2276 __mp_diag(")");
2277 __mp_diagtag("</TD>\n");
2278 __mp_diagtag("</TR>\n");
2279 __mp_diagtag("<TR>\n");
2280 __mp_diagtag("<TD>");
2281 __mp_diag("marked blocks");
2282 __mp_diagtag("</TD>\n");
2283 __mp_diagtag("<TD>");
2284 __mp_diag("%lu (", h->mcount);
2285 __mp_printsize(h->mtotal);
2286 __mp_diag(")");
2287 __mp_diagtag("</TD>\n");
2288 __mp_diagtag("</TR>\n");
2289 __mp_diagtag("<TR>\n");
2290 __mp_diagtag("<TD>");
2291 __mp_diag("freed blocks");
2292 __mp_diagtag("</TD>\n");
2293 __mp_diagtag("<TD>");
2294 __mp_diag("%lu (", h->alloc.gtree.size);
2295 __mp_printsize(h->alloc.gsize);
2296 __mp_diag(")");
2297 __mp_diagtag("</TD>\n");
2298 __mp_diagtag("</TR>\n");
2299 __mp_diagtag("<TR>\n");
2300 __mp_diagtag("<TD>");
2301 __mp_diag("free blocks");
2302 __mp_diagtag("</TD>\n");
2303 __mp_diagtag("<TD>");
2304 __mp_diag("%lu (", h->alloc.ftree.size);
2305 __mp_printsize(h->alloc.fsize);
2306 __mp_diag(")");
2307 __mp_diagtag("</TD>\n");
2308 __mp_diagtag("</TR>\n");
2309 }
2310 else
2311 {
2312 __mp_diag("\nsymbols read: %lu", h->syms.dtree.size);
2313 __mp_diag("\nautosave count: %lu", h->prof.autosave);
2314 __mp_diag("\nfreed queue size: %lu", h->alloc.fmax);
2315 __mp_diag("\nallocation count: %lu", h->count);
2316 __mp_diag("\nallocation peak: %lu (", h->cpeak);
2317 __mp_printsize(h->peak);
2318 __mp_diag(")\nallocation limit: ");
2319 __mp_printsize(h->limit);
2320 __mp_diag("\nallocated blocks: %lu (", h->alloc.atree.size);
2321 __mp_printsize(h->alloc.asize);
2322 __mp_diag(")\nmarked blocks: %lu (", h->mcount);
2323 __mp_printsize(h->mtotal);
2324 __mp_diag(")\nfreed blocks: %lu (", h->alloc.gtree.size);
2325 __mp_printsize(h->alloc.gsize);
2326 __mp_diag(")\nfree blocks: %lu (", h->alloc.ftree.size);
2327 __mp_printsize(h->alloc.fsize);
2328 }
2329 n = h->alloc.heap.itree.size + h->alloc.itree.size + h->addr.list.size +
2330 h->syms.strings.list.size + h->syms.strings.tree.size +
2331 h->syms.itree.size + h->ltable.list.size + h->prof.ilist.size +
2332 h->list.size + h->alist.size;
2333 if (__mp_diagflags & FLG_HTML)
2334 {
2335 __mp_diagtag("<TR>\n");
2336 __mp_diagtag("<TD>");
2337 __mp_diag("internal blocks");
2338 __mp_diagtag("</TD>\n");
2339 __mp_diagtag("<TD>");
2340 __mp_diag("%lu (", n);
2341 }
2342 else
2343 __mp_diag(")\ninternal blocks: %lu (", n);
2344 n = h->alloc.heap.isize + h->alloc.isize + h->addr.size +
2345 h->syms.strings.size + h->syms.size + h->ltable.isize + h->prof.size +
2346 h->size;
2347 __mp_printsize(n);
2348 if (__mp_diagflags & FLG_HTML)
2349 {
2350 __mp_diag(")");
2351 __mp_diagtag("</TD>\n");
2352 __mp_diagtag("</TR>\n");
2353 __mp_diagtag("<TR>\n");
2354 __mp_diagtag("<TD>");
2355 __mp_diag("total heap usage");
2356 __mp_diagtag("</TD>\n");
2357 __mp_diagtag("<TD>");
2358 }
2359 else
2360 __mp_diag(")\ntotal heap usage: ");
2361 n = h->alloc.heap.isize + h->alloc.heap.dsize;
2362 __mp_printsize(n);
2363 if (__mp_diagflags & FLG_HTML)
2364 {
2365 __mp_diagtag("</TD>\n");
2366 __mp_diagtag("</TR>\n");
2367 __mp_diagtag("<TR>\n");
2368 __mp_diagtag("<TD>");
2369 __mp_diag("total compared");
2370 __mp_diagtag("</TD>\n");
2371 __mp_diagtag("<TD>");
2372 __mp_printsize(h->dtotal);
2373 __mp_diagtag("</TD>\n");
2374 __mp_diagtag("</TR>\n");
2375 __mp_diagtag("<TR>\n");
2376 __mp_diagtag("<TD>");
2377 __mp_diag("total located");
2378 __mp_diagtag("</TD>\n");
2379 __mp_diagtag("<TD>");
2380 __mp_printsize(h->ltotal);
2381 __mp_diagtag("</TD>\n");
2382 __mp_diagtag("</TR>\n");
2383 __mp_diagtag("<TR>\n");
2384 __mp_diagtag("<TD>");
2385 __mp_diag("total copied");
2386 __mp_diagtag("</TD>\n");
2387 __mp_diagtag("<TD>");
2388 __mp_printsize(h->ctotal);
2389 __mp_diagtag("</TD>\n");
2390 __mp_diagtag("</TR>\n");
2391 __mp_diagtag("<TR>\n");
2392 __mp_diagtag("<TD>");
2393 __mp_diag("total set");
2394 __mp_diagtag("</TD>\n");
2395 __mp_diagtag("<TD>");
2396 __mp_printsize(h->stotal);
2397 __mp_diagtag("</TD>\n");
2398 __mp_diagtag("</TR>\n");
2399 __mp_diagtag("<TR>\n");
2400 __mp_diagtag("<TD>");
2401 __mp_diag("total warnings");
2402 __mp_diagtag("</TD>\n");
2403 __mp_diagtag("<TD>");
2404 __mp_diag("%lu", warnings);
2405 __mp_diagtag("</TD>\n");
2406 __mp_diagtag("</TR>\n");
2407 __mp_diagtag("<TR>\n");
2408 __mp_diagtag("<TD>");
2409 __mp_diag("total errors");
2410 __mp_diagtag("</TD>\n");
2411 __mp_diagtag("<TD>");
2412 __mp_diag("%lu", errors);
2413 __mp_diagtag("</TD>\n");
2414 __mp_diagtag("</TR>\n");
2415 __mp_diagtag("</TABLE>\n");
2416 }
2417 else
2418 {
2419 __mp_diag("\ntotal compared: ");
2420 __mp_printsize(h->dtotal);
2421 __mp_diag("\ntotal located: ");
2422 __mp_printsize(h->ltotal);
2423 __mp_diag("\ntotal copied: ");
2424 __mp_printsize(h->ctotal);
2425 __mp_diag("\ntotal set: ");
2426 __mp_printsize(h->stotal);
2427 __mp_diag("\ntotal warnings: %lu", warnings);
2428 __mp_diag("\ntotal errors: %lu\n", errors);
2429 }
2430 }
2431
2432
2433 #ifdef __cplusplus
2434 }
2435 #endif /* __cplusplus */
2436