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 "pipe/p_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
, PIPE_BUFFER_USAGE_CPU_WRITE
);
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
, PIPE_BUFFER_USAGE_CPU_READ
);
185 boolean underflow
, overflow
;
186 pb_size min_ofs
, max_ofs
;
188 underflow
= !check_random_pattern(map
, buf
->underflow_size
,
191 debug_printf("buffer underflow (offset -%u%s to -%u bytes) detected\n",
192 buf
->underflow_size
- min_ofs
,
193 min_ofs
== 0 ? "+" : "",
194 buf
->underflow_size
- max_ofs
);
197 overflow
= !check_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
201 debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
205 max_ofs
== buf
->overflow_size
- 1 ? "+" : "");
208 if(underflow
|| overflow
)
209 debug_backtrace_dump(buf
->create_backtrace
, PB_DEBUG_CREATE_BACKTRACE
);
211 debug_assert(!underflow
&& !overflow
);
213 /* re-fill if not aborted */
215 fill_random_pattern(map
, buf
->underflow_size
);
217 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
220 pb_unmap(buf
->buffer
);
226 pb_debug_buffer_destroy(struct pb_buffer
*_buf
)
228 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
229 struct pb_debug_manager
*mgr
= buf
->mgr
;
231 assert(!pipe_is_referenced(&buf
->base
.base
.reference
));
233 pb_debug_buffer_check(buf
);
235 pipe_mutex_lock(mgr
->mutex
);
236 LIST_DEL(&buf
->head
);
237 pipe_mutex_unlock(mgr
->mutex
);
239 pipe_mutex_destroy(buf
->mutex
);
241 pb_reference(&buf
->buffer
, NULL
);
247 pb_debug_buffer_map(struct pb_buffer
*_buf
,
250 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
253 pb_debug_buffer_check(buf
);
255 map
= pb_map(buf
->buffer
, flags
);
260 pipe_mutex_lock(buf
->mutex
);
262 debug_backtrace_capture(buf
->map_backtrace
, 1, PB_DEBUG_MAP_BACKTRACE
);
263 pipe_mutex_unlock(buf
->mutex
);
266 return (uint8_t *)map
+ buf
->underflow_size
;
271 pb_debug_buffer_unmap(struct pb_buffer
*_buf
)
273 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
275 pipe_mutex_lock(buf
->mutex
);
276 assert(buf
->map_count
);
279 pipe_mutex_unlock(buf
->mutex
);
281 pb_unmap(buf
->buffer
);
283 pb_debug_buffer_check(buf
);
288 pb_debug_buffer_get_base_buffer(struct pb_buffer
*_buf
,
289 struct pb_buffer
**base_buf
,
292 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
293 pb_get_base_buffer(buf
->buffer
, base_buf
, offset
);
294 *offset
+= buf
->underflow_size
;
298 static enum pipe_error
299 pb_debug_buffer_validate(struct pb_buffer
*_buf
,
300 struct pb_validate
*vl
,
303 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
305 pipe_mutex_lock(buf
->mutex
);
307 debug_printf("%s: attempting to validate a mapped buffer\n", __FUNCTION__
);
308 debug_printf("last map backtrace is\n");
309 debug_backtrace_dump(buf
->map_backtrace
, PB_DEBUG_MAP_BACKTRACE
);
311 pipe_mutex_unlock(buf
->mutex
);
313 pb_debug_buffer_check(buf
);
315 return pb_validate(buf
->buffer
, vl
, flags
);
320 pb_debug_buffer_fence(struct pb_buffer
*_buf
,
321 struct pipe_fence_handle
*fence
)
323 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
324 pb_fence(buf
->buffer
, fence
);
329 pb_debug_buffer_vtbl
= {
330 pb_debug_buffer_destroy
,
332 pb_debug_buffer_unmap
,
333 pb_debug_buffer_validate
,
334 pb_debug_buffer_fence
,
335 pb_debug_buffer_get_base_buffer
340 pb_debug_manager_dump(struct pb_debug_manager
*mgr
)
342 struct list_head
*curr
, *next
;
343 struct pb_debug_buffer
*buf
;
345 pipe_mutex_lock(mgr
->mutex
);
347 curr
= mgr
->list
.next
;
349 while(curr
!= &mgr
->list
) {
350 buf
= LIST_ENTRY(struct pb_debug_buffer
, curr
, head
);
352 debug_printf("buffer = %p\n", buf
);
353 debug_printf(" .size = 0x%x\n", buf
->base
.base
.size
);
354 debug_backtrace_dump(buf
->create_backtrace
, PB_DEBUG_CREATE_BACKTRACE
);
360 pipe_mutex_unlock(mgr
->mutex
);
364 static struct pb_buffer
*
365 pb_debug_manager_create_buffer(struct pb_manager
*_mgr
,
367 const struct pb_desc
*desc
)
369 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
370 struct pb_debug_buffer
*buf
;
371 struct pb_desc real_desc
;
374 buf
= CALLOC_STRUCT(pb_debug_buffer
);
378 real_size
= mgr
->underflow_size
+ size
+ mgr
->overflow_size
;
380 real_desc
.usage
|= PIPE_BUFFER_USAGE_CPU_WRITE
;
381 real_desc
.usage
|= PIPE_BUFFER_USAGE_CPU_READ
;
383 buf
->buffer
= mgr
->provider
->create_buffer(mgr
->provider
,
389 pipe_mutex_lock(mgr
->mutex
);
390 debug_printf("%s: failed to create buffer\n", __FUNCTION__
);
391 if(!LIST_IS_EMPTY(&mgr
->list
))
392 pb_debug_manager_dump(mgr
);
393 pipe_mutex_unlock(mgr
->mutex
);
398 assert(pipe_is_referenced(&buf
->buffer
->base
.reference
));
399 assert(pb_check_alignment(real_desc
.alignment
, buf
->buffer
->base
.alignment
));
400 assert(pb_check_usage(real_desc
.usage
, buf
->buffer
->base
.usage
));
401 assert(buf
->buffer
->base
.size
>= real_size
);
403 pipe_reference_init(&buf
->base
.base
.reference
, 1);
404 buf
->base
.base
.alignment
= desc
->alignment
;
405 buf
->base
.base
.usage
= desc
->usage
;
406 buf
->base
.base
.size
= size
;
408 buf
->base
.vtbl
= &pb_debug_buffer_vtbl
;
411 buf
->underflow_size
= mgr
->underflow_size
;
412 buf
->overflow_size
= buf
->buffer
->base
.size
- buf
->underflow_size
- size
;
414 debug_backtrace_capture(buf
->create_backtrace
, 1, PB_DEBUG_CREATE_BACKTRACE
);
416 pb_debug_buffer_fill(buf
);
418 pipe_mutex_init(buf
->mutex
);
420 pipe_mutex_lock(mgr
->mutex
);
421 LIST_ADDTAIL(&buf
->head
, &mgr
->list
);
422 pipe_mutex_unlock(mgr
->mutex
);
429 pb_debug_manager_flush(struct pb_manager
*_mgr
)
431 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
432 assert(mgr
->provider
->flush
);
433 if(mgr
->provider
->flush
)
434 mgr
->provider
->flush(mgr
->provider
);
439 pb_debug_manager_destroy(struct pb_manager
*_mgr
)
441 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
443 pipe_mutex_lock(mgr
->mutex
);
444 if(!LIST_IS_EMPTY(&mgr
->list
)) {
445 debug_printf("%s: unfreed buffers\n", __FUNCTION__
);
446 pb_debug_manager_dump(mgr
);
448 pipe_mutex_unlock(mgr
->mutex
);
450 pipe_mutex_destroy(mgr
->mutex
);
451 mgr
->provider
->destroy(mgr
->provider
);
457 pb_debug_manager_create(struct pb_manager
*provider
,
458 pb_size underflow_size
, pb_size overflow_size
)
460 struct pb_debug_manager
*mgr
;
465 mgr
= CALLOC_STRUCT(pb_debug_manager
);
469 mgr
->base
.destroy
= pb_debug_manager_destroy
;
470 mgr
->base
.create_buffer
= pb_debug_manager_create_buffer
;
471 mgr
->base
.flush
= pb_debug_manager_flush
;
472 mgr
->provider
= provider
;
473 mgr
->underflow_size
= underflow_size
;
474 mgr
->overflow_size
= overflow_size
;
476 pipe_mutex_init(mgr
->mutex
);
477 LIST_INITHEAD(&mgr
->list
);
487 pb_debug_manager_create(struct pb_manager
*provider
,
488 pb_size underflow_size
, pb_size overflow_size
)