sync with tizen_2.2
[sdk/emulator/qemu.git] / gl / mesa / 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 #include "os/os_thread.h"
42
43 #include "util/u_debug.h" 
44 #include "util/u_debug_stack.h" 
45 #include "util/u_double_list.h" 
46
47
48 #define DEBUG_MEMORY_MAGIC 0x6e34090aU 
49 #define DEBUG_MEMORY_STACK 0 /* XXX: disabled until we have symbol lookup */
50
51
52 struct debug_memory_header 
53 {
54    struct list_head head;
55    
56    unsigned long no;
57    const char *file;
58    unsigned line;
59    const char *function;
60 #if DEBUG_MEMORY_STACK
61    struct debug_stack_frame backtrace[DEBUG_MEMORY_STACK];
62 #endif
63    size_t size;
64    
65    unsigned magic;
66 };
67
68 struct debug_memory_footer
69 {
70    unsigned magic;
71 };
72
73
74 static struct list_head list = { &list, &list };
75
76 pipe_static_mutex(list_mutex);
77
78 static unsigned long last_no = 0;
79
80
81 static INLINE struct debug_memory_header *
82 header_from_data(void *data)
83 {
84    if(data)
85       return (struct debug_memory_header *)((char *)data - sizeof(struct debug_memory_header));
86    else
87       return NULL;
88 }
89
90 static INLINE void *
91 data_from_header(struct debug_memory_header *hdr)
92 {
93    if(hdr)
94       return (void *)((char *)hdr + sizeof(struct debug_memory_header));
95    else
96       return NULL;
97 }
98
99 static INLINE struct debug_memory_footer *
100 footer_from_header(struct debug_memory_header *hdr)
101 {
102    if(hdr)
103       return (struct debug_memory_footer *)((char *)hdr + sizeof(struct debug_memory_header) + hdr->size);
104    else
105       return NULL;
106 }
107
108
109 void *
110 debug_malloc(const char *file, unsigned line, const char *function,
111              size_t size) 
112 {
113    struct debug_memory_header *hdr;
114    struct debug_memory_footer *ftr;
115    
116    hdr = os_malloc(sizeof(*hdr) + size + sizeof(*ftr));
117    if(!hdr) {
118       debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
119                    file, line, function,
120                    (long unsigned)size);
121       return NULL;
122    }
123  
124    hdr->no = last_no++;
125    hdr->file = file;
126    hdr->line = line;
127    hdr->function = function;
128    hdr->size = size;
129    hdr->magic = DEBUG_MEMORY_MAGIC;
130
131 #if DEBUG_MEMORY_STACK
132    debug_backtrace_capture(hdr->backtrace, 0, DEBUG_MEMORY_STACK);
133 #endif
134
135    ftr = footer_from_header(hdr);
136    ftr->magic = DEBUG_MEMORY_MAGIC;
137    
138    pipe_mutex_lock(list_mutex);
139    LIST_ADDTAIL(&hdr->head, &list);
140    pipe_mutex_unlock(list_mutex);
141    
142    return data_from_header(hdr);
143 }
144
145 void
146 debug_free(const char *file, unsigned line, const char *function,
147            void *ptr) 
148 {
149    struct debug_memory_header *hdr;
150    struct debug_memory_footer *ftr;
151    
152    if(!ptr)
153       return;
154    
155    hdr = header_from_data(ptr);
156    if(hdr->magic != DEBUG_MEMORY_MAGIC) {
157       debug_printf("%s:%u:%s: freeing bad or corrupted memory %p\n",
158                    file, line, function,
159                    ptr);
160       debug_assert(0);
161       return;
162    }
163
164    ftr = footer_from_header(hdr);
165    if(ftr->magic != DEBUG_MEMORY_MAGIC) {
166       debug_printf("%s:%u:%s: buffer overflow %p\n",
167                    hdr->file, hdr->line, hdr->function,
168                    ptr);
169       debug_assert(0);
170    }
171
172    pipe_mutex_lock(list_mutex);
173    LIST_DEL(&hdr->head);
174    pipe_mutex_unlock(list_mutex);
175    hdr->magic = 0;
176    ftr->magic = 0;
177    
178    os_free(hdr);
179 }
180
181 void *
182 debug_calloc(const char *file, unsigned line, const char *function,
183              size_t count, size_t size )
184 {
185    void *ptr = debug_malloc( file, line, function, count * size );
186    if( ptr )
187       memset( ptr, 0, count * size );
188    return ptr;
189 }
190
191 void *
192 debug_realloc(const char *file, unsigned line, const char *function,
193               void *old_ptr, size_t old_size, size_t new_size )
194 {
195    struct debug_memory_header *old_hdr, *new_hdr;
196    struct debug_memory_footer *old_ftr, *new_ftr;
197    void *new_ptr;
198    
199    if(!old_ptr)
200       return debug_malloc( file, line, function, new_size );
201    
202    if(!new_size) {
203       debug_free( file, line, function, old_ptr );
204       return NULL;
205    }
206    
207    old_hdr = header_from_data(old_ptr);
208    if(old_hdr->magic != DEBUG_MEMORY_MAGIC) {
209       debug_printf("%s:%u:%s: reallocating bad or corrupted memory %p\n",
210                    file, line, function,
211                    old_ptr);
212       debug_assert(0);
213       return NULL;
214    }
215    
216    old_ftr = footer_from_header(old_hdr);
217    if(old_ftr->magic != DEBUG_MEMORY_MAGIC) {
218       debug_printf("%s:%u:%s: buffer overflow %p\n",
219                    old_hdr->file, old_hdr->line, old_hdr->function,
220                    old_ptr);
221       debug_assert(0);
222    }
223
224    /* alloc new */
225    new_hdr = os_malloc(sizeof(*new_hdr) + new_size + sizeof(*new_ftr));
226    if(!new_hdr) {
227       debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
228                    file, line, function,
229                    (long unsigned)new_size);
230       return NULL;
231    }
232    new_hdr->no = old_hdr->no;
233    new_hdr->file = old_hdr->file;
234    new_hdr->line = old_hdr->line;
235    new_hdr->function = old_hdr->function;
236    new_hdr->size = new_size;
237    new_hdr->magic = DEBUG_MEMORY_MAGIC;
238    
239    new_ftr = footer_from_header(new_hdr);
240    new_ftr->magic = DEBUG_MEMORY_MAGIC;
241    
242    pipe_mutex_lock(list_mutex);
243    LIST_REPLACE(&old_hdr->head, &new_hdr->head);
244    pipe_mutex_unlock(list_mutex);
245
246    /* copy data */
247    new_ptr = data_from_header(new_hdr);
248    memcpy( new_ptr, old_ptr, old_size < new_size ? old_size : new_size );
249
250    /* free old */
251    old_hdr->magic = 0;
252    old_ftr->magic = 0;
253    os_free(old_hdr);
254
255    return new_ptr;
256 }
257
258 unsigned long
259 debug_memory_begin(void)
260 {
261    return last_no;
262 }
263
264 void 
265 debug_memory_end(unsigned long start_no)
266 {
267    size_t total_size = 0;
268    struct list_head *entry;
269
270    if(start_no == last_no)
271       return;
272
273    entry = list.prev;
274    for (; entry != &list; entry = entry->prev) {
275       struct debug_memory_header *hdr;
276       void *ptr;
277       struct debug_memory_footer *ftr;
278
279       hdr = LIST_ENTRY(struct debug_memory_header, entry, head);
280       ptr = data_from_header(hdr);
281       ftr = footer_from_header(hdr);
282
283       if(hdr->magic != DEBUG_MEMORY_MAGIC) {
284          debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
285                       hdr->file, hdr->line, hdr->function,
286                       ptr);
287          debug_assert(0);
288       }
289
290       if((start_no <= hdr->no && hdr->no < last_no) ||
291          (last_no < start_no && (hdr->no < last_no || start_no <= hdr->no))) {
292          debug_printf("%s:%u:%s: %lu bytes at %p not freed\n",
293                       hdr->file, hdr->line, hdr->function,
294                       (unsigned long) hdr->size, ptr);
295 #if DEBUG_MEMORY_STACK
296          debug_backtrace_dump(hdr->backtrace, DEBUG_MEMORY_STACK);
297 #endif
298          total_size += hdr->size;
299       }
300
301       if(ftr->magic != DEBUG_MEMORY_MAGIC) {
302          debug_printf("%s:%u:%s: buffer overflow %p\n",
303                       hdr->file, hdr->line, hdr->function,
304                       ptr);
305          debug_assert(0);
306       }
307    }
308
309    if(total_size) {
310       debug_printf("Total of %lu KB of system memory apparently leaked\n",
311                    (unsigned long) (total_size + 1023)/1024);
312    }
313    else {
314       debug_printf("No memory leaks detected.\n");
315    }
316 }