VirtualBox

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

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

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.5 KB
Line 
1/* $Id: dbgmoddwarf.cpp 38603 2011-09-01 17:45:36Z 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.215389.xyz. 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#define LOG_GROUP RTLOGGROUP_DBG_DWARF
32#include <iprt/dbg.h>
33#include "internal/iprt.h"
34
35#include <iprt/asm.h>
36#include <iprt/ctype.h>
37#include <iprt/err.h>
38#include <iprt/log.h>
39#include <iprt/mem.h>
40#include <iprt/path.h>
41#include <iprt/string.h>
42#include "internal/dbgmod.h"
43
44
45/*******************************************************************************
46* Defined Constants And Macros *
47*******************************************************************************/
48/** @name Standard DWARF Line Number Opcodes
49 * @{ */
50#define DW_LNS_extended UINT8_C(0)
51#define DW_LNS_copy UINT8_C(1)
52#define DW_LNS_advance_pc UINT8_C(2)
53#define DW_LNS_advance_line UINT8_C(3)
54#define DW_LNS_set_file UINT8_C(4)
55#define DW_LNS_set_column UINT8_C(5)
56#define DW_LNS_negate_stmt UINT8_C(6)
57#define DW_LNS_set_basic_block UINT8_C(7)
58#define DW_LNS_const_add_pc UINT8_C(8)
59#define DW_LNS_fixed_advance_pc UINT8_C(9)
60#define DW_LNS_set_prologue_end UINT8_C(10)
61#define DW_LNS_set_epilogue_begin UINT8_C(11)
62#define DW_LNS_set_isa UINT8_C(12)
63/** @} */
64
65
66/** @name Extended DWARF Line Number Opcodes
67 * @{ */
68#define DW_LNE_end_sequence UINT8_C(1)
69#define DW_LNE_set_address UINT8_C(2)
70#define DW_LNE_define_file UINT8_C(3)
71#define DW_LNE_set_descriminator UINT8_C(4)
72/** @} */
73
74/** @name DIE Tags.
75 * @{ */
76#define DW_TAG_array_type UINT16_C(0x0001)
77#define DW_TAG_class_type UINT16_C(0x0002)
78#define DW_TAG_entry_point UINT16_C(0x0003)
79#define DW_TAG_enumeration_type UINT16_C(0x0004)
80#define DW_TAG_formal_parameter UINT16_C(0x0005)
81#define DW_TAG_imported_declaration UINT16_C(0x0008)
82#define DW_TAG_label UINT16_C(0x000a)
83#define DW_TAG_lexical_block UINT16_C(0x000b)
84#define DW_TAG_member UINT16_C(0x000d)
85#define DW_TAG_pointer_type UINT16_C(0x000f)
86#define DW_TAG_reference_type UINT16_C(0x0010)
87#define DW_TAG_compile_unit UINT16_C(0x0011)
88#define DW_TAG_string_type UINT16_C(0x0012)
89#define DW_TAG_structure_type UINT16_C(0x0013)
90#define DW_TAG_subroutine_type UINT16_C(0x0015)
91#define DW_TAG_typedef UINT16_C(0x0016)
92#define DW_TAG_union_type UINT16_C(0x0017)
93#define DW_TAG_unspecified_parameters UINT16_C(0x0018)
94#define DW_TAG_variant UINT16_C(0x0019)
95#define DW_TAG_common_block UINT16_C(0x001a)
96#define DW_TAG_common_inclusion UINT16_C(0x001b)
97#define DW_TAG_inheritance UINT16_C(0x001c)
98#define DW_TAG_inlined_subroutine UINT16_C(0x001d)
99#define DW_TAG_module UINT16_C(0x001e)
100#define DW_TAG_ptr_to_member_type UINT16_C(0x001f)
101#define DW_TAG_set_type UINT16_C(0x0020)
102#define DW_TAG_subrange_type UINT16_C(0x0021)
103#define DW_TAG_with_stmt UINT16_C(0x0022)
104#define DW_TAG_access_declaration UINT16_C(0x0023)
105#define DW_TAG_base_type UINT16_C(0x0024)
106#define DW_TAG_catch_block UINT16_C(0x0025)
107#define DW_TAG_const_type UINT16_C(0x0026)
108#define DW_TAG_constant UINT16_C(0x0027)
109#define DW_TAG_enumerator UINT16_C(0x0028)
110#define DW_TAG_file_type UINT16_C(0x0029)
111#define DW_TAG_friend UINT16_C(0x002a)
112#define DW_TAG_namelist UINT16_C(0x002b)
113#define DW_TAG_namelist_item UINT16_C(0x002c)
114#define DW_TAG_packed_type UINT16_C(0x002d)
115#define DW_TAG_subprogram UINT16_C(0x002e)
116#define DW_TAG_template_type_parameter UINT16_C(0x002f)
117#define DW_TAG_template_value_parameter UINT16_C(0x0030)
118#define DW_TAG_thrown_type UINT16_C(0x0031)
119#define DW_TAG_try_block UINT16_C(0x0032)
120#define DW_TAG_variant_part UINT16_C(0x0033)
121#define DW_TAG_variable UINT16_C(0x0034)
122#define DW_TAG_volatile_type UINT16_C(0x0035)
123#define DW_TAG_dwarf_procedure UINT16_C(0x0036)
124#define DW_TAG_restrict_type UINT16_C(0x0037)
125#define DW_TAG_interface_type UINT16_C(0x0038)
126#define DW_TAG_namespace UINT16_C(0x0039)
127#define DW_TAG_imported_module UINT16_C(0x003a)
128#define DW_TAG_unspecified_type UINT16_C(0x003b)
129#define DW_TAG_partial_unit UINT16_C(0x003c)
130#define DW_TAG_imported_unit UINT16_C(0x003d)
131#define DW_TAG_condition UINT16_C(0x003f)
132#define DW_TAG_shared_type UINT16_C(0x0040)
133#define DW_TAG_type_unit UINT16_C(0x0041)
134#define DW_TAG_rvalue_reference_type UINT16_C(0x0042)
135#define DW_TAG_template_alias UINT16_C(0x0043)
136#define DW_TAG_lo_user UINT16_C(0x4080)
137#define DW_TAG_hi_user UINT16_C(0xffff)
138/** @} */
139
140/*******************************************************************************
141* Structures and Typedefs *
142*******************************************************************************/
143/**
144 * DWARF sections.
145 */
146typedef enum krtDbgModDwarfSect
147{
148 krtDbgModDwarfSect_abbrev = 0,
149 krtDbgModDwarfSect_aranges,
150 krtDbgModDwarfSect_frame,
151 krtDbgModDwarfSect_info,
152 krtDbgModDwarfSect_inlined,
153 krtDbgModDwarfSect_line,
154 krtDbgModDwarfSect_loc,
155 krtDbgModDwarfSect_macinfo,
156 krtDbgModDwarfSect_pubnames,
157 krtDbgModDwarfSect_pubtypes,
158 krtDbgModDwarfSect_ranges,
159 krtDbgModDwarfSect_str,
160 krtDbgModDwarfSect_types,
161 /** End of valid parts (exclusive). */
162 krtDbgModDwarfSect_End
163} krtDbgModDwarfSect;
164
165/**
166 * Abbreviation cache entry.
167 */
168typedef struct RTDWARFABBREV
169{
170 /** Whether this entry is filled in or not. */
171 bool fFilled;
172 /** Whether there are children or not. */
173 bool fChildren;
174 /** The tag. */
175 uint16_t uTag;
176 /** Offset into the abbrev section of the specification pairs. */
177 uint32_t offSpec;
178} RTDWARFABBREV;
179/** Pointer to an abbreviation cache entry. */
180typedef RTDWARFABBREV *PRTDWARFABBREV;
181/** Pointer to a const abbreviation cache entry. */
182typedef RTDWARFABBREV const *PCRTDWARFABBREV;
183
184
185/**
186 * The instance data of the DWARF reader.
187 */
188typedef struct RTDBGMODDWARF
189{
190 /** The debug container containing doing the real work. */
191 RTDBGMOD hCnt;
192 /** Pointer to back to the debug info module (no reference ofc). */
193 PRTDBGMODINT pMod;
194
195 /** DWARF debug info sections. */
196 struct
197 {
198 /** The file offset of the part. */
199 RTFOFF offFile;
200 /** The size of the part. */
201 size_t cb;
202 /** The memory mapping of the part. */
203 void const *pv;
204 /** Set if present. */
205 bool fPresent;
206 } aSections[krtDbgModDwarfSect_End];
207
208 /** The offset into the abbreviation section of the current cache. */
209 uint32_t offCachedAbbrev;
210 /** The number of cached abbreviations we've allocated space for. */
211 uint32_t cCachedAbbrevsAlloced;
212 /** Used for range checking cache lookups. */
213 uint32_t cCachedAbbrevs;
214 /** Array of cached abbreviations, indexed by code. */
215 PRTDWARFABBREV paCachedAbbrevs;
216 /** Used by rtDwarfAbbrev_Lookup when the result is uncachable. */
217 RTDWARFABBREV LookupAbbrev;
218} RTDBGMODDWARF;
219/** Pointer to instance data of the DWARF reader. */
220typedef RTDBGMODDWARF *PRTDBGMODDWARF;
221
222/**
223 * DWARF cursor for reading byte data.
224 */
225typedef struct RTDWARFSECTRDR
226{
227 /** The current position. */
228 uint8_t const *pb;
229 /** The number of bytes left to read. */
230 size_t cbLeft;
231 /** The number of bytes left to read in the current unit. */
232 size_t cbUnitLeft;
233 /** The DWARF debug info reader instance. */
234 PRTDBGMODDWARF pDwarfMod;
235 /** Set if this is 64-bit DWARF, clear if 32-bit. */
236 bool f64bitDwarf;
237 /** Set if the format endian is native, clear if endian needs to be
238 * inverted. */
239 bool fNativEndian;
240 /** The size of a native address. */
241 uint8_t cbNativeAddr;
242 /** The cursor status code. This is VINF_SUCCESS until some error
243 * occurs. */
244 int rc;
245 /** The start of the area covered by the cursor.
246 * Used for repositioning the cursor relative to the start of a section. */
247 uint8_t const *pbStart;
248 /** The section. */
249 krtDbgModDwarfSect enmSect;
250} RTDWARFCURSOR;
251/** Pointer to a DWARF section reader. */
252typedef RTDWARFCURSOR *PRTDWARFCURSOR;
253
254
255/**
256 * DWARF line number program state.
257 */
258typedef struct RTDWARFLINESTATE
259{
260 /** Virtual Line Number Machine Registers. */
261 struct
262 {
263 uint64_t uAddress;
264 uint64_t idxOp;
265 uint32_t iFile;
266 uint32_t uLine;
267 uint32_t uColumn;
268 bool fIsStatement;
269 bool fBasicBlock;
270 bool fEndSequence;
271 bool fPrologueEnd;
272 bool fEpilogueBegin;
273 uint32_t uIsa;
274 uint32_t uDiscriminator;
275 } Regs;
276 /** @} */
277
278 /** Header. */
279 struct
280 {
281 uint32_t uVer;
282 uint64_t offFirstOpcode;
283 uint8_t cbMinInstr;
284 uint8_t cMaxOpsPerInstr;
285 uint8_t u8DefIsStmt;
286 int8_t s8LineBase;
287 uint8_t u8LineRange;
288 uint8_t u8OpcodeBase;
289 uint8_t const *pacStdOperands;
290 } Hdr;
291
292 /** @name Include Path Table (0-based)
293 * @{ */
294 const char **papszIncPaths;
295 uint32_t cIncPaths;
296 /** @} */
297
298 /** @name File Name Table (0-based, dummy zero entry)
299 * @{ */
300 char **papszFileNames;
301 uint32_t cFileNames;
302 /** @} */
303
304 /** The DWARF debug info reader instance. */
305 PRTDBGMODDWARF pDwarfMod;
306} RTDWARFLINESTATE;
307/** Pointer to a DWARF line number program state. */
308typedef RTDWARFLINESTATE *PRTDWARFLINESTATE;
309
310
311/** @callback_method_impl{FNRTLDRENUMSEGS} */
312static DECLCALLBACK(int) rtDbgModHlpAddSegmentCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
313{
314 PRTDBGMODINT pMod = (PRTDBGMODINT)pvUser;
315 Log(("Segment %.*s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
316 pSeg->cchName, pSeg->pchName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
317 RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
318#if 1
319 return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->RVA, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
320#else
321 return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->LinkAddress, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
322#endif
323}
324
325
326/**
327 * Calls pfnSegmentAdd for each segment in the executable image.
328 *
329 * @returns IPRT status code.
330 * @param pMod The debug module.
331 */
332DECLHIDDEN(int) rtDbgModHlpAddSegmentsFromImage(PRTDBGMODINT pMod)
333{
334 AssertReturn(pMod->pImgVt, VERR_INTERNAL_ERROR_2);
335 return pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModHlpAddSegmentCallback, pMod);
336}
337
338
339
340
341/**
342 * Loads a DWARF section from the image file.
343 *
344 * @returns IPRT status code.
345 * @param pThis The DWARF instance.
346 * @param enmSect The section to load.
347 */
348static int rtDbgModDwarfLoadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect enmSect)
349{
350 /*
351 * Don't load stuff twice.
352 */
353 if (pThis->aSections[enmSect].pv)
354 return VINF_SUCCESS;
355
356 /*
357 * Sections that are not present cannot be loaded, treat them like they
358 * are empty
359 */
360 if (!pThis->aSections[enmSect].fPresent)
361 {
362 Assert(pThis->aSections[enmSect].cb);
363 return VINF_SUCCESS;
364 }
365 if (!pThis->aSections[enmSect].cb)
366 return VINF_SUCCESS;
367
368 /*
369 * Sections must be readable with the current image interface.
370 */
371 if (pThis->aSections[enmSect].offFile < 0)
372 return VERR_OUT_OF_RANGE;
373
374 /*
375 * Do the job.
376 */
377 return pThis->pMod->pImgVt->pfnMapPart(pThis->pMod, pThis->aSections[enmSect].offFile, pThis->aSections[enmSect].cb,
378 &pThis->aSections[enmSect].pv);
379}
380
381
382/**
383 * Unloads a DWARF section previously mapped by rtDbgModDwarfLoadSection.
384 *
385 * @returns IPRT status code.
386 * @param pThis The DWARF instance.
387 * @param enmSect The section to unload.
388 */
389static int rtDbgModDwarfUnloadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect enmSect)
390{
391 if (!pThis->aSections[enmSect].pv)
392 return VINF_SUCCESS;
393
394 int rc = pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[enmSect].cb, &pThis->aSections[enmSect].pv);
395 AssertRC(rc);
396 return rc;
397}
398
399
400/**
401 * Converts to UTF-8 or otherwise makes sure it's valid UTF-8.
402 *
403 * @returns IPRT status code.
404 * @param pThis The DWARF instance.
405 * @param ppsz Pointer to the string pointer. May be
406 * reallocated (RTStr*).
407 */
408static int rtDbgModDwarfStringToUtf8(PRTDBGMODDWARF pThis, char **ppsz)
409{
410 RTStrPurgeEncoding(*ppsz);
411 return VINF_SUCCESS;
412}
413
414
415/**
416 * Convers a link address into a segment+offset or RVA.
417 *
418 * @returns IPRT status code.
419 * @param pThis The DWARF instance.
420 * @param LinkAddress The address to convert..
421 * @param piSeg The segment index.
422 * @param poffSeg Where to return the segment offset.
423 */
424static int rtDbgModDwarfLinkAddressToSegOffset(PRTDBGMODDWARF pThis, uint64_t LinkAddress,
425 PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg)
426{
427 return pThis->pMod->pImgVt->pfnLinkAddressToSegOffset(pThis->pMod, LinkAddress, piSeg, poffSeg);
428}
429
430
431/*
432 *
433 * DWARF Cursor.
434 * DWARF Cursor.
435 * DWARF Cursor.
436 *
437 */
438
439
440/**
441 * Reads a 8-bit unsigned integer and advances the cursor.
442 *
443 * @returns 8-bit unsigned integer. On error RTDWARFCURSOR::rc is set and @a
444 * uErrValue is returned.
445 * @param pCursor The cursor.
446 * @param uErrValue What to return on read error.
447 */
448static uint8_t rtDwarfCursor_GetU8(PRTDWARFCURSOR pCursor, uint8_t uErrValue)
449{
450 if (pCursor->cbUnitLeft < 1)
451 {
452 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
453 return uErrValue;
454 }
455
456 uint8_t u8 = pCursor->pb[0];
457 pCursor->pb += 1;
458 pCursor->cbUnitLeft -= 1;
459 pCursor->cbLeft -= 1;
460 return u8;
461}
462
463
464/**
465 * Reads a 16-bit unsigned integer and advances the cursor.
466 *
467 * @returns 16-bit unsigned integer. On error RTDWARFCURSOR::rc is set and @a
468 * uErrValue is returned.
469 * @param pCursor The cursor.
470 * @param uErrValue What to return on read error.
471 */
472static uint16_t rtDwarfCursor_GetU16(PRTDWARFCURSOR pCursor, uint16_t uErrValue)
473{
474 if (pCursor->cbUnitLeft < 2)
475 {
476 pCursor->pb += pCursor->cbUnitLeft;
477 pCursor->cbLeft -= pCursor->cbUnitLeft;
478 pCursor->cbUnitLeft = 0;
479 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
480 return uErrValue;
481 }
482
483 uint16_t u16 = RT_MAKE_U16(pCursor->pb[0], pCursor->pb[1]);
484 pCursor->pb += 2;
485 pCursor->cbUnitLeft -= 2;
486 pCursor->cbLeft -= 2;
487 if (!pCursor->fNativEndian)
488 u16 = RT_BSWAP_U16(u16);
489 return u16;
490}
491
492
493/**
494 * Reads a 32-bit unsigned integer and advances the cursor.
495 *
496 * @returns 32-bit unsigned integer. On error RTDWARFCURSOR::rc is set and @a
497 * uErrValue is returned.
498 * @param pCursor The cursor.
499 * @param uErrValue What to return on read error.
500 */
501static uint32_t rtDwarfCursor_GetU32(PRTDWARFCURSOR pCursor, uint32_t uErrValue)
502{
503 if (pCursor->cbUnitLeft < 4)
504 {
505 pCursor->pb += pCursor->cbUnitLeft;
506 pCursor->cbLeft -= pCursor->cbUnitLeft;
507 pCursor->cbUnitLeft = 0;
508 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
509 return uErrValue;
510 }
511
512 uint32_t u32 = RT_MAKE_U32_FROM_U8(pCursor->pb[0], pCursor->pb[1], pCursor->pb[2], pCursor->pb[3]);
513 pCursor->pb += 4;
514 pCursor->cbUnitLeft -= 4;
515 pCursor->cbLeft -= 4;
516 if (!pCursor->fNativEndian)
517 u32 = RT_BSWAP_U32(u32);
518 return u32;
519}
520
521
522/**
523 * Reads a 64-bit unsigned integer and advances the cursor.
524 *
525 * @returns 64-bit unsigned integer. On error RTDWARFCURSOR::rc is set and @a
526 * uErrValue is returned.
527 * @param pCursor The cursor.
528 * @param uErrValue What to return on read error.
529 */
530static uint64_t rtDwarfCursor_GetU64(PRTDWARFCURSOR pCursor, uint64_t uErrValue)
531{
532 if (pCursor->cbUnitLeft < 8)
533 {
534 pCursor->pb += pCursor->cbUnitLeft;
535 pCursor->cbLeft -= pCursor->cbUnitLeft;
536 pCursor->cbUnitLeft = 0;
537 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
538 return uErrValue;
539 }
540
541 uint64_t u64 = RT_MAKE_U64_FROM_U8(pCursor->pb[0], pCursor->pb[1], pCursor->pb[2], pCursor->pb[3],
542 pCursor->pb[4], pCursor->pb[5], pCursor->pb[6], pCursor->pb[7]);
543 pCursor->pb += 8;
544 pCursor->cbUnitLeft -= 8;
545 pCursor->cbLeft -= 8;
546 if (!pCursor->fNativEndian)
547 u64 = RT_BSWAP_U64(u64);
548 return u64;
549}
550
551
552/**
553 * Reads an unsigned LEB128 encoded number.
554 *
555 * @returns unsigned 64-bit number. On error RTDWARFCURSOR::rc is set and @a
556 * uErrValue is returned.
557 * @param pCursor The cursor.
558 * @param uErrValue The value to return on error.
559 */
560static uint64_t rtDwarfCursor_GetULeb128(PRTDWARFCURSOR pCursor, uint64_t uErrValue)
561{
562 if (pCursor->cbUnitLeft < 1)
563 {
564 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
565 return uErrValue;
566 }
567
568 /*
569 * Special case - single byte.
570 */
571 uint8_t b = pCursor->pb[0];
572 if (!(b & 0x80))
573 {
574 pCursor->pb += 1;
575 pCursor->cbUnitLeft -= 1;
576 pCursor->cbLeft -= 1;
577 return b;
578 }
579
580 /*
581 * Generic case.
582 */
583 /* Decode. */
584 uint32_t off = 1;
585 uint64_t u64Ret = b & 0x7f;
586 do
587 {
588 if (off == pCursor->cbUnitLeft)
589 {
590 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
591 u64Ret = uErrValue;
592 break;
593 }
594 b = pCursor->pb[off];
595 u64Ret |= (b & 0x7f) << off * 7;
596 off++;
597 } while (b & 0x80);
598
599 /* Update the cursor. */
600 pCursor->pb += off;
601 pCursor->cbUnitLeft -= off;
602 pCursor->cbLeft -= off;
603
604 /* Check the range. */
605 uint32_t cBits = off * 7;
606 if (cBits > 64)
607 {
608 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
609 u64Ret = uErrValue;
610 }
611
612 return u64Ret;
613}
614
615
616/**
617 * Reads a signed LEB128 encoded number.
618 *
619 * @returns signed 64-bit number. On error RTDWARFCURSOR::rc is set and @a
620 * uErrValue is returned.
621 * @param pCursor The cursor.
622 * @param sErrValue The value to return on error.
623 */
624static int64_t rtDwarfCursor_GetSLeb128(PRTDWARFCURSOR pCursor, int64_t sErrValue)
625{
626 if (pCursor->cbUnitLeft < 1)
627 {
628 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
629 return sErrValue;
630 }
631
632 /*
633 * Special case - single byte.
634 */
635 uint8_t b = pCursor->pb[0];
636 if (!(b & 0x80))
637 {
638 pCursor->pb += 1;
639 pCursor->cbUnitLeft -= 1;
640 pCursor->cbLeft -= 1;
641 if (b & 0x40)
642 b |= 0x80;
643 return (int8_t)b;
644 }
645
646 /*
647 * Generic case.
648 */
649 /* Decode it. */
650 uint32_t off = 1;
651 uint64_t u64Ret = b & 0x7f;
652 do
653 {
654 if (off == pCursor->cbUnitLeft)
655 {
656 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
657 u64Ret = (uint64_t)sErrValue;
658 break;
659 }
660 b = pCursor->pb[off];
661 u64Ret |= (b & 0x7f) << off * 7;
662 off++;
663 } while (b & 0x80);
664
665 /* Update cursor. */
666 pCursor->pb += off;
667 pCursor->cbUnitLeft -= off;
668 pCursor->cbLeft -= off;
669
670 /* Check the range. */
671 uint32_t cBits = off * 7;
672 if (cBits > 64)
673 {
674 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
675 u64Ret = (uint64_t)sErrValue;
676 }
677 /* Sign extend the value. */
678 else if (u64Ret & RT_BIT_64(cBits - 1))
679 u64Ret |= ~(RT_BIT_64(cBits - 1) - 1);
680
681 return (int64_t)u64Ret;
682}
683
684
685/**
686 * Reads an unsigned LEB128 encoded number, max 32-bit width.
687 *
688 * @returns unsigned 32-bit number. On error RTDWARFCURSOR::rc is set and @a
689 * uErrValue is returned.
690 * @param pCursor The cursor.
691 * @param uErrValue The value to return on error.
692 */
693static uint32_t rtDwarfCursor_GetULeb128AsU32(PRTDWARFCURSOR pCursor, uint32_t uErrValue)
694{
695 uint64_t u64 = rtDwarfCursor_GetULeb128(pCursor, uErrValue);
696 if (u64 > UINT32_MAX)
697 {
698 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
699 return uErrValue;
700 }
701 return (uint32_t)u64;
702}
703
704
705/**
706 * Reads a signed LEB128 encoded number, max 32-bit width.
707 *
708 * @returns signed 32-bit number. On error RTDWARFCURSOR::rc is set and @a
709 * uErrValue is returned.
710 * @param pCursor The cursor.
711 * @param sErrValue The value to return on error.
712 */
713static int32_t rtDwarfCursor_GetSLeb128AsS32(PRTDWARFCURSOR pCursor, int32_t sErrValue)
714{
715 int64_t s64 = rtDwarfCursor_GetSLeb128(pCursor, sErrValue);
716 if (s64 > INT32_MAX || s64 < INT32_MIN)
717 {
718 pCursor->rc = VERR_DWARF_LEB_OVERFLOW;
719 return sErrValue;
720 }
721 return (int32_t)s64;
722}
723
724
725/**
726 * Skips a LEB128 encoded number.
727 *
728 * @returns IPRT status code.
729 * @param pCursor The cursor.
730 */
731static int rtDwarfCursor_SkipLeb128(PRTDWARFCURSOR pCursor)
732{
733 if (pCursor->cbUnitLeft < 1)
734 return pCursor->rc = VERR_DWARF_UNEXPECTED_END;
735
736 uint32_t offSkip = 1;
737 if (pCursor->pb[0] & 0x80)
738 do
739 {
740 if (offSkip == pCursor->cbUnitLeft)
741 {
742 pCursor->rc = VERR_DWARF_UNEXPECTED_END;
743 break;
744 }
745 } while (pCursor->pb[offSkip++] & 0x80);
746
747 pCursor->pb += offSkip;
748 pCursor->cbUnitLeft -= offSkip;
749 pCursor->cbLeft -= offSkip;
750 return pCursor->rc;
751}
752
753
754/**
755 * Reads a zero terminated string, advancing the cursor beyond the terminator.
756 *
757 * @returns Pointer to the string.
758 * @param pCursor The cursor.
759 * @param pszErrValue What to return if the string isn't terminated
760 * before the end of the unit.
761 */
762static const char *rtDwarfCursor_GetSZ(PRTDWARFCURSOR pCursor, const char *pszErrValue)
763{
764 const char *pszRet = (const char *)pCursor->pb;
765 for (;;)
766 {
767 if (!pCursor->cbUnitLeft)
768 {
769 pCursor->rc = VERR_DWARF_BAD_STRING;
770 return pszErrValue;
771 }
772 pCursor->cbUnitLeft--;
773 pCursor->cbLeft--;
774 if (!*pCursor->pb++)
775 break;
776 }
777 return pszRet;
778}
779
780
781/**
782 * Reads an unsigned DWARF half number.
783 *
784 * @returns The number. On error RTDWARFCURSOR::rc is set and @a
785 * uErrValue is returned.
786 * @param pCursor The cursor.
787 * @param uErrValue What to return on error.
788 */
789static uint16_t rtDwarfCursor_GetUHalf(PRTDWARFCURSOR pCursor, uint16_t uErrValue)
790{
791 return rtDwarfCursor_GetU16(pCursor, uErrValue);
792}
793
794
795/**
796 * Reads an unsigned DWARF byte number.
797 *
798 * @returns The number. On error RTDWARFCURSOR::rc is set and @a
799 * uErrValue is returned.
800 * @param pCursor The cursor.
801 * @param uErrValue What to return on error.
802 */
803static uint8_t rtDwarfCursor_GetUByte(PRTDWARFCURSOR pCursor, uint8_t uErrValue)
804{
805 return rtDwarfCursor_GetU8(pCursor, uErrValue);
806}
807
808
809/**
810 * Reads a signed DWARF byte number.
811 *
812 * @returns The number. On error RTDWARFCURSOR::rc is set and @a
813 * uErrValue is returned.
814 * @param pCursor The cursor.
815 * @param uErrValue What to return on error.
816 */
817static int8_t rtDwarfCursor_GetSByte(PRTDWARFCURSOR pCursor, int8_t iErrValue)
818{
819 return (int8_t)rtDwarfCursor_GetU8(pCursor, (uint8_t)iErrValue);
820}
821
822
823/**
824 * Reads a unsigned DWARF offset value.
825 *
826 * @returns The value. On error RTDWARFCURSOR::rc is set and @a
827 * uErrValue is returned.
828 * @param pCursor The cursor.
829 * @param uErrValue What to return on error.
830 */
831static uint64_t rtDwarfCursor_GetUOff(PRTDWARFCURSOR pCursor, uint64_t uErrValue)
832{
833 if (pCursor->f64bitDwarf)
834 return rtDwarfCursor_GetU64(pCursor, uErrValue);
835 return rtDwarfCursor_GetU32(pCursor, (uint32_t)uErrValue);
836}
837
838
839/**
840 * Reads a unsigned DWARF native offset value.
841 *
842 * @returns The value. On error RTDWARFCURSOR::rc is set and @a
843 * uErrValue is returned.
844 * @param pCursor The cursor.
845 * @param uErrValue What to return on error.
846 */
847static uint64_t rtDwarfCursor_GetNativeUOff(PRTDWARFCURSOR pCursor, uint64_t uErrValue)
848{
849 switch (pCursor->cbNativeAddr)
850 {
851 case 1: return rtDwarfCursor_GetU8(pCursor, (uint8_t )uErrValue);
852 case 2: return rtDwarfCursor_GetU16(pCursor, (uint16_t)uErrValue);
853 case 4: return rtDwarfCursor_GetU32(pCursor, (uint32_t)uErrValue);
854 case 8: return rtDwarfCursor_GetU64(pCursor, uErrValue);
855 default:
856 pCursor->rc = VERR_INTERNAL_ERROR_2;
857 return uErrValue;
858 }
859}
860
861
862/**
863 * Gets the unit length, updating the unit length member and DWARF bitness
864 * members of the cursor.
865 *
866 * @returns The unit length.
867 * @param pCursor The cursor.
868 */
869static uint64_t rtDwarfCursor_GetInitalLength(PRTDWARFCURSOR pCursor)
870{
871 /*
872 * Read the initial length.
873 */
874 pCursor->cbUnitLeft = pCursor->cbLeft;
875 uint64_t cbUnit = rtDwarfCursor_GetU32(pCursor, 0);
876 if (cbUnit != UINT32_C(0xffffffff))
877 pCursor->f64bitDwarf = false;
878 else
879 {
880 pCursor->f64bitDwarf = true;
881 cbUnit = rtDwarfCursor_GetU64(pCursor, 0);
882 }
883
884
885 /*
886 * Set the unit length, quitely fixing bad lengths.
887 */
888 pCursor->cbUnitLeft = (size_t)cbUnit;
889 if ( pCursor->cbUnitLeft > pCursor->cbLeft
890 || pCursor->cbUnitLeft != cbUnit)
891 pCursor->cbUnitLeft = pCursor->cbLeft;
892
893 return cbUnit;
894}
895
896
897/**
898 * Calculates the section offset corresponding to the current cursor position.
899 *
900 * @returns 32-bit section offset. If out of range, RTDWARFCURSOR::rc will be
901 * set and UINT32_MAX returned.
902 * @param pCursor The cursor.
903 */
904static uint32_t rtDwarfCursor_CalcSectOffsetU32(PRTDWARFCURSOR pCursor)
905{
906 size_t off = (uint8_t const *)pCursor->pDwarfMod->aSections[pCursor->enmSect].pv - pCursor->pb;
907 uint32_t offRet = (uint32_t)off;
908 if (offRet != off)
909 {
910 pCursor->rc = VERR_OUT_OF_RANGE;
911 offRet = UINT32_MAX;
912 }
913 return offRet;
914}
915
916
917/**
918 * Calculates an absolute cursor position from one relative to the current
919 * cursor position.
920 *
921 * @returns The absolute cursor position.
922 * @param pCursor The cursor.
923 * @param offRelative The relative position. Must be a positive
924 * offset.
925 */
926static uint8_t const *rtDwarfCursor_CalcPos(PRTDWARFCURSOR pCursor, size_t offRelative)
927{
928 if (offRelative > pCursor->cbUnitLeft)
929 {
930 pCursor->rc = VERR_DWARF_BAD_POS;
931 return NULL;
932 }
933 return pCursor->pb + offRelative;
934}
935
936
937/**
938 * Advances the cursor to the given position.
939 *
940 * @returns IPRT status code.
941 * @param pCursor The cursor.
942 * @param pbNewPos The new position - returned by
943 * rtDwarfCursor_CalcPos().
944 */
945static int rtDwarfCursor_AdvanceToPos(PRTDWARFCURSOR pCursor, uint8_t const *pbNewPos)
946{
947 if (RT_FAILURE(pCursor->rc))
948 return pCursor->rc;
949 AssertPtr(pbNewPos);
950 if ((uintptr_t)pbNewPos < (uintptr_t)pCursor->pb)
951 return pCursor->rc = VERR_DWARF_BAD_POS;
952
953 uintptr_t cbAdj = (uintptr_t)pbNewPos - (uintptr_t)pCursor->pb;
954 if (RT_UNLIKELY(cbAdj > pCursor->cbUnitLeft))
955 {
956 AssertFailed();
957 pCursor->rc = VERR_DWARF_BAD_POS;
958 cbAdj = pCursor->cbUnitLeft;
959 }
960
961 pCursor->cbUnitLeft -= cbAdj;
962 pCursor->cbLeft -= cbAdj;
963 pCursor->pb += cbAdj;
964 return pCursor->rc;
965}
966
967
968/**
969 * Check if the cursor is at the end of the current DWARF unit.
970 *
971 * @retval @c true if at the end or a cursor error is pending.
972 * @retval @c false if not.
973 * @param pCursor The cursor.
974 */
975static bool rtDwarfCursor_IsAtEndOfUnit(PRTDWARFCURSOR pCursor)
976{
977 return !pCursor->cbUnitLeft || RT_FAILURE(pCursor->rc);
978}
979
980
981/**
982 * Skips to the end of the current unit.
983 *
984 * @returns IPRT status code.
985 * @param pCursor The cursor.
986 */
987static int rtDwarfCursor_SkipUnit(PRTDWARFCURSOR pCursor)
988{
989 pCursor->pb += pCursor->cbUnitLeft;
990 pCursor->cbLeft -= pCursor->cbUnitLeft;
991 pCursor->cbUnitLeft = 0;
992 return pCursor->rc;
993}
994
995
996/**
997 * Check if the cursor is at the end of the section (or whatever the cursor is
998 * processing).
999 *
1000 * @retval @c true if at the end or a cursor error is pending.
1001 * @retval @c false if not.
1002 * @param pCursor The cursor.
1003 */
1004static bool rtDwarfCursor_IsAtEnd(PRTDWARFCURSOR pCursor)
1005{
1006 return !pCursor->cbLeft || RT_FAILURE(pCursor->rc);
1007}
1008
1009
1010/**
1011 * Initialize a section reader cursor.
1012 *
1013 * @returns IPRT status code.
1014 * @param pCursor The cursor.
1015 * @param pThis The dwarf module.
1016 * @param enmSect The name of the section to read.
1017 */
1018static int rtDwarfCursor_Init(PRTDWARFCURSOR pCursor, PRTDBGMODDWARF pThis, krtDbgModDwarfSect enmSect)
1019{
1020 int rc = rtDbgModDwarfLoadSection(pThis, enmSect);
1021 if (RT_FAILURE(rc))
1022 return rc;
1023
1024 pCursor->enmSect = enmSect;
1025 pCursor->pbStart = (uint8_t const *)pThis->aSections[enmSect].pv;
1026 pCursor->pb = pCursor->pbStart;
1027 pCursor->cbLeft = pThis->aSections[enmSect].cb;
1028 pCursor->cbUnitLeft = pCursor->cbLeft;
1029 pCursor->pDwarfMod = pThis;
1030 pCursor->f64bitDwarf = false;
1031 /** @todo ask the image about the endian used as well as the address
1032 * width. */
1033 pCursor->fNativEndian = true;
1034 pCursor->cbNativeAddr = 4;
1035 pCursor->rc = VINF_SUCCESS;
1036
1037 return VINF_SUCCESS;
1038}
1039
1040
1041/**
1042 * Initialize a section reader cursor with an offset.
1043 *
1044 * @returns IPRT status code.
1045 * @param pCursor The cursor.
1046 * @param pThis The dwarf module.
1047 * @param enmSect The name of the section to read.
1048 * @param offSect The offset into the section.
1049 */
1050static int rtDwarfCursor_InitWithOffset(PRTDWARFCURSOR pCursor, PRTDBGMODDWARF pThis,
1051 krtDbgModDwarfSect enmSect, uint32_t offSect)
1052{
1053 if (offSect > pThis->aSections[enmSect].cb)
1054 return VERR_DWARF_BAD_POS;
1055
1056 int rc = rtDwarfCursor_Init(pCursor, pThis, enmSect);
1057 if (RT_SUCCESS(rc))
1058 {
1059 pCursor->pbStart += offSect;
1060 pCursor->pb += offSect;
1061 pCursor->cbLeft -= offSect;
1062 pCursor->cbUnitLeft -= offSect;
1063 }
1064
1065 return rc;
1066}
1067
1068
1069/**
1070 * Deletes a section reader initialized by rtDwarfCursor_Init.
1071 *
1072 * @returns @a rcOther or RTDWARCURSOR::rc.
1073 * @param pCursor The section reader.
1074 * @param rcOther Other error code to be returned if it indicates
1075 * error or if the cursor status is OK.
1076 */
1077static int rtDwarfCursor_Delete(PRTDWARFCURSOR pCursor, int rcOther)
1078{
1079 /* ... and a drop of poison. */
1080 pCursor->pb = NULL;
1081 pCursor->cbLeft = ~(size_t)0;
1082 pCursor->cbUnitLeft = ~(size_t)0;
1083 pCursor->pDwarfMod = NULL;
1084 if (RT_FAILURE(pCursor->rc) && RT_SUCCESS(rcOther))
1085 rcOther = pCursor->rc;
1086 pCursor->rc = VERR_INTERNAL_ERROR_4;
1087 return rcOther;
1088}
1089
1090
1091/*
1092 *
1093 * DWARF Line Numbers.
1094 * DWARF Line Numbers.
1095 * DWARF Line Numbers.
1096 *
1097 */
1098
1099
1100/**
1101 * Defines a file name.
1102 *
1103 * @returns IPRT status code.
1104 * @param pLnState The line number program state.
1105 * @param pszFilename The name of the file.
1106 * @param idxInc The include path index.
1107 */
1108static int rtDwarfLine_DefineFileName(PRTDWARFLINESTATE pLnState, const char *pszFilename, uint64_t idxInc)
1109{
1110 /*
1111 * Resize the array if necessary.
1112 */
1113 uint32_t iFileName = pLnState->cFileNames;
1114 if ((iFileName % 2) == 0)
1115 {
1116 void *pv = RTMemRealloc(pLnState->papszFileNames, sizeof(pLnState->papszFileNames[0]) * (iFileName + 2));
1117 if (!pv)
1118 return VERR_NO_MEMORY;
1119 pLnState->papszFileNames = (char **)pv;
1120 }
1121
1122 /*
1123 * Add the file name.
1124 */
1125 if ( pszFilename[0] == '/'
1126 || pszFilename[0] == '\\'
1127 || (RT_C_IS_ALPHA(pszFilename[0]) && pszFilename[1] == ':') )
1128 pLnState->papszFileNames[iFileName] = RTStrDup(pszFilename);
1129 else if (idxInc < pLnState->cIncPaths)
1130 pLnState->papszFileNames[iFileName] = RTPathJoinA(pLnState->papszIncPaths[idxInc], pszFilename);
1131 else
1132 return VERR_DWARF_BAD_LINE_NUMBER_HEADER;
1133 if (!pLnState->papszFileNames[iFileName])
1134 return VERR_NO_STR_MEMORY;
1135 pLnState->cFileNames = iFileName + 1;
1136
1137 /*
1138 * Sanitize the name.
1139 */
1140 int rc = rtDbgModDwarfStringToUtf8(pLnState->pDwarfMod, &pLnState->papszFileNames[iFileName]);
1141 Log((" File #%02u = '%s'\n", iFileName, pLnState->papszFileNames[iFileName]));
1142 return rc;
1143}
1144
1145
1146/**
1147 * Adds a line to the table and resets parts of the state (DW_LNS_copy).
1148 *
1149 * @returns IPRT status code
1150 * @param pLnState The line number program state.
1151 */
1152static int rtDwarfLine_AddLine(PRTDWARFLINESTATE pLnState)
1153{
1154 const char *pszFile = pLnState->Regs.iFile < pLnState->cFileNames
1155 ? pLnState->papszFileNames[pLnState->Regs.iFile]
1156 : "<bad file name index>";
1157 RTDBGSEGIDX iSeg;
1158 RTUINTPTR offSeg;
1159 int rc = rtDbgModDwarfLinkAddressToSegOffset(pLnState->pDwarfMod, pLnState->Regs.uAddress, &iSeg, &offSeg);
1160 if (RT_SUCCESS(rc))
1161 {
1162 Log2(("rtDwarfLine_AddLine: %x:%08llx (%#llx) %s(%d)\n", iSeg, offSeg, pLnState->Regs.uAddress, pszFile, pLnState->Regs.uLine));
1163 rc = RTDbgModLineAdd(pLnState->pDwarfMod->hCnt, pszFile, pLnState->Regs.uLine, iSeg, offSeg, NULL);
1164
1165 /* Ignore address conflicts for now. */
1166 if (rc == VERR_DBG_ADDRESS_CONFLICT)
1167 rc = VINF_SUCCESS;
1168 }
1169
1170 pLnState->Regs.fBasicBlock = false;
1171 pLnState->Regs.fPrologueEnd = false;
1172 pLnState->Regs.fEpilogueBegin = false;
1173 pLnState->Regs.uDiscriminator = 0;
1174 return rc;
1175}
1176
1177
1178/**
1179 * Reset the program to the start-of-sequence state.
1180 *
1181 * @param pLnState The line number program state.
1182 */
1183static void rtDwarfLine_ResetState(PRTDWARFLINESTATE pLnState)
1184{
1185 pLnState->Regs.uAddress = 0;
1186 pLnState->Regs.idxOp = 0;
1187 pLnState->Regs.iFile = 1;
1188 pLnState->Regs.uLine = 1;
1189 pLnState->Regs.uColumn = 0;
1190 pLnState->Regs.fIsStatement = RT_BOOL(pLnState->Hdr.u8DefIsStmt);
1191 pLnState->Regs.fBasicBlock = false;
1192 pLnState->Regs.fEndSequence = false;
1193 pLnState->Regs.fPrologueEnd = false;
1194 pLnState->Regs.fEpilogueBegin = false;
1195 pLnState->Regs.uIsa = 0;
1196 pLnState->Regs.uDiscriminator = 0;
1197}
1198
1199
1200/**
1201 * Runs the line number program.
1202 *
1203 * @returns IPRT status code.
1204 * @param pLnState The line number program state.
1205 * @param pCursor The cursor.
1206 */
1207static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCursor)
1208{
1209 LogFlow(("rtDwarfLine_RunProgram: cbUnitLeft=%zu\n", pCursor->cbUnitLeft));
1210
1211 int rc = VINF_SUCCESS;
1212 rtDwarfLine_ResetState(pLnState);
1213
1214 while (!rtDwarfCursor_IsAtEndOfUnit(pCursor))
1215 {
1216 uint8_t bOpCode = rtDwarfCursor_GetUByte(pCursor, DW_LNS_extended);
1217 if (bOpCode > pLnState->Hdr.u8OpcodeBase)
1218 {
1219 /*
1220 * Special opcode.
1221 */
1222 uint8_t const bLogOpCode = bOpCode; NOREF(bLogOpCode);
1223 bOpCode -= pLnState->Hdr.u8OpcodeBase;
1224
1225 int32_t const cLineDelta = bOpCode % pLnState->Hdr.u8LineRange + (int32_t)pLnState->Hdr.s8LineBase;
1226 bOpCode /= pLnState->Hdr.u8LineRange;
1227
1228 uint64_t uTmp = bOpCode + pLnState->Regs.idxOp + bOpCode;
1229 uint64_t const cAddressDelta = uTmp / pLnState->Hdr.cMaxOpsPerInstr * pLnState->Hdr.cbMinInstr;
1230 uint64_t const cOpIndexDelta = uTmp % pLnState->Hdr.cMaxOpsPerInstr;
1231
1232 pLnState->Regs.uLine += cLineDelta;
1233 pLnState->Regs.uAddress += cAddressDelta;
1234 pLnState->Regs.idxOp += cOpIndexDelta;
1235 Log2(("DW Special Opcode %#04x: uLine + %d => %u; uAddress + %#llx => %#llx; idxOp + %#llx => %#llx\n",
1236 bLogOpCode, cLineDelta, pLnState->Regs.uLine, cAddressDelta, pLnState->Regs.uAddress,
1237 cOpIndexDelta, pLnState->Regs.idxOp));
1238
1239 rc = rtDwarfLine_AddLine(pLnState);
1240 }
1241 else
1242 {
1243 switch (bOpCode)
1244 {
1245 /*
1246 * Standard opcode.
1247 */
1248 case DW_LNS_copy:
1249 Log2(("DW_LNS_copy\n"));
1250 rc = rtDwarfLine_AddLine(pLnState);
1251 break;
1252
1253 case DW_LNS_advance_pc:
1254 {
1255 uint64_t u64Adv = rtDwarfCursor_GetULeb128(pCursor, 0);
1256 pLnState->Regs.uAddress += (pLnState->Regs.idxOp + u64Adv) / pLnState->Hdr.cMaxOpsPerInstr
1257 * pLnState->Hdr.cbMinInstr;
1258 pLnState->Regs.idxOp += (pLnState->Regs.idxOp + u64Adv) % pLnState->Hdr.cMaxOpsPerInstr;
1259 Log2(("DW_LNS_advance_pc\n"));
1260 break;
1261 }
1262
1263 case DW_LNS_advance_line:
1264 {
1265 int32_t cLineDelta = rtDwarfCursor_GetSLeb128AsS32(pCursor, 0);
1266 pLnState->Regs.uLine += cLineDelta;
1267 Log2(("DW_LNS_advance_line: uLine + %d => %u\n", cLineDelta, pLnState->Regs.uLine));
1268 break;
1269 }
1270
1271 case DW_LNS_set_file:
1272 pLnState->Regs.iFile = rtDwarfCursor_GetULeb128AsU32(pCursor, 0);
1273 Log2(("DW_LNS_set_file: iFile=%u\n", pLnState->Regs.iFile));
1274 break;
1275
1276 case DW_LNS_set_column:
1277 pLnState->Regs.uColumn = rtDwarfCursor_GetULeb128AsU32(pCursor, 0);
1278 Log2(("DW_LNS_set_column\n"));
1279 break;
1280
1281 case DW_LNS_negate_stmt:
1282 pLnState->Regs.fIsStatement = !pLnState->Regs.fIsStatement;
1283 Log2(("DW_LNS_negate_stmt\n"));
1284 break;
1285
1286 case DW_LNS_set_basic_block:
1287 pLnState->Regs.fBasicBlock = true;
1288 Log2(("DW_LNS_set_basic_block\n"));
1289 break;
1290
1291 case DW_LNS_const_add_pc:
1292 pLnState->Regs.uAddress += (pLnState->Regs.idxOp + 255) / pLnState->Hdr.cMaxOpsPerInstr
1293 * pLnState->Hdr.cbMinInstr;
1294 pLnState->Regs.idxOp += (pLnState->Regs.idxOp + 255) % pLnState->Hdr.cMaxOpsPerInstr;
1295 Log2(("DW_LNS_const_add_pc\n"));
1296 break;
1297
1298 case DW_LNS_fixed_advance_pc:
1299 pLnState->Regs.uAddress += rtDwarfCursor_GetUHalf(pCursor, 0);
1300 pLnState->Regs.idxOp = 0;
1301 Log2(("DW_LNS_fixed_advance_pc\n"));
1302 break;
1303
1304 case DW_LNS_set_prologue_end:
1305 pLnState->Regs.fPrologueEnd = true;
1306 Log2(("DW_LNS_set_prologue_end\n"));
1307 break;
1308
1309 case DW_LNS_set_epilogue_begin:
1310 pLnState->Regs.fEpilogueBegin = true;
1311 Log2(("DW_LNS_set_epilogue_begin\n"));
1312 break;
1313
1314 case DW_LNS_set_isa:
1315 pLnState->Regs.uIsa = rtDwarfCursor_GetULeb128AsU32(pCursor, 0);
1316 Log2(("DW_LNS_set_isa %#x\n", pLnState->Regs.uIsa));
1317 break;
1318
1319 default:
1320 {
1321 unsigned cOpsToSkip = pLnState->Hdr.pacStdOperands[bOpCode - 1];
1322 Log2(("rtDwarfLine_RunProgram: Unknown standard opcode %#x, %#x operands\n", bOpCode, cOpsToSkip));
1323 while (cOpsToSkip-- > 0)
1324 rc = rtDwarfCursor_SkipLeb128(pCursor);
1325 break;
1326 }
1327
1328 /*
1329 * Extended opcode.
1330 */
1331 case DW_LNS_extended:
1332 {
1333 /* The instruction has a length prefix. */
1334 uint64_t cbInstr = rtDwarfCursor_GetULeb128(pCursor, UINT64_MAX);
1335 if (RT_FAILURE(pCursor->rc))
1336 return pCursor->rc;
1337 if (cbInstr > pCursor->cbUnitLeft)
1338 return VERR_DWARF_BAD_LNE;
1339 uint8_t const * const pbEndOfInstr = rtDwarfCursor_CalcPos(pCursor, cbInstr);
1340
1341 /* Get the opcode and deal with it if we know it. */
1342 bOpCode = rtDwarfCursor_GetUByte(pCursor, 0);
1343 switch (bOpCode)
1344 {
1345 case DW_LNE_end_sequence:
1346#if 0 /* No need for this, I think. */
1347 pLnState->Regs.fEndSequence = true;
1348 rc = rtDwarfLine_AddLine(pLnState);
1349#endif
1350 rtDwarfLine_ResetState(pLnState);
1351 Log2(("DW_LNE_end_sequence\n"));
1352 break;
1353
1354 case DW_LNE_set_address:
1355 switch (cbInstr - 1)
1356 {
1357 case 2: pLnState->Regs.uAddress = rtDwarfCursor_GetU16(pCursor, UINT16_MAX); break;
1358 case 4: pLnState->Regs.uAddress = rtDwarfCursor_GetU32(pCursor, UINT32_MAX); break;
1359 case 8: pLnState->Regs.uAddress = rtDwarfCursor_GetU64(pCursor, UINT64_MAX); break;
1360 default:
1361 AssertMsgFailed(("%d\n", cbInstr));
1362 pLnState->Regs.uAddress = rtDwarfCursor_GetNativeUOff(pCursor, UINT64_MAX);
1363 break;
1364 }
1365 pLnState->Regs.idxOp = 0;
1366 Log2(("DW_LNE_set_address: %#llx\n", pLnState->Regs.uAddress));
1367 break;
1368
1369 case DW_LNE_define_file:
1370 {
1371 const char *pszFilename = rtDwarfCursor_GetSZ(pCursor, NULL);
1372 uint32_t idxInc = rtDwarfCursor_GetULeb128AsU32(pCursor, UINT32_MAX);
1373 rtDwarfCursor_SkipLeb128(pCursor); /* st_mtime */
1374 rtDwarfCursor_SkipLeb128(pCursor); /* st_size */
1375 Log2(("DW_LNE_define_file: {%d}/%s\n", idxInc, pszFilename));
1376
1377 rc = rtDwarfCursor_AdvanceToPos(pCursor, pbEndOfInstr);
1378 if (RT_SUCCESS(rc))
1379 rc = rtDwarfLine_DefineFileName(pLnState, pszFilename, idxInc);
1380 }
1381
1382 case DW_LNE_set_descriminator:
1383 pLnState->Regs.uDiscriminator = rtDwarfCursor_GetULeb128AsU32(pCursor, UINT32_MAX);
1384 Log2(("DW_LNE_set_descriminator: %u\n", pLnState->Regs.uDiscriminator));
1385 break;
1386
1387 default:
1388 Log2(("rtDwarfLine_RunProgram: Unknown extended opcode %#x, length %#x\n", bOpCode, cbInstr));
1389 break;
1390 }
1391
1392 /* Advance the cursor to the end of the instruction . */
1393 rtDwarfCursor_AdvanceToPos(pCursor, pbEndOfInstr);
1394 break;
1395 }
1396 }
1397 }
1398
1399 /*
1400 * Check the status before looping.
1401 */
1402 if (RT_FAILURE(rc))
1403 return rc;
1404 if (RT_FAILURE(pCursor->rc))
1405 return pCursor->rc;
1406 }
1407 return rc;
1408}
1409
1410
1411/**
1412 * Reads the include directories for a line number unit.
1413 *
1414 * @returns IPRT status code
1415 * @param pLnState The line number program state.
1416 * @param pCursor The cursor.
1417 */
1418static int rtDwarfLine_ReadFileNames(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCursor)
1419{
1420 int rc = rtDwarfLine_DefineFileName(pLnState, "/<bad-zero-file-name-entry>", 0);
1421 if (RT_FAILURE(rc))
1422 return rc;
1423
1424 for (;;)
1425 {
1426 const char *psz = rtDwarfCursor_GetSZ(pCursor, NULL);
1427 if (!*psz)
1428 break;
1429
1430 uint64_t idxInc = rtDwarfCursor_GetULeb128(pCursor, UINT64_MAX);
1431 rtDwarfCursor_SkipLeb128(pCursor); /* st_mtime */
1432 rtDwarfCursor_SkipLeb128(pCursor); /* st_size */
1433
1434 rc = rtDwarfLine_DefineFileName(pLnState, psz, idxInc);
1435 if (RT_FAILURE(rc))
1436 return rc;
1437 }
1438 return pCursor->rc;
1439}
1440
1441
1442/**
1443 * Reads the include directories for a line number unit.
1444 *
1445 * @returns IPRT status code
1446 * @param pLnState The line number program state.
1447 * @param pCursor The cursor.
1448 */
1449static int rtDwarfLine_ReadIncludePaths(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCursor)
1450{
1451 const char *psz = ""; /* The zeroth is the unit dir. */
1452 for (;;)
1453 {
1454 if ((pLnState->cIncPaths % 2) == 0)
1455 {
1456 void *pv = RTMemRealloc(pLnState->papszIncPaths, sizeof(pLnState->papszIncPaths[0]) * (pLnState->cIncPaths + 2));
1457 if (!pv)
1458 return VERR_NO_MEMORY;
1459 pLnState->papszIncPaths = (const char **)pv;
1460 }
1461 Log((" Path #%02u = '%s'\n", pLnState->cIncPaths, psz));
1462 pLnState->papszIncPaths[pLnState->cIncPaths] = psz;
1463 pLnState->cIncPaths++;
1464
1465 psz = rtDwarfCursor_GetSZ(pCursor, NULL);
1466 if (!*psz)
1467 break;
1468 }
1469
1470 return pCursor->rc;
1471}
1472
1473
1474/**
1475 * Explodes the line number table for a compilation unit.
1476 *
1477 * @returns IPRT status code
1478 * @param pThis The DWARF instance.
1479 * @param pCursor The cursor to read the line number information
1480 * via.
1481 */
1482static int rtDwarfLine_ExplodeUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor)
1483{
1484 RTDWARFLINESTATE LnState;
1485 RT_ZERO(LnState);
1486 LnState.pDwarfMod = pThis;
1487
1488 /*
1489 * Parse the header.
1490 */
1491 rtDwarfCursor_GetInitalLength(pCursor);
1492 LnState.Hdr.uVer = rtDwarfCursor_GetUHalf(pCursor, 0);
1493 if ( LnState.Hdr.uVer < 2
1494 || LnState.Hdr.uVer > 4)
1495 return rtDwarfCursor_SkipUnit(pCursor);
1496
1497 LnState.Hdr.offFirstOpcode = rtDwarfCursor_GetUOff(pCursor, 0);
1498 uint8_t const * const pbFirstOpcode = rtDwarfCursor_CalcPos(pCursor, LnState.Hdr.offFirstOpcode);
1499
1500 LnState.Hdr.cbMinInstr = rtDwarfCursor_GetUByte(pCursor, 0);
1501 if (LnState.Hdr.uVer >= 4)
1502 LnState.Hdr.cMaxOpsPerInstr = rtDwarfCursor_GetUByte(pCursor, 0);
1503 else
1504 LnState.Hdr.cMaxOpsPerInstr = 1;
1505 LnState.Hdr.u8DefIsStmt = rtDwarfCursor_GetUByte(pCursor, 0);
1506 LnState.Hdr.s8LineBase = rtDwarfCursor_GetSByte(pCursor, 0);
1507 LnState.Hdr.u8LineRange = rtDwarfCursor_GetUByte(pCursor, 0);
1508 LnState.Hdr.u8OpcodeBase = rtDwarfCursor_GetUByte(pCursor, 0);
1509
1510 if ( !LnState.Hdr.u8OpcodeBase
1511 || !LnState.Hdr.cMaxOpsPerInstr
1512 || !LnState.Hdr.u8LineRange
1513 || LnState.Hdr.u8DefIsStmt > 1)
1514 return VERR_DWARF_BAD_LINE_NUMBER_HEADER;
1515 Log2(("DWARF Line number header:\n"
1516 " uVer %d\n"
1517 " offFirstOpcode %#llx\n"
1518 " cbMinInstr %u\n"
1519 " cMaxOpsPerInstr %u\n"
1520 " u8DefIsStmt %u\n"
1521 " s8LineBase %d\n"
1522 " u8LineRange %u\n"
1523 " u8OpcodeBase %u\n",
1524 LnState.Hdr.uVer, LnState.Hdr.offFirstOpcode, LnState.Hdr.cbMinInstr, LnState.Hdr.cMaxOpsPerInstr,
1525 LnState.Hdr.u8DefIsStmt, LnState.Hdr.s8LineBase, LnState.Hdr.u8LineRange, LnState.Hdr.u8OpcodeBase));
1526
1527 LnState.Hdr.pacStdOperands = pCursor->pb;
1528 for (uint8_t iStdOpcode = 1; iStdOpcode < LnState.Hdr.u8OpcodeBase; iStdOpcode++)
1529 rtDwarfCursor_GetUByte(pCursor, 0);
1530
1531 int rc = pCursor->rc;
1532 if (RT_SUCCESS(rc))
1533 rc = rtDwarfLine_ReadIncludePaths(&LnState, pCursor);
1534 if (RT_SUCCESS(rc))
1535 rc = rtDwarfLine_ReadFileNames(&LnState, pCursor);
1536
1537 /*
1538 * Run the program....
1539 */
1540 if (RT_SUCCESS(rc))
1541 rc = rtDwarfCursor_AdvanceToPos(pCursor, pbFirstOpcode);
1542 if (RT_SUCCESS(rc))
1543 rc = rtDwarfLine_RunProgram(&LnState, pCursor);
1544
1545 /*
1546 * Clean up.
1547 */
1548 size_t i = LnState.cFileNames;
1549 while (i-- > 0)
1550 RTStrFree(LnState.papszFileNames[i]);
1551 RTMemFree(LnState.papszFileNames);
1552 RTMemFree(LnState.papszIncPaths);
1553
1554 Assert(rtDwarfCursor_IsAtEndOfUnit(pCursor) || RT_FAILURE(rc));
1555 return rc;
1556}
1557
1558
1559/**
1560 * Explodes the line number table.
1561 *
1562 * The line numbers are insered into the debug info container.
1563 *
1564 * @returns IPRT status code
1565 * @param pThis The DWARF instance.
1566 */
1567static int rtDwarfLine_ExplodeAll(PRTDBGMODDWARF pThis)
1568{
1569 if (!pThis->aSections[krtDbgModDwarfSect_line].fPresent)
1570 return VINF_SUCCESS;
1571
1572 RTDWARFCURSOR Cursor;
1573 int rc = rtDwarfCursor_Init(&Cursor, pThis, krtDbgModDwarfSect_line);
1574 if (RT_FAILURE(rc))
1575 return rc;
1576
1577 while ( !rtDwarfCursor_IsAtEnd(&Cursor)
1578 && RT_SUCCESS(rc))
1579 rc = rtDwarfLine_ExplodeUnit(pThis, &Cursor);
1580
1581 return rtDwarfCursor_Delete(&Cursor, rc);
1582}
1583
1584
1585/*
1586 *
1587 * DWARF Abbreviations.
1588 * DWARF Abbreviations.
1589 * DWARF Abbreviations.
1590 *
1591 */
1592
1593/**
1594 * Deals with a cache miss in rtDwarfAbbrev_Lookup.
1595 *
1596 * @returns Pointer to abbreviation cache entry (read only). May be rendered
1597 * invalid by subsequent calls to this function.
1598 * @param pThis The DWARF instance.
1599 * @param uCode The abbreviation code to lookup.
1600 */
1601static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t uCode)
1602{
1603 /*
1604 * There is no entry with code zero.
1605 */
1606 if (!uCode)
1607 return NULL;
1608
1609 /*
1610 * Resize the cache array if the code is considered cachable.
1611 */
1612 bool fFillCache = true;
1613 if (pThis->cCachedAbbrevsAlloced < uCode)
1614 {
1615 if (uCode > _64K)
1616 fFillCache = false;
1617 else
1618 {
1619 uint32_t cNew = RT_ALIGN(uCode, 64);
1620 void *pv = RTMemRealloc(pThis->paCachedAbbrevs, sizeof(pThis->paCachedAbbrevs[0]) * cNew);
1621 if (!pv)
1622 fFillCache = false;
1623 else
1624 {
1625 pThis->cCachedAbbrevsAlloced = cNew;
1626 pThis->paCachedAbbrevs = (PRTDWARFABBREV)pv;
1627 }
1628 }
1629 }
1630
1631 /*
1632 * Walk the abbreviations till we find the desired code.
1633 */
1634 RTDWARFCURSOR Cursor;
1635 int rc = rtDwarfCursor_InitWithOffset(&Cursor, pThis, krtDbgModDwarfSect_abbrev, pThis->offCachedAbbrev);
1636 if (RT_FAILURE(rc))
1637 return NULL;
1638
1639 PRTDWARFABBREV pRet = NULL;
1640 if (fFillCache)
1641 {
1642 /*
1643 * Search for the entry and fill the cache while doing so.
1644 */
1645 for (;;)
1646 {
1647 /* Read the 'header'. */
1648 uint32_t const uCurCode = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1649 uint32_t const uCurTag = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1650 uint8_t const uChildren = rtDwarfCursor_GetU8(&Cursor, 0);
1651 if (RT_FAILURE(Cursor.rc))
1652 break;
1653 if ( uCurTag > 0xffff
1654 || uChildren > 1)
1655 {
1656 Cursor.rc = VERR_DWARF_BAD_ABBREV;
1657 break;
1658 }
1659
1660 /* Cache it? */
1661 if (uCurCode >= pThis->cCachedAbbrevsAlloced)
1662 {
1663 PRTDWARFABBREV pEntry = &pThis->paCachedAbbrevs[uCurCode - 1];
1664 while (pThis->cCachedAbbrevs < uCurCode)
1665 {
1666 pThis->paCachedAbbrevs[pThis->cCachedAbbrevs].fFilled = false;
1667 pThis->cCachedAbbrevs++;
1668 }
1669
1670 pEntry->fFilled = true;
1671 pEntry->fChildren = RT_BOOL(uChildren);
1672 pEntry->uTag = uCurTag;
1673 pEntry->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
1674
1675 if (uCurCode == uCode)
1676 {
1677 pRet = pEntry;
1678 if (uCurCode == pThis->cCachedAbbrevsAlloced)
1679 break;
1680 }
1681 }
1682
1683 /* Skip the specification. */
1684 uint32_t uAttr, uForm;
1685 do
1686 {
1687 uAttr = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1688 uForm = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1689 } while (uAttr != 0 && uForm != 0);
1690 if (RT_FAILURE(Cursor.rc))
1691 break;
1692
1693 /* Done? (Maximize cache filling.) */
1694 if ( pRet != NULL
1695 && uCurCode >= pThis->cCachedAbbrevsAlloced)
1696 break;
1697 }
1698 }
1699 else
1700 {
1701 /*
1702 * Search for the entry with the desired code, no cache filling.
1703 */
1704 for (;;)
1705 {
1706 /* Read the 'header'. */
1707 uint32_t const uCurCode = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1708 uint32_t const uCurTag = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1709 uint8_t const uChildren = rtDwarfCursor_GetU8(&Cursor, 0);
1710 if (RT_FAILURE(Cursor.rc))
1711 break;
1712 if ( uCurTag > 0xffff
1713 || uChildren > 1)
1714 {
1715 Cursor.rc = VERR_DWARF_BAD_ABBREV;
1716 break;
1717 }
1718
1719 /* Do we have a match? */
1720 if (uCurCode == uCode)
1721 {
1722 pRet = &pThis->LookupAbbrev;
1723 pRet->fFilled = true;
1724 pRet->fChildren = RT_BOOL(uChildren);
1725 pRet->uTag = uCurTag;
1726 pRet->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
1727 break;
1728 }
1729
1730 /* Skip the specification. */
1731 uint32_t uAttr, uForm;
1732 do
1733 {
1734 uAttr = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1735 uForm = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
1736 } while (uAttr != 0 && uForm != 0);
1737 if (RT_FAILURE(Cursor.rc))
1738 break;
1739 }
1740 }
1741
1742 rtDwarfCursor_Delete(&Cursor, VINF_SUCCESS);
1743 return pRet;
1744}
1745
1746
1747/**
1748 * Looks up an abbreviation.
1749 *
1750 * @returns Pointer to abbreviation cache entry (read only). May be rendered
1751 * invalid by subsequent calls to this function.
1752 * @param pThis The DWARF instance.
1753 * @param uCode The abbreviation code to lookup.
1754 */
1755static PCRTDWARFABBREV rtDwarfAbbrev_Lookup(PRTDBGMODDWARF pThis, uint32_t uCode)
1756{
1757 if ( uCode - 1 >= pThis->cCachedAbbrevs
1758 || !pThis->paCachedAbbrevs[uCode - 1].fFilled)
1759 return rtDwarfAbbrev_LookupMiss(pThis, uCode);
1760 return &pThis->paCachedAbbrevs[uCode - 1];
1761}
1762
1763
1764/**
1765 * Sets the abbreviation offset of the current unit.
1766 *
1767 * This will flush the cached abbreviation entries if the offset differs from
1768 * the previous unit.
1769 *
1770 * @param pThis The DWARF instance.
1771 * @param offAbbrev The offset into the abbreviation section.
1772 */
1773static void rtDwarfAbbrev_SetUnitOffset(PRTDBGMODDWARF pThis, uint32_t offAbbrev)
1774{
1775 if (pThis->offCachedAbbrev != offAbbrev)
1776 {
1777 pThis->offCachedAbbrev = offAbbrev;
1778 pThis->cCachedAbbrevs = 0;
1779 }
1780}
1781
1782
1783/*
1784 *
1785 * DWARF DIE stack (used by the debug_info parser).
1786 * DWARF DIE stack (used by the debug_info parser).
1787 * DWARF DIE stack (used by the debug_info parser).
1788 *
1789 */
1790
1791/**
1792 * DWARF DIE stack entry.
1793 */
1794typedef struct RTDWARFDIESTACKENTRY
1795{
1796 /** The abbreviation code. */
1797 uint32_t uAbbrCode;
1798 /** The tag. */
1799 uint16_t uTag;
1800 /** The offset into the debug_info section of the data. */
1801 uint32_t offData;
1802 /** The associated name. (Points into some dwarf section.) */
1803 const char *pszName;
1804} RTDWARFDIESTACKENTRY;
1805/** Pointer to a DIE stack entry. */
1806typedef RTDWARFDIESTACKENTRY *PRTDWARFDIESTACKENTRY;
1807
1808/**
1809 * DWARF DIE stack.
1810 */
1811typedef struct RTDWARFDIESTACK
1812{
1813 /** The number of items on the stack. */
1814 uint32_t cOnStack;
1815 /** The number of stack entries we've allocated. */
1816 uint32_t cAlloced;
1817 /** Pointer to the stack entries. */
1818 PRTDWARFDIESTACKENTRY paEntries;
1819} RTDWARFDIESTACK;
1820/** Pointer to a DIE stack. */
1821typedef RTDWARFDIESTACK *PRTDWARFDIESTACK;
1822/** Pointer to a const DIE stack. */
1823typedef RTDWARFDIESTACK const *PCRTDWARFDIESTACK;
1824
1825
1826static int rtDwarfDieStack_SetName(PRTDWARFDIESTACK pStack, const char *pszName)
1827{
1828 uint32_t i = pStack->cOnStack;
1829 if (i == 0)
1830 return VERR_DWARF_BAD_INFO;
1831 i--;
1832 pStack->paEntries[i].pszName = pszName;
1833 return VINF_SUCCESS;
1834}
1835
1836
1837static int rtDwarfDieStack_Push(PRTDWARFDIESTACK pStack, uint32_t uAbbrCode, uint16_t uTag, uint32_t offData)
1838{
1839 uint32_t i = pStack->cOnStack;
1840 if (i == pStack->cAlloced)
1841 {
1842 uint32_t cNewSize = pStack->cAlloced ? pStack->cAlloced * 2 : 1 /*16*/;
1843 void *pv = RTMemRealloc(pStack->paEntries, sizeof(pStack->paEntries[0]) * cNewSize);
1844 if (!pv)
1845 return VERR_NO_MEMORY;
1846 pStack->paEntries = (PRTDWARFDIESTACKENTRY)pv;
1847 pStack->cAlloced = cNewSize;
1848 }
1849 Assert(i < pStack->cAlloced);
1850
1851 pStack->paEntries[i].uAbbrCode = uAbbrCode;
1852 pStack->paEntries[i].uTag = uTag;
1853 pStack->paEntries[i].offData = offData;
1854 pStack->paEntries[i].pszName = NULL;
1855 pStack->cOnStack = i + 1;
1856
1857 return VINF_SUCCESS;
1858}
1859
1860
1861static int rtDwarfDieStack_Pop(PRTDWARFDIESTACK pStack)
1862{
1863 if (pStack->cOnStack == 0)
1864 return VERR_DWARF_BAD_INFO;
1865 pStack->cOnStack--;
1866 return VINF_SUCCESS;
1867}
1868
1869
1870static void rtDwarfDieStack_Init(PRTDWARFDIESTACK pStack)
1871{
1872 pStack->cOnStack = 0;
1873 pStack->cAlloced = 0;
1874 pStack->paEntries = NULL;
1875}
1876
1877
1878static void rtDwarfDieStack_Delete(PRTDWARFDIESTACK pStack)
1879{
1880 RTMemFree(pStack->paEntries);
1881 pStack->paEntries = NULL;
1882}
1883
1884
1885
1886/*
1887 *
1888 * DWARF debug_info parser
1889 * DWARF debug_info parser
1890 * DWARF debug_info parser
1891 *
1892 */
1893
1894
1895/**
1896 * Parse a DIE.
1897 *
1898 * @returns IPRT status code.
1899 * @param pThis The DWARF instance.
1900 * @param pCursor The debug_info cursor.
1901 * @param pAbbrev The abbreviation entry.
1902 * @param pAbbrevCursor The abbreviation cursor.
1903 * @param pStack The DIE stack.
1904 */
1905static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor,
1906 PCRTDWARFABBREV pAbbrev, PRTDWARFCURSOR pAbbrevCursor,
1907 PRTDWARFDIESTACK pStack)
1908{
1909 return VERR_NOT_IMPLEMENTED;
1910}
1911
1912
1913
1914static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor)
1915{
1916 /*
1917 * Read the compilation unit header.
1918 */
1919 rtDwarfCursor_GetInitalLength(pCursor);
1920 uint16_t const uVer = rtDwarfCursor_GetUHalf(pCursor, 0);
1921 if ( uVer < 2
1922 || uVer > 4)
1923 return rtDwarfCursor_SkipUnit(pCursor);
1924 uint64_t const offAbbrev = rtDwarfCursor_GetUOff(pCursor, UINT64_MAX);
1925 uint8_t const cbNativeAddr = rtDwarfCursor_GetU8(pCursor, UINT8_MAX);
1926 if (RT_FAILURE(pCursor->rc))
1927 return pCursor->rc;
1928
1929 /*
1930 * Set up the abbreviation cache and store the native address size in the cursor.
1931 */
1932 if (offAbbrev > UINT32_MAX)
1933 return VERR_DWARF_BAD_INFO;
1934 rtDwarfAbbrev_SetUnitOffset(pThis, offAbbrev);
1935 pCursor->cbNativeAddr = cbNativeAddr;
1936
1937 /*
1938 * We want a DIE stack as well.
1939 */
1940 RTDWARFDIESTACK Stack;
1941 rtDwarfDieStack_Init(&Stack);
1942
1943 /*
1944 * Parse DIEs.
1945 */
1946 int rc = VINF_SUCCESS;
1947 while (!rtDwarfCursor_IsAtEndOfUnit(pCursor))
1948 {
1949 uint32_t uAbbrCode = rtDwarfCursor_GetULeb128AsU32(pCursor, UINT32_MAX);
1950
1951 if (!uAbbrCode)
1952 {
1953 /* End of siblings, pop the stack. */
1954 rc = rtDwarfDieStack_Pop(&Stack);
1955 if (RT_FAILURE(rc))
1956 break;
1957 }
1958 else
1959 {
1960 /*
1961 * Look up the abbreviation.
1962 */
1963 PCRTDWARFABBREV pAbbrev = rtDwarfAbbrev_Lookup(pThis, uAbbrCode);
1964 if (!pAbbrev)
1965 {
1966 rc = VERR_DWARF_ABBREV_NOT_FOUND;
1967 break;
1968 }
1969
1970 /*
1971 * If this DIE has children, push it onto the stack.
1972 */
1973 if (pAbbrev->fChildren)
1974 {
1975 rc = rtDwarfDieStack_Push(&Stack, uAbbrCode, pAbbrev->uTag, rtDwarfCursor_CalcSectOffsetU32(pCursor));
1976 if (RT_FAILURE(rc))
1977 break;
1978 }
1979
1980 /*
1981 * Parse it.
1982 */
1983 RTDWARFCURSOR AbbrevCursor;
1984 rc = rtDwarfCursor_InitWithOffset(&AbbrevCursor, pThis, krtDbgModDwarfSect_abbrev, pAbbrev->offSpec);
1985 if (RT_SUCCESS(rc))
1986 {
1987 rc = rtDwarfInfo_ParseDie(pThis, pCursor, pAbbrev, &AbbrevCursor, &Stack);
1988 rc = rtDwarfCursor_Delete(&AbbrevCursor, rc);
1989 }
1990 if (RT_FAILURE(rc))
1991 break;
1992 }
1993 }
1994
1995 rtDwarfDieStack_Delete(&Stack);
1996 return RT_SUCCESS(rc) ? pCursor->rc : rc;
1997}
1998
1999
2000/**
2001 * Extracts the symbols.
2002 *
2003 * The symbols are insered into the debug info container.
2004 *
2005 * @returns IPRT status code
2006 * @param pThis The DWARF instance.
2007 */
2008static int rtDwarfInfo_LoadAll(PRTDBGMODDWARF pThis)
2009{
2010 RTDWARFCURSOR Cursor;
2011 int rc = rtDwarfCursor_Init(&Cursor, pThis, krtDbgModDwarfSect_info);
2012 if (RT_FAILURE(rc))
2013 return rc;
2014
2015 while ( !rtDwarfCursor_IsAtEnd(&Cursor)
2016 && RT_SUCCESS(rc))
2017 rc = rtDwarfInfo_LoadUnit(pThis, &Cursor);
2018
2019 return rtDwarfCursor_Delete(&Cursor, rc);
2020}
2021
2022
2023
2024
2025/*
2026 *
2027 * DWARF Debug module implementation.
2028 * DWARF Debug module implementation.
2029 * DWARF Debug module implementation.
2030 *
2031 */
2032
2033
2034/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
2035static DECLCALLBACK(int) rtDbgModDwarf_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
2036 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
2037{
2038 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2039 return RTDbgModLineByAddr(pThis->hCnt, iSeg, off, poffDisp, pLineInfo);
2040}
2041
2042
2043/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
2044static DECLCALLBACK(int) rtDbgModDwarf_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
2045{
2046 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2047 return RTDbgModLineByOrdinal(pThis->hCnt, iOrdinal, pLineInfo);
2048}
2049
2050
2051/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
2052static DECLCALLBACK(uint32_t) rtDbgModDwarf_LineCount(PRTDBGMODINT pMod)
2053{
2054 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2055 return RTDbgModLineCount(pThis->hCnt);
2056}
2057
2058
2059/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
2060static DECLCALLBACK(int) rtDbgModDwarf_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
2061 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
2062{
2063 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2064 return RTDbgModLineAdd(pThis->hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
2065}
2066
2067
2068/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
2069static DECLCALLBACK(int) rtDbgModDwarf_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
2070 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
2071{
2072 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2073 return RTDbgModSymbolByAddr(pThis->hCnt, iSeg, off, poffDisp, pSymInfo);
2074}
2075
2076
2077/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
2078static DECLCALLBACK(int) rtDbgModDwarf_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
2079 PRTDBGSYMBOL pSymInfo)
2080{
2081 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2082 Assert(!pszSymbol[cchSymbol]);
2083 return RTDbgModSymbolByName(pThis->hCnt, pszSymbol/*, cchSymbol*/, pSymInfo);
2084}
2085
2086
2087/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
2088static DECLCALLBACK(int) rtDbgModDwarf_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
2089{
2090 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2091 return RTDbgModSymbolByOrdinal(pThis->hCnt, iOrdinal, pSymInfo);
2092}
2093
2094
2095/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
2096static DECLCALLBACK(uint32_t) rtDbgModDwarf_SymbolCount(PRTDBGMODINT pMod)
2097{
2098 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2099 return RTDbgModSymbolCount(pThis->hCnt);
2100}
2101
2102
2103/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
2104static DECLCALLBACK(int) rtDbgModDwarf_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
2105 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
2106 uint32_t *piOrdinal)
2107{
2108 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2109 return RTDbgModSymbolAdd(pThis->hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
2110}
2111
2112
2113/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
2114static DECLCALLBACK(int) rtDbgModDwarf_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
2115{
2116 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2117 return RTDbgModSegmentByIndex(pThis->hCnt, iSeg, pSegInfo);
2118}
2119
2120
2121/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
2122static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDwarf_SegmentCount(PRTDBGMODINT pMod)
2123{
2124 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2125 return RTDbgModSegmentCount(pThis->hCnt);
2126}
2127
2128
2129/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
2130static DECLCALLBACK(int) rtDbgModDwarf_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
2131 uint32_t fFlags, PRTDBGSEGIDX piSeg)
2132{
2133 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2134 return RTDbgModSegmentAdd(pThis->hCnt, uRva, cb, pszName, fFlags, piSeg);
2135}
2136
2137
2138/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
2139static DECLCALLBACK(RTUINTPTR) rtDbgModDwarf_ImageSize(PRTDBGMODINT pMod)
2140{
2141 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2142 RTUINTPTR cb1 = RTDbgModImageSize(pThis->hCnt);
2143 RTUINTPTR cb2 = pMod->pImgVt->pfnImageSize(pMod);
2144 return RT_MAX(cb1, cb2);
2145}
2146
2147
2148/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
2149static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDwarf_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
2150{
2151 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2152 return RTDbgModRvaToSegOff(pThis->hCnt, uRva, poffSeg);
2153}
2154
2155
2156/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
2157static DECLCALLBACK(int) rtDbgModDwarf_Close(PRTDBGMODINT pMod)
2158{
2159 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
2160
2161 for (unsigned iSect = 0; iSect < RT_ELEMENTS(pThis->aSections); iSect++)
2162 if (pThis->aSections[iSect].pv)
2163 pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb, &pThis->aSections[iSect].pv);
2164
2165 RTDbgModRelease(pThis->hCnt);
2166 RTMemFree(pThis->paCachedAbbrevs);
2167 RTMemFree(pThis);
2168
2169 return VINF_SUCCESS;
2170}
2171
2172
2173/** @callback_method_impl{FNRTLDRENUMDBG} */
2174static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iDbgInfo, RTLDRDBGINFOTYPE enmType,
2175 uint16_t iMajorVer, uint16_t iMinorVer, const char *pszPartNm,
2176 RTFOFF offFile, RTLDRADDR LinkAddress, RTLDRADDR cb,
2177 const char *pszExtFile, void *pvUser)
2178{
2179 /*
2180 * Skip stuff we can't handle.
2181 */
2182 if ( enmType != RTLDRDBGINFOTYPE_DWARF
2183 || !pszPartNm
2184 || pszExtFile)
2185 return VINF_SUCCESS;
2186
2187 /*
2188 * Must have a part name starting with debug_ and possibly prefixed by dots
2189 * or underscores.
2190 */
2191 if (!strncmp(pszPartNm, ".debug_", sizeof(".debug_") - 1)) /* ELF */
2192 pszPartNm += sizeof(".debug_") - 1;
2193 else if (!strncmp(pszPartNm, "__debug_", sizeof("__debug_") - 1)) /* Mach-O */
2194 pszPartNm += sizeof("__debug_") - 1;
2195 else
2196 AssertMsgFailedReturn(("%s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
2197
2198 /*
2199 * Figure out which part we're talking about.
2200 */
2201 krtDbgModDwarfSect enmSect;
2202 if (0) { /* dummy */ }
2203#define ELSE_IF_STRCMP_SET(a_Name) else if (!strcmp(pszPartNm, #a_Name)) enmSect = krtDbgModDwarfSect_ ## a_Name
2204 ELSE_IF_STRCMP_SET(abbrev);
2205 ELSE_IF_STRCMP_SET(aranges);
2206 ELSE_IF_STRCMP_SET(frame);
2207 ELSE_IF_STRCMP_SET(info);
2208 ELSE_IF_STRCMP_SET(inlined);
2209 ELSE_IF_STRCMP_SET(line);
2210 ELSE_IF_STRCMP_SET(loc);
2211 ELSE_IF_STRCMP_SET(macinfo);
2212 ELSE_IF_STRCMP_SET(pubnames);
2213 ELSE_IF_STRCMP_SET(pubtypes);
2214 ELSE_IF_STRCMP_SET(ranges);
2215 ELSE_IF_STRCMP_SET(str);
2216 ELSE_IF_STRCMP_SET(types);
2217#undef ELSE_IF_STRCMP_SET
2218 else
2219 {
2220 AssertMsgFailed(("%s\n", pszPartNm));
2221 return VINF_SUCCESS;
2222 }
2223
2224 /*
2225 * Record the section.
2226 */
2227 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
2228 AssertMsgReturn(!pThis->aSections[enmSect].fPresent, ("duplicate %s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
2229
2230 pThis->aSections[enmSect].fPresent = true;
2231 pThis->aSections[enmSect].offFile = offFile;
2232 pThis->aSections[enmSect].pv = NULL;
2233 pThis->aSections[enmSect].cb = (size_t)cb;
2234 if (pThis->aSections[enmSect].cb != cb)
2235 pThis->aSections[enmSect].cb = ~(size_t)0;
2236
2237 return VINF_SUCCESS;
2238}
2239
2240
2241/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
2242static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
2243{
2244 /*
2245 * DWARF is only supported when part of an image.
2246 */
2247 if (!pMod->pImgVt)
2248 return VERR_DBG_NO_MATCHING_INTERPRETER;
2249
2250 /*
2251 * Enumerate the debug info in the module, looking for DWARF bits.
2252 */
2253 PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)RTMemAllocZ(sizeof(*pThis));
2254 if (!pThis)
2255 return VERR_NO_MEMORY;
2256 pThis->pMod = pMod;
2257
2258 int rc = pMod->pImgVt->pfnEnumDbgInfo(pMod, rtDbgModDwarfEnumCallback, pThis);
2259 if (RT_SUCCESS(rc))
2260 {
2261 if (pThis->aSections[krtDbgModDwarfSect_info].fPresent)
2262 {
2263 /*
2264 * Extract / explode the data we want (symbols and line numbers)
2265 * storing them in a container module.
2266 */
2267 rc = RTDbgModCreate(&pThis->hCnt, pMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
2268 if (RT_SUCCESS(rc))
2269 {
2270 pMod->pvDbgPriv = pThis;
2271
2272 rc = rtDbgModHlpAddSegmentsFromImage(pMod);
2273 if (RT_SUCCESS(rc))
2274 rc = rtDwarfInfo_LoadAll(pThis);
2275 if (RT_SUCCESS(rc))
2276 rc = rtDwarfLine_ExplodeAll(pThis);
2277 if (RT_SUCCESS(rc))
2278 {
2279 /*
2280 * Free the cached abbreviations and unload all sections.
2281 */
2282 pThis->cCachedAbbrevs = pThis->cCachedAbbrevsAlloced = 0;
2283 RTMemFree(pThis->paCachedAbbrevs);
2284
2285 for (unsigned iSect = 0; iSect < RT_ELEMENTS(pThis->aSections); iSect++)
2286 if (pThis->aSections[iSect].pv)
2287 pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb,
2288 &pThis->aSections[iSect].pv);
2289
2290
2291 return VINF_SUCCESS;
2292 }
2293
2294 /* bail out. */
2295 RTDbgModRelease(pThis->hCnt);
2296 pMod->pvDbgPriv = NULL;
2297 }
2298 }
2299 else
2300 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
2301 }
2302 RTMemFree(pThis->paCachedAbbrevs);
2303 RTMemFree(pThis);
2304
2305 return rc;
2306}
2307
2308
2309
2310/** Virtual function table for the DWARF debug info reader. */
2311DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgDwarf =
2312{
2313 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
2314 /*.fSupports = */ RT_DBGTYPE_DWARF,
2315 /*.pszName = */ "dwarf",
2316 /*.pfnTryOpen = */ rtDbgModDwarf_TryOpen,
2317 /*.pfnClose = */ rtDbgModDwarf_Close,
2318
2319 /*.pfnRvaToSegOff = */ rtDbgModDwarf_RvaToSegOff,
2320 /*.pfnImageSize = */ rtDbgModDwarf_ImageSize,
2321
2322 /*.pfnSegmentAdd = */ rtDbgModDwarf_SegmentAdd,
2323 /*.pfnSegmentCount = */ rtDbgModDwarf_SegmentCount,
2324 /*.pfnSegmentByIndex = */ rtDbgModDwarf_SegmentByIndex,
2325
2326 /*.pfnSymbolAdd = */ rtDbgModDwarf_SymbolAdd,
2327 /*.pfnSymbolCount = */ rtDbgModDwarf_SymbolCount,
2328 /*.pfnSymbolByOrdinal = */ rtDbgModDwarf_SymbolByOrdinal,
2329 /*.pfnSymbolByName = */ rtDbgModDwarf_SymbolByName,
2330 /*.pfnSymbolByAddr = */ rtDbgModDwarf_SymbolByAddr,
2331
2332 /*.pfnLineAdd = */ rtDbgModDwarf_LineAdd,
2333 /*.pfnLineCount = */ rtDbgModDwarf_LineCount,
2334 /*.pfnLineByOrdinal = */ rtDbgModDwarf_LineByOrdinal,
2335 /*.pfnLineByAddr = */ rtDbgModDwarf_LineByAddr,
2336
2337 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
2338};
2339
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