VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp@ 38557

Last change on this file since 38557 was 38557, checked in by vboxsync, 14 years ago

dbgmoddwarf.cpp: line number virtual machine coding.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.1 KB
Line 
1/* $Id: dbgmoddwarf.cpp 38557 2011-08-29 13:13:27Z vboxsync $ */
2/** @file
3 * IPRT - Debug Info Reader For DWARF.
4 */
5
6/*
7 * Copyright (C) 2011 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/asm.h>
35#include <iprt/err.h>
36#include <iprt/ctype.h>
37#include <iprt/mem.h>
38#include <iprt/path.h>
39#include <iprt/stream.h>
40#include <iprt/string.h>
41#include "internal/dbgmod.h"
42
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** @name Standard DWARF Line Number Opcodes
48 * @{ */
49#define DW_LNS_extended UINT8_C(0)
50#define DW_LNS_copy UINT8_C(1)
51#define DW_LNS_advance_pc UINT8_C(2)
52#define DW_LNS_advance_line UINT8_C(3)
53#define DW_LNS_set_file UINT8_C(4)
54#define DW_LNS_set_column UINT8_C(5)
55#define DW_LNS_negate_stmt UINT8_C(6)
56#define DW_LNS_set_basic_block UINT8_C(7)
57#define DW_LNS_const_add_pc UINT8_C(8)
58#define DW_LNS_fixed_advance_pc UINT8_C(9)
59#define DW_LNS_set_prologue_end UINT8_C(10)
60#define DW_LNS_set_epilogue_begin UINT8_C(11)
61#define DW_LNS_set_isa UINT8_C(12)
62/** @} */
63
64
65/** @name Extended DWARF Line Number Opcodes
66 * @{ */
67#define DW_LNE_end_sequence UINT8_C(1)
68#define DW_LNE_set_address UINT8_C(2)
69#define DW_LNE_define_file UINT8_C(3)
70#define DW_LNE_set_descriminator UINT8_C(4)
71/** @} */
72
73
74/*******************************************************************************
75* Structures and Typedefs *
76*******************************************************************************/
77/**
78 * DWARF sections.
79 */
80typedef enum krtDbgModDwarfSect
81{
82 krtDbgModDwarfSect_abbrev = 0,
83 krtDbgModDwarfSect_aranges,
84 krtDbgModDwarfSect_frame,
85 krtDbgModDwarfSect_info,
86 krtDbgModDwarfSect_inlined,
87 krtDbgModDwarfSect_line,
88 krtDbgModDwarfSect_loc,
89 krtDbgModDwarfSect_macinfo,
90 krtDbgModDwarfSect_pubnames,
91 krtDbgModDwarfSect_pubtypes,
92 krtDbgModDwarfSect_ranges,
93 krtDbgModDwarfSect_str,
94 krtDbgModDwarfSect_types,
95 /** End of valid parts (exclusive). */
96 krtDbgModDwarfSect_End
97} krtDbgModDwarfSect;
98
99/**
100 * The instance data of the DWARF reader.
101 */
102typedef struct RTDBGMODDWARF
103{
104 /** The debug container containing doing the real work. */
105 RTDBGMOD hCnt;
106 /** Pointer to back to the debug info module (no reference ofc). */
107 PRTDBGMODINT pMod;
108
109 /** DWARF debug info sections. */
110 struct
111 {
112 /** The file offset of the part. */
113 RTFOFF offFile;
114 /** The size of the part. */
115 size_t cb;
116 /** The memory mapping of the part. */
117 void const *pv;
118 /** Set if present. */
119 bool fPresent;
120 } aSections[krtDbgModDwarfSect_End];
121} RTDBGMODDWARF;
122/** Pointer to instance data of the DWARF reader. */
123typedef RTDBGMODDWARF *PRTDBGMODDWARF;
124
125/**
126 * Section reader instance.
127 */
128typedef struct RTDWARFSECTRDR
129{
130 /** The current position. */
131 uint8_t const *pb;
132 /** The number of bytes left to read. */
133 size_t cbLeft;
134 /** The number of bytes left to read in the current unit. */
135 size_t cbUnitLeft;
136 /** The DWARF debug info reader instance. */
137 PRTDBGMODDWARF pDwarfMod;
138 /** Set if this is 64-bit DWARF, clear if 32-bit. */
139 bool f64bitDwarf;
140 /** Set if the format endian is native, clear if endian needs to be
141 * inverted. */
142 bool fNativEndian;
143 /** The size of a native address. */
144 uint8_t cbNativeAddr;
145 /** The cursor status code. This is VINF_SUCCESS until some error
146 * occurs. */
147 int rc;
148} RTDWARFCURSOR;
149/** Pointer to a DWARF section reader. */
150typedef RTDWARFCURSOR *PRTDWARFCURSOR;
151
152
153#define VERR_DWARF_BAD_LINE_NUMBER_HEADER -55555
154#define VERR_DWARF_UNEXPECTED_END -55554
155#define VERR_DWARF_LEB_OVERFLOW -55553
156#define VERR_DWARF_BAD_LNE -55552
157
158
159/**
160 * Loads a DWARF section from the image file.
161 *
162 * @returns IPRT status code.
163 * @param pThis The DWARF instance.
164 * @param enmSect The section to load.
165 */
166static int rtDbgModDwarfLoadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect enmSect)
167{
168 /*
169 * Don't load stuff twice.
170 */
171 if (pThis->aSections[enmSect].pv)
172 return VINF_SUCCESS;
173
174 /*
175 * Sections that are not present cannot be loaded, treat them like they
176 * are empty
177 */
178 if (!pThis->aSections[enmSect].fPresent)
179 {
180 Assert(pThis->aSections[enmSect].cb);
181 return VINF_SUCCESS;
182 }
183 if (!pThis->aSections[enmSect].cb)
184 return VINF_SUCCESS;
185
186 /*
187 * Sections must be readable with the current image interface.
188 */
189 if (pThis->aSections[enmSect].offFile < 0)
190 return VERR_OUT_OF_RANGE;
191
192 /*
193 * Do the job.
194 */
195 return pThis->pMod->pImgVt->pfnMapPart(pThis->pMod, pThis->aSections[enmSect].offFile, pThis->aSections[enmSect].cb,
196 &pThis->aSections[enmSect].pv);
197}
198
199
200/**
201 * Unloads a DWARF section previously mapped by rtDbgModDwarfLoadSection.
202 *
203 * @returns IPRT status code.
204 * @param pThis The DWARF instance.
205 * @param enmSect The section to unload.
206 */
207static int rtDbgModDwarfUnloadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect enmSect)
208{
209 if (!pThis->aSections[enmSect].pv)
210 return VINF_SUCCESS;
211
212 int rc = pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[enmSect].cb, &pThis->aSections[enmSect].pv);
213 AssertRC(rc);
214 return rc;
215}
216
217
218/**
219 * Converts to UTF-8 or otherwise makes sure it's valid UTF-8.
220 *
221 * @returns IPRT status code.
222 * @param pThis The DWARF instance.
223 * @param ppsz Pointer to the string pointer. May be
224 * reallocated (RTStr*).
225 */
226static int rtDbgModDwarfStringToUtf8(PRTDBGMODDWARF pThis, char **ppsz)
227{
228 RTStrPurgeEncoding(*ppsz);
229 return VINF_SUCCESS;
230}
231
232
233/**
234 * Convers a link address into a segment+offset or RVA.
235 *
236 * @returns IPRT status code.
237 * @param pThis The DWARF instance.
238 * @param LinkAddress The address to convert..
239 * @param piSeg The segment index.
240 * @param poffSeg Where to return the segment offset.
241 */
242static int rtDbgModDwarfLinkAddressToSegOffset(PRTDBGMODDWARF pThis, uint64_t LinkAddress,
243 PRTDBGSEGIDX piSeg, PRTUINTPTR poffSeg)
244{
245 /** @todo The image should be doing this conversion, not we. */
246 *piSeg = RTDBGSEGIDX_RVA;
247 *poffSeg = LinkAddress;
248 return VINF_SUCCESS;
249}
250
251
252static uint8_t rtDwarfCursor_GetU8(PRTDWARFCURSOR pCursor, uint8_t uErrValue)
253{
254 if (pCursor->cbUnitLeft < 1)
255 {
256 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
257 return uErrValue;
258 }
259
260 uint8_t u8 = pCursor->pb[0];
261 pCursor->pb += 1;
262 pCursor->cbUnitLeft -= 1;
263 pCursor->cbLeft -= 1;
264 return u8;
265}
266
267
268static uint16_t rtDwarfCursor_GetU16(PRTDWARFCURSOR pCursor, uint16_t uErrValue)
269{
270 if (pCursor->cbUnitLeft < 2)
271 {
272 pCursor->pb += pCursor->cbUnitLeft;
273 pCursor->cbLeft -= pCursor->cbUnitLeft;
274 pCursor->cbUnitLeft = 0;
275 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
276 return uErrValue;
277 }
278
279 uint16_t u16 = RT_MAKE_U16(pCursor->pb[0], pCursor->pb[1]);
280 pCursor->pb += 2;
281 pCursor->cbUnitLeft -= 2;
282 pCursor->cbLeft -= 2;
283 if (!pCursor->fNativEndian)
284 u16 = RT_BSWAP_U16(u16);
285 return u16;
286}
287
288
289static uint32_t rtDwarfCursor_GetU32(PRTDWARFCURSOR pCursor, uint32_t uErrValue)
290{
291 if (pCursor->cbUnitLeft < 4)
292 {
293 pCursor->pb += pCursor->cbUnitLeft;
294 pCursor->cbLeft -= pCursor->cbUnitLeft;
295 pCursor->cbUnitLeft = 0;
296 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
297 return uErrValue;
298 }
299
300 uint32_t u32 = RT_MAKE_U32_FROM_U8(pCursor->pb[0], pCursor->pb[1], pCursor->pb[2], pCursor->pb[3]);
301 pCursor->pb += 4;
302 pCursor->cbUnitLeft -= 4;
303 pCursor->cbLeft -= 4;
304 if (!pCursor->fNativEndian)
305 u32 = RT_BSWAP_U32(u32);
306 return u32;
307}
308
309
310static uint64_t rtDwarfCursor_GetU64(PRTDWARFCURSOR pCursor, uint64_t uErrValue)
311{
312 if (pCursor->cbUnitLeft < 8)
313 {
314 pCursor->pb += pCursor->cbUnitLeft;
315 pCursor->cbLeft -= pCursor->cbUnitLeft;
316 pCursor->cbUnitLeft = 0;
317 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
318 return uErrValue;
319 }
320
321 uint64_t u64 = RT_MAKE_U64_FROM_U8(pCursor->pb[0], pCursor->pb[1], pCursor->pb[2], pCursor->pb[3],
322 pCursor->pb[4], pCursor->pb[5], pCursor->pb[6], pCursor->pb[7]);
323 pCursor->pb += 8;
324 pCursor->cbUnitLeft -= 8;
325 pCursor->cbLeft -= 8;
326 if (!pCursor->fNativEndian)
327 u64 = RT_BSWAP_U64(u64);
328 return u64;
329}
330
331
332/**
333 * Gets a unsigned LEB128 encoded number.
334 *
335 * @returns unsigned number.
336 * @param pCursor The cursor.
337 * @param uErrValue The value to return on error.
338 */
339static uint64_t rtDwarfCursor_GetULeb128(PRTDWARFCURSOR pCursor, uint64_t uErrValue)
340{
341 if (pCursor->cbUnitLeft < 1)
342 {
343 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
344 return uErrValue;
345 }
346
347 /*
348 * Special case - single byte.
349 */
350 uint8_t b = pCursor->pb[0];
351 if (!(b & 0x80))
352 {
353 pCursor->pb += 1;
354 pCursor->cbUnitLeft -= 1;
355 pCursor->cbLeft -= 1;
356 return b;
357 }
358
359 /*
360 * Generic case.
361 */
362 /* Decode. */
363 uint32_t off = 1;
364 uint64_t u64Ret = b & 0x7f;
365 do
366 {
367 if (off == pCursor->cbUnitLeft)
368 {
369 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
370 u64Ret = uErrValue;
371 break;
372 }
373 b = pCursor->pb[off];
374 u64Ret |= (b & 0x7f) << off * 7;
375 off++;
376 } while (b & 0x80);
377
378 /* Update the cursor. */
379 pCursor->pb += off;
380 pCursor->cbUnitLeft -= off;
381 pCursor->cbLeft -= off;
382
383 /* Check the range. */
384 uint32_t cBits = off * 7;
385 if (cBits > 64)
386 {
387 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
388 u64Ret = uErrValue;
389 }
390
391 return u64Ret;
392}
393
394
395/**
396 * Gets a signed LEB128 encoded number.
397 *
398 * @returns signed number.
399 * @param pCursor The cursor.
400 * @param sErrValue The value to return on error.
401 */
402static int64_t rtDwarfCursor_GetSLeb128(PRTDWARFCURSOR pCursor, int64_t sErrValue)
403{
404 if (pCursor->cbUnitLeft < 1)
405 {
406 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
407 return sErrValue;
408 }
409
410 /*
411 * Special case - single byte.
412 */
413 uint8_t b = pCursor->pb[0];
414 if (!(b & 0x80))
415 {
416 pCursor->pb += 1;
417 pCursor->cbUnitLeft -= 1;
418 pCursor->cbLeft -= 1;
419 if (b & 0x40)
420 b |= 0x80;
421 return (int8_t)b;
422 }
423
424 /*
425 * Generic case.
426 */
427 /* Decode it. */
428 uint32_t off = 1;
429 uint64_t u64Ret = b & 0x7f;
430 do
431 {
432 if (off == pCursor->cbUnitLeft)
433 {
434 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
435 u64Ret = (uint64_t)sErrValue;
436 break;
437 }
438 b = pCursor->pb[off];
439 u64Ret |= (b & 0x7f) << off * 7;
440 off++;
441 } while (b & 0x80);
442
443 /* Update cursor. */
444 pCursor->pb += off;
445 pCursor->cbUnitLeft -= off;
446 pCursor->cbLeft -= off;
447
448 /* Check the range. */
449 uint32_t cBits = off * 7;
450 if (cBits > 64)
451 {
452 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
453 u64Ret = (uint64_t)sErrValue;
454 }
455 /* Sign extend the value. */
456 else if (u64Ret & RT_BIT_64(cBits - 1))
457 u64Ret |= ~RT_BIT_64(cBits - 1);
458
459 return (int64_t)u64Ret;
460}
461
462
463/**
464 * Gets a unsigned LEB128 encoded number, max 32-bit width.
465 *
466 * @returns unsigned number.
467 * @param pCursor The cursor.
468 * @param uErrValue The value to return on error.
469 */
470static uint32_t rtDwarfCursor_GetULeb128AsU32(PRTDWARFCURSOR pCursor, uint32_t uErrValue)
471{
472 uint64_t u64 = rtDwarfCursor_GetULeb128(pCursor, uErrValue);
473 if (u64 > UINT32_MAX)
474 {
475 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
476 return uErrValue;
477 }
478 return (uint32_t)u64;
479}
480
481
482/**
483 * Gets a signed LEB128 encoded number, max 32-bit width.
484 *
485 * @returns unsigned number.
486 * @param pCursor The cursor.
487 * @param sErrValue The value to return on error.
488 */
489static int32_t rtDwarfCursor_GetSLeb128AsS32(PRTDWARFCURSOR pCursor, int32_t sErrValue)
490{
491 int64_t s64 = rtDwarfCursor_GetSLeb128(pCursor, sErrValue);
492 if (s64 > INT32_MAX || s64 < INT32_MIN)
493 {
494 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
495 return sErrValue;
496 }
497 return (int32_t)s64;
498}
499
500
501static int rtDwarfCursor_SkipLeb128(PRTDWARFCURSOR pCursor)
502{
503 if (pCursor->cbUnitLeft < 1)
504 return pCursor->rc = VERR_DWARF_UNEXPECTED_END;
505
506 uint32_t offSkip = 1;
507 if (pCursor->pb[0] & 0x80)
508 do
509 {
510 if (offSkip == pCursor->cbUnitLeft)
511 {
512 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
513 break;
514 }
515 } while (pCursor->pb[offSkip++] & 0x80);
516
517 pCursor->pb += offSkip;
518 pCursor->cbUnitLeft -= offSkip;
519 pCursor->cbLeft -= offSkip;
520 return pCursor->rc;
521}
522
523
524
525/**
526 * Reads a zero terminated string, advancing the cursor beyond the terminator.
527 *
528 * @returns Pointer to the string.
529 * @param pCursor The cursor.
530 * @param pszErrValue What to return if the string isn't terminated
531 * before the end of the unit.
532 */
533static const char *rtDwarfCursor_GetSZ(PRTDWARFCURSOR pCursor, const char *pszErrValue)
534{
535 const char *pszRet = (const char *)pCursor->pb;
536 for (;;)
537 {
538 if (!pCursor->cbUnitLeft)
539 return pszErrValue;
540 pCursor->cbUnitLeft--;
541 pCursor->cbLeft--;
542 if (!*pCursor->pb++)
543 break;
544 }
545 return pszRet;
546}
547
548
549
550static uint16_t rtDwarfCursor_GetUHalf(PRTDWARFCURSOR pCursor, uint16_t uErrValue)
551{
552 return rtDwarfCursor_GetU16(pCursor, uErrValue);
553}
554
555
556static uint8_t rtDwarfCursor_GetUByte(PRTDWARFCURSOR pCursor, uint8_t uErrValue)
557{
558 return rtDwarfCursor_GetU8(pCursor, uErrValue);
559}
560
561
562static int8_t rtDwarfCursor_GetSByte(PRTDWARFCURSOR pCursor, int8_t iErrValue)
563{
564 return (int8_t)rtDwarfCursor_GetU8(pCursor, (uint8_t)iErrValue);
565}
566
567
568static uint64_t rtDwarfCursor_GetUOff(PRTDWARFCURSOR pCursor, uint64_t uErrValue)
569{
570 if (pCursor->f64bitDwarf)
571 return rtDwarfCursor_GetU64(pCursor, uErrValue);
572 return rtDwarfCursor_GetU32(pCursor, (uint32_t)uErrValue);
573}
574
575
576/**
577 * Gets the unit length, updating the unit length member and DWARF bitness
578 * members of the cursor.
579 *
580 * @returns The unit length.
581 * @param pCursor The cursor.
582 */
583static uint64_t rtDwarfCursor_GetInitalLength(PRTDWARFCURSOR pCursor)
584{
585 /*
586 * Read the initial length.
587 */
588 pCursor->cbUnitLeft = pCursor->cbLeft;
589 uint64_t cbUnit = rtDwarfCursor_GetU32(pCursor, 0);
590 if (cbUnit != UINT32_C(0xffffffff))
591 pCursor->f64bitDwarf = false;
592 else
593 {
594 pCursor->f64bitDwarf = true;
595 cbUnit = rtDwarfCursor_GetU64(pCursor, 0);
596 }
597
598
599 /*
600 * Set the unit length, quitely fixing bad lengths.
601 */
602 pCursor->cbUnitLeft = (size_t)cbUnit;
603 if ( pCursor->cbUnitLeft > pCursor->cbLeft
604 || pCursor->cbUnitLeft != cbUnit)
605 pCursor->cbUnitLeft = pCursor->cbLeft;
606
607 return cbUnit;
608}
609
610
611static bool rtDwarfCursor_IsAtEndOfUnit(PRTDWARFCURSOR pCursor)
612{
613 return pCursor->cbUnitLeft > 0;
614}
615
616
617static int rtDwarfCursor_SkipUnit(PRTDWARFCURSOR pCursor)
618{
619 pCursor->pb += pCursor->cbUnitLeft;
620 pCursor->cbLeft -= pCursor->cbUnitLeft;
621 pCursor->cbUnitLeft = 0;
622 return VINF_SUCCESS;
623}
624
625
626static bool rtDwarfCursor_IsAtEnd(PRTDWARFCURSOR pCursor)
627{
628 return pCursor->cbLeft > 0;
629}
630
631
632/**
633 * Initialize a section reader.
634 *
635 * @returns IPRT status code.
636 * @param pCursor The section reader.
637 * @param pThis The dwarf module.
638 * @param enmSect .
639 */
640static int rtDwarfCursor_Init(PRTDWARFCURSOR pCursor, PRTDBGMODDWARF pThis, krtDbgModDwarfSect enmSect)
641{
642 int rc = rtDbgModDwarfLoadSection(pThis, enmSect);
643 if (RT_FAILURE(rc))
644 return rc;
645
646 pCursor->pb = (uint8_t const *)pThis->aSections[enmSect].pv;
647 pCursor->cbLeft = pThis->aSections[enmSect].cb;
648 pCursor->cbUnitLeft = pCursor->cbLeft;
649 pCursor->pDwarfMod = pThis;
650 pCursor->fNativEndian = true; /** @todo endian */
651 pCursor->f64bitDwarf = false;
652 pCursor->cbNativeAddr = 4;
653 pCursor->rc = VINF_SUCCESS;
654
655 /** @todo ask the image about the endian used as well as the address
656 * width. */
657
658 return VINF_SUCCESS;
659}
660
661
662/**
663 * Deletes a section reader initialized by rtDwarfCursor_Init.
664 *
665 * @param pCursor The section reader.
666 */
667static void rtDwarfCursor_Delete(PRTDWARFCURSOR pCursor)
668{
669 /* ... and a drop of poison. */
670 pCursor->pb = NULL;
671 pCursor->cbLeft = ~(size_t)0;
672 pCursor->cbUnitLeft = ~(size_t)0;
673 pCursor->pDwarfMod = NULL;
674 pCursor->rc = VERR_INTERNAL_ERROR_4;
675}
676
677
678/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
679static DECLCALLBACK(int) rtDbgModDwarf_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
680 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
681{
682 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
683 return RTDbgModLineByAddr(pThis->hCnt, iSeg, off, poffDisp, pLineInfo);
684}
685
686
687/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
688static DECLCALLBACK(int) rtDbgModDwarf_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
689{
690 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
691 return RTDbgModLineByOrdinal(pThis->hCnt, iOrdinal, pLineInfo);
692}
693
694
695/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
696static DECLCALLBACK(uint32_t) rtDbgModDwarf_LineCount(PRTDBGMODINT pMod)
697{
698 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
699 return RTDbgModLineCount(pThis->hCnt);
700}
701
702
703/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
704static DECLCALLBACK(int) rtDbgModDwarf_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
705 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
706{
707 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
708 return RTDbgModLineAdd(pThis->hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
709}
710
711
712/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
713static DECLCALLBACK(int) rtDbgModDwarf_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
714 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
715{
716 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
717 return RTDbgModSymbolByAddr(pThis->hCnt, iSeg, off, poffDisp, pSymInfo);
718}
719
720
721/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
722static DECLCALLBACK(int) rtDbgModDwarf_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
723 PRTDBGSYMBOL pSymInfo)
724{
725 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
726 Assert(!pszSymbol[cchSymbol]);
727 return RTDbgModSymbolByName(pThis->hCnt, pszSymbol/*, cchSymbol*/, pSymInfo);
728}
729
730
731/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
732static DECLCALLBACK(int) rtDbgModDwarf_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
733{
734 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
735 return RTDbgModSymbolByOrdinal(pThis->hCnt, iOrdinal, pSymInfo);
736}
737
738
739/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
740static DECLCALLBACK(uint32_t) rtDbgModDwarf_SymbolCount(PRTDBGMODINT pMod)
741{
742 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
743 return RTDbgModSymbolCount(pThis->hCnt);
744}
745
746
747/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
748static DECLCALLBACK(int) rtDbgModDwarf_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
749 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
750 uint32_t *piOrdinal)
751{
752 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
753 return RTDbgModSymbolAdd(pThis->hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
754}
755
756
757/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
758static DECLCALLBACK(int) rtDbgModDwarf_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
759{
760 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
761 return RTDbgModSegmentByIndex(pThis->hCnt, iSeg, pSegInfo);
762}
763
764
765/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
766static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDwarf_SegmentCount(PRTDBGMODINT pMod)
767{
768 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
769 return RTDbgModSegmentCount(pThis->hCnt);
770}
771
772
773/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
774static DECLCALLBACK(int) rtDbgModDwarf_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
775 uint32_t fFlags, PRTDBGSEGIDX piSeg)
776{
777 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
778 return RTDbgModSegmentAdd(pThis->hCnt, uRva, cb, pszName, fFlags, piSeg);
779}
780
781
782/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
783static DECLCALLBACK(RTUINTPTR) rtDbgModDwarf_ImageSize(PRTDBGMODINT pMod)
784{
785 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
786 RTUINTPTR cb1 = RTDbgModImageSize(pThis->hCnt);
787 RTUINTPTR cb2 = pMod->pImgVt->pfnImageSize(pMod);
788 return RT_MAX(cb1, cb2);
789}
790
791
792/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
793static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDwarf_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
794{
795 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
796 return RTDbgModRvaToSegOff(pThis->hCnt, uRva, poffSeg);
797}
798
799
800/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
801static DECLCALLBACK(int) rtDbgModDwarf_Close(PRTDBGMODINT pMod)
802{
803 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
804
805 for (unsigned iSect = 0; iSect < RT_ELEMENTS(pThis->aSections); iSect++)
806 if (pThis->aSections[iSect].pv)
807 pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb, &pThis->aSections[iSect].pv);
808
809 RTDbgModRelease(pThis->hCnt);
810 RTMemFree(pThis);
811
812 return VINF_SUCCESS;
813}
814
815
816/**
817 * DWARF line number program state.
818 */
819typedef struct RTDWARFLINESTATE
820{
821 /** Registers */
822 struct
823 {
824 uint64_t uAddress;
825 uint32_t idxOp;
826 uint32_t iFile;
827 uint32_t uLine;
828 uint32_t uColumn;
829 bool fIsStatement;
830 bool fBasicBlock;
831 bool fEndSequence;
832 bool fPrologueEnd;
833 bool fEpilogueBegin;
834 uint32_t uIsa;
835 uint32_t uDiscriminator;
836 } Regs;
837 /** @} */
838
839 /** @name Header
840 * @{ */
841 uint32_t uVer;
842 uint64_t cbSkipAfterHdr;
843 uint8_t cbMinInstr;
844 uint8_t cMaxOpsPerInstr;
845 uint8_t u8DefIsStmt;
846 int8_t s8LineBase;
847 uint8_t u8LineRange;
848 uint8_t u8OpcodeBase;
849 uint8_t const *pacStdOperands;
850 /** @} */
851
852 /** @name Include Path Table (0-based)
853 * @{ */
854 const char **papszIncPaths;
855 uint32_t cIncPaths;
856 /** @} */
857
858 /** @name File Name Table (1-based)
859 * @{ */
860 char **papszFileNames;
861 uint32_t cFileNames;
862 /** @} */
863
864 /** The DWARF debug info reader instance. */
865 PRTDBGMODDWARF pDwarfMod;
866} RTDWARFLINESTATE;
867/** Pointer to a DWARF line number program state. */
868typedef RTDWARFLINESTATE *PRTDWARFLINESTATE;
869
870
871static int rtDwarfLine_DefineFileName(PRTDWARFLINESTATE pLnState, const char *pszFilename, uint64_t idxInc)
872{
873 /*
874 * Resize the array if necessary.
875 */
876 size_t iFileName = pLnState->cFileNames;
877 if ((iFileName % 2) == 0)
878 {
879 void *pv = RTMemRealloc(pLnState->papszFileNames, sizeof(pLnState->papszFileNames[0]) * (iFileName + 2));
880 if (!pv)
881 return VERR_NO_MEMORY;
882 pLnState->papszFileNames = (char **)pv;
883 }
884
885 /*
886 * Add the file name.
887 */
888 if ( pszFilename[0] == '/'
889 || pszFilename[0] == '\\'
890 || (RT_C_IS_ALPHA(pszFilename[0]) && pszFilename[1] == ':') )
891 pLnState->papszFileNames[iFileName] = RTStrDup(pszFilename);
892 else if (idxInc < pLnState->cIncPaths)
893 pLnState->papszFileNames[iFileName] = RTPathJoinA(pLnState->papszIncPaths[idxInc], pszFilename);
894 else
895 return VERR_DWARF_BAD_LINE_NUMBER_HEADER;
896 if (!pLnState->papszFileNames[iFileName])
897 return VERR_NO_STR_MEMORY;
898 pLnState->cFileNames = iFileName + 1;
899
900 /*
901 * Sanitize the name.
902 */
903 return rtDbgModDwarfStringToUtf8(pLnState->pDwarfMod, &pLnState->papszFileNames[iFileName]);
904}
905
906
907static int rtDwarfLine_StdOp_Copy(PRTDWARFLINESTATE pLnState)
908{
909 const char *pszFile = pLnState->Regs.iFile < pLnState->cFileNames
910 ? pLnState->papszFileNames[pLnState->Regs.iFile]
911 : "<bad file name index>";
912 RTDBGSEGIDX iSeg;
913 RTUINTPTR offSeg;
914 int rc = rtDbgModDwarfLinkAddressToSegOffset(pLnState->pDwarfMod, pLnState->Regs.uAddress, &iSeg, &offSeg);
915 if (RT_SUCCESS(rc))
916 rc = RTDbgModLineAdd(pLnState->pDwarfMod->hCnt, pszFile, pLnState->Regs.uLine, iSeg, offSeg, NULL);
917
918 pLnState->Regs.fBasicBlock = false;
919 pLnState->Regs.fPrologueEnd = false;
920 pLnState->Regs.fEpilogueBegin = false;
921 pLnState->Regs.uDiscriminator = 0;
922 return rc;
923}
924
925
926/**
927 * Reset the program to the start-of-sequence state.
928 *
929 * @param pLnState The line number program state.
930 */
931static void rtDwarfLine_ResetState(PRTDWARFLINESTATE pLnState)
932{
933 pLnState->Regs.uAddress = 0;
934 pLnState->Regs.idxOp = 0;
935 pLnState->Regs.iFile = 1;
936 pLnState->Regs.uLine = 1;
937 pLnState->Regs.uColumn = 0;
938 pLnState->Regs.fIsStatement = RT_BOOL(pLnState->u8DefIsStmt);
939 pLnState->Regs.fBasicBlock = false;
940 pLnState->Regs.fEndSequence = false;
941 pLnState->Regs.fPrologueEnd = false;
942 pLnState->Regs.fEpilogueBegin = false;
943 pLnState->Regs.uIsa = 0;
944 pLnState->Regs.uDiscriminator = 0;
945}
946
947
948/**
949 * Runs the line number program.
950 *
951 * @returns IPRT status code.
952 * @param pLnState The line number program state.
953 * @param pCursor The cursor.
954 */
955static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCursor)
956{
957 int rc = VINF_SUCCESS;
958 rtDwarfLine_ResetState(pLnState);
959 do
960 {
961 uint8_t bOpCode = rtDwarfCursor_GetUByte(pCursor, 0);
962 if (bOpCode > pLnState->u8OpcodeBase)
963 {
964 /*
965 * Special opcode.
966 */
967 bOpCode -= pLnState->u8OpcodeBase;
968 pLnState->Regs.uLine += bOpCode % pLnState->u8LineRange + (int32_t)pLnState->s8LineBase;
969 bOpCode /= pLnState->u8LineRange;
970 pLnState->Regs.uAddress += (pLnState->Regs.idxOp + bOpCode) / pLnState->cMaxOpsPerInstr
971 * pLnState->cbMinInstr;
972 pLnState->Regs.idxOp += (pLnState->Regs.idxOp + bOpCode) % pLnState->cMaxOpsPerInstr;
973
974 rc = rtDwarfLine_StdOp_Copy(pLnState);
975 }
976 else
977 {
978 switch (bOpCode)
979 {
980 /*
981 * Standard opcode.
982 */
983 case DW_LNS_copy:
984 rtDwarfLine_StdOp_Copy(pLnState);
985 break;
986
987 case DW_LNS_advance_pc:
988 {
989 uint64_t u64Adv = rtDwarfCursor_GetULeb128(pCursor, 0);
990 pLnState->Regs.uAddress += (pLnState->Regs.idxOp + u64Adv) / pLnState->cMaxOpsPerInstr
991 * pLnState->cbMinInstr;
992 pLnState->Regs.idxOp += (pLnState->Regs.idxOp + u64Adv) % pLnState->cMaxOpsPerInstr;
993 break;
994 }
995
996 case DW_LNS_advance_line:
997 pLnState->Regs.uLine += rtDwarfCursor_GetSLeb128AsS32(pCursor, 0);
998 break;
999
1000 case DW_LNS_set_file:
1001 pLnState->Regs.iFile = rtDwarfCursor_GetULeb128AsU32(pCursor, 0);
1002 break;
1003
1004 case DW_LNS_set_column:
1005 pLnState->Regs.uColumn = rtDwarfCursor_GetULeb128AsU32(pCursor, 0);
1006 break;
1007
1008 case DW_LNS_negate_stmt:
1009 pLnState->Regs.fIsStatement = !pLnState->Regs.fIsStatement;
1010 break;
1011
1012 case DW_LNS_set_basic_block:
1013 pLnState->Regs.fBasicBlock = true;
1014 break;
1015
1016 case DW_LNS_const_add_pc:
1017 pLnState->Regs.uAddress += (pLnState->Regs.idxOp + 255) / pLnState->cMaxOpsPerInstr
1018 * pLnState->cbMinInstr;
1019 pLnState->Regs.idxOp += (pLnState->Regs.idxOp + 255) % pLnState->cMaxOpsPerInstr;
1020 break;
1021
1022 case DW_LNS_fixed_advance_pc:
1023 pLnState->Regs.uAddress += rtDwarfCursor_GetUHalf(pCursor, 0);
1024 pLnState->Regs.idxOp = 0;
1025 break;
1026
1027 case DW_LNS_set_prologue_end:
1028 pLnState->Regs.fPrologueEnd = true;
1029 break;
1030
1031 case DW_LNS_set_epilogue_begin:
1032 pLnState->Regs.fEpilogueBegin = true;
1033 break;
1034
1035 case DW_LNS_set_isa:
1036 pLnState->Regs.uIsa = rtDwarfCursor_GetULeb128AsU32(pCursor, 0);
1037 break;
1038
1039 default:
1040 {
1041 unsigned cOpsToSkip = pLnState->pacStdOperands[bOpCode - 1];
1042 while (cOpsToSkip-- > 0)
1043 rc = rtDwarfCursor_SkipLeb128(pCursor);
1044 break;
1045 }
1046
1047 /*
1048 * Extended opcode.
1049 */
1050 case DW_LNS_extended:
1051 {
1052 uint64_t cbInstr = rtDwarfCursor_GetULeb128(pCursor, UINT64_MAX);
1053 if (cbInstr > pCursor->cbUnitLeft)
1054 return VERR_DWARF_BAD_LNE;
1055 /** @todo continue here. */
1056 bOpCode = rtDwarfCursor_GetUByte(pCursor, 0);
1057 switch (bOpCode)
1058 {
1059 case DW_LNE_end_sequence:
1060 case DW_LNE_set_address:
1061 case DW_LNE_define_file:
1062 case DW_LNE_set_descriminator:
1063 break;
1064 }
1065 break;
1066 }
1067 }
1068 }
1069 } while (RT_SUCCESS(rc));
1070 return rc;
1071}
1072
1073
1074/**
1075 * Reads the include directories for a line number unit.
1076 *
1077 * @returns IPRT status code
1078 * @param pLnState The line number program state.
1079 * @param pCursor The cursor.
1080 */
1081static int rtDwarfLine_ReadFileNames(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCursor)
1082{
1083 for (;;)
1084 {
1085 const char *psz = rtDwarfCursor_GetSZ(pCursor, NULL);
1086 if (!*psz)
1087 break;
1088
1089 uint64_t idxInc = rtDwarfCursor_GetULeb128(pCursor, UINT64_MAX);
1090 rtDwarfCursor_SkipLeb128(pCursor); /* st_mtime */
1091 rtDwarfCursor_SkipLeb128(pCursor); /* st_size */
1092
1093 int rc = rtDwarfLine_DefineFileName(pLnState, psz, idxInc);
1094 if (RT_FAILURE(rc))
1095 return rc;
1096 }
1097 return VINF_SUCCESS;
1098}
1099
1100
1101/**
1102 * Reads the include directories for a line number unit.
1103 *
1104 * @returns IPRT status code
1105 * @param pLnState The line number program state.
1106 * @param pCursor The cursor.
1107 */
1108static int rtDwarfLine_ReadIncludePaths(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCursor)
1109{
1110 const char *psz = ""; /* The zeroth is the unit dir. */
1111 for (;;)
1112 {
1113 if ((pLnState->cIncPaths % 2) == 0)
1114 {
1115 void *pv = RTMemRealloc(pLnState->papszIncPaths, sizeof(pLnState->papszIncPaths[0]) * (pLnState->cIncPaths + 2));
1116 if (!pv)
1117 return VERR_NO_MEMORY;
1118 pLnState->papszIncPaths = (const char **)pv;
1119 }
1120 pLnState->papszIncPaths[pLnState->cIncPaths] = psz;
1121 pLnState->cIncPaths++;
1122
1123 psz = rtDwarfCursor_GetSZ(pCursor, NULL);
1124 if (!*psz)
1125 break;
1126 }
1127
1128 return VINF_SUCCESS;
1129}
1130
1131
1132static int rtDbgModDwarfExplodeLineNumbersForUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor)
1133{
1134 RTDWARFLINESTATE LnState;
1135 RT_ZERO(LnState);
1136 LnState.pDwarfMod = pThis;
1137
1138 /*
1139 * Parse the header.
1140 */
1141 LnState.uVer = rtDwarfCursor_GetUHalf(pCursor, 0);
1142 if (LnState.uVer >= 2 && LnState.uVer <= 4)
1143 return rtDwarfCursor_SkipUnit(pCursor);
1144 LnState.cbSkipAfterHdr = rtDwarfCursor_GetUOff(pCursor, 0);
1145 LnState.cbMinInstr = rtDwarfCursor_GetUByte(pCursor, 0);
1146 LnState.cMaxOpsPerInstr= rtDwarfCursor_GetUByte(pCursor, 0);
1147 LnState.u8DefIsStmt = rtDwarfCursor_GetUByte(pCursor, 0);
1148 LnState.s8LineBase = rtDwarfCursor_GetSByte(pCursor, 0);
1149 LnState.u8LineRange = rtDwarfCursor_GetUByte(pCursor, 0);
1150 LnState.u8OpcodeBase = rtDwarfCursor_GetUByte(pCursor, 0);
1151 if (!LnState.u8OpcodeBase)
1152 return VERR_DWARF_BAD_LINE_NUMBER_HEADER;
1153
1154 LnState.pacStdOperands = pCursor->pb;
1155 for (uint8_t iStdOpcode = 1; iStdOpcode < LnState.u8OpcodeBase; iStdOpcode++)
1156 rtDwarfCursor_GetUByte(pCursor, 0);
1157
1158 int rc = rtDwarfLine_ReadIncludePaths(&LnState, pCursor);
1159 if (RT_SUCCESS(rc))
1160 rc = rtDwarfLine_ReadFileNames(&LnState, pCursor);
1161
1162 /*
1163 * Run the program....
1164 */
1165 if (RT_SUCCESS(rc))
1166 rc = rtDwarfLine_RunProgram(&LnState, pCursor);
1167
1168 /*
1169 * Clean up.
1170 */
1171 size_t i = LnState.cFileNames;
1172 while (i-- > 0)
1173 RTStrFree(LnState.papszFileNames[i]);
1174 RTMemFree(LnState.papszFileNames);
1175 RTMemFree(LnState.papszIncPaths);
1176
1177 Assert(rtDwarfCursor_IsAtEndOfUnit(pCursor) || RT_FAILURE(rc));
1178 return rc;
1179}
1180
1181
1182/**
1183 * Explodes the line number table.
1184 *
1185 * The line numbers are insered into the debug info container.
1186 *
1187 * @returns IPRT status code
1188 * @param pThis The DWARF instance.
1189 */
1190static int rtDbgModDwarfExplodeLineNumbers(PRTDBGMODDWARF pThis)
1191{
1192 if (!pThis->aSections[krtDbgModDwarfSect_line].fPresent)
1193 return VINF_SUCCESS;
1194
1195 RTDWARFCURSOR Cursor;
1196 int rc = rtDwarfCursor_Init(&Cursor, pThis, krtDbgModDwarfSect_line);
1197 if (RT_FAILURE(rc))
1198 return rc;
1199
1200 while ( rtDwarfCursor_IsAtEnd(&Cursor)
1201 && RT_SUCCESS(rc))
1202 rc = rtDbgModDwarfExplodeLineNumbersForUnit(pThis, &Cursor);
1203
1204
1205 rtDwarfCursor_Delete(&Cursor);
1206 return rc;
1207}
1208
1209
1210/**
1211 * Extracts the symbols.
1212 *
1213 * The symbols are insered into the debug info container.
1214 *
1215 * @returns IPRT status code
1216 * @param pThis The DWARF instance.
1217 */
1218static int rtDbgModDwarfExtractSymbols(PRTDBGMODDWARF pThis)
1219{
1220 int rc = rtDbgModDwarfLoadSection(pThis, krtDbgModDwarfSect_info);
1221 if (RT_FAILURE(rc))
1222 return rc;
1223
1224 /** @todo */
1225
1226 rtDbgModDwarfUnloadSection(pThis, krtDbgModDwarfSect_info);
1227 return rc;
1228}
1229
1230
1231/**
1232 * Loads the abbreviations used to parse the info section.
1233 *
1234 * @returns IPRT status code
1235 * @param pThis The DWARF instance.
1236 */
1237static int rtDbgModDwarfLoadAbbreviations(PRTDBGMODDWARF pThis)
1238{
1239 int rc = rtDbgModDwarfLoadSection(pThis, krtDbgModDwarfSect_abbrev);
1240 if (RT_FAILURE(rc))
1241 return rc;
1242
1243#if 0 /** @todo */
1244 size_t cbLeft = pThis->aSections[krtDbgModDwarfSect_abbrev].cb;
1245 uint8_t const *pb = (uint8_t const *)pThis->aSections[krtDbgModDwarfSect_abbrev].pv;
1246 while (cbLeft > 0)
1247 {
1248
1249 }
1250#endif
1251
1252 rtDbgModDwarfUnloadSection(pThis, krtDbgModDwarfSect_abbrev);
1253 return rc;
1254}
1255
1256
1257/** @callback_method_impl{FNRTLDRENUMSEGS} */
1258static DECLCALLBACK(int) rtDbgModHlpAddSegmentCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
1259{
1260 PRTDBGMODINT pMod = (PRTDBGMODINT)pvUser;
1261 return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->RVA, pSeg->cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
1262}
1263
1264
1265/**
1266 * Calls pfnSegmentAdd for each segment in the executable image.
1267 *
1268 * @returns IPRT status code.
1269 * @param pMod The debug module.
1270 */
1271DECLHIDDEN(int) rtDbgModHlpAddSegmentsFromImage(PRTDBGMODINT pMod)
1272{
1273 AssertReturn(pMod->pImgVt, VERR_INTERNAL_ERROR_2);
1274 return pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModHlpAddSegmentCallback, pMod);
1275}
1276
1277
1278/** @callback_method_impl{FNRTLDRENUMDBG} */
1279static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iDbgInfo, RTLDRDBGINFOTYPE enmType,
1280 uint16_t iMajorVer, uint16_t iMinorVer, const char *pszPartNm,
1281 RTFOFF offFile, RTLDRADDR LinkAddress, RTLDRADDR cb,
1282 const char *pszExtFile, void *pvUser)
1283{
1284 /*
1285 * Skip stuff we can't handle.
1286 */
1287 if ( enmType != RTLDRDBGINFOTYPE_DWARF
1288 || !pszPartNm
1289 || pszExtFile)
1290 return VINF_SUCCESS;
1291
1292 /*
1293 * Must have a part name starting with debug_ and possibly prefixed by dots
1294 * or underscores.
1295 */
1296 if (!strncmp(pszPartNm, ".debug_", sizeof(".debug_") - 1)) /* ELF */
1297 pszPartNm += sizeof(".debug_") - 1;
1298 else if (!strncmp(pszPartNm, "__debug_", sizeof("__debug_") - 1)) /* Mach-O */
1299 pszPartNm += sizeof("__debug_") - 1;
1300 else
1301 AssertMsgFailedReturn(("%s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
1302
1303 /*
1304 * Figure out which part we're talking about.
1305 */
1306 krtDbgModDwarfSect enmSect;
1307 if (0) { /* dummy */ }
1308#define ELSE_IF_STRCMP_SET(a_Name) else if (!strcmp(pszPartNm, #a_Name)) enmSect = krtDbgModDwarfSect_ ## a_Name
1309 ELSE_IF_STRCMP_SET(abbrev);
1310 ELSE_IF_STRCMP_SET(aranges);
1311 ELSE_IF_STRCMP_SET(frame);
1312 ELSE_IF_STRCMP_SET(info);
1313 ELSE_IF_STRCMP_SET(inlined);
1314 ELSE_IF_STRCMP_SET(line);
1315 ELSE_IF_STRCMP_SET(loc);
1316 ELSE_IF_STRCMP_SET(macinfo);
1317 ELSE_IF_STRCMP_SET(pubnames);
1318 ELSE_IF_STRCMP_SET(pubtypes);
1319 ELSE_IF_STRCMP_SET(ranges);
1320 ELSE_IF_STRCMP_SET(str);
1321 ELSE_IF_STRCMP_SET(types);
1322#undef ELSE_IF_STRCMP_SET
1323 else
1324 {
1325 AssertMsgFailed(("%s\n", pszPartNm));
1326 return VINF_SUCCESS;
1327 }
1328
1329 /*
1330 * Record the section.
1331 */
1332 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
1333 AssertMsgReturn(!pThis->aSections[enmSect].fPresent, ("duplicate %s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
1334
1335 pThis->aSections[enmSect].fPresent = true;
1336 pThis->aSections[enmSect].offFile = offFile;
1337 pThis->aSections[enmSect].pv = NULL;
1338 pThis->aSections[enmSect].cb = (size_t)cb;
1339 if (pThis->aSections[enmSect].cb != cb)
1340 pThis->aSections[enmSect].cb = ~(size_t)0;
1341
1342 return VINF_SUCCESS;
1343}
1344
1345
1346/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
1347static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
1348{
1349 /*
1350 * DWARF is only supported when part of an image.
1351 */
1352 if (!pMod->pImgVt)
1353 return VERR_DBG_NO_MATCHING_INTERPRETER;
1354
1355 /*
1356 * Enumerate the debug info in the module, looking for DWARF bits.
1357 */
1358 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)RTMemAllocZ(sizeof(*pThis));
1359 if (!pThis)
1360 return VERR_NO_MEMORY;
1361 pThis->pMod = pMod;
1362
1363 int rc = pMod->pImgVt->pfnEnumDbgInfo(pMod, rtDbgModDwarfEnumCallback, pThis);
1364 if (RT_SUCCESS(rc))
1365 {
1366 if (pThis->aSections[krtDbgModDwarfSect_info].fPresent)
1367 {
1368 /*
1369 * Extract / explode the data we want (symbols and line numbers)
1370 * storing them in a container module.
1371 */
1372 rc = RTDbgModCreate(&pThis->hCnt, pMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
1373 if (RT_SUCCESS(rc))
1374 {
1375 pMod->pvDbgPriv = pThis;
1376
1377 rc = rtDbgModHlpAddSegmentsFromImage(pMod);
1378 if (RT_SUCCESS(rc))
1379 rc = rtDbgModDwarfLoadAbbreviations(pThis);
1380 if (RT_SUCCESS(rc))
1381 rc = rtDbgModDwarfExtractSymbols(pThis);
1382 if (RT_SUCCESS(rc))
1383 rc = rtDbgModDwarfExplodeLineNumbers(pThis);
1384 if (RT_SUCCESS(rc))
1385 {
1386 return VINF_SUCCESS;
1387 }
1388
1389 /* bail out. */
1390 RTDbgModRelease(pThis->hCnt);
1391 pMod->pvDbgPriv = NULL;
1392 }
1393 }
1394 else
1395 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
1396 }
1397 RTMemFree(pThis);
1398
1399 return rc;
1400}
1401
1402
1403
1404/** Virtual function table for the DWARF debug info reader. */
1405DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgDwarf =
1406{
1407 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
1408 /*.fSupports = */ RT_DBGTYPE_DWARF,
1409 /*.pszName = */ "dwarf",
1410 /*.pfnTryOpen = */ rtDbgModDwarf_TryOpen,
1411 /*.pfnClose = */ rtDbgModDwarf_Close,
1412
1413 /*.pfnRvaToSegOff = */ rtDbgModDwarf_RvaToSegOff,
1414 /*.pfnImageSize = */ rtDbgModDwarf_ImageSize,
1415
1416 /*.pfnSegmentAdd = */ rtDbgModDwarf_SegmentAdd,
1417 /*.pfnSegmentCount = */ rtDbgModDwarf_SegmentCount,
1418 /*.pfnSegmentByIndex = */ rtDbgModDwarf_SegmentByIndex,
1419
1420 /*.pfnSymbolAdd = */ rtDbgModDwarf_SymbolAdd,
1421 /*.pfnSymbolCount = */ rtDbgModDwarf_SymbolCount,
1422 /*.pfnSymbolByOrdinal = */ rtDbgModDwarf_SymbolByOrdinal,
1423 /*.pfnSymbolByName = */ rtDbgModDwarf_SymbolByName,
1424 /*.pfnSymbolByAddr = */ rtDbgModDwarf_SymbolByAddr,
1425
1426 /*.pfnLineAdd = */ rtDbgModDwarf_LineAdd,
1427 /*.pfnLineCount = */ rtDbgModDwarf_LineCount,
1428 /*.pfnLineByOrdinal = */ rtDbgModDwarf_LineByOrdinal,
1429 /*.pfnLineByAddr = */ rtDbgModDwarf_LineByAddr,
1430
1431 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
1432};
1433
Note: See TracBrowser for help on using the repository browser.

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