mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-24 18:20:38 +00:00
DebugInfo: Add a DWARF FORM extension for addrx+offset references to reduce relocations
This is an alternative to the use of complex DWARF expressions for addresses - shaving off a few extra bytes of expression overhead.
This commit is contained in:
parent
d6be277347
commit
4318028cd2
@ -494,6 +494,8 @@ HANDLE_DW_FORM(0x1f02, GNU_str_index, 0, GNU)
|
||||
// Alternate debug sections proposal (output of "dwz" tool).
|
||||
HANDLE_DW_FORM(0x1f20, GNU_ref_alt, 0, GNU)
|
||||
HANDLE_DW_FORM(0x1f21, GNU_strp_alt, 0, GNU)
|
||||
// LLVM addr+offset extension
|
||||
HANDLE_DW_FORM(0x2001, LLVM_addrx_offset, 0, LLVM)
|
||||
|
||||
// DWARF Expression operators.
|
||||
HANDLE_DW_OP(0x03, addr, 2, DWARF)
|
||||
|
@ -345,6 +345,22 @@ public:
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A BaseTypeRef DIE.
|
||||
class DIEAddrOffset {
|
||||
DIEInteger Addr;
|
||||
DIEDelta Offset;
|
||||
|
||||
public:
|
||||
explicit DIEAddrOffset(uint64_t Idx, const MCSymbol *Hi, const MCSymbol *Lo)
|
||||
: Addr(Idx), Offset(Hi, Lo) {}
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A debug information entry value. Some of these roughly correlate
|
||||
/// to DWARF attribute classes.
|
||||
@ -368,9 +384,10 @@ private:
|
||||
///
|
||||
/// All values that aren't standard layout (or are larger than 8 bytes)
|
||||
/// should be stored by reference instead of by value.
|
||||
using ValTy = AlignedCharArrayUnion<DIEInteger, DIEString, DIEExpr, DIELabel,
|
||||
DIEDelta *, DIEEntry, DIEBlock *,
|
||||
DIELoc *, DIELocList, DIEBaseTypeRef *>;
|
||||
using ValTy =
|
||||
AlignedCharArrayUnion<DIEInteger, DIEString, DIEExpr, DIELabel,
|
||||
DIEDelta *, DIEEntry, DIEBlock *, DIELoc *,
|
||||
DIELocList, DIEBaseTypeRef *, DIEAddrOffset *>;
|
||||
|
||||
static_assert(sizeof(ValTy) <= sizeof(uint64_t) ||
|
||||
sizeof(ValTy) <= sizeof(void *),
|
||||
|
@ -41,6 +41,7 @@ HANDLE_DIEVALUE_LARGE(Block)
|
||||
HANDLE_DIEVALUE_LARGE(Loc)
|
||||
HANDLE_DIEVALUE_SMALL(LocList)
|
||||
HANDLE_DIEVALUE_LARGE(InlineString)
|
||||
HANDLE_DIEVALUE_LARGE(AddrOffset)
|
||||
|
||||
#undef HANDLE_DIEVALUE
|
||||
#undef HANDLE_DIEVALUE_SMALL
|
||||
|
@ -855,3 +855,27 @@ void DIELocList::emitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
void DIELocList::print(raw_ostream &O) const { O << "LocList: " << Index; }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIEAddrOffset Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
unsigned DIEAddrOffset::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
return Addr.SizeOf(AP, dwarf::DW_FORM_addrx) +
|
||||
Offset.SizeOf(AP, dwarf::DW_FORM_data4);
|
||||
}
|
||||
|
||||
/// EmitValue - Emit label value.
|
||||
///
|
||||
void DIEAddrOffset::emitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
Addr.emitValue(AP, dwarf::DW_FORM_addrx);
|
||||
Offset.emitValue(AP, dwarf::DW_FORM_data4);
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
void DIEAddrOffset::print(raw_ostream &O) const {
|
||||
O << "AddrOffset: ";
|
||||
Addr.print(O);
|
||||
O << " + ";
|
||||
Offset.print(O);
|
||||
}
|
||||
|
@ -319,6 +319,7 @@ void DIEHash::hashAttribute(const DIEValue &Value, dwarf::Tag Tag) {
|
||||
case DIEValue::isLabel:
|
||||
case DIEValue::isBaseTypeRef:
|
||||
case DIEValue::isDelta:
|
||||
case DIEValue::isAddrOffset:
|
||||
llvm_unreachable("Add support for additional value types.");
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
@ -73,16 +74,20 @@ void DwarfCompileUnit::addLabelAddress(DIE &Die, dwarf::Attribute Attribute,
|
||||
if (Label)
|
||||
DD->addArangeLabel(SymbolCU(this, Label));
|
||||
|
||||
if (Label->isInSection() || !DD->useAddrOffsetExpressions()) {
|
||||
const MCSymbol *Base = DD->getSectionLabel(&Label->getSection());
|
||||
if (Base == Label || !DD->useAddrOffsetExpressions()) {
|
||||
unsigned idx = DD->getAddressPool().getIndex(Label);
|
||||
Die.addValue(DIEValueAllocator, Attribute,
|
||||
DD->getDwarfVersion() >= 5 ? dwarf::DW_FORM_addrx
|
||||
: dwarf::DW_FORM_GNU_addr_index,
|
||||
DIEInteger(idx));
|
||||
return;
|
||||
}
|
||||
bool UseAddrOffsetFormOrExpressions =
|
||||
DD->useAddrOffsetForm() || DD->useAddrOffsetExpressions();
|
||||
|
||||
const MCSymbol *Base = nullptr;
|
||||
if (Label->isInSection() && UseAddrOffsetFormOrExpressions)
|
||||
Base = DD->getSectionLabel(&Label->getSection());
|
||||
|
||||
if (!Base || Base == Label) {
|
||||
unsigned idx = DD->getAddressPool().getIndex(Label);
|
||||
Die.addValue(DIEValueAllocator, Attribute,
|
||||
DD->getDwarfVersion() >= 5 ? dwarf::DW_FORM_addrx
|
||||
: dwarf::DW_FORM_GNU_addr_index,
|
||||
DIEInteger(idx));
|
||||
return;
|
||||
}
|
||||
|
||||
// Could be extended to work with DWARFv4 Split DWARF if that's important for
|
||||
@ -90,9 +95,14 @@ void DwarfCompileUnit::addLabelAddress(DIE &Die, dwarf::Attribute Attribute,
|
||||
assert(DD->getDwarfVersion() >= 5 &&
|
||||
"Addr+offset expressions are only valuable when using debug_addr (to "
|
||||
"reduce relocations) available in DWARFv5 or higher");
|
||||
auto *Loc = new (DIEValueAllocator) DIEBlock();
|
||||
addPoolOpAddress(*Loc, Label);
|
||||
addBlock(Die, Attribute, dwarf::DW_FORM_exprloc, Loc);
|
||||
if (DD->useAddrOffsetExpressions()) {
|
||||
auto *Loc = new (DIEValueAllocator) DIEBlock();
|
||||
addPoolOpAddress(*Loc, Label);
|
||||
addBlock(Die, Attribute, dwarf::DW_FORM_exprloc, Loc);
|
||||
} else
|
||||
Die.addValue(
|
||||
DIEValueAllocator, Attribute, dwarf::DW_FORM_LLVM_addrx_offset,
|
||||
new DIEAddrOffset(DD->getAddressPool().getIndex(Base), Label, Base));
|
||||
}
|
||||
|
||||
void DwarfCompileUnit::addLocalLabelAddress(DIE &Die,
|
||||
|
@ -164,6 +164,9 @@ static cl::opt<DwarfDebug::MinimizeAddrInV5> MinimizeAddrInV5Option(
|
||||
"Expressions",
|
||||
"Use exprloc addrx+offset expressions for any "
|
||||
"address with a prior base address"),
|
||||
clEnumValN(DwarfDebug::MinimizeAddrInV5::Form, "Form",
|
||||
"Use addrx+offset extension form for any address "
|
||||
"with a prior base address"),
|
||||
clEnumValN(DwarfDebug::MinimizeAddrInV5::Disabled, "Disabled",
|
||||
"Stuff")),
|
||||
cl::init(DwarfDebug::MinimizeAddrInV5::Default));
|
||||
|
@ -384,6 +384,7 @@ public:
|
||||
Disabled,
|
||||
Ranges,
|
||||
Expressions,
|
||||
Form,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -713,6 +714,12 @@ public:
|
||||
return MinimizeAddr == MinimizeAddrInV5::Expressions;
|
||||
}
|
||||
|
||||
// Returns whether addrx+offset LLVM extension form should be used to reduce
|
||||
// debug_addr size.
|
||||
bool useAddrOffsetForm() const {
|
||||
return MinimizeAddr == MinimizeAddrInV5::Form;
|
||||
}
|
||||
|
||||
/// Returns whether to use sections as labels rather than temp symbols.
|
||||
bool useSectionsAsReferences() const {
|
||||
return UseSectionsAsReferences;
|
||||
|
@ -316,8 +316,11 @@ unsigned DwarfTypeUnit::getOrCreateSourceID(const DIFile *File) {
|
||||
}
|
||||
|
||||
void DwarfUnit::addPoolOpAddress(DIEValueList &Die, const MCSymbol *Label) {
|
||||
bool UseAddrOffsetFormOrExpressions =
|
||||
DD->useAddrOffsetForm() || DD->useAddrOffsetExpressions();
|
||||
|
||||
const MCSymbol *Base = nullptr;
|
||||
if (Label->isInSection() && DD->useAddrOffsetExpressions())
|
||||
if (Label->isInSection() && UseAddrOffsetFormOrExpressions)
|
||||
Base = DD->getSectionLabel(&Label->getSection());
|
||||
|
||||
uint32_t Index = DD->getAddressPool().getIndex(Base ? Base : Label);
|
||||
|
@ -74,7 +74,7 @@ static const DWARFFormValue::FormClass DWARF5FormClasses[] = {
|
||||
DWARFFormValue::FC_Address, // 0x2a DW_FORM_addrx2
|
||||
DWARFFormValue::FC_Address, // 0x2b DW_FORM_addrx3
|
||||
DWARFFormValue::FC_Address, // 0x2c DW_FORM_addrx4
|
||||
|
||||
DWARFFormValue::FC_Address, // 0x2001 DW_FORM_addrx_offset
|
||||
};
|
||||
|
||||
DWARFFormValue DWARFFormValue::createFromSValue(dwarf::Form F, int64_t V) {
|
||||
@ -191,6 +191,11 @@ bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
|
||||
DebugInfoData.getULEB128(OffsetPtr);
|
||||
return true;
|
||||
|
||||
case DW_FORM_LLVM_addrx_offset:
|
||||
DebugInfoData.getULEB128(OffsetPtr);
|
||||
*OffsetPtr += 4;
|
||||
return true;
|
||||
|
||||
case DW_FORM_indirect:
|
||||
Indirect = true;
|
||||
Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr));
|
||||
@ -217,6 +222,8 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
|
||||
case DW_FORM_GNU_str_index:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
return (FC == FC_String);
|
||||
case DW_FORM_LLVM_addrx_offset:
|
||||
return (FC == FC_Address);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -322,6 +329,10 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
|
||||
case DW_FORM_strx:
|
||||
Value.uval = Data.getULEB128(OffsetPtr, &Err);
|
||||
break;
|
||||
case DW_FORM_LLVM_addrx_offset:
|
||||
Value.uval = Data.getULEB128(OffsetPtr, &Err) << 32;
|
||||
Value.uval = Data.getU32(OffsetPtr, &Err);
|
||||
break;
|
||||
case DW_FORM_string:
|
||||
Value.cstr = Data.getCStr(OffsetPtr, &Err);
|
||||
break;
|
||||
@ -417,6 +428,23 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
|
||||
OS << "<unresolved>";
|
||||
break;
|
||||
}
|
||||
case DW_FORM_LLVM_addrx_offset: {
|
||||
if (U == nullptr) {
|
||||
OS << "<invalid dwarf unit>";
|
||||
break;
|
||||
}
|
||||
uint32_t Index = UValue >> 32;
|
||||
uint32_t Offset = UValue & 0xffffffff;
|
||||
Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(Index);
|
||||
if (!A || DumpOpts.Verbose)
|
||||
AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset);
|
||||
if (A) {
|
||||
A->Address += Offset;
|
||||
dumpSectionedAddress(AddrOS, DumpOpts, *A);
|
||||
} else
|
||||
OS << "<unresolved>";
|
||||
break;
|
||||
}
|
||||
case DW_FORM_flag_present:
|
||||
OS << "true";
|
||||
break;
|
||||
@ -636,13 +664,17 @@ Optional<object::SectionedAddress>
|
||||
DWARFFormValue::getAsSectionedAddress() const {
|
||||
if (!isFormClass(FC_Address))
|
||||
return None;
|
||||
if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx) {
|
||||
uint32_t Index = Value.uval;
|
||||
bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset;
|
||||
if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || AddrOffset) {
|
||||
|
||||
uint32_t Index = AddrOffset ? (Value.uval >> 32) : Value.uval;
|
||||
if (!U)
|
||||
return None;
|
||||
Optional<object::SectionedAddress> SA = U->getAddrOffsetSectionItem(Index);
|
||||
if (!SA)
|
||||
return None;
|
||||
if (AddrOffset)
|
||||
SA->Address += (Value.uval & 0xffffffff);
|
||||
return SA;
|
||||
}
|
||||
return {{Value.uval, Value.SectionIndex}};
|
||||
|
@ -3,12 +3,17 @@
|
||||
; RUN: | FileCheck --check-prefix=CHECK --check-prefix=RNG \
|
||||
; RUN: --implicit-check-not=DW_TAG --implicit-check-not=NULL --implicit-check-not=_pc %s
|
||||
|
||||
|
||||
; RUN: llc -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o - -minimize-addr-in-v5=Expressions \
|
||||
; RUN: | llvm-dwarfdump -debug-info -debug-addr -debug-rnglists -v - \
|
||||
; RUN: | FileCheck --check-prefix=CHECK --check-prefix=EXPR \
|
||||
; RUN: | FileCheck --check-prefix=CHECK --check-prefix=EXPRORFORM --check-prefix=EXPR\
|
||||
; RUN: --implicit-check-not=DW_TAG --implicit-check-not=NULL --implicit-check-not=_pc %s
|
||||
|
||||
; RUN: llc -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o - -minimize-addr-in-v5=Form \
|
||||
; RUN: | llvm-dwarfdump -debug-info -debug-addr -debug-rnglists -v - \
|
||||
; RUN: | FileCheck --check-prefix=CHECK --check-prefix=EXPRORFORM --check-prefix=FORM \
|
||||
; RUN: --implicit-check-not=DW_TAG --implicit-check-not=NULL --implicit-check-not=_pc %s
|
||||
|
||||
|
||||
; Generated from the following source. f4 is used to put a hole in the CU
|
||||
; ranges while keeping f2 and f4 in the same section (as opposed to
|
||||
; -ffunction-sections, which would produce CU ranges, but each function would
|
||||
@ -44,7 +49,7 @@
|
||||
; CHECK: DW_TAG_compile_unit
|
||||
; CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
|
||||
; RNG: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x2) rangelist = [[CU_RANGE:.*]]
|
||||
; EXPR: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = [[CU_RANGE:.*]]
|
||||
; EXPRORFORM: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = [[CU_RANGE:.*]]
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; CHECK: DW_AT_name {{.*}} "f2"
|
||||
; CHECK: DW_TAG_subprogram
|
||||
@ -52,25 +57,29 @@
|
||||
; CHECK: DW_AT_high_pc [DW_FORM_data4] (0x00000010)
|
||||
; CHECK: DW_TAG_inlined_subroutine
|
||||
; EXPR: DW_AT_low_pc [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0x9, DW_OP_plus)
|
||||
; EXPR: DW_AT_high_pc [DW_FORM_data4] (0x00000005)
|
||||
; FORM: DW_AT_low_pc [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0x9 address = 0x0000000000000009 ".text")
|
||||
; EXPRORFORM: DW_AT_high_pc [DW_FORM_data4] (0x00000005)
|
||||
; RNG: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = [[INL_RANGE:.*]]
|
||||
; CHECK: DW_TAG_call_site
|
||||
; RNG: DW_AT_call_return_pc [DW_FORM_addrx] (indexed (00000001) address = 0x0000000000000009 ".text")
|
||||
; EXPR: DW_AT_call_return_pc [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0x9, DW_OP_plus)
|
||||
; FORM: DW_AT_call_return_pc [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0x9 address = 0x0000000000000009 ".text")
|
||||
; CHECK: DW_TAG_call_site
|
||||
; RNG: DW_AT_call_return_pc [DW_FORM_addrx] (indexed (00000002) address = 0x000000000000000e ".text")
|
||||
; EXPR: DW_AT_call_return_pc [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0xe, DW_OP_plus)
|
||||
; FORM: DW_AT_call_return_pc [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0xe address = 0x000000000000000e ".text")
|
||||
; CHECK: NULL
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; CHECK: DW_AT_name {{.*}} "f1"
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; EXPR: DW_AT_low_pc [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0x20, DW_OP_plus)
|
||||
; EXPR: DW_AT_high_pc [DW_FORM_data4] (0x00000006)
|
||||
; FORM: DW_AT_low_pc [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0x20 address = 0x0000000000000020 ".text")
|
||||
; EXPRORFORM: DW_AT_high_pc [DW_FORM_data4] (0x00000006)
|
||||
; RNG: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = [[F5_RANGE:.*]]
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (
|
||||
; RNG-SAME: 00000003
|
||||
; EXPR-SAME: 00000001
|
||||
; EXPRORFORM-SAME: 00000001
|
||||
; CHECK: ) address = 0x0000000000000000 ".other")
|
||||
; CHECK: DW_AT_high_pc [DW_FORM_data4] (0x00000006)
|
||||
; CHECK: NULL
|
||||
@ -86,7 +95,7 @@
|
||||
|
||||
; CHECK-LABEL: .debug_rnglists contents:
|
||||
; RNG: 0x00000000: range list header: {{.*}}, offset_entry_count = 0x00000003
|
||||
; EXPR: 0x00000000: range list header: {{.*}}, offset_entry_count = 0x00000001
|
||||
; EXPRORFORM: 0x00000000: range list header: {{.*}}, offset_entry_count = 0x00000001
|
||||
; CHECK: ranges:
|
||||
; RNG-NEXT: [[INL_RANGE]]: [DW_RLE_base_addressx]: 0x0000000000000000
|
||||
; RNG-NEXT: [DW_RLE_offset_pair ]
|
||||
@ -100,7 +109,7 @@
|
||||
; CHECK-NEXT: [DW_RLE_offset_pair ]
|
||||
; CHECK-NEXT: [DW_RLE_offset_pair ]
|
||||
; RNG-NEXT: [DW_RLE_startx_length]: 0x0000000000000003
|
||||
; EXPR-NEXT: [DW_RLE_startx_length]: 0x0000000000000001
|
||||
; EXPRORFORM-NEXT: [DW_RLE_startx_length]: 0x0000000000000001
|
||||
; CHECK-NEXT: [DW_RLE_end_of_list ]
|
||||
|
||||
; Function Attrs: noinline optnone uwtable mustprogress
|
||||
|
Loading…
x
Reference in New Issue
Block a user