VirtualBox

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

Last change on this file since 75244 was 74980, checked in by vboxsync, 6 years ago

IPRT/dbg: Added a few flags to RTDbg[Mod|As]SymbolAdd to deal with conflicts.

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