summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp')
-rw-r--r--src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp1647
1 files changed, 1458 insertions, 189 deletions
diff --git a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
index b1757877..6e11da29 100644
--- a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -38,8 +38,13 @@
#include <iprt/list.h>
#include <iprt/log.h>
#include <iprt/mem.h>
+#define RTDBGMODDWARF_WITH_MEM_CACHE
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+# include <iprt/memcache.h>
+#endif
#include <iprt/path.h>
#include <iprt/string.h>
+#include <iprt/strcache.h>
#include "internal/dbgmod.h"
@@ -136,6 +141,8 @@
#define DW_TAG_rvalue_reference_type UINT16_C(0x0042)
#define DW_TAG_template_alias UINT16_C(0x0043)
#define DW_TAG_lo_user UINT16_C(0x4080)
+#define DW_TAG_GNU_call_site UINT16_C(0x4109)
+#define DW_TAG_GNU_call_site_parameter UINT16_C(0x410a)
#define DW_TAG_hi_user UINT16_C(0xffff)
/** @} */
@@ -235,6 +242,8 @@
#define DW_AT_enum_class UINT16_C(0x006d)
#define DW_AT_linkage_name UINT16_C(0x006e)
#define DW_AT_lo_user UINT16_C(0x2000)
+/** Used by GCC and others, same as DW_AT_linkage_name. See http://wiki.dwarfstd.org/index.php?title=DW_AT_linkage_name*/
+#define DW_AT_MIPS_linkage_name UINT16_C(0x2007)
#define DW_AT_hi_user UINT16_C(0x3fff)
/** @} */
@@ -279,6 +288,68 @@
/** @} */
+/** @name Location Expression Opcodes
+ * @{ */
+#define DW_OP_addr UINT8_C(0x03) /**< 1 operand, a constant address (size target specific). */
+#define DW_OP_deref UINT8_C(0x06) /**< 0 operands. */
+#define DW_OP_const1u UINT8_C(0x08) /**< 1 operand, a 1-byte constant. */
+#define DW_OP_const1s UINT8_C(0x09) /**< 1 operand, a 1-byte constant. */
+#define DW_OP_const2u UINT8_C(0x0a) /**< 1 operand, a 2-byte constant. */
+#define DW_OP_const2s UINT8_C(0x0b) /**< 1 operand, a 2-byte constant. */
+#define DW_OP_const4u UINT8_C(0x0c) /**< 1 operand, a 4-byte constant. */
+#define DW_OP_const4s UINT8_C(0x0d) /**< 1 operand, a 4-byte constant. */
+#define DW_OP_const8u UINT8_C(0x0e) /**< 1 operand, a 8-byte constant. */
+#define DW_OP_const8s UINT8_C(0x0f) /**< 1 operand, a 8-byte constant. */
+#define DW_OP_constu UINT8_C(0x10) /**< 1 operand, a ULEB128 constant. */
+#define DW_OP_consts UINT8_C(0x11) /**< 1 operand, a SLEB128 constant. */
+#define DW_OP_dup UINT8_C(0x12) /**< 0 operands. */
+#define DW_OP_drop UINT8_C(0x13) /**< 0 operands. */
+#define DW_OP_over UINT8_C(0x14) /**< 0 operands. */
+#define DW_OP_pick UINT8_C(0x15) /**< 1 operands, a 1-byte stack index. */
+#define DW_OP_swap UINT8_C(0x16) /**< 0 operands. */
+#define DW_OP_rot UINT8_C(0x17) /**< 0 operands. */
+#define DW_OP_xderef UINT8_C(0x18) /**< 0 operands. */
+#define DW_OP_abs UINT8_C(0x19) /**< 0 operands. */
+#define DW_OP_and UINT8_C(0x1a) /**< 0 operands. */
+#define DW_OP_div UINT8_C(0x1b) /**< 0 operands. */
+#define DW_OP_minus UINT8_C(0x1c) /**< 0 operands. */
+#define DW_OP_mod UINT8_C(0x1d) /**< 0 operands. */
+#define DW_OP_mul UINT8_C(0x1e) /**< 0 operands. */
+#define DW_OP_neg UINT8_C(0x1f) /**< 0 operands. */
+#define DW_OP_not UINT8_C(0x20) /**< 0 operands. */
+#define DW_OP_or UINT8_C(0x21) /**< 0 operands. */
+#define DW_OP_plus UINT8_C(0x22) /**< 0 operands. */
+#define DW_OP_plus_uconst UINT8_C(0x23) /**< 1 operands, a ULEB128 addend. */
+#define DW_OP_shl UINT8_C(0x24) /**< 0 operands. */
+#define DW_OP_shr UINT8_C(0x25) /**< 0 operands. */
+#define DW_OP_shra UINT8_C(0x26) /**< 0 operands. */
+#define DW_OP_xor UINT8_C(0x27) /**< 0 operands. */
+#define DW_OP_skip UINT8_C(0x2f) /**< 1 signed 2-byte constant. */
+#define DW_OP_bra UINT8_C(0x28) /**< 1 signed 2-byte constant. */
+#define DW_OP_eq UINT8_C(0x29) /**< 0 operands. */
+#define DW_OP_ge UINT8_C(0x2a) /**< 0 operands. */
+#define DW_OP_gt UINT8_C(0x2b) /**< 0 operands. */
+#define DW_OP_le UINT8_C(0x2c) /**< 0 operands. */
+#define DW_OP_lt UINT8_C(0x2d) /**< 0 operands. */
+#define DW_OP_ne UINT8_C(0x2e) /**< 0 operands. */
+#define DW_OP_lit0 UINT8_C(0x30) /**< 0 operands - literals 0..31 */
+#define DW_OP_lit31 UINT8_C(0x4f) /**< last litteral. */
+#define DW_OP_reg0 UINT8_C(0x50) /**< 0 operands - reg 0..31. */
+#define DW_OP_reg31 UINT8_C(0x6f) /**< last register. */
+#define DW_OP_breg0 UINT8_C(0x70) /**< 1 operand, a SLEB128 offset. */
+#define DW_OP_breg31 UINT8_C(0x8f) /**< last branch register. */
+#define DW_OP_regx UINT8_C(0x90) /**< 1 operand, a ULEB128 register. */
+#define DW_OP_fbreg UINT8_C(0x91) /**< 1 operand, a SLEB128 offset. */
+#define DW_OP_bregx UINT8_C(0x92) /**< 2 operands, a ULEB128 register followed by a SLEB128 offset. */
+#define DW_OP_piece UINT8_C(0x93) /**< 1 operand, a ULEB128 size of piece addressed. */
+#define DW_OP_deref_size UINT8_C(0x94) /**< 1 operand, a 1-byte size of data retrieved. */
+#define DW_OP_xderef_size UINT8_C(0x95) /**< 1 operand, a 1-byte size of data retrieved. */
+#define DW_OP_nop UINT8_C(0x96) /**< 0 operands. */
+#define DW_OP_lo_user UINT8_C(0xe0) /**< First user opcode */
+#define DW_OP_hi_user UINT8_C(0xff) /**< Last user opcode. */
+/** @} */
+
+
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
@@ -318,20 +389,38 @@ typedef enum krtDbgModDwarfSect
*/
typedef struct RTDWARFABBREV
{
- /** Whether this entry is filled in or not. */
- bool fFilled;
/** Whether there are children or not. */
bool fChildren;
/** The tag. */
uint16_t uTag;
/** Offset into the abbrev section of the specification pairs. */
uint32_t offSpec;
+ /** The abbreviation table offset this is entry is valid for.
+ * UINT32_MAX if not valid. */
+ uint32_t offAbbrev;
} RTDWARFABBREV;
/** Pointer to an abbreviation cache entry. */
typedef RTDWARFABBREV *PRTDWARFABBREV;
/** Pointer to a const abbreviation cache entry. */
typedef RTDWARFABBREV const *PCRTDWARFABBREV;
+/**
+ * Structure for gathering segment info.
+ */
+typedef struct RTDBGDWARFSEG
+{
+ /** The highest offset in the segment. */
+ uint64_t offHighest;
+ /** Calculated base address. */
+ uint64_t uBaseAddr;
+ /** Estimated The segment size. */
+ uint64_t cbSegment;
+ /** Segment number (RTLDRSEG::Sel16bit). */
+ RTSEL uSegment;
+} RTDBGDWARFSEG;
+/** Pointer to segment info. */
+typedef RTDBGDWARFSEG *PRTDBGDWARFSEG;
+
/**
* The instance data of the DWARF reader.
@@ -340,8 +429,12 @@ typedef struct RTDBGMODDWARF
{
/** The debug container containing doing the real work. */
RTDBGMOD hCnt;
- /** Pointer to back to the debug info module (no reference ofc). */
- PRTDBGMODINT pMod;
+ /** The image module (no reference). */
+ PRTDBGMODINT pImgMod;
+ /** The debug info module (no reference). */
+ PRTDBGMODINT pDbgInfoMod;
+ /** Nested image module (with reference ofc). */
+ PRTDBGMODINT pNestedMod;
/** DWARF debug info sections. */
struct
@@ -354,14 +447,14 @@ typedef struct RTDBGMODDWARF
void const *pv;
/** Set if present. */
bool fPresent;
+ /** The debug info ordinal number in the image file. */
+ uint32_t iDbgInfo;
} aSections[krtDbgModDwarfSect_End];
/** The offset into the abbreviation section of the current cache. */
uint32_t offCachedAbbrev;
/** The number of cached abbreviations we've allocated space for. */
uint32_t cCachedAbbrevsAlloced;
- /** Used for range checking cache lookups. */
- uint32_t cCachedAbbrevs;
/** Array of cached abbreviations, indexed by code. */
PRTDWARFABBREV paCachedAbbrevs;
/** Used by rtDwarfAbbrev_Lookup when the result is uncachable. */
@@ -369,6 +462,34 @@ typedef struct RTDBGMODDWARF
/** The list of compilation units (RTDWARFDIE). */
RTLISTANCHOR CompileUnitList;
+
+ /** Set if we have to use link addresses because the module does not have
+ * fixups (mach_kernel). */
+ bool fUseLinkAddress;
+ /** This is set to -1 if we're doing everything in one pass.
+ * Otherwise it's 1 or 2:
+ * - In pass 1, we collect segment info.
+ * - In pass 2, we add debug info to the container.
+ * The two pass parsing is necessary for watcom generated symbol files as
+ * these contains no information about the code and data segments in the
+ * image. So we have to figure out some approximate stuff based on the
+ * segments and offsets we encounter in the debug info. */
+ int8_t iWatcomPass;
+ /** Segment index hint. */
+ uint16_t iSegHint;
+ /** The number of segments in paSegs.
+ * (During segment copying, this is abused to count useful segments.) */
+ uint32_t cSegs;
+ /** Pointer to segments if iWatcomPass isn't -1. */
+ PRTDBGDWARFSEG paSegs;
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ /** DIE allocators. */
+ struct
+ {
+ RTMEMCACHE hMemCache;
+ uint32_t cbMax;
+ } aDieAllocators[2];
+#endif
} RTDBGMODDWARF;
/** Pointer to instance data of the DWARF reader. */
typedef RTDBGMODDWARF *PRTDBGMODDWARF;
@@ -424,6 +545,7 @@ typedef struct RTDWARFLINESTATE
bool fEpilogueBegin;
uint32_t uIsa;
uint32_t uDiscriminator;
+ RTSEL uSegment;
} Regs;
/** @} */
@@ -481,11 +603,12 @@ typedef FNRTDWARFATTRDECODER *PFNRTDWARFATTRDECODER;
typedef struct RTDWARFATTRDESC
{
/** The attribute. */
- uint8_t uAttr;
- /** The data member size and initialization method. */
- uint8_t cbInit;
+ uint16_t uAttr;
/** The data member offset. */
uint16_t off;
+ /** The data member size and initialization method. */
+ uint8_t cbInit;
+ uint8_t bPadding[3]; /**< Alignment padding. */
/** The decoder function. */
PFNRTDWARFATTRDECODER pfnDecoder;
} RTDWARFATTRDESC;
@@ -494,8 +617,9 @@ typedef struct RTDWARFATTRDESC
#define ATTR_ENTRY(a_uAttr, a_Struct, a_Member, a_Init, a_pfnDecoder) \
{ \
a_uAttr, \
- a_Init | ((uint8_t)RT_SIZEOFMEMB(a_Struct, a_Member) & ATTR_SIZE_MASK), \
(uint16_t)RT_OFFSETOF(a_Struct, a_Member), \
+ a_Init | ((uint8_t)RT_SIZEOFMEMB(a_Struct, a_Member) & ATTR_SIZE_MASK), \
+ { 0, 0, 0 }, \
a_pfnDecoder\
}
@@ -541,7 +665,11 @@ typedef struct RTDWARFDIE
uint8_t cDecodedAttrs;
/** The number of unknown or otherwise unhandled attributes. */
uint8_t cUnhandledAttrs;
- /** The date tag, indicating which union structure to use. */
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ /** The allocator index. */
+ uint8_t iAllocator;
+#endif
+ /** The die tag, indicating which union structure to use. */
uint16_t uTag;
/** Offset of the abbreviation specification (within debug_abbrev). */
uint32_t offSpec;
@@ -571,6 +699,7 @@ typedef struct RTDWARFADDRRANGE
uint8_t cAttrs : 2;
uint8_t fHaveLowAddress : 1;
uint8_t fHaveHighAddress : 1;
+ uint8_t fHaveHighIsAddress : 1;
uint8_t fHaveRanges : 1;
} RTDWARFADDRRANGE;
typedef RTDWARFADDRRANGE *PRTDWARFADDRRANGE;
@@ -602,6 +731,22 @@ typedef RTDWARFREF *PRTDWARFREF;
typedef RTDWARFREF const *PCRTDWARFREF;
+/**
+ * DWARF Location state.
+ */
+typedef struct RTDWARFLOCST
+{
+ /** The input cursor. */
+ RTDWARFCURSOR Cursor;
+ /** Points to the current top of the stack. Initial value -1. */
+ int32_t iTop;
+ /** The value stack. */
+ uint64_t auStack[64];
+} RTDWARFLOCST;
+/** Pointer to location state. */
+typedef RTDWARFLOCST *PRTDWARFLOCST;
+
+
/*******************************************************************************
* Internal Functions *
@@ -614,6 +759,7 @@ static FNRTDWARFATTRDECODER rtDwarfDecode_Reference;
static FNRTDWARFATTRDECODER rtDwarfDecode_SectOff;
static FNRTDWARFATTRDECODER rtDwarfDecode_String;
static FNRTDWARFATTRDECODER rtDwarfDecode_UnsignedInt;
+static FNRTDWARFATTRDECODER rtDwarfDecode_SegmentLoc;
/*******************************************************************************
@@ -635,7 +781,7 @@ typedef struct RTDWARFDIECOMPILEUNIT
/** The address range of the code belonging to this unit. */
RTDWARFADDRRANGE PcRange;
/** The language name. */
- uint8_t uLanguage;
+ uint16_t uLanguage;
/** The identifier case. */
uint8_t uIdentifierCase;
/** String are UTF-8 encoded. If not set, the encoding is
@@ -708,6 +854,10 @@ typedef struct RTDWARFDIESUBPROGRAM
RTDWARFADDRRANGE PcRange;
/** The first instruction in the function. */
RTDWARFADDR EntryPc;
+ /** Segment number (watcom). */
+ RTSEL uSegment;
+ /** Reference to the specification. */
+ RTDWARFREF SpecRef;
} RTDWARFDIESUBPROGRAM;
/** Pointer to a DW_TAG_subprogram DIE. */
typedef RTDWARFDIESUBPROGRAM *PRTDWARFDIESUBPROGRAM;
@@ -720,16 +870,66 @@ static const RTDWARFATTRDESC g_aSubProgramAttrs[] =
{
ATTR_ENTRY(DW_AT_name, RTDWARFDIESUBPROGRAM, pszName, ATTR_INIT_ZERO, rtDwarfDecode_String),
ATTR_ENTRY(DW_AT_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_MIPS_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
ATTR_ENTRY(DW_AT_low_pc, RTDWARFDIESUBPROGRAM, PcRange, ATTR_INIT_ZERO, rtDwarfDecode_LowHighPc),
ATTR_ENTRY(DW_AT_high_pc, RTDWARFDIESUBPROGRAM, PcRange, ATTR_INIT_ZERO, rtDwarfDecode_LowHighPc),
ATTR_ENTRY(DW_AT_ranges, RTDWARFDIESUBPROGRAM, PcRange, ATTR_INIT_ZERO, rtDwarfDecode_Ranges),
ATTR_ENTRY(DW_AT_entry_pc, RTDWARFDIESUBPROGRAM, EntryPc, ATTR_INIT_ZERO, rtDwarfDecode_Address),
+ ATTR_ENTRY(DW_AT_segment, RTDWARFDIESUBPROGRAM, uSegment, ATTR_INIT_ZERO, rtDwarfDecode_SegmentLoc),
+ ATTR_ENTRY(DW_AT_specification, RTDWARFDIESUBPROGRAM, SpecRef, ATTR_INIT_ZERO, rtDwarfDecode_Reference)
};
/** RTDWARFDIESUBPROGRAM description. */
static const RTDWARFDIEDESC g_SubProgramDesc = DIE_DESC_INIT(RTDWARFDIESUBPROGRAM, g_aSubProgramAttrs);
+/** RTDWARFDIESUBPROGRAM attributes for the specification hack. */
+static const RTDWARFATTRDESC g_aSubProgramSpecHackAttrs[] =
+{
+ ATTR_ENTRY(DW_AT_name, RTDWARFDIESUBPROGRAM, pszName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_MIPS_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+};
+
+/** RTDWARFDIESUBPROGRAM description for the specification hack. */
+static const RTDWARFDIEDESC g_SubProgramSpecHackDesc = DIE_DESC_INIT(RTDWARFDIESUBPROGRAM, g_aSubProgramSpecHackAttrs);
+
+
+/**
+ * DW_TAG_label.
+ */
+typedef struct RTDWARFDIELABEL
+{
+ /** The DIE core structure. */
+ RTDWARFDIE Core;
+ /** The name. */
+ const char *pszName;
+ /** The address of the first instruction. */
+ RTDWARFADDR Address;
+ /** Segment number (watcom). */
+ RTSEL uSegment;
+ /** Externally visible? */
+ bool fExternal;
+} RTDWARFDIELABEL;
+/** Pointer to a DW_TAG_label DIE. */
+typedef RTDWARFDIELABEL *PRTDWARFDIELABEL;
+/** Pointer to a const DW_TAG_label DIE. */
+typedef RTDWARFDIELABEL const *PCRTDWARFDIELABEL;
+
+
+/** RTDWARFDIESUBPROGRAM attributes. */
+static const RTDWARFATTRDESC g_aLabelAttrs[] =
+{
+ ATTR_ENTRY(DW_AT_name, RTDWARFDIELABEL, pszName, ATTR_INIT_ZERO, rtDwarfDecode_String),
+ ATTR_ENTRY(DW_AT_low_pc, RTDWARFDIELABEL, Address, ATTR_INIT_ZERO, rtDwarfDecode_Address),
+ ATTR_ENTRY(DW_AT_segment, RTDWARFDIELABEL, uSegment, ATTR_INIT_ZERO, rtDwarfDecode_SegmentLoc),
+ ATTR_ENTRY(DW_AT_external, RTDWARFDIELABEL, fExternal, ATTR_INIT_ZERO, rtDwarfDecode_Bool)
+};
+
+/** RTDWARFDIESUBPROGRAM description. */
+static const RTDWARFDIEDESC g_LabelDesc = DIE_DESC_INIT(RTDWARFDIELABEL, g_aLabelAttrs);
+
+
/**
* Tag names and descriptors.
*/
@@ -756,7 +956,7 @@ static const struct RTDWARFTAGDESC
TAGDESC_EMPTY(),
TAGDESC_CORE(TAG_imported_declaration), /* 0x08 */
TAGDESC_EMPTY(),
- TAGDESC_CORE(TAG_label),
+ TAGDESC(TAG_label, &g_LabelDesc),
TAGDESC_CORE(TAG_lexical_block),
TAGDESC_EMPTY(), /* 0x0c */
TAGDESC_CORE(TAG_member),
@@ -820,19 +1020,226 @@ static const struct RTDWARFTAGDESC
};
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWARFDIEDESC pDieDesc,
+ PRTDWARFCURSOR pCursor, PCRTDWARFABBREV pAbbrev, bool fInitDie);
+
+
+
+#if defined(LOG_ENABLED) || defined(RT_STRICT)
+
+/**
+ * Turns a tag value into a string for logging purposes.
+ *
+ * @returns String name.
+ * @param uTag The tag.
+ */
+static const char *rtDwarfLog_GetTagName(uint32_t uTag)
+{
+ if (uTag < RT_ELEMENTS(g_aTagDescs))
+ {
+ const char *pszTag = g_aTagDescs[uTag].pszName;
+ if (pszTag)
+ return pszTag;
+ }
+
+ static char s_szStatic[32];
+ RTStrPrintf(s_szStatic, sizeof(s_szStatic),"DW_TAG_%#x", uTag);
+ return s_szStatic;
+}
+
+
+/**
+ * Turns an attributevalue into a string for logging purposes.
+ *
+ * @returns String name.
+ * @param uAttr The attribute.
+ */
+static const char *rtDwarfLog_AttrName(uint32_t uAttr)
+{
+ switch (uAttr)
+ {
+ RT_CASE_RET_STR(DW_AT_sibling);
+ RT_CASE_RET_STR(DW_AT_location);
+ RT_CASE_RET_STR(DW_AT_name);
+ RT_CASE_RET_STR(DW_AT_ordering);
+ RT_CASE_RET_STR(DW_AT_byte_size);
+ RT_CASE_RET_STR(DW_AT_bit_offset);
+ RT_CASE_RET_STR(DW_AT_bit_size);
+ RT_CASE_RET_STR(DW_AT_stmt_list);
+ RT_CASE_RET_STR(DW_AT_low_pc);
+ RT_CASE_RET_STR(DW_AT_high_pc);
+ RT_CASE_RET_STR(DW_AT_language);
+ RT_CASE_RET_STR(DW_AT_discr);
+ RT_CASE_RET_STR(DW_AT_discr_value);
+ RT_CASE_RET_STR(DW_AT_visibility);
+ RT_CASE_RET_STR(DW_AT_import);
+ RT_CASE_RET_STR(DW_AT_string_length);
+ RT_CASE_RET_STR(DW_AT_common_reference);
+ RT_CASE_RET_STR(DW_AT_comp_dir);
+ RT_CASE_RET_STR(DW_AT_const_value);
+ RT_CASE_RET_STR(DW_AT_containing_type);
+ RT_CASE_RET_STR(DW_AT_default_value);
+ RT_CASE_RET_STR(DW_AT_inline);
+ RT_CASE_RET_STR(DW_AT_is_optional);
+ RT_CASE_RET_STR(DW_AT_lower_bound);
+ RT_CASE_RET_STR(DW_AT_producer);
+ RT_CASE_RET_STR(DW_AT_prototyped);
+ RT_CASE_RET_STR(DW_AT_return_addr);
+ RT_CASE_RET_STR(DW_AT_start_scope);
+ RT_CASE_RET_STR(DW_AT_bit_stride);
+ RT_CASE_RET_STR(DW_AT_upper_bound);
+ RT_CASE_RET_STR(DW_AT_abstract_origin);
+ RT_CASE_RET_STR(DW_AT_accessibility);
+ RT_CASE_RET_STR(DW_AT_address_class);
+ RT_CASE_RET_STR(DW_AT_artificial);
+ RT_CASE_RET_STR(DW_AT_base_types);
+ RT_CASE_RET_STR(DW_AT_calling_convention);
+ RT_CASE_RET_STR(DW_AT_count);
+ RT_CASE_RET_STR(DW_AT_data_member_location);
+ RT_CASE_RET_STR(DW_AT_decl_column);
+ RT_CASE_RET_STR(DW_AT_decl_file);
+ RT_CASE_RET_STR(DW_AT_decl_line);
+ RT_CASE_RET_STR(DW_AT_declaration);
+ RT_CASE_RET_STR(DW_AT_discr_list);
+ RT_CASE_RET_STR(DW_AT_encoding);
+ RT_CASE_RET_STR(DW_AT_external);
+ RT_CASE_RET_STR(DW_AT_frame_base);
+ RT_CASE_RET_STR(DW_AT_friend);
+ RT_CASE_RET_STR(DW_AT_identifier_case);
+ RT_CASE_RET_STR(DW_AT_macro_info);
+ RT_CASE_RET_STR(DW_AT_namelist_item);
+ RT_CASE_RET_STR(DW_AT_priority);
+ RT_CASE_RET_STR(DW_AT_segment);
+ RT_CASE_RET_STR(DW_AT_specification);
+ RT_CASE_RET_STR(DW_AT_static_link);
+ RT_CASE_RET_STR(DW_AT_type);
+ RT_CASE_RET_STR(DW_AT_use_location);
+ RT_CASE_RET_STR(DW_AT_variable_parameter);
+ RT_CASE_RET_STR(DW_AT_virtuality);
+ RT_CASE_RET_STR(DW_AT_vtable_elem_location);
+ RT_CASE_RET_STR(DW_AT_allocated);
+ RT_CASE_RET_STR(DW_AT_associated);
+ RT_CASE_RET_STR(DW_AT_data_location);
+ RT_CASE_RET_STR(DW_AT_byte_stride);
+ RT_CASE_RET_STR(DW_AT_entry_pc);
+ RT_CASE_RET_STR(DW_AT_use_UTF8);
+ RT_CASE_RET_STR(DW_AT_extension);
+ RT_CASE_RET_STR(DW_AT_ranges);
+ RT_CASE_RET_STR(DW_AT_trampoline);
+ RT_CASE_RET_STR(DW_AT_call_column);
+ RT_CASE_RET_STR(DW_AT_call_file);
+ RT_CASE_RET_STR(DW_AT_call_line);
+ RT_CASE_RET_STR(DW_AT_description);
+ RT_CASE_RET_STR(DW_AT_binary_scale);
+ RT_CASE_RET_STR(DW_AT_decimal_scale);
+ RT_CASE_RET_STR(DW_AT_small);
+ RT_CASE_RET_STR(DW_AT_decimal_sign);
+ RT_CASE_RET_STR(DW_AT_digit_count);
+ RT_CASE_RET_STR(DW_AT_picture_string);
+ RT_CASE_RET_STR(DW_AT_mutable);
+ RT_CASE_RET_STR(DW_AT_threads_scaled);
+ RT_CASE_RET_STR(DW_AT_explicit);
+ RT_CASE_RET_STR(DW_AT_object_pointer);
+ RT_CASE_RET_STR(DW_AT_endianity);
+ RT_CASE_RET_STR(DW_AT_elemental);
+ RT_CASE_RET_STR(DW_AT_pure);
+ RT_CASE_RET_STR(DW_AT_recursive);
+ RT_CASE_RET_STR(DW_AT_signature);
+ RT_CASE_RET_STR(DW_AT_main_subprogram);
+ RT_CASE_RET_STR(DW_AT_data_bit_offset);
+ RT_CASE_RET_STR(DW_AT_const_expr);
+ RT_CASE_RET_STR(DW_AT_enum_class);
+ RT_CASE_RET_STR(DW_AT_linkage_name);
+ RT_CASE_RET_STR(DW_AT_MIPS_linkage_name);
+ }
+ static char s_szStatic[32];
+ RTStrPrintf(s_szStatic, sizeof(s_szStatic),"DW_AT_%#x", uAttr);
+ return s_szStatic;
+}
+
+
+/**
+ * Turns a form value into a string for logging purposes.
+ *
+ * @returns String name.
+ * @param uForm The form.
+ */
+static const char *rtDwarfLog_FormName(uint32_t uForm)
+{
+ switch (uForm)
+ {
+ RT_CASE_RET_STR(DW_FORM_addr);
+ RT_CASE_RET_STR(DW_FORM_block2);
+ RT_CASE_RET_STR(DW_FORM_block4);
+ RT_CASE_RET_STR(DW_FORM_data2);
+ RT_CASE_RET_STR(DW_FORM_data4);
+ RT_CASE_RET_STR(DW_FORM_data8);
+ RT_CASE_RET_STR(DW_FORM_string);
+ RT_CASE_RET_STR(DW_FORM_block);
+ RT_CASE_RET_STR(DW_FORM_block1);
+ RT_CASE_RET_STR(DW_FORM_data1);
+ RT_CASE_RET_STR(DW_FORM_flag);
+ RT_CASE_RET_STR(DW_FORM_sdata);
+ RT_CASE_RET_STR(DW_FORM_strp);
+ RT_CASE_RET_STR(DW_FORM_udata);
+ RT_CASE_RET_STR(DW_FORM_ref_addr);
+ RT_CASE_RET_STR(DW_FORM_ref1);
+ RT_CASE_RET_STR(DW_FORM_ref2);
+ RT_CASE_RET_STR(DW_FORM_ref4);
+ RT_CASE_RET_STR(DW_FORM_ref8);
+ RT_CASE_RET_STR(DW_FORM_ref_udata);
+ RT_CASE_RET_STR(DW_FORM_indirect);
+ RT_CASE_RET_STR(DW_FORM_sec_offset);
+ RT_CASE_RET_STR(DW_FORM_exprloc);
+ RT_CASE_RET_STR(DW_FORM_flag_present);
+ RT_CASE_RET_STR(DW_FORM_ref_sig8);
+ }
+ static char s_szStatic[32];
+ RTStrPrintf(s_szStatic, sizeof(s_szStatic),"DW_FORM_%#x", uForm);
+ return s_szStatic;
+}
+
+#endif /* LOG_ENABLED || RT_STRICT */
+
+
+
/** @callback_method_impl{FNRTLDRENUMSEGS} */
-static DECLCALLBACK(int) rtDbgModHlpAddSegmentCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+static DECLCALLBACK(int) rtDbgModDwarfScanSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
{
- PRTDBGMODINT pMod = (PRTDBGMODINT)pvUser;
+ PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
Log(("Segment %.*s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
- pSeg->cchName, pSeg->pchName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
+ pSeg->cchName, pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
+ NOREF(hLdrMod);
+
+ /* Count relevant segments. */
+ if (pSeg->RVA != NIL_RTLDRADDR)
+ pThis->cSegs++;
+
+ return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNRTLDRENUMSEGS} */
+static DECLCALLBACK(int) rtDbgModDwarfAddSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+{
+ PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
+ Log(("Segment %.*s: LinkAddress=%#llx RVA=%#llx cb=%#llx cbMapped=%#llx\n",
+ pSeg->cchName, pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb, pSeg->cbMapped));
NOREF(hLdrMod);
+ Assert(pSeg->cchName > 0);
+ Assert(!pSeg->pszName[pSeg->cchName]);
+
+ /* If the segment doesn't have a mapping, just add a dummy so the indexing
+ works out correctly (same as for the image). */
+ if (pSeg->RVA == NIL_RTLDRADDR)
+ return RTDbgModSegmentAdd(pThis->hCnt, 0, 0, pSeg->pszName, 0 /*fFlags*/, NULL);
+
+ /* The link address is 0 for all segments in a relocatable ELF image. */
RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
-#if 1
- return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->RVA, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
-#else
- return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->LinkAddress, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
-#endif
+ return RTDbgModSegmentAdd(pThis->hCnt, pSeg->RVA, cb, pSeg->pszName, 0 /*fFlags*/, NULL);
}
@@ -840,15 +1247,158 @@ static DECLCALLBACK(int) rtDbgModHlpAddSegmentCallback(RTLDRMOD hLdrMod, PCRTLDR
* Calls pfnSegmentAdd for each segment in the executable image.
*
* @returns IPRT status code.
- * @param pMod The debug module.
+ * @param pThis The DWARF instance.
*/
-DECLHIDDEN(int) rtDbgModHlpAddSegmentsFromImage(PRTDBGMODINT pMod)
+static int rtDbgModDwarfAddSegmentsFromImage(PRTDBGMODDWARF pThis)
{
- AssertReturn(pMod->pImgVt, VERR_INTERNAL_ERROR_2);
- return pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModHlpAddSegmentCallback, pMod);
+ AssertReturn(pThis->pImgMod && pThis->pImgMod->pImgVt, VERR_INTERNAL_ERROR_2);
+ Assert(!pThis->cSegs);
+ int rc = pThis->pImgMod->pImgVt->pfnEnumSegments(pThis->pImgMod, rtDbgModDwarfScanSegmentsCallback, pThis);
+ if (RT_SUCCESS(rc))
+ {
+ if (pThis->cSegs == 0)
+ pThis->iWatcomPass = 1;
+ else
+ {
+ pThis->cSegs = 0;
+ pThis->iWatcomPass = -1;
+ rc = pThis->pImgMod->pImgVt->pfnEnumSegments(pThis->pImgMod, rtDbgModDwarfAddSegmentsCallback, pThis);
+ }
+ }
+
+ return rc;
}
+/**
+ * Looks up a segment.
+ *
+ * @returns Pointer to the segment on success, NULL if not found.
+ * @param pThis The DWARF instance.
+ * @param uSeg The segment number / selector.
+ */
+static PRTDBGDWARFSEG rtDbgModDwarfFindSegment(PRTDBGMODDWARF pThis, RTSEL uSeg)
+{
+ uint32_t cSegs = pThis->cSegs;
+ uint32_t iSeg = pThis->iSegHint;
+ PRTDBGDWARFSEG paSegs = pThis->paSegs;
+ if ( iSeg < cSegs
+ && paSegs[iSeg].uSegment == uSeg)
+ return &paSegs[iSeg];
+
+ for (iSeg = 0; iSeg < cSegs; iSeg++)
+ if (uSeg == paSegs[iSeg].uSegment)
+ {
+ pThis->iSegHint = iSeg;
+ return &paSegs[iSeg];
+ }
+
+ AssertFailed();
+ return NULL;
+}
+
+
+/**
+ * Record a segment:offset during pass 1.
+ *
+ * @returns IPRT status code.
+ * @param pThis The DWARF instance.
+ * @param uSeg The segment number / selector.
+ * @param offSeg The segment offset.
+ */
+static int rtDbgModDwarfRecordSegOffset(PRTDBGMODDWARF pThis, RTSEL uSeg, uint64_t offSeg)
+{
+ /* Look up the segment. */
+ uint32_t cSegs = pThis->cSegs;
+ uint32_t iSeg = pThis->iSegHint;
+ PRTDBGDWARFSEG paSegs = pThis->paSegs;
+ if ( iSeg >= cSegs
+ || paSegs[iSeg].uSegment != uSeg)
+ {
+ for (iSeg = 0; iSeg < cSegs; iSeg++)
+ if (uSeg <= paSegs[iSeg].uSegment)
+ break;
+ if ( iSeg >= cSegs
+ || paSegs[iSeg].uSegment != uSeg)
+ {
+ /* Add */
+ void *pvNew = RTMemRealloc(paSegs, (pThis->cSegs + 1) * sizeof(paSegs[0]));
+ if (!pvNew)
+ return VERR_NO_MEMORY;
+ pThis->paSegs = paSegs = (PRTDBGDWARFSEG)pvNew;
+ if (iSeg != cSegs)
+ memmove(&paSegs[iSeg + 1], &paSegs[iSeg], (cSegs - iSeg) * sizeof(paSegs[0]));
+ paSegs[iSeg].offHighest = offSeg;
+ paSegs[iSeg].uBaseAddr = 0;
+ paSegs[iSeg].cbSegment = 0;
+ paSegs[iSeg].uSegment = uSeg;
+ pThis->cSegs++;
+ }
+
+ pThis->iSegHint = iSeg;
+ }
+
+ /* Increase it's range? */
+ if (paSegs[iSeg].offHighest < offSeg)
+ {
+ Log3(("rtDbgModDwarfRecordSegOffset: iSeg=%d uSeg=%#06x offSeg=%#llx\n", iSeg, uSeg, offSeg));
+ paSegs[iSeg].offHighest = offSeg;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Calls pfnSegmentAdd for each segment in the executable image.
+ *
+ * @returns IPRT status code.
+ * @param pThis The DWARF instance.
+ */
+static int rtDbgModDwarfAddSegmentsFromPass1(PRTDBGMODDWARF pThis)
+{
+ AssertReturn(pThis->cSegs, VERR_DWARF_BAD_INFO);
+ uint32_t const cSegs = pThis->cSegs;
+ PRTDBGDWARFSEG paSegs = pThis->paSegs;
+
+ /*
+ * Are the segments assigned more or less in numerical order?
+ */
+ if ( paSegs[0].uSegment < 16U
+ && paSegs[cSegs - 1].uSegment - paSegs[0].uSegment + 1U <= cSegs + 16U)
+ {
+ /** @todo heuristics, plase. */
+ AssertFailedReturn(VERR_DWARF_TODO);
+
+ }
+ /*
+ * Assume DOS segmentation.
+ */
+ else
+ {
+ for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
+ paSegs[iSeg].uBaseAddr = (uint32_t)paSegs[iSeg].uSegment << 16;
+ for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
+ paSegs[iSeg].cbSegment = paSegs[iSeg].offHighest;
+ }
+
+ /*
+ * Add them.
+ */
+ for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
+ {
+ Log3(("rtDbgModDwarfAddSegmentsFromPass1: Seg#%u: %#010llx LB %#llx uSegment=%#x\n",
+ iSeg, paSegs[iSeg].uBaseAddr, paSegs[iSeg].cbSegment, paSegs[iSeg].uSegment));
+ char szName[32];
+ RTStrPrintf(szName, sizeof(szName), "seg-%#04xh", paSegs[iSeg].uSegment);
+ int rc = RTDbgModSegmentAdd(pThis->hCnt, paSegs[iSeg].uBaseAddr, paSegs[iSeg].cbSegment,
+ szName, 0 /*fFlags*/, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
/**
@@ -887,8 +1437,11 @@ static int rtDbgModDwarfLoadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect enm
/*
* Do the job.
*/
- return pThis->pMod->pImgVt->pfnMapPart(pThis->pMod, pThis->aSections[enmSect].offFile, pThis->aSections[enmSect].cb,
- &pThis->aSections[enmSect].pv);
+ return pThis->pDbgInfoMod->pImgVt->pfnMapPart(pThis->pDbgInfoMod,
+ pThis->aSections[enmSect].iDbgInfo,
+ pThis->aSections[enmSect].offFile,
+ pThis->aSections[enmSect].cb,
+ &pThis->aSections[enmSect].pv);
}
@@ -905,7 +1458,7 @@ static int rtDbgModDwarfUnloadSection(PRTDBGMODDWARF pThis, krtDbgModDwarfSect e
if (!pThis->aSections[enmSect].pv)
return VINF_SUCCESS;
- int rc = pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[enmSect].cb, &pThis->aSections[enmSect].pv);
+ int rc = pThis->pDbgInfoMod->pImgVt->pfnUnmapPart(pThis->pDbgInfoMod, pThis->aSections[enmSect].cb, &pThis->aSections[enmSect].pv);
AssertRC(rc);
return rc;
}
@@ -934,14 +1487,28 @@ static int rtDbgModDwarfStringToUtf8(PRTDBGMODDWARF pThis, char **ppsz)
*
* @returns IPRT status code.
* @param pThis The DWARF instance.
+ * @param uSegment The segment, 0 if not applicable.
* @param LinkAddress The address to convert..
* @param piSeg The segment index.
* @param poffSeg Where to return the segment offset.
*/
-static int rtDbgModDwarfLinkAddressToSegOffset(PRTDBGMODDWARF pThis, uint64_t LinkAddress,
+static int rtDbgModDwarfLinkAddressToSegOffset(PRTDBGMODDWARF pThis, RTSEL uSegment, uint64_t LinkAddress,
PRTDBGSEGIDX piSeg, PRTLDRADDR poffSeg)
{
- return pThis->pMod->pImgVt->pfnLinkAddressToSegOffset(pThis->pMod, LinkAddress, piSeg, poffSeg);
+ if (pThis->paSegs)
+ {
+ PRTDBGDWARFSEG pSeg = rtDbgModDwarfFindSegment(pThis, uSegment);
+ if (pSeg)
+ {
+ *piSeg = pSeg - pThis->paSegs;
+ *poffSeg = LinkAddress;
+ return VINF_SUCCESS;
+ }
+ }
+
+ if (pThis->fUseLinkAddress)
+ return pThis->pImgMod->pImgVt->pfnLinkAddressToSegOffset(pThis->pImgMod, LinkAddress, piSeg, poffSeg);
+ return pThis->pImgMod->pImgVt->pfnRvaToSegOffset(pThis->pImgMod, LinkAddress, piSeg, poffSeg);
}
@@ -1348,6 +1915,32 @@ static uint64_t rtDwarfCursor_GetVarSizedU(PRTDWARFCURSOR pCursor, size_t cbValu
}
+#if 0 /* unused */
+/**
+ * Gets the pointer to a variable size block and advances the cursor.
+ *
+ * @returns Pointer to the block at the current cursor location. On error
+ * RTDWARFCURSOR::rc is set and NULL returned.
+ * @param pCursor The cursor.
+ * @param cbBlock The block size.
+ */
+static const uint8_t *rtDwarfCursor_GetBlock(PRTDWARFCURSOR pCursor, uint32_t cbBlock)
+{
+ if (cbBlock > pCursor->cbUnitLeft)
+ {
+ pCursor->rc = VERR_DWARF_UNEXPECTED_END;
+ return NULL;
+ }
+
+ uint8_t const *pb = &pCursor->pb[0];
+ pCursor->pb += cbBlock;
+ pCursor->cbUnitLeft -= cbBlock;
+ pCursor->cbLeft -= cbBlock;
+ return pb;
+}
+#endif
+
+
/**
* Reads an unsigned DWARF half number.
*
@@ -1477,6 +2070,7 @@ static uint32_t rtDwarfCursor_CalcSectOffsetU32(PRTDWARFCURSOR pCursor)
uint32_t offRet = (uint32_t)off;
if (offRet != off)
{
+ AssertFailed();
pCursor->rc = VERR_OUT_OF_RANGE;
offRet = UINT32_MAX;
}
@@ -1644,6 +2238,39 @@ static int rtDwarfCursor_InitWithOffset(PRTDWARFCURSOR pCursor, PRTDBGMODDWARF p
/**
+ * Initialize a cursor for a block (subsection) retrieved from the given cursor.
+ *
+ * The parent cursor will be advanced past the block.
+ *
+ * @returns IPRT status code.
+ * @param pCursor The cursor.
+ * @param pParent The parent cursor. Will be moved by @a cbBlock.
+ * @param cbBlock The size of the block the new cursor should
+ * cover.
+ */
+static int rtDwarfCursor_InitForBlock(PRTDWARFCURSOR pCursor, PRTDWARFCURSOR pParent, uint32_t cbBlock)
+{
+ if (RT_FAILURE(pParent->rc))
+ return pParent->rc;
+ if (pParent->cbUnitLeft < cbBlock)
+ {
+ Log(("rtDwarfCursor_InitForBlock: cbUnitLeft=%#x < cbBlock=%#x \n", pParent->cbUnitLeft, cbBlock));
+ return VERR_DWARF_BAD_POS;
+ }
+
+ *pCursor = *pParent;
+ pCursor->cbLeft = cbBlock;
+ pCursor->cbUnitLeft = cbBlock;
+
+ pParent->pb += cbBlock;
+ pParent->cbLeft -= cbBlock;
+ pParent->cbUnitLeft -= cbBlock;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
* Deletes a section reader initialized by rtDwarfCursor_Init.
*
* @returns @a rcOther or RTDWARCURSOR::rc.
@@ -1730,22 +2357,32 @@ static int rtDwarfLine_DefineFileName(PRTDWARFLINESTATE pLnState, const char *ps
*/
static int rtDwarfLine_AddLine(PRTDWARFLINESTATE pLnState, uint32_t offOpCode)
{
- const char *pszFile = pLnState->Regs.iFile < pLnState->cFileNames
- ? pLnState->papszFileNames[pLnState->Regs.iFile]
- : "<bad file name index>";
- NOREF(offOpCode);
-
- RTDBGSEGIDX iSeg;
- RTUINTPTR offSeg;
- int rc = rtDbgModDwarfLinkAddressToSegOffset(pLnState->pDwarfMod, pLnState->Regs.uAddress, &iSeg, &offSeg);
- if (RT_SUCCESS(rc))
+ PRTDBGMODDWARF pThis = pLnState->pDwarfMod;
+ int rc;
+ if (pThis->iWatcomPass == 1)
+ rc = rtDbgModDwarfRecordSegOffset(pThis, pLnState->Regs.uSegment, pLnState->Regs.uAddress + 1);
+ else
{
- Log2(("rtDwarfLine_AddLine: %x:%08llx (%#llx) %s(%d) [offOpCode=%08x]\n", iSeg, offSeg, pLnState->Regs.uAddress, pszFile, pLnState->Regs.uLine, offOpCode));
- rc = RTDbgModLineAdd(pLnState->pDwarfMod->hCnt, pszFile, pLnState->Regs.uLine, iSeg, offSeg, NULL);
+ const char *pszFile = pLnState->Regs.iFile < pLnState->cFileNames
+ ? pLnState->papszFileNames[pLnState->Regs.iFile]
+ : "<bad file name index>";
+ NOREF(offOpCode);
+
+ RTDBGSEGIDX iSeg;
+ RTUINTPTR offSeg;
+ rc = rtDbgModDwarfLinkAddressToSegOffset(pLnState->pDwarfMod, pLnState->Regs.uSegment, pLnState->Regs.uAddress,
+ &iSeg, &offSeg); /*AssertRC(rc);*/
+ if (RT_SUCCESS(rc))
+ {
+ Log2(("rtDwarfLine_AddLine: %x:%08llx (%#llx) %s(%d) [offOpCode=%08x]\n", iSeg, offSeg, pLnState->Regs.uAddress, pszFile, pLnState->Regs.uLine, offOpCode));
+ rc = RTDbgModLineAdd(pLnState->pDwarfMod->hCnt, pszFile, pLnState->Regs.uLine, iSeg, offSeg, NULL);
- /* Ignore address conflicts for now. */
- if (rc == VERR_DBG_ADDRESS_CONFLICT)
- rc = VINF_SUCCESS;
+ /* Ignore address conflicts for now. */
+ if (rc == VERR_DBG_ADDRESS_CONFLICT)
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VINF_SUCCESS; /* ignore failure */
}
pLnState->Regs.fBasicBlock = false;
@@ -1775,6 +2412,7 @@ static void rtDwarfLine_ResetState(PRTDWARFLINESTATE pLnState)
pLnState->Regs.fEpilogueBegin = false;
pLnState->Regs.uIsa = 0;
pLnState->Regs.uDiscriminator = 0;
+ pLnState->Regs.uSegment = 0;
}
@@ -1811,7 +2449,7 @@ static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCu
int32_t const cLineDelta = bOpCode % pLnState->Hdr.u8LineRange + (int32_t)pLnState->Hdr.s8LineBase;
bOpCode /= pLnState->Hdr.u8LineRange;
- uint64_t uTmp = bOpCode + pLnState->Regs.idxOp + bOpCode;
+ uint64_t uTmp = bOpCode + pLnState->Regs.idxOp;
uint64_t const cAddressDelta = uTmp / pLnState->Hdr.cMaxOpsPerInstr * pLnState->Hdr.cbMinInstr;
uint64_t const cOpIndexDelta = uTmp % pLnState->Hdr.cMaxOpsPerInstr;
@@ -1954,6 +2592,7 @@ static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCu
rc = rtDwarfCursor_AdvanceToPos(pCursor, pbEndOfInstr);
if (RT_SUCCESS(rc))
rc = rtDwarfLine_DefineFileName(pLnState, pszFilename, idxInc);
+ break;
}
/*
@@ -1971,9 +2610,9 @@ static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCu
else
{
uint64_t uSeg = rtDwarfCursor_GetVarSizedU(pCursor, cbInstr - 1, UINT64_MAX);
- Log2(("%08x: DW_LNE_set_segment: %ll#x - Watcom Extension\n", offOpCode, uSeg));
- NOREF(uSeg);
- /** @todo make use of this? */
+ Log2(("%08x: DW_LNE_set_segment: %#llx, cbInstr=%#x - Watcom Extension\n", offOpCode, uSeg, cbInstr));
+ pLnState->Regs.uSegment = (RTSEL)uSeg;
+ AssertStmt(pLnState->Regs.uSegment == uSeg, rc = VERR_DWARF_BAD_INFO);
}
break;
@@ -2205,7 +2844,7 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
bool fFillCache = true;
if (pThis->cCachedAbbrevsAlloced < uCode)
{
- if (uCode > _64K)
+ if (uCode >= _64K)
fFillCache = false;
else
{
@@ -2215,8 +2854,11 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
fFillCache = false;
else
{
- pThis->cCachedAbbrevsAlloced = cNew;
+ Log(("rtDwarfAbbrev_LookupMiss: Growing from %u to %u...\n", pThis->cCachedAbbrevsAlloced, cNew));
pThis->paCachedAbbrevs = (PRTDWARFABBREV)pv;
+ for (uint32_t i = pThis->cCachedAbbrevsAlloced; i < cNew; i++)
+ pThis->paCachedAbbrevs[i].offAbbrev = UINT32_MAX;
+ pThis->cCachedAbbrevsAlloced = cNew;
}
}
}
@@ -2234,52 +2876,61 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
{
/*
* Search for the entry and fill the cache while doing so.
+ * We assume that abbreviation codes for a unit will stop when we see
+ * zero code or when the code value drops.
*/
+ uint32_t uPrevCode = 0;
for (;;)
{
- /* Read the 'header'. */
- uint32_t const uCurCode = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- uint32_t const uCurTag = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- uint8_t const uChildren = rtDwarfCursor_GetU8(&Cursor, 0);
- if (RT_FAILURE(Cursor.rc))
- break;
- if ( uCurTag > 0xffff
- || uChildren > 1)
+ /* Read the 'header'. Skipping zero code bytes. */
+ uint32_t const uCurCode = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ if (pRet && (uCurCode == 0 || uCurCode < uPrevCode))
+ break; /* probably end of unit. */
+ if (uCurCode != 0)
{
- Cursor.rc = VERR_DWARF_BAD_ABBREV;
- break;
- }
-
- /* Cache it? */
- if (uCurCode <= pThis->cCachedAbbrevsAlloced)
- {
- PRTDWARFABBREV pEntry = &pThis->paCachedAbbrevs[uCurCode - 1];
- while (pThis->cCachedAbbrevs < uCurCode)
+ uint32_t const uCurTag = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ uint8_t const uChildren = rtDwarfCursor_GetU8(&Cursor, 0);
+ if (RT_FAILURE(Cursor.rc))
+ break;
+ if ( uCurTag > 0xffff
+ || uChildren > 1)
{
- pThis->paCachedAbbrevs[pThis->cCachedAbbrevs].fFilled = false;
- pThis->cCachedAbbrevs++;
+ Cursor.rc = VERR_DWARF_BAD_ABBREV;
+ break;
}
- pEntry->fFilled = true;
- pEntry->fChildren = RT_BOOL(uChildren);
- pEntry->uTag = uCurTag;
- pEntry->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
-
- if (uCurCode == uCode)
+ /* Cache it? */
+ if (uCurCode <= pThis->cCachedAbbrevsAlloced)
{
- pRet = pEntry;
- if (uCurCode == pThis->cCachedAbbrevsAlloced)
- break;
+ PRTDWARFABBREV pEntry = &pThis->paCachedAbbrevs[uCurCode - 1];
+ if (pEntry->offAbbrev != pThis->offCachedAbbrev)
+ {
+ pEntry->offAbbrev = pThis->offCachedAbbrev;
+ pEntry->fChildren = RT_BOOL(uChildren);
+ pEntry->uTag = uCurTag;
+ pEntry->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
+
+ if (uCurCode == uCode)
+ {
+ Assert(!pRet);
+ pRet = pEntry;
+ if (uCurCode == pThis->cCachedAbbrevsAlloced)
+ break;
+ }
+ }
+ else if (pRet)
+ break; /* Next unit, don't cache more. */
+ /* else: We're growing the cache and re-reading old data. */
}
- }
- /* Skip the specification. */
- uint32_t uAttr, uForm;
- do
- {
- uAttr = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- uForm = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
- } while (uAttr != 0);
+ /* Skip the specification. */
+ uint32_t uAttr, uForm;
+ do
+ {
+ uAttr = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ uForm = rtDwarfCursor_GetULeb128AsU32(&Cursor, 0);
+ } while (uAttr != 0);
+ }
if (RT_FAILURE(Cursor.rc))
break;
@@ -2313,10 +2964,10 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
if (uCurCode == uCode)
{
pRet = &pThis->LookupAbbrev;
- pRet->fFilled = true;
pRet->fChildren = RT_BOOL(uChildren);
pRet->uTag = uCurTag;
pRet->offSpec = rtDwarfCursor_CalcSectOffsetU32(&Cursor);
+ pRet->offAbbrev = pThis->offCachedAbbrev;
break;
}
@@ -2347,8 +2998,8 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
*/
static PCRTDWARFABBREV rtDwarfAbbrev_Lookup(PRTDBGMODDWARF pThis, uint32_t uCode)
{
- if ( uCode - 1 >= pThis->cCachedAbbrevs
- || !pThis->paCachedAbbrevs[uCode - 1].fFilled)
+ if ( uCode - 1 >= pThis->cCachedAbbrevsAlloced
+ || pThis->paCachedAbbrevs[uCode - 1].offAbbrev != pThis->offCachedAbbrev)
return rtDwarfAbbrev_LookupMiss(pThis, uCode);
return &pThis->paCachedAbbrevs[uCode - 1];
}
@@ -2357,19 +3008,12 @@ static PCRTDWARFABBREV rtDwarfAbbrev_Lookup(PRTDBGMODDWARF pThis, uint32_t uCode
/**
* Sets the abbreviation offset of the current unit.
*
- * This will flush the cached abbreviation entries if the offset differs from
- * the previous unit.
- *
* @param pThis The DWARF instance.
* @param offAbbrev The offset into the abbreviation section.
*/
static void rtDwarfAbbrev_SetUnitOffset(PRTDBGMODDWARF pThis, uint32_t offAbbrev)
{
- if (pThis->offCachedAbbrev != offAbbrev)
- {
- pThis->offCachedAbbrev = offAbbrev;
- pThis->cCachedAbbrevs = 0;
- }
+ pThis->offCachedAbbrev = offAbbrev;
}
@@ -2408,7 +3052,7 @@ static PRTDWARFDIECOMPILEUNIT rtDwarfDie_GetCompileUnit(PRTDWARFDIE pDie)
* @param pszErrValue What to return on failure (@a
* pCursor->rc is set).
*/
-static const char *rtDwarfDecode_GetStrp(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, const char *pszErrValue)
+static const char *rtDwarfDecodeHlp_GetStrp(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, const char *pszErrValue)
{
uint64_t offDebugStr = rtDwarfCursor_GetUOff(pCursor, UINT64_MAX);
if (RT_FAILURE(pCursor->rc))
@@ -2453,7 +3097,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Address(PRTDWARFDIE pDie, uint8_t *pbMemb
case DW_FORM_data8: uAddr = rtDwarfCursor_GetU64(pCursor, 0); break;
case DW_FORM_udata: uAddr = rtDwarfCursor_GetULeb128(pCursor, 0); break;
default:
- AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
+ AssertMsgFailedReturn(("%#x (%s)\n", uForm, rtDwarfLog_FormName(uForm)), VERR_DWARF_UNEXPECTED_FORM);
}
if (RT_FAILURE(pCursor->rc))
return pCursor->rc;
@@ -2461,6 +3105,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Address(PRTDWARFDIE pDie, uint8_t *pbMemb
PRTDWARFADDR pAddr = (PRTDWARFADDR)pbMember;
pAddr->uAddress = uAddr;
+ Log4((" %-20s %#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), uAddr, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2479,7 +3124,10 @@ static DECLCALLBACK(int) rtDwarfDecode_Bool(PRTDWARFDIE pDie, uint8_t *pbMember,
{
uint8_t b = rtDwarfCursor_GetU8(pCursor, UINT8_MAX);
if (b > 1)
+ {
+ Log(("Unexpected boolean value %#x\n", b));
return RT_FAILURE(pCursor->rc) ? pCursor->rc : pCursor->rc = VERR_DWARF_BAD_INFO;
+ }
*pfMember = RT_BOOL(b);
break;
}
@@ -2492,6 +3140,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Bool(PRTDWARFDIE pDie, uint8_t *pbMember,
AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
}
+ Log4((" %-20s %RTbool [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), *pfMember, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2538,10 +3187,19 @@ static DECLCALLBACK(int) rtDwarfDecode_LowHighPc(PRTDWARFDIE pDie, uint8_t *pbMe
return pCursor->rc = VERR_DWARF_BAD_INFO;
}
pRange->fHaveHighAddress = true;
- pRange->uHighAddress = uAddr;
+ pRange->fHaveHighIsAddress = uForm == DW_FORM_addr;
+ if (!pRange->fHaveHighIsAddress && pRange->fHaveLowAddress)
+ {
+ pRange->fHaveHighIsAddress = true;
+ pRange->uHighAddress = uAddr + pRange->uLowAddress;
+ }
+ else
+ pRange->uHighAddress = uAddr;
+
}
pRange->cAttrs++;
+ Log4((" %-20s %#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), uAddr, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2551,16 +3209,17 @@ static DECLCALLBACK(int) rtDwarfDecode_Ranges(PRTDWARFDIE pDie, uint8_t *pbMembe
uint32_t uForm, PRTDWARFCURSOR pCursor)
{
AssertReturn(ATTR_GET_SIZE(pDesc) == sizeof(RTDWARFADDRRANGE), VERR_INTERNAL_ERROR_3);
- AssertReturn(pDesc->uAttr == DW_AT_low_pc || pDesc->uAttr == DW_AT_high_pc, VERR_INTERNAL_ERROR_3);
+ AssertReturn(pDesc->uAttr == DW_AT_ranges, VERR_INTERNAL_ERROR_3);
NOREF(pDie);
/* Decode it. */
uint64_t off;
switch (uForm)
{
- case DW_FORM_addr: off = rtDwarfCursor_GetNativeUOff(pCursor, 0); break;
- case DW_FORM_data4: off = rtDwarfCursor_GetU32(pCursor, 0); break;
- case DW_FORM_data8: off = rtDwarfCursor_GetU64(pCursor, 0); break;
+ case DW_FORM_addr: off = rtDwarfCursor_GetNativeUOff(pCursor, 0); break;
+ case DW_FORM_data4: off = rtDwarfCursor_GetU32(pCursor, 0); break;
+ case DW_FORM_data8: off = rtDwarfCursor_GetU64(pCursor, 0); break;
+ case DW_FORM_sec_offset: off = rtDwarfCursor_GetUOff(pCursor, 0); break;
default:
AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
}
@@ -2593,6 +3252,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Ranges(PRTDWARFDIE pDie, uint8_t *pbMembe
pRange->cAttrs++;
pRange->pbRanges = (uint8_t const *)pThis->aSections[krtDbgModDwarfSect_ranges].pv + (size_t)off;
+ Log4((" %-20s TODO [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2605,7 +3265,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Reference(PRTDWARFDIE pDie, uint8_t *pbMe
/* Decode it. */
uint64_t off;
- krtDwarfRef enmWrt = krtDwarfRef_InfoSection;
+ krtDwarfRef enmWrt = krtDwarfRef_SameUnit;
switch (uForm)
{
case DW_FORM_ref1: off = rtDwarfCursor_GetU8(pCursor, 0); break;
@@ -2657,6 +3317,7 @@ static DECLCALLBACK(int) rtDwarfDecode_Reference(PRTDWARFDIE pDie, uint8_t *pbMe
pRef->enmWrt = enmWrt;
pRef->off = off;
+ Log4((" %-20s %d:%#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), enmWrt, off, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2675,7 +3336,7 @@ static DECLCALLBACK(int) rtDwarfDecode_SectOff(PRTDWARFDIE pDie, uint8_t *pbMemb
case DW_FORM_data8: off = rtDwarfCursor_GetU64(pCursor, 0); break;
case DW_FORM_sec_offset: off = rtDwarfCursor_GetUOff(pCursor, 0); break;
default:
- AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
+ AssertMsgFailedReturn(("%#x (%s)\n", uForm, rtDwarfLog_FormName(uForm)), VERR_DWARF_UNEXPECTED_FORM);
}
if (RT_FAILURE(pCursor->rc))
return pCursor->rc;
@@ -2687,18 +3348,24 @@ static DECLCALLBACK(int) rtDwarfDecode_SectOff(PRTDWARFDIE pDie, uint8_t *pbMemb
case DW_AT_stmt_list: enmSect = krtDbgModDwarfSect_line; enmWrt = krtDwarfRef_LineSection; break;
case DW_AT_macro_info: enmSect = krtDbgModDwarfSect_loc; enmWrt = krtDwarfRef_LocSection; break;
case DW_AT_ranges: enmSect = krtDbgModDwarfSect_ranges; enmWrt = krtDwarfRef_RangesSection; break;
- default: AssertMsgFailedReturn(("%u\n", pDesc->uAttr), VERR_INTERNAL_ERROR_4);
+ default:
+ AssertMsgFailedReturn(("%u (%s)\n", pDesc->uAttr, rtDwarfLog_AttrName(pDesc->uAttr)), VERR_INTERNAL_ERROR_4);
}
- if (off >= pCursor->pDwarfMod->aSections[enmSect].cb)
+ size_t cbSect = pCursor->pDwarfMod->aSections[enmSect].cb;
+ if (off >= cbSect)
{
- Log(("rtDwarfDecode_SectOff: bad off=%#llx, attr %#x\n", off, pDesc->uAttr));
- return pCursor->rc = VERR_DWARF_BAD_POS;
+ /* Watcom generates offset past the end of the section, increasing the
+ offset by one for each compile unit. So, just fudge it. */
+ Log(("rtDwarfDecode_SectOff: bad off=%#llx, attr %#x (%s), enmSect=%d cb=%#llx; Assuming watcom/gcc.\n", off,
+ pDesc->uAttr, rtDwarfLog_AttrName(pDesc->uAttr), enmSect, cbSect));
+ off = cbSect;
}
PRTDWARFREF pRef = (PRTDWARFREF)pbMember;
pRef->enmWrt = enmWrt;
pRef->off = off;
+ Log4((" %-20s %d:%#010llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), enmWrt, off, rtDwarfLog_FormName(uForm)));
return VINF_SUCCESS;
}
@@ -2710,20 +3377,23 @@ static DECLCALLBACK(int) rtDwarfDecode_String(PRTDWARFDIE pDie, uint8_t *pbMembe
AssertReturn(ATTR_GET_SIZE(pDesc) == sizeof(const char *), VERR_INTERNAL_ERROR_3);
NOREF(pDie);
+ const char *psz;
switch (uForm)
{
case DW_FORM_string:
- *(const char **)pbMember = rtDwarfCursor_GetSZ(pCursor, NULL);
+ psz = rtDwarfCursor_GetSZ(pCursor, NULL);
break;
case DW_FORM_strp:
- *(const char **)pbMember = rtDwarfDecode_GetStrp(pCursor->pDwarfMod, pCursor, NULL);
+ psz = rtDwarfDecodeHlp_GetStrp(pCursor->pDwarfMod, pCursor, NULL);
break;
default:
AssertMsgFailedReturn(("%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
}
+ *(const char **)pbMember = psz;
+ Log4((" %-20s '%s' [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr), psz, rtDwarfLog_FormName(uForm)));
return pCursor->rc;
}
@@ -2752,25 +3422,37 @@ static DECLCALLBACK(int) rtDwarfDecode_UnsignedInt(PRTDWARFDIE pDie, uint8_t *pb
case 1:
*pbMember = (uint8_t)u64Val;
if (*pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
case 2:
*(uint16_t *)pbMember = (uint16_t)u64Val;
if (*(uint16_t *)pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
case 4:
*(uint32_t *)pbMember = (uint32_t)u64Val;
if (*(uint32_t *)pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
case 8:
*(uint64_t *)pbMember = (uint64_t)u64Val;
if (*(uint64_t *)pbMember != u64Val)
+ {
+ AssertFailed();
return VERR_OUT_OF_RANGE;
+ }
break;
default:
@@ -2780,6 +3462,256 @@ static DECLCALLBACK(int) rtDwarfDecode_UnsignedInt(PRTDWARFDIE pDie, uint8_t *pb
}
+/**
+ * Initialize location interpreter state from cursor & form.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_NOT_FOUND if no location information (i.e. there is source but
+ * it resulted in no byte code).
+ * @param pLoc The location state structure to initialize.
+ * @param pCursor The cursor to read from.
+ * @param uForm The attribute form.
+ */
+static int rtDwarfLoc_Init(PRTDWARFLOCST pLoc, PRTDWARFCURSOR pCursor, uint32_t uForm)
+{
+ uint32_t cbBlock;
+ switch (uForm)
+ {
+ case DW_FORM_block1:
+ cbBlock = rtDwarfCursor_GetU8(pCursor, 0);
+ break;
+
+ case DW_FORM_block2:
+ cbBlock = rtDwarfCursor_GetU16(pCursor, 0);
+ break;
+
+ case DW_FORM_block4:
+ cbBlock = rtDwarfCursor_GetU32(pCursor, 0);
+ break;
+
+ case DW_FORM_block:
+ cbBlock = rtDwarfCursor_GetULeb128(pCursor, 0);
+ break;
+
+ default:
+ AssertMsgFailedReturn(("uForm=%#x\n", uForm), VERR_DWARF_UNEXPECTED_FORM);
+ }
+ if (!cbBlock)
+ return VERR_NOT_FOUND;
+
+ int rc = rtDwarfCursor_InitForBlock(&pLoc->Cursor, pCursor, cbBlock);
+ if (RT_FAILURE(rc))
+ return rc;
+ pLoc->iTop = -1;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Pushes a value onto the stack.
+ *
+ * @returns VINF_SUCCESS or VERR_DWARF_STACK_OVERFLOW.
+ * @param pLoc The state.
+ * @param uValue The value to push.
+ */
+static int rtDwarfLoc_Push(PRTDWARFLOCST pLoc, uint64_t uValue)
+{
+ int iTop = pLoc->iTop + 1;
+ AssertReturn((unsigned)iTop < RT_ELEMENTS(pLoc->auStack), VERR_DWARF_STACK_OVERFLOW);
+ pLoc->auStack[iTop] = uValue;
+ pLoc->iTop = iTop;
+ return VINF_SUCCESS;
+}
+
+
+static int rtDwarfLoc_Evaluate(PRTDWARFLOCST pLoc, void *pvLater, void *pvUser)
+{
+ while (!rtDwarfCursor_IsAtEndOfUnit(&pLoc->Cursor))
+ {
+ /* Read the next opcode.*/
+ uint8_t const bOpcode = rtDwarfCursor_GetU8(&pLoc->Cursor, 0);
+
+ /* Get its operands. */
+ uint64_t uOperand1 = 0;
+ uint64_t uOperand2 = 0;
+ switch (bOpcode)
+ {
+ case DW_OP_addr:
+ uOperand1 = rtDwarfCursor_GetNativeUOff(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_pick:
+ case DW_OP_const1u:
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ uOperand1 = rtDwarfCursor_GetU8(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const1s:
+ uOperand1 = (int8_t)rtDwarfCursor_GetU8(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const2u:
+ uOperand1 = rtDwarfCursor_GetU16(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ case DW_OP_const2s:
+ uOperand1 = (int16_t)rtDwarfCursor_GetU16(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const4u:
+ uOperand1 = rtDwarfCursor_GetU32(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const4s:
+ uOperand1 = (int32_t)rtDwarfCursor_GetU32(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const8u:
+ uOperand1 = rtDwarfCursor_GetU64(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_const8s:
+ uOperand1 = rtDwarfCursor_GetU64(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_regx:
+ case DW_OP_piece:
+ case DW_OP_plus_uconst:
+ case DW_OP_constu:
+ uOperand1 = rtDwarfCursor_GetULeb128(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_consts:
+ case DW_OP_fbreg:
+ case DW_OP_breg0+0: case DW_OP_breg0+1: case DW_OP_breg0+2: case DW_OP_breg0+3:
+ case DW_OP_breg0+4: case DW_OP_breg0+5: case DW_OP_breg0+6: case DW_OP_breg0+7:
+ case DW_OP_breg0+8: case DW_OP_breg0+9: case DW_OP_breg0+10: case DW_OP_breg0+11:
+ case DW_OP_breg0+12: case DW_OP_breg0+13: case DW_OP_breg0+14: case DW_OP_breg0+15:
+ case DW_OP_breg0+16: case DW_OP_breg0+17: case DW_OP_breg0+18: case DW_OP_breg0+19:
+ case DW_OP_breg0+20: case DW_OP_breg0+21: case DW_OP_breg0+22: case DW_OP_breg0+23:
+ case DW_OP_breg0+24: case DW_OP_breg0+25: case DW_OP_breg0+26: case DW_OP_breg0+27:
+ case DW_OP_breg0+28: case DW_OP_breg0+29: case DW_OP_breg0+30: case DW_OP_breg0+31:
+ uOperand1 = rtDwarfCursor_GetSLeb128(&pLoc->Cursor, 0);
+ break;
+ case DW_OP_bregx:
+ uOperand1 = rtDwarfCursor_GetULeb128(&pLoc->Cursor, 0);
+ uOperand2 = rtDwarfCursor_GetSLeb128(&pLoc->Cursor, 0);
+ break;
+ }
+ if (RT_FAILURE(pLoc->Cursor.rc))
+ break;
+
+ /* Interpret the opcode. */
+ int rc;
+ switch (bOpcode)
+ {
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ case DW_OP_constu:
+ case DW_OP_consts:
+ case DW_OP_addr:
+ rc = rtDwarfLoc_Push(pLoc, uOperand1);
+ break;
+ case DW_OP_lit0 + 0: case DW_OP_lit0 + 1: case DW_OP_lit0 + 2: case DW_OP_lit0 + 3:
+ case DW_OP_lit0 + 4: case DW_OP_lit0 + 5: case DW_OP_lit0 + 6: case DW_OP_lit0 + 7:
+ case DW_OP_lit0 + 8: case DW_OP_lit0 + 9: case DW_OP_lit0 + 10: case DW_OP_lit0 + 11:
+ case DW_OP_lit0 + 12: case DW_OP_lit0 + 13: case DW_OP_lit0 + 14: case DW_OP_lit0 + 15:
+ case DW_OP_lit0 + 16: case DW_OP_lit0 + 17: case DW_OP_lit0 + 18: case DW_OP_lit0 + 19:
+ case DW_OP_lit0 + 20: case DW_OP_lit0 + 21: case DW_OP_lit0 + 22: case DW_OP_lit0 + 23:
+ case DW_OP_lit0 + 24: case DW_OP_lit0 + 25: case DW_OP_lit0 + 26: case DW_OP_lit0 + 27:
+ case DW_OP_lit0 + 28: case DW_OP_lit0 + 29: case DW_OP_lit0 + 30: case DW_OP_lit0 + 31:
+ rc = rtDwarfLoc_Push(pLoc, bOpcode - DW_OP_lit0);
+ break;
+ case DW_OP_nop:
+ break;
+ case DW_OP_dup: /** @todo 0 operands. */
+ case DW_OP_drop: /** @todo 0 operands. */
+ case DW_OP_over: /** @todo 0 operands. */
+ case DW_OP_pick: /** @todo 1 operands, a 1-byte stack index. */
+ case DW_OP_swap: /** @todo 0 operands. */
+ case DW_OP_rot: /** @todo 0 operands. */
+ case DW_OP_abs: /** @todo 0 operands. */
+ case DW_OP_and: /** @todo 0 operands. */
+ case DW_OP_div: /** @todo 0 operands. */
+ case DW_OP_minus: /** @todo 0 operands. */
+ case DW_OP_mod: /** @todo 0 operands. */
+ case DW_OP_mul: /** @todo 0 operands. */
+ case DW_OP_neg: /** @todo 0 operands. */
+ case DW_OP_not: /** @todo 0 operands. */
+ case DW_OP_or: /** @todo 0 operands. */
+ case DW_OP_plus: /** @todo 0 operands. */
+ case DW_OP_plus_uconst: /** @todo 1 operands, a ULEB128 addend. */
+ case DW_OP_shl: /** @todo 0 operands. */
+ case DW_OP_shr: /** @todo 0 operands. */
+ case DW_OP_shra: /** @todo 0 operands. */
+ case DW_OP_xor: /** @todo 0 operands. */
+ case DW_OP_skip: /** @todo 1 signed 2-byte constant. */
+ case DW_OP_bra: /** @todo 1 signed 2-byte constant. */
+ case DW_OP_eq: /** @todo 0 operands. */
+ case DW_OP_ge: /** @todo 0 operands. */
+ case DW_OP_gt: /** @todo 0 operands. */
+ case DW_OP_le: /** @todo 0 operands. */
+ case DW_OP_lt: /** @todo 0 operands. */
+ case DW_OP_ne: /** @todo 0 operands. */
+ case DW_OP_reg0 + 0: case DW_OP_reg0 + 1: case DW_OP_reg0 + 2: case DW_OP_reg0 + 3: /** @todo 0 operands - reg 0..31. */
+ case DW_OP_reg0 + 4: case DW_OP_reg0 + 5: case DW_OP_reg0 + 6: case DW_OP_reg0 + 7:
+ case DW_OP_reg0 + 8: case DW_OP_reg0 + 9: case DW_OP_reg0 + 10: case DW_OP_reg0 + 11:
+ case DW_OP_reg0 + 12: case DW_OP_reg0 + 13: case DW_OP_reg0 + 14: case DW_OP_reg0 + 15:
+ case DW_OP_reg0 + 16: case DW_OP_reg0 + 17: case DW_OP_reg0 + 18: case DW_OP_reg0 + 19:
+ case DW_OP_reg0 + 20: case DW_OP_reg0 + 21: case DW_OP_reg0 + 22: case DW_OP_reg0 + 23:
+ case DW_OP_reg0 + 24: case DW_OP_reg0 + 25: case DW_OP_reg0 + 26: case DW_OP_reg0 + 27:
+ case DW_OP_reg0 + 28: case DW_OP_reg0 + 29: case DW_OP_reg0 + 30: case DW_OP_reg0 + 31:
+ case DW_OP_breg0+ 0: case DW_OP_breg0+ 1: case DW_OP_breg0+ 2: case DW_OP_breg0+ 3: /** @todo 1 operand, a SLEB128 offset. */
+ case DW_OP_breg0+ 4: case DW_OP_breg0+ 5: case DW_OP_breg0+ 6: case DW_OP_breg0+ 7:
+ case DW_OP_breg0+ 8: case DW_OP_breg0+ 9: case DW_OP_breg0+ 10: case DW_OP_breg0+ 11:
+ case DW_OP_breg0+ 12: case DW_OP_breg0+ 13: case DW_OP_breg0+ 14: case DW_OP_breg0+ 15:
+ case DW_OP_breg0+ 16: case DW_OP_breg0+ 17: case DW_OP_breg0+ 18: case DW_OP_breg0+ 19:
+ case DW_OP_breg0+ 20: case DW_OP_breg0+ 21: case DW_OP_breg0+ 22: case DW_OP_breg0+ 23:
+ case DW_OP_breg0+ 24: case DW_OP_breg0+ 25: case DW_OP_breg0+ 26: case DW_OP_breg0+ 27:
+ case DW_OP_breg0+ 28: case DW_OP_breg0+ 29: case DW_OP_breg0+ 30: case DW_OP_breg0+ 31:
+ case DW_OP_piece: /** @todo 1 operand, a ULEB128 size of piece addressed. */
+ case DW_OP_regx: /** @todo 1 operand, a ULEB128 register. */
+ case DW_OP_fbreg: /** @todo 1 operand, a SLEB128 offset. */
+ case DW_OP_bregx: /** @todo 2 operands, a ULEB128 register followed by a SLEB128 offset. */
+ case DW_OP_deref: /** @todo 0 operands. */
+ case DW_OP_deref_size: /** @todo 1 operand, a 1-byte size of data retrieved. */
+ case DW_OP_xderef: /** @todo 0 operands. */
+ case DW_OP_xderef_size: /** @todo 1 operand, a 1-byte size of data retrieved. */
+ AssertMsgFailedReturn(("bOpcode=%#x\n", bOpcode), VERR_DWARF_TODO);
+ default:
+ AssertMsgFailedReturn(("bOpcode=%#x\n", bOpcode), VERR_DWARF_UNKNOWN_LOC_OPCODE);
+ }
+ }
+
+ return pLoc->Cursor.rc;
+}
+
+
+/** @callback_method_impl{FNRTDWARFATTRDECODER} */
+static DECLCALLBACK(int) rtDwarfDecode_SegmentLoc(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
+ uint32_t uForm, PRTDWARFCURSOR pCursor)
+{
+ NOREF(pDie);
+ AssertReturn(ATTR_GET_SIZE(pDesc) == 2, VERR_DWARF_IPE);
+
+ RTDWARFLOCST LocSt;
+ int rc = rtDwarfLoc_Init(&LocSt, pCursor, uForm);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtDwarfLoc_Evaluate(&LocSt, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ if (LocSt.iTop >= 0)
+ {
+ *(uint16_t *)pbMember = LocSt.auStack[LocSt.iTop];
+ Log4((" %-20s %#06llx [%s]\n", rtDwarfLog_AttrName(pDesc->uAttr),
+ LocSt.auStack[LocSt.iTop], rtDwarfLog_FormName(uForm)));
+ return VINF_SUCCESS;
+ }
+ rc = VERR_DWARF_STACK_UNDERFLOW;
+ }
+ }
+ return rc;
+}
/*
*
@@ -2791,6 +3723,87 @@ static DECLCALLBACK(int) rtDwarfDecode_UnsignedInt(PRTDWARFDIE pDie, uint8_t *pb
/**
+ * Special hack to get the name and/or linkage name for a subprogram via a
+ * specification reference.
+ *
+ * Since this is a hack, we ignore failure.
+ *
+ * If we want to really make use of DWARF info, we'll have to create some kind
+ * of lookup tree for handling this. But currently we don't, so a hack will
+ * suffice.
+ *
+ * @param pThis The DWARF instance.
+ * @param pSubProgram The subprogram which is short on names.
+ */
+static void rtDwarfInfo_TryGetSubProgramNameFromSpecRef(PRTDBGMODDWARF pThis, PRTDWARFDIESUBPROGRAM pSubProgram)
+{
+ /*
+ * Must have a spec ref, and it must be in the info section.
+ */
+ if (pSubProgram->SpecRef.enmWrt != krtDwarfRef_InfoSection)
+ return;
+
+ /*
+ * Create a cursor for reading the info and then the abbrivation code
+ * starting the off the DIE.
+ */
+ RTDWARFCURSOR InfoCursor;
+ int rc = rtDwarfCursor_InitWithOffset(&InfoCursor, pThis, krtDbgModDwarfSect_info, pSubProgram->SpecRef.off);
+ if (RT_FAILURE(rc))
+ return;
+
+ uint32_t uAbbrCode = rtDwarfCursor_GetULeb128AsU32(&InfoCursor, UINT32_MAX);
+ if (uAbbrCode)
+ {
+ /* Only references to subprogram tags are interesting here. */
+ PCRTDWARFABBREV pAbbrev = rtDwarfAbbrev_Lookup(pThis, uAbbrCode);
+ if ( pAbbrev
+ && pAbbrev->uTag == DW_TAG_subprogram)
+ {
+ /*
+ * Use rtDwarfInfo_ParseDie to do the parsing, but with a different
+ * attribute spec than usual.
+ */
+ rtDwarfInfo_ParseDie(pThis, &pSubProgram->Core, &g_SubProgramSpecHackDesc, &InfoCursor,
+ pAbbrev, false /*fInitDie*/);
+ }
+ }
+
+ rtDwarfCursor_Delete(&InfoCursor, VINF_SUCCESS);
+}
+
+
+/**
+ * Select which name to use.
+ *
+ * @returns One of the names.
+ * @param pszName The DWARF name, may exclude namespace and class.
+ * Can also be NULL.
+ * @param pszLinkageName The linkage name. Can be NULL.
+ */
+static const char *rtDwarfInfo_SelectName(const char *pszName, const char *pszLinkageName)
+{
+ if (!pszName || !pszLinkageName)
+ return pszName ? pszName : pszLinkageName;
+
+ /*
+ * Some heuristics for selecting the link name if the normal name is missing
+ * namespace or class prefixes.
+ */
+ size_t cchName = strlen(pszName);
+ size_t cchLinkageName = strlen(pszLinkageName);
+ if (cchLinkageName <= cchName + 1)
+ return pszName;
+
+ const char *psz = strstr(pszLinkageName, pszName);
+ if (!psz || psz - pszLinkageName < 4)
+ return pszName;
+
+ return pszLinkageName;
+}
+
+
+/**
* Parse the attributes of a DIE.
*
* @returns IPRT status code.
@@ -2804,7 +3817,13 @@ static int rtDwarfInfo_SnoopSymbols(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
{
case DW_TAG_subprogram:
{
- PCRTDWARFDIESUBPROGRAM pSubProgram = (PCRTDWARFDIESUBPROGRAM)pDie;
+ PRTDWARFDIESUBPROGRAM pSubProgram = (PRTDWARFDIESUBPROGRAM)pDie;
+
+ /* Obtain referenced specification there is only partial info. */
+ if ( pSubProgram->PcRange.cAttrs
+ && !pSubProgram->pszName)
+ rtDwarfInfo_TryGetSubProgramNameFromSpecRef(pThis, pSubProgram);
+
if (pSubProgram->PcRange.cAttrs)
{
if (pSubProgram->PcRange.fHaveRanges)
@@ -2814,19 +3833,50 @@ static int rtDwarfInfo_SnoopSymbols(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
Log5(("subprogram %s (%s) %#llx-%#llx%s\n", pSubProgram->pszName, pSubProgram->pszLinkageName,
pSubProgram->PcRange.uLowAddress, pSubProgram->PcRange.uHighAddress,
pSubProgram->PcRange.cAttrs == 2 ? "" : " !bad!"));
- if ( pSubProgram->pszName
+ if ( ( pSubProgram->pszName || pSubProgram->pszLinkageName)
&& pSubProgram->PcRange.cAttrs == 2)
{
- RTDBGSEGIDX iSeg;
- RTUINTPTR offSeg;
- rc = rtDbgModDwarfLinkAddressToSegOffset(pThis, pSubProgram->PcRange.uLowAddress,
- &iSeg, &offSeg);
- if (RT_SUCCESS(rc))
- rc = RTDbgModSymbolAdd(pThis->hCnt, pSubProgram->pszName, iSeg, offSeg,
- pSubProgram->PcRange.uHighAddress - pSubProgram->PcRange.uLowAddress,
- 0 /*fFlags*/, NULL /*piOrdinal*/);
+ if (pThis->iWatcomPass == 1)
+ rc = rtDbgModDwarfRecordSegOffset(pThis, pSubProgram->uSegment, pSubProgram->PcRange.uHighAddress);
else
- Log5(("rtDbgModDwarfLinkAddressToSegOffset failed: %Rrc\n", rc));
+ {
+ RTDBGSEGIDX iSeg;
+ RTUINTPTR offSeg;
+ rc = rtDbgModDwarfLinkAddressToSegOffset(pThis, pSubProgram->uSegment,
+ pSubProgram->PcRange.uLowAddress,
+ &iSeg, &offSeg);
+ if (RT_SUCCESS(rc))
+ {
+ uint64_t cb;
+ if (pSubProgram->PcRange.uHighAddress >= pSubProgram->PcRange.uLowAddress)
+ cb = pSubProgram->PcRange.uHighAddress - pSubProgram->PcRange.uLowAddress;
+ else
+ cb = 1;
+ rc = RTDbgModSymbolAdd(pThis->hCnt,
+ rtDwarfInfo_SelectName(pSubProgram->pszName, pSubProgram->pszLinkageName),
+ iSeg, offSeg, cb, 0 /*fFlags*/, NULL /*piOrdinal*/);
+ if (RT_FAILURE(rc))
+ {
+ if ( rc == VERR_DBG_DUPLICATE_SYMBOL
+ || rc == VERR_DBG_ADDRESS_CONFLICT /** @todo figure why this happens with 10.6.8 mach_kernel, 32-bit. */
+ )
+ rc = VINF_SUCCESS;
+ else
+ AssertMsgFailed(("%Rrc\n", rc));
+ }
+ }
+ else if ( pSubProgram->PcRange.uLowAddress == 0 /* see with vmlinux */
+ && pSubProgram->PcRange.uHighAddress == 0)
+ {
+ Log5(("rtDbgModDwarfLinkAddressToSegOffset: Ignoring empty range.\n"));
+ rc = VINF_SUCCESS; /* ignore */
+ }
+ else
+ {
+ AssertRC(rc);
+ Log5(("rtDbgModDwarfLinkAddressToSegOffset failed: %Rrc\n", rc));
+ }
+ }
}
}
}
@@ -2835,6 +3885,35 @@ static int rtDwarfInfo_SnoopSymbols(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
break;
}
+ case DW_TAG_label:
+ {
+ PCRTDWARFDIELABEL pLabel = (PCRTDWARFDIELABEL)pDie;
+ if (pLabel->fExternal)
+ {
+ Log5(("label %s %#x:%#llx\n", pLabel->pszName, pLabel->uSegment, pLabel->Address.uAddress));
+ if (pThis->iWatcomPass == 1)
+ rc = rtDbgModDwarfRecordSegOffset(pThis, pLabel->uSegment, pLabel->Address.uAddress);
+ else
+ {
+ RTDBGSEGIDX iSeg;
+ RTUINTPTR offSeg;
+ rc = rtDbgModDwarfLinkAddressToSegOffset(pThis, pLabel->uSegment, pLabel->Address.uAddress,
+ &iSeg, &offSeg);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTDbgModSymbolAdd(pThis->hCnt, pLabel->pszName, iSeg, offSeg, 0 /*cb*/,
+ 0 /*fFlags*/, NULL /*piOrdinal*/);
+ AssertRC(rc);
+ }
+ else
+ Log5(("rtDbgModDwarfLinkAddressToSegOffset failed: %Rrc\n", rc));
+ }
+
+ }
+ break;
+ }
+
}
return rc;
}
@@ -2901,9 +3980,19 @@ static PRTDWARFDIE rtDwarfInfo_NewDie(PRTDBGMODDWARF pThis, PCRTDWARFDIEDESC pDi
{
NOREF(pThis);
Assert(pDieDesc->cbDie >= sizeof(RTDWARFDIE));
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ uint32_t iAllocator = pDieDesc->cbDie > pThis->aDieAllocators[0].cbMax;
+ Assert(pDieDesc->cbDie <= pThis->aDieAllocators[iAllocator].cbMax);
+ PRTDWARFDIE pDie = (PRTDWARFDIE)RTMemCacheAlloc(pThis->aDieAllocators[iAllocator].hMemCache);
+#else
PRTDWARFDIE pDie = (PRTDWARFDIE)RTMemAllocZ(pDieDesc->cbDie);
+#endif
if (pDie)
{
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ RT_BZERO(pDie, pDieDesc->cbDie);
+ pDie->iAllocator = iAllocator;
+#endif
rtDwarfInfo_InitDie(pDie, pDieDesc);
pDie->uTag = pAbbrev->uTag;
@@ -2921,6 +4010,47 @@ static PRTDWARFDIE rtDwarfInfo_NewDie(PRTDBGMODDWARF pThis, PCRTDWARFDIEDESC pDi
/**
+ * Free all children of a DIE.
+ *
+ * @param pThis The DWARF instance.
+ * @param pParent The parent DIE.
+ */
+static void rtDwarfInfo_FreeChildren(PRTDBGMODDWARF pThis, PRTDWARFDIE pParentDie)
+{
+ PRTDWARFDIE pChild, pNextChild;
+ RTListForEachSafe(&pParentDie->ChildList, pChild, pNextChild, RTDWARFDIE, SiblingNode)
+ {
+ if (!RTListIsEmpty(&pChild->ChildList))
+ rtDwarfInfo_FreeChildren(pThis, pChild);
+ RTListNodeRemove(&pChild->SiblingNode);
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ RTMemCacheFree(pThis->aDieAllocators[pChild->iAllocator].hMemCache, pChild);
+#else
+ RTMemFree(pChild);
+#endif
+ }
+}
+
+
+/**
+ * Free a DIE an all its children.
+ *
+ * @param pThis The DWARF instance.
+ * @param pDie The DIE to free.
+ */
+static void rtDwarfInfo_FreeDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie)
+{
+ rtDwarfInfo_FreeChildren(pThis, pDie);
+ RTListNodeRemove(&pDie->SiblingNode);
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ RTMemCacheFree(pThis->aDieAllocators[pDie->iAllocator].hMemCache, pDie);
+#else
+ RTMemFree(pChild);
+#endif
+}
+
+
+/**
* Skips a form.
* @returns IPRT status code
* @param pCursor The cursor.
@@ -3026,16 +4156,21 @@ static int rtDwarfInfo_SkipDie(PRTDWARFCURSOR pCursor, PRTDWARFCURSOR pAbbrevCur
* @param pDieDesc The DIE descriptor.
* @param pCursor The debug_info cursor.
* @param pAbbrev The abbreviation cache entry.
+ * @param fInitDie Whether to initialize the DIE first. If not (@c
+ * false) it's safe to assume we're following a
+ * DW_AT_specification or DW_AT_abstract_origin,
+ * and that we shouldn't be snooping any symbols.
*/
static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWARFDIEDESC pDieDesc,
- PRTDWARFCURSOR pCursor, PCRTDWARFABBREV pAbbrev)
+ PRTDWARFCURSOR pCursor, PCRTDWARFABBREV pAbbrev, bool fInitDie)
{
RTDWARFCURSOR AbbrevCursor;
int rc = rtDwarfCursor_InitWithOffset(&AbbrevCursor, pThis, krtDbgModDwarfSect_abbrev, pAbbrev->offSpec);
if (RT_FAILURE(rc))
return rc;
- rtDwarfInfo_InitDie(pDie, pDieDesc);
+ if (fInitDie)
+ rtDwarfInfo_InitDie(pDie, pDieDesc);
for (;;)
{
uint32_t uAttr = rtDwarfCursor_GetULeb128AsU32(&AbbrevCursor, 0);
@@ -3063,6 +4198,7 @@ static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWAR
{
pDie->cUnhandledAttrs++;
rc = rtDwarfInfo_SkipForm(pCursor, uForm);
+ Log4((" %-20s [%s]\n", rtDwarfLog_AttrName(uAttr), rtDwarfLog_FormName(uForm)));
}
if (RT_FAILURE(rc))
break;
@@ -3073,9 +4209,9 @@ static int rtDwarfInfo_ParseDie(PRTDBGMODDWARF pThis, PRTDWARFDIE pDie, PCRTDWAR
rc = pCursor->rc;
/*
- * Snoope up symbols on the way out.
+ * Snoop up symbols on the way out.
*/
- if (RT_SUCCESS(rc))
+ if (RT_SUCCESS(rc) && fInitDie)
{
rc = rtDwarfInfo_SnoopSymbols(pThis, pDie);
/* Ignore duplicates, get work done instead. */
@@ -3121,7 +4257,10 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
* Set up the abbreviation cache and store the native address size in the cursor.
*/
if (offAbbrev > UINT32_MAX)
+ {
+ Log(("Unexpected abbrviation code offset of %#llx\n", offAbbrev));
return VERR_DWARF_BAD_INFO;
+ }
rtDwarfAbbrev_SetUnitOffset(pThis, (uint32_t)offAbbrev);
pCursor->cbNativeAddr = cbNativeAddr;
@@ -3130,7 +4269,10 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
*/
uint32_t uAbbrCode = rtDwarfCursor_GetULeb128AsU32(pCursor, UINT32_MAX);
if (!uAbbrCode)
+ {
+ Log(("Unexpected abbrviation code of zero\n"));
return VERR_DWARF_BAD_INFO;
+ }
PCRTDWARFABBREV pAbbrev = rtDwarfAbbrev_Lookup(pThis, uAbbrCode);
if (!pAbbrev)
return VERR_DWARF_ABBREV_NOT_FOUND;
@@ -3152,7 +4294,7 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
pUnit->uDwarfVer = (uint8_t)uVer;
RTListAppend(&pThis->CompileUnitList, &pUnit->Core.SiblingNode);
- int rc = rtDwarfInfo_ParseDie(pThis, &pUnit->Core, &g_CompileUnitDesc, pCursor, pAbbrev);
+ int rc = rtDwarfInfo_ParseDie(pThis, &pUnit->Core, &g_CompileUnitDesc, pCursor, pAbbrev, true /*fInitDie*/);
if (RT_FAILURE(rc))
return rc;
@@ -3163,28 +4305,19 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
PRTDWARFDIE pParentDie = &pUnit->Core;
while (!rtDwarfCursor_IsAtEndOfUnit(pCursor))
{
+#ifdef LOG_ENABLED
+ uint32_t offLog = rtDwarfCursor_CalcSectOffsetU32(pCursor);
+#endif
uAbbrCode = rtDwarfCursor_GetULeb128AsU32(pCursor, UINT32_MAX);
if (!uAbbrCode)
{
- /* End of siblings, up one level. */
- pParentDie = pParentDie->pParent;
- if (!pParentDie)
- {
- if (!rtDwarfCursor_IsAtEndOfUnit(pCursor))
- return VERR_DWARF_BAD_INFO;
- break;
- }
- cDepth--;
-
- /* Unlink and free child DIEs if told to do so. */
- if (!fKeepDies && pParentDie->pParent)
+ /* End of siblings, up one level. (Is this correct?) */
+ if (pParentDie->pParent)
{
- PRTDWARFDIE pChild, pNextChild;
- RTListForEachSafe(&pParentDie->ChildList, pChild, pNextChild, RTDWARFDIE, SiblingNode)
- {
- RTListNodeRemove(&pChild->SiblingNode);
- RTMemFree(pChild);
- }
+ pParentDie = pParentDie->pParent;
+ cDepth--;
+ if (!fKeepDies && pParentDie->pParent)
+ rtDwarfInfo_FreeChildren(pThis, pParentDie);
}
}
else
@@ -3207,10 +4340,10 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
else
{
pszName = "<unknown>";
- pDieDesc = g_aTagDescs[0].pDesc;
+ pDieDesc = &g_CoreDieDesc;
}
- Log4((" %*stag=%s (%#x)%s\n", cDepth * 2, "", pszName,
- pAbbrev->uTag, pAbbrev->fChildren ? " has children" : ""));
+ Log4(("%08x: %*stag=%s (%#x, abbrev %u)%s\n", offLog, cDepth * 2, "", pszName,
+ pAbbrev->uTag, uAbbrCode, pAbbrev->fChildren ? " has children" : ""));
/*
* Create a new internal DIE structure and parse the
@@ -3226,12 +4359,20 @@ static int rtDwarfInfo_LoadUnit(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, bo
cDepth++;
}
- rc = rtDwarfInfo_ParseDie(pThis, pNewDie, pDieDesc, pCursor, pAbbrev);
+ rc = rtDwarfInfo_ParseDie(pThis, pNewDie, pDieDesc, pCursor, pAbbrev, true /*fInitDie*/);
if (RT_FAILURE(rc))
return rc;
+
+ if (!fKeepDies && !pAbbrev->fChildren)
+ rtDwarfInfo_FreeDie(pThis, pNewDie);
}
} /* while more DIEs */
+
+ /* Unlink and free child DIEs if told to do so. */
+ if (!fKeepDies)
+ rtDwarfInfo_FreeChildren(pThis, &pUnit->Core);
+
return RT_SUCCESS(rc) ? pCursor->rc : rc;
}
@@ -3248,14 +4389,15 @@ static int rtDwarfInfo_LoadAll(PRTDBGMODDWARF pThis)
{
RTDWARFCURSOR Cursor;
int rc = rtDwarfCursor_Init(&Cursor, pThis, krtDbgModDwarfSect_info);
- if (RT_FAILURE(rc))
- return rc;
-
- while ( !rtDwarfCursor_IsAtEnd(&Cursor)
- && RT_SUCCESS(rc))
- rc = rtDwarfInfo_LoadUnit(pThis, &Cursor, false /* fKeepDies */);
+ if (RT_SUCCESS(rc))
+ {
+ while ( !rtDwarfCursor_IsAtEnd(&Cursor)
+ && RT_SUCCESS(rc))
+ rc = rtDwarfInfo_LoadUnit(pThis, &Cursor, false /* fKeepDies */);
- return rtDwarfCursor_Delete(&Cursor, rc);
+ rc = rtDwarfCursor_Delete(&Cursor, rc);
+ }
+ return rc;
}
@@ -3382,7 +4524,7 @@ static DECLCALLBACK(RTUINTPTR) rtDbgModDwarf_ImageSize(PRTDBGMODINT pMod)
{
PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pMod->pvDbgPriv;
RTUINTPTR cb1 = RTDbgModImageSize(pThis->hCnt);
- RTUINTPTR cb2 = pMod->pImgVt->pfnImageSize(pMod);
+ RTUINTPTR cb2 = pThis->pImgMod->pImgVt->pfnImageSize(pMod);
return RT_MAX(cb1, cb2);
}
@@ -3402,10 +4544,28 @@ static DECLCALLBACK(int) rtDbgModDwarf_Close(PRTDBGMODINT pMod)
for (unsigned iSect = 0; iSect < RT_ELEMENTS(pThis->aSections); iSect++)
if (pThis->aSections[iSect].pv)
- pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb, &pThis->aSections[iSect].pv);
+ pThis->pDbgInfoMod->pImgVt->pfnUnmapPart(pThis->pDbgInfoMod, pThis->aSections[iSect].cb, &pThis->aSections[iSect].pv);
RTDbgModRelease(pThis->hCnt);
RTMemFree(pThis->paCachedAbbrevs);
+ if (pThis->pNestedMod)
+ {
+ pThis->pNestedMod->pImgVt->pfnClose(pThis->pNestedMod);
+ RTStrCacheRelease(g_hDbgModStrCache, pThis->pNestedMod->pszName);
+ RTStrCacheRelease(g_hDbgModStrCache, pThis->pNestedMod->pszDbgFile);
+ RTMemFree(pThis->pNestedMod);
+ pThis->pNestedMod = NULL;
+ }
+
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ uint32_t i = RT_ELEMENTS(pThis->aDieAllocators);
+ while (i-- > 0)
+ {
+ RTMemCacheDestroy(pThis->aDieAllocators[i].hMemCache);
+ pThis->aDieAllocators[i].hMemCache = NIL_RTMEMCACHE;
+ }
+#endif
+
RTMemFree(pThis);
return VINF_SUCCESS;
@@ -3413,38 +4573,42 @@ static DECLCALLBACK(int) rtDbgModDwarf_Close(PRTDBGMODINT pMod)
/** @callback_method_impl{FNRTLDRENUMDBG} */
-static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iDbgInfo, RTLDRDBGINFOTYPE enmType,
- uint16_t iMajorVer, uint16_t iMinorVer, const char *pszPartNm,
- RTFOFF offFile, RTLDRADDR LinkAddress, RTLDRADDR cb,
- const char *pszExtFile, void *pvUser)
+static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
{
- NOREF(hLdrMod); NOREF(iDbgInfo); NOREF(iMajorVer); NOREF(iMinorVer); NOREF(LinkAddress);
-
/*
* Skip stuff we can't handle.
*/
- if ( enmType != RTLDRDBGINFOTYPE_DWARF
- || !pszPartNm
- || pszExtFile)
+ if (pDbgInfo->enmType != RTLDRDBGINFOTYPE_DWARF)
return VINF_SUCCESS;
+ const char *pszSection = pDbgInfo->u.Dwarf.pszSection;
+ if (!pszSection || !*pszSection)
+ return VINF_SUCCESS;
+ Assert(!pDbgInfo->pszExtFile);
/*
* Must have a part name starting with debug_ and possibly prefixed by dots
* or underscores.
*/
- if (!strncmp(pszPartNm, ".debug_", sizeof(".debug_") - 1)) /* ELF */
- pszPartNm += sizeof(".debug_") - 1;
- else if (!strncmp(pszPartNm, "__debug_", sizeof("__debug_") - 1)) /* Mach-O */
- pszPartNm += sizeof("__debug_") - 1;
+ if (!strncmp(pszSection, RT_STR_TUPLE(".debug_"))) /* ELF */
+ pszSection += sizeof(".debug_") - 1;
+ else if (!strncmp(pszSection, RT_STR_TUPLE("__debug_"))) /* Mach-O */
+ pszSection += sizeof("__debug_") - 1;
+ else if (!strcmp(pszSection, ".WATCOM_references"))
+ return VINF_SUCCESS; /* Ignore special watcom section for now.*/
+ else if ( !strcmp(pszSection, "__apple_types")
+ || !strcmp(pszSection, "__apple_namespac")
+ || !strcmp(pszSection, "__apple_objc")
+ || !strcmp(pszSection, "__apple_names"))
+ return VINF_SUCCESS; /* Ignore special apple sections for now. */
else
- AssertMsgFailedReturn(("%s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
+ AssertMsgFailedReturn(("%s\n", pszSection), VINF_SUCCESS /*ignore*/);
/*
* Figure out which part we're talking about.
*/
krtDbgModDwarfSect enmSect;
if (0) { /* dummy */ }
-#define ELSE_IF_STRCMP_SET(a_Name) else if (!strcmp(pszPartNm, #a_Name)) enmSect = krtDbgModDwarfSect_ ## a_Name
+#define ELSE_IF_STRCMP_SET(a_Name) else if (!strcmp(pszSection, #a_Name)) enmSect = krtDbgModDwarfSect_ ## a_Name
ELSE_IF_STRCMP_SET(abbrev);
ELSE_IF_STRCMP_SET(aranges);
ELSE_IF_STRCMP_SET(frame);
@@ -3461,7 +4625,7 @@ static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iD
#undef ELSE_IF_STRCMP_SET
else
{
- AssertMsgFailed(("%s\n", pszPartNm));
+ AssertMsgFailed(("%s\n", pszSection));
return VINF_SUCCESS;
}
@@ -3469,21 +4633,66 @@ static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iD
* Record the section.
*/
PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)pvUser;
- AssertMsgReturn(!pThis->aSections[enmSect].fPresent, ("duplicate %s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
+ AssertMsgReturn(!pThis->aSections[enmSect].fPresent, ("duplicate %s\n", pszSection), VINF_SUCCESS /*ignore*/);
pThis->aSections[enmSect].fPresent = true;
- pThis->aSections[enmSect].offFile = offFile;
+ pThis->aSections[enmSect].offFile = pDbgInfo->offFile;
pThis->aSections[enmSect].pv = NULL;
- pThis->aSections[enmSect].cb = (size_t)cb;
- if (pThis->aSections[enmSect].cb != cb)
+ pThis->aSections[enmSect].cb = (size_t)pDbgInfo->cb;
+ pThis->aSections[enmSect].iDbgInfo = pDbgInfo->iDbgInfo;
+ if (pThis->aSections[enmSect].cb != pDbgInfo->cb)
pThis->aSections[enmSect].cb = ~(size_t)0;
return VINF_SUCCESS;
}
+static int rtDbgModDwarfTryOpenDbgFile(PRTDBGMODINT pDbgMod, PRTDBGMODDWARF pThis, RTLDRARCH enmArch)
+{
+ if ( !pDbgMod->pszDbgFile
+ || RTPathIsSame(pDbgMod->pszDbgFile, pDbgMod->pszImgFile) == (int)true /* returns VERR too */)
+ return VERR_DBG_NO_MATCHING_INTERPRETER;
+
+ /*
+ * Only open the image.
+ */
+ PRTDBGMODINT pDbgInfoMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgInfoMod));
+ if (!pDbgInfoMod)
+ return VERR_NO_MEMORY;
+
+ int rc;
+ pDbgInfoMod->u32Magic = RTDBGMOD_MAGIC;
+ pDbgInfoMod->cRefs = 1;
+ if (RTStrCacheRetain(pDbgMod->pszDbgFile) != UINT32_MAX)
+ {
+ pDbgInfoMod->pszImgFile = pDbgMod->pszDbgFile;
+ if (RTStrCacheRetain(pDbgMod->pszName) != UINT32_MAX)
+ {
+ pDbgInfoMod->pszName = pDbgMod->pszName;
+ pDbgInfoMod->pImgVt = &g_rtDbgModVtImgLdr;
+ rc = pDbgInfoMod->pImgVt->pfnTryOpen(pDbgInfoMod, enmArch);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->pDbgInfoMod = pDbgInfoMod;
+ pThis->pNestedMod = pDbgInfoMod;
+ return VINF_SUCCESS;
+ }
+
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgInfoMod->pszName);
+ }
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTStrCacheRelease(g_hDbgModStrCache, pDbgInfoMod->pszImgFile);
+ }
+ else
+ rc = VERR_NO_STR_MEMORY;
+ RTMemFree(pDbgInfoMod);
+ return rc;
+}
+
+
/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
-static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
+static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
{
/*
* DWARF is only supported when part of an image.
@@ -3492,15 +4701,54 @@ static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
return VERR_DBG_NO_MATCHING_INTERPRETER;
/*
- * Enumerate the debug info in the module, looking for DWARF bits.
+ * Create the module instance data.
*/
PRTDBGMODDWARF pThis = (PRTDBGMODDWARF)RTMemAllocZ(sizeof(*pThis));
if (!pThis)
return VERR_NO_MEMORY;
- pThis->pMod = pMod;
+ pThis->pDbgInfoMod = pMod;
+ pThis->pImgMod = pMod;
RTListInit(&pThis->CompileUnitList);
+ /** @todo better fUseLinkAddress heuristics! */
+ if ( (pMod->pszDbgFile && strstr(pMod->pszDbgFile, "mach_kernel"))
+ || (pMod->pszImgFile && strstr(pMod->pszImgFile, "mach_kernel")) )
+ pThis->fUseLinkAddress = true;
+
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ AssertCompile(RT_ELEMENTS(pThis->aDieAllocators) == 2);
+ pThis->aDieAllocators[0].cbMax = sizeof(RTDWARFDIE);
+ pThis->aDieAllocators[1].cbMax = sizeof(RTDWARFDIECOMPILEUNIT);
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aTagDescs); i++)
+ if (g_aTagDescs[i].pDesc && g_aTagDescs[i].pDesc->cbDie > pThis->aDieAllocators[1].cbMax)
+ pThis->aDieAllocators[1].cbMax = (uint32_t)g_aTagDescs[i].pDesc->cbDie;
+ pThis->aDieAllocators[1].cbMax = RT_ALIGN_32(pThis->aDieAllocators[1].cbMax, sizeof(uint64_t));
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDieAllocators); i++)
+ {
+ int rc = RTMemCacheCreate(&pThis->aDieAllocators[i].hMemCache, pThis->aDieAllocators[i].cbMax, sizeof(uint64_t),
+ UINT32_MAX, NULL /*pfnCtor*/, NULL /*pfnDtor*/, NULL /*pvUser*/, 0 /*fFlags*/);
+ if (RT_FAILURE(rc))
+ {
+ while (i-- > 0)
+ RTMemCacheDestroy(pThis->aDieAllocators[i].hMemCache);
+ RTMemFree(pThis);
+ return rc;
+ }
+ }
+#endif
- int rc = pMod->pImgVt->pfnEnumDbgInfo(pMod, rtDbgModDwarfEnumCallback, pThis);
+ /*
+ * If the debug file name is set, let's see if it's an ELF image with DWARF
+ * inside it. In that case we'll have to deal with two image modules, one
+ * for segments and address translation and one for the debug information.
+ */
+ if (pMod->pszDbgFile != NULL)
+ rtDbgModDwarfTryOpenDbgFile(pMod, pThis, enmArch);
+
+ /*
+ * Enumerate the debug info in the module, looking for DWARF bits.
+ */
+ int rc = pThis->pDbgInfoMod->pImgVt->pfnEnumDbgInfo(pThis->pDbgInfoMod, rtDbgModDwarfEnumCallback, pThis);
if (RT_SUCCESS(rc))
{
if (pThis->aSections[krtDbgModDwarfSect_info].fPresent)
@@ -3514,25 +4762,35 @@ static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
{
pMod->pvDbgPriv = pThis;
- rc = rtDbgModHlpAddSegmentsFromImage(pMod);
+ rc = rtDbgModDwarfAddSegmentsFromImage(pThis);
if (RT_SUCCESS(rc))
rc = rtDwarfInfo_LoadAll(pThis);
if (RT_SUCCESS(rc))
rc = rtDwarfLine_ExplodeAll(pThis);
+ if (RT_SUCCESS(rc) && pThis->iWatcomPass == 1)
+ {
+ rc = rtDbgModDwarfAddSegmentsFromPass1(pThis);
+ pThis->iWatcomPass = 2;
+ if (RT_SUCCESS(rc))
+ rc = rtDwarfInfo_LoadAll(pThis);
+ if (RT_SUCCESS(rc))
+ rc = rtDwarfLine_ExplodeAll(pThis);
+ }
if (RT_SUCCESS(rc))
{
/*
* Free the cached abbreviations and unload all sections.
*/
- pThis->cCachedAbbrevs = pThis->cCachedAbbrevsAlloced = 0;
+ pThis->cCachedAbbrevsAlloced = 0;
RTMemFree(pThis->paCachedAbbrevs);
+ pThis->paCachedAbbrevs = NULL;
for (unsigned iSect = 0; iSect < RT_ELEMENTS(pThis->aSections); iSect++)
if (pThis->aSections[iSect].pv)
- pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb,
- &pThis->aSections[iSect].pv);
-
+ pThis->pDbgInfoMod->pImgVt->pfnUnmapPart(pThis->pDbgInfoMod, pThis->aSections[iSect].cb,
+ &pThis->aSections[iSect].pv);
+ /** @todo Kill pThis->CompileUnitList and the alloc caches. */
return VINF_SUCCESS;
}
@@ -3544,7 +4802,18 @@ static DECLCALLBACK(int) rtDbgModDwarf_TryOpen(PRTDBGMODINT pMod)
else
rc = VERR_DBG_NO_MATCHING_INTERPRETER;
}
+
RTMemFree(pThis->paCachedAbbrevs);
+
+#ifdef RTDBGMODDWARF_WITH_MEM_CACHE
+ uint32_t i = RT_ELEMENTS(pThis->aDieAllocators);
+ while (i-- > 0)
+ {
+ RTMemCacheDestroy(pThis->aDieAllocators[i].hMemCache);
+ pThis->aDieAllocators[i].hMemCache = NIL_RTMEMCACHE;
+ }
+#endif
+
RTMemFree(pThis);
return rc;