1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2007-2008 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * \file
30bf215546Sopenharmony_ci * Debug buffer manager to detect buffer under- and overflows.
31bf215546Sopenharmony_ci *
32bf215546Sopenharmony_ci * \author Jose Fonseca <jfonseca@vmware.com>
33bf215546Sopenharmony_ci */
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#include "pipe/p_compiler.h"
37bf215546Sopenharmony_ci#include "util/u_debug.h"
38bf215546Sopenharmony_ci#include "os/os_thread.h"
39bf215546Sopenharmony_ci#include "util/u_math.h"
40bf215546Sopenharmony_ci#include "util/u_memory.h"
41bf215546Sopenharmony_ci#include "util/list.h"
42bf215546Sopenharmony_ci#include "util/u_debug_stack.h"
43bf215546Sopenharmony_ci#include <inttypes.h>
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci#include "pb_buffer.h"
46bf215546Sopenharmony_ci#include "pb_bufmgr.h"
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci#ifdef DEBUG
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci#define PB_DEBUG_CREATE_BACKTRACE 8
53bf215546Sopenharmony_ci#define PB_DEBUG_MAP_BACKTRACE 8
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci/**
57bf215546Sopenharmony_ci * Convenience macro (type safe).
58bf215546Sopenharmony_ci */
59bf215546Sopenharmony_ci#define SUPER(__derived) (&(__derived)->base)
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_cistruct pb_debug_manager;
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci/**
66bf215546Sopenharmony_ci * Wrapper around a pipe buffer which adds delayed destruction.
67bf215546Sopenharmony_ci */
68bf215546Sopenharmony_cistruct pb_debug_buffer
69bf215546Sopenharmony_ci{
70bf215546Sopenharmony_ci   struct pb_buffer base;
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   struct pb_buffer *buffer;
73bf215546Sopenharmony_ci   struct pb_debug_manager *mgr;
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci   pb_size underflow_size;
76bf215546Sopenharmony_ci   pb_size overflow_size;
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   struct debug_stack_frame create_backtrace[PB_DEBUG_CREATE_BACKTRACE];
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   mtx_t mutex;
81bf215546Sopenharmony_ci   unsigned map_count;
82bf215546Sopenharmony_ci   struct debug_stack_frame map_backtrace[PB_DEBUG_MAP_BACKTRACE];
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   struct list_head head;
85bf215546Sopenharmony_ci};
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_cistruct pb_debug_manager
89bf215546Sopenharmony_ci{
90bf215546Sopenharmony_ci   struct pb_manager base;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   struct pb_manager *provider;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   pb_size underflow_size;
95bf215546Sopenharmony_ci   pb_size overflow_size;
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   mtx_t mutex;
98bf215546Sopenharmony_ci   struct list_head list;
99bf215546Sopenharmony_ci};
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_cistatic inline struct pb_debug_buffer *
103bf215546Sopenharmony_cipb_debug_buffer(struct pb_buffer *buf)
104bf215546Sopenharmony_ci{
105bf215546Sopenharmony_ci   assert(buf);
106bf215546Sopenharmony_ci   return (struct pb_debug_buffer *)buf;
107bf215546Sopenharmony_ci}
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_cistatic inline struct pb_debug_manager *
111bf215546Sopenharmony_cipb_debug_manager(struct pb_manager *mgr)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci   assert(mgr);
114bf215546Sopenharmony_ci   return (struct pb_debug_manager *)mgr;
115bf215546Sopenharmony_ci}
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_cistatic const uint8_t random_pattern[32] = {
119bf215546Sopenharmony_ci   0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
120bf215546Sopenharmony_ci   0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
121bf215546Sopenharmony_ci   0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
122bf215546Sopenharmony_ci   0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
123bf215546Sopenharmony_ci};
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_cistatic inline void
127bf215546Sopenharmony_cifill_random_pattern(uint8_t *dst, pb_size size)
128bf215546Sopenharmony_ci{
129bf215546Sopenharmony_ci   pb_size i = 0;
130bf215546Sopenharmony_ci   while(size--) {
131bf215546Sopenharmony_ci      *dst++ = random_pattern[i++];
132bf215546Sopenharmony_ci      i &= sizeof(random_pattern) - 1;
133bf215546Sopenharmony_ci   }
134bf215546Sopenharmony_ci}
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_cistatic inline boolean
138bf215546Sopenharmony_cicheck_random_pattern(const uint8_t *dst, pb_size size,
139bf215546Sopenharmony_ci                     pb_size *min_ofs, pb_size *max_ofs)
140bf215546Sopenharmony_ci{
141bf215546Sopenharmony_ci   boolean result = TRUE;
142bf215546Sopenharmony_ci   pb_size i;
143bf215546Sopenharmony_ci   *min_ofs = size;
144bf215546Sopenharmony_ci   *max_ofs = 0;
145bf215546Sopenharmony_ci   for(i = 0; i < size; ++i) {
146bf215546Sopenharmony_ci      if(*dst++ != random_pattern[i % sizeof(random_pattern)]) {
147bf215546Sopenharmony_ci         *min_ofs = MIN2(*min_ofs, i);
148bf215546Sopenharmony_ci         *max_ofs = MAX2(*max_ofs, i);
149bf215546Sopenharmony_ci	 result = FALSE;
150bf215546Sopenharmony_ci      }
151bf215546Sopenharmony_ci   }
152bf215546Sopenharmony_ci   return result;
153bf215546Sopenharmony_ci}
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_cistatic void
157bf215546Sopenharmony_cipb_debug_buffer_fill(struct pb_debug_buffer *buf)
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci   uint8_t *map;
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   map = pb_map(buf->buffer, PB_USAGE_CPU_WRITE, NULL);
162bf215546Sopenharmony_ci   assert(map);
163bf215546Sopenharmony_ci   if (map) {
164bf215546Sopenharmony_ci      fill_random_pattern(map, buf->underflow_size);
165bf215546Sopenharmony_ci      fill_random_pattern(map + buf->underflow_size + buf->base.size,
166bf215546Sopenharmony_ci                          buf->overflow_size);
167bf215546Sopenharmony_ci      pb_unmap(buf->buffer);
168bf215546Sopenharmony_ci   }
169bf215546Sopenharmony_ci}
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci/**
173bf215546Sopenharmony_ci * Check for under/over flows.
174bf215546Sopenharmony_ci *
175bf215546Sopenharmony_ci * Should be called with the buffer unmaped.
176bf215546Sopenharmony_ci */
177bf215546Sopenharmony_cistatic void
178bf215546Sopenharmony_cipb_debug_buffer_check(struct pb_debug_buffer *buf)
179bf215546Sopenharmony_ci{
180bf215546Sopenharmony_ci   uint8_t *map;
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   map = pb_map(buf->buffer,
183bf215546Sopenharmony_ci                PB_USAGE_CPU_READ |
184bf215546Sopenharmony_ci                PB_USAGE_UNSYNCHRONIZED, NULL);
185bf215546Sopenharmony_ci   assert(map);
186bf215546Sopenharmony_ci   if (map) {
187bf215546Sopenharmony_ci      boolean underflow, overflow;
188bf215546Sopenharmony_ci      pb_size min_ofs, max_ofs;
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci      underflow = !check_random_pattern(map, buf->underflow_size,
191bf215546Sopenharmony_ci                                        &min_ofs, &max_ofs);
192bf215546Sopenharmony_ci      if(underflow) {
193bf215546Sopenharmony_ci         debug_printf("buffer underflow (offset -%"PRIu64"%s to -%"PRIu64" bytes) detected\n",
194bf215546Sopenharmony_ci                      buf->underflow_size - min_ofs,
195bf215546Sopenharmony_ci                      min_ofs == 0 ? "+" : "",
196bf215546Sopenharmony_ci                      buf->underflow_size - max_ofs);
197bf215546Sopenharmony_ci      }
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci      overflow = !check_random_pattern(map + buf->underflow_size + buf->base.size,
200bf215546Sopenharmony_ci                                       buf->overflow_size,
201bf215546Sopenharmony_ci                                       &min_ofs, &max_ofs);
202bf215546Sopenharmony_ci      if(overflow) {
203bf215546Sopenharmony_ci         debug_printf("buffer overflow (size %"PRIu64" plus offset %"PRIu64" to %"PRIu64"%s bytes) detected\n",
204bf215546Sopenharmony_ci                      buf->base.size,
205bf215546Sopenharmony_ci                      min_ofs,
206bf215546Sopenharmony_ci                      max_ofs,
207bf215546Sopenharmony_ci                      max_ofs == buf->overflow_size - 1 ? "+" : "");
208bf215546Sopenharmony_ci      }
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci      if(underflow || overflow)
211bf215546Sopenharmony_ci         debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci      assert(!underflow);
214bf215546Sopenharmony_ci      assert(!overflow);
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci      /* re-fill if not aborted */
217bf215546Sopenharmony_ci      if(underflow)
218bf215546Sopenharmony_ci         fill_random_pattern(map, buf->underflow_size);
219bf215546Sopenharmony_ci      if(overflow)
220bf215546Sopenharmony_ci         fill_random_pattern(map + buf->underflow_size + buf->base.size,
221bf215546Sopenharmony_ci                             buf->overflow_size);
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci      pb_unmap(buf->buffer);
224bf215546Sopenharmony_ci   }
225bf215546Sopenharmony_ci}
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_cistatic void
229bf215546Sopenharmony_cipb_debug_buffer_destroy(void *winsys, struct pb_buffer *_buf)
230bf215546Sopenharmony_ci{
231bf215546Sopenharmony_ci   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
232bf215546Sopenharmony_ci   struct pb_debug_manager *mgr = buf->mgr;
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci   assert(!pipe_is_referenced(&buf->base.reference));
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   pb_debug_buffer_check(buf);
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   mtx_lock(&mgr->mutex);
239bf215546Sopenharmony_ci   list_del(&buf->head);
240bf215546Sopenharmony_ci   mtx_unlock(&mgr->mutex);
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_ci   mtx_destroy(&buf->mutex);
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci   pb_reference(&buf->buffer, NULL);
245bf215546Sopenharmony_ci   FREE(buf);
246bf215546Sopenharmony_ci}
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_cistatic void *
250bf215546Sopenharmony_cipb_debug_buffer_map(struct pb_buffer *_buf,
251bf215546Sopenharmony_ci                    enum pb_usage_flags flags, void *flush_ctx)
252bf215546Sopenharmony_ci{
253bf215546Sopenharmony_ci   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
254bf215546Sopenharmony_ci   void *map;
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   pb_debug_buffer_check(buf);
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci   map = pb_map(buf->buffer, flags, flush_ctx);
259bf215546Sopenharmony_ci   if (!map)
260bf215546Sopenharmony_ci      return NULL;
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci   mtx_lock(&buf->mutex);
263bf215546Sopenharmony_ci   ++buf->map_count;
264bf215546Sopenharmony_ci   debug_backtrace_capture(buf->map_backtrace, 1, PB_DEBUG_MAP_BACKTRACE);
265bf215546Sopenharmony_ci   mtx_unlock(&buf->mutex);
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   return (uint8_t *)map + buf->underflow_size;
268bf215546Sopenharmony_ci}
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_cistatic void
272bf215546Sopenharmony_cipb_debug_buffer_unmap(struct pb_buffer *_buf)
273bf215546Sopenharmony_ci{
274bf215546Sopenharmony_ci   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   mtx_lock(&buf->mutex);
277bf215546Sopenharmony_ci   assert(buf->map_count);
278bf215546Sopenharmony_ci   if(buf->map_count)
279bf215546Sopenharmony_ci      --buf->map_count;
280bf215546Sopenharmony_ci   mtx_unlock(&buf->mutex);
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci   pb_unmap(buf->buffer);
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   pb_debug_buffer_check(buf);
285bf215546Sopenharmony_ci}
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_cistatic void
289bf215546Sopenharmony_cipb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
290bf215546Sopenharmony_ci                                struct pb_buffer **base_buf,
291bf215546Sopenharmony_ci                                pb_size *offset)
292bf215546Sopenharmony_ci{
293bf215546Sopenharmony_ci   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
294bf215546Sopenharmony_ci   pb_get_base_buffer(buf->buffer, base_buf, offset);
295bf215546Sopenharmony_ci   *offset += buf->underflow_size;
296bf215546Sopenharmony_ci}
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_cistatic enum pipe_error
300bf215546Sopenharmony_cipb_debug_buffer_validate(struct pb_buffer *_buf,
301bf215546Sopenharmony_ci                         struct pb_validate *vl,
302bf215546Sopenharmony_ci                         enum pb_usage_flags flags)
303bf215546Sopenharmony_ci{
304bf215546Sopenharmony_ci   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci   assert((flags & ~PB_USAGE_ALL) == 0);
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   mtx_lock(&buf->mutex);
309bf215546Sopenharmony_ci   if(buf->map_count) {
310bf215546Sopenharmony_ci      debug_printf("%s: attempting to validate a mapped buffer\n", __FUNCTION__);
311bf215546Sopenharmony_ci      debug_printf("last map backtrace is\n");
312bf215546Sopenharmony_ci      debug_backtrace_dump(buf->map_backtrace, PB_DEBUG_MAP_BACKTRACE);
313bf215546Sopenharmony_ci   }
314bf215546Sopenharmony_ci   mtx_unlock(&buf->mutex);
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci   pb_debug_buffer_check(buf);
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   return pb_validate(buf->buffer, vl, flags);
319bf215546Sopenharmony_ci}
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_cistatic void
323bf215546Sopenharmony_cipb_debug_buffer_fence(struct pb_buffer *_buf,
324bf215546Sopenharmony_ci                      struct pipe_fence_handle *fence)
325bf215546Sopenharmony_ci{
326bf215546Sopenharmony_ci   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
327bf215546Sopenharmony_ci   pb_fence(buf->buffer, fence);
328bf215546Sopenharmony_ci}
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ciconst struct pb_vtbl
332bf215546Sopenharmony_cipb_debug_buffer_vtbl = {
333bf215546Sopenharmony_ci      pb_debug_buffer_destroy,
334bf215546Sopenharmony_ci      pb_debug_buffer_map,
335bf215546Sopenharmony_ci      pb_debug_buffer_unmap,
336bf215546Sopenharmony_ci      pb_debug_buffer_validate,
337bf215546Sopenharmony_ci      pb_debug_buffer_fence,
338bf215546Sopenharmony_ci      pb_debug_buffer_get_base_buffer
339bf215546Sopenharmony_ci};
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_cistatic void
343bf215546Sopenharmony_cipb_debug_manager_dump_locked(struct pb_debug_manager *mgr)
344bf215546Sopenharmony_ci{
345bf215546Sopenharmony_ci   struct list_head *curr, *next;
346bf215546Sopenharmony_ci   struct pb_debug_buffer *buf;
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   curr = mgr->list.next;
349bf215546Sopenharmony_ci   next = curr->next;
350bf215546Sopenharmony_ci   while(curr != &mgr->list) {
351bf215546Sopenharmony_ci      buf = list_entry(curr, struct pb_debug_buffer, head);
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci      debug_printf("buffer = %p\n", (void *) buf);
354bf215546Sopenharmony_ci      debug_printf("    .size = 0x%"PRIx64"\n", buf->base.size);
355bf215546Sopenharmony_ci      debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci      curr = next;
358bf215546Sopenharmony_ci      next = curr->next;
359bf215546Sopenharmony_ci   }
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci}
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_cistatic struct pb_buffer *
365bf215546Sopenharmony_cipb_debug_manager_create_buffer(struct pb_manager *_mgr,
366bf215546Sopenharmony_ci                               pb_size size,
367bf215546Sopenharmony_ci                               const struct pb_desc *desc)
368bf215546Sopenharmony_ci{
369bf215546Sopenharmony_ci   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
370bf215546Sopenharmony_ci   struct pb_debug_buffer *buf;
371bf215546Sopenharmony_ci   struct pb_desc real_desc;
372bf215546Sopenharmony_ci   pb_size real_size;
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci   assert(size);
375bf215546Sopenharmony_ci   assert(desc->alignment);
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   buf = CALLOC_STRUCT(pb_debug_buffer);
378bf215546Sopenharmony_ci   if (!buf)
379bf215546Sopenharmony_ci      return NULL;
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci   real_size = mgr->underflow_size + size + mgr->overflow_size;
382bf215546Sopenharmony_ci   real_desc = *desc;
383bf215546Sopenharmony_ci   real_desc.usage |= PB_USAGE_CPU_WRITE;
384bf215546Sopenharmony_ci   real_desc.usage |= PB_USAGE_CPU_READ;
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   buf->buffer = mgr->provider->create_buffer(mgr->provider,
387bf215546Sopenharmony_ci                                              real_size,
388bf215546Sopenharmony_ci                                              &real_desc);
389bf215546Sopenharmony_ci   if(!buf->buffer) {
390bf215546Sopenharmony_ci      FREE(buf);
391bf215546Sopenharmony_ci#if 0
392bf215546Sopenharmony_ci      mtx_lock(&mgr->mutex);
393bf215546Sopenharmony_ci      debug_printf("%s: failed to create buffer\n", __FUNCTION__);
394bf215546Sopenharmony_ci      if(!list_is_empty(&mgr->list))
395bf215546Sopenharmony_ci         pb_debug_manager_dump_locked(mgr);
396bf215546Sopenharmony_ci      mtx_unlock(&mgr->mutex);
397bf215546Sopenharmony_ci#endif
398bf215546Sopenharmony_ci      return NULL;
399bf215546Sopenharmony_ci   }
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci   assert(pipe_is_referenced(&buf->buffer->reference));
402bf215546Sopenharmony_ci   assert(pb_check_alignment(real_desc.alignment, 1u << buf->buffer->alignment_log2));
403bf215546Sopenharmony_ci   assert(pb_check_usage(real_desc.usage, buf->buffer->usage));
404bf215546Sopenharmony_ci   assert(buf->buffer->size >= real_size);
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_ci   pipe_reference_init(&buf->base.reference, 1);
407bf215546Sopenharmony_ci   buf->base.alignment_log2 = util_logbase2(desc->alignment);
408bf215546Sopenharmony_ci   buf->base.usage = desc->usage;
409bf215546Sopenharmony_ci   buf->base.size = size;
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   buf->base.vtbl = &pb_debug_buffer_vtbl;
412bf215546Sopenharmony_ci   buf->mgr = mgr;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   buf->underflow_size = mgr->underflow_size;
415bf215546Sopenharmony_ci   buf->overflow_size = buf->buffer->size - buf->underflow_size - size;
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_ci   debug_backtrace_capture(buf->create_backtrace, 1, PB_DEBUG_CREATE_BACKTRACE);
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci   pb_debug_buffer_fill(buf);
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci   (void) mtx_init(&buf->mutex, mtx_plain);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   mtx_lock(&mgr->mutex);
424bf215546Sopenharmony_ci   list_addtail(&buf->head, &mgr->list);
425bf215546Sopenharmony_ci   mtx_unlock(&mgr->mutex);
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   return &buf->base;
428bf215546Sopenharmony_ci}
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_cistatic void
432bf215546Sopenharmony_cipb_debug_manager_flush(struct pb_manager *_mgr)
433bf215546Sopenharmony_ci{
434bf215546Sopenharmony_ci   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
435bf215546Sopenharmony_ci   assert(mgr->provider->flush);
436bf215546Sopenharmony_ci   if(mgr->provider->flush)
437bf215546Sopenharmony_ci      mgr->provider->flush(mgr->provider);
438bf215546Sopenharmony_ci}
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_cistatic void
442bf215546Sopenharmony_cipb_debug_manager_destroy(struct pb_manager *_mgr)
443bf215546Sopenharmony_ci{
444bf215546Sopenharmony_ci   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   mtx_lock(&mgr->mutex);
447bf215546Sopenharmony_ci   if(!list_is_empty(&mgr->list)) {
448bf215546Sopenharmony_ci      debug_printf("%s: unfreed buffers\n", __FUNCTION__);
449bf215546Sopenharmony_ci      pb_debug_manager_dump_locked(mgr);
450bf215546Sopenharmony_ci   }
451bf215546Sopenharmony_ci   mtx_unlock(&mgr->mutex);
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   mtx_destroy(&mgr->mutex);
454bf215546Sopenharmony_ci   mgr->provider->destroy(mgr->provider);
455bf215546Sopenharmony_ci   FREE(mgr);
456bf215546Sopenharmony_ci}
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_cistruct pb_manager *
460bf215546Sopenharmony_cipb_debug_manager_create(struct pb_manager *provider,
461bf215546Sopenharmony_ci                        pb_size underflow_size, pb_size overflow_size)
462bf215546Sopenharmony_ci{
463bf215546Sopenharmony_ci   struct pb_debug_manager *mgr;
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   if (!provider)
466bf215546Sopenharmony_ci      return NULL;
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   mgr = CALLOC_STRUCT(pb_debug_manager);
469bf215546Sopenharmony_ci   if (!mgr)
470bf215546Sopenharmony_ci      return NULL;
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci   mgr->base.destroy = pb_debug_manager_destroy;
473bf215546Sopenharmony_ci   mgr->base.create_buffer = pb_debug_manager_create_buffer;
474bf215546Sopenharmony_ci   mgr->base.flush = pb_debug_manager_flush;
475bf215546Sopenharmony_ci   mgr->provider = provider;
476bf215546Sopenharmony_ci   mgr->underflow_size = underflow_size;
477bf215546Sopenharmony_ci   mgr->overflow_size = overflow_size;
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   (void) mtx_init(&mgr->mutex, mtx_plain);
480bf215546Sopenharmony_ci   list_inithead(&mgr->list);
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci   return &mgr->base;
483bf215546Sopenharmony_ci}
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci#else /* !DEBUG */
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci
489bf215546Sopenharmony_cistruct pb_manager *
490bf215546Sopenharmony_cipb_debug_manager_create(struct pb_manager *provider,
491bf215546Sopenharmony_ci                        pb_size underflow_size, pb_size overflow_size)
492bf215546Sopenharmony_ci{
493bf215546Sopenharmony_ci   return provider;
494bf215546Sopenharmony_ci}
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci#endif /* !DEBUG */
498