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(&currenttime));
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(&currenttime));
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 &lt, &gt, &amp and &quot 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("&lt;", logfile);
627                     break;
628                   case '>':
629                     fputs("&gt;", logfile);
630                     break;
631                   case '&':
632                     fputs("&amp;", logfile);
633                     break;
634                   case '"':
635                     fputs("&quot;", 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(&currenttime));
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