1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2008 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * @file
30bf215546Sopenharmony_ci * Memory debugging.
31bf215546Sopenharmony_ci *
32bf215546Sopenharmony_ci * @author José Fonseca <jfonseca@vmware.com>
33bf215546Sopenharmony_ci */
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "pipe/p_config.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#define DEBUG_MEMORY_IMPLEMENTATION
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#include "os/os_thread.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#include "util/u_debug.h"
42bf215546Sopenharmony_ci#include "util/u_debug_stack.h"
43bf215546Sopenharmony_ci#include "util/list.h"
44bf215546Sopenharmony_ci#include "util/os_memory.h"
45bf215546Sopenharmony_ci#include "util/os_memory_debug.h"
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci#define DEBUG_MEMORY_MAGIC 0x6e34090aU
49bf215546Sopenharmony_ci#define DEBUG_MEMORY_STACK 0 /* XXX: disabled until we have symbol lookup */
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci/**
52bf215546Sopenharmony_ci * Set to 1 to enable checking of freed blocks of memory.
53bf215546Sopenharmony_ci * Basically, don't really deallocate freed memory; keep it in the list
54bf215546Sopenharmony_ci * but mark it as freed and do extra checking in debug_memory_check().
55bf215546Sopenharmony_ci * This can detect some cases of use-after-free.  But note that since we
56bf215546Sopenharmony_ci * never really free anything this will use a lot of memory.
57bf215546Sopenharmony_ci */
58bf215546Sopenharmony_ci#define DEBUG_FREED_MEMORY 0
59bf215546Sopenharmony_ci#define DEBUG_FREED_BYTE 0x33
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_cistruct debug_memory_header
63bf215546Sopenharmony_ci{
64bf215546Sopenharmony_ci   struct list_head head;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   unsigned long no;
67bf215546Sopenharmony_ci   const char *file;
68bf215546Sopenharmony_ci   unsigned line;
69bf215546Sopenharmony_ci   const char *function;
70bf215546Sopenharmony_ci#if DEBUG_MEMORY_STACK
71bf215546Sopenharmony_ci   struct debug_stack_frame backtrace[DEBUG_MEMORY_STACK];
72bf215546Sopenharmony_ci#endif
73bf215546Sopenharmony_ci   size_t size;
74bf215546Sopenharmony_ci#if DEBUG_FREED_MEMORY
75bf215546Sopenharmony_ci   boolean freed;  /**< Is this a freed block? */
76bf215546Sopenharmony_ci#endif
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   unsigned magic;
79bf215546Sopenharmony_ci   unsigned tag;
80bf215546Sopenharmony_ci};
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_cistruct debug_memory_footer
83bf215546Sopenharmony_ci{
84bf215546Sopenharmony_ci   unsigned magic;
85bf215546Sopenharmony_ci};
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_cistatic struct list_head list = { &list, &list };
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_cistatic mtx_t list_mutex = _MTX_INITIALIZER_NP;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_cistatic unsigned long last_no = 0;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_cistatic inline struct debug_memory_header *
96bf215546Sopenharmony_ciheader_from_data(void *data)
97bf215546Sopenharmony_ci{
98bf215546Sopenharmony_ci   if (data)
99bf215546Sopenharmony_ci      return (struct debug_memory_header *)((char *)data - sizeof(struct debug_memory_header));
100bf215546Sopenharmony_ci   else
101bf215546Sopenharmony_ci      return NULL;
102bf215546Sopenharmony_ci}
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_cistatic inline void *
105bf215546Sopenharmony_cidata_from_header(struct debug_memory_header *hdr)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci   if (hdr)
108bf215546Sopenharmony_ci      return (void *)((char *)hdr + sizeof(struct debug_memory_header));
109bf215546Sopenharmony_ci   else
110bf215546Sopenharmony_ci      return NULL;
111bf215546Sopenharmony_ci}
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_cistatic inline struct debug_memory_footer *
114bf215546Sopenharmony_cifooter_from_header(struct debug_memory_header *hdr)
115bf215546Sopenharmony_ci{
116bf215546Sopenharmony_ci   if (hdr)
117bf215546Sopenharmony_ci      return (struct debug_memory_footer *)((char *)hdr + sizeof(struct debug_memory_header) + hdr->size);
118bf215546Sopenharmony_ci   else
119bf215546Sopenharmony_ci      return NULL;
120bf215546Sopenharmony_ci}
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_civoid *
124bf215546Sopenharmony_cidebug_malloc(const char *file, unsigned line, const char *function,
125bf215546Sopenharmony_ci             size_t size)
126bf215546Sopenharmony_ci{
127bf215546Sopenharmony_ci   struct debug_memory_header *hdr;
128bf215546Sopenharmony_ci   struct debug_memory_footer *ftr;
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   hdr = os_malloc(sizeof(*hdr) + size + sizeof(*ftr));
131bf215546Sopenharmony_ci   if (!hdr) {
132bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
133bf215546Sopenharmony_ci                   file, line, function,
134bf215546Sopenharmony_ci                   (long unsigned)size);
135bf215546Sopenharmony_ci      return NULL;
136bf215546Sopenharmony_ci   }
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   hdr->no = last_no++;
139bf215546Sopenharmony_ci   hdr->file = file;
140bf215546Sopenharmony_ci   hdr->line = line;
141bf215546Sopenharmony_ci   hdr->function = function;
142bf215546Sopenharmony_ci   hdr->size = size;
143bf215546Sopenharmony_ci   hdr->magic = DEBUG_MEMORY_MAGIC;
144bf215546Sopenharmony_ci   hdr->tag = 0;
145bf215546Sopenharmony_ci#if DEBUG_FREED_MEMORY
146bf215546Sopenharmony_ci   hdr->freed = FALSE;
147bf215546Sopenharmony_ci#endif
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci#if DEBUG_MEMORY_STACK
150bf215546Sopenharmony_ci   debug_backtrace_capture(hdr->backtrace, 0, DEBUG_MEMORY_STACK);
151bf215546Sopenharmony_ci#endif
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   ftr = footer_from_header(hdr);
154bf215546Sopenharmony_ci   ftr->magic = DEBUG_MEMORY_MAGIC;
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   mtx_lock(&list_mutex);
157bf215546Sopenharmony_ci   list_addtail(&hdr->head, &list);
158bf215546Sopenharmony_ci   mtx_unlock(&list_mutex);
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   return data_from_header(hdr);
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_civoid
164bf215546Sopenharmony_cidebug_free(const char *file, unsigned line, const char *function,
165bf215546Sopenharmony_ci           void *ptr)
166bf215546Sopenharmony_ci{
167bf215546Sopenharmony_ci   struct debug_memory_header *hdr;
168bf215546Sopenharmony_ci   struct debug_memory_footer *ftr;
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci   if (!ptr)
171bf215546Sopenharmony_ci      return;
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   hdr = header_from_data(ptr);
174bf215546Sopenharmony_ci   if (hdr->magic != DEBUG_MEMORY_MAGIC) {
175bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: freeing bad or corrupted memory %p\n",
176bf215546Sopenharmony_ci                   file, line, function,
177bf215546Sopenharmony_ci                   ptr);
178bf215546Sopenharmony_ci      assert(0);
179bf215546Sopenharmony_ci      return;
180bf215546Sopenharmony_ci   }
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   ftr = footer_from_header(hdr);
183bf215546Sopenharmony_ci   if (ftr->magic != DEBUG_MEMORY_MAGIC) {
184bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: buffer overflow %p\n",
185bf215546Sopenharmony_ci                   hdr->file, hdr->line, hdr->function,
186bf215546Sopenharmony_ci                   ptr);
187bf215546Sopenharmony_ci      assert(0);
188bf215546Sopenharmony_ci   }
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci#if DEBUG_FREED_MEMORY
191bf215546Sopenharmony_ci   /* Check for double-free */
192bf215546Sopenharmony_ci   assert(!hdr->freed);
193bf215546Sopenharmony_ci   /* Mark the block as freed but don't really free it */
194bf215546Sopenharmony_ci   hdr->freed = TRUE;
195bf215546Sopenharmony_ci   /* Save file/line where freed */
196bf215546Sopenharmony_ci   hdr->file = file;
197bf215546Sopenharmony_ci   hdr->line = line;
198bf215546Sopenharmony_ci   /* set freed memory to special value */
199bf215546Sopenharmony_ci   memset(ptr, DEBUG_FREED_BYTE, hdr->size);
200bf215546Sopenharmony_ci#else
201bf215546Sopenharmony_ci   mtx_lock(&list_mutex);
202bf215546Sopenharmony_ci   list_del(&hdr->head);
203bf215546Sopenharmony_ci   mtx_unlock(&list_mutex);
204bf215546Sopenharmony_ci   hdr->magic = 0;
205bf215546Sopenharmony_ci   ftr->magic = 0;
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   os_free(hdr);
208bf215546Sopenharmony_ci#endif
209bf215546Sopenharmony_ci}
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_civoid *
212bf215546Sopenharmony_cidebug_calloc(const char *file, unsigned line, const char *function,
213bf215546Sopenharmony_ci             size_t count, size_t size )
214bf215546Sopenharmony_ci{
215bf215546Sopenharmony_ci   void *ptr = debug_malloc( file, line, function, count * size );
216bf215546Sopenharmony_ci   if (ptr)
217bf215546Sopenharmony_ci      memset( ptr, 0, count * size );
218bf215546Sopenharmony_ci   return ptr;
219bf215546Sopenharmony_ci}
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_civoid *
222bf215546Sopenharmony_cidebug_realloc(const char *file, unsigned line, const char *function,
223bf215546Sopenharmony_ci              void *old_ptr, size_t old_size, size_t new_size )
224bf215546Sopenharmony_ci{
225bf215546Sopenharmony_ci   struct debug_memory_header *old_hdr, *new_hdr;
226bf215546Sopenharmony_ci   struct debug_memory_footer *old_ftr, *new_ftr;
227bf215546Sopenharmony_ci   void *new_ptr;
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci   if (!old_ptr)
230bf215546Sopenharmony_ci      return debug_malloc( file, line, function, new_size );
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   if (!new_size) {
233bf215546Sopenharmony_ci      debug_free( file, line, function, old_ptr );
234bf215546Sopenharmony_ci      return NULL;
235bf215546Sopenharmony_ci   }
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   old_hdr = header_from_data(old_ptr);
238bf215546Sopenharmony_ci   if (old_hdr->magic != DEBUG_MEMORY_MAGIC) {
239bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: reallocating bad or corrupted memory %p\n",
240bf215546Sopenharmony_ci                   file, line, function,
241bf215546Sopenharmony_ci                   old_ptr);
242bf215546Sopenharmony_ci      assert(0);
243bf215546Sopenharmony_ci      return NULL;
244bf215546Sopenharmony_ci   }
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   old_ftr = footer_from_header(old_hdr);
247bf215546Sopenharmony_ci   if (old_ftr->magic != DEBUG_MEMORY_MAGIC) {
248bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: buffer overflow %p\n",
249bf215546Sopenharmony_ci                   old_hdr->file, old_hdr->line, old_hdr->function,
250bf215546Sopenharmony_ci                   old_ptr);
251bf215546Sopenharmony_ci      assert(0);
252bf215546Sopenharmony_ci   }
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   /* alloc new */
255bf215546Sopenharmony_ci   new_hdr = os_malloc(sizeof(*new_hdr) + new_size + sizeof(*new_ftr));
256bf215546Sopenharmony_ci   if (!new_hdr) {
257bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
258bf215546Sopenharmony_ci                   file, line, function,
259bf215546Sopenharmony_ci                   (long unsigned)new_size);
260bf215546Sopenharmony_ci      return NULL;
261bf215546Sopenharmony_ci   }
262bf215546Sopenharmony_ci   new_hdr->no = old_hdr->no;
263bf215546Sopenharmony_ci   new_hdr->file = old_hdr->file;
264bf215546Sopenharmony_ci   new_hdr->line = old_hdr->line;
265bf215546Sopenharmony_ci   new_hdr->function = old_hdr->function;
266bf215546Sopenharmony_ci   new_hdr->size = new_size;
267bf215546Sopenharmony_ci   new_hdr->magic = DEBUG_MEMORY_MAGIC;
268bf215546Sopenharmony_ci   new_hdr->tag = 0;
269bf215546Sopenharmony_ci#if DEBUG_FREED_MEMORY
270bf215546Sopenharmony_ci   new_hdr->freed = FALSE;
271bf215546Sopenharmony_ci#endif
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci   new_ftr = footer_from_header(new_hdr);
274bf215546Sopenharmony_ci   new_ftr->magic = DEBUG_MEMORY_MAGIC;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   mtx_lock(&list_mutex);
277bf215546Sopenharmony_ci   list_replace(&old_hdr->head, &new_hdr->head);
278bf215546Sopenharmony_ci   mtx_unlock(&list_mutex);
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   /* copy data */
281bf215546Sopenharmony_ci   new_ptr = data_from_header(new_hdr);
282bf215546Sopenharmony_ci   memcpy( new_ptr, old_ptr, old_size < new_size ? old_size : new_size );
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   /* free old */
285bf215546Sopenharmony_ci   old_hdr->magic = 0;
286bf215546Sopenharmony_ci   old_ftr->magic = 0;
287bf215546Sopenharmony_ci   os_free(old_hdr);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   return new_ptr;
290bf215546Sopenharmony_ci}
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ciunsigned long
293bf215546Sopenharmony_cidebug_memory_begin(void)
294bf215546Sopenharmony_ci{
295bf215546Sopenharmony_ci   return last_no;
296bf215546Sopenharmony_ci}
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_civoid
299bf215546Sopenharmony_cidebug_memory_end(unsigned long start_no)
300bf215546Sopenharmony_ci{
301bf215546Sopenharmony_ci   size_t total_size = 0;
302bf215546Sopenharmony_ci   struct list_head *entry;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   if (start_no == last_no)
305bf215546Sopenharmony_ci      return;
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   entry = list.prev;
308bf215546Sopenharmony_ci   for (; entry != &list; entry = entry->prev) {
309bf215546Sopenharmony_ci      struct debug_memory_header *hdr;
310bf215546Sopenharmony_ci      void *ptr;
311bf215546Sopenharmony_ci      struct debug_memory_footer *ftr;
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci      hdr = list_entry(entry, struct debug_memory_header, head);
314bf215546Sopenharmony_ci      ptr = data_from_header(hdr);
315bf215546Sopenharmony_ci      ftr = footer_from_header(hdr);
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci      if (hdr->magic != DEBUG_MEMORY_MAGIC) {
318bf215546Sopenharmony_ci         debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
319bf215546Sopenharmony_ci                      hdr->file, hdr->line, hdr->function,
320bf215546Sopenharmony_ci                      ptr);
321bf215546Sopenharmony_ci         assert(0);
322bf215546Sopenharmony_ci      }
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci      if ((start_no <= hdr->no && hdr->no < last_no) ||
325bf215546Sopenharmony_ci          (last_no < start_no && (hdr->no < last_no || start_no <= hdr->no))) {
326bf215546Sopenharmony_ci         debug_printf("%s:%u:%s: %lu bytes at %p not freed\n",
327bf215546Sopenharmony_ci                      hdr->file, hdr->line, hdr->function,
328bf215546Sopenharmony_ci                      (unsigned long) hdr->size, ptr);
329bf215546Sopenharmony_ci#if DEBUG_MEMORY_STACK
330bf215546Sopenharmony_ci         debug_backtrace_dump(hdr->backtrace, DEBUG_MEMORY_STACK);
331bf215546Sopenharmony_ci#endif
332bf215546Sopenharmony_ci         total_size += hdr->size;
333bf215546Sopenharmony_ci      }
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci      if (ftr->magic != DEBUG_MEMORY_MAGIC) {
336bf215546Sopenharmony_ci         debug_printf("%s:%u:%s: buffer overflow %p\n",
337bf215546Sopenharmony_ci                      hdr->file, hdr->line, hdr->function,
338bf215546Sopenharmony_ci                      ptr);
339bf215546Sopenharmony_ci         assert(0);
340bf215546Sopenharmony_ci      }
341bf215546Sopenharmony_ci   }
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci   if (total_size) {
344bf215546Sopenharmony_ci      debug_printf("Total of %lu KB of system memory apparently leaked\n",
345bf215546Sopenharmony_ci                   (unsigned long) (total_size + 1023)/1024);
346bf215546Sopenharmony_ci   }
347bf215546Sopenharmony_ci   else {
348bf215546Sopenharmony_ci      debug_printf("No memory leaks detected.\n");
349bf215546Sopenharmony_ci   }
350bf215546Sopenharmony_ci}
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci/**
354bf215546Sopenharmony_ci * Put a tag (arbitrary integer) on a memory block.
355bf215546Sopenharmony_ci * Can be useful for debugging.
356bf215546Sopenharmony_ci */
357bf215546Sopenharmony_civoid
358bf215546Sopenharmony_cidebug_memory_tag(void *ptr, unsigned tag)
359bf215546Sopenharmony_ci{
360bf215546Sopenharmony_ci   struct debug_memory_header *hdr;
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci   if (!ptr)
363bf215546Sopenharmony_ci      return;
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci   hdr = header_from_data(ptr);
366bf215546Sopenharmony_ci   if (hdr->magic != DEBUG_MEMORY_MAGIC) {
367bf215546Sopenharmony_ci      debug_printf("%s corrupted memory at %p\n", __FUNCTION__, ptr);
368bf215546Sopenharmony_ci      assert(0);
369bf215546Sopenharmony_ci   }
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci   hdr->tag = tag;
372bf215546Sopenharmony_ci}
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci/**
376bf215546Sopenharmony_ci * Check the given block of memory for validity/corruption.
377bf215546Sopenharmony_ci */
378bf215546Sopenharmony_civoid
379bf215546Sopenharmony_cidebug_memory_check_block(void *ptr)
380bf215546Sopenharmony_ci{
381bf215546Sopenharmony_ci   struct debug_memory_header *hdr;
382bf215546Sopenharmony_ci   struct debug_memory_footer *ftr;
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci   if (!ptr)
385bf215546Sopenharmony_ci      return;
386bf215546Sopenharmony_ci
387bf215546Sopenharmony_ci   hdr = header_from_data(ptr);
388bf215546Sopenharmony_ci   ftr = footer_from_header(hdr);
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci   if (hdr->magic != DEBUG_MEMORY_MAGIC) {
391bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
392bf215546Sopenharmony_ci                   hdr->file, hdr->line, hdr->function, ptr);
393bf215546Sopenharmony_ci      assert(0);
394bf215546Sopenharmony_ci   }
395bf215546Sopenharmony_ci
396bf215546Sopenharmony_ci   if (ftr->magic != DEBUG_MEMORY_MAGIC) {
397bf215546Sopenharmony_ci      debug_printf("%s:%u:%s: buffer overflow %p\n",
398bf215546Sopenharmony_ci                   hdr->file, hdr->line, hdr->function, ptr);
399bf215546Sopenharmony_ci      assert(0);
400bf215546Sopenharmony_ci   }
401bf215546Sopenharmony_ci}
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_ci/**
406bf215546Sopenharmony_ci * We can periodically call this from elsewhere to do a basic sanity
407bf215546Sopenharmony_ci * check of the heap memory we've allocated.
408bf215546Sopenharmony_ci */
409bf215546Sopenharmony_civoid
410bf215546Sopenharmony_cidebug_memory_check(void)
411bf215546Sopenharmony_ci{
412bf215546Sopenharmony_ci   struct list_head *entry;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   entry = list.prev;
415bf215546Sopenharmony_ci   for (; entry != &list; entry = entry->prev) {
416bf215546Sopenharmony_ci      struct debug_memory_header *hdr;
417bf215546Sopenharmony_ci      struct debug_memory_footer *ftr;
418bf215546Sopenharmony_ci      const char *ptr;
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci      hdr = list_entry(entry, struct debug_memory_header, head);
421bf215546Sopenharmony_ci      ftr = footer_from_header(hdr);
422bf215546Sopenharmony_ci      ptr = (const char *) data_from_header(hdr);
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci      if (hdr->magic != DEBUG_MEMORY_MAGIC) {
425bf215546Sopenharmony_ci         debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
426bf215546Sopenharmony_ci                      hdr->file, hdr->line, hdr->function, ptr);
427bf215546Sopenharmony_ci         assert(0);
428bf215546Sopenharmony_ci      }
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci      if (ftr->magic != DEBUG_MEMORY_MAGIC) {
431bf215546Sopenharmony_ci         debug_printf("%s:%u:%s: buffer overflow %p\n",
432bf215546Sopenharmony_ci                      hdr->file, hdr->line, hdr->function, ptr);
433bf215546Sopenharmony_ci         assert(0);
434bf215546Sopenharmony_ci      }
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci#if DEBUG_FREED_MEMORY
437bf215546Sopenharmony_ci      /* If this block is marked as freed, check that it hasn't been touched */
438bf215546Sopenharmony_ci      if (hdr->freed) {
439bf215546Sopenharmony_ci         int i;
440bf215546Sopenharmony_ci         for (i = 0; i < hdr->size; i++) {
441bf215546Sopenharmony_ci            if (ptr[i] != DEBUG_FREED_BYTE) {
442bf215546Sopenharmony_ci               debug_printf("Memory error: byte %d of block at %p of size %d is 0x%x\n",
443bf215546Sopenharmony_ci                            i, ptr, hdr->size, ptr[i]);
444bf215546Sopenharmony_ci               debug_printf("Block was freed at %s:%d\n", hdr->file, hdr->line);
445bf215546Sopenharmony_ci            }
446bf215546Sopenharmony_ci            assert(ptr[i] == DEBUG_FREED_BYTE);
447bf215546Sopenharmony_ci         }
448bf215546Sopenharmony_ci      }
449bf215546Sopenharmony_ci#endif
450bf215546Sopenharmony_ci   }
451bf215546Sopenharmony_ci}
452