Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / auxiliary / util / u_debug_memory.c
1 /**************************************************************************
2  * 
3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4  * All Rights Reserved.
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  * 
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  * 
26  **************************************************************************/
27
28 /**
29  * @file
30  * Memory debugging.
31  * 
32  * @author José Fonseca <jrfonseca@tungstengraphics.com>
33  */
34
35 #include "pipe/p_config.h" 
36
37 #define DEBUG_MEMORY_IMPLEMENTATION
38
39 #include "os/os_memory.h"
40 #include "os/os_memory_debug.h"
41
42 #include "util/u_debug.h" 
43 #include "util/u_debug_stack.h" 
44 #include "util/u_double_list.h" 
45
46
47 #define DEBUG_MEMORY_MAGIC 0x6e34090aU 
48 #define DEBUG_MEMORY_STACK 0 /* XXX: disabled until we have symbol lookup */
49
50
51 struct debug_memory_header 
52 {
53    struct list_head head;
54    
55    unsigned long no;
56    const char *file;
57    unsigned line;
58    const char *function;
59 #if DEBUG_MEMORY_STACK
60    struct debug_stack_frame backtrace[DEBUG_MEMORY_STACK];
61 #endif
62    size_t size;
63    
64    unsigned magic;
65 };
66
67 struct debug_memory_footer
68 {
69    unsigned magic;
70 };
71
72
73 static struct list_head list = { &list, &list };
74
75 static unsigned long last_no = 0;
76
77
78 static INLINE struct debug_memory_header *
79 header_from_data(void *data)
80 {
81    if(data)
82       return (struct debug_memory_header *)((char *)data - sizeof(struct debug_memory_header));
83    else
84       return NULL;
85 }
86
87 static INLINE void *
88 data_from_header(struct debug_memory_header *hdr)
89 {
90    if(hdr)
91       return (void *)((char *)hdr + sizeof(struct debug_memory_header));
92    else
93       return NULL;
94 }
95
96 static INLINE struct debug_memory_footer *
97 footer_from_header(struct debug_memory_header *hdr)
98 {
99    if(hdr)
100       return (struct debug_memory_footer *)((char *)hdr + sizeof(struct debug_memory_header) + hdr->size);
101    else
102       return NULL;
103 }
104
105
106 void *
107 debug_malloc(const char *file, unsigned line, const char *function,
108              size_t size) 
109 {
110    struct debug_memory_header *hdr;
111    struct debug_memory_footer *ftr;
112    
113    hdr = os_malloc(sizeof(*hdr) + size + sizeof(*ftr));
114    if(!hdr) {
115       debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
116                    file, line, function,
117                    (long unsigned)size);
118       return NULL;
119    }
120  
121    hdr->no = last_no++;
122    hdr->file = file;
123    hdr->line = line;
124    hdr->function = function;
125    hdr->size = size;
126    hdr->magic = DEBUG_MEMORY_MAGIC;
127
128 #if DEBUG_MEMORY_STACK
129    debug_backtrace_capture(hdr->backtrace, 0, DEBUG_MEMORY_STACK);
130 #endif
131
132    ftr = footer_from_header(hdr);
133    ftr->magic = DEBUG_MEMORY_MAGIC;
134    
135    LIST_ADDTAIL(&hdr->head, &list);
136    
137    return data_from_header(hdr);
138 }
139
140 void
141 debug_free(const char *file, unsigned line, const char *function,
142            void *ptr) 
143 {
144    struct debug_memory_header *hdr;
145    struct debug_memory_footer *ftr;
146    
147    if(!ptr)
148       return;
149    
150    hdr = header_from_data(ptr);
151    if(hdr->magic != DEBUG_MEMORY_MAGIC) {
152       debug_printf("%s:%u:%s: freeing bad or corrupted memory %p\n",
153                    file, line, function,
154                    ptr);
155       debug_assert(0);
156       return;
157    }
158
159    ftr = footer_from_header(hdr);
160    if(ftr->magic != DEBUG_MEMORY_MAGIC) {
161       debug_printf("%s:%u:%s: buffer overflow %p\n",
162                    hdr->file, hdr->line, hdr->function,
163                    ptr);
164       debug_assert(0);
165    }
166
167    LIST_DEL(&hdr->head);
168    hdr->magic = 0;
169    ftr->magic = 0;
170    
171    os_free(hdr);
172 }
173
174 void *
175 debug_calloc(const char *file, unsigned line, const char *function,
176              size_t count, size_t size )
177 {
178    void *ptr = debug_malloc( file, line, function, count * size );
179    if( ptr )
180       memset( ptr, 0, count * size );
181    return ptr;
182 }
183
184 void *
185 debug_realloc(const char *file, unsigned line, const char *function,
186               void *old_ptr, size_t old_size, size_t new_size )
187 {
188    struct debug_memory_header *old_hdr, *new_hdr;
189    struct debug_memory_footer *old_ftr, *new_ftr;
190    void *new_ptr;
191    
192    if(!old_ptr)
193       return debug_malloc( file, line, function, new_size );
194    
195    if(!new_size) {
196       debug_free( file, line, function, old_ptr );
197       return NULL;
198    }
199    
200    old_hdr = header_from_data(old_ptr);
201    if(old_hdr->magic != DEBUG_MEMORY_MAGIC) {
202       debug_printf("%s:%u:%s: reallocating bad or corrupted memory %p\n",
203                    file, line, function,
204                    old_ptr);
205       debug_assert(0);
206       return NULL;
207    }
208    
209    old_ftr = footer_from_header(old_hdr);
210    if(old_ftr->magic != DEBUG_MEMORY_MAGIC) {
211       debug_printf("%s:%u:%s: buffer overflow %p\n",
212                    old_hdr->file, old_hdr->line, old_hdr->function,
213                    old_ptr);
214       debug_assert(0);
215    }
216
217    /* alloc new */
218    new_hdr = os_malloc(sizeof(*new_hdr) + new_size + sizeof(*new_ftr));
219    if(!new_hdr) {
220       debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
221                    file, line, function,
222                    (long unsigned)new_size);
223       return NULL;
224    }
225    new_hdr->no = old_hdr->no;
226    new_hdr->file = old_hdr->file;
227    new_hdr->line = old_hdr->line;
228    new_hdr->function = old_hdr->function;
229    new_hdr->size = new_size;
230    new_hdr->magic = DEBUG_MEMORY_MAGIC;
231    
232    new_ftr = footer_from_header(new_hdr);
233    new_ftr->magic = DEBUG_MEMORY_MAGIC;
234    
235    LIST_REPLACE(&old_hdr->head, &new_hdr->head);
236
237    /* copy data */
238    new_ptr = data_from_header(new_hdr);
239    memcpy( new_ptr, old_ptr, old_size < new_size ? old_size : new_size );
240
241    /* free old */
242    old_hdr->magic = 0;
243    old_ftr->magic = 0;
244    os_free(old_hdr);
245
246    return new_ptr;
247 }
248
249 unsigned long
250 debug_memory_begin(void)
251 {
252    return last_no;
253 }
254
255 void 
256 debug_memory_end(unsigned long start_no)
257 {
258    size_t total_size = 0;
259    struct list_head *entry;
260
261    if(start_no == last_no)
262       return;
263
264    entry = list.prev;
265    for (; entry != &list; entry = entry->prev) {
266       struct debug_memory_header *hdr;
267       void *ptr;
268       struct debug_memory_footer *ftr;
269
270       hdr = LIST_ENTRY(struct debug_memory_header, entry, head);
271       ptr = data_from_header(hdr);
272       ftr = footer_from_header(hdr);
273
274       if(hdr->magic != DEBUG_MEMORY_MAGIC) {
275          debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
276                       hdr->file, hdr->line, hdr->function,
277                       ptr);
278          debug_assert(0);
279       }
280
281       if((start_no <= hdr->no && hdr->no < last_no) ||
282          (last_no < start_no && (hdr->no < last_no || start_no <= hdr->no))) {
283          debug_printf("%s:%u:%s: %lu bytes at %p not freed\n",
284                       hdr->file, hdr->line, hdr->function,
285                       (unsigned long) hdr->size, ptr);
286 #if DEBUG_MEMORY_STACK
287          debug_backtrace_dump(hdr->backtrace, DEBUG_MEMORY_STACK);
288 #endif
289          total_size += hdr->size;
290       }
291
292       if(ftr->magic != DEBUG_MEMORY_MAGIC) {
293          debug_printf("%s:%u:%s: buffer overflow %p\n",
294                       hdr->file, hdr->line, hdr->function,
295                       ptr);
296          debug_assert(0);
297       }
298    }
299
300    if(total_size) {
301       debug_printf("Total of %lu KB of system memory apparently leaked\n",
302                    (unsigned long) (total_size + 1023)/1024);
303    }
304    else {
305       debug_printf("No memory leaks detected.\n");
306    }
307 }