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  * Option handling.  Run-time modifiable flags are set here by parsing
25  * an option string read from an environment variable.  Any warnings
26  * or errors that occurred during parsing will be reported.
27  */
28 
29 
30 #include "option.h"
31 #include "diag.h"
32 #include "utils.h"
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <time.h>
39 
40 
41 #if MP_IDENT_SUPPORT
42 #ident "$Id: option.c,v 1.43 2002/01/08 20:13:59 graeme Exp $"
43 #else /* MP_IDENT_SUPPORT */
44 static MP_CONST MP_VOLATILE char *option_id = "$Id: option.c,v 1.43 2002/01/08 20:13:59 graeme Exp $";
45 #endif /* MP_IDENT_SUPPORT */
46 
47 
48 #ifdef __cplusplus
49 extern "C"
50 {
51 #endif /* __cplusplus */
52 
53 
54 /* The temporary buffer used to parse the configuration environment variable,
55  * since if we change the variable directly then we change the environment.
56  * This should not really be a file scope variable as it prevents this module
57  * from being re-entrant.
58  */
59 
60 static char options[1024];
61 
62 
63 /* The table describing a summary of all recognised options.
64  */
65 
66 static char *options_help[] =
67 {
68     "ALLOCBYTE", "unsigned integer",
69     "", "Specifies an 8-bit byte pattern with which to prefill newly-allocated",
70     "", "memory.",
71     "ALLOCSTOP", "unsigned integer",
72     "", "Specifies an allocation index at which to stop the program when it is",
73     "", "being allocated.",
74     "ALLOWOFLOW", NULL,
75     "", "Specifies that a warning rather than an error should be produced if",
76     "", "any memory operation function overflows the boundaries of a memory",
77     "", "allocation, and that the operation should still be performed.",
78     "AUTOSAVE", "unsigned integer",
79     "", "Specifies the frequency at which to periodically write the profiling",
80     "", "data to the profiling output file.",
81     "CHECK", "unsigned range",
82     "", "Specifies a range of allocation indices at which to check the",
83     "", "integrity of free memory and overflow buffers.",
84     "CHECKALL", NULL,
85     "", "Equivalent to the CHECKALLOCS, CHECKREALLOCS, CHECKFREES and",
86     "", "CHECKMEMORY options specified together.",
87     "CHECKALLOCS", NULL,
88     "", "Checks that no attempt is made to allocate a block of memory of size",
89     "", "zero.",
90     "CHECKFORK", NULL,
91     "", "Checks at every call to see if the process has been forked in case",
92     "", "new log, profiling and tracing output files need to be started.",
93     "CHECKFREES", NULL,
94     "", "Checks that no attempt is made to deallocate a NULL pointer.",
95     "CHECKMEMORY", NULL,
96     "", "Checks that no attempt is made to perform a zero-length memory",
97     "", "operation on a NULL pointer.",
98     "CHECKREALLOCS", NULL,
99     "", "Checks that no attempt is made to reallocate a NULL pointer or resize",
100     "", "an existing block of memory to size zero.",
101     "DEFALIGN", "unsigned integer",
102     "", "Specifies the default alignment for general-purpose memory",
103     "", "allocations, which must be a power of two.",
104     "EDIT", NULL,
105     "", "Specifies that a text editor should be invoked to edit any relevant",
106     "", "source files that are associated with any warnings or errors when",
107     "", "they occur.",
108     "FAILFREQ", "unsigned integer",
109     "", "Specifies the frequency at which all memory allocations will randomly",
110     "", "fail.",
111     "FAILSEED", "unsigned integer",
112     "", "Specifies the random number seed which will be used when determining",
113     "", "which memory allocations will randomly fail.",
114     "FREEBYTE", "unsigned integer",
115     "", "Specifies an 8-bit byte pattern with which to prefill newly-freed",
116     "", "memory.",
117     "FREESTOP", "unsigned integer",
118     "", "Specifies an allocation index at which to stop the program when it is",
119     "", "being freed.",
120     "HELP", NULL,
121     "", "Displays this quick-reference option summary.",
122     "HTML", NULL,
123     "", "Specifies that the log file should be formatted in HTML.",
124     "LARGEBOUND", "unsigned integer",
125     "", "Specifies the limit in bytes up to which memory allocations should be",
126     "", "classified as large allocations for profiling purposes.",
127     "LEAKTABLE", NULL,
128     "", "Specifies that the leak table should be automatically used and a leak",
129     "", "table summary should be displayed at the end of program execution.",
130     "LIMIT", "unsigned integer",
131     "", "Specifies the limit in bytes at which all memory allocations should",
132     "", "fail if the total allocated memory should increase beyond this.",
133     "LIST", NULL,
134     "", "Specifies that a context listing should be shown for any relevant",
135     "", "source files that are associated with any warnings or errors when",
136     "", "they occur.",
137     "LOGALL", NULL,
138     "", "Equivalent to the LOGALLOCS, LOGREALLOCS, LOGFREES and LOGMEMORY",
139     "", "options specified together.",
140     "LOGALLOCS", NULL,
141     "", "Specifies that all memory allocations are to be logged and sent to",
142     "", "the log file.",
143     "LOGFILE", "string",
144     "", "Specifies an alternative file in which to place all diagnostics from",
145     "", "the mpatrol library.",
146     "LOGFREES", NULL,
147     "", "Specifies that all memory deallocations are to be logged and sent to",
148     "", "the log file.",
149     "LOGMEMORY", NULL,
150     "", "Specifies that all memory operations are to be logged and sent to the",
151     "", "log file.",
152     "LOGREALLOCS", NULL,
153     "", "Specifies that all memory reallocations are to be logged and sent to",
154     "", "the log file.",
155     "MEDIUMBOUND", "unsigned integer",
156     "", "Specifies the limit in bytes up to which memory allocations should be",
157     "", "classified as medium allocations for profiling purposes.",
158     "NOFREE", "unsigned integer",
159     "", "Specifies that a number of recently-freed memory allocations should",
160     "", "be prevented from being returned to the free memory pool.",
161     "NOPROTECT", NULL,
162     "", "Specifies that the mpatrol library's internal data structures should",
163     "", "not be made read-only after every memory allocation, reallocation or",
164     "", "deallocation.",
165     "OFLOWBYTE", "unsigned integer",
166     "", "Specifies an 8-bit byte pattern with which to fill the overflow",
167     "", "buffers of all memory allocations.",
168     "OFLOWSIZE", "unsigned integer",
169     "", "Specifies the size in bytes to use for all overflow buffers, which",
170     "", "must be a power of two.",
171     "OFLOWWATCH", NULL,
172     "", "Specifies that watch point areas should be used for overflow buffers",
173     "", "rather than filling with the overflow byte.",
174     "PAGEALLOC", "LOWER|UPPER",
175     "", "Specifies that each individual memory allocation should occupy at",
176     "", "least one page of virtual memory and should be placed at the lowest",
177     "", "or highest point within these pages.",
178     "PRESERVE", NULL,
179     "", "Specifies that any reallocated or freed memory allocations should",
180     "", "preserve their original contents.",
181     "PROF", NULL,
182     "", "Specifies that all memory allocations are to be profiled and sent to",
183     "", "the profiling output file.",
184     "PROFFILE", "string",
185     "", "Specifies an alternative file in which to place all memory allocation",
186     "", "profiling information from the mpatrol library.",
187     "PROGFILE", "string",
188     "", "Specifies an alternative filename with which to locate the executable",
189     "", "file containing the program's symbols.",
190     "REALLOCSTOP", "unsigned integer",
191     "", "Specifies an allocation index at which to stop the program when a",
192     "", "memory allocation is being reallocated.",
193     "SAFESIGNALS", NULL,
194     "", "Instructs the library to save and replace certain signal handlers",
195     "", "during the execution of library code and to restore them afterwards.",
196     "SHOWALL", NULL,
197     "", "Equivalent to the SHOWFREE, SHOWFREED, SHOWUNFREED, SHOWMAP and",
198     "", "SHOWSYMBOLS options specified together.",
199     "SHOWFREE", NULL,
200     "", "Specifies that a summary of all of the free memory blocks should be",
201     "", "displayed at the end of program execution.",
202     "SHOWFREED", NULL,
203     "", "Specifies that a summary of all of the freed memory allocations",
204     "", "should be displayed at the end of program execution.",
205     "SHOWMAP", NULL,
206     "", "Specifies that a memory map of the entire heap should be displayed at",
207     "", "the end of program execution.",
208     "SHOWSYMBOLS", NULL,
209     "", "Specifies that a summary of all of the function symbols read from the",
210     "", "program's executable file should be displayed at the end of program",
211     "", "execution.",
212     "SHOWUNFREED", NULL,
213     "", "Specifies that a summary of all of the unfreed memory allocations",
214     "", "should be displayed at the end of program execution.",
215     "SMALLBOUND", "unsigned integer",
216     "", "Specifies the limit in bytes up to which memory allocations should be",
217     "", "classified as small allocations for profiling purposes.",
218     "TRACE", NULL,
219     "", "Specifies that all memory allocations are to be traced and sent to",
220     "", "the tracing output file.",
221     "TRACEFILE", "string",
222     "", "Specifies an alternative file in which to place all memory allocation",
223     "", "tracing information from the mpatrol library.",
224     "UNFREEDABORT", "unsigned integer",
225     "", "Specifies the minimum number of unfreed allocations at which to abort",
226     "", "the program just before program termination.",
227     "USEDEBUG", NULL,
228     "", "Specifies that any debugging information in the executable file",
229     "", "should be used to obtain additional source-level information.",
230     "USEMMAP", NULL,
231     "", "Specifies that the library should use mmap() instead of sbrk() to",
232     "", "allocate user memory on UNIX platforms.",
233     NULL
234 };
235 
236 
237 /* Perform a case-insensitive comparison between two option keywords.
238  */
239 
240 static
241 int
matchoption(char * s,char * t)242 matchoption(char *s, char *t)
243 {
244 #if TARGET != TARGET_AMIGA && TARGET != TARGET_WINDOWS && \
245     TARGET != TARGET_NETWARE
246     int d;
247 #endif /* TARGET */
248 
249 #if TARGET == TARGET_AMIGA || TARGET == TARGET_WINDOWS || \
250     TARGET == TARGET_NETWARE
251     return !stricmp(s, t);
252 #else /* TARGET */
253     while (((d = toupper(*s) - toupper(*t)) == 0) && (*s != '\0'))
254     {
255         s++;
256         t++;
257     }
258     return (d == 0);
259 #endif /* TARGET */
260 }
261 
262 
263 /* Convert a string representation of a number to an integer,
264  * reporting any errors that occur during the conversion.
265  */
266 
267 static
268 size_t
readnumber(char * s,long * n,int u)269 readnumber(char *s, long *n, int u)
270 {
271     char *t;
272     int e;
273 
274     e = errno;
275     errno = 0;
276     while (isspace(*s))
277         s++;
278     if ((u == 1) && (*s == '-'))
279     {
280         __mp_error(ET_MAX, AT_MAX, NULL, 0, "ignoring negative number `%s'\n",
281                    s);
282         t = s;
283     }
284     else if ((u == 0) && (*s == '-') && (s[1] == '0') && ((s[2] == 'b') ||
285              (s[2] == 'B')))
286         /* This is a negative binary number.
287          */
288         *n = -strtol(s + 3, &t, 2);
289     else if ((*s == '0') && ((s[1] == 'b') || (s[1] == 'B')))
290     {
291         /* This is a positive binary number.
292          */
293         if (u == 0)
294             *n = strtol(s + 2, &t, 2);
295         else
296             *n = strtoul(s + 2, &t, 2);
297     }
298     /* Otherwise let the conversion function work out the number base
299      * from the prefix.
300      */
301     else if (u == 0)
302         *n = strtol(s, &t, 0);
303     else
304         *n = strtoul(s, &t, 0);
305     if (errno == ERANGE)
306         __mp_warn(ET_MAX, AT_MAX, NULL, 0, "%s number overflow in `%s'\n",
307                   ((u == 0) && (*n == LONG_MIN)) ? "negative" : "positive", s);
308     errno = e;
309     return (size_t) (t - s);
310 }
311 
312 
313 /* Convert a string representation of a numeric range to two unsigned integers,
314  * ensuring that the first integer is less than or equal to the second.  An
315  * open range at either end is represented by -1.
316  */
317 
318 static
319 int
readrange(char * s,unsigned long * l,unsigned long * u,unsigned long * d)320 readrange(char *s, unsigned long *l, unsigned long *u, unsigned long *d)
321 {
322     char *p, *t;
323     unsigned long n;
324     int w;
325     char b, c;
326 
327     w = 0;
328     *l = *u = (unsigned long) -1;
329     *d = 1;
330     for (p = s; (*p != '/') && (*p != '\0'); p++);
331     b = *p;
332     *p = '\0';
333     for (t = s; (*t != '-') && (*t != '\0'); t++);
334     c = *t;
335     *t = '\0';
336     /* If there was a number before the minus sign then read it.
337      */
338     if ((*s != '\0') && (s[readnumber(s, (long *) l, 1)] != '\0'))
339     {
340         *l = (unsigned long) -1;
341         w = 1;
342     }
343     else if (c == '\0')
344         *u = *l;
345     else
346     {
347         s = t + 1;
348         /* If there was a number after the minus sign then read it too.
349          */
350         if ((*s != '\0') && (s[readnumber(s, (long *) u, 1)] != '\0'))
351         {
352             *u = (unsigned long) -1;
353             w = 1;
354         }
355     }
356     if ((w == 0) && (b == '/'))
357     {
358         s = p + 1;
359         /* If there was a forward slash then read the number after it as well.
360          */
361         if ((*s != '\0') && (s[readnumber(s, (long *) d, 1)] != '\0'))
362         {
363             *d = 1;
364             w = 1;
365         }
366     }
367     if (w != 0)
368         return 0;
369     /* If one or the other of the integers was zero (but not both) then convert
370      * it to an open range.
371      */
372     if ((*l == 0) && (*u != 0))
373         *l = (unsigned long) -1;
374     else if ((*l != 0) && (*u == 0))
375         *u = (unsigned long) -1;
376     /* If the frequency was zero then convert it to one.
377      */
378     if (*d == 0)
379         *d = 1;
380     /* Swap the integers if the first number is greater than the second.
381      */
382     if ((*l != (unsigned long) -1) && (*u != (unsigned long) -1) && (*l > *u))
383     {
384         n = *l;
385         *l = *u;
386         *u = n;
387     }
388     return 1;
389 }
390 
391 
392 /* Display the quick-reference help summary.
393  */
394 
395 static
396 void
showoptions(void)397 showoptions(void)
398 {
399     char **s, **t;
400 
401     __mp_diag("Available options:\n\n");
402     for (s = options_help, t = s + 1; *s != NULL; s += 2, t += 2)
403         if (**s != '\0')
404         {
405             __mp_diag("    %s", *s);
406             if (*t != NULL)
407                 __mp_diag("=<%s>", *t);
408             __mp_diag("\n");
409         }
410         else
411             __mp_diag("\t%s\n", *t);
412     __mp_diag("\n");
413 }
414 
415 
416 /* The main option parsing routine.
417  */
418 
419 MP_GLOBAL
420 void
__mp_parseoptions(infohead * h)421 __mp_parseoptions(infohead *h)
422 {
423     char *a, *f, *o, *p, *s, *t;
424     unsigned long d, m, n;
425     int i, l, q;
426 
427     l = 0;
428     f = p = t = NULL;
429     if (((s = getenv(MP_OPTIONS)) == NULL) || (*s == '\0'))
430         return;
431     if (strlen(s) + 1 > sizeof(options))
432     {
433         __mp_error(ET_MAX, AT_MAX, NULL, 0, "%s: environment variable too "
434                    "long\n", MP_OPTIONS);
435         return;
436     }
437     /* We shouldn't modify the original string returned by getenv() since
438      * that would modify the environment, and it may be placed in read-only
439      * memory anyway.
440      */
441     strcpy(options, s);
442     s = options;
443     while (*s != '\0')
444     {
445         i = 0;
446         while (isspace(*s))
447             s++;
448         if (*s == '\0')
449             break;
450         if (*s != '=')
451         {
452             /* Scan the option keyword.
453              */
454             for (o = s, q = 0; ((q == 1) || !isspace(*s)) && (*s != '\0') &&
455                  (*s != '='); s++)
456                 if (*s == '"')
457                 {
458                     /* Remove any quotes from the keyword.
459                      */
460                     __mp_memcopy(s, s + 1, strlen(s));
461                     q = (q == 0) ? 1 : 0;
462                     s--;
463                 }
464             if ((*s != '\0') && (*s != '='))
465             {
466                 *s++ = '\0';
467                 i = 1;
468             }
469         }
470         else
471             o = "";
472         if ((*s == '=') && (i == 0))
473         {
474             /* Scan the option value.
475              */
476             *s++ = '\0';
477             for (a = s, q = 0; ((q == 1) || !isspace(*s)) && (*s != '\0'); s++)
478                 if (*s == '"')
479                 {
480                     /* Remove any quotes from the value.
481                      */
482                     __mp_memcopy(s, s + 1, strlen(s));
483                     q = (q == 0) ? 1 : 0;
484                     s--;
485                 }
486             if (*s != '\0')
487                 *s++ = '\0';
488         }
489         else
490             a = "";
491         if (*o != '\0')
492         {
493             /* We now have an option keyword and possibly an associated
494              * value, so we can now check for valid keywords.
495              */
496             i = OE_UNRECOGNISED;
497             switch (toupper(*o))
498             {
499               case 'A':
500                 if (matchoption(o, "ALLOCBYTE"))
501                     if (*a == '\0')
502                         i = OE_NOARGUMENT;
503                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
504                         i = OE_BADNUMBER;
505                     else if (n > 0xFF)
506                         i = OE_BIGNUMBER;
507                     else
508                     {
509                         h->alloc.abyte = n;
510                         i = OE_RECOGNISED;
511                     }
512                 else if (matchoption(o, "ALLOCSTOP"))
513                     if (*a == '\0')
514                         i = OE_NOARGUMENT;
515                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
516                         i = OE_BADNUMBER;
517                     else
518                     {
519                         h->astop = n;
520                         i = OE_RECOGNISED;
521                     }
522                 else if (matchoption(o, "ALLOWOFLOW"))
523                 {
524                     if (*a != '\0')
525                         i = OE_IGNARGUMENT;
526                     else
527                         i = OE_RECOGNISED;
528                     h->flags |= FLG_ALLOWOFLOW;
529                 }
530                 else if (matchoption(o, "AUTOSAVE"))
531                     if (*a == '\0')
532                         i = OE_NOARGUMENT;
533                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
534                         i = OE_BADNUMBER;
535                     else
536                     {
537                         h->prof.autosave = n;
538                         i = OE_RECOGNISED;
539                     }
540                 break;
541               case 'C':
542                 if (matchoption(o, "CHECK"))
543                     if (*a == '\0')
544                         i = OE_NOARGUMENT;
545                     else if (!readrange(a, &m, &n, &d))
546                         i = OE_BADRANGE;
547                     else
548                     {
549                         h->lrange = m;
550                         h->urange = n;
551                         h->check = d;
552                         i = OE_RECOGNISED;
553                     }
554                 else if (matchoption(o, "CHECKALL"))
555                 {
556                     if (*a != '\0')
557                         i = OE_IGNARGUMENT;
558                     else
559                         i = OE_RECOGNISED;
560                     h->flags |= FLG_CHECKALLOCS | FLG_CHECKREALLOCS |
561                                 FLG_CHECKFREES | FLG_CHECKMEMORY;
562                 }
563                 else if (matchoption(o, "CHECKALLOCS"))
564                 {
565                     if (*a != '\0')
566                         i = OE_IGNARGUMENT;
567                     else
568                         i = OE_RECOGNISED;
569                     h->flags |= FLG_CHECKALLOCS;
570                 }
571                 else if (matchoption(o, "CHECKFORK"))
572                 {
573                     if (*a != '\0')
574                         i = OE_IGNARGUMENT;
575                     else
576                         i = OE_RECOGNISED;
577                     h->flags |= FLG_CHECKFORK;
578                 }
579                 else if (matchoption(o, "CHECKFREES"))
580                 {
581                     if (*a != '\0')
582                         i = OE_IGNARGUMENT;
583                     else
584                         i = OE_RECOGNISED;
585                     h->flags |= FLG_CHECKFREES;
586                 }
587                 else if (matchoption(o, "CHECKMEMORY"))
588                 {
589                     if (*a != '\0')
590                         i = OE_IGNARGUMENT;
591                     else
592                         i = OE_RECOGNISED;
593                     h->flags |= FLG_CHECKMEMORY;
594                 }
595                 else if (matchoption(o, "CHECKREALLOCS"))
596                 {
597                     if (*a != '\0')
598                         i = OE_IGNARGUMENT;
599                     else
600                         i = OE_RECOGNISED;
601                     h->flags |= FLG_CHECKREALLOCS;
602                 }
603                 break;
604               case 'D':
605                 if (matchoption(o, "DEFALIGN"))
606                     if (*a == '\0')
607                         i = OE_NOARGUMENT;
608                     else if ((a[readnumber(a, (long *) &n, 1)] != '\0') ||
609                              (n == 0))
610                         i = OE_BADNUMBER;
611                     else if (n > h->alloc.heap.memory.page)
612                         i = OE_BIGNUMBER;
613                     else
614                     {
615                         h->alloc.heap.memory.align = __mp_poweroftwo(n);
616                         i = OE_RECOGNISED;
617                     }
618                 break;
619               case 'E':
620                 if (matchoption(o, "EDIT"))
621                 {
622                     if (*a != '\0')
623                         i = OE_IGNARGUMENT;
624                     else
625                         i = OE_RECOGNISED;
626 #if TARGET == TARGET_UNIX
627                     __mp_diagflags &= ~FLG_LIST;
628                     __mp_diagflags |= FLG_EDIT;
629 #endif /* TARGET */
630                 }
631                 break;
632               case 'F':
633                 if (matchoption(o, "FAILFREQ"))
634                     if (*a == '\0')
635                         i = OE_NOARGUMENT;
636                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
637                         i = OE_BADNUMBER;
638                     else
639                     {
640                         h->ffreq = n;
641                         i = OE_RECOGNISED;
642                     }
643                 else if (matchoption(o, "FAILSEED"))
644                     if (*a == '\0')
645                         i = OE_NOARGUMENT;
646                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
647                         i = OE_BADNUMBER;
648                     else
649                     {
650                         h->fseed = n;
651                         i = OE_RECOGNISED;
652                     }
653                 else if (matchoption(o, "FREEBYTE"))
654                     if (*a == '\0')
655                         i = OE_NOARGUMENT;
656                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
657                         i = OE_BADNUMBER;
658                     else if (n > 0xFF)
659                         i = OE_BIGNUMBER;
660                     else
661                     {
662                         h->alloc.fbyte = n;
663                         i = OE_RECOGNISED;
664                     }
665                 else if (matchoption(o, "FREESTOP"))
666                     if (*a == '\0')
667                         i = OE_NOARGUMENT;
668                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
669                         i = OE_BADNUMBER;
670                     else
671                     {
672                         h->fstop = n;
673                         i = OE_RECOGNISED;
674                     }
675                 break;
676               case 'H':
677                 if (matchoption(o, "HELP"))
678                 {
679                     if (*a != '\0')
680                         i = OE_IGNARGUMENT;
681                     else
682                         i = OE_RECOGNISED;
683                     l = 1;
684                 }
685                 else if (matchoption(o, "HTML"))
686                 {
687                     if (*a != '\0')
688                         i = OE_IGNARGUMENT;
689                     else
690                         i = OE_RECOGNISED;
691                     __mp_diagflags |= FLG_HTMLNEXT;
692                 }
693                 break;
694               case 'L':
695                 if (matchoption(o, "LARGEBOUND"))
696                     if (*a == '\0')
697                         i = OE_NOARGUMENT;
698                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
699                         i = OE_BADNUMBER;
700                     else
701                     {
702                         if (n == 0)
703                             h->prof.lbound = MP_LARGEBOUND;
704                         else
705                             h->prof.lbound = n;
706                         i = OE_RECOGNISED;
707                     }
708                 else if (matchoption(o, "LEAKTABLE"))
709                 {
710                     if (*a != '\0')
711                         i = OE_IGNARGUMENT;
712                     else
713                         i = OE_RECOGNISED;
714                     h->flags |= FLG_LEAKTABLE;
715                 }
716                 else if (matchoption(o, "LIMIT"))
717                     if (*a == '\0')
718                         i = OE_NOARGUMENT;
719                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
720                         i = OE_BADNUMBER;
721                     else
722                     {
723                         h->limit = n;
724                         i = OE_RECOGNISED;
725                     }
726                 else if (matchoption(o, "LIST"))
727                 {
728                     if (*a != '\0')
729                         i = OE_IGNARGUMENT;
730                     else
731                         i = OE_RECOGNISED;
732 #if TARGET == TARGET_UNIX
733                     __mp_diagflags &= ~FLG_EDIT;
734                     __mp_diagflags |= FLG_LIST;
735 #endif /* TARGET */
736                 }
737                 else if (matchoption(o, "LOGALL"))
738                 {
739                     if (*a != '\0')
740                         i = OE_IGNARGUMENT;
741                     else
742                         i = OE_RECOGNISED;
743                     h->flags |= FLG_LOGALLOCS | FLG_LOGREALLOCS | FLG_LOGFREES |
744                                 FLG_LOGMEMORY;
745                 }
746                 else if (matchoption(o, "LOGALLOCS"))
747                 {
748                     if (*a != '\0')
749                         i = OE_IGNARGUMENT;
750                     else
751                         i = OE_RECOGNISED;
752                     h->flags |= FLG_LOGALLOCS;
753                 }
754                 else if (matchoption(o, "LOGFILE"))
755                     if (*a == '\0')
756                         i = OE_NOARGUMENT;
757                     else
758                     {
759                         f = a;
760                         i = OE_RECOGNISED;
761                     }
762                 else if (matchoption(o, "LOGFREES"))
763                 {
764                     if (*a != '\0')
765                         i = OE_IGNARGUMENT;
766                     else
767                         i = OE_RECOGNISED;
768                     h->flags |= FLG_LOGFREES;
769                 }
770                 else if (matchoption(o, "LOGMEMORY"))
771                 {
772                     if (*a != '\0')
773                         i = OE_IGNARGUMENT;
774                     else
775                         i = OE_RECOGNISED;
776                     h->flags |= FLG_LOGMEMORY;
777                 }
778                 else if (matchoption(o, "LOGREALLOCS"))
779                 {
780                     if (*a != '\0')
781                         i = OE_IGNARGUMENT;
782                     else
783                         i = OE_RECOGNISED;
784                     h->flags |= FLG_LOGREALLOCS;
785                 }
786                 break;
787               case 'M':
788                 if (matchoption(o, "MEDIUMBOUND"))
789                     if (*a == '\0')
790                         i = OE_NOARGUMENT;
791                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
792                         i = OE_BADNUMBER;
793                     else
794                     {
795                         if (n == 0)
796                             h->prof.mbound = MP_MEDIUMBOUND;
797                         else
798                             h->prof.mbound = n;
799                         i = OE_RECOGNISED;
800                     }
801                 break;
802               case 'N':
803                 if (matchoption(o, "NOFREE"))
804                     if (*a == '\0')
805                         i = OE_NOARGUMENT;
806                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
807                         i = OE_BADNUMBER;
808                     else
809                     {
810                         if (h->alloc.fmax = n)
811                             h->alloc.flags |= FLG_NOFREE;
812                         else
813                             h->alloc.flags &= ~FLG_NOFREE;
814                         i = OE_RECOGNISED;
815                     }
816                 else if (matchoption(o, "NOPROTECT"))
817                 {
818                     if (*a != '\0')
819                         i = OE_IGNARGUMENT;
820                     else
821                         i = OE_RECOGNISED;
822                     h->flags |= FLG_NOPROTECT;
823                 }
824                 break;
825               case 'O':
826                 if (matchoption(o, "OFLOWBYTE"))
827                     if (*a == '\0')
828                         i = OE_NOARGUMENT;
829                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
830                         i = OE_BADNUMBER;
831                     else if (n > 0xFF)
832                         i = OE_BIGNUMBER;
833                     else
834                     {
835                         h->alloc.obyte = n;
836                         i = OE_RECOGNISED;
837                     }
838                 else if (matchoption(o, "OFLOWSIZE"))
839                     if (*a == '\0')
840                         i = OE_NOARGUMENT;
841                     else if ((a[readnumber(a, (long *) &n, 1)] != '\0') ||
842                              ((n == 0) && (h->alloc.flags & FLG_PAGEALLOC)))
843                         i = OE_BADNUMBER;
844                     else
845                     {
846                         h->alloc.oflow = __mp_poweroftwo(n);
847                         if (h->alloc.flags & FLG_PAGEALLOC)
848                             h->alloc.oflow = __mp_roundup(h->alloc.oflow,
849                                              h->alloc.heap.memory.page);
850                         i = OE_RECOGNISED;
851                     }
852                 else if (matchoption(o, "OFLOWWATCH"))
853                 {
854                     if (*a != '\0')
855                         i = OE_IGNARGUMENT;
856                     else
857                         i = OE_RECOGNISED;
858 #if MP_WATCH_SUPPORT
859                     h->alloc.flags |= FLG_OFLOWWATCH;
860 #endif /* MP_WATCH_SUPPORT */
861                 }
862                 break;
863               case 'P':
864                 if (matchoption(o, "PAGEALLOC"))
865                     if (*a == '\0')
866                         i = OE_NOARGUMENT;
867                     else if (matchoption(a, "LOWER"))
868                     {
869 #if MP_PROTECT_SUPPORT
870                         h->alloc.flags |= FLG_PAGEALLOC;
871                         if (h->alloc.oflow == 0)
872                             h->alloc.oflow = 1;
873                         h->alloc.oflow = __mp_roundup(h->alloc.oflow,
874                                          h->alloc.heap.memory.page);
875 #endif /* MP_PROTECT_SUPPORT */
876                         i = OE_RECOGNISED;
877                     }
878                     else if (matchoption(a, "UPPER"))
879                     {
880 #if MP_PROTECT_SUPPORT
881                         h->alloc.flags |= FLG_PAGEALLOC | FLG_ALLOCUPPER;
882                         if (h->alloc.oflow == 0)
883                             h->alloc.oflow = 1;
884                         h->alloc.oflow = __mp_roundup(h->alloc.oflow,
885                                          h->alloc.heap.memory.page);
886 #endif /* MP_PROTECT_SUPPORT */
887                         i = OE_RECOGNISED;
888                     }
889                     else
890                         i = OE_LOWERORUPPER;
891                 else if (matchoption(o, "PRESERVE"))
892                 {
893                     if (*a != '\0')
894                         i = OE_IGNARGUMENT;
895                     else
896                         i = OE_RECOGNISED;
897                     h->alloc.flags |= FLG_PRESERVE;
898                 }
899                 else if (matchoption(o, "PROF"))
900                 {
901                     if (*a != '\0')
902                         i = OE_IGNARGUMENT;
903                     else
904                         i = OE_RECOGNISED;
905                     h->prof.profiling = 1;
906                 }
907                 else if (matchoption(o, "PROFFILE"))
908                     if (*a == '\0')
909                         i = OE_NOARGUMENT;
910                     else
911                     {
912                         p = a;
913                         i = OE_RECOGNISED;
914                     }
915                 else if (matchoption(o, "PROGFILE"))
916                     if (*a == '\0')
917                         i = OE_NOARGUMENT;
918                     else
919                     {
920                         h->alloc.heap.memory.prog = a;
921                         i = OE_RECOGNISED;
922                     }
923                 break;
924               case 'R':
925                 if (matchoption(o, "REALLOCSTOP"))
926                     if (*a == '\0')
927                         i = OE_NOARGUMENT;
928                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
929                         i = OE_BADNUMBER;
930                     else
931                     {
932                         h->rstop = n;
933                         i = OE_RECOGNISED;
934                     }
935                 break;
936               case 'S':
937                 if (matchoption(o, "SAFESIGNALS"))
938                 {
939                     if (*a != '\0')
940                         i = OE_IGNARGUMENT;
941                     else
942                         i = OE_RECOGNISED;
943                     h->flags |= FLG_SAFESIGNALS;
944                 }
945                 else if (matchoption(o, "SHOWALL"))
946                 {
947                     if (*a != '\0')
948                         i = OE_IGNARGUMENT;
949                     else
950                         i = OE_RECOGNISED;
951                     h->flags |= FLG_SHOWFREE | FLG_SHOWFREED | FLG_SHOWUNFREED |
952                                 FLG_SHOWMAP | FLG_SHOWSYMBOLS;
953                 }
954                 else if (matchoption(o, "SHOWFREE"))
955                 {
956                     if (*a != '\0')
957                         i = OE_IGNARGUMENT;
958                     else
959                         i = OE_RECOGNISED;
960                     h->flags |= FLG_SHOWFREE;
961                 }
962                 else if (matchoption(o, "SHOWFREED"))
963                 {
964                     if (*a != '\0')
965                         i = OE_IGNARGUMENT;
966                     else
967                         i = OE_RECOGNISED;
968                     h->flags |= FLG_SHOWFREED;
969                 }
970                 else if (matchoption(o, "SHOWMAP"))
971                 {
972                     if (*a != '\0')
973                         i = OE_IGNARGUMENT;
974                     else
975                         i = OE_RECOGNISED;
976                     h->flags |= FLG_SHOWMAP;
977                 }
978                 else if (matchoption(o, "SHOWSYMBOLS"))
979                 {
980                     if (*a != '\0')
981                         i = OE_IGNARGUMENT;
982                     else
983                         i = OE_RECOGNISED;
984                     h->flags |= FLG_SHOWSYMBOLS;
985                 }
986                 else if (matchoption(o, "SHOWUNFREED"))
987                 {
988                     if (*a != '\0')
989                         i = OE_IGNARGUMENT;
990                     else
991                         i = OE_RECOGNISED;
992                     h->flags |= FLG_SHOWUNFREED;
993                 }
994                 else if (matchoption(o, "SMALLBOUND"))
995                     if (*a == '\0')
996                         i = OE_NOARGUMENT;
997                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
998                         i = OE_BADNUMBER;
999                     else
1000                     {
1001                         if (n == 0)
1002                             h->prof.sbound = MP_SMALLBOUND;
1003                         else
1004                             h->prof.sbound = n;
1005                         i = OE_RECOGNISED;
1006                     }
1007                 break;
1008               case 'T':
1009                 if (matchoption(o, "TRACE"))
1010                 {
1011                     if (*a != '\0')
1012                         i = OE_IGNARGUMENT;
1013                     else
1014                         i = OE_RECOGNISED;
1015                     h->trace.tracing = 1;
1016                     h->alloc.heap.tracing = 1;
1017                 }
1018                 else if (matchoption(o, "TRACEFILE"))
1019                     if (*a == '\0')
1020                         i = OE_NOARGUMENT;
1021                     else
1022                     {
1023                         t = a;
1024                         i = OE_RECOGNISED;
1025                     }
1026                 break;
1027               case 'U':
1028                 if (matchoption(o, "UNFREEDABORT"))
1029                     if (*a == '\0')
1030                         i = OE_NOARGUMENT;
1031                     else if (a[readnumber(a, (long *) &n, 1)] != '\0')
1032                         i = OE_BADNUMBER;
1033                     else
1034                     {
1035                         h->uabort = n;
1036                         i = OE_RECOGNISED;
1037                     }
1038                 else if (matchoption(o, "USEDEBUG"))
1039                 {
1040                     if (*a != '\0')
1041                         i = OE_IGNARGUMENT;
1042                     else
1043                         i = OE_RECOGNISED;
1044                     h->syms.lineinfo = 1;
1045                 }
1046                 else if (matchoption(o, "USEMMAP"))
1047                 {
1048                     if (*a != '\0')
1049                         i = OE_IGNARGUMENT;
1050                     else
1051                         i = OE_RECOGNISED;
1052 #if MP_MMAP_SUPPORT
1053                     if (h->alloc.list.size == 0)
1054                         h->alloc.heap.memory.flags |= FLG_USEMMAP;
1055 #endif /* MP_MMAP_SUPPORT */
1056                 }
1057                 break;
1058               default:
1059                 break;
1060             }
1061             /* Now check the error code returned from attempting to match
1062              * the keyword and report if anything went wrong.
1063              */
1064             switch (i)
1065             {
1066               case OE_UNRECOGNISED:
1067                 if (*a == '\0')
1068                     __mp_error(ET_MAX, AT_MAX, NULL, 0, "unrecognised option "
1069                                "`%s'\n", o);
1070                 else
1071                     __mp_error(ET_MAX, AT_MAX, NULL, 0, "unrecognised option "
1072                                "`%s=%s'\n", o, a);
1073                 break;
1074               case OE_NOARGUMENT:
1075                 __mp_error(ET_MAX, AT_MAX, NULL, 0, "missing argument for "
1076                            "option `%s'\n", o);
1077                 break;
1078               case OE_BADNUMBER:
1079                 __mp_error(ET_MAX, AT_MAX, NULL, 0, "bad numeric argument `%s' "
1080                            "for option `%s'\n", a, o);
1081                 break;
1082               case OE_BADRANGE:
1083                 __mp_error(ET_MAX, AT_MAX, NULL, 0, "bad numeric range `%s' "
1084                            "for option `%s'\n", a, o);
1085                 break;
1086               case OE_BIGNUMBER:
1087                 __mp_error(ET_MAX, AT_MAX, NULL, 0, "numeric argument `%s' is "
1088                            "too large for option `%s'\n", a, o);
1089                 break;
1090               case OE_LOWERORUPPER:
1091                 __mp_error(ET_MAX, AT_MAX, NULL, 0, "must specify `LOWER' or "
1092                            "`UPPER' for option `%s'\n", o);
1093                 break;
1094               case OE_IGNARGUMENT:
1095                 __mp_warn(ET_MAX, AT_MAX, NULL, 0, "ignoring argument `%s' for "
1096                           "option `%s'\n", a, o);
1097                 break;
1098               default:
1099                 break;
1100             }
1101         }
1102         else if (*a != '\0')
1103             __mp_warn(ET_MAX, AT_MAX, NULL, 0, "missing option for argument "
1104                       "`%s'\n", a);
1105     }
1106     /* Check the validity of the profiling allocation boundaries.  There is
1107      * potential for error if either of the small or large bounds overlap the
1108      * medium bound and the medium bound is either 1 or the maximum sized
1109      * integer, but it will just result in wrong profiling and nothing more.
1110      */
1111     if (h->prof.sbound >= h->prof.mbound)
1112     {
1113         __mp_error(ET_MAX, AT_MAX, NULL, 0, "small allocation boundary `%lu' "
1114                    "overlaps medium allocation boundary `%lu'\n",
1115                    h->prof.sbound, h->prof.mbound);
1116         h->prof.sbound = h->prof.mbound - 1;
1117     }
1118     if (h->prof.lbound <= h->prof.mbound)
1119     {
1120         __mp_error(ET_MAX, AT_MAX, NULL, 0, "large allocation boundary `%lu' "
1121                    "overlaps medium allocation boundary `%lu'\n",
1122                    h->prof.lbound, h->prof.mbound);
1123         h->prof.lbound = h->prof.mbound + 1;
1124     }
1125     /* Show the quick-reference option summary if it was requested.
1126      */
1127     if (l != 0)
1128         showoptions();
1129     /* Set up the filenames of the log, profiling and tracing files if they
1130      * were overridden.
1131      */
1132     if (f != NULL)
1133         h->log = __mp_logfile(&h->alloc.heap.memory, f);
1134     if (p != NULL)
1135         h->prof.file = __mp_proffile(&h->alloc.heap.memory, p);
1136     if (t != NULL)
1137         h->trace.file = __mp_tracefile(&h->alloc.heap.memory, t);
1138 }
1139 
1140 
1141 /* Set mpatrol flags after the library has been initialised.
1142  */
1143 
1144 static
1145 unsigned long
setflags(infohead * h,unsigned long f,int u)1146 setflags(infohead *h, unsigned long f, int u)
1147 {
1148     unsigned long i;
1149 
1150     if (f == 0)
1151         return 0;
1152     for (i = 1; i != 0; i <<= 1)
1153         if (f & i)
1154         {
1155             f &= ~i;
1156             switch (i)
1157             {
1158               case OPT_CHECKALLOCS:
1159                 if (u == 0)
1160                     h->flags |= FLG_CHECKALLOCS;
1161                 else
1162                     h->flags &= ~FLG_CHECKALLOCS;
1163                 break;
1164               case OPT_CHECKREALLOCS:
1165                 if (u == 0)
1166                     h->flags |= FLG_CHECKREALLOCS;
1167                 else
1168                     h->flags &= ~FLG_CHECKREALLOCS;
1169                 break;
1170               case OPT_CHECKFREES:
1171                 if (u == 0)
1172                     h->flags |= FLG_CHECKFREES;
1173                 else
1174                     h->flags &= ~FLG_CHECKFREES;
1175                 break;
1176               case OPT_CHECKMEMORY:
1177                 if (u == 0)
1178                     h->flags |= FLG_CHECKMEMORY;
1179                 else
1180                     h->flags &= ~FLG_CHECKMEMORY;
1181                 break;
1182               case OPT_LOGALLOCS:
1183                 if (u == 0)
1184                     h->flags |= FLG_LOGALLOCS;
1185                 else
1186                     h->flags &= ~FLG_LOGALLOCS;
1187                 break;
1188               case OPT_LOGREALLOCS:
1189                 if (u == 0)
1190                     h->flags |= FLG_LOGREALLOCS;
1191                 else
1192                     h->flags &= ~FLG_LOGREALLOCS;
1193                 break;
1194               case OPT_LOGFREES:
1195                 if (u == 0)
1196                     h->flags |= FLG_LOGFREES;
1197                 else
1198                     h->flags &= ~FLG_LOGFREES;
1199                 break;
1200               case OPT_LOGMEMORY:
1201                 if (u == 0)
1202                     h->flags |= FLG_LOGMEMORY;
1203                 else
1204                     h->flags &= ~FLG_LOGMEMORY;
1205                 break;
1206               case OPT_SHOWMAP:
1207                 if (u == 0)
1208                     h->flags |= FLG_SHOWMAP;
1209                 else
1210                     h->flags &= ~FLG_SHOWMAP;
1211                 break;
1212               case OPT_SHOWSYMBOLS:
1213                 if (u == 0)
1214                     h->flags |= FLG_SHOWSYMBOLS;
1215                 else
1216                     h->flags &= ~FLG_SHOWSYMBOLS;
1217                 break;
1218               case OPT_SHOWFREE:
1219                 if (u == 0)
1220                     h->flags |= FLG_SHOWFREE;
1221                 else
1222                     h->flags &= ~FLG_SHOWFREE;
1223                 break;
1224               case OPT_SHOWFREED:
1225                 if (u == 0)
1226                     h->flags |= FLG_SHOWFREED;
1227                 else
1228                     h->flags &= ~FLG_SHOWFREED;
1229                 break;
1230               case OPT_SHOWUNFREED:
1231                 if (u == 0)
1232                     h->flags |= FLG_SHOWUNFREED;
1233                 else
1234                     h->flags &= ~FLG_SHOWUNFREED;
1235                 break;
1236               case OPT_LEAKTABLE:
1237                 if (u == 0)
1238                 {
1239                     h->flags |= FLG_LEAKTABLE;
1240                     h->ltable.tracing = 1;
1241                 }
1242                 else
1243                 {
1244                     h->flags &= ~FLG_LEAKTABLE;
1245                     h->ltable.tracing = 0;
1246                 }
1247                 break;
1248               case OPT_ALLOWOFLOW:
1249                 if (u == 0)
1250                     h->flags |= FLG_ALLOWOFLOW;
1251                 else
1252                     h->flags &= ~FLG_ALLOWOFLOW;
1253                 break;
1254               case OPT_CHECKFORK:
1255                 if (u == 0)
1256                     h->flags |= FLG_CHECKFORK;
1257                 else
1258                     h->flags &= ~FLG_CHECKFORK;
1259                 break;
1260               case OPT_EDIT:
1261                 if (u == 0)
1262                 {
1263 #if TARGET == TARGET_UNIX
1264                     __mp_diagflags &= ~FLG_LIST;
1265                     __mp_diagflags |= FLG_EDIT;
1266 #endif /* TARGET */
1267                 }
1268                 else
1269                 {
1270 #if TARGET == TARGET_UNIX
1271                     __mp_diagflags &= ~FLG_EDIT;
1272 #endif /* TARGET */
1273                 }
1274                 break;
1275               case OPT_LIST:
1276                 if (u == 0)
1277                 {
1278 #if TARGET == TARGET_UNIX
1279                     __mp_diagflags &= ~FLG_EDIT;
1280                     __mp_diagflags |= FLG_LIST;
1281 #endif /* TARGET */
1282                 }
1283                 else
1284                 {
1285 #if TARGET == TARGET_UNIX
1286                     __mp_diagflags &= ~FLG_LIST;
1287 #endif /* TARGET */
1288                 }
1289                 break;
1290               default:
1291                 f |= i;
1292                 break;
1293             }
1294         }
1295     return f;
1296 }
1297 
1298 
1299 /* Set an mpatrol option after the library has been initialised.
1300  */
1301 
1302 MP_GLOBAL
1303 unsigned long
__mp_set(infohead * h,unsigned long o,unsigned long v)1304 __mp_set(infohead *h, unsigned long o, unsigned long v)
1305 {
1306     unsigned long r;
1307 
1308     r = 0;
1309     switch (o)
1310     {
1311       case OPT_HELP:
1312         showoptions();
1313         break;
1314       case OPT_SETFLAGS:
1315         r = setflags(h, v, 0);
1316         break;
1317       case OPT_UNSETFLAGS:
1318         r = setflags(h, v, 1);
1319         break;
1320       case OPT_ALLOCSTOP:
1321         h->astop = v;
1322         break;
1323       case OPT_REALLOCSTOP:
1324         h->rstop = v;
1325         break;
1326       case OPT_FREESTOP:
1327         h->fstop = v;
1328         break;
1329       case OPT_ALLOCBYTE:
1330         if (v > 0xFF)
1331             v = 0xFF;
1332         h->alloc.abyte = v;
1333         break;
1334       case OPT_DEFALIGN:
1335         if ((v == 0) || (v > h->alloc.heap.memory.page))
1336             r = o;
1337         else
1338             h->alloc.heap.memory.align = __mp_poweroftwo(v);
1339         break;
1340       case OPT_LIMIT:
1341         h->limit = v;
1342         break;
1343       case OPT_FAILFREQ:
1344         h->ffreq = v;
1345         break;
1346       case OPT_FAILSEED:
1347         if (v == 0)
1348             v = (unsigned long) time(NULL);
1349         srand((unsigned int) v);
1350         h->fseed = v;
1351         break;
1352       case OPT_UNFREEDABORT:
1353         h->uabort = v;
1354         break;
1355       case OPT_AUTOSAVE:
1356         if (h->prof.autocount > 0)
1357             __mp_writeprofile(&h->prof, !(h->flags & FLG_NOPROTECT));
1358         h->prof.autosave = v;
1359         break;
1360       case OPT_CHECKLOWER:
1361         h->lrange = v;
1362         break;
1363       case OPT_CHECKUPPER:
1364         h->urange = v;
1365         break;
1366       case OPT_CHECKFREQ:
1367         if (v == 0)
1368             v = 1;
1369         h->check = v;
1370         break;
1371       case OPT_NOFREE:
1372         while (h->alloc.flist.size > v)
1373             __mp_recyclefreed(&h->alloc);
1374         if (h->alloc.fmax = v)
1375             h->alloc.flags |= FLG_NOFREE;
1376         else
1377             h->alloc.flags &= ~FLG_NOFREE;
1378         break;
1379       default:
1380         r = o;
1381         break;
1382     }
1383     return r;
1384 }
1385 
1386 
1387 /* Get mpatrol flags after the library has been initialised.
1388  */
1389 
1390 static
1391 unsigned long
getflags(infohead * h)1392 getflags(infohead *h)
1393 {
1394     unsigned long f;
1395 
1396     f = 0;
1397     if (h->flags & FLG_CHECKALLOCS)
1398         f |= OPT_CHECKALLOCS;
1399     if (h->flags & FLG_CHECKREALLOCS)
1400         f |= OPT_CHECKREALLOCS;
1401     if (h->flags & FLG_CHECKFREES)
1402         f |= OPT_CHECKFREES;
1403     if (h->flags & FLG_CHECKMEMORY)
1404         f |= OPT_CHECKMEMORY;
1405     if (h->flags & FLG_LOGALLOCS)
1406         f |= OPT_LOGALLOCS;
1407     if (h->flags & FLG_LOGREALLOCS)
1408         f |= OPT_LOGREALLOCS;
1409     if (h->flags & FLG_LOGFREES)
1410         f |= OPT_LOGFREES;
1411     if (h->flags & FLG_LOGMEMORY)
1412         f |= OPT_LOGMEMORY;
1413     if (h->flags & FLG_SHOWMAP)
1414         f |= OPT_SHOWMAP;
1415     if (h->flags & FLG_SHOWSYMBOLS)
1416         f |= OPT_SHOWSYMBOLS;
1417     if (h->flags & FLG_SHOWFREE)
1418         f |= OPT_SHOWFREE;
1419     if (h->flags & FLG_SHOWFREED)
1420         f |= OPT_SHOWFREED;
1421     if (h->flags & FLG_SHOWUNFREED)
1422         f |= OPT_SHOWUNFREED;
1423     if (h->flags & FLG_LEAKTABLE)
1424         f |= OPT_LEAKTABLE;
1425     if (h->flags & FLG_ALLOWOFLOW)
1426         f |= OPT_ALLOWOFLOW;
1427     if (h->prof.profiling)
1428         f |= OPT_PROF;
1429     if (h->trace.tracing)
1430         f |= OPT_TRACE;
1431     if (h->flags & FLG_SAFESIGNALS)
1432         f |= OPT_SAFESIGNALS;
1433     if (h->flags & FLG_NOPROTECT)
1434         f |= OPT_NOPROTECT;
1435     if (h->flags & FLG_CHECKFORK)
1436         f |= OPT_CHECKFORK;
1437     if (h->alloc.flags & FLG_PRESERVE)
1438         f |= OPT_PRESERVE;
1439     if (h->alloc.flags & FLG_OFLOWWATCH)
1440         f |= OPT_OFLOWWATCH;
1441     if (h->alloc.flags & FLG_PAGEALLOC)
1442         f |= OPT_PAGEALLOC;
1443     if (h->alloc.flags & FLG_ALLOCUPPER)
1444         f |= OPT_ALLOCUPPER;
1445     if (h->alloc.heap.memory.flags & FLG_USEMMAP)
1446         f |= OPT_USEMMAP;
1447     if (h->syms.lineinfo)
1448         f |= OPT_USEDEBUG;
1449     if (__mp_diagflags & FLG_EDIT)
1450         f |= OPT_EDIT;
1451     if (__mp_diagflags & FLG_LIST)
1452         f |= OPT_LIST;
1453     if (__mp_diagflags & FLG_HTML)
1454         f |= OPT_HTML;
1455     return f;
1456 }
1457 
1458 
1459 /* Get an mpatrol option after the library has been initialised.
1460  */
1461 
1462 MP_GLOBAL
1463 int
__mp_get(infohead * h,unsigned long o,unsigned long * v)1464 __mp_get(infohead *h, unsigned long o, unsigned long *v)
1465 {
1466     int r;
1467 
1468     r = 1;
1469     switch (o)
1470     {
1471       case OPT_HELP:
1472         *v = 0;
1473         break;
1474       case OPT_SETFLAGS:
1475         *v = getflags(h);
1476         break;
1477       case OPT_UNSETFLAGS:
1478         *v = ~getflags(h);
1479         break;
1480       case OPT_ALLOCSTOP:
1481         *v = h->astop;
1482         break;
1483       case OPT_REALLOCSTOP:
1484         *v = h->rstop;
1485         break;
1486       case OPT_FREESTOP:
1487         *v = h->fstop;
1488         break;
1489       case OPT_ALLOCBYTE:
1490         *v = h->alloc.abyte;
1491         break;
1492       case OPT_FREEBYTE:
1493         *v = h->alloc.fbyte;
1494         break;
1495       case OPT_OFLOWBYTE:
1496         *v = h->alloc.obyte;
1497         break;
1498       case OPT_OFLOWSIZE:
1499         *v = h->alloc.oflow;
1500         break;
1501       case OPT_DEFALIGN:
1502         *v = h->alloc.heap.memory.align;
1503         break;
1504       case OPT_LIMIT:
1505         *v = h->limit;
1506         break;
1507       case OPT_FAILFREQ:
1508         *v = h->ffreq;
1509         break;
1510       case OPT_FAILSEED:
1511         *v = h->fseed;
1512         break;
1513       case OPT_UNFREEDABORT:
1514         *v = h->uabort;
1515         break;
1516       case OPT_LOGFILE:
1517         *v = (unsigned long) h->log;
1518         break;
1519       case OPT_PROFFILE:
1520         *v = (unsigned long) h->prof.file;
1521         break;
1522       case OPT_TRACEFILE:
1523         *v = (unsigned long) h->trace.file;
1524         break;
1525       case OPT_PROGFILE:
1526         *v = (unsigned long) h->alloc.heap.memory.prog;
1527         break;
1528       case OPT_AUTOSAVE:
1529         *v = h->prof.autosave;
1530         break;
1531       case OPT_CHECKLOWER:
1532         *v = h->lrange;
1533         break;
1534       case OPT_CHECKUPPER:
1535         *v = h->urange;
1536         break;
1537       case OPT_CHECKFREQ:
1538         *v = h->check;
1539         break;
1540       case OPT_NOFREE:
1541         *v = h->alloc.fmax;
1542         break;
1543       case OPT_SMALLBOUND:
1544         *v = h->prof.sbound;
1545         break;
1546       case OPT_MEDIUMBOUND:
1547         *v = h->prof.mbound;
1548         break;
1549       case OPT_LARGEBOUND:
1550         *v = h->prof.lbound;
1551         break;
1552       default:
1553         r = 0;
1554         break;
1555     }
1556     return r;
1557 }
1558 
1559 
1560 #ifdef __cplusplus
1561 }
1562 #endif /* __cplusplus */
1563