Annotation of embedaddon/mpd/src/contrib/libpdel/util/typed_mem.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43:
44: #ifndef _KERNEL
45: #include <stdio.h>
46: #include <stddef.h>
47: #include <stdlib.h>
48: #include <stdarg.h>
49: #include <syslog.h>
50: #include <string.h>
51: #include <assert.h>
52: #include <errno.h>
53: #include <pthread.h>
54: #else
55: #include <sys/systm.h>
56: #include <machine/stdarg.h>
57: #include <malloc.h>
58: #include "util/kernelglue.h"
59: #endif
60:
61: #include "structs/structs.h"
62: #include "structs/type/array.h"
63: #include "structs/type/struct.h"
64: #include "structs/type/string.h"
65: #include "structs/type/int.h"
66: #include "util/gtree.h"
67: #include "util/typed_mem.h"
68:
69: /* Alignment, with a minimum of 4 bytes */
70: #if defined(__FreeBSD__)
71: #include <machine/param.h>
72: #define ALIGNMENT (_ALIGNBYTES + 1)
73: #else
74: #define ALIGNMENT 8 /* conservative guess */
75: #endif
76:
77: /* Summary information about a single type of memory */
78: struct mem_type {
79: char name[TYPED_MEM_TYPELEN];/* string for this type */
80: u_int32_t count; /* number of allocated blocks */
81: size_t total; /* total allocated bytes */
82: };
83:
84: /* Information about a single allocated block of memory */
85: struct mem_info {
86: void *mem; /* actual memory block */
87: size_t size; /* size of memory block */
88: struct mem_type *type; /* pointer to type info */
89: };
90:
91: /*
92: * Structs type for 'struct typed_mem_stats'
93: */
94: #define TYPED_MEM_STATS_MTYPE "typed_mem_stats"
95:
96: static const struct structs_type typebuf_type
97: = STRUCTS_FIXEDSTRING_TYPE(TYPED_MEM_TYPELEN);
98: static const struct structs_field typed_mem_typestats_fields[] = {
99: STRUCTS_STRUCT_FIELD(typed_mem_typestats, type, &typebuf_type),
100: STRUCTS_STRUCT_FIELD(typed_mem_typestats, allocs, &structs_type_uint),
101: STRUCTS_STRUCT_FIELD(typed_mem_typestats, bytes, &structs_type_uint),
102: STRUCTS_STRUCT_FIELD_END
103: };
104: static const struct structs_type typed_mem_typestats_type
105: = STRUCTS_STRUCT_TYPE(typed_mem_typestats, typed_mem_typestats_fields);
106: const struct structs_type typed_mem_stats_type
107: = STRUCTS_ARRAY_TYPE(&typed_mem_typestats_type,
108: TYPED_MEM_STATS_MTYPE, "type");
109:
110: /* We need to use the real functions in here */
111: #undef malloc
112: #undef calloc
113: #undef realloc
114: #undef reallocf
115: #undef free
116: #undef asprintf
117: #undef vasprintf
118:
119: /* How to print out problems */
120: #define WHINE(fmt, args...) (void)fprintf(stderr, fmt "\n" , ## args)
121:
122: /*
123: * Kernel glue
124: */
125: #ifdef _KERNEL
126:
127: #if TYPED_MEM_TRACE
128: #error TYPED_MEM_TRACE not supported in kernel mode
129: #endif
130:
131: #define malloc(x) kern_malloc(x)
132: #define realloc(x, y) kern_realloc(x, y)
133: #define free(x) kern_free(x)
134:
135: #define pthread_mutex_lock() 0
136: #define pthread_mutex_unlock() 0
137:
138: #undef WHINE
139: #define WHINE(fmt, args...) log(LOG_CRIT, fmt "\n" , ## args)
140:
141: #endif /* _KERNEL */
142:
143: /*
144: * Internal variables
145: */
146: static u_char typed_mem_started;
147: static u_char typed_mem_enabled;
148: static struct gtree *mem_tree;
149: static struct gtree *type_tree;
150: static u_int tree_node_size;
151:
152: #ifndef _KERNEL
153: static pthread_mutex_t typed_mem_mutex;
154: #endif
155:
156: /* Guard bytes. Should have an "aligned" length. */
157: static const u_char typed_mem_guard_data[] = { 0x34, 0x8e, 0x71, 0x9f };
158: static u_char typed_mem_guard[ALIGNMENT];
159:
160: /*
161: * Internal functions
162: */
163: static gtree_cmp_t type_cmp;
164: static gtree_print_t type_print;
165: static gtree_cmp_t mem_cmp;
166:
167: static struct mem_info *typed_mem_find(
168: #if TYPED_MEM_TRACE
169: const char *file, u_int line,
170: #endif
171: void *mem, const char *typename, const char *func);
172:
173: #ifndef _KERNEL
174: static gtree_print_t mem_print;
175: #else
176: #define mem_print NULL
177: #endif
178:
179: /*
180: * Enable typed memory.
181: */
182: int
183: typed_mem_enable(void)
184: {
185: pthread_mutexattr_t mattr;
186: int i;
187:
188: /* Already enabled? */
189: if (typed_mem_enabled)
190: return (0);
191:
192: /* Already started allocating memory? */
193: if (typed_mem_started) {
194: errno = EALREADY;
195: return (-1);
196: }
197:
198: /* Initialize recursive mutex */
199: if ((errno = pthread_mutexattr_init(&mattr)) != 0)
200: return (-1);
201: if ((errno = pthread_mutexattr_settype(&mattr,
202: PTHREAD_MUTEX_RECURSIVE)) != 0) {
203: pthread_mutexattr_destroy(&mattr);
204: return (-1);
205: }
206: if ((errno = pthread_mutex_init(&typed_mem_mutex, &mattr)) != 0) {
207: pthread_mutexattr_destroy(&mattr);
208: return (-1);
209: }
210: pthread_mutexattr_destroy(&mattr);
211:
212: /* Fill in guard bytes */
213: for (i = 0; i < ALIGNMENT; i++) {
214: typed_mem_guard[i] = typed_mem_guard_data[
215: i % sizeof(typed_mem_guard_data)];
216: }
217:
218: /* Done */
219: typed_mem_enabled = 1;
220: return (0);
221: }
222:
223: /*
224: * realloc(3) replacement
225: */
226: void *
227: typed_mem_realloc(
228: #if TYPED_MEM_TRACE
229: const char *file, u_int line,
230: #endif
231: const char *typename, void *mem, size_t size)
232: {
233: #if TYPED_MEM_TRACE
234: void *const omem = mem;
235: #endif
236: struct mem_info *info;
237: void *rtn = NULL;
238: int errno_save;
239: int removed;
240: int r;
241:
242: /* Check if typed memory is active */
243: typed_mem_started = 1;
244: if (!typed_mem_enabled || typename == NULL)
245: return (realloc(mem, size));
246:
247: /* Lock info */
248: r = pthread_mutex_lock(&typed_mem_mutex);
249: assert(r == 0);
250:
251: /* Initialize first */
252: if (mem_tree == NULL) {
253: if ((mem_tree = gtree_create(NULL, NULL,
254: mem_cmp, NULL, NULL, mem_print)) == NULL)
255: goto done;
256: if ((type_tree = gtree_create(NULL, NULL,
257: type_cmp, NULL, NULL, type_print)) == NULL) {
258: gtree_destroy(&mem_tree);
259: goto done;
260: }
261: tree_node_size = gtree_node_size();
262: }
263:
264: /* Find/create the memory descriptor block */
265: if (mem == NULL) {
266: struct mem_type *type;
267: struct mem_type tkey;
268:
269: /* Get memory and new descriptor block */
270: if ((info = malloc(sizeof(*info))) == NULL)
271: goto done;
272: if ((info->mem = malloc(size
273: + 2 * sizeof(typed_mem_guard))) == NULL) {
274: errno_save = errno;
275: free(info);
276: errno = errno_save;
277: goto done;
278: }
279: info->size = size;
280:
281: /* Find/create type descriptor for this memory type */
282: strncpy(tkey.name, typename, sizeof(tkey.name) - 1);
283: tkey.name[sizeof(tkey.name) - 1] = '\0';
284: if ((type = gtree_get(type_tree, &tkey)) == NULL) {
285: if ((type = malloc(sizeof(*type))) == NULL) {
286: errno_save = errno;
287: free(info->mem);
288: free(info);
289: errno = errno_save;
290: goto done;
291: }
292: strcpy(type->name, tkey.name);
293: type->count = 0;
294: type->total = 0;
295: if (gtree_put(type_tree, type) == -1) {
296: errno_save = errno;
297: free(type);
298: free(info->mem);
299: free(info);
300: errno = errno_save;
301: goto done;
302: }
303: }
304: info->type = type;
305:
306: /* Add block descriptor to mem tree */
307: if (gtree_put(mem_tree, info) == -1) {
308: errno_save = errno;
309: if (type->count == 0) { /* was a new type */
310: removed = gtree_remove(type_tree, type);
311: assert(removed);
312: free(type);
313: }
314: free(info->mem);
315: free(info);
316: errno = errno_save;
317: goto done;
318: }
319: } else {
320: void *node;
321:
322: /* Find memory descriptor */
323: #if TYPED_MEM_TRACE
324: info = typed_mem_find(file, line, mem, typename, "REALLOC");
325: #else
326: info = typed_mem_find(mem, typename, "REALLOC");
327: #endif
328:
329: /* Pre-allocate mem tree node */
330: if ((node = malloc(tree_node_size)) == NULL)
331: goto done;
332:
333: /* Get reallocated memory block */
334: if ((mem = realloc(info->mem,
335: size + 2 * sizeof(typed_mem_guard))) == NULL) {
336: errno_save = errno;
337: free(node);
338: errno = errno_save;
339: goto done;
340: }
341:
342: /* Subtract old block from type stats */
343: info->type->total -= info->size;
344: info->type->count--;
345:
346: /* Update block descriptor */
347: info->size = size;
348: if (info->mem != mem) {
349: removed = gtree_remove(mem_tree, info);
350: assert(removed);
351: info->mem = mem;
352: gtree_put_prealloc(mem_tree, info, node);
353: } else
354: free(node); /* we didn't need it */
355: }
356:
357: /* Add new block to type stats */
358: info->type->total += info->size;
359: info->type->count++;
360:
361: /* Install guard bytes */
362: memcpy(info->mem, typed_mem_guard, sizeof(typed_mem_guard));
363: memcpy((u_char *)info->mem + sizeof(typed_mem_guard) + info->size,
364: typed_mem_guard, sizeof(typed_mem_guard));
365:
366: #if TYPED_MEM_TRACE
367: /* Tracing */
368: {
369: const char *basename;
370:
371: if ((basename = strrchr(file, '/')) != NULL)
372: basename++;
373: else
374: basename = file;
375: fprintf(stderr, "%s:%u:ALLOC %p -> %p \"%s\" %u [%u]\n",
376: basename, line, omem, (u_char *)info->mem
377: + sizeof(typed_mem_guard), typename, size,
378: info->type->count);
379: }
380: #endif
381:
382: /* Return memory block */
383: rtn = (u_char *)info->mem + sizeof(typed_mem_guard);
384:
385: done:
386: /* Done */
387: r = pthread_mutex_unlock(&typed_mem_mutex);
388: assert(r == 0);
389: return (rtn);
390: }
391:
392: /*
393: * reallocf(3) replacement
394: */
395: void *
396: typed_mem_reallocf(
397: #if TYPED_MEM_TRACE
398: const char *file, u_int line,
399: #endif
400: const char *typename, void *mem, size_t size)
401: {
402: void *p;
403:
404: #if TYPED_MEM_TRACE
405: if ((p = typed_mem_realloc(file, line, typename, mem, size)) == NULL)
406: typed_mem_free(file, line, typename, mem);
407: #else
408: if ((p = typed_mem_realloc(typename, mem, size)) == NULL)
409: typed_mem_free(typename, mem);
410: #endif
411: return (p);
412: }
413:
414: /*
415: * free(3) replacement
416: *
417: * Note: it is OK if "typedname" points to memory within the region
418: * pointed to by "mem".
419: */
420: void
421: typed_mem_free(
422: #if TYPED_MEM_TRACE
423: const char *file, u_int line,
424: #endif
425: const char *typename, void *mem)
426: {
427: const int errno_save = errno;
428: struct mem_info *info;
429: int removed;
430: int r;
431:
432: /* free(NULL) does nothing */
433: if (mem == NULL)
434: return;
435:
436: /* Check if typed memory is active */
437: typed_mem_started = 1;
438: if (!typed_mem_enabled || typename == NULL) {
439: free(mem);
440: return;
441: }
442:
443: /* Lock info */
444: r = pthread_mutex_lock(&typed_mem_mutex);
445: assert(r == 0);
446:
447: /* Find memory descriptor */
448: #if TYPED_MEM_TRACE
449: info = typed_mem_find(file, line, mem, typename, "FREE");
450: #else
451: info = typed_mem_find(mem, typename, "FREE");
452: #endif
453:
454: #if TYPED_MEM_TRACE
455: /* Tracing */
456: {
457: const char *basename;
458:
459: if ((basename = strrchr(file, '/')) != NULL)
460: basename++;
461: else
462: basename = file;
463: fprintf(stderr, "%s:%u:FREE %p -> %p \"%s\" [%u]\n",
464: basename, line, mem, (void *)0,
465: typename, info->type->count);
466: }
467: #endif
468:
469: /* Subtract block from descriptor info */
470: info->type->total -= info->size;
471: if (--info->type->count == 0) {
472: assert(info->type->total == 0);
473: removed = gtree_remove(type_tree, info->type);
474: assert(removed);
475: free(info->type);
476: }
477:
478: /* Free memory and descriptor block */
479: removed = gtree_remove(mem_tree, info);
480: assert(removed);
481: free(info->mem);
482: free(info);
483:
484: /* Done */
485: r = pthread_mutex_unlock(&typed_mem_mutex);
486: assert(r == 0);
487: errno = errno_save;
488: }
489:
490: /*
491: * calloc(3) replacement
492: */
493: void *
494: typed_mem_calloc(
495: #if TYPED_MEM_TRACE
496: const char *file, u_int line,
497: #endif
498: const char *type, size_t num, size_t size)
499: {
500: void *mem;
501:
502: size *= num;
503: #if TYPED_MEM_TRACE
504: if ((mem = typed_mem_realloc(file, line, type, NULL, size)) == NULL)
505: return (NULL);
506: #else
507: if ((mem = typed_mem_realloc(type, NULL, size)) == NULL)
508: return (NULL);
509: #endif
510: memset(mem, 0, size);
511: return (mem);
512: }
513:
514: /*
515: * strdup(3) replacement
516: */
517: char *
518: typed_mem_strdup(
519: #if TYPED_MEM_TRACE
520: const char *file, u_int line,
521: #endif
522: const char *type, const char *string)
523: {
524: const int slen = strlen(string) + 1;
525: char *result;
526:
527: #if TYPED_MEM_TRACE
528: if ((result = typed_mem_realloc(file, line, type, NULL, slen)) == NULL)
529: return (NULL);
530: #else
531: if ((result = typed_mem_realloc(type, NULL, slen)) == NULL)
532: return (NULL);
533: #endif
534: memcpy(result, string, slen);
535: return (result);
536: }
537:
538: /*
539: * asprintf(3) replacement
540: */
541: int
542: typed_mem_asprintf(
543: #if TYPED_MEM_TRACE
544: const char *file, u_int line,
545: #endif
546: const char *type, char **ret, const char *fmt, ...)
547: {
548: va_list args;
549: int r;
550:
551: va_start(args, fmt);
552: #if TYPED_MEM_TRACE
553: r = typed_mem_vasprintf(file, line, type, ret, fmt, args);
554: #else
555: r = typed_mem_vasprintf(type, ret, fmt, args);
556: #endif
557: va_end(args);
558: return (r);
559: }
560:
561: /*
562: * vasprintf(3) replacement
563: */
564: int
565: typed_mem_vasprintf(
566: #if TYPED_MEM_TRACE
567: const char *file, u_int line,
568: #endif
569: const char *type, char **ret, const char *fmt, va_list args)
570: {
571: int errno_save;
572: char *s;
573: int r;
574:
575: if ((r = vasprintf(ret, fmt, args)) == -1) {
576: *ret = NULL;
577: return (-1);
578: }
579: if (!typed_mem_enabled)
580: return r;
581: s = *ret;
582: #if TYPED_MEM_TRACE
583: *ret = typed_mem_strdup(file, line, type, s);
584: #else
585: *ret = typed_mem_strdup(type, s);
586: #endif
587: errno_save = errno;
588: free(s);
589: if (*ret == NULL) {
590: errno = errno_save;
591: return (-1);
592: }
593: return (r);
594: }
595:
596: /*
597: * Get type for a memory block.
598: */
599: char *
600: typed_mem_type(const void *mem, char *typebuf)
601: {
602: struct mem_info *info = NULL;
603: struct mem_info ikey;
604: int r;
605:
606: /* Are we enabled? */
607: if (!typed_mem_enabled) {
608: errno = ENXIO;
609: return (NULL);
610: }
611:
612: /* Lock info */
613: r = pthread_mutex_lock(&typed_mem_mutex);
614: assert(r == 0);
615:
616: /* Find memory descriptor */
617: ikey.mem = (u_char *)mem - sizeof(typed_mem_guard);
618: if (mem_tree == NULL || (info = gtree_get(mem_tree, &ikey)) == NULL) {
619: errno = ENOENT;
620: typebuf = NULL;
621: goto done;
622: }
623:
624: /* Copy type */
625: strlcpy(typebuf, info->type->name, TYPED_MEM_TYPELEN);
626:
627: done:
628: /* Unlock info */
629: r = pthread_mutex_unlock(&typed_mem_mutex);
630: assert(r == 0);
631:
632: /* Done */
633: return (typebuf);
634: }
635:
636: /*
637: * Return typed memory usage statistics. The caller must free the
638: * array by calling "structs_free(&typed_mem_stats_type, NULL, stats)".
639: *
640: * Returns zero if successful, -1 (and sets errno) if not.
641: * If typed memory is disabled, errno = ENXIO.
642: */
643: int
644: typed_mem_usage(struct typed_mem_stats *stats)
645: {
646: struct mem_type *type;
647: int i;
648: int r;
649:
650: /* Check if enabled */
651: if (!typed_mem_enabled) {
652: errno = ENXIO;
653: return (-1);
654: }
655:
656: /* Lock info */
657: r = pthread_mutex_lock(&typed_mem_mutex);
658: assert(r == 0);
659:
660: /* Allocate array */
661: memset(stats, 0, sizeof(*stats));
662: if ((stats->elems = typed_mem_realloc(
663: #if TYPED_MEM_TRACE
664: __FILE__, __LINE__,
665: #endif
666: TYPED_MEM_STATS_MTYPE, NULL, (gtree_size(type_tree) + 1)
667: * sizeof(*stats->elems))) == NULL) {
668: r = pthread_mutex_unlock(&typed_mem_mutex);
669: assert(r == 0);
670: return (-1);
671: }
672:
673: /* Copy type stats */
674: for (i = 0, type = gtree_first(type_tree);
675: type != NULL; i++, type = gtree_next(type_tree, type)) {
676: struct typed_mem_typestats *const elem = &stats->elems[i];
677:
678: strlcpy(elem->type, type->name, sizeof(elem->type));
679: elem->allocs = type->count;
680: elem->bytes = type->total;
681: }
682: stats->length = i;
683:
684: /* Unlock info */
685: r = pthread_mutex_unlock(&typed_mem_mutex);
686: assert(r == 0);
687:
688: /* Done */
689: return (0);
690: }
691:
692: #ifndef _KERNEL
693:
694: /*
695: * Return usage statistics in a malloc'd string of the specified type.
696: */
697: void
698: typed_mem_dump(FILE *fp)
699: {
700: u_long total_blocks = 0;
701: u_long total_alloc = 0;
702: struct mem_type *type;
703: int r;
704:
705: /* Check if enabled */
706: if (!typed_mem_enabled) {
707: fprintf(fp, "Typed memory is not enabled.\n");
708: return;
709: }
710:
711: /* Print header */
712: fprintf(fp, " %-28s %10s %10s\n", "Type", "Count", "Total");
713: fprintf(fp, " %-28s %10s %10s\n", "----", "-----", "-----");
714:
715: /* Lock info */
716: r = pthread_mutex_lock(&typed_mem_mutex);
717: assert(r == 0);
718:
719: /* Print allocation types */
720: for (type = gtree_first(type_tree);
721: type != NULL; type = gtree_next(type_tree, type)) {
722: fprintf(fp, " %-28s %10u %10lu\n",
723: type->name, (int)type->count, (u_long)type->total);
724: total_blocks += type->count;
725: total_alloc += type->total;
726: }
727:
728: /* Print totals */
729: fprintf(fp, " %-28s %10s %10s\n", "", "-----", "-----");
730: fprintf(fp, " %-28s %10lu %10lu\n",
731: "Totals", total_blocks, total_alloc);
732:
733: /* Unlock info */
734: r = pthread_mutex_unlock(&typed_mem_mutex);
735: assert(r == 0);
736: }
737:
738: #endif /* !_KERNEL */
739:
740: /*
741: * Find memory block info descriptor and verify guard bytes
742: *
743: * This assumes the mutex is locked.
744: */
745: static struct mem_info *
746: typed_mem_find(
747: #if TYPED_MEM_TRACE
748: const char *file, u_int line,
749: #endif
750: void *mem, const char *typename, const char *func)
751: {
752: struct mem_info *info = NULL;
753: struct mem_info ikey;
754:
755: /* Find memory descriptor which must already exist */
756: ikey.mem = (u_char *)mem - sizeof(typed_mem_guard);
757: if (mem_tree == NULL || (info = gtree_get(mem_tree, &ikey)) == NULL) {
758: #if TYPED_MEM_TRACE
759: WHINE("%s:%u: %s() of unallocated block:"
760: " ptr=%p type=\"%s\"", file, line, func, mem, typename);
761: #else
762: WHINE("%s() of unallocated block:"
763: " ptr=%p type=\"%s\"", func, mem, typename);
764: #endif
765: assert(0);
766: }
767:
768: /* Check type is the same */
769: if (strncmp(info->type->name, typename, TYPED_MEM_TYPELEN - 1) != 0) {
770: #if TYPED_MEM_TRACE
771: WHINE("%s:%u: %s() with wrong type:"
772: " ptr=%p \"%s\" != \"%s\"", file, line,
773: func, mem, typename, info->type->name);
774: #else
775: WHINE("%s() with wrong type:"
776: " ptr=%p \"%s\" != \"%s\"",
777: func, mem, typename, info->type->name);
778: #endif
779: assert(0);
780: }
781:
782: /* Check ref count */
783: assert(info->type->count > 0);
784:
785: /* Check guard bytes */
786: if (memcmp(info->mem, typed_mem_guard, sizeof(typed_mem_guard)) != 0) {
787: #if TYPED_MEM_TRACE
788: WHINE("%s:%u: %s(): %s guard violated ptr=%p type=\"%s\"",
789: file, line, func, "head", mem, typename);
790: #else
791: WHINE("%s(): %s guard violated ptr=%p type=\"%s\"",
792: func, "head", mem, typename);
793: #endif
794: assert(0);
795: }
796: if (memcmp((u_char *)info->mem + sizeof(typed_mem_guard) + info->size,
797: typed_mem_guard, sizeof(typed_mem_guard)) != 0) {
798: #if TYPED_MEM_TRACE
799: WHINE("%s:%u: %s(): %s guard violated ptr=%p type=\"%s\"",
800: file, line, func, "tail", mem, typename);
801: #else
802: WHINE("%s(): %s guard violated ptr=%p type=\"%s\"",
803: func, "tail", mem, typename);
804: #endif
805: assert(0);
806: }
807:
808: /* Done */
809: return (info);
810: }
811:
812: /*
813: * Sort type descriptors by type string.
814: */
815: static int
816: type_cmp(struct gtree *g, const void *item1, const void *item2)
817: {
818: const struct mem_type *const type1 = item1;
819: const struct mem_type *const type2 = item2;
820:
821: return (strcmp(type1->name, type2->name));
822: }
823:
824: /*
825: * Print a type
826: */
827: static const char *
828: type_print(struct gtree *g, const void *item)
829: {
830: const struct mem_type *const type = item;
831:
832: return (type->name);
833: }
834:
835: /*
836: * Sort memory block descriptors by memory address.
837: */
838: static int
839: mem_cmp(struct gtree *g, const void *item1, const void *item2)
840: {
841: const struct mem_info *const info1 = item1;
842: const struct mem_info *const info2 = item2;
843:
844: if (info1->mem < info2->mem)
845: return (-1);
846: if (info1->mem > info2->mem)
847: return (1);
848: return (0);
849: }
850:
851: #ifndef _KERNEL
852:
853: /*
854: * Print a type
855: */
856: static const char *
857: mem_print(struct gtree *g, const void *item)
858: {
859: const struct mem_info *const info = item;
860: static char buf[32];
861:
862: snprintf(buf, sizeof(buf), "%p", info->mem);
863: return (buf);
864: }
865:
866: #endif /* !_KERNEL */
867:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>