1 /**************************************************************************
3 * Copyright 2007-2008 VMware, Inc.
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 VMWARE 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 <jfonseca@vmware.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/list.h"
42 #include "util/u_time.h"
43 #include "util/u_debug_stack.h"
46 #include "pb_buffer.h"
47 #include "pb_bufmgr.h"
53 #define PB_DEBUG_CREATE_BACKTRACE 8
54 #define PB_DEBUG_MAP_BACKTRACE 8
58 * Convenience macro (type safe).
60 #define SUPER(__derived) (&(__derived)->base)
63 struct pb_debug_manager
;
67 * Wrapper around a pipe buffer which adds delayed destruction.
69 struct pb_debug_buffer
71 struct pb_buffer base
;
73 struct pb_buffer
*buffer
;
74 struct pb_debug_manager
*mgr
;
76 pb_size underflow_size
;
77 pb_size overflow_size
;
79 struct debug_stack_frame create_backtrace
[PB_DEBUG_CREATE_BACKTRACE
];
83 struct debug_stack_frame map_backtrace
[PB_DEBUG_MAP_BACKTRACE
];
85 struct list_head head
;
89 struct pb_debug_manager
91 struct pb_manager base
;
93 struct pb_manager
*provider
;
95 pb_size underflow_size
;
96 pb_size overflow_size
;
99 struct list_head list
;
103 static inline struct pb_debug_buffer
*
104 pb_debug_buffer(struct pb_buffer
*buf
)
107 return (struct pb_debug_buffer
*)buf
;
111 static inline struct pb_debug_manager
*
112 pb_debug_manager(struct pb_manager
*mgr
)
115 return (struct pb_debug_manager
*)mgr
;
119 static const uint8_t random_pattern
[32] = {
120 0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
121 0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
122 0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
123 0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
128 fill_random_pattern(uint8_t *dst
, pb_size size
)
132 *dst
++ = random_pattern
[i
++];
133 i
&= sizeof(random_pattern
) - 1;
138 static inline boolean
139 check_random_pattern(const uint8_t *dst
, pb_size size
,
140 pb_size
*min_ofs
, pb_size
*max_ofs
)
142 boolean result
= TRUE
;
146 for(i
= 0; i
< size
; ++i
) {
147 if(*dst
++ != random_pattern
[i
% sizeof(random_pattern
)]) {
148 *min_ofs
= MIN2(*min_ofs
, i
);
149 *max_ofs
= MAX2(*max_ofs
, i
);
158 pb_debug_buffer_fill(struct pb_debug_buffer
*buf
)
162 map
= pb_map(buf
->buffer
, PB_USAGE_CPU_WRITE
, NULL
);
165 fill_random_pattern(map
, buf
->underflow_size
);
166 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.size
,
168 pb_unmap(buf
->buffer
);
174 * Check for under/over flows.
176 * Should be called with the buffer unmaped.
179 pb_debug_buffer_check(struct pb_debug_buffer
*buf
)
183 map
= pb_map(buf
->buffer
,
185 PB_USAGE_UNSYNCHRONIZED
, NULL
);
188 boolean underflow
, overflow
;
189 pb_size min_ofs
, max_ofs
;
191 underflow
= !check_random_pattern(map
, buf
->underflow_size
,
194 debug_printf("buffer underflow (offset -%"PRIu64
"%s to -%"PRIu64
" bytes) detected\n",
195 buf
->underflow_size
- min_ofs
,
196 min_ofs
== 0 ? "+" : "",
197 buf
->underflow_size
- max_ofs
);
200 overflow
= !check_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.size
,
204 debug_printf("buffer overflow (size %"PRIu64
" plus offset %"PRIu64
" to %"PRIu64
"%s bytes) detected\n",
208 max_ofs
== buf
->overflow_size
- 1 ? "+" : "");
211 if(underflow
|| overflow
)
212 debug_backtrace_dump(buf
->create_backtrace
, PB_DEBUG_CREATE_BACKTRACE
);
214 debug_assert(!underflow
);
215 debug_assert(!overflow
);
217 /* re-fill if not aborted */
219 fill_random_pattern(map
, buf
->underflow_size
);
221 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.size
,
224 pb_unmap(buf
->buffer
);
230 pb_debug_buffer_destroy(struct pb_buffer
*_buf
)
232 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
233 struct pb_debug_manager
*mgr
= buf
->mgr
;
235 assert(!pipe_is_referenced(&buf
->base
.reference
));
237 pb_debug_buffer_check(buf
);
239 pipe_mutex_lock(mgr
->mutex
);
240 LIST_DEL(&buf
->head
);
241 pipe_mutex_unlock(mgr
->mutex
);
243 pipe_mutex_destroy(buf
->mutex
);
245 pb_reference(&buf
->buffer
, NULL
);
251 pb_debug_buffer_map(struct pb_buffer
*_buf
,
252 unsigned flags
, void *flush_ctx
)
254 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
257 pb_debug_buffer_check(buf
);
259 map
= pb_map(buf
->buffer
, flags
, flush_ctx
);
263 pipe_mutex_lock(buf
->mutex
);
265 debug_backtrace_capture(buf
->map_backtrace
, 1, PB_DEBUG_MAP_BACKTRACE
);
266 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_locked(struct pb_debug_manager
*mgr
)
344 struct list_head
*curr
, *next
;
345 struct pb_debug_buffer
*buf
;
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", (void *) buf
);
353 debug_printf(" .size = 0x%"PRIx64
"\n", buf
->base
.size
);
354 debug_backtrace_dump(buf
->create_backtrace
, PB_DEBUG_CREATE_BACKTRACE
);
363 static struct pb_buffer
*
364 pb_debug_manager_create_buffer(struct pb_manager
*_mgr
,
366 const struct pb_desc
*desc
)
368 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
369 struct pb_debug_buffer
*buf
;
370 struct pb_desc real_desc
;
374 assert(desc
->alignment
);
376 buf
= CALLOC_STRUCT(pb_debug_buffer
);
380 real_size
= mgr
->underflow_size
+ size
+ mgr
->overflow_size
;
382 real_desc
.usage
|= PB_USAGE_CPU_WRITE
;
383 real_desc
.usage
|= PB_USAGE_CPU_READ
;
385 buf
->buffer
= mgr
->provider
->create_buffer(mgr
->provider
,
391 pipe_mutex_lock(mgr
->mutex
);
392 debug_printf("%s: failed to create buffer\n", __FUNCTION__
);
393 if(!LIST_IS_EMPTY(&mgr
->list
))
394 pb_debug_manager_dump_locked(mgr
);
395 pipe_mutex_unlock(mgr
->mutex
);
400 assert(pipe_is_referenced(&buf
->buffer
->reference
));
401 assert(pb_check_alignment(real_desc
.alignment
, buf
->buffer
->alignment
));
402 assert(pb_check_usage(real_desc
.usage
, buf
->buffer
->usage
));
403 assert(buf
->buffer
->size
>= real_size
);
405 pipe_reference_init(&buf
->base
.reference
, 1);
406 buf
->base
.alignment
= desc
->alignment
;
407 buf
->base
.usage
= desc
->usage
;
408 buf
->base
.size
= size
;
410 buf
->base
.vtbl
= &pb_debug_buffer_vtbl
;
413 buf
->underflow_size
= mgr
->underflow_size
;
414 buf
->overflow_size
= buf
->buffer
->size
- buf
->underflow_size
- size
;
416 debug_backtrace_capture(buf
->create_backtrace
, 1, PB_DEBUG_CREATE_BACKTRACE
);
418 pb_debug_buffer_fill(buf
);
420 pipe_mutex_init(buf
->mutex
);
422 pipe_mutex_lock(mgr
->mutex
);
423 LIST_ADDTAIL(&buf
->head
, &mgr
->list
);
424 pipe_mutex_unlock(mgr
->mutex
);
431 pb_debug_manager_flush(struct pb_manager
*_mgr
)
433 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
434 assert(mgr
->provider
->flush
);
435 if(mgr
->provider
->flush
)
436 mgr
->provider
->flush(mgr
->provider
);
441 pb_debug_manager_destroy(struct pb_manager
*_mgr
)
443 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
445 pipe_mutex_lock(mgr
->mutex
);
446 if(!LIST_IS_EMPTY(&mgr
->list
)) {
447 debug_printf("%s: unfreed buffers\n", __FUNCTION__
);
448 pb_debug_manager_dump_locked(mgr
);
450 pipe_mutex_unlock(mgr
->mutex
);
452 pipe_mutex_destroy(mgr
->mutex
);
453 mgr
->provider
->destroy(mgr
->provider
);
459 pb_debug_manager_create(struct pb_manager
*provider
,
460 pb_size underflow_size
, pb_size overflow_size
)
462 struct pb_debug_manager
*mgr
;
467 mgr
= CALLOC_STRUCT(pb_debug_manager
);
471 mgr
->base
.destroy
= pb_debug_manager_destroy
;
472 mgr
->base
.create_buffer
= pb_debug_manager_create_buffer
;
473 mgr
->base
.flush
= pb_debug_manager_flush
;
474 mgr
->provider
= provider
;
475 mgr
->underflow_size
= underflow_size
;
476 mgr
->overflow_size
= overflow_size
;
478 pipe_mutex_init(mgr
->mutex
);
479 LIST_INITHEAD(&mgr
->list
);
489 pb_debug_manager_create(struct pb_manager
*provider
,
490 pb_size underflow_size
, pb_size overflow_size
)