Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/dwarfcache.c')
-rw-r--r--agent/tcf/services/dwarfcache.c1345
1 files changed, 1345 insertions, 0 deletions
diff --git a/agent/tcf/services/dwarfcache.c b/agent/tcf/services/dwarfcache.c
new file mode 100644
index 00000000..0da30798
--- /dev/null
+++ b/agent/tcf/services/dwarfcache.c
@@ -0,0 +1,1345 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements caching of DWARF debug information.
+ *
+ * Functions in this module use exceptions to report errors, see exceptions.h
+ */
+
+#include <config.h>
+
+#if ENABLE_ELF && ENABLE_DebugContext
+
+#include <assert.h>
+#include <framework/exceptions.h>
+#include <framework/myalloc.h>
+#include <services/dwarf.h>
+#include <services/dwarfio.h>
+#include <services/dwarfcache.h>
+#include <services/dwarfexpr.h>
+#include <services/stacktrace.h>
+
+#define OBJ_HASH(Cache,ID) (((U4_T)(ID) + ((U4_T)(ID) >> 8)) % Cache->mObjectHashSize)
+
+static DWARFCache * sCache;
+static ELF_Section * sDebugSection;
+static DIO_UnitDescriptor sUnitDesc;
+static CompUnit * sCompUnit;
+static ObjectInfo * sParentObject;
+static ObjectInfo * sPrevSibling;
+
+static int sCloseListenerOK = 0;
+
+unsigned calc_file_name_hash(const char * s) {
+ unsigned l = strlen(s);
+ unsigned h = 0;
+ while (l > 0) {
+ unsigned g;
+ unsigned char ch = s[--l];
+ if (ch == '/') break;
+ if (ch == '\\') break;
+ h = (h << 4) + ch;
+ g = h & 0xf0000000;
+ if (g) h ^= g >> 24;
+ h &= ~g;
+ }
+ return h;
+}
+
+ObjectInfo * find_object(DWARFCache * Cache, U8_T ID) {
+ if (Cache->mObjectHash != NULL) {
+ ObjectInfo * Info = Cache->mObjectHash[OBJ_HASH(Cache, ID)];
+
+ while (Info != NULL) {
+ if (Info->mID == ID) return Info;
+ Info = Info->mHashNext;
+ }
+ }
+ return NULL;
+}
+
+static ObjectInfo * add_object_info(U8_T ID) {
+ ObjectInfo * Info = find_object(sCache, ID);
+ if (Info == NULL) {
+ U4_T Hash;
+ if (ID < sDebugSection->addr + dio_gEntryPos) str_exception(ERR_INV_DWARF, "Invalid entry reference");
+ if (ID > sDebugSection->addr + sDebugSection->size) str_exception(ERR_INV_DWARF, "Invalid entry reference");
+ if (sCache->mObjectHash == NULL) {
+ sCache->mObjectHashSize = (unsigned)(sDebugSection->size / 251);
+ if (sCache->mObjectHashSize < 101) sCache->mObjectHashSize = 101;
+ sCache->mObjectHash = (ObjectInfo **)loc_alloc_zero(sizeof(ObjectInfo *) * sCache->mObjectHashSize);
+ }
+ Hash = OBJ_HASH(sCache, ID);
+ if (sCache->mObjectArrayPos >= OBJECT_ARRAY_SIZE) {
+ ObjectArray * Buf = (ObjectArray *)loc_alloc_zero(sizeof(ObjectArray));
+ Buf->mNext = sCache->mObjectList;
+ sCache->mObjectList = Buf;
+ sCache->mObjectArrayPos = 0;
+ }
+ Info = sCache->mObjectList->mArray + sCache->mObjectArrayPos++;
+ Info->mHashNext = sCache->mObjectHash[Hash];
+ sCache->mObjectHash[Hash] = Info;
+ Info->mID = ID;
+ }
+ return Info;
+}
+
+static CompUnit * add_comp_unit(U8_T ID) {
+ ObjectInfo * Info = add_object_info(ID);
+ if (Info->mCompUnit == NULL) {
+ CompUnit * Unit = (CompUnit *)loc_alloc_zero(sizeof(CompUnit));
+ Unit->mObject = Info;
+ Info->mCompUnit = Unit;
+ }
+ return Info->mCompUnit;
+}
+
+static U4_T get_fund_type_size(CompUnit * Unit, U2_T ft) {
+ switch (ft) {
+ case FT_char :
+ case FT_signed_char :
+ case FT_unsigned_char :
+ return 1;
+ case FT_short :
+ case FT_signed_short :
+ case FT_unsigned_short:
+ return 2;
+ case FT_integer :
+ case FT_signed_integer:
+ case FT_unsigned_integer:
+ return 4;
+ case FT_long :
+ case FT_signed_long :
+ case FT_unsigned_long :
+ return Unit->mFile->elf64 ? 8 : 4;
+ case FT_pointer :
+ return Unit->mDesc.mAddressSize;
+ case FT_float :
+ return 4;
+ case FT_dbl_prec_float:
+ return 8;
+ case FT_complex :
+ return 8;
+ case FT_dbl_prec_complex:
+ return 16;
+ case FT_boolean :
+ return 4;
+ case FT_void :
+ return 0;
+ }
+ str_exception(ERR_INV_DWARF, "Invalid fundamental type code");
+ return 0;
+}
+
+static void read_mod_fund_type(U2_T Form, ObjectInfo ** Type) {
+ U1_T * Buf;
+ size_t BufSize;
+ size_t BufPos;
+ int i;
+ U2_T FT = 0;
+ dio_ChkBlock(Form, &Buf, &BufSize);
+ for (i = 0; i < 2; i++) {
+ FT |= (U2_T)Buf[BufSize - 2 +
+ (sDebugSection->file->big_endian ? 1 - i : i)] << (i * 8);
+ }
+ *Type = add_object_info(sDebugSection->addr + dio_GetPos() - 2);
+ (*Type)->mTag = TAG_fund_type;
+ (*Type)->mCompUnit = sCompUnit;
+ (*Type)->u.mFundType = FT;
+ BufPos = BufSize - 2;
+ while (BufPos > 0) {
+ U2_T Tag = 0;
+ ObjectInfo * Mod = NULL;
+ switch (Buf[--BufPos]) {
+ case MOD_volatile:
+ case MOD_const:
+ continue;
+ case MOD_pointer_to:
+ Tag = TAG_mod_pointer;
+ break;
+ case MOD_reference_to:
+ Tag = TAG_mod_reference;
+ break;
+ default:
+ str_exception(ERR_INV_DWARF, "Invalid type modifier code");
+ }
+ Mod = add_object_info(sDebugSection->addr + dio_GetPos() - BufSize + BufPos);
+ Mod->mTag = Tag;
+ Mod->mCompUnit = sCompUnit;
+ Mod->mType = *Type;
+ *Type = Mod;
+ }
+}
+
+static void read_mod_user_def_type(U2_T Form, ObjectInfo ** Type) {
+ U1_T * Buf;
+ size_t BufSize;
+ size_t BufPos;
+ int i;
+ U4_T Ref = 0;
+ dio_ChkBlock(Form, &Buf, &BufSize);
+ for (i = 0; i < 4; i++) {
+ Ref |= (U4_T)Buf[BufSize - 4 +
+ (sDebugSection->file->big_endian ? 3 - i : i)] << (i * 8);
+ }
+ *Type = add_object_info(sDebugSection->addr + Ref);
+ BufPos = BufSize - 4;
+ while (BufPos > 0) {
+ U2_T Tag = 0;
+ ObjectInfo * Mod = NULL;
+ switch (Buf[--BufPos]) {
+ case MOD_volatile:
+ case MOD_const:
+ continue;
+ case MOD_pointer_to:
+ Tag = TAG_mod_pointer;
+ break;
+ case MOD_reference_to:
+ Tag = TAG_mod_reference;
+ break;
+ default:
+ str_exception(ERR_INV_DWARF, "Invalid type modifier code");
+ }
+ Mod = add_object_info(sDebugSection->addr + dio_GetPos() - BufSize + BufPos);
+ Mod->mTag = Tag;
+ Mod->mCompUnit = sCompUnit;
+ Mod->mType = *Type;
+ *Type = Mod;
+ }
+}
+
+static I8_T read_long_value(void) {
+ switch (get_fund_type_size(sCompUnit, FT_long)) {
+ case 4: return (I4_T)dio_ReadU4();
+ case 8: return (I8_T)dio_ReadU8();
+ }
+ str_exception(ERR_OTHER, "Invalid size of long int");
+ return 0;
+}
+
+static void read_subscr_data(U2_T Form, ObjectInfo * Array) {
+ U1_T * Buf;
+ size_t BufSize;
+ U8_T BufEnd = 0;
+ U8_T OrgPos = dio_GetPos();
+ ObjectInfo ** Children = &Array->mChildren;
+
+ assert(Array->mChildren == NULL);
+ assert(Array->mType == NULL);
+
+ dio_ChkBlock(Form, &Buf, &BufSize);
+ dio_SetPos(Buf - (U1_T *)sDebugSection->data);
+ BufEnd = dio_GetPos() + BufSize;
+ while (dio_GetPos() < BufEnd) {
+ ObjectInfo * Type = NULL;
+ U1_T Fmt = dio_ReadU1();
+ switch (Fmt) {
+ case FMT_FT_C_C:
+ case FMT_FT_C_X:
+ case FMT_FT_X_C:
+ case FMT_FT_X_X:
+ Type = add_object_info(sDebugSection->addr + dio_GetPos());
+ Type->mTag = TAG_fund_type;
+ Type->mCompUnit = sCompUnit;
+ Type->u.mFundType = dio_ReadU2();
+ break;
+ case FMT_UT_C_C:
+ case FMT_UT_C_X:
+ case FMT_UT_X_C:
+ case FMT_UT_X_X:
+ dio_ReadAttribute(AT_subscr_data, FORM_REF);
+ Type = add_object_info(dio_gFormData);
+ break;
+ }
+ if (Type != NULL) {
+ ObjectInfo * Range = add_object_info(sDebugSection->addr + dio_GetPos());
+ Range->mTag = TAG_index_range;
+ Range->mCompUnit = sCompUnit;
+ Range->mType = Type;
+ Range->u.mRange.mFmt = Fmt;
+ switch (Fmt) {
+ case FMT_FT_C_C:
+ case FMT_FT_C_X:
+ case FMT_UT_C_C:
+ case FMT_UT_C_X:
+ Range->u.mRange.mLow.mValue = read_long_value();
+ break;
+ case FMT_FT_X_C:
+ case FMT_FT_X_X:
+ case FMT_UT_X_C:
+ case FMT_UT_X_X:
+ dio_ReadAttribute(0, FORM_BLOCK2);
+ Range->u.mRange.mLow.mExpr.mAddr = (U1_T *)dio_gFormDataAddr;
+ Range->u.mRange.mLow.mExpr.mSize = dio_gFormDataSize;
+ break;
+ }
+ switch (Fmt) {
+ case FMT_FT_C_C:
+ case FMT_FT_X_C:
+ case FMT_UT_C_C:
+ case FMT_UT_X_C:
+ Range->u.mRange.mHigh.mValue = read_long_value();
+ break;
+ case FMT_FT_C_X:
+ case FMT_FT_X_X:
+ case FMT_UT_C_X:
+ case FMT_UT_X_X:
+ dio_ReadAttribute(0, FORM_BLOCK2);
+ Range->u.mRange.mHigh.mExpr.mAddr = (U1_T *)dio_gFormDataAddr;
+ Range->u.mRange.mHigh.mExpr.mSize = dio_gFormDataSize;
+ break;
+ }
+ *Children = Range;
+ Children = &Range->mSibling;
+ }
+ else if (Fmt == FMT_ET) {
+ U2_T x = dio_ReadU2();
+ U2_T Attr = (x & 0xfff0u) >> 4;
+ U2_T Form = x & 0xfu;
+ dio_ReadAttribute(Attr, Form);
+ switch (Attr) {
+ case AT_fund_type:
+ dio_ChkData(Form);
+ Type = add_object_info(sDebugSection->addr + dio_GetPos() - dio_gFormDataSize);
+ Type->mTag = TAG_fund_type;
+ Type->mCompUnit = sCompUnit;
+ Type->u.mFundType = (U2_T)dio_gFormData;
+ break;
+ case AT_user_def_type:
+ dio_ChkRef(Form);
+ Type = add_object_info(dio_gFormData);
+ break;
+ case AT_mod_fund_type:
+ read_mod_fund_type(Form, &Type);
+ break;
+ case AT_mod_u_d_type:
+ read_mod_user_def_type(Form, &Type);
+ break;
+ default:
+ str_exception(ERR_INV_DWARF, "Invalid array element type format");
+ }
+ Array->mType = Type;
+ }
+ else {
+ str_exception(ERR_INV_DWARF, "Invalid array subscription format");
+ }
+ }
+ dio_SetPos(OrgPos);
+}
+
+static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) {
+ static ObjectInfo * Info;
+ static ObjectInfo * Spec;
+ static ObjectInfo * AOrg;
+ static U8_T Sibling;
+ static int HasChildren;
+
+ switch (Attr) {
+ case 0:
+ if (Form) {
+ assert((sParentObject == NULL) == (Tag == TAG_compile_unit));
+ if (Tag == TAG_compile_unit) {
+ CompUnit * Unit = add_comp_unit(sDebugSection->addr + dio_gEntryPos);
+ Unit->mFile = sCache->mFile;
+ Unit->mDebugRangesOffs = ~(U8_T)0;
+ Unit->mRegIdScope.big_endian = sCache->mFile->big_endian;
+ Unit->mRegIdScope.machine = sCache->mFile->machine;
+ Unit->mRegIdScope.os_abi = sCache->mFile->os_abi;
+ Unit->mRegIdScope.id_type = REGNUM_DWARF;
+ Info = Unit->mObject;
+ sCompUnit = Unit;
+ }
+ else {
+ Info = add_object_info(sDebugSection->addr + dio_gEntryPos);
+ Info->mCompUnit = sCompUnit;
+ }
+ assert(Info->mTag == 0);
+ Info->mTag = Tag;
+ Info->mParent = sParentObject;
+ HasChildren = Form == DWARF_ENTRY_HAS_CHILDREN;
+ Sibling = 0;
+ Spec = NULL;
+ AOrg = NULL;
+ }
+ else {
+ if (Spec != NULL) {
+ if (Info->mName == NULL) Info->mName = Spec->mName;
+ if (Info->mType == NULL) Info->mType = Spec->mType;
+ }
+ if (AOrg != NULL) {
+ if (Info->mName == NULL) Info->mName = AOrg->mName;
+ if (Info->mType == NULL) Info->mType = AOrg->mType;
+ }
+ if (Tag == TAG_compile_unit && Sibling == 0) Sibling = sUnitDesc.mUnitOffs + sUnitDesc.mUnitSize;
+ if (Tag == TAG_enumerator && Info->mType == NULL) Info->mType = sParentObject;
+ if (sPrevSibling != NULL) sPrevSibling->mSibling = Info;
+ else if (sParentObject != NULL) sParentObject->mChildren = Info;
+ else sCache->mCompUnits = Info;
+ sPrevSibling = Info;
+ if (Sibling != 0 || HasChildren) {
+ U8_T SiblingPos = Sibling;
+ ObjectInfo * Parent = sParentObject;
+ ObjectInfo * PrevSibling = sPrevSibling;
+ sParentObject = Info;
+ sPrevSibling = NULL;
+ for (;;) {
+ if (SiblingPos > 0 && dio_GetPos() >= SiblingPos) break;
+ if (!dio_ReadEntry(read_object_info, 0)) break;
+ }
+ if (SiblingPos > dio_GetPos()) dio_SetPos(SiblingPos);
+ sParentObject = Parent;
+ sPrevSibling = PrevSibling;
+ }
+ }
+ break;
+ case AT_sibling:
+ dio_ChkRef(Form);
+ Sibling = dio_gFormData - sDebugSection->addr;
+ break;
+ case AT_type:
+ dio_ChkRef(Form);
+ Info->mType = add_object_info(dio_gFormData);
+ break;
+ case AT_fund_type:
+ dio_ChkData(Form);
+ Info->mType = add_object_info(sDebugSection->addr + dio_GetPos() - dio_gFormDataSize);
+ Info->mType->mTag = TAG_fund_type;
+ Info->mType->mCompUnit = sCompUnit;
+ Info->mType->u.mFundType = (U2_T)dio_gFormData;
+ break;
+ case AT_user_def_type:
+ dio_ChkRef(Form);
+ Info->mType = add_object_info(dio_gFormData);
+ break;
+ case AT_mod_fund_type:
+ read_mod_fund_type(Form, &Info->mType);
+ break;
+ case AT_mod_u_d_type:
+ read_mod_user_def_type(Form, &Info->mType);
+ break;
+ case AT_subscr_data:
+ read_subscr_data(Form, Info);
+ break;
+ case AT_name:
+ dio_ChkString(Form);
+ Info->mName = (char *)dio_gFormDataAddr;
+ break;
+ case AT_specification_v2:
+ dio_ChkRef(Form);
+ Spec = add_object_info(dio_gFormData);
+ break;
+ case AT_abstract_origin:
+ dio_ChkRef(Form);
+ AOrg = add_object_info(dio_gFormData);
+ break;
+ case AT_low_pc:
+ dio_ChkAddr(Form);
+ Info->u.mAddr.mLowPC = (ContextAddress)dio_gFormData;
+ break;
+ case AT_high_pc:
+ dio_ChkAddr(Form);
+ Info->u.mAddr.mHighPC = (ContextAddress)dio_gFormData;
+ break;
+ }
+ if (Tag == TAG_compile_unit) {
+ CompUnit * Unit = Info->mCompUnit;
+ switch (Attr) {
+ case AT_low_pc:
+ dio_ChkAddr(Form);
+ Unit->mLowPC = (ContextAddress)dio_gFormData;
+ Unit->mTextSection = dio_gFormSection;
+ break;
+ case AT_high_pc:
+ dio_ChkAddr(Form);
+ Unit->mHighPC = (ContextAddress)dio_gFormData;
+ break;
+ case AT_ranges:
+ dio_ChkData(Form);
+ Unit->mDebugRangesOffs = dio_gFormData;
+ break;
+ case AT_comp_dir:
+ dio_ChkString(Form);
+ Unit->mDir = (char *)dio_gFormDataAddr;
+ break;
+ case AT_stmt_list:
+ dio_ChkData(Form);
+ Unit->mLineInfoOffs = dio_gFormData;
+ break;
+ case AT_base_types:
+ Unit->mBaseTypes = add_comp_unit(dio_gFormData);
+ break;
+ case AT_language:
+ dio_ChkData(Form);
+ Unit->mLanguage = (U2_T)dio_gFormData;
+ break;
+ }
+ }
+}
+
+static int cmp_addr_ranges(const void * x, const void * y) {
+ UnitAddressRange * rx = (UnitAddressRange *)x;
+ UnitAddressRange * ry = (UnitAddressRange *)y;
+ if (rx->mAddr < ry->mAddr) return -1;
+ if (rx->mAddr > ry->mAddr) return +1;
+ return 0;
+}
+
+static void add_addr_range(ELF_Section * sec, CompUnit * unit, ContextAddress addr, ContextAddress size) {
+ UnitAddressRange * range = NULL;
+ if (sCache->mAddrRangesCnt >= sCache->mAddrRangesMax) {
+ sCache->mAddrRangesMax = sCache->mAddrRangesMax == 0 ? 64 : sCache->mAddrRangesMax * 2;
+ sCache->mAddrRanges = (UnitAddressRange *)loc_realloc(sCache->mAddrRanges, sizeof(UnitAddressRange) * sCache->mAddrRangesMax);
+ }
+ range = sCache->mAddrRanges + sCache->mAddrRangesCnt++;
+ memset(range, 0, sizeof(UnitAddressRange));
+ range->mSection = sec;
+ range->mAddr = addr;
+ range->mSize = size;
+ range->mUnit = unit;
+}
+
+static void load_addr_ranges(void) {
+ Trap trap;
+ unsigned idx;
+ ELF_File * file = sCache->mFile;
+ ELF_Section * debug_ranges = NULL;
+
+ memset(&trap, 0, sizeof(trap));
+ for (idx = 1; idx < file->section_cnt; idx++) {
+ ELF_Section * sec = file->sections + idx;
+ if (sec->size == 0) continue;
+ if (sec->name == NULL) continue;
+ if (strcmp(sec->name, ".debug_ranges") == 0) {
+ debug_ranges = sec;
+ }
+ else if (strcmp(sec->name, ".debug_aranges") == 0) {
+ ObjectInfo * info = sCache->mCompUnits;
+ dio_EnterSection(NULL, sec, 0);
+ if (set_trap(&trap)) {
+ while (dio_GetPos() < sec->size) {
+ int dwarf64 = 0;
+ U8_T size = dio_ReadU4();
+ U8_T next = 0;
+ if (size == 0xffffffffu) {
+ dwarf64 = 1;
+ size = dio_ReadU8();
+ }
+ next = dio_GetPos() + size;
+ if (dio_ReadU2() != 2) {
+ dio_SetPos(next);
+ }
+ else {
+ U8_T offs = dwarf64 ? dio_ReadU8() : (U8_T)dio_ReadU4();
+ U1_T addr_size = dio_ReadU1();
+ U1_T segm_size = dio_ReadU1();
+ if (segm_size != 0) str_exception(ERR_INV_DWARF, "segment descriptors are not supported");
+ while (info != NULL && info->mCompUnit->mDesc.mUnitOffs != offs) info = info->mSibling;
+ if (info == NULL) {
+ info = sCache->mCompUnits;
+ while (info != NULL && info->mCompUnit->mDesc.mUnitOffs != offs) info = info->mSibling;
+ }
+ if (info == NULL) str_exception(ERR_INV_DWARF, "invalid .debug_aranges section");
+ info->mCompUnit->mARangesFound = 1;
+ while (dio_GetPos() % (addr_size * 2) != 0) dio_Skip(1);
+ for (;;) {
+ ELF_Section * range_sec = NULL;
+ ContextAddress addr = dio_ReadAddressX(&range_sec, addr_size);
+ ContextAddress size = dio_ReadUX(addr_size);
+ if (addr == 0 && size == 0) break;
+ if (size == 0) continue;
+ add_addr_range(range_sec, info->mCompUnit, addr, size);
+ }
+ }
+ }
+ clear_trap(&trap);
+ }
+ dio_ExitSection();
+ if (trap.error) break;
+ }
+ }
+ if (trap.error) exception(trap.error);
+ if (sCache->mCompUnits != NULL) {
+ ObjectInfo * info = sCache->mCompUnits;
+ while (info != NULL) {
+ CompUnit * unit = info->mCompUnit;
+ ContextAddress base = unit->mLowPC;
+ ContextAddress size = unit->mHighPC - unit->mLowPC;
+ info = info->mSibling;
+ if (unit->mARangesFound) continue;
+ if (size == 0) continue;
+ if (unit->mDebugRangesOffs != ~(U8_T)0 && debug_ranges != NULL) {
+ dio_EnterSection(&unit->mDesc, debug_ranges, unit->mDebugRangesOffs);
+ for (;;) {
+ ELF_Section * sec = NULL;
+ U8_T x = dio_ReadAddress(&sec);
+ U8_T y = dio_ReadAddress(&sec);
+ if (x == 0 && y == 0) break;
+ if (sec != unit->mTextSection) exception(ERR_INV_DWARF);
+ if (x == ((U8_T)1 << unit->mDesc.mAddressSize * 8) - 1) {
+ base = (ContextAddress)y;
+ }
+ else {
+ x = base + x;
+ y = base + y;
+ add_addr_range(sec, unit, x, y - x);
+ }
+ }
+ dio_ExitSection();
+ }
+ else {
+ add_addr_range(unit->mTextSection, unit, base, size);
+ }
+ }
+ }
+ if (sCache->mAddrRangesCnt > 1) {
+ qsort(sCache->mAddrRanges, sCache->mAddrRangesCnt, sizeof(UnitAddressRange), cmp_addr_ranges);
+ }
+}
+
+static void load_pub_names(ELF_Section * debug_info, ELF_Section * pub_names, PubNamesTable * tbl) {
+ tbl->mMax = (unsigned)(pub_names->size / 16) + 16;
+ tbl->mHash = (unsigned *)loc_alloc_zero(sizeof(unsigned) * SYM_HASH_SIZE);
+ tbl->mNext = (PubNamesInfo *)loc_alloc(sizeof(PubNamesInfo) * tbl->mMax);
+ memset(tbl->mNext + tbl->mCnt++, 0, sizeof(PubNamesInfo));
+ dio_EnterSection(NULL, pub_names, 0);
+ while (dio_GetPos() < pub_names->size) {
+ int dwarf64 = 0;
+ U8_T size = dio_ReadU4();
+ U8_T next = 0;
+ if (size == 0xffffffffu) {
+ dwarf64 = 1;
+ size = dio_ReadU8();
+ }
+ next = dio_GetPos() + size;
+ if (dio_ReadU2() == 2) {
+ ELF_Section * unit_sect = NULL;
+ U8_T unit_addr = dio_ReadAddressX(&unit_sect, dwarf64 ? 8 : 4);
+ U8_T unit_offs = unit_sect == NULL ? unit_addr : unit_addr - unit_sect->addr;
+ U8_T unit_size = dwarf64 ? dio_ReadU8() : (U8_T)dio_ReadU4();
+ if (unit_offs + unit_size > debug_info->size) str_fmt_exception(ERR_INV_DWARF,
+ "Invalid unit size in %s section", pub_names->name);
+ for (;;) {
+ unsigned h;
+ PubNamesInfo * info = NULL;
+ U8_T obj_offs = dwarf64 ? dio_ReadU8() : (U8_T)dio_ReadU4();
+ if (obj_offs == 0) break;
+ if (obj_offs >= unit_size) str_fmt_exception(ERR_INV_DWARF,
+ "Invalid object offset in %s section", pub_names->name);
+ if (tbl->mCnt >= tbl->mMax) {
+ tbl->mMax = tbl->mMax * 3 / 2;
+ tbl->mNext = (PubNamesInfo *)loc_realloc(tbl->mNext, sizeof(PubNamesInfo) * tbl->mMax);
+ }
+ info = tbl->mNext + tbl->mCnt;
+ h = calc_symbol_name_hash(dio_ReadString());
+ info->mID = debug_info->addr + unit_offs + obj_offs;
+ info->mNext = tbl->mHash[h];
+ tbl->mHash[h] = tbl->mCnt++;
+ }
+ }
+ assert(next >= dio_GetPos());
+ dio_SetPos(next);
+ }
+ dio_ExitSection();
+}
+
+static void load_debug_sections(void) {
+ Trap trap;
+ unsigned idx;
+ ELF_Section * pub_names = NULL;
+ ELF_Section * pub_types = NULL;
+ ELF_Section * debug_info = NULL;
+ ELF_File * file = sCache->mFile;
+
+ memset(&trap, 0, sizeof(trap));
+
+ for (idx = 1; idx < file->section_cnt; idx++) {
+ ELF_Section * sec = file->sections + idx;
+ if (sec->size == 0) continue;
+ if (sec->name == NULL) continue;
+ if (strcmp(sec->name, ".debug") == 0 || strcmp(sec->name, ".debug_info") == 0) {
+ if (strcmp(sec->name, ".debug_info") == 0) debug_info = sec;
+ sDebugSection = sec;
+ sParentObject = NULL;
+ sPrevSibling = NULL;
+ dio_EnterSection(NULL, sec, 0);
+ if (set_trap(&trap)) {
+ while (dio_GetPos() < sec->size) {
+ dio_ReadUnit(&sUnitDesc, read_object_info);
+ sCompUnit->mDesc = sUnitDesc;
+ }
+ clear_trap(&trap);
+ }
+ dio_ExitSection();
+ sParentObject = NULL;
+ sPrevSibling = NULL;
+ sCompUnit = NULL;
+ sDebugSection = NULL;
+ if (trap.error) break;
+ }
+ else if (strcmp(sec->name, ".line") == 0) {
+ sCache->mDebugLineV1 = sec;
+ }
+ else if (strcmp(sec->name, ".debug_line") == 0) {
+ sCache->mDebugLine = sec;
+ }
+ else if (strcmp(sec->name, ".debug_loc") == 0) {
+ sCache->mDebugLoc = sec;
+ }
+ else if (strcmp(sec->name, ".debug_ranges") == 0) {
+ sCache->mDebugRanges = sec;
+ }
+ else if (strcmp(sec->name, ".debug_frame") == 0) {
+ sCache->mDebugFrame = sec;
+ }
+ else if (strcmp(sec->name, ".eh_frame") == 0) {
+ sCache->mEHFrame = sec;
+ }
+ else if (strcmp(sec->name, ".debug_pubnames") == 0) {
+ pub_names = sec;
+ }
+ else if (strcmp(sec->name, ".debug_pubtypes") == 0) {
+ pub_types = sec;
+ }
+ }
+
+ if (debug_info) {
+ if (pub_names) load_pub_names(debug_info, pub_names, &sCache->mPubNames);
+ if (pub_types) load_pub_names(debug_info, pub_types, &sCache->mPubTypes);
+ }
+
+ if (trap.error) exception(trap.error);
+}
+
+static U2_T gop_gAttr = 0;
+static U2_T gop_gForm = 0;
+static U8_T gop_gFormData = 0;
+static size_t gop_gFormDataSize = 0;
+static void * gop_gFormDataAddr = NULL;
+static ELF_Section * gop_gFormSection = NULL;
+static U8_T gop_gSpecification = 0;
+static U8_T gop_gAbstractOrigin = 0;
+
+static void get_object_property_callback(U2_T Tag, U2_T Attr, U2_T Form) {
+ if (Attr == AT_specification_v2) gop_gSpecification = dio_gFormData;
+ if (Attr == AT_abstract_origin) gop_gAbstractOrigin = dio_gFormData;
+ if (Attr != gop_gAttr) return;
+ gop_gForm = Form;
+ gop_gFormData = dio_gFormData;
+ gop_gFormDataSize = dio_gFormDataSize;
+ gop_gFormDataAddr = dio_gFormDataAddr;
+ gop_gFormSection = dio_gFormSection;
+}
+
+U8_T get_numeric_property_value(PropertyValue * Value) {
+ U8_T Res = 0;
+
+ if (Value->mPieces != NULL || Value->mRegister != NULL) {
+ str_exception(ERR_INV_CONTEXT, "Constant DWARF attribute value expected");
+ }
+ else if (Value->mAddr != NULL) {
+ size_t i;
+ for (i = 0; i < Value->mSize; i++) {
+ Res = (Res << 8) | Value->mAddr[Value->mBigEndian ? i : Value->mSize - i - 1];
+ }
+ }
+ else {
+ Res = Value->mValue;
+ }
+ return Res;
+}
+
+static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T Attr, PropertyValue * Value) {
+
+ memset(Value, 0, sizeof(PropertyValue));
+ Value->mContext = Ctx;
+ Value->mFrame = Frame;
+ Value->mObject = Obj;
+ Value->mAttr = Attr;
+ Value->mBigEndian = Obj->mCompUnit->mFile->big_endian;
+
+ if (Obj->mTag >= TAG_fund_type && Obj->mTag < TAG_fund_type + 0x100) {
+ /* Virtual DWARF object that is created by DWARF reader. It has no properties. */
+ if (Obj->mTag == TAG_fund_type) {
+ if (Attr == AT_byte_size) {
+ Value->mValue = get_fund_type_size(Obj->mCompUnit, Obj->u.mFundType);
+ return;
+ }
+ }
+ else if (Obj->mTag == TAG_index_range) {
+ /* TAG_index_range is virtual DWARF object that is created by DWARF reader. It has no properties. */
+ if (Attr == AT_lower_bound) {
+ switch (Obj->u.mRange.mFmt) {
+ case FMT_FT_C_C:
+ case FMT_FT_C_X:
+ case FMT_UT_C_C:
+ case FMT_UT_C_X:
+ Value->mValue = Obj->u.mRange.mLow.mValue;
+ return;
+ case FMT_FT_X_C:
+ case FMT_FT_X_X:
+ case FMT_UT_X_C:
+ case FMT_UT_X_X:
+ Value->mForm = FORM_BLOCK2;
+ Value->mAddr = Obj->u.mRange.mLow.mExpr.mAddr;
+ Value->mSize = Obj->u.mRange.mLow.mExpr.mSize;
+ return;
+ }
+ }
+ if (Attr == AT_upper_bound) {
+ switch (Obj->u.mRange.mFmt) {
+ case FMT_FT_C_C:
+ case FMT_FT_X_C:
+ case FMT_UT_C_C:
+ case FMT_UT_X_C:
+ Value->mValue = Obj->u.mRange.mHigh.mValue;
+ return;
+ case FMT_FT_C_X:
+ case FMT_FT_X_X:
+ case FMT_UT_C_X:
+ case FMT_UT_X_X:
+ Value->mForm = FORM_BLOCK2;
+ Value->mAddr = Obj->u.mRange.mHigh.mExpr.mAddr;
+ Value->mSize = Obj->u.mRange.mHigh.mExpr.mSize;
+ return;
+ }
+ }
+ }
+ else if (Obj->mTag == TAG_mod_pointer || Obj->mTag == TAG_mod_reference) {
+ if (Attr == AT_byte_size) {
+ Value->mValue = Obj->mCompUnit->mDesc.mAddressSize;
+ return;
+ }
+ }
+ exception(ERR_SYM_NOT_FOUND);
+ }
+
+ sCompUnit = Obj->mCompUnit;
+ sCache = (DWARFCache *)sCompUnit->mFile->dwarf_dt_cache;
+ sDebugSection = sCompUnit->mDesc.mSection;
+ dio_EnterSection(&sCompUnit->mDesc, sDebugSection, Obj->mID - sDebugSection->addr);
+ for (;;) {
+ gop_gAttr = Attr;
+ gop_gForm = 0;
+ gop_gSpecification = 0;
+ gop_gAbstractOrigin = 0;
+ dio_ReadEntry(get_object_property_callback, Attr);
+ dio_ExitSection();
+ if (gop_gForm != 0) break;
+ if (gop_gSpecification != 0) dio_EnterSection(&sCompUnit->mDesc, sDebugSection, gop_gSpecification - sDebugSection->addr);
+ else if (gop_gAbstractOrigin != 0) dio_EnterSection(&sCompUnit->mDesc, sDebugSection, gop_gAbstractOrigin - sDebugSection->addr);
+ else break;
+ }
+
+ switch (Value->mForm = gop_gForm) {
+ case FORM_REF :
+ case FORM_REF_ADDR :
+ case FORM_REF1 :
+ case FORM_REF2 :
+ case FORM_REF4 :
+ case FORM_REF8 :
+ case FORM_REF_UDATA :
+ if (Attr == AT_import) {
+ Value->mValue = gop_gFormData;
+ }
+ else {
+ PropertyValue ValueAddr;
+ ObjectInfo * RefObj = find_object(sCache, gop_gFormData);
+
+ if (RefObj == NULL) exception(ERR_INV_DWARF);
+ read_and_evaluate_dwarf_object_property(Ctx, Frame, 0, RefObj, AT_location, &ValueAddr);
+ if (ValueAddr.mRegister != NULL) {
+ static U1_T Buf[8];
+ StackFrame * Frame = NULL;
+ if (get_frame_info(ValueAddr.mContext, ValueAddr.mFrame, &Frame) < 0) exception(errno);
+ if (read_reg_bytes(Frame, ValueAddr.mRegister, 0, ValueAddr.mRegister->size, Buf) < 0) exception(errno);
+ Value->mAddr = Buf;
+ Value->mSize = ValueAddr.mSize;
+ Value->mBigEndian = ValueAddr.mBigEndian;
+ }
+ else {
+ static U1_T Buf[8];
+ PropertyValue ValueSize;
+ ContextAddress Addr;
+ size_t Size;
+
+ Addr = (ContextAddress)get_numeric_property_value(&ValueAddr);
+ read_and_evaluate_dwarf_object_property(Ctx, Frame, Addr, RefObj, AT_byte_size, &ValueSize);
+ Size = (size_t)get_numeric_property_value(&ValueSize);
+ if (Size < 1 || Size > sizeof(Buf)) exception(ERR_INV_DATA_TYPE);
+ if (context_read_mem(Ctx, Addr, Buf, Size) < 0) exception(errno);
+ Value->mAddr = Buf;
+ Value->mSize = Size;
+ }
+ }
+ break;
+ case FORM_DATA1 :
+ case FORM_DATA2 :
+ case FORM_DATA4 :
+ case FORM_DATA8 :
+ case FORM_FLAG :
+ case FORM_BLOCK1 :
+ case FORM_BLOCK2 :
+ case FORM_BLOCK4 :
+ case FORM_BLOCK :
+ case FORM_STRP :
+ Value->mAddr = (U1_T *)gop_gFormDataAddr;
+ Value->mSize = gop_gFormDataSize;
+ break;
+ case FORM_SDATA :
+ case FORM_UDATA :
+ Value->mValue = gop_gFormData;
+ break;
+ case FORM_ADDR :
+ Value->mValue = elf_map_to_run_time_address(Ctx, Obj->mCompUnit->mFile, gop_gFormSection, (ContextAddress)gop_gFormData);
+ break;
+ default:
+ if (Attr == AT_data_member_location && Obj->mTag == TAG_member && Obj->mParent->mTag == TAG_union_type) {
+ Value->mForm = FORM_UDATA;
+ Value->mValue = 0;
+ break;
+ }
+ if (Attr == AT_byte_size) {
+ if (Obj->mTag == TAG_pointer_type || Obj->mTag == TAG_reference_type || Obj->mTag == TAG_mod_pointer || Obj->mTag == TAG_mod_reference) {
+ Value->mForm = FORM_UDATA;
+ Value->mValue = sCompUnit->mDesc.mAddressSize;
+ break;
+ }
+ if (Obj->mTag == TAG_ptr_to_member_type) {
+ Value->mForm = FORM_UDATA;
+ Value->mValue = sCompUnit->mDesc.mAddressSize * 2;
+ break;
+ }
+ }
+ exception(ERR_SYM_NOT_FOUND);
+ }
+
+ sCompUnit = NULL;
+ sCache = NULL;
+ sDebugSection = NULL;
+}
+
+void read_and_evaluate_dwarf_object_property(Context * Ctx, int Frame, U8_T Base, ObjectInfo * Obj, U2_T Attr, PropertyValue * Value) {
+ read_dwarf_object_property(Ctx, Frame, Obj, Attr, Value);
+ assert(Value->mContext == Ctx);
+ assert(Value->mFrame == Frame);
+ assert(Value->mObject == Obj);
+ assert(Value->mAttr == Attr);
+ if (Attr == AT_location || Attr == AT_data_member_location || Attr == AT_frame_base) {
+ switch (Value->mForm) {
+ case FORM_DATA4 :
+ case FORM_DATA8 :
+ case FORM_BLOCK1 :
+ case FORM_BLOCK2 :
+ case FORM_BLOCK4 :
+ case FORM_BLOCK :
+ dwarf_evaluate_expression(Base, Value);
+ break;
+ }
+ }
+ else if (Attr == AT_count || Attr == AT_byte_size || Attr == AT_lower_bound || Attr == AT_upper_bound) {
+ switch (Value->mForm) {
+ case FORM_BLOCK1 :
+ case FORM_BLOCK2 :
+ case FORM_BLOCK4 :
+ case FORM_BLOCK :
+ dwarf_evaluate_expression(Base, Value);
+ break;
+ }
+ }
+}
+
+static void free_unit_cache(CompUnit * Unit) {
+ Unit->mFilesCnt = 0;
+ Unit->mFilesMax = 0;
+ loc_free(Unit->mFiles);
+ Unit->mFiles = NULL;
+
+ Unit->mDirsCnt = 0;
+ Unit->mDirsMax = 0;
+ loc_free(Unit->mDirs);
+ Unit->mDirs = NULL;
+
+ while (Unit->mStatesCnt > 0) {
+ loc_free(Unit->mStates[--Unit->mStatesCnt].mFileName);
+ }
+ loc_free(Unit->mStates);
+ loc_free(Unit->mStatesIndex);
+ Unit->mStates = NULL;
+ Unit->mStatesMax = 0;
+ Unit->mStatesIndex = NULL;
+}
+
+static void free_dwarf_cache(ELF_File * file) {
+ DWARFCache * Cache = (DWARFCache *)file->dwarf_dt_cache;
+ if (Cache != NULL) {
+ assert(Cache->magic == DWARF_CACHE_MAGIC);
+ Cache->magic = 0;
+ while (Cache->mCompUnits != NULL) {
+ CompUnit * Unit = Cache->mCompUnits->mCompUnit;
+ Cache->mCompUnits = Cache->mCompUnits->mSibling;
+ free_unit_cache(Unit);
+ loc_free(Unit);
+ }
+ while (Cache->mObjectList != NULL) {
+ ObjectArray * Buf = Cache->mObjectList;
+ Cache->mObjectList = Buf->mNext;
+ loc_free(Buf);
+ }
+ loc_free(Cache->mObjectHash);
+ loc_free(Cache->mAddrRanges);
+ loc_free(Cache->mFrameInfoRanges);
+ loc_free(Cache->mPubNames.mHash);
+ loc_free(Cache->mPubNames.mNext);
+ loc_free(Cache->mPubTypes.mHash);
+ loc_free(Cache->mPubTypes.mNext);
+ loc_free(Cache->mFileInfoHash);
+ loc_free(Cache);
+ file->dwarf_dt_cache = NULL;
+ }
+}
+
+DWARFCache * get_dwarf_cache(ELF_File * file) {
+ DWARFCache * Cache = (DWARFCache *)file->dwarf_dt_cache;
+ if (Cache == NULL) {
+ Trap trap;
+ if (!sCloseListenerOK) {
+ elf_add_close_listener(free_dwarf_cache);
+ sCloseListenerOK = 1;
+ }
+ sCache = Cache = (DWARFCache *)(file->dwarf_dt_cache = loc_alloc_zero(sizeof(DWARFCache)));
+ sCache->magic = DWARF_CACHE_MAGIC;
+ sCache->mFile = file;
+ sCache->mObjectArrayPos = OBJECT_ARRAY_SIZE;
+ if (set_trap(&trap)) {
+ dio_LoadAbbrevTable(file);
+ load_debug_sections();
+ load_addr_ranges();
+ clear_trap(&trap);
+ }
+ else {
+ sCache->mErrorReport = get_error_report(trap.error);
+ }
+ sCache = NULL;
+ }
+ if (Cache->mErrorReport) exception(set_error_report_errno(Cache->mErrorReport));
+ return Cache;
+}
+
+static void add_dir(CompUnit * Unit, char * Name) {
+ if (Unit->mDirsCnt >= Unit->mDirsMax) {
+ Unit->mDirsMax = Unit->mDirsMax == 0 ? 16 : Unit->mDirsMax * 2;
+ Unit->mDirs = (char **)loc_realloc(Unit->mDirs, sizeof(char *) * Unit->mDirsMax);
+ }
+ Unit->mDirs[Unit->mDirsCnt++] = Name;
+}
+
+static void add_file(CompUnit * Unit, FileInfo * file) {
+ file->mNameHash = calc_file_name_hash(file->mName);
+ if (Unit->mFilesCnt >= Unit->mFilesMax) {
+ Unit->mFilesMax = Unit->mFilesMax == 0 ? 16 : Unit->mFilesMax * 2;
+ Unit->mFiles = (FileInfo *)loc_realloc(Unit->mFiles, sizeof(FileInfo) * Unit->mFilesMax);
+ }
+ if (file->mDir == NULL) file->mDir = Unit->mDir;
+ Unit->mFiles[Unit->mFilesCnt++] = *file;
+}
+
+static void add_state(CompUnit * Unit, LineNumbersState * state) {
+ if (Unit->mStatesCnt >= Unit->mStatesMax) {
+ Unit->mStatesMax = Unit->mStatesMax == 0 ? 128 : Unit->mStatesMax * 2;
+ Unit->mStates = (LineNumbersState *)loc_realloc(Unit->mStates, sizeof(LineNumbersState) * Unit->mStatesMax);
+ }
+ Unit->mStates[Unit->mStatesCnt++] = *state;
+}
+
+static int state_address_comparator(const void * x1, const void * x2) {
+ LineNumbersState * s1 = (LineNumbersState *)x1;
+ LineNumbersState * s2 = (LineNumbersState *)x2;
+ if (s1->mAddress < s2->mAddress) return -1;
+ if (s1->mAddress > s2->mAddress) return +1;
+ return 0;
+}
+
+static int state_text_pos_comparator(const void * x1, const void * x2) {
+ LineNumbersState * s1 = *(LineNumbersState **)x1;
+ LineNumbersState * s2 = *(LineNumbersState **)x2;
+ if (s1->mFile < s2->mFile) return -1;
+ if (s1->mFile > s2->mFile) return +1;
+ if (s1->mLine < s2->mLine) return -1;
+ if (s1->mLine > s2->mLine) return +1;
+ if (s1->mColumn < s2->mColumn) return -1;
+ if (s1->mColumn > s2->mColumn) return +1;
+ if (s1->mAddress < s2->mAddress) return -1;
+ if (s1->mAddress > s2->mAddress) return +1;
+ return 0;
+}
+
+static void compute_reverse_lookup_indices(DWARFCache * Cache, CompUnit * Unit) {
+ U4_T i;
+ qsort(Unit->mStates, Unit->mStatesCnt, sizeof(LineNumbersState), state_address_comparator);
+ Unit->mStatesIndex = (LineNumbersState **)loc_alloc(sizeof(LineNumbersState *) * Unit->mStatesCnt);
+ for (i = 0; i < Unit->mStatesCnt; i++) Unit->mStatesIndex[i] = Unit->mStates + i;
+ qsort(Unit->mStatesIndex, Unit->mStatesCnt, sizeof(LineNumbersState *), state_text_pos_comparator);
+ for (i = 1; i < Unit->mStatesCnt; i++) {
+ LineNumbersState * s = Unit->mStatesIndex[i - 1];
+ LineNumbersState * n = Unit->mStatesIndex[i];
+ s->mNext = n - Unit->mStates;
+ }
+ if (Cache->mFileInfoHash == NULL) {
+ Cache->mFileInfoHashSize = 251;
+ Cache->mFileInfoHash = (FileInfo **)loc_alloc_zero(sizeof(FileInfo *) * Cache->mFileInfoHashSize);
+ }
+ for (i = 0; i < Unit->mFilesCnt; i++) {
+ FileInfo * File = Unit->mFiles + i;
+ unsigned h = File->mNameHash % Cache->mFileInfoHashSize;
+ File->mCompUnit = Unit;
+ File->mNextInHash = Cache->mFileInfoHash[h];
+ Cache->mFileInfoHash[h] = File;
+ }
+}
+
+static void load_line_numbers_v1(CompUnit * Unit, U4_T unit_size) {
+ LineNumbersState state;
+ ELF_Section * s = NULL;
+ ContextAddress addr = 0;
+ U4_T line = 0;
+
+ memset(&state, 0, sizeof(state));
+ addr = (ContextAddress)dio_ReadAddress(&s);
+ while (dio_GetPos() < Unit->mLineInfoOffs + unit_size) {
+ state.mLine = dio_ReadU4();
+ state.mColumn = dio_ReadU2();
+ if (state.mColumn == 0xffffu) state.mColumn = 0;
+ state.mAddress = addr + dio_ReadU4();
+ if (state.mLine == 0) {
+ state.mLine = line + 1;
+ state.mColumn = 0;
+ }
+ add_state(Unit, &state);
+ line = state.mLine;
+ }
+}
+
+static void load_line_numbers_v2(CompUnit * Unit, U8_T unit_size, int dwarf64) {
+ U8_T header_pos = 0;
+ U1_T opcode_base = 0;
+ U1_T opcode_size[256];
+ U8_T header_size = 0;
+ U1_T min_instruction_length = 0;
+ U1_T is_stmt_default = 0;
+ I1_T line_base = 0;
+ U1_T line_range = 0;
+ LineNumbersState state;
+
+ dio_ReadU2(); /* line info version */
+ header_size = dwarf64 ? dio_ReadU8() : (U8_T)dio_ReadU4();
+ header_pos = dio_GetPos();
+ min_instruction_length = dio_ReadU1();
+ is_stmt_default = dio_ReadU1() != 0;
+ line_base = (I1_T)dio_ReadU1();
+ line_range = dio_ReadU1();
+ opcode_base = dio_ReadU1();
+ memset(opcode_size, 0, sizeof(opcode_size));
+ dio_Read(opcode_size + 1, opcode_base - 1);
+
+ /* Read directory names */
+ for (;;) {
+ char * Name = dio_ReadString();
+ if (Name == NULL) break;
+ add_dir(Unit, Name);
+ }
+
+ /* Read source files info */
+ for (;;) {
+ U4_T dir = 0;
+ FileInfo file;
+ memset(&file, 0, sizeof(file));
+ file.mName = dio_ReadString();
+ if (file.mName == NULL) break;
+ dir = dio_ReadULEB128();
+ if (dir > 0 && dir <= Unit->mDirsCnt) file.mDir = Unit->mDirs[dir - 1];
+ file.mModTime = dio_ReadULEB128();
+ file.mSize = dio_ReadULEB128();
+ add_file(Unit, &file);
+ }
+
+ /* Run the program */
+ if (header_pos + header_size != dio_GetPos())
+ str_exception(ERR_INV_DWARF, "Invalid line info header");
+ memset(&state, 0, sizeof(state));
+ state.mFile = 1;
+ state.mLine = 1;
+ if (is_stmt_default) state.mFlags |= LINE_IsStmt;
+ while (dio_GetPos() < Unit->mLineInfoOffs + unit_size) {
+ U1_T opcode = dio_ReadU1();
+ if (opcode >= opcode_base) {
+ state.mLine += (unsigned)((int)((opcode - opcode_base) % line_range) + line_base);
+ state.mAddress += (opcode - opcode_base) / line_range * min_instruction_length;
+ add_state(Unit, &state);
+ state.mFlags &= ~(LINE_BasicBlock | LINE_PrologueEnd | LINE_EpilogueBegin);
+ }
+ else if (opcode == 0) {
+ U4_T op_size = dio_ReadULEB128();
+ U8_T op_pos = dio_GetPos();
+ switch (dio_ReadU1()) {
+ case DW_LNE_define_file: {
+ U4_T dir = 0;
+ FileInfo file;
+ memset(&file, 0, sizeof(file));
+ file.mName = dio_ReadString();
+ dir = dio_ReadULEB128();
+ if (dir > 0 && dir <= Unit->mDirsCnt) file.mDir = Unit->mDirs[dir - 1];
+ file.mModTime = dio_ReadULEB128();
+ file.mSize = dio_ReadULEB128();
+ add_file(Unit, &file);
+ break;
+ }
+ case DW_LNE_end_sequence:
+ state.mFlags |= LINE_EndSequence;
+ add_state(Unit, &state);
+ memset(&state, 0, sizeof(state));
+ state.mFile = 1;
+ state.mLine = 1;
+ if (is_stmt_default) state.mFlags |= LINE_IsStmt;
+ else state.mFlags &= ~LINE_IsStmt;
+ break;
+ case DW_LNE_set_address:
+ {
+ ELF_Section * s = NULL;
+ state.mAddress = (ContextAddress)dio_ReadAddress(&s);
+ if (s != Unit->mTextSection) state.mAddress = 0;
+ }
+ break;
+ default:
+ dio_Skip(op_size - 1);
+ break;
+ }
+ if (dio_GetPos() != op_pos + op_size)
+ str_exception(ERR_INV_DWARF, "Invalid line info op size");
+ }
+ else {
+ switch (opcode) {
+ case DW_LNS_copy:
+ add_state(Unit, &state);
+ state.mFlags &= ~(LINE_BasicBlock | LINE_PrologueEnd | LINE_EpilogueBegin);
+ break;
+ case DW_LNS_advance_pc:
+ state.mAddress += (ContextAddress)(dio_ReadU8LEB128() * min_instruction_length);
+ break;
+ case DW_LNS_advance_line:
+ state.mLine += dio_ReadSLEB128();
+ break;
+ case DW_LNS_set_file:
+ state.mFile = dio_ReadULEB128();
+ break;
+ case DW_LNS_set_column:
+ state.mColumn = (U2_T)dio_ReadULEB128();
+ break;
+ case DW_LNS_negate_stmt:
+ state.mFlags ^= LINE_IsStmt;
+ break;
+ case DW_LNS_set_basic_block:
+ state.mFlags |= LINE_BasicBlock;
+ break;
+ case DW_LNS_const_add_pc:
+ state.mAddress += (255 - opcode_base) / line_range * min_instruction_length;
+ break;
+ case DW_LNS_fixed_advance_pc:
+ state.mAddress += dio_ReadU2();
+ break;
+ case DW_LNS_set_prologue_end:
+ state.mFlags |= LINE_PrologueEnd;
+ break;
+ case DW_LNS_set_epilogue_begin:
+ state.mFlags |= LINE_EpilogueBegin;
+ break;
+ case DW_LNS_set_isa:
+ state.mISA = (U1_T)dio_ReadULEB128();
+ break;
+ default:
+ str_exception(ERR_INV_DWARF, "Invalid line info op code");
+ break;
+ }
+ }
+ }
+}
+
+void load_line_numbers(CompUnit * Unit) {
+ Trap trap;
+ DWARFCache * Cache = (DWARFCache *)Unit->mFile->dwarf_dt_cache;
+ ELF_Section * LineInfoSection = Unit->mDesc.mVersion <= 1 ? Cache->mDebugLineV1 : Cache->mDebugLine;
+ if (LineInfoSection == NULL) return;
+ if (Unit->mLineInfoLoaded) return;
+ if (elf_load(LineInfoSection)) exception(errno);
+ dio_EnterSection(&Unit->mDesc, LineInfoSection, Unit->mLineInfoOffs);
+ if (set_trap(&trap)) {
+ U8_T unit_size = 0;
+ FileInfo file;
+ memset(&file, 0, sizeof(file));
+ file.mDir = Unit->mDir;
+ file.mName = Unit->mObject->mName;
+ add_file(Unit, &file);
+ /* Read header */
+ unit_size = dio_ReadU4();
+ if (Unit->mDesc.mVersion <= 1) {
+ /* DWARF 1.1 */
+ load_line_numbers_v1(Unit, (U4_T)unit_size);
+ }
+ else {
+ /* DWARF 2+ */
+ int dwarf64 = 0;
+ if (unit_size == 0xffffffffu) {
+ unit_size = dio_ReadU8();
+ unit_size += 12;
+ dwarf64 = 1;
+ }
+ else {
+ unit_size += 4;
+ }
+ load_line_numbers_v2(Unit, unit_size, dwarf64);
+ }
+ dio_ExitSection();
+ compute_reverse_lookup_indices(Cache, Unit);
+ Unit->mLineInfoLoaded = 1;
+ clear_trap(&trap);
+ }
+ else {
+ dio_ExitSection();
+ free_unit_cache(Unit);
+ exception(trap.error);
+ }
+}
+
+UnitAddressRange * find_comp_unit_addr_range(DWARFCache * cache, ContextAddress addr_min, ContextAddress addr_max) {
+ unsigned l = 0;
+ unsigned h = cache->mAddrRangesCnt;
+ while (l < h) {
+ unsigned k = (h + l) / 2;
+ UnitAddressRange * rk = cache->mAddrRanges + k;
+ if (rk->mAddr <= addr_max && rk->mAddr + rk->mSize > addr_min) {
+ int first = 1;
+ if (k > 0) {
+ UnitAddressRange * rp = rk - 1;
+ first = rp->mAddr + rp->mSize <= addr_min;
+ }
+ if (first) return rk;
+ }
+ if (rk->mAddr >= addr_min) h = k;
+ else l = k + 1;
+ }
+ return NULL;
+}
+
+#endif /* ENABLE_ELF && ENABLE_DebugContext */

Back to the top