1 #include <linux/kernel.h>
2 #include <linux/kthread.h>
3 #include <linux/spinlock.h>
9 // Whether not all allocations and frees will be printed
10 #define SHOW_ALL_ALLOCS 0
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)
21 // How far up the stack to track the caller
24 // 2 => caller of v3_alloc..
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)
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];
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];
47 static void printmem(char *prefix, memcheck_state_t *m);
50 static memcheck_state_t *get_mem_entry(void)
56 palacios_spinlock_lock_irqsave(&lock,f);
58 for (i=0;i<NUM_ALLOCS;i++) {
66 palacios_spinlock_unlock_irqrestore(&lock,f);
76 static memcheck_state_t *find_mem_entry(void *addr, unsigned long size, palacios_memcheck_memtype_t type)
81 for (i=0;i<NUM_ALLOCS;i++) {
83 if (m->inuse && m->addr == addr && m->type==type) {
99 static void free_mem_entry(memcheck_state_t *m)
105 void palacios_memcheck_init()
107 memset(state,0,sizeof(memcheck_state_t)*NUM_ALLOCS);
108 palacios_spinlock_init(&lock);
109 DEBUG("MEMCHECK: MEMORY CHECKING INITED\n");
113 // This needs to be defined explictly since the intrinsic does not take a var
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);
122 // For printing a backtrace
125 #define backtrace_format "%pS << %pS << %pS << %pS"
126 #define backtrace_expand(t) ((t)[0]),((t)[1]),((t)[2]),((t)[3])
130 static void clear_trace(void **trace)
134 for (i=0;i<STEP_BACK_DEPTH;i++) {
140 #define TYPE_TO_STR(type) ((type)==PALACIOS_KMALLOC ? "kmalloc" : \
141 (type)==PALACIOS_VMALLOC ? "vmalloc" : \
142 (type)==PALACIOS_PAGE_ALLOC ? "pagealloc" : "UNKNOWN")
145 static void printmem(char *prefix, memcheck_state_t *m)
147 if (!m || !(m->addr) ) {
148 DEBUG("MEMCHECK: %s: memory state 0x%p BOGUS\n",prefix,m);
152 DEBUG("MEMCHECK: %s: %s memory at 0x%p for %lu bytes allocator="
156 TYPE_TO_STR(m->type),
159 backtrace_expand(m->allocator));
164 void palacios_memcheck_deinit()
169 for (i=0;i<NUM_ALLOCS;i++) {
172 printmem("ALLOCATED MEMORY AT DEINIT",m);
175 INFO("MEMCHECK: DEINITED\n");
177 // Note that this function could garbage collect at this
178 // point if we desired
182 void threshold(memcheck_state_t *m)
184 #if SHOW_THRESHOLD_WARNINGS
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);
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);
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);
216 void find_overlaps(memcheck_state_t *m)
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);
233 void palacios_memcheck_alloc(void *addr, unsigned long size, palacios_memcheck_memtype_t type)
235 memcheck_state_t *m=get_mem_entry();
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);
245 backtrace(m->allocator);
248 printmem("ALLOCATE", m);
255 void palacios_memcheck_free(void *addr,unsigned long size, palacios_memcheck_memtype_t type)
257 memcheck_state_t *m=find_mem_entry(addr,0,type); // don't care about the size now
260 DEBUG("MEMCHECK: FREEING UNTRACKED %s MEMORY AT 0x%p FOR %lu BYTES\n",TYPE_TO_STR(type),addr,size);
264 if (m->type==PALACIOS_PAGE_ALLOC) {
265 // need to verify sizes are identical
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);