Correct the usage description
[firmware_extractor.git] / heap_reap.c
1 /* Experimental tracking of heap allocations for easy reaping no matter what the code path is
2  * Copyright 2016 TJ <hacker@iam.tj>
3  * Licensed on the terms of the GNU General Public License version 3.
4  *
5  * Both tasks are in the same function to take advantage of local static variables that are
6  * persistent across calls but invisible to code outside the function.
7  */
8
9 #include "heap_reap.h"
10 #include <stdio.h>
11
12 unsigned int heap_debug = 0;
13
14 struct mem_track {
15   void *ptr;
16   struct mem_track *prev;
17   struct mem_track *next;
18   size_t requested;
19   size_t allocated;
20 };
21
22 /* 
23  * @param ptr   NULL: calloc(nmemb, size), NULL-1: reap all, otherwise free(ptr)
24  * @param nmemb number of elements of size to allocate
25  * @param size  size if each element
26  */
27 void *
28 heap_and_reap(void *ptr, size_t nmemb, size_t size)
29 {
30   static struct mem_track *memalloc = NULL;
31   struct mem_track *tmp;
32   void *result = NULL;
33
34   if (ptr == NULL) { 
35     // allocate requested memory and 'hide' the struct mem_track at the end of it
36     size_t dwords = ((nmemb * size + sizeof(struct mem_track)) / 4) + 1;
37
38     if ((result = calloc(dwords, 4)) != NULL) {
39       tmp = (struct mem_track *) (result + (dwords * 4) - sizeof(struct mem_track)  );
40       tmp->allocated = dwords * 4;
41       tmp->requested = nmemb * size;
42       tmp->ptr = result;
43       tmp->prev = memalloc;
44       tmp->next = NULL;
45       if (memalloc)
46         memalloc->next = tmp;
47       else
48         memalloc = tmp;
49       if (heap_debug)
50         fprintf(stderr, "heap req %08lx alloc %08lx @ %p\n", tmp->requested, tmp->allocated, tmp);
51     }
52   }
53   else { // free allocation
54     struct mem_track *p = memalloc;
55     while (p) {
56       if (ptr == NULL-1 || p->ptr == ptr) { // free all or a specific allocation
57         if (heap_debug)
58           fprintf(stderr, "heap free %08lx @ %p\n", p->allocated, p);
59         tmp = p->next;
60         if (p->prev)
61           p->prev->next = p->next;
62         if (p->next)
63           p->next->prev = p->prev;
64         free(p->ptr);
65         if (memalloc == p)
66           memalloc = tmp;
67         p = tmp;
68         if (ptr != NULL-1) // only freeing a specific allocation
69           break;
70       } else
71         p = p->next;
72     }
73   }
74   return result;
75 }
76