summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Budovski <alexbud@meta.com>2023-03-23 00:19:13 (GMT)
committerAlex Budovski <alexbud@meta.com>2023-03-24 15:25:37 (GMT)
commitd48181528456501562f4b7551878eefe19381cbe (patch)
tree1d4d2bc867d1317f58703e989ebff184007c5f02
parent6fd46e795333430d28657fbeba72b4a0232a28ce (diff)
downloadcv2pdb-d48181528456501562f4b7551878eefe19381cbe.zip
cv2pdb-d48181528456501562f4b7551878eefe19381cbe.tar.gz
cv2pdb-d48181528456501562f4b7551878eefe19381cbe.tar.bz2
Fix bug in DWARF v4 location decoding
This fixes a long standing bug in the DWARF v4 location decoding logic. Previously, the logic would not recognize "base address selection" entries at all and assume an entry was either an end-of-list or a location list entry thus resulting in incorrect decoding in release builds, and an assert in debug builds. See DWARF v4 spec section 2.6.2 for details.
-rw-r--r--src/readDwarf.cpp27
-rw-r--r--src/readDwarf.h20
2 files changed, 43 insertions, 4 deletions
diff --git a/src/readDwarf.cpp b/src/readDwarf.cpp
index 8e4ca4d..6562980 100644
--- a/src/readDwarf.cpp
+++ b/src/readDwarf.cpp
@@ -414,9 +414,12 @@ void mergeSpecification(DWARF_InfoData& id, const CV2PDB& context)
LOCCursor::LOCCursor(const DIECursor& parent, unsigned long off)
: parent(parent)
{
+ // Default the base address to the compilation unit (DWARF v4 2.6.2)
base = parent.cu->base_address;
isLocLists = (parent.cu->version >= 5);
+ // DWARF v4 uses .debug_loc, DWARF v5 uses .debug_loclists with a different
+ // schema.
const PESection& sec = isLocLists ? parent.img->debug_loclists : parent.img->debug_loc;
ptr = sec.byteAt(off);
end = sec.endByte();
@@ -426,6 +429,8 @@ bool LOCCursor::readNext(LOCEntry& entry)
{
if (isLocLists)
{
+ // DWARF v5 location list parsing.
+
if (parent.debug & DbgDwarfLocLists)
fprintf(stderr, "%s:%d: loclists off=%x DIEoff=%x:\n", __FUNCTION__, __LINE__,
parent.img->debug_loclists.sectOff(ptr), parent.entryOff);
@@ -488,6 +493,8 @@ bool LOCCursor::readNext(LOCEntry& entry)
}
else
{
+ // The logic here is goverened by DWARF4 section 2.6.2.
+
if (ptr >= end)
return false;
@@ -495,10 +502,28 @@ bool LOCCursor::readNext(LOCEntry& entry)
fprintf(stderr, "%s:%d: loclist off=%x DIEoff=%x:\n", __FUNCTION__, __LINE__,
parent.img->debug_loc.sectOff(ptr), parent.entryOff);
+ // Extract the begin and end offset
+ // TODO: Why is this truncating to 32 bit?
entry.beg_offset = (unsigned long) parent.RDAddr(ptr);
entry.end_offset = (unsigned long) parent.RDAddr(ptr);
- if (!entry.beg_offset && !entry.end_offset)
+
+ // Check for a base-address-selection entry.
+ if (entry.beg_offset == -1U) {
+ // This is a base address selection entry and thus has no location
+ // description.
+ // Update the base address with this entry's value.
+ base = entry.end_offset;
+
+ // Continue the scan, but don't try to decode further since there
+ // are no location description records following this type of entry.
+ return true;
+ }
+
+ // Check for end-of-list entry. (Both offsets 0)
+ if (!entry.beg_offset && !entry.end_offset) {
+ // Terminate the scan.
return false;
+ }
DWARF_Attribute attr;
attr.type = Block;
diff --git a/src/readDwarf.h b/src/readDwarf.h
index 04afa38..4b0ac98 100644
--- a/src/readDwarf.h
+++ b/src/readDwarf.h
@@ -470,9 +470,15 @@ struct Location
class LOCEntry
{
public:
- unsigned long beg_offset;
- unsigned long end_offset;
+ // TODO: investigate making these 64bit (or vary). Also consider renaming
+ // to Value0 and Value1 since their meanings varies depending on entry type.
+ unsigned long beg_offset; // or -1U for base address selection entries
+ unsigned long end_offset; // or the base address in base address selection entries
+
+ // DWARF v5 only. See DW_LLE_default_location.
bool isDefault;
+
+ // Location description.
Location loc;
void addBase(uint32_t base)
@@ -482,16 +488,24 @@ public:
}
};
-// Location list cursor
+// Location list cursor (see DWARF v4 and v5 Section 2.6).
class LOCCursor
{
public:
LOCCursor(const DIECursor& parent, unsigned long off);
const DIECursor& parent;
+
+ // The base address for subsequent loc list entries read in a given list.
+ // Default to the CU base in the absense of any base address selection entries.
+ //
+ // TODO: So far we only assign to this but never actually use it.
uint32_t base;
+
byte* end;
byte* ptr;
+
+ // Is this image using the new debug_loclists section in DWARF v5?
bool isLocLists;
bool readNext(LOCEntry& entry);