Path: blob/21.2-virgl/src/gallium/auxiliary/pipebuffer/pb_bufmgr_debug.c
4565 views
/**************************************************************************1*2* Copyright 2007-2008 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/**28* \file29* Debug buffer manager to detect buffer under- and overflows.30*31* \author Jose Fonseca <[email protected]>32*/333435#include "pipe/p_compiler.h"36#include "util/u_debug.h"37#include "os/os_thread.h"38#include "util/u_math.h"39#include "util/u_memory.h"40#include "util/list.h"41#include "util/u_debug_stack.h"42#include <inttypes.h>4344#include "pb_buffer.h"45#include "pb_bufmgr.h"464748#ifdef DEBUG495051#define PB_DEBUG_CREATE_BACKTRACE 852#define PB_DEBUG_MAP_BACKTRACE 8535455/**56* Convenience macro (type safe).57*/58#define SUPER(__derived) (&(__derived)->base)596061struct pb_debug_manager;626364/**65* Wrapper around a pipe buffer which adds delayed destruction.66*/67struct pb_debug_buffer68{69struct pb_buffer base;7071struct pb_buffer *buffer;72struct pb_debug_manager *mgr;7374pb_size underflow_size;75pb_size overflow_size;7677struct debug_stack_frame create_backtrace[PB_DEBUG_CREATE_BACKTRACE];7879mtx_t mutex;80unsigned map_count;81struct debug_stack_frame map_backtrace[PB_DEBUG_MAP_BACKTRACE];8283struct list_head head;84};858687struct pb_debug_manager88{89struct pb_manager base;9091struct pb_manager *provider;9293pb_size underflow_size;94pb_size overflow_size;9596mtx_t mutex;97struct list_head list;98};99100101static inline struct pb_debug_buffer *102pb_debug_buffer(struct pb_buffer *buf)103{104assert(buf);105return (struct pb_debug_buffer *)buf;106}107108109static inline struct pb_debug_manager *110pb_debug_manager(struct pb_manager *mgr)111{112assert(mgr);113return (struct pb_debug_manager *)mgr;114}115116117static const uint8_t random_pattern[32] = {1180xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,1190x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,1200x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,1210x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94122};123124125static inline void126fill_random_pattern(uint8_t *dst, pb_size size)127{128pb_size i = 0;129while(size--) {130*dst++ = random_pattern[i++];131i &= sizeof(random_pattern) - 1;132}133}134135136static inline boolean137check_random_pattern(const uint8_t *dst, pb_size size,138pb_size *min_ofs, pb_size *max_ofs)139{140boolean result = TRUE;141pb_size i;142*min_ofs = size;143*max_ofs = 0;144for(i = 0; i < size; ++i) {145if(*dst++ != random_pattern[i % sizeof(random_pattern)]) {146*min_ofs = MIN2(*min_ofs, i);147*max_ofs = MAX2(*max_ofs, i);148result = FALSE;149}150}151return result;152}153154155static void156pb_debug_buffer_fill(struct pb_debug_buffer *buf)157{158uint8_t *map;159160map = pb_map(buf->buffer, PB_USAGE_CPU_WRITE, NULL);161assert(map);162if (map) {163fill_random_pattern(map, buf->underflow_size);164fill_random_pattern(map + buf->underflow_size + buf->base.size,165buf->overflow_size);166pb_unmap(buf->buffer);167}168}169170171/**172* Check for under/over flows.173*174* Should be called with the buffer unmaped.175*/176static void177pb_debug_buffer_check(struct pb_debug_buffer *buf)178{179uint8_t *map;180181map = pb_map(buf->buffer,182PB_USAGE_CPU_READ |183PB_USAGE_UNSYNCHRONIZED, NULL);184assert(map);185if (map) {186boolean underflow, overflow;187pb_size min_ofs, max_ofs;188189underflow = !check_random_pattern(map, buf->underflow_size,190&min_ofs, &max_ofs);191if(underflow) {192debug_printf("buffer underflow (offset -%"PRIu64"%s to -%"PRIu64" bytes) detected\n",193buf->underflow_size - min_ofs,194min_ofs == 0 ? "+" : "",195buf->underflow_size - max_ofs);196}197198overflow = !check_random_pattern(map + buf->underflow_size + buf->base.size,199buf->overflow_size,200&min_ofs, &max_ofs);201if(overflow) {202debug_printf("buffer overflow (size %"PRIu64" plus offset %"PRIu64" to %"PRIu64"%s bytes) detected\n",203buf->base.size,204min_ofs,205max_ofs,206max_ofs == buf->overflow_size - 1 ? "+" : "");207}208209if(underflow || overflow)210debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);211212debug_assert(!underflow);213debug_assert(!overflow);214215/* re-fill if not aborted */216if(underflow)217fill_random_pattern(map, buf->underflow_size);218if(overflow)219fill_random_pattern(map + buf->underflow_size + buf->base.size,220buf->overflow_size);221222pb_unmap(buf->buffer);223}224}225226227static void228pb_debug_buffer_destroy(void *winsys, struct pb_buffer *_buf)229{230struct pb_debug_buffer *buf = pb_debug_buffer(_buf);231struct pb_debug_manager *mgr = buf->mgr;232233assert(!pipe_is_referenced(&buf->base.reference));234235pb_debug_buffer_check(buf);236237mtx_lock(&mgr->mutex);238list_del(&buf->head);239mtx_unlock(&mgr->mutex);240241mtx_destroy(&buf->mutex);242243pb_reference(&buf->buffer, NULL);244FREE(buf);245}246247248static void *249pb_debug_buffer_map(struct pb_buffer *_buf,250enum pb_usage_flags flags, void *flush_ctx)251{252struct pb_debug_buffer *buf = pb_debug_buffer(_buf);253void *map;254255pb_debug_buffer_check(buf);256257map = pb_map(buf->buffer, flags, flush_ctx);258if (!map)259return NULL;260261mtx_lock(&buf->mutex);262++buf->map_count;263debug_backtrace_capture(buf->map_backtrace, 1, PB_DEBUG_MAP_BACKTRACE);264mtx_unlock(&buf->mutex);265266return (uint8_t *)map + buf->underflow_size;267}268269270static void271pb_debug_buffer_unmap(struct pb_buffer *_buf)272{273struct pb_debug_buffer *buf = pb_debug_buffer(_buf);274275mtx_lock(&buf->mutex);276assert(buf->map_count);277if(buf->map_count)278--buf->map_count;279mtx_unlock(&buf->mutex);280281pb_unmap(buf->buffer);282283pb_debug_buffer_check(buf);284}285286287static void288pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,289struct pb_buffer **base_buf,290pb_size *offset)291{292struct pb_debug_buffer *buf = pb_debug_buffer(_buf);293pb_get_base_buffer(buf->buffer, base_buf, offset);294*offset += buf->underflow_size;295}296297298static enum pipe_error299pb_debug_buffer_validate(struct pb_buffer *_buf,300struct pb_validate *vl,301enum pb_usage_flags flags)302{303struct pb_debug_buffer *buf = pb_debug_buffer(_buf);304305assert((flags & ~PB_USAGE_ALL) == 0);306307mtx_lock(&buf->mutex);308if(buf->map_count) {309debug_printf("%s: attempting to validate a mapped buffer\n", __FUNCTION__);310debug_printf("last map backtrace is\n");311debug_backtrace_dump(buf->map_backtrace, PB_DEBUG_MAP_BACKTRACE);312}313mtx_unlock(&buf->mutex);314315pb_debug_buffer_check(buf);316317return pb_validate(buf->buffer, vl, flags);318}319320321static void322pb_debug_buffer_fence(struct pb_buffer *_buf,323struct pipe_fence_handle *fence)324{325struct pb_debug_buffer *buf = pb_debug_buffer(_buf);326pb_fence(buf->buffer, fence);327}328329330const struct pb_vtbl331pb_debug_buffer_vtbl = {332pb_debug_buffer_destroy,333pb_debug_buffer_map,334pb_debug_buffer_unmap,335pb_debug_buffer_validate,336pb_debug_buffer_fence,337pb_debug_buffer_get_base_buffer338};339340341static void342pb_debug_manager_dump_locked(struct pb_debug_manager *mgr)343{344struct list_head *curr, *next;345struct pb_debug_buffer *buf;346347curr = mgr->list.next;348next = curr->next;349while(curr != &mgr->list) {350buf = LIST_ENTRY(struct pb_debug_buffer, curr, head);351352debug_printf("buffer = %p\n", (void *) buf);353debug_printf(" .size = 0x%"PRIx64"\n", buf->base.size);354debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);355356curr = next;357next = curr->next;358}359360}361362363static struct pb_buffer *364pb_debug_manager_create_buffer(struct pb_manager *_mgr,365pb_size size,366const struct pb_desc *desc)367{368struct pb_debug_manager *mgr = pb_debug_manager(_mgr);369struct pb_debug_buffer *buf;370struct pb_desc real_desc;371pb_size real_size;372373assert(size);374assert(desc->alignment);375376buf = CALLOC_STRUCT(pb_debug_buffer);377if (!buf)378return NULL;379380real_size = mgr->underflow_size + size + mgr->overflow_size;381real_desc = *desc;382real_desc.usage |= PB_USAGE_CPU_WRITE;383real_desc.usage |= PB_USAGE_CPU_READ;384385buf->buffer = mgr->provider->create_buffer(mgr->provider,386real_size,387&real_desc);388if(!buf->buffer) {389FREE(buf);390#if 0391mtx_lock(&mgr->mutex);392debug_printf("%s: failed to create buffer\n", __FUNCTION__);393if(!list_is_empty(&mgr->list))394pb_debug_manager_dump_locked(mgr);395mtx_unlock(&mgr->mutex);396#endif397return NULL;398}399400assert(pipe_is_referenced(&buf->buffer->reference));401assert(pb_check_alignment(real_desc.alignment, 1u << buf->buffer->alignment_log2));402assert(pb_check_usage(real_desc.usage, buf->buffer->usage));403assert(buf->buffer->size >= real_size);404405pipe_reference_init(&buf->base.reference, 1);406buf->base.alignment_log2 = util_logbase2(desc->alignment);407buf->base.usage = desc->usage;408buf->base.size = size;409410buf->base.vtbl = &pb_debug_buffer_vtbl;411buf->mgr = mgr;412413buf->underflow_size = mgr->underflow_size;414buf->overflow_size = buf->buffer->size - buf->underflow_size - size;415416debug_backtrace_capture(buf->create_backtrace, 1, PB_DEBUG_CREATE_BACKTRACE);417418pb_debug_buffer_fill(buf);419420(void) mtx_init(&buf->mutex, mtx_plain);421422mtx_lock(&mgr->mutex);423list_addtail(&buf->head, &mgr->list);424mtx_unlock(&mgr->mutex);425426return &buf->base;427}428429430static void431pb_debug_manager_flush(struct pb_manager *_mgr)432{433struct pb_debug_manager *mgr = pb_debug_manager(_mgr);434assert(mgr->provider->flush);435if(mgr->provider->flush)436mgr->provider->flush(mgr->provider);437}438439440static void441pb_debug_manager_destroy(struct pb_manager *_mgr)442{443struct pb_debug_manager *mgr = pb_debug_manager(_mgr);444445mtx_lock(&mgr->mutex);446if(!list_is_empty(&mgr->list)) {447debug_printf("%s: unfreed buffers\n", __FUNCTION__);448pb_debug_manager_dump_locked(mgr);449}450mtx_unlock(&mgr->mutex);451452mtx_destroy(&mgr->mutex);453mgr->provider->destroy(mgr->provider);454FREE(mgr);455}456457458struct pb_manager *459pb_debug_manager_create(struct pb_manager *provider,460pb_size underflow_size, pb_size overflow_size)461{462struct pb_debug_manager *mgr;463464if (!provider)465return NULL;466467mgr = CALLOC_STRUCT(pb_debug_manager);468if (!mgr)469return NULL;470471mgr->base.destroy = pb_debug_manager_destroy;472mgr->base.create_buffer = pb_debug_manager_create_buffer;473mgr->base.flush = pb_debug_manager_flush;474mgr->provider = provider;475mgr->underflow_size = underflow_size;476mgr->overflow_size = overflow_size;477478(void) mtx_init(&mgr->mutex, mtx_plain);479list_inithead(&mgr->list);480481return &mgr->base;482}483484485#else /* !DEBUG */486487488struct pb_manager *489pb_debug_manager_create(struct pb_manager *provider,490pb_size underflow_size, pb_size overflow_size)491{492return provider;493}494495496#endif /* !DEBUG */497498499