This source file includes following definitions.
- TAILQ_HEAD
- debug_free
- debug_malloc_init
- debug_malloc_allocate_free
- debug_malloc_print
- debug_malloc_assert_allocated
- debug_malloc_printit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 #include <sys/param.h>
54 #include <sys/proc.h>
55 #include <sys/kernel.h>
56 #include <sys/malloc.h>
57 #include <sys/systm.h>
58 #include <sys/pool.h>
59
60 #include <uvm/uvm.h>
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 int debug_malloc_type = -1;
76 int debug_malloc_size = -1;
77 int debug_malloc_size_lo = -1;
78 int debug_malloc_size_hi = -1;
79
80
81
82
83
84 #define MALLOC_DEBUG_CHUNKS 16
85
86 void debug_malloc_allocate_free(int);
87
88 struct debug_malloc_entry {
89 TAILQ_ENTRY(debug_malloc_entry) md_list;
90 vaddr_t md_va;
91 paddr_t md_pa;
92 size_t md_size;
93 int md_type;
94 };
95
96 TAILQ_HEAD(,debug_malloc_entry) debug_malloc_freelist;
97 TAILQ_HEAD(,debug_malloc_entry) debug_malloc_usedlist;
98
99 int debug_malloc_allocs;
100 int debug_malloc_frees;
101 int debug_malloc_pages;
102 int debug_malloc_chunks_on_freelist;
103
104 int debug_malloc_initialized;
105
106 struct pool debug_malloc_pool;
107
108 int
109 debug_malloc(unsigned long size, int type, int flags, void **addr)
110 {
111 struct debug_malloc_entry *md = NULL;
112 int s, wait = (flags & M_NOWAIT) == 0;
113
114
115 if (((type != debug_malloc_type && debug_malloc_type != 0) ||
116 (size != debug_malloc_size && debug_malloc_size != 0) ||
117 (debug_malloc_size_lo != -1 && size < debug_malloc_size_lo) ||
118 (debug_malloc_size_hi != -1 && size > debug_malloc_size_hi) ||
119 !debug_malloc_initialized) && type != M_DEBUG)
120 return (0);
121
122
123 if (size > PAGE_SIZE)
124 return (0);
125
126 s = splvm();
127 if (debug_malloc_chunks_on_freelist < MALLOC_DEBUG_CHUNKS)
128 debug_malloc_allocate_free(wait);
129
130 md = TAILQ_FIRST(&debug_malloc_freelist);
131 if (md == NULL) {
132 splx(s);
133 return (0);
134 }
135 TAILQ_REMOVE(&debug_malloc_freelist, md, md_list);
136 debug_malloc_chunks_on_freelist--;
137
138 TAILQ_INSERT_HEAD(&debug_malloc_usedlist, md, md_list);
139 debug_malloc_allocs++;
140 splx(s);
141
142 pmap_kenter_pa(md->md_va, md->md_pa, VM_PROT_READ|VM_PROT_WRITE);
143 pmap_update(pmap_kernel());
144
145 md->md_size = size;
146 md->md_type = type;
147
148
149
150
151
152 *addr = (void *)(md->md_va + PAGE_SIZE - roundup(size, sizeof(long)));
153 return (1);
154 }
155
156 int
157 debug_free(void *addr, int type)
158 {
159 struct debug_malloc_entry *md;
160 vaddr_t va;
161 int s;
162
163 if (type != debug_malloc_type && debug_malloc_type != 0 &&
164 type != M_DEBUG)
165 return (0);
166
167
168
169
170 va = trunc_page((vaddr_t)addr);
171
172 s = splvm();
173 TAILQ_FOREACH(md, &debug_malloc_usedlist, md_list)
174 if (md->md_va == va)
175 break;
176
177
178
179
180
181 if (md == NULL) {
182
183
184
185 TAILQ_FOREACH(md, &debug_malloc_freelist, md_list)
186 if (md->md_va == va)
187 panic("debug_free: already free");
188 splx(s);
189 return (0);
190 }
191
192 debug_malloc_frees++;
193 TAILQ_REMOVE(&debug_malloc_usedlist, md, md_list);
194
195 TAILQ_INSERT_TAIL(&debug_malloc_freelist, md, md_list);
196 debug_malloc_chunks_on_freelist++;
197
198
199
200 pmap_kremove(md->md_va, PAGE_SIZE);
201 pmap_update(pmap_kernel());
202 splx(s);
203
204 return (1);
205 }
206
207 void
208 debug_malloc_init(void)
209 {
210
211 TAILQ_INIT(&debug_malloc_freelist);
212 TAILQ_INIT(&debug_malloc_usedlist);
213
214 debug_malloc_allocs = 0;
215 debug_malloc_frees = 0;
216 debug_malloc_pages = 0;
217 debug_malloc_chunks_on_freelist = 0;
218
219 pool_init(&debug_malloc_pool, sizeof(struct debug_malloc_entry),
220 0, 0, 0, "mdbepl", NULL);
221
222 debug_malloc_initialized = 1;
223 }
224
225
226
227
228
229
230 void
231 debug_malloc_allocate_free(int wait)
232 {
233 vaddr_t va, offset;
234 struct vm_page *pg;
235 struct debug_malloc_entry *md;
236
237 splassert(IPL_VM);
238
239 md = pool_get(&debug_malloc_pool, wait ? PR_WAITOK : PR_NOWAIT);
240 if (md == NULL)
241 return;
242
243 va = uvm_km_kmemalloc(kmem_map, NULL, PAGE_SIZE * 2,
244 UVM_KMF_VALLOC | (wait ? 0: UVM_KMF_NOWAIT));
245 if (va == 0) {
246 pool_put(&debug_malloc_pool, md);
247 return;
248 }
249
250 offset = va - vm_map_min(kernel_map);
251 for (;;) {
252 pg = uvm_pagealloc(NULL, 0, NULL, 0);
253 if (pg) {
254 atomic_clearbits_int(&pg->pg_flags, PG_BUSY);
255 UVM_PAGE_OWN(pg, NULL);
256 }
257
258 if (pg)
259 break;
260
261 if (wait == 0) {
262 uvm_unmap(kmem_map, va, va + PAGE_SIZE * 2);
263 pool_put(&debug_malloc_pool, md);
264 return;
265 }
266 uvm_wait("debug_malloc");
267 }
268
269 md->md_va = va;
270 md->md_pa = VM_PAGE_TO_PHYS(pg);
271
272 debug_malloc_pages++;
273 TAILQ_INSERT_HEAD(&debug_malloc_freelist, md, md_list);
274 debug_malloc_chunks_on_freelist++;
275 }
276
277 void
278 debug_malloc_print(void)
279 {
280
281 debug_malloc_printit(printf, NULL);
282 }
283
284 void
285 debug_malloc_assert_allocated(void *addr, const char *func)
286 {
287 struct debug_malloc_entry *md;
288 vaddr_t va = (vaddr_t)addr;
289
290 TAILQ_FOREACH(md, &debug_malloc_freelist, md_list) {
291 if (va >= md->md_va &&
292 va < md->md_va + 2 * PAGE_SIZE)
293 panic("debug_malloc: (%s): %p - freed", func, addr);
294 }
295 TAILQ_FOREACH(md, &debug_malloc_usedlist, md_list) {
296 if (va >= md->md_va + PAGE_SIZE &&
297 va < md->md_va + 2 * PAGE_SIZE)
298 panic("debug_malloc: (%s): %p - overflow", func, addr);
299 }
300 }
301
302 void
303 debug_malloc_printit(int (*pr)(const char *, ...), vaddr_t addr)
304 {
305 struct debug_malloc_entry *md;
306
307 if (addr) {
308 TAILQ_FOREACH(md, &debug_malloc_freelist, md_list) {
309 if (addr >= md->md_va &&
310 addr < md->md_va + 2 * PAGE_SIZE) {
311 (*pr)("Memory at address 0x%x is in a freed "
312 "area. type %d, size: %d\n ",
313 addr, md->md_type, md->md_size);
314 return;
315 }
316 }
317 TAILQ_FOREACH(md, &debug_malloc_usedlist, md_list) {
318 if (addr >= md->md_va + PAGE_SIZE &&
319 addr < md->md_va + 2 * PAGE_SIZE) {
320 (*pr)("Memory at address 0x%x is just outside "
321 "an allocated area. type %d, size: %d\n",
322 addr, md->md_type, md->md_size);
323 return;
324 }
325 }
326 (*pr)("Memory at address 0x%x is outside debugged malloc.\n");
327 return;
328 }
329
330 (*pr)("allocs: %d\n", debug_malloc_allocs);
331 (*pr)("frees: %d\n", debug_malloc_frees);
332 (*pr)("pages used: %d\n", debug_malloc_pages);
333 (*pr)("chunks on freelist: %d\n", debug_malloc_chunks_on_freelist);
334
335 (*pr)("\taddr:\tsize:\n");
336 (*pr)("free chunks:\n");
337 TAILQ_FOREACH(md, &debug_malloc_freelist, md_list)
338 (*pr)("\t0x%x\t0x%x\t%d\n", md->md_va, md->md_size,
339 md->md_type);
340 (*pr)("used chunks:\n");
341 TAILQ_FOREACH(md, &debug_malloc_usedlist, md_list)
342 (*pr)("\t0x%x\t0x%x\t%d\n", md->md_va, md->md_size,
343 md->md_type);
344 }