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.


17894c6c825d5328583d7f3d1769432401782efc
[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
176   palacios_spinlock_deinit(&lock);
177
178   INFO("MEMCHECK: DEINITED\n");
179
180   // Note that this function could garbage collect at this 
181   // point if we desired
182 }
183
184
185 void threshold(memcheck_state_t *m)
186 {
187 #if SHOW_THRESHOLD_WARNINGS
188   switch (m->type) {
189   case PALACIOS_KMALLOC:
190     if (m->size < SMALL_KMALLOC_THRESHOLD ||
191         m->size > BIG_KMALLOC_THRESHOLD) { 
192       DEBUG("MEMCHECK: ALLOCATION EXCEEDS THRESHOLDS of %u and %u\n",
193             SMALL_KMALLOC_THRESHOLD, BIG_KMALLOC_THRESHOLD);
194       printmem("ALLOCATION EXCEEDS",m);
195     }
196     break;
197   case PALACIOS_VMALLOC:
198     if (m->size < SMALL_VMALLOC_THRESHOLD ||
199         m->size > BIG_VMALLOC_THRESHOLD) { 
200       DEBUG("MEMCHECK: ALLOCATION EXCEEDS THRESHOLDS of %u and %u\n",
201             SMALL_VMALLOC_THRESHOLD, BIG_VMALLOC_THRESHOLD);
202       printmem("ALLOCATION EXCEEDS",m);
203     }
204     break;
205   case PALACIOS_PAGE_ALLOC:
206     if (m->size < SMALL_PAGE_ALLOC_THRESHOLD ||
207         m->size > BIG_PAGE_ALLOC_THRESHOLD) { 
208       DEBUG("MEMCHECK: ALLOCATION EXCEEDS THRESHOLDS of %u and %u\n",
209             SMALL_PAGE_ALLOC_THRESHOLD, BIG_PAGE_ALLOC_THRESHOLD);
210       printmem("ALLOCATION EXCEEDS",m);
211     }
212     break;
213   default: 
214     break;
215   }
216 #endif
217 }
218
219 void find_overlaps(memcheck_state_t *m)
220 {
221   int i;
222   for (i=0;i<NUM_ALLOCS;i++) {
223     memcheck_state_t *s = &(state[i]);
224     if (s->inuse && s!=m && s->type==m->type) {
225       if (((m->addr >= s->addr) && (m->addr < (s->addr+s->size))) ||
226           (((m->addr+m->size-1) >= s->addr) && ((m->addr+m->size-1) < (s->addr+s->size))) ||
227           ((m->addr < s->addr) && (m->addr+m->size-1)>=(s->addr+s->size))) { 
228         DEBUG("MEMCHECK: OVERLAP DETECTED\n");
229         printmem("OVERLAP (0)",s);
230         printmem("OVERLAP (1)",s);
231       }
232     }
233   }
234 }
235
236 void palacios_memcheck_alloc(void *addr, unsigned long size, palacios_memcheck_memtype_t type)
237 {
238   memcheck_state_t *m=get_mem_entry();
239
240   if (!m) { 
241     DEBUG("MEMCHECK: UNABLE TO ALLOCATE TRACKING DATA FOR %s ALLOC AT 0x%p FOR %lu BYTES\n",
242           TYPE_TO_STR(type),addr,size);
243     return;
244   }
245   m->type=type;
246   m->addr=addr;
247   m->size=size;
248   backtrace(m->allocator);
249
250 #if SHOW_ALL_ALLOCS
251   printmem("ALLOCATE", m);
252 #endif
253
254   threshold(m);
255   find_overlaps(m);
256 }
257   
258 void palacios_memcheck_free(void *addr,unsigned long size, palacios_memcheck_memtype_t type)
259 {
260   memcheck_state_t *m=find_mem_entry(addr,0,type); // don't care about the size now
261   
262   if (!m){
263     DEBUG("MEMCHECK: FREEING UNTRACKED %s MEMORY AT 0x%p FOR %lu BYTES\n",TYPE_TO_STR(type),addr,size);
264     return;
265   }
266
267   if (m->type==PALACIOS_PAGE_ALLOC) { 
268     // need to verify sizes are identical
269     if (size!=m->size) {
270       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);
271       printmem("MATCHING ENTRY",m);
272     }
273   }
274
275 #if SHOW_ALL_ALLOCS
276   printmem("FREE",m);
277 #endif
278
279   free_mem_entry(m);
280 }
281