1 /**************************************************************************
3 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
30 * Debug buffer manager to detect buffer under- and overflows.
32 * \author Jose Fonseca <jrfonseca@tungstengraphics.com>
36 #include "pipe/p_compiler.h"
37 #include "util/u_debug.h"
38 #include "os/os_thread.h"
39 #include "util/u_math.h"
40 #include "util/u_memory.h"
41 #include "util/u_double_list.h"
42 #include "util/u_time.h"
43 #include "util/u_debug_stack.h"
45 #include "pb_buffer.h"
46 #include "pb_bufmgr.h"
52 #define PB_DEBUG_CREATE_BACKTRACE 8
53 #define PB_DEBUG_MAP_BACKTRACE 8
57 * Convenience macro (type safe).
59 #define SUPER(__derived) (&(__derived)->base)
62 struct pb_debug_manager
;
66 * Wrapper around a pipe buffer which adds delayed destruction.
68 struct pb_debug_buffer
70 struct pb_buffer base
;
72 struct pb_buffer
*buffer
;
73 struct pb_debug_manager
*mgr
;
75 pb_size underflow_size
;
76 pb_size overflow_size
;
78 struct debug_stack_frame create_backtrace
[PB_DEBUG_CREATE_BACKTRACE
];
82 struct debug_stack_frame map_backtrace
[PB_DEBUG_MAP_BACKTRACE
];
84 struct list_head head
;
88 struct pb_debug_manager
90 struct pb_manager base
;
92 struct pb_manager
*provider
;
94 pb_size underflow_size
;
95 pb_size overflow_size
;
98 struct list_head list
;
102 static INLINE
struct pb_debug_buffer
*
103 pb_debug_buffer(struct pb_buffer
*buf
)
106 return (struct pb_debug_buffer
*)buf
;
110 static INLINE
struct pb_debug_manager
*
111 pb_debug_manager(struct pb_manager
*mgr
)
114 return (struct pb_debug_manager
*)mgr
;
118 static const uint8_t random_pattern
[32] = {
119 0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
120 0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
121 0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
122 0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
127 fill_random_pattern(uint8_t *dst
, pb_size size
)
131 *dst
++ = random_pattern
[i
++];
132 i
&= sizeof(random_pattern
) - 1;
137 static INLINE boolean
138 check_random_pattern(const uint8_t *dst
, pb_size size
,
139 pb_size
*min_ofs
, pb_size
*max_ofs
)
141 boolean result
= TRUE
;
145 for(i
= 0; i
< size
; ++i
) {
146 if(*dst
++ != random_pattern
[i
% sizeof(random_pattern
)]) {
147 *min_ofs
= MIN2(*min_ofs
, i
);
148 *max_ofs
= MAX2(*max_ofs
, i
);
157 pb_debug_buffer_fill(struct pb_debug_buffer
*buf
)
161 map
= pb_map(buf
->buffer
, PB_USAGE_CPU_WRITE
, NULL
);
164 fill_random_pattern(map
, buf
->underflow_size
);
165 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
167 pb_unmap(buf
->buffer
);
173 * Check for under/over flows.
175 * Should be called with the buffer unmaped.
178 pb_debug_buffer_check(struct pb_debug_buffer
*buf
)
182 map
= pb_map(buf
->buffer
,
184 PB_USAGE_UNSYNCHRONIZED
, NULL
);
187 boolean underflow
, overflow
;
188 pb_size min_ofs
, max_ofs
;
190 underflow
= !check_random_pattern(map
, buf
->underflow_size
,
193 debug_printf("buffer underflow (offset -%u%s to -%u bytes) detected\n",
194 buf
->underflow_size
- min_ofs
,
195 min_ofs
== 0 ? "+" : "",
196 buf
->underflow_size
- max_ofs
);
199 overflow
= !check_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
203 debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
207 max_ofs
== buf
->overflow_size
- 1 ? "+" : "");
210 if(underflow
|| overflow
)
211 debug_backtrace_dump(buf
->create_backtrace
, PB_DEBUG_CREATE_BACKTRACE
);
213 debug_assert(!underflow
&& !overflow
);
215 /* re-fill if not aborted */
217 fill_random_pattern(map
, buf
->underflow_size
);
219 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
222 pb_unmap(buf
->buffer
);
228 pb_debug_buffer_destroy(struct pb_buffer
*_buf
)
230 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
231 struct pb_debug_manager
*mgr
= buf
->mgr
;
233 assert(!pipe_is_referenced(&buf
->base
.base
.reference
));
235 pb_debug_buffer_check(buf
);
237 pipe_mutex_lock(mgr
->mutex
);
238 LIST_DEL(&buf
->head
);
239 pipe_mutex_unlock(mgr
->mutex
);
241 pipe_mutex_destroy(buf
->mutex
);
243 pb_reference(&buf
->buffer
, NULL
);
249 pb_debug_buffer_map(struct pb_buffer
*_buf
,
250 unsigned flags
, void *flush_ctx
)
252 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
255 pb_debug_buffer_check(buf
);
257 map
= pb_map(buf
->buffer
, flags
, flush_ctx
);
262 pipe_mutex_lock(buf
->mutex
);
264 debug_backtrace_capture(buf
->map_backtrace
, 1, PB_DEBUG_MAP_BACKTRACE
);
265 pipe_mutex_unlock(buf
->mutex
);
268 return (uint8_t *)map
+ buf
->underflow_size
;
273 pb_debug_buffer_unmap(struct pb_buffer
*_buf
)
275 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
277 pipe_mutex_lock(buf
->mutex
);
278 assert(buf
->map_count
);
281 pipe_mutex_unlock(buf
->mutex
);
283 pb_unmap(buf
->buffer
);
285 pb_debug_buffer_check(buf
);
290 pb_debug_buffer_get_base_buffer(struct pb_buffer
*_buf
,
291 struct pb_buffer
**base_buf
,
294 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
295 pb_get_base_buffer(buf
->buffer
, base_buf
, offset
);
296 *offset
+= buf
->underflow_size
;
300 static enum pipe_error
301 pb_debug_buffer_validate(struct pb_buffer
*_buf
,
302 struct pb_validate
*vl
,
305 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
307 pipe_mutex_lock(buf
->mutex
);
309 debug_printf("%s: attempting to validate a mapped buffer\n", __FUNCTION__
);
310 debug_printf("last map backtrace is\n");
311 debug_backtrace_dump(buf
->map_backtrace
, PB_DEBUG_MAP_BACKTRACE
);
313 pipe_mutex_unlock(buf
->mutex
);
315 pb_debug_buffer_check(buf
);
317 return pb_validate(buf
->buffer
, vl
, flags
);
322 pb_debug_buffer_fence(struct pb_buffer
*_buf
,
323 struct pipe_fence_handle
*fence
)
325 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
326 pb_fence(buf
->buffer
, fence
);
331 pb_debug_buffer_vtbl
= {
332 pb_debug_buffer_destroy
,
334 pb_debug_buffer_unmap
,
335 pb_debug_buffer_validate
,
336 pb_debug_buffer_fence
,
337 pb_debug_buffer_get_base_buffer
342 pb_debug_manager_dump(struct pb_debug_manager
*mgr
)
344 struct list_head
*curr
, *next
;
345 struct pb_debug_buffer
*buf
;
347 pipe_mutex_lock(mgr
->mutex
);
349 curr
= mgr
->list
.next
;
351 while(curr
!= &mgr
->list
) {
352 buf
= LIST_ENTRY(struct pb_debug_buffer
, curr
, head
);
354 debug_printf("buffer = %p\n", (void *) buf
);
355 debug_printf(" .size = 0x%x\n", buf
->base
.base
.size
);
356 debug_backtrace_dump(buf
->create_backtrace
, PB_DEBUG_CREATE_BACKTRACE
);
362 pipe_mutex_unlock(mgr
->mutex
);
366 static struct pb_buffer
*
367 pb_debug_manager_create_buffer(struct pb_manager
*_mgr
,
369 const struct pb_desc
*desc
)
371 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
372 struct pb_debug_buffer
*buf
;
373 struct pb_desc real_desc
;
377 assert(desc
->alignment
);
379 buf
= CALLOC_STRUCT(pb_debug_buffer
);
383 real_size
= mgr
->underflow_size
+ size
+ mgr
->overflow_size
;
385 real_desc
.usage
|= PB_USAGE_CPU_WRITE
;
386 real_desc
.usage
|= PB_USAGE_CPU_READ
;
388 buf
->buffer
= mgr
->provider
->create_buffer(mgr
->provider
,
394 pipe_mutex_lock(mgr
->mutex
);
395 debug_printf("%s: failed to create buffer\n", __FUNCTION__
);
396 if(!LIST_IS_EMPTY(&mgr
->list
))
397 pb_debug_manager_dump(mgr
);
398 pipe_mutex_unlock(mgr
->mutex
);
403 assert(pipe_is_referenced(&buf
->buffer
->base
.reference
));
404 assert(pb_check_alignment(real_desc
.alignment
, buf
->buffer
->base
.alignment
));
405 assert(pb_check_usage(real_desc
.usage
, buf
->buffer
->base
.usage
));
406 assert(buf
->buffer
->base
.size
>= real_size
);
408 pipe_reference_init(&buf
->base
.base
.reference
, 1);
409 buf
->base
.base
.alignment
= desc
->alignment
;
410 buf
->base
.base
.usage
= desc
->usage
;
411 buf
->base
.base
.size
= size
;
413 buf
->base
.vtbl
= &pb_debug_buffer_vtbl
;
416 buf
->underflow_size
= mgr
->underflow_size
;
417 buf
->overflow_size
= buf
->buffer
->base
.size
- buf
->underflow_size
- size
;
419 debug_backtrace_capture(buf
->create_backtrace
, 1, PB_DEBUG_CREATE_BACKTRACE
);
421 pb_debug_buffer_fill(buf
);
423 pipe_mutex_init(buf
->mutex
);
425 pipe_mutex_lock(mgr
->mutex
);
426 LIST_ADDTAIL(&buf
->head
, &mgr
->list
);
427 pipe_mutex_unlock(mgr
->mutex
);
434 pb_debug_manager_flush(struct pb_manager
*_mgr
)
436 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
437 assert(mgr
->provider
->flush
);
438 if(mgr
->provider
->flush
)
439 mgr
->provider
->flush(mgr
->provider
);
444 pb_debug_manager_destroy(struct pb_manager
*_mgr
)
446 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
448 pipe_mutex_lock(mgr
->mutex
);
449 if(!LIST_IS_EMPTY(&mgr
->list
)) {
450 debug_printf("%s: unfreed buffers\n", __FUNCTION__
);
451 pb_debug_manager_dump(mgr
);
453 pipe_mutex_unlock(mgr
->mutex
);
455 pipe_mutex_destroy(mgr
->mutex
);
456 mgr
->provider
->destroy(mgr
->provider
);
462 pb_debug_manager_create(struct pb_manager
*provider
,
463 pb_size underflow_size
, pb_size overflow_size
)
465 struct pb_debug_manager
*mgr
;
470 mgr
= CALLOC_STRUCT(pb_debug_manager
);
474 mgr
->base
.destroy
= pb_debug_manager_destroy
;
475 mgr
->base
.create_buffer
= pb_debug_manager_create_buffer
;
476 mgr
->base
.flush
= pb_debug_manager_flush
;
477 mgr
->provider
= provider
;
478 mgr
->underflow_size
= underflow_size
;
479 mgr
->overflow_size
= overflow_size
;
481 pipe_mutex_init(mgr
->mutex
);
482 LIST_INITHEAD(&mgr
->list
);
492 pb_debug_manager_create(struct pb_manager
*provider
,
493 pb_size underflow_size
, pb_size overflow_size
)