diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h index 4bbff49606abc..28929306ca925 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h @@ -12,6 +12,8 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/Optional.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/DataExtractor.h" namespace llvm { @@ -88,7 +90,8 @@ class DWARFExpression { uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; } uint64_t getOperandEndOffset(unsigned Idx) { return OperandEndOffsets[Idx]; } uint64_t getEndOffset() { return EndOffset; } - bool extract(DataExtractor Data, uint8_t AddressSize, uint64_t Offset); + bool extract(DataExtractor Data, uint8_t AddressSize, uint64_t Offset, + Optional Format); bool isError() { return Error; } bool print(raw_ostream &OS, const DWARFExpression *Expr, const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH); @@ -107,7 +110,7 @@ class DWARFExpression { : Expr(Expr), Offset(Offset) { Op.Error = Offset >= Expr->Data.getData().size() || - !Op.extract(Expr->Data, Expr->AddressSize, Offset); + !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); } public: @@ -115,7 +118,7 @@ class DWARFExpression { Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset; Op.Error = Offset >= Expr->Data.getData().size() || - !Op.extract(Expr->Data, Expr->AddressSize, Offset); + !Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format); return Op; } @@ -127,8 +130,9 @@ class DWARFExpression { friend bool operator==(const iterator &, const iterator &); }; - DWARFExpression(DataExtractor Data, uint8_t AddressSize) - : Data(Data), AddressSize(AddressSize) { + DWARFExpression(DataExtractor Data, uint8_t AddressSize, + Optional Format = None) + : Data(Data), AddressSize(AddressSize), Format(Format) { assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2); } @@ -143,6 +147,7 @@ class DWARFExpression { private: DataExtractor Data; uint8_t AddressSize; + Optional Format; }; inline bool operator==(const DWARFExpression::iterator &LHS, diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index cf1e269e80adf..25b973ec836c3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2337,7 +2337,7 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, DWARFDataExtractor Data(StringRef(DebugLocs.getBytes(Entry).data(), DebugLocs.getBytes(Entry).size()), Asm->getDataLayout().isLittleEndian(), PtrSize); - DWARFExpression Expr(Data, PtrSize); + DWARFExpression Expr(Data, PtrSize, Asm->OutContext.getDwarfFormat()); using Encoding = DWARFExpression::Operation::Encoding; uint64_t Offset = 0; diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp index 1d7ef350f63da..fff3763aea414 100644 --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -1008,7 +1008,8 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute( DWARFUnit &OrigUnit = Unit.getOrigUnit(); DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()), IsLittleEndian, OrigUnit.getAddressByteSize()); - DWARFExpression Expr(Data, OrigUnit.getAddressByteSize()); + DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(), + OrigUnit.getFormParams().Format); cloneExpression(Data, Expr, File, Unit, Buffer); Bytes = Buffer; } @@ -2134,7 +2135,8 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits( DataExtractor Data(Bytes, IsLittleEndian, OrigUnit.getAddressByteSize()); cloneExpression(Data, - DWARFExpression(Data, OrigUnit.getAddressByteSize()), + DWARFExpression(Data, OrigUnit.getAddressByteSize(), + OrigUnit.getFormParams().Format), File, *CurrentUnit, Buffer); }; Emitter->emitLocationsForUnit(*CurrentUnit, DwarfContext, ProcessExpr); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index 7c1280dd19442..5b38b29227ab1 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -130,6 +130,9 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset, DataExtractor Extractor( Data.getData().slice(*Offset, *Offset + ExprLength), Data.isLittleEndian(), Data.getAddressSize()); + // Note. We do not pass the DWARF format to DWARFExpression, because + // DW_OP_call_ref, the only operation which depends on the format, is + // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. Instructions.back().Expression = DWARFExpression(Extractor, Data.getAddressSize()); *Offset += ExprLength; @@ -143,6 +146,9 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset, DataExtractor Extractor( Data.getData().slice(*Offset, *Offset + BlockLength), Data.isLittleEndian(), Data.getAddressSize()); + // Note. We do not pass the DWARF format to DWARFExpression, because + // DW_OP_call_ref, the only operation which depends on the format, is + // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. Instructions.back().Expression = DWARFExpression(Extractor, Data.getAddressSize()); *Offset += BlockLength; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index 17f0b7f5c32ab..f381263644012 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -110,6 +110,10 @@ static void dumpExpression(raw_ostream &OS, ArrayRef Data, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U) { DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize); + // Note. We do not pass any format to DWARFExpression, even if the + // corresponding unit is known. For now, there is only one operation, + // DW_OP_call_ref, which depends on the format; it is rarely used, and + // is unexpected in location tables. DWARFExpression(Extractor, AddressSize).print(OS, MRI, U); } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index f93f32917c337..81a6b5dcd5e7e 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -79,7 +79,8 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, ArrayRef Expr = *FormValue.getAsBlock(); DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), Ctx.isLittleEndian(), 0); - DWARFExpression(Data, U->getAddressByteSize()).print(OS, MRI, U); + DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format) + .print(OS, MRI, U); return; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp index 379b88c49c731..605236bc1833c 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -8,7 +8,6 @@ #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/Format.h" #include @@ -119,7 +118,8 @@ static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) { } bool DWARFExpression::Operation::extract(DataExtractor Data, - uint8_t AddressSize, uint64_t Offset) { + uint8_t AddressSize, uint64_t Offset, + Optional Format) { Opcode = Data.getU8(&Offset); Desc = getOpDesc(Opcode); @@ -135,6 +135,7 @@ bool DWARFExpression::Operation::extract(DataExtractor Data, if (Size == Operation::SizeNA) break; + EndOffset = Offset; switch (Size & ~Operation::SignBit) { case Operation::Size1: Operands[Operand] = Data.getU8(&Offset); @@ -158,8 +159,10 @@ bool DWARFExpression::Operation::extract(DataExtractor Data, Operands[Operand] = Data.getUnsigned(&Offset, AddressSize); break; case Operation::SizeRefAddr: - // TODO: Add support for 64-bit DWARF format. - Operands[Operand] = Data.getU32(&Offset); + if (!Format) + return false; + Operands[Operand] = + Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format)); break; case Operation::SizeLEB: if (Signed) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index c7d3974fd79aa..4f128788b1025 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -486,7 +486,8 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, DWARFUnit *U = Die.getDwarfUnit(); for (const auto &Entry : *Loc) { DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0); - DWARFExpression Expression(Data, U->getAddressByteSize()); + DWARFExpression Expression(Data, U->getAddressByteSize(), + U->getFormParams().Format); bool Error = any_of(Expression, [](DWARFExpression::Operation &Op) { return Op.isError(); }); @@ -1294,7 +1295,8 @@ static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { for (const auto &Entry : *Loc) { DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), U->getAddressByteSize()); - DWARFExpression Expression(Data, U->getAddressByteSize()); + DWARFExpression Expression(Data, U->getAddressByteSize(), + U->getFormParams().Format); bool IsInteresting = any_of(Expression, [](DWARFExpression::Operation &Op) { return !Op.isError() && (Op.getCode() == DW_OP_addr || Op.getCode() == DW_OP_form_tls_address || diff --git a/llvm/test/DebugInfo/X86/DW_OP_call_ref_dwarf64.s b/llvm/test/DebugInfo/X86/DW_OP_call_ref_dwarf64.s new file mode 100644 index 0000000000000..5031e141956d2 --- /dev/null +++ b/llvm/test/DebugInfo/X86/DW_OP_call_ref_dwarf64.s @@ -0,0 +1,42 @@ +# RUN: llvm-mc -triple x86_64 %s -filetype=obj -o %t.o +# RUN: llvm-dwarfdump -debug-info %t.o | FileCheck %s +# RUN: llvm-dwarfdump -verify %t.o | FileCheck %s --check-prefix=VERIFY + +# CHECK: DW_TAG_variable +# CHECK-NEXT: DW_AT_location (DW_OP_call_ref 0x1100223344) + +# VERIFY-NOT: error: DIE contains invalid DWARF expression: +# VERIFY: No errors. + + .section .debug_abbrev,"",@progbits + .uleb128 1 # Abbreviation Code + .uleb128 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .uleb128 5 # Abbreviation Code + .uleb128 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .uleb128 2 # DW_AT_location + .uleb128 24 # DW_FORM_exprloc + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits + .long 0xffffffff # DWARF64 mark + .quad .Lcu_end-.Lcu_start # Length of Unit +.Lcu_start: + .short 5 # DWARF version number + .byte 1 # DW_UT_compile + .byte 8 # Address Size + .quad .debug_abbrev # Offset Into Abbrev. Section + .uleb128 1 # Abbrev [1] DW_TAG_compile_unit + .uleb128 5 # Abbrev [5] DW_TAG_variable + .byte .Lloc_end-.Lloc_begin # DW_AT_location +.Lloc_begin: + .byte 154 # DW_OP_call_ref + .quad 0x1100223344 # Offset +.Lloc_end: + .byte 0 # End Of Children Mark +.Lcu_end: diff --git a/llvm/test/DebugInfo/X86/DW_OP_call_ref_unexpected.s b/llvm/test/DebugInfo/X86/DW_OP_call_ref_unexpected.s new file mode 100644 index 0000000000000..036e044270b63 --- /dev/null +++ b/llvm/test/DebugInfo/X86/DW_OP_call_ref_unexpected.s @@ -0,0 +1,28 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: llvm-dwarfdump -debug-loc %t.o | FileCheck %s + +# This checks that we do not try to interpret DW_OP_call_ref if it is +# encountered in a location table. + +# CHECK: .debug_loc contents: +# CHECK-NEXT: 0x00000000: +# CHECK-NEXT: (0x0000000000000000, 0x0000000000000015): + + .section .debug_loc, "", @progbits + .quad 0 # Beginning address offset + .quad 0x15 # Ending address offset + .short .LDescrEnd-.LDescrBegin # Location description length +.LDescrBegin: + .byte 0x9a # DW_OP_call_ref + .long 0xff +.LDescrEnd: + .quad 0, 0 # EOL entry + +# A dummy CU to provide the parser of .debug_loc with the address size. + .section .debug_info,"",@progbits + .long .LCUEnd-.LCUBegin # Length of Unit +.LCUBegin: + .short 4 # DWARF version number + .long 0 # Offset Into Abbrev. Section + .byte 8 # Address Size +.LCUEnd: diff --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp index f1f37c9ec6ea6..18b4c40c4d751 100644 --- a/llvm/tools/llvm-dwarfdump/Statistics.cpp +++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp @@ -248,7 +248,8 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, DWARFUnit *U = Die.getDwarfUnit(); DataExtractor Data(toStringRef(D), Die.getDwarfUnit()->getContext().isLittleEndian(), 0); - DWARFExpression Expression(Data, U->getAddressByteSize()); + DWARFExpression Expression(Data, U->getAddressByteSize(), + U->getFormParams().Format); // Consider the expression containing the DW_OP_entry_value as // an entry value. return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {