Version 1.01
[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 = memalloc ? memalloc->next : NULL;
45       if (memalloc) {
46         if (memalloc->next)
47           memalloc->next->prev = tmp;
48         memalloc->next = tmp;
49       }
50       else
51         memalloc = tmp;
52       if (heap_debug)
53         fprintf(stderr, "heap %p req %08lx alloc %08lx @ %p track %p next %p\n", memalloc, tmp->requested, tmp->allocated, tmp->ptr, tmp, memalloc->next);
54     }
55   }
56   else { // free allocation
57     struct mem_track *p = memalloc;
58     while (p) {
59       if(heap_debug)
60         fprintf(stderr, "%sheap %p free %08lx @ %p track %p next %p\n", (p->ptr != ptr ? "  " : ""), memalloc, p->requested, p->ptr, p, p->next);
61       if (ptr == NULL-1 || p->ptr == ptr) { // free all or a specific allocation
62         tmp = p->next;
63         if (p->prev)
64           p->prev->next = p->next;
65         if (p->next)
66           p->next->prev = p->prev;
67         free(p->ptr);
68         if (memalloc == p)
69           memalloc = tmp;
70         p = tmp;
71         if (ptr != NULL-1) // only freeing a specific allocation
72           break;
73       } else
74         p = p->next;
75     }
76   }
77   return result;
78 }
79