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);
176 palacios_spinlock_deinit(&lock);
178 INFO("MEMCHECK: DEINITED\n");
180 // Note that this function could garbage collect at this
181 // point if we desired
185 void threshold(memcheck_state_t *m)
187 #if SHOW_THRESHOLD_WARNINGS
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);
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);
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);
219 void find_overlaps(memcheck_state_t *m)
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);
236 void palacios_memcheck_alloc(void *addr, unsigned long size, palacios_memcheck_memtype_t type)
238 memcheck_state_t *m=get_mem_entry();
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);
248 backtrace(m->allocator);
251 printmem("ALLOCATE", m);
258 void palacios_memcheck_free(void *addr,unsigned long size, palacios_memcheck_memtype_t type)
260 memcheck_state_t *m=find_mem_entry(addr,0,type); // don't care about the size now
263 DEBUG("MEMCHECK: FREEING UNTRACKED %s MEMORY AT 0x%p FOR %lu BYTES\n",TYPE_TO_STR(type),addr,size);
267 if (m->type==PALACIOS_PAGE_ALLOC) {
268 // need to verify sizes are identical
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);