symbolizer::findDefinitionDie returns incorrect DW_AT_specification offset for DW_FORM_ref_addr
symbolizer::findDefinitionDie unconditionally adds cu.offset to the offset returned by getAttribute<uint64_t>(cu, die, DW_AT_specification). in my gcc14-compiled binaries, that is usually correct since the DW_AT_specification is specified as DW_FORM_sdata, but sometimes it is represented as DW_FORM_ref_addr, in which case it is an absolute offset form the beginning of the .debug_info section (this is according to https://github.com/eliben/pyelftools/issues/241#issuecomment-565637775 ). this issue caused a an out-of-bounds FOLLY_SAFE_CHECK(sp.size() >= sizeof(T), "underflow"); in read.
a small patch to readAttribute fixes my use case, but i'm not sure it's completely proper, especially since it causes the Attribute's uint64_t attrValue to be negative:
case DW_FORM_ref_addr:
- return {spec, die, readOffset(info, die.is64Bit)};
+ {
+ uint64_t rawval = readOffset(info, die.is64Bit);
+ if(spec.name == DW_AT_specification) {
+ // A DW_AT_specification attribute is of class reference, and a
+ // reference is relative to the first byte of the cu header unless its
+ // of form DW_AT_refaddr, where its relative to the .debug_info section.
+ rawval -= cu.offset;
+ }
+ return {spec, die, rawval};
+ }