VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgmodcontainer.cpp@ 103250

Last change on this file since 103250 was 100931, checked in by vboxsync, 16 months ago

IPRT/dbg: Early PDB support.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.8 KB
Line 
1/* $Id: dbgmodcontainer.cpp 100931 2023-08-21 23:11:01Z vboxsync $ */
2/** @file
3 * IPRT - Debug Info Container.
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_DBG
42#include <iprt/dbg.h>
43#include "internal/iprt.h"
44
45#include <iprt/avl.h>
46#include <iprt/err.h>
47#include <iprt/log.h>
48#include <iprt/mem.h>
49#define RTDBGMODCNT_WITH_MEM_CACHE
50#ifdef RTDBGMODCNT_WITH_MEM_CACHE
51# include <iprt/memcache.h>
52#endif
53#include <iprt/string.h>
54#include <iprt/strcache.h>
55#include "internal/dbgmod.h"
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61/**
62 * Symbol entry.
63 */
64typedef struct RTDBGMODCTNSYMBOL
65{
66 /** The address core. */
67 AVLRUINTPTRNODECORE AddrCore;
68 /** The name space core. */
69 RTSTRSPACECORE NameCore;
70 /** The ordinal number core. */
71 AVLU32NODECORE OrdinalCore;
72 /** The segment index. */
73 RTDBGSEGIDX iSeg;
74 /** The symbol flags. */
75 uint32_t fFlags;
76 /** The symbol size.
77 * This may be zero while the range in AddrCore indicates 0. */
78 RTUINTPTR cb;
79} RTDBGMODCTNSYMBOL;
80/** Pointer to a symbol entry in the debug info container. */
81typedef RTDBGMODCTNSYMBOL *PRTDBGMODCTNSYMBOL;
82/** Pointer to a const symbol entry in the debug info container. */
83typedef RTDBGMODCTNSYMBOL const *PCRTDBGMODCTNSYMBOL;
84
85/**
86 * Line number entry.
87 */
88typedef struct RTDBGMODCTNLINE
89{
90 /** The address core.
91 * The Key is the address of the line number. */
92 AVLUINTPTRNODECORE AddrCore;
93 /** The ordinal number core. */
94 AVLU32NODECORE OrdinalCore;
95 /** Pointer to the file name (in string cache). */
96 const char *pszFile;
97 /** The line number. */
98 uint32_t uLineNo;
99 /** The segment index. */
100 RTDBGSEGIDX iSeg;
101} RTDBGMODCTNLINE;
102/** Pointer to a line number entry. */
103typedef RTDBGMODCTNLINE *PRTDBGMODCTNLINE;
104/** Pointer to const a line number entry. */
105typedef RTDBGMODCTNLINE const *PCRTDBGMODCTNLINE;
106
107/**
108 * Segment entry.
109 */
110typedef struct RTDBGMODCTNSEGMENT
111{
112 /** The symbol address space tree. */
113 AVLRUINTPTRTREE SymAddrTree;
114 /** The line number address space tree. */
115 AVLUINTPTRTREE LineAddrTree;
116 /** The segment offset. */
117 RTUINTPTR off;
118 /** The segment size. */
119 RTUINTPTR cb;
120 /** The segment flags. */
121 uint32_t fFlags;
122 /** The segment name. */
123 const char *pszName;
124} RTDBGMODCTNSEGMENT;
125/** Pointer to a segment entry in the debug info container. */
126typedef RTDBGMODCTNSEGMENT *PRTDBGMODCTNSEGMENT;
127/** Pointer to a const segment entry in the debug info container. */
128typedef RTDBGMODCTNSEGMENT const *PCRTDBGMODCTNSEGMENT;
129
130/**
131 * Instance data.
132 */
133typedef struct RTDBGMODCTN
134{
135 /** The name space. */
136 RTSTRSPACE Names;
137 /** Tree containing any absolute addresses. */
138 AVLRUINTPTRTREE AbsAddrTree;
139 /** Tree organizing the symbols by ordinal number. */
140 AVLU32TREE SymbolOrdinalTree;
141 /** Tree organizing the line numbers by ordinal number. */
142 AVLU32TREE LineOrdinalTree;
143 /** Segment table. */
144 PRTDBGMODCTNSEGMENT paSegs;
145 /** The number of segments in the segment table. */
146 RTDBGSEGIDX cSegs;
147 /** The image size. 0 means unlimited. */
148 RTUINTPTR cb;
149 /** The next symbol ordinal. */
150 uint32_t iNextSymbolOrdinal;
151 /** The next line number ordinal. */
152 uint32_t iNextLineOrdinal;
153#ifdef RTDBGMODCNT_WITH_MEM_CACHE
154 /** Line number allocator.
155 * Using a cache is a bit overkill since we normally won't free them, but
156 * it's a construct that exists and does the job relatively efficiently. */
157 RTMEMCACHE hLineNumAllocator;
158#endif
159} RTDBGMODCTN;
160/** Pointer to instance data for the debug info container. */
161typedef RTDBGMODCTN *PRTDBGMODCTN;
162
163
164
165/** @interface_method_impl{RTDBGMODVTDBG,pfnUnwindFrame} */
166static DECLCALLBACK(int)
167rtDbgModContainer_UnwindFrame(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTDBGUNWINDSTATE pState)
168{
169 RT_NOREF(pMod, iSeg, off, pState);
170 return VERR_DBG_NO_UNWIND_INFO;
171}
172
173
174/**
175 * Fills in a RTDBGSYMBOL structure.
176 *
177 * @returns VINF_SUCCESS.
178 * @param pMySym Our internal symbol representation.
179 * @param pExtSym The external symbol representation.
180 */
181DECLINLINE(int) rtDbgModContainerReturnSymbol(PCRTDBGMODCTNSYMBOL pMySym, PRTDBGSYMBOL pExtSym)
182{
183 pExtSym->Value = pMySym->AddrCore.Key;
184 pExtSym->offSeg = pMySym->AddrCore.Key;
185 pExtSym->iSeg = pMySym->iSeg;
186 pExtSym->fFlags = pMySym->fFlags;
187 pExtSym->cb = pMySym->cb;
188 pExtSym->iOrdinal = pMySym->OrdinalCore.Key;
189 Assert(pMySym->NameCore.cchString < sizeof(pExtSym->szName));
190 memcpy(pExtSym->szName, pMySym->NameCore.pszString, pMySym->NameCore.cchString + 1);
191 return VINF_SUCCESS;
192}
193
194
195
196/** @copydoc RTDBGMODVTDBG::pfnLineByAddr */
197static DECLCALLBACK(int) rtDbgModContainer_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
198 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
199{
200 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
201
202 /*
203 * Validate the input address.
204 */
205 AssertMsgReturn(iSeg < pThis->cSegs,
206 ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
207 VERR_DBG_INVALID_SEGMENT_INDEX);
208 AssertMsgReturn(off < pThis->paSegs[iSeg].cb,
209 ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
210 VERR_DBG_INVALID_SEGMENT_OFFSET);
211
212 /*
213 * Lookup the nearest line number with an address less or equal to the specified address.
214 */
215 PAVLUINTPTRNODECORE pAvlCore = RTAvlUIntPtrGetBestFit(&pThis->paSegs[iSeg].LineAddrTree, off, false /*fAbove*/);
216 if (!pAvlCore)
217 return pThis->iNextLineOrdinal
218 ? VERR_DBG_LINE_NOT_FOUND
219 : VERR_DBG_NO_LINE_NUMBERS;
220 PCRTDBGMODCTNLINE pMyLine = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNLINE const, AddrCore);
221 pLineInfo->Address = pMyLine->AddrCore.Key;
222 pLineInfo->offSeg = pMyLine->AddrCore.Key;
223 pLineInfo->iSeg = iSeg;
224 pLineInfo->uLineNo = pMyLine->uLineNo;
225 pLineInfo->iOrdinal = pMyLine->OrdinalCore.Key;
226 strcpy(pLineInfo->szFilename, pMyLine->pszFile);
227 if (poffDisp)
228 *poffDisp = off - pMyLine->AddrCore.Key;
229 return VINF_SUCCESS;
230}
231
232
233/** @copydoc RTDBGMODVTDBG::pfnLineByOrdinal */
234static DECLCALLBACK(int) rtDbgModContainer_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
235{
236 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
237
238 /*
239 * Look it up.
240 */
241 if (iOrdinal >= pThis->iNextLineOrdinal)
242 return pThis->iNextLineOrdinal
243 ? VERR_DBG_LINE_NOT_FOUND
244 : VERR_DBG_NO_LINE_NUMBERS;
245 PAVLU32NODECORE pAvlCore = RTAvlU32Get(&pThis->LineOrdinalTree, iOrdinal);
246 AssertReturn(pAvlCore, VERR_DBG_LINE_NOT_FOUND);
247 PCRTDBGMODCTNLINE pMyLine = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNLINE const, OrdinalCore);
248 pLineInfo->Address = pMyLine->AddrCore.Key;
249 pLineInfo->offSeg = pMyLine->AddrCore.Key;
250 pLineInfo->iSeg = pMyLine->iSeg;
251 pLineInfo->uLineNo = pMyLine->uLineNo;
252 pLineInfo->iOrdinal = pMyLine->OrdinalCore.Key;
253 strcpy(pLineInfo->szFilename, pMyLine->pszFile);
254 return VINF_SUCCESS;
255}
256
257
258/** @copydoc RTDBGMODVTDBG::pfnLineCount */
259static DECLCALLBACK(uint32_t) rtDbgModContainer_LineCount(PRTDBGMODINT pMod)
260{
261 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
262
263 /* Note! The ordinal numbers are 0-based. */
264 return pThis->iNextLineOrdinal;
265}
266
267
268/** @copydoc RTDBGMODVTDBG::pfnLineAdd */
269static DECLCALLBACK(int) rtDbgModContainer_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
270 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
271{
272 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
273
274 /*
275 * Validate the input address.
276 */
277 AssertMsgReturn(iSeg < pThis->cSegs, ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
278 VERR_DBG_INVALID_SEGMENT_INDEX);
279 AssertMsgReturn(off <= pThis->paSegs[iSeg].cb, ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
280 VERR_DBG_INVALID_SEGMENT_OFFSET);
281
282 /*
283 * Create a new entry.
284 */
285#ifdef RTDBGMODCNT_WITH_MEM_CACHE
286 PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemCacheAlloc(pThis->hLineNumAllocator);
287#else
288 PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemAllocZ(sizeof(*pLine));
289#endif
290 if (!pLine)
291 return VERR_NO_MEMORY;
292 pLine->AddrCore.Key = off;
293 pLine->OrdinalCore.Key = pThis->iNextLineOrdinal;
294 pLine->uLineNo = uLineNo;
295 pLine->iSeg = iSeg;
296 pLine->pszFile = RTStrCacheEnterN(g_hDbgModStrCache, pszFile, cchFile);
297 int rc;
298 if (pLine->pszFile)
299 {
300 if (RTAvlUIntPtrInsert(&pThis->paSegs[iSeg].LineAddrTree, &pLine->AddrCore))
301 {
302 if (RTAvlU32Insert(&pThis->LineOrdinalTree, &pLine->OrdinalCore))
303 {
304 if (piOrdinal)
305 *piOrdinal = pThis->iNextLineOrdinal;
306 pThis->iNextLineOrdinal++;
307 return VINF_SUCCESS;
308 }
309
310 rc = VERR_INTERNAL_ERROR_5;
311 RTAvlUIntPtrRemove(&pThis->paSegs[iSeg].LineAddrTree, pLine->AddrCore.Key);
312 }
313
314 /* bail out */
315 rc = VERR_DBG_ADDRESS_CONFLICT;
316 RTStrCacheRelease(g_hDbgModStrCache, pLine->pszFile);
317 }
318 else
319 rc = VERR_NO_MEMORY;
320#ifdef RTDBGMODCNT_WITH_MEM_CACHE
321 RTMemCacheFree(pThis->hLineNumAllocator, pLine);
322#else
323 RTMemFree(pLine);
324#endif
325 return rc;
326}
327
328
329/** @copydoc RTDBGMODVTDBG::pfnSymbolByAddr */
330static DECLCALLBACK(int) rtDbgModContainer_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
331 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
332{
333 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
334
335 /*
336 * Validate the input address.
337 */
338 AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS
339 || iSeg < pThis->cSegs,
340 ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
341 VERR_DBG_INVALID_SEGMENT_INDEX);
342 AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
343 || off <= pThis->paSegs[iSeg].cb,
344 ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
345 VERR_DBG_INVALID_SEGMENT_OFFSET);
346
347 /*
348 * Lookup the nearest symbol with an address less or equal to the specified address.
349 */
350 PAVLRUINTPTRNODECORE pAvlCore = RTAvlrUIntPtrGetBestFit( iSeg == RTDBGSEGIDX_ABS
351 ? &pThis->AbsAddrTree
352 : &pThis->paSegs[iSeg].SymAddrTree,
353 off,
354 fFlags == RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL /*fAbove*/);
355 if (!pAvlCore)
356 return VERR_SYMBOL_NOT_FOUND;
357 PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNSYMBOL const, AddrCore);
358 if (poffDisp)
359 *poffDisp = off - pMySym->AddrCore.Key;
360 return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
361}
362
363
364/** @copydoc RTDBGMODVTDBG::pfnSymbolByName */
365static DECLCALLBACK(int) rtDbgModContainer_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol, PRTDBGSYMBOL pSymInfo)
366{
367 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
368 NOREF(cchSymbol);
369
370 /*
371 * Look it up in the name space.
372 */
373 PRTSTRSPACECORE pStrCore = RTStrSpaceGet(&pThis->Names, pszSymbol);
374 if (!pStrCore)
375 return VERR_SYMBOL_NOT_FOUND;
376 PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pStrCore, RTDBGMODCTNSYMBOL const, NameCore);
377 return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
378}
379
380
381/** @copydoc RTDBGMODVTDBG::pfnSymbolByOrdinal */
382static DECLCALLBACK(int) rtDbgModContainer_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
383{
384 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
385
386 /*
387 * Look it up in the ordinal tree.
388 */
389 if (iOrdinal >= pThis->iNextSymbolOrdinal)
390 return pThis->iNextSymbolOrdinal
391 ? VERR_DBG_NO_SYMBOLS
392 : VERR_SYMBOL_NOT_FOUND;
393 PAVLU32NODECORE pAvlCore = RTAvlU32Get(&pThis->SymbolOrdinalTree, iOrdinal);
394 AssertReturn(pAvlCore, VERR_SYMBOL_NOT_FOUND);
395 PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNSYMBOL const, OrdinalCore);
396 return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
397}
398
399
400/** @copydoc RTDBGMODVTDBG::pfnSymbolCount */
401static DECLCALLBACK(uint32_t) rtDbgModContainer_SymbolCount(PRTDBGMODINT pMod)
402{
403 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
404
405 /* Note! The ordinal numbers are 0-based. */
406 return pThis->iNextSymbolOrdinal;
407}
408
409
410/**
411 * Worker for rtDbgModContainer_SymbolAdd that removes a symbol to resolve
412 * address conflicts.
413 *
414 * We don't shift ordinals up as that could be very expensive, instead we move
415 * the last one up to take the place of the one we're removing. Caller must
416 * take this into account.
417 *
418 * @param pThis The container.
419 * @param pAddrTree The address tree to remove from.
420 * @param pToRemove The conflicting symbol to be removed.
421 */
422static void rtDbgModContainer_SymbolReplace(PRTDBGMODCTN pThis, PAVLRUINTPTRTREE pAddrTree, PRTDBGMODCTNSYMBOL pToRemove)
423{
424 Log(("rtDbgModContainer_SymbolReplace: pToRemove=%p ordinal=%u %04x:%08RX64 %s\n",
425 pToRemove, pToRemove->OrdinalCore.Key, pToRemove->iSeg, pToRemove->AddrCore.Key, pToRemove->NameCore.pszString));
426
427 /* Unlink it. */
428 PRTSTRSPACECORE pRemovedName = RTStrSpaceRemove(&pThis->Names, pToRemove->NameCore.pszString);
429 Assert(pRemovedName); RT_NOREF_PV(pRemovedName);
430 pToRemove->NameCore.pszString = NULL;
431
432 PAVLRUINTPTRNODECORE pRemovedAddr = RTAvlrUIntPtrRemove(pAddrTree, pToRemove->AddrCore.Key);
433 Assert(pRemovedAddr); RT_NOREF_PV(pRemovedAddr);
434 pToRemove->AddrCore.Key = 0;
435 pToRemove->AddrCore.KeyLast = 0;
436
437 uint32_t const iOrdinal = pToRemove->OrdinalCore.Key;
438 PAVLU32NODECORE pRemovedOrdinal = RTAvlU32Remove(&pThis->SymbolOrdinalTree, iOrdinal);
439 Assert(pRemovedOrdinal); RT_NOREF_PV(pRemovedOrdinal);
440
441 RTMemFree(pToRemove);
442
443 /* Jump the last symbol ordinal to take its place, unless pToRemove is the last one. */
444 if (iOrdinal >= pThis->iNextSymbolOrdinal - 1)
445 pThis->iNextSymbolOrdinal -= 1;
446 else
447 {
448 PAVLU32NODECORE pLastOrdinal = RTAvlU32Remove(&pThis->SymbolOrdinalTree, pThis->iNextSymbolOrdinal - 1);
449 AssertReturnVoid(pLastOrdinal);
450
451 pThis->iNextSymbolOrdinal -= 1;
452 pLastOrdinal->Key = iOrdinal;
453 bool fInsert = RTAvlU32Insert(&pThis->SymbolOrdinalTree, pLastOrdinal);
454 Assert(fInsert); RT_NOREF_PV(fInsert);
455 }
456}
457
458
459/** @copydoc RTDBGMODVTDBG::pfnSymbolAdd */
460static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
461 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
462 uint32_t *piOrdinal)
463{
464 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
465
466 /*
467 * Address validation. The other arguments have already been validated.
468 */
469 AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS
470 || iSeg < pThis->cSegs,
471 ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
472 VERR_DBG_INVALID_SEGMENT_INDEX);
473 AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
474 || off <= pThis->paSegs[iSeg].cb,
475 ("off=%RTptr cb=%RTptr cbSeg=%RTptr\n", off, cb, pThis->paSegs[iSeg].cb),
476 VERR_DBG_INVALID_SEGMENT_OFFSET);
477
478 /* Be a little relaxed wrt to the symbol size. */
479 int rc = VINF_SUCCESS;
480 if (iSeg != RTDBGSEGIDX_ABS && off + cb > pThis->paSegs[iSeg].cb)
481 {
482 cb = pThis->paSegs[iSeg].cb - off;
483 rc = VINF_DBG_ADJUSTED_SYM_SIZE;
484 }
485
486 /*
487 * Create a new entry.
488 */
489 PRTDBGMODCTNSYMBOL pSymbol = (PRTDBGMODCTNSYMBOL)RTMemAllocZ(sizeof(*pSymbol));
490 if (!pSymbol)
491 return VERR_NO_MEMORY;
492
493 pSymbol->AddrCore.Key = off;
494 pSymbol->AddrCore.KeyLast = off + (cb ? cb - 1 : 0);
495 pSymbol->OrdinalCore.Key = pThis->iNextSymbolOrdinal;
496 pSymbol->iSeg = iSeg;
497 pSymbol->cb = cb;
498 pSymbol->fFlags = fFlags;
499 pSymbol->NameCore.pszString = RTStrCacheEnterN(g_hDbgModStrCache, pszSymbol, cchSymbol);
500 if (pSymbol->NameCore.pszString)
501 {
502 if (RTStrSpaceInsert(&pThis->Names, &pSymbol->NameCore))
503 {
504 PAVLRUINTPTRTREE pAddrTree = iSeg == RTDBGSEGIDX_ABS
505 ? &pThis->AbsAddrTree
506 : &pThis->paSegs[iSeg].SymAddrTree;
507 if (RTAvlrUIntPtrInsert(pAddrTree, &pSymbol->AddrCore))
508 {
509 if (RTAvlU32Insert(&pThis->SymbolOrdinalTree, &pSymbol->OrdinalCore))
510 {
511 /*
512 * Success.
513 */
514 if (piOrdinal)
515 *piOrdinal = pThis->iNextSymbolOrdinal;
516 Log12(("rtDbgModContainer_SymbolAdd: ordinal=%u %04x:%08RX64 LB %#RX64 %s\n",
517 pThis->iNextSymbolOrdinal, iSeg, off, cb, pSymbol->NameCore.pszString));
518 pThis->iNextSymbolOrdinal++;
519 return rc;
520 }
521
522 /* bail out */
523 rc = VERR_INTERNAL_ERROR_5;
524 RTAvlrUIntPtrRemove(pAddrTree, pSymbol->AddrCore.Key);
525 }
526 /*
527 * Did the caller specify a conflict resolution method?
528 */
529 else if (fFlags & ( RTDBGSYMBOLADD_F_REPLACE_SAME_ADDR
530 | RTDBGSYMBOLADD_F_REPLACE_ANY
531 | RTDBGSYMBOLADD_F_ADJUST_SIZES_ON_CONFLICT))
532 {
533 /*
534 * Handle anything at or before the start address first:
535 */
536 AssertCompileMemberOffset(RTDBGMODCTNSYMBOL, AddrCore, 0);
537 PRTDBGMODCTNSYMBOL pConflict = (PRTDBGMODCTNSYMBOL)RTAvlrUIntPtrRangeGet(pAddrTree, pSymbol->AddrCore.Key);
538 if (pConflict)
539 {
540 if (pConflict->AddrCore.Key == pSymbol->AddrCore.Key)
541 {
542 /* Same address, only option is replacing it. */
543 if (fFlags & (RTDBGSYMBOLADD_F_REPLACE_SAME_ADDR | RTDBGSYMBOLADD_F_REPLACE_ANY))
544 rtDbgModContainer_SymbolReplace(pThis, pAddrTree, pConflict);
545 else
546 rc = VERR_DBG_ADDRESS_CONFLICT;
547 }
548 else if (fFlags & RTDBGSYMBOLADD_F_ADJUST_SIZES_ON_CONFLICT)
549 {
550 /* Reduce the size of the symbol before us, adopting the size if we've got none. */
551 Assert(pConflict->AddrCore.Key < pSymbol->AddrCore.Key);
552 if (!pSymbol->cb)
553 {
554 pSymbol->AddrCore.KeyLast = pSymbol->AddrCore.KeyLast;
555 pSymbol->cb = pSymbol->AddrCore.KeyLast - pConflict->AddrCore.Key + 1;
556 rc = VINF_DBG_ADJUSTED_SYM_SIZE;
557 }
558 pConflict->AddrCore.KeyLast = pSymbol->AddrCore.Key - 1;
559 pConflict->cb = pSymbol->AddrCore.Key - pConflict->AddrCore.Key;
560 }
561 else if (fFlags & RTDBGSYMBOLADD_F_REPLACE_ANY)
562 rtDbgModContainer_SymbolReplace(pThis, pAddrTree, pConflict);
563 else
564 rc = VERR_DBG_ADDRESS_CONFLICT;
565 }
566
567 /*
568 * Try insert again and deal with symbols in the range.
569 */
570 while (RT_SUCCESS(rc))
571 {
572 if (RTAvlrUIntPtrInsert(pAddrTree, &pSymbol->AddrCore))
573 {
574 pSymbol->OrdinalCore.Key = pThis->iNextSymbolOrdinal;
575 if (RTAvlU32Insert(&pThis->SymbolOrdinalTree, &pSymbol->OrdinalCore))
576 {
577 /*
578 * Success.
579 */
580 if (piOrdinal)
581 *piOrdinal = pThis->iNextSymbolOrdinal;
582 pThis->iNextSymbolOrdinal++;
583 Log12(("rtDbgModContainer_SymbolAdd: ordinal=%u %04x:%08RX64 LB %#RX64 %s [replace codepath]\n",
584 pThis->iNextSymbolOrdinal, iSeg, off, cb, pSymbol->NameCore.pszString));
585 return rc;
586 }
587
588 rc = VERR_INTERNAL_ERROR_5;
589 RTAvlrUIntPtrRemove(pAddrTree, pSymbol->AddrCore.Key);
590 break;
591 }
592
593 /* Get the first symbol above us and see if we can do anything about it (or ourselves). */
594 AssertCompileMemberOffset(RTDBGMODCTNSYMBOL, AddrCore, 0);
595 pConflict = (PRTDBGMODCTNSYMBOL)RTAvlrUIntPtrGetBestFit(pAddrTree, pSymbol->AddrCore.Key, true /*fAbove*/);
596 AssertBreakStmt(pConflict, rc = VERR_DBG_ADDRESS_CONFLICT);
597 Assert(pSymbol->AddrCore.Key != pConflict->AddrCore.Key);
598 Assert(pSymbol->AddrCore.KeyLast >= pConflict->AddrCore.Key);
599
600 if (fFlags & RTDBGSYMBOLADD_F_ADJUST_SIZES_ON_CONFLICT)
601 {
602 Assert(pSymbol->cb > 0);
603 pSymbol->AddrCore.Key = pConflict->AddrCore.Key - 1;
604 pSymbol->cb = pConflict->AddrCore.Key - pSymbol->AddrCore.Key;
605 rc = VINF_DBG_ADJUSTED_SYM_SIZE;
606 }
607 else if (fFlags & RTDBGSYMBOLADD_F_REPLACE_ANY)
608 rtDbgModContainer_SymbolReplace(pThis, pAddrTree, pConflict);
609 else
610 rc = VERR_DBG_ADDRESS_CONFLICT;
611 }
612 }
613 else
614 rc = VERR_DBG_ADDRESS_CONFLICT;
615 RTStrSpaceRemove(&pThis->Names, pSymbol->NameCore.pszString);
616 }
617 else
618 rc = VERR_DBG_DUPLICATE_SYMBOL;
619 RTStrCacheRelease(g_hDbgModStrCache, pSymbol->NameCore.pszString);
620 }
621 else
622 rc = VERR_NO_MEMORY;
623 RTMemFree(pSymbol);
624 return rc;
625}
626
627
628/** @copydoc RTDBGMODVTDBG::pfnSegmentByIndex */
629static DECLCALLBACK(int) rtDbgModContainer_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
630{
631 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
632 if (iSeg >= pThis->cSegs)
633 return VERR_DBG_INVALID_SEGMENT_INDEX;
634 pSegInfo->Address = RTUINTPTR_MAX;
635 pSegInfo->uRva = pThis->paSegs[iSeg].off;
636 pSegInfo->cb = pThis->paSegs[iSeg].cb;
637 pSegInfo->fFlags = pThis->paSegs[iSeg].fFlags;
638 pSegInfo->iSeg = iSeg;
639 strcpy(pSegInfo->szName, pThis->paSegs[iSeg].pszName);
640 return VINF_SUCCESS;
641}
642
643
644/** @copydoc RTDBGMODVTDBG::pfnSegmentCount */
645static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_SegmentCount(PRTDBGMODINT pMod)
646{
647 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
648 return pThis->cSegs;
649}
650
651
652/** @copydoc RTDBGMODVTDBG::pfnSegmentAdd */
653static DECLCALLBACK(int) rtDbgModContainer_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
654 uint32_t fFlags, PRTDBGSEGIDX piSeg)
655{
656 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
657
658 /*
659 * Input validation (the bits the caller cannot do).
660 */
661 /* Overlapping segments are not yet supported. Will use flags to deal with it if it becomes necessary. */
662 RTUINTPTR uRvaLast = uRva + RT_MAX(cb, 1) - 1;
663 RTUINTPTR uRvaLastMax = uRvaLast;
664 RTDBGSEGIDX iSeg = pThis->cSegs;
665 while (iSeg-- > 0)
666 {
667 RTUINTPTR uCurRva = pThis->paSegs[iSeg].off;
668 RTUINTPTR uCurRvaLast = uCurRva + RT_MAX(pThis->paSegs[iSeg].cb, 1) - 1;
669 if ( uRva <= uCurRvaLast
670 && uRvaLast >= uCurRva
671 && ( /* HACK ALERT! Allow empty segments to share space (bios/watcom, elf). */
672 (cb != 0 && pThis->paSegs[iSeg].cb != 0)
673 || ( cb == 0
674 && uRva != uCurRva
675 && uRva != uCurRvaLast)
676 || ( pThis->paSegs[iSeg].cb == 0
677 && uCurRva != uRva
678 && uCurRva != uRvaLast)
679 )
680 )
681 AssertMsgFailedReturn(("uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\";\n"
682 "uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\" iSeg=%#x\n",
683 uRva, uRvaLast, cb, pszName,
684 uCurRva, uCurRvaLast, pThis->paSegs[iSeg].cb, pThis->paSegs[iSeg].pszName, iSeg),
685 VERR_DBG_SEGMENT_INDEX_CONFLICT);
686 if (uRvaLastMax < uCurRvaLast)
687 uRvaLastMax = uCurRvaLast;
688 }
689 /* Strict ordered segment addition at the moment. */
690 iSeg = pThis->cSegs;
691 AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg == iSeg,
692 ("iSeg=%#x *piSeg=%#x\n", iSeg, *piSeg),
693 VERR_DBG_INVALID_SEGMENT_INDEX);
694
695 /*
696 * Add an entry to the segment table, extending it if necessary.
697 */
698 if (!(iSeg % 8))
699 {
700 void *pvSegs = RTMemRealloc(pThis->paSegs, sizeof(RTDBGMODCTNSEGMENT) * (iSeg + 8));
701 if (!pvSegs)
702 return VERR_NO_MEMORY;
703 pThis->paSegs = (PRTDBGMODCTNSEGMENT)pvSegs;
704 }
705
706 pThis->paSegs[iSeg].SymAddrTree = NULL;
707 pThis->paSegs[iSeg].LineAddrTree = NULL;
708 pThis->paSegs[iSeg].off = uRva;
709 pThis->paSegs[iSeg].cb = cb;
710 pThis->paSegs[iSeg].fFlags = fFlags;
711 pThis->paSegs[iSeg].pszName = RTStrCacheEnterN(g_hDbgModStrCache, pszName, cchName);
712 if (pThis->paSegs[iSeg].pszName)
713 {
714 if (piSeg)
715 *piSeg = iSeg;
716 pThis->cSegs++;
717 pThis->cb = uRvaLastMax + 1;
718 if (!pThis->cb)
719 pThis->cb = RTUINTPTR_MAX;
720 return VINF_SUCCESS;
721 }
722 return VERR_NO_MEMORY;
723}
724
725
726/** @copydoc RTDBGMODVTDBG::pfnImageSize */
727static DECLCALLBACK(RTUINTPTR) rtDbgModContainer_ImageSize(PRTDBGMODINT pMod)
728{
729 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
730 return pThis->cb;
731}
732
733
734/** @copydoc RTDBGMODVTDBG::pfnRvaToSegOff */
735static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
736{
737 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
738 PCRTDBGMODCTNSEGMENT paSeg = pThis->paSegs;
739 uint32_t const cSegs = pThis->cSegs;
740#if 0
741 if (cSegs <= 7)
742#endif
743 {
744 /*
745 * Linear search.
746 */
747 for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
748 {
749 RTUINTPTR offSeg = uRva - paSeg[iSeg].off;
750 if (offSeg < paSeg[iSeg].cb)
751 {
752 if (poffSeg)
753 *poffSeg = offSeg;
754 return iSeg;
755 }
756 }
757 }
758#if 0 /** @todo binary search doesn't work if we've got empty segments in the list */
759 else
760 {
761 /*
762 * Binary search.
763 */
764 uint32_t iFirst = 0;
765 uint32_t iLast = cSegs - 1;
766 for (;;)
767 {
768 uint32_t iSeg = iFirst + (iLast - iFirst) / 2;
769 RTUINTPTR offSeg = uRva - paSeg[iSeg].off;
770 if (offSeg < paSeg[iSeg].cb)
771 {
772#if 0 /* Enable if we change the above test. */
773 if (offSeg == 0 && paSeg[iSeg].cb == 0)
774 while ( iSeg > 0
775 && paSeg[iSeg - 1].cb == 0
776 && paSeg[iSeg - 1].off == uRva)
777 iSeg--;
778#endif
779
780 if (poffSeg)
781 *poffSeg = offSeg;
782 return iSeg;
783 }
784
785 /* advance */
786 if (uRva < paSeg[iSeg].off)
787 {
788 /* between iFirst and iSeg. */
789 if (iSeg == iFirst)
790 break;
791 iLast = iSeg - 1;
792 }
793 else
794 {
795 /* between iSeg and iLast. paSeg[iSeg].cb == 0 ends up here too. */
796 if (iSeg == iLast)
797 break;
798 iFirst = iSeg + 1;
799 }
800 }
801 }
802#endif
803
804 /* Invalid. */
805 return NIL_RTDBGSEGIDX;
806}
807
808
809/** Destroy a line number node. */
810static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeLineNode(PAVLU32NODECORE pNode, void *pvUser)
811{
812 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pvUser;
813 PRTDBGMODCTNLINE pLine = RT_FROM_MEMBER(pNode, RTDBGMODCTNLINE, OrdinalCore);
814 RTStrCacheRelease(g_hDbgModStrCache, pLine->pszFile);
815 pLine->pszFile = NULL;
816#ifdef RTDBGMODCNT_WITH_MEM_CACHE
817 RTMemCacheFree(pThis->hLineNumAllocator, pLine);
818#else
819 RTMemFree(pLine); NOREF(pThis);
820#endif
821 return 0;
822}
823
824
825/** Destroy a symbol node. */
826static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeNode(PAVLRUINTPTRNODECORE pNode, void *pvUser)
827{
828 PRTDBGMODCTNSYMBOL pSym = RT_FROM_MEMBER(pNode, RTDBGMODCTNSYMBOL, AddrCore);
829 RTStrCacheRelease(g_hDbgModStrCache, pSym->NameCore.pszString);
830 pSym->NameCore.pszString = NULL;
831
832#if 0
833 //PRTDBGMODCTN pThis = (PRTDBGMODCTN)pvUser;
834 //PAVLU32NODECORE pRemoved = RTAvlU32Remove(&pThis->SymbolOrdinalTree, pSym->OrdinalCore.Key);
835 //Assert(pRemoved == &pSym->OrdinalCore); RT_NOREF_PV(pRemoved);
836#else
837 RT_NOREF_PV(pvUser);
838#endif
839
840 RTMemFree(pSym);
841 return 0;
842}
843
844
845/** @copydoc RTDBGMODVTDBG::pfnClose */
846static DECLCALLBACK(int) rtDbgModContainer_Close(PRTDBGMODINT pMod)
847{
848 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
849
850 /*
851 * Destroy the symbols and instance data.
852 */
853 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
854 {
855 RTAvlrUIntPtrDestroy(&pThis->paSegs[iSeg].SymAddrTree, rtDbgModContainer_DestroyTreeNode, pThis);
856 RTStrCacheRelease(g_hDbgModStrCache, pThis->paSegs[iSeg].pszName);
857 pThis->paSegs[iSeg].pszName = NULL;
858 }
859
860 RTAvlrUIntPtrDestroy(&pThis->AbsAddrTree, rtDbgModContainer_DestroyTreeNode, pThis);
861
862 pThis->Names = NULL;
863
864#ifdef RTDBGMODCNT_WITH_MEM_CACHE
865 RTMemCacheDestroy(pThis->hLineNumAllocator);
866 pThis->hLineNumAllocator = NIL_RTMEMCACHE;
867#else
868 RTAvlU32Destroy(&pThis->LineOrdinalTree, rtDbgModContainer_DestroyTreeLineNode, pThis);
869#endif
870
871 RTMemFree(pThis->paSegs);
872 pThis->paSegs = NULL;
873
874 RTMemFree(pThis);
875
876 return VINF_SUCCESS;
877}
878
879
880/** @copydoc RTDBGMODVTDBG::pfnTryOpen */
881static DECLCALLBACK(int) rtDbgModContainer_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch, RTDBGCFG hDbgCfg)
882{
883 NOREF(pMod); NOREF(enmArch); RT_NOREF_PV(hDbgCfg);
884 return VERR_INTERNAL_ERROR_5;
885}
886
887
888
889/** Virtual function table for the debug info container. */
890DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgContainer =
891{
892 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
893 /*.fSupports = */ 0, /* (Don't call my TryOpen, please.) */
894 /*.pszName = */ "container",
895 /*.pfnTryOpen = */ rtDbgModContainer_TryOpen,
896 /*.pfnClose = */ rtDbgModContainer_Close,
897
898 /*.pfnRvaToSegOff = */ rtDbgModContainer_RvaToSegOff,
899 /*.pfnImageSize = */ rtDbgModContainer_ImageSize,
900
901 /*.pfnSegmentAdd = */ rtDbgModContainer_SegmentAdd,
902 /*.pfnSegmentCount = */ rtDbgModContainer_SegmentCount,
903 /*.pfnSegmentByIndex = */ rtDbgModContainer_SegmentByIndex,
904
905 /*.pfnSymbolAdd = */ rtDbgModContainer_SymbolAdd,
906 /*.pfnSymbolCount = */ rtDbgModContainer_SymbolCount,
907 /*.pfnSymbolByOrdinal = */ rtDbgModContainer_SymbolByOrdinal,
908 /*.pfnSymbolByName = */ rtDbgModContainer_SymbolByName,
909 /*.pfnSymbolByAddr = */ rtDbgModContainer_SymbolByAddr,
910
911 /*.pfnLineAdd = */ rtDbgModContainer_LineAdd,
912 /*.pfnLineCount = */ rtDbgModContainer_LineCount,
913 /*.pfnLineByOrdinal = */ rtDbgModContainer_LineByOrdinal,
914 /*.pfnLineByAddr = */ rtDbgModContainer_LineByAddr,
915
916 /*.pfnUnwindFrame = */ rtDbgModContainer_UnwindFrame,
917
918 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
919};
920
921
922
923/**
924 * Special container operation for removing all symbols.
925 *
926 * @returns IPRT status code.
927 * @param pMod The module instance.
928 */
929DECLHIDDEN(int) rtDbgModContainer_SymbolRemoveAll(PRTDBGMODINT pMod)
930{
931 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
932
933 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
934 {
935 RTAvlrUIntPtrDestroy(&pThis->paSegs[iSeg].SymAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
936 Assert(pThis->paSegs[iSeg].SymAddrTree == NULL);
937 }
938
939 RTAvlrUIntPtrDestroy(&pThis->AbsAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
940 Assert(pThis->AbsAddrTree == NULL);
941
942 pThis->Names = NULL;
943 pThis->iNextSymbolOrdinal = 0;
944
945 return VINF_SUCCESS;
946}
947
948
949/**
950 * Special container operation for removing all line numbers.
951 *
952 * @returns IPRT status code.
953 * @param pMod The module instance.
954 */
955DECLHIDDEN(int) rtDbgModContainer_LineRemoveAll(PRTDBGMODINT pMod)
956{
957 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
958
959 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
960 pThis->paSegs[iSeg].LineAddrTree = NULL;
961
962 RTAvlU32Destroy(&pThis->LineOrdinalTree, rtDbgModContainer_DestroyTreeLineNode, pThis);
963 Assert(pThis->LineOrdinalTree == NULL);
964
965 pThis->iNextLineOrdinal = 0;
966
967 return VINF_SUCCESS;
968}
969
970
971/**
972 * Special container operation for removing everything.
973 *
974 * @returns IPRT status code.
975 * @param pMod The module instance.
976 */
977DECLHIDDEN(int) rtDbgModContainer_RemoveAll(PRTDBGMODINT pMod)
978{
979 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
980
981 rtDbgModContainer_LineRemoveAll(pMod);
982 rtDbgModContainer_SymbolRemoveAll(pMod);
983
984 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
985 {
986 RTStrCacheRelease(g_hDbgModStrCache, pThis->paSegs[iSeg].pszName);
987 pThis->paSegs[iSeg].pszName = NULL;
988 }
989
990 pThis->cSegs = 0;
991 pThis->cb = 0;
992
993 return VINF_SUCCESS;
994}
995
996
997/**
998 * Creates a generic debug info container and associates it with the module.
999 *
1000 * @returns IPRT status code.
1001 * @param pMod The module instance.
1002 * @param cbSeg The size of the initial segment. 0 if segments are to be
1003 * created manually later on.
1004 */
1005DECLHIDDEN(int) rtDbgModContainerCreate(PRTDBGMODINT pMod, RTUINTPTR cbSeg)
1006{
1007 PRTDBGMODCTN pThis = (PRTDBGMODCTN)RTMemAlloc(sizeof(*pThis));
1008 if (!pThis)
1009 return VERR_NO_MEMORY;
1010
1011 pThis->Names = NULL;
1012 pThis->AbsAddrTree = NULL;
1013 pThis->SymbolOrdinalTree = NULL;
1014 pThis->LineOrdinalTree = NULL;
1015 pThis->paSegs = NULL;
1016 pThis->cSegs = 0;
1017 pThis->cb = 0;
1018 pThis->iNextSymbolOrdinal = 0;
1019 pThis->iNextLineOrdinal = 0;
1020
1021 pMod->pDbgVt = &g_rtDbgModVtDbgContainer;
1022 pMod->pvDbgPriv = pThis;
1023
1024#ifdef RTDBGMODCNT_WITH_MEM_CACHE
1025 int rc = RTMemCacheCreate(&pThis->hLineNumAllocator, sizeof(RTDBGMODCTNLINE), sizeof(void *), UINT32_MAX,
1026 NULL /*pfnCtor*/, NULL /*pfnDtor*/, NULL /*pvUser*/, 0 /*fFlags*/);
1027#else
1028 int rc = VINF_SUCCESS;
1029#endif
1030 if (RT_SUCCESS(rc))
1031 {
1032 /*
1033 * Add the initial segment.
1034 */
1035 if (cbSeg)
1036 rc = rtDbgModContainer_SegmentAdd(pMod, 0, cbSeg, "default", sizeof("default") - 1, 0, NULL);
1037 if (RT_SUCCESS(rc))
1038 return rc;
1039
1040#ifdef RTDBGMODCNT_WITH_MEM_CACHE
1041 RTMemCacheDestroy(pThis->hLineNumAllocator);
1042#endif
1043 }
1044
1045 RTMemFree(pThis);
1046 pMod->pDbgVt = NULL;
1047 pMod->pvDbgPriv = NULL;
1048 return rc;
1049}
1050
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette