Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


2ab86b237a8219d2d5ae3390cb13371f772f9a62
[palacios.git] / linux_module / memcheck.c
1 #include <linux/kernel.h>
2 #include <linux/kthread.h>
3 #include <linux/spinlock.h>
4
5 #include "palacios.h"
6
7 #include "memcheck.h"
8
9 // Whether not all allocations and frees will be printed
10 #define SHOW_ALL_ALLOCS    0
11
12 // Whether or now allocations outside of a size range will be printed
13 #define SHOW_THRESHOLD_WARNINGS 1
14 #define SMALL_KMALLOC_THRESHOLD 9
15 #define BIG_KMALLOC_THRESHOLD   ((1024*16)-1)
16 #define SMALL_VMALLOC_THRESHOLD 9
17 #define BIG_VMALLOC_THRESHOLD   ((1024*1024)-1)
18 #define SMALL_PAGE_ALLOC_THRESHOLD (4096-1)
19 #define BIG_PAGE_ALLOC_THRESHOLD   (4096*8-1)
20
21 // How far up the stack to track the caller
22 // 0 => palacios_...
23 // 1 => v3_alloc...
24 // 2 => caller of v3_alloc..
25 // ... 
26 #define STEP_BACK_DEPTH_FIRST 1
27 #define STEP_BACK_DEPTH_LAST  4
28 #define STEP_BACK_DEPTH       (STEP_BACK_DEPTH_LAST-STEP_BACK_DEPTH_FIRST+1)
29
30
31 typedef struct {
32   int  inuse;         // 1=inuse
33   palacios_memcheck_memtype_t type; 
34                       // PALACIOS_KMALLOC,VMALLOC,PAGE_ALLOC
35   void *addr;         // the allocated block's address
36   unsigned long size; // the allocated block's size
37   void *allocator[STEP_BACK_DEPTH];
38                       // who allocated this
39 } memcheck_state_t;
40
41
42 // This lock is currently used only to control
43 // allocation of entries in the global state
44 static spinlock_t lock; 
45 static memcheck_state_t state[NUM_ALLOCS];
46
47 static void printmem(char *prefix, memcheck_state_t *m);
48
49
50 static memcheck_state_t *get_mem_entry(void)
51 {
52   int i;
53   unsigned long f;
54   memcheck_state_t *m;
55
56   palacios_spinlock_lock_irqsave(&lock,f);
57
58   for (i=0;i<NUM_ALLOCS;i++) { 
59     m=&(state[i]);
60     if (!(m->inuse)) { 
61       m->inuse=1;
62       break;
63     }
64   }
65
66   palacios_spinlock_unlock_irqrestore(&lock,f);
67   
68   if (i<NUM_ALLOCS) { 
69     return m;
70   } else {
71     return 0;
72   }
73 }
74
75
76 static memcheck_state_t *find_mem_entry(void *addr, unsigned long size, palacios_memcheck_memtype_t type)
77 {
78   int i;
79   memcheck_state_t *m;
80
81   for (i=0;i<NUM_ALLOCS;i++) { 
82     m=&(state[i]);
83     if (m->inuse && m->addr == addr && m->type==type) { 
84       if (size) {
85         if (m->size==size) { 
86           return m;
87         } else {
88           return 0;
89         }
90       } else {
91         return m;
92       }
93     }
94   }
95   return 0;
96 }
97
98
99 static void free_mem_entry(memcheck_state_t *m)
100 {
101   m->inuse=0;
102 }
103
104
105 void palacios_memcheck_init()
106 {
107   memset(state,0,sizeof(memcheck_state_t)*NUM_ALLOCS);
108   palacios_spinlock_init(&lock);
109   DEBUG("MEMCHECK: MEMORY CHECKING INITED\n");
110 }
111
112 //
113 // This needs to be defined explictly since the intrinsic does not take a var
114 //
115 #define backtrace(t) \
116   t[0]=__builtin_return_address(STEP_BACK_DEPTH_FIRST); \
117   t[1]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+1); \
118   t[2]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+2); \
119   t[3]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+3); 
120
121 //
122 // For printing a backtrace
123 //
124 //
125 #define backtrace_format "%pS << %pS << %pS << %pS"
126 #define backtrace_expand(t) ((t)[0]),((t)[1]),((t)[2]),((t)[3])
127
128
129 #if 0
130 static void clear_trace(void **trace)
131 {
132   int i;
133
134   for (i=0;i<STEP_BACK_DEPTH;i++) { 
135     trace[i]=0;
136   }
137 }
138 #endif
139
140 #define TYPE_TO_STR(type) ((type)==PALACIOS_KMALLOC ? "kmalloc" : \
141                            (type)==PALACIOS_VMALLOC ? "vmalloc" : \
142                            (type)==PALACIOS_PAGE_ALLOC ? "pagealloc" : "UNKNOWN")
143
144
145 static void printmem(char *prefix, memcheck_state_t *m)
146 {
147   if (!m || !(m->addr) ) { 
148     DEBUG("MEMCHECK: %s: memory state 0x%p BOGUS\n",prefix,m);
149     return;
150   }
151   if (m->addr) { 
152     DEBUG("MEMCHECK: %s: %s memory at 0x%p for %lu bytes allocator=" 
153           backtrace_format
154           "\n",
155           prefix,
156           TYPE_TO_STR(m->type),
157           m->addr,
158           m->size,
159           backtrace_expand(m->allocator));
160   }
161 }
162
163
164 void palacios_memcheck_deinit()
165 {
166   int i;
167   memcheck_state_t *m;
168   
169   for (i=0;i<NUM_ALLOCS;i++) { 
170     m=&(state[i]);
171     if (m->inuse) { 
172       printmem("ALLOCATED MEMORY AT DEINIT",m);
173     } 
174   }
175   INFO("MEMCHECK: DEINITED\n");
176
177   // Note that this function could garbage collect at this 
178   // point if we desired
179 }
180
181
182 void threshold(memcheck_state_t *m)
183 {
184 #if SHOW_THRESHOLD_WARNINGS
185   switch (m->type) {
186   case PALACIOS_KMALLOC:
187     if (m->size < SMALL_KMALLOC_THRESHOLD ||
188         m->size > BIG_KMALLOC_THRESHOLD) { 
189       DEBUG("MEMCHECK: ALLOCATION EXCEEDS THRESHOLDS of %u and %u\n",
190             SMALL_KMALLOC_THRESHOLD, BIG_KMALLOC_THRESHOLD);
191       printmem("ALLOCATION EXCEEDS",m);
192     }
193     break;
194   case PALACIOS_VMALLOC:
195     if (m->size < SMALL_VMALLOC_THRESHOLD ||
196         m->size > BIG_VMALLOC_THRESHOLD) { 
197       DEBUG("MEMCHECK: ALLOCATION EXCEEDS THRESHOLDS of %u and %u\n",
198             SMALL_VMALLOC_THRESHOLD, BIG_VMALLOC_THRESHOLD);
199       printmem("ALLOCATION EXCEEDS",m);
200     }
201     break;
202   case PALACIOS_PAGE_ALLOC:
203     if (m->size < SMALL_PAGE_ALLOC_THRESHOLD ||
204         m->size > BIG_PAGE_ALLOC_THRESHOLD) { 
205       DEBUG("MEMCHECK: ALLOCATION EXCEEDS THRESHOLDS of %u and %u\n",
206             SMALL_PAGE_ALLOC_THRESHOLD, BIG_PAGE_ALLOC_THRESHOLD);
207       printmem("ALLOCATION EXCEEDS",m);
208     }
209     break;
210   default: 
211     break;
212   }
213 #endif
214 }
215
216 void find_overlaps(memcheck_state_t *m)
217 {
218   int i;
219   for (i=0;i<NUM_ALLOCS;i++) {
220     memcheck_state_t *s = &(state[i]);
221     if (s->inuse && s!=m && s->type==m->type) {
222       if (((m->addr >= s->addr) && (m->addr < (s->addr+s->size))) ||
223           (((m->addr+m->size-1) >= s->addr) && ((m->addr+m->size-1) < (s->addr+s->size))) ||
224           ((m->addr < s->addr) && (m->addr+m->size-1)>=(s->addr+s->size))) { 
225         DEBUG("MEMCHECK: OVERLAP DETECTED\n");
226         printmem("OVERLAP (0)",s);
227         printmem("OVERLAP (1)",s);
228       }
229     }
230   }
231 }
232
233 void palacios_memcheck_alloc(void *addr, unsigned long size, palacios_memcheck_memtype_t type)
234 {
235   memcheck_state_t *m=get_mem_entry();
236
237   if (!m) { 
238     DEBUG("MEMCHECK: UNABLE TO ALLOCATE TRACKING DATA FOR %s ALLOC AT 0x%p FOR %lu BYTES\n",
239           TYPE_TO_STR(type),addr,size);
240     return;
241   }
242   m->type=type;
243   m->addr=addr;
244   m->size=size;
245   backtrace(m->allocator);
246
247 #if SHOW_ALL_ALLOCS
248   printmem("ALLOCATE", m);
249 #endif
250
251   threshold(m);
252   find_overlaps(m);
253 }
254   
255 void palacios_memcheck_free(void *addr,unsigned long size, palacios_memcheck_memtype_t type)
256 {
257   memcheck_state_t *m=find_mem_entry(addr,0,type); // don't care about the size now
258   
259   if (!m){
260     DEBUG("MEMCHECK: FREEING UNTRACKED %s MEMORY AT 0x%p FOR %lu BYTES\n",TYPE_TO_STR(type),addr,size);
261     return;
262   }
263
264   if (m->type==PALACIOS_PAGE_ALLOC) { 
265     // need to verify sizes are identical
266     if (size!=m->size) {
267       DEBUG("MEMCHECK: FREEING %s MEMORY AT 0x%p FOR %lu bytes, BUT MATCHING ENTRY HAS %lu BYTES\n",TYPE_TO_STR(type),addr,size,m->size);
268       printmem("MATCHING ENTRY",m);
269     }
270   }
271
272 #if SHOW_ALL_ALLOCS
273   printmem("FREE",m);
274 #endif
275
276   free_mem_entry(m);
277 }
278