VirtualBox

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

Last change on this file since 58591 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.9 KB
Line 
1/* $Id: dbgmodcontainer.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT - Debug Info Container.
4 */
5
6/*
7 * Copyright (C) 2009-2015 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 * Fills in a RTDBGSYMBOL structure.
154 *
155 * @returns VINF_SUCCESS.
156 * @param pMySym Our internal symbol representation.
157 * @param pExtSym The external symbol representation.
158 */
159DECLINLINE(int) rtDbgModContainerReturnSymbol(PCRTDBGMODCTNSYMBOL pMySym, PRTDBGSYMBOL pExtSym)
160{
161 pExtSym->Value = pMySym->AddrCore.Key;
162 pExtSym->offSeg = pMySym->AddrCore.Key;
163 pExtSym->iSeg = pMySym->iSeg;
164 pExtSym->fFlags = pMySym->fFlags;
165 pExtSym->cb = pMySym->cb;
166 pExtSym->iOrdinal = pMySym->OrdinalCore.Key;
167 Assert(pMySym->NameCore.cchString < sizeof(pExtSym->szName));
168 memcpy(pExtSym->szName, pMySym->NameCore.pszString, pMySym->NameCore.cchString + 1);
169 return VINF_SUCCESS;
170}
171
172
173
174/** @copydoc RTDBGMODVTDBG::pfnLineByAddr */
175static DECLCALLBACK(int) rtDbgModContainer_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
176 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
177{
178 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
179
180 /*
181 * Validate the input address.
182 */
183 AssertMsgReturn(iSeg < pThis->cSegs,
184 ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
185 VERR_DBG_INVALID_SEGMENT_INDEX);
186 AssertMsgReturn(off < pThis->paSegs[iSeg].cb,
187 ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
188 VERR_DBG_INVALID_SEGMENT_OFFSET);
189
190 /*
191 * Lookup the nearest line number with an address less or equal to the specified address.
192 */
193 PAVLUINTPTRNODECORE pAvlCore = RTAvlUIntPtrGetBestFit(&pThis->paSegs[iSeg].LineAddrTree, off, false /*fAbove*/);
194 if (!pAvlCore)
195 return pThis->iNextLineOrdinal
196 ? VERR_DBG_LINE_NOT_FOUND
197 : VERR_DBG_NO_LINE_NUMBERS;
198 PCRTDBGMODCTNLINE pMyLine = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNLINE const, AddrCore);
199 pLineInfo->Address = pMyLine->AddrCore.Key;
200 pLineInfo->offSeg = pMyLine->AddrCore.Key;
201 pLineInfo->iSeg = iSeg;
202 pLineInfo->uLineNo = pMyLine->uLineNo;
203 pLineInfo->iOrdinal = pMyLine->OrdinalCore.Key;
204 strcpy(pLineInfo->szFilename, pMyLine->pszFile);
205 if (poffDisp)
206 *poffDisp = off - pMyLine->AddrCore.Key;
207 return VINF_SUCCESS;
208}
209
210
211/** @copydoc RTDBGMODVTDBG::pfnLineByOrdinal */
212static DECLCALLBACK(int) rtDbgModContainer_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
213{
214 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
215
216 /*
217 * Look it up.
218 */
219 if (iOrdinal >= pThis->iNextLineOrdinal)
220 return pThis->iNextLineOrdinal
221 ? VERR_DBG_LINE_NOT_FOUND
222 : VERR_DBG_NO_LINE_NUMBERS;
223 PAVLU32NODECORE pAvlCore = RTAvlU32Get(&pThis->LineOrdinalTree, iOrdinal);
224 AssertReturn(pAvlCore, VERR_DBG_LINE_NOT_FOUND);
225 PCRTDBGMODCTNLINE pMyLine = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNLINE const, OrdinalCore);
226 pLineInfo->Address = pMyLine->AddrCore.Key;
227 pLineInfo->offSeg = pMyLine->AddrCore.Key;
228 pLineInfo->iSeg = pMyLine->iSeg;
229 pLineInfo->uLineNo = pMyLine->uLineNo;
230 pLineInfo->iOrdinal = pMyLine->OrdinalCore.Key;
231 strcpy(pLineInfo->szFilename, pMyLine->pszFile);
232 return VINF_SUCCESS;
233}
234
235
236/** @copydoc RTDBGMODVTDBG::pfnLineCount */
237static DECLCALLBACK(uint32_t) rtDbgModContainer_LineCount(PRTDBGMODINT pMod)
238{
239 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
240
241 /* Note! The ordinal numbers are 0-based. */
242 return pThis->iNextLineOrdinal;
243}
244
245
246/** @copydoc RTDBGMODVTDBG::pfnLineAdd */
247static DECLCALLBACK(int) rtDbgModContainer_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
248 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
249{
250 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
251
252 /*
253 * Validate the input address.
254 */
255 AssertMsgReturn(iSeg < pThis->cSegs, ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
256 VERR_DBG_INVALID_SEGMENT_INDEX);
257 AssertMsgReturn(off < pThis->paSegs[iSeg].cb, ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
258 VERR_DBG_INVALID_SEGMENT_OFFSET);
259
260 /*
261 * Create a new entry.
262 */
263#ifdef RTDBGMODCNT_WITH_MEM_CACHE
264 PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemCacheAlloc(pThis->hLineNumAllocator);
265#else
266 PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemAllocZ(sizeof(*pLine));
267#endif
268 if (!pLine)
269 return VERR_NO_MEMORY;
270 pLine->AddrCore.Key = off;
271 pLine->OrdinalCore.Key = pThis->iNextLineOrdinal;
272 pLine->uLineNo = uLineNo;
273 pLine->iSeg = iSeg;
274 pLine->pszFile = RTStrCacheEnterN(g_hDbgModStrCache, pszFile, cchFile);
275 int rc;
276 if (pLine->pszFile)
277 {
278 if (RTAvlUIntPtrInsert(&pThis->paSegs[iSeg].LineAddrTree, &pLine->AddrCore))
279 {
280 if (RTAvlU32Insert(&pThis->LineOrdinalTree, &pLine->OrdinalCore))
281 {
282 if (piOrdinal)
283 *piOrdinal = pThis->iNextLineOrdinal;
284 pThis->iNextLineOrdinal++;
285 return VINF_SUCCESS;
286 }
287
288 rc = VERR_INTERNAL_ERROR_5;
289 RTAvlUIntPtrRemove(&pThis->paSegs[iSeg].LineAddrTree, pLine->AddrCore.Key);
290 }
291
292 /* bail out */
293 rc = VERR_DBG_ADDRESS_CONFLICT;
294 RTStrCacheRelease(g_hDbgModStrCache, pLine->pszFile);
295 }
296 else
297 rc = VERR_NO_MEMORY;
298#ifdef RTDBGMODCNT_WITH_MEM_CACHE
299 RTMemCacheFree(pThis->hLineNumAllocator, pLine);
300#else
301 RTMemFree(pLine);
302#endif
303 return rc;
304}
305
306
307/** @copydoc RTDBGMODVTDBG::pfnSymbolByAddr */
308static DECLCALLBACK(int) rtDbgModContainer_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
309 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
310{
311 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
312
313 /*
314 * Validate the input address.
315 */
316 AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS
317 || iSeg < pThis->cSegs,
318 ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
319 VERR_DBG_INVALID_SEGMENT_INDEX);
320 AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
321 || off <= pThis->paSegs[iSeg].cb,
322 ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
323 VERR_DBG_INVALID_SEGMENT_OFFSET);
324
325 /*
326 * Lookup the nearest symbol with an address less or equal to the specified address.
327 */
328 PAVLRUINTPTRNODECORE pAvlCore = RTAvlrUIntPtrGetBestFit( iSeg == RTDBGSEGIDX_ABS
329 ? &pThis->AbsAddrTree
330 : &pThis->paSegs[iSeg].SymAddrTree,
331 off,
332 fFlags == RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL /*fAbove*/);
333 if (!pAvlCore)
334 return VERR_SYMBOL_NOT_FOUND;
335 PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNSYMBOL const, AddrCore);
336 if (poffDisp)
337 *poffDisp = off - pMySym->AddrCore.Key;
338 return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
339}
340
341
342/** @copydoc RTDBGMODVTDBG::pfnSymbolByName */
343static DECLCALLBACK(int) rtDbgModContainer_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol, PRTDBGSYMBOL pSymInfo)
344{
345 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
346 NOREF(cchSymbol);
347
348 /*
349 * Look it up in the name space.
350 */
351 PRTSTRSPACECORE pStrCore = RTStrSpaceGet(&pThis->Names, pszSymbol);
352 if (!pStrCore)
353 return VERR_SYMBOL_NOT_FOUND;
354 PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pStrCore, RTDBGMODCTNSYMBOL const, NameCore);
355 return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
356}
357
358
359/** @copydoc RTDBGMODVTDBG::pfnSymbolByOrdinal */
360static DECLCALLBACK(int) rtDbgModContainer_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
361{
362 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
363
364 /*
365 * Look it up in the ordinal tree.
366 */
367 if (iOrdinal >= pThis->iNextSymbolOrdinal)
368 return pThis->iNextSymbolOrdinal
369 ? VERR_DBG_NO_SYMBOLS
370 : VERR_SYMBOL_NOT_FOUND;
371 PAVLU32NODECORE pAvlCore = RTAvlU32Get(&pThis->SymbolOrdinalTree, iOrdinal);
372 AssertReturn(pAvlCore, VERR_SYMBOL_NOT_FOUND);
373 PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNSYMBOL const, OrdinalCore);
374 return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
375}
376
377
378/** @copydoc RTDBGMODVTDBG::pfnSymbolCount */
379static DECLCALLBACK(uint32_t) rtDbgModContainer_SymbolCount(PRTDBGMODINT pMod)
380{
381 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
382
383 /* Note! The ordinal numbers are 0-based. */
384 return pThis->iNextSymbolOrdinal;
385}
386
387
388/** @copydoc RTDBGMODVTDBG::pfnSymbolAdd */
389static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
390 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
391 uint32_t *piOrdinal)
392{
393 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
394
395 /*
396 * Address validation. The other arguments have already been validated.
397 */
398 AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS
399 || iSeg < pThis->cSegs,
400 ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs),
401 VERR_DBG_INVALID_SEGMENT_INDEX);
402 AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
403 || off <= pThis->paSegs[iSeg].cb,
404 ("off=%RTptr cb=%RTptr cbSeg=%RTptr\n", off, cb, pThis->paSegs[iSeg].cb),
405 VERR_DBG_INVALID_SEGMENT_OFFSET);
406
407 /* Be a little relaxed wrt to the symbol size. */
408 int rc = VINF_SUCCESS;
409 if (iSeg != RTDBGSEGIDX_ABS && off + cb > pThis->paSegs[iSeg].cb)
410 {
411 cb = pThis->paSegs[iSeg].cb - off;
412 rc = VINF_DBG_ADJUSTED_SYM_SIZE;
413 }
414
415 /*
416 * Create a new entry.
417 */
418 PRTDBGMODCTNSYMBOL pSymbol = (PRTDBGMODCTNSYMBOL)RTMemAllocZ(sizeof(*pSymbol));
419 if (!pSymbol)
420 return VERR_NO_MEMORY;
421
422 pSymbol->AddrCore.Key = off;
423 pSymbol->AddrCore.KeyLast = off + (cb ? cb - 1 : 0);
424 pSymbol->OrdinalCore.Key = pThis->iNextSymbolOrdinal;
425 pSymbol->iSeg = iSeg;
426 pSymbol->cb = cb;
427 pSymbol->fFlags = fFlags;
428 pSymbol->NameCore.pszString = RTStrCacheEnterN(g_hDbgModStrCache, pszSymbol, cchSymbol);
429 if (pSymbol->NameCore.pszString)
430 {
431 if (RTStrSpaceInsert(&pThis->Names, &pSymbol->NameCore))
432 {
433 PAVLRUINTPTRTREE pAddrTree = iSeg == RTDBGSEGIDX_ABS
434 ? &pThis->AbsAddrTree
435 : &pThis->paSegs[iSeg].SymAddrTree;
436 if (RTAvlrUIntPtrInsert(pAddrTree, &pSymbol->AddrCore))
437 {
438 if (RTAvlU32Insert(&pThis->SymbolOrdinalTree, &pSymbol->OrdinalCore))
439 {
440 if (piOrdinal)
441 *piOrdinal = pThis->iNextSymbolOrdinal;
442 pThis->iNextSymbolOrdinal++;
443 return rc;
444 }
445
446 /* bail out */
447 rc = VERR_INTERNAL_ERROR_5;
448 RTAvlrUIntPtrRemove(pAddrTree, pSymbol->AddrCore.Key);
449 }
450 else
451 rc = VERR_DBG_ADDRESS_CONFLICT;
452 RTStrSpaceRemove(&pThis->Names, pSymbol->NameCore.pszString);
453 }
454 else
455 rc = VERR_DBG_DUPLICATE_SYMBOL;
456 RTStrCacheRelease(g_hDbgModStrCache, pSymbol->NameCore.pszString);
457 }
458 else
459 rc = VERR_NO_MEMORY;
460 RTMemFree(pSymbol);
461 return rc;
462}
463
464
465/** @copydoc RTDBGMODVTDBG::pfnSegmentByIndex */
466static DECLCALLBACK(int) rtDbgModContainer_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
467{
468 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
469 if (iSeg >= pThis->cSegs)
470 return VERR_DBG_INVALID_SEGMENT_INDEX;
471 pSegInfo->Address = RTUINTPTR_MAX;
472 pSegInfo->uRva = pThis->paSegs[iSeg].off;
473 pSegInfo->cb = pThis->paSegs[iSeg].cb;
474 pSegInfo->fFlags = pThis->paSegs[iSeg].fFlags;
475 pSegInfo->iSeg = iSeg;
476 strcpy(pSegInfo->szName, pThis->paSegs[iSeg].pszName);
477 return VINF_SUCCESS;
478}
479
480
481/** @copydoc RTDBGMODVTDBG::pfnSegmentCount */
482static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_SegmentCount(PRTDBGMODINT pMod)
483{
484 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
485 return pThis->cSegs;
486}
487
488
489/** @copydoc RTDBGMODVTDBG::pfnSegmentAdd */
490static DECLCALLBACK(int) rtDbgModContainer_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
491 uint32_t fFlags, PRTDBGSEGIDX piSeg)
492{
493 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
494
495 /*
496 * Input validation (the bits the caller cannot do).
497 */
498 /* Overlapping segments are not yet supported. Will use flags to deal with it if it becomes necessary. */
499 RTUINTPTR uRvaLast = uRva + RT_MAX(cb, 1) - 1;
500 RTUINTPTR uRvaLastMax = uRvaLast;
501 RTDBGSEGIDX iSeg = pThis->cSegs;
502 while (iSeg-- > 0)
503 {
504 RTUINTPTR uCurRva = pThis->paSegs[iSeg].off;
505 RTUINTPTR uCurRvaLast = uCurRva + RT_MAX(pThis->paSegs[iSeg].cb, 1) - 1;
506 if ( uRva <= uCurRvaLast
507 && uRvaLast >= uCurRva
508 && ( /* HACK ALERT! Allow empty segments to share space (bios/watcom, elf). */
509 (cb != 0 && pThis->paSegs[iSeg].cb != 0)
510 || ( cb == 0
511 && uRva != uCurRva
512 && uRva != uCurRvaLast)
513 || ( pThis->paSegs[iSeg].cb == 0
514 && uCurRva != uRva
515 && uCurRva != uRvaLast)
516 )
517 )
518 AssertMsgFailedReturn(("uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\";\n"
519 "uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\" iSeg=%#x\n",
520 uRva, uRvaLast, cb, pszName,
521 uCurRva, uCurRvaLast, pThis->paSegs[iSeg].cb, pThis->paSegs[iSeg].pszName, iSeg),
522 VERR_DBG_SEGMENT_INDEX_CONFLICT);
523 if (uRvaLastMax < uCurRvaLast)
524 uRvaLastMax = uCurRvaLast;
525 }
526 /* Strict ordered segment addition at the moment. */
527 iSeg = pThis->cSegs;
528 AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg == iSeg,
529 ("iSeg=%#x *piSeg=%#x\n", iSeg, *piSeg),
530 VERR_DBG_INVALID_SEGMENT_INDEX);
531
532 /*
533 * Add an entry to the segment table, extending it if necessary.
534 */
535 if (!(iSeg % 8))
536 {
537 void *pvSegs = RTMemRealloc(pThis->paSegs, sizeof(RTDBGMODCTNSEGMENT) * (iSeg + 8));
538 if (!pvSegs)
539 return VERR_NO_MEMORY;
540 pThis->paSegs = (PRTDBGMODCTNSEGMENT)pvSegs;
541 }
542
543 pThis->paSegs[iSeg].SymAddrTree = NULL;
544 pThis->paSegs[iSeg].LineAddrTree = NULL;
545 pThis->paSegs[iSeg].off = uRva;
546 pThis->paSegs[iSeg].cb = cb;
547 pThis->paSegs[iSeg].fFlags = fFlags;
548 pThis->paSegs[iSeg].pszName = RTStrCacheEnterN(g_hDbgModStrCache, pszName, cchName);
549 if (pThis->paSegs[iSeg].pszName)
550 {
551 if (piSeg)
552 *piSeg = iSeg;
553 pThis->cSegs++;
554 pThis->cb = uRvaLastMax + 1;
555 if (!pThis->cb)
556 pThis->cb = RTUINTPTR_MAX;
557 return VINF_SUCCESS;
558 }
559 return VERR_NO_MEMORY;
560}
561
562
563/** @copydoc RTDBGMODVTDBG::pfnImageSize */
564static DECLCALLBACK(RTUINTPTR) rtDbgModContainer_ImageSize(PRTDBGMODINT pMod)
565{
566 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
567 return pThis->cb;
568}
569
570
571/** @copydoc RTDBGMODVTDBG::pfnRvaToSegOff */
572static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
573{
574 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
575 PCRTDBGMODCTNSEGMENT paSeg = pThis->paSegs;
576 uint32_t const cSegs = pThis->cSegs;
577#if 0
578 if (cSegs <= 7)
579#endif
580 {
581 /*
582 * Linear search.
583 */
584 for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
585 {
586 RTUINTPTR offSeg = uRva - paSeg[iSeg].off;
587 if (offSeg < paSeg[iSeg].cb)
588 {
589 if (poffSeg)
590 *poffSeg = offSeg;
591 return iSeg;
592 }
593 }
594 }
595#if 0 /** @todo binary search doesn't work if we've got empty segments in the list */
596 else
597 {
598 /*
599 * Binary search.
600 */
601 uint32_t iFirst = 0;
602 uint32_t iLast = cSegs - 1;
603 for (;;)
604 {
605 uint32_t iSeg = iFirst + (iLast - iFirst) / 2;
606 RTUINTPTR offSeg = uRva - paSeg[iSeg].off;
607 if (offSeg < paSeg[iSeg].cb)
608 {
609#if 0 /* Enable if we change the above test. */
610 if (offSeg == 0 && paSeg[iSeg].cb == 0)
611 while ( iSeg > 0
612 && paSeg[iSeg - 1].cb == 0
613 && paSeg[iSeg - 1].off == uRva)
614 iSeg--;
615#endif
616
617 if (poffSeg)
618 *poffSeg = offSeg;
619 return iSeg;
620 }
621
622 /* advance */
623 if (uRva < paSeg[iSeg].off)
624 {
625 /* between iFirst and iSeg. */
626 if (iSeg == iFirst)
627 break;
628 iLast = iSeg - 1;
629 }
630 else
631 {
632 /* between iSeg and iLast. paSeg[iSeg].cb == 0 ends up here too. */
633 if (iSeg == iLast)
634 break;
635 iFirst = iSeg + 1;
636 }
637 }
638 }
639#endif
640
641 /* Invalid. */
642 return NIL_RTDBGSEGIDX;
643}
644
645
646/** Destroy a line number node. */
647static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeLineNode(PAVLU32NODECORE pNode, void *pvUser)
648{
649 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pvUser;
650 PRTDBGMODCTNLINE pLine = RT_FROM_MEMBER(pNode, RTDBGMODCTNLINE, OrdinalCore);
651 RTStrCacheRelease(g_hDbgModStrCache, pLine->pszFile);
652 pLine->pszFile = NULL;
653#ifdef RTDBGMODCNT_WITH_MEM_CACHE
654 RTMemCacheFree(pThis->hLineNumAllocator, pLine);
655#else
656 RTMemFree(pLine); NOREF(pThis);
657#endif
658 return 0;
659}
660
661
662/** Destroy a symbol node. */
663static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeNode(PAVLRUINTPTRNODECORE pNode, void *pvUser)
664{
665 PRTDBGMODCTNSYMBOL pSym = RT_FROM_MEMBER(pNode, RTDBGMODCTNSYMBOL, AddrCore);
666 RTStrCacheRelease(g_hDbgModStrCache, pSym->NameCore.pszString);
667 pSym->NameCore.pszString = NULL;
668 RTMemFree(pSym);
669 NOREF(pvUser);
670 return 0;
671}
672
673
674/** @copydoc RTDBGMODVTDBG::pfnClose */
675static DECLCALLBACK(int) rtDbgModContainer_Close(PRTDBGMODINT pMod)
676{
677 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
678
679 /*
680 * Destroy the symbols and instance data.
681 */
682 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
683 {
684 RTAvlrUIntPtrDestroy(&pThis->paSegs[iSeg].SymAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
685 RTStrCacheRelease(g_hDbgModStrCache, pThis->paSegs[iSeg].pszName);
686 pThis->paSegs[iSeg].pszName = NULL;
687 }
688
689 RTAvlrUIntPtrDestroy(&pThis->AbsAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
690 pThis->Names = NULL;
691
692#ifdef RTDBGMODCNT_WITH_MEM_CACHE
693 RTMemCacheDestroy(pThis->hLineNumAllocator);
694 pThis->hLineNumAllocator = NIL_RTMEMCACHE;
695#else
696 RTAvlU32Destroy(&pThis->LineOrdinalTree, rtDbgModContainer_DestroyTreeLineNode, pThis);
697#endif
698
699 RTMemFree(pThis->paSegs);
700 pThis->paSegs = NULL;
701
702 RTMemFree(pThis);
703
704 return VINF_SUCCESS;
705}
706
707
708/** @copydoc RTDBGMODVTDBG::pfnTryOpen */
709static DECLCALLBACK(int) rtDbgModContainer_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
710{
711 NOREF(pMod); NOREF(enmArch);
712 return VERR_INTERNAL_ERROR_5;
713}
714
715
716
717/** Virtual function table for the debug info container. */
718DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgContainer =
719{
720 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
721 /*.fSupports = */ 0, /* (Don't call my TryOpen, please.) */
722 /*.pszName = */ "container",
723 /*.pfnTryOpen = */ rtDbgModContainer_TryOpen,
724 /*.pfnClose = */ rtDbgModContainer_Close,
725
726 /*.pfnRvaToSegOff = */ rtDbgModContainer_RvaToSegOff,
727 /*.pfnImageSize = */ rtDbgModContainer_ImageSize,
728
729 /*.pfnSegmentAdd = */ rtDbgModContainer_SegmentAdd,
730 /*.pfnSegmentCount = */ rtDbgModContainer_SegmentCount,
731 /*.pfnSegmentByIndex = */ rtDbgModContainer_SegmentByIndex,
732
733 /*.pfnSymbolAdd = */ rtDbgModContainer_SymbolAdd,
734 /*.pfnSymbolCount = */ rtDbgModContainer_SymbolCount,
735 /*.pfnSymbolByOrdinal = */ rtDbgModContainer_SymbolByOrdinal,
736 /*.pfnSymbolByName = */ rtDbgModContainer_SymbolByName,
737 /*.pfnSymbolByAddr = */ rtDbgModContainer_SymbolByAddr,
738
739 /*.pfnLineAdd = */ rtDbgModContainer_LineAdd,
740 /*.pfnLineCount = */ rtDbgModContainer_LineCount,
741 /*.pfnLineByOrdinal = */ rtDbgModContainer_LineByOrdinal,
742 /*.pfnLineByAddr = */ rtDbgModContainer_LineByAddr,
743
744 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
745};
746
747
748
749/**
750 * Special container operation for removing all symbols.
751 *
752 * @returns IPRT status code.
753 * @param pMod The module instance.
754 */
755DECLHIDDEN(int) rtDbgModContainer_SymbolRemoveAll(PRTDBGMODINT pMod)
756{
757 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
758
759 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
760 {
761 RTAvlrUIntPtrDestroy(&pThis->paSegs[iSeg].SymAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
762 Assert(pThis->paSegs[iSeg].SymAddrTree == NULL);
763 }
764
765 RTAvlrUIntPtrDestroy(&pThis->AbsAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
766 Assert(pThis->AbsAddrTree == NULL);
767
768 pThis->Names = NULL;
769 pThis->iNextSymbolOrdinal = 0;
770
771 return VINF_SUCCESS;
772}
773
774
775/**
776 * Special container operation for removing all line numbers.
777 *
778 * @returns IPRT status code.
779 * @param pMod The module instance.
780 */
781DECLHIDDEN(int) rtDbgModContainer_LineRemoveAll(PRTDBGMODINT pMod)
782{
783 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
784
785 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
786 pThis->paSegs[iSeg].LineAddrTree = NULL;
787
788 RTAvlU32Destroy(&pThis->LineOrdinalTree, rtDbgModContainer_DestroyTreeLineNode, pThis);
789 Assert(pThis->LineOrdinalTree == NULL);
790
791 pThis->iNextLineOrdinal = 0;
792
793 return VINF_SUCCESS;
794}
795
796
797/**
798 * Special container operation for removing everything.
799 *
800 * @returns IPRT status code.
801 * @param pMod The module instance.
802 */
803DECLHIDDEN(int) rtDbgModContainer_RemoveAll(PRTDBGMODINT pMod)
804{
805 PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
806
807 rtDbgModContainer_LineRemoveAll(pMod);
808 rtDbgModContainer_SymbolRemoveAll(pMod);
809
810 for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
811 {
812 RTStrCacheRelease(g_hDbgModStrCache, pThis->paSegs[iSeg].pszName);
813 pThis->paSegs[iSeg].pszName = NULL;
814 }
815
816 pThis->cSegs = 0;
817 pThis->cb = 0;
818
819 return VINF_SUCCESS;
820}
821
822
823/**
824 * Creates a generic debug info container and associates it with the module.
825 *
826 * @returns IPRT status code.
827 * @param pMod The module instance.
828 * @param cbSeg The size of the initial segment. 0 if segments are to be
829 * created manually later on.
830 */
831int rtDbgModContainerCreate(PRTDBGMODINT pMod, RTUINTPTR cbSeg)
832{
833 PRTDBGMODCTN pThis = (PRTDBGMODCTN)RTMemAlloc(sizeof(*pThis));
834 if (!pThis)
835 return VERR_NO_MEMORY;
836
837 pThis->Names = NULL;
838 pThis->AbsAddrTree = NULL;
839 pThis->SymbolOrdinalTree = NULL;
840 pThis->LineOrdinalTree = NULL;
841 pThis->paSegs = NULL;
842 pThis->cSegs = 0;
843 pThis->cb = 0;
844 pThis->iNextSymbolOrdinal = 0;
845 pThis->iNextLineOrdinal = 0;
846
847 pMod->pDbgVt = &g_rtDbgModVtDbgContainer;
848 pMod->pvDbgPriv = pThis;
849
850#ifdef RTDBGMODCNT_WITH_MEM_CACHE
851 int rc = RTMemCacheCreate(&pThis->hLineNumAllocator, sizeof(RTDBGMODCTNLINE), sizeof(void *), UINT32_MAX,
852 NULL /*pfnCtor*/, NULL /*pfnDtor*/, NULL /*pvUser*/, 0 /*fFlags*/);
853#else
854 int rc = VINF_SUCCESS;
855#endif
856 if (RT_SUCCESS(rc))
857 {
858 /*
859 * Add the initial segment.
860 */
861 if (cbSeg)
862 rc = rtDbgModContainer_SegmentAdd(pMod, 0, cbSeg, "default", sizeof("default") - 1, 0, NULL);
863 if (RT_SUCCESS(rc))
864 return rc;
865
866#ifdef RTDBGMODCNT_WITH_MEM_CACHE
867 RTMemCacheDestroy(pThis->hLineNumAllocator);
868#endif
869 }
870
871 RTMemFree(pThis);
872 pMod->pDbgVt = NULL;
873 pMod->pvDbgPriv = NULL;
874 return rc;
875}
876
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