diff options
author | Fangrui Song <maskray@google.com> | 2020-05-08 09:28:25 -0700 |
---|---|---|
committer | Fangrui Song <maskray@google.com> | 2020-05-08 09:35:54 -0700 |
commit | befbc99a7f092df5868b5ff0c6e46f41236cb1af (patch) | |
tree | 9bc41bdeac244f2affc631c9f812b4a9f06ac041 | |
parent | 7cf4ab13af8aa3183e551b3319399cddd9384948 (diff) | |
download | llvm-befbc99a7f092df5868b5ff0c6e46f41236cb1af.zip llvm-befbc99a7f092df5868b5ff0c6e46f41236cb1af.tar.gz llvm-befbc99a7f092df5868b5ff0c6e46f41236cb1af.tar.bz2 |
Reland D79501 "[DebugInfo] Fix handling DW_OP_call_ref in DWARF64 units."
With a fix to uninitialized EndOffset.
DW_OP_call_ref is the only operation that has an operand which depends
on the DWARF format. The patch fixes handling that operation in DWARF64
units.
Differential Revision: https://reviews.llvm.org/D79501
-rw-r--r-- | llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h | 15 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/DWARFLinker/DWARFLinker.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp | 11 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp | 6 | ||||
-rw-r--r-- | llvm/test/DebugInfo/X86/DW_OP_call_ref_dwarf64.s | 42 | ||||
-rw-r--r-- | llvm/test/DebugInfo/X86/DW_OP_call_ref_unexpected.s | 28 | ||||
-rw-r--r-- | llvm/tools/llvm-dwarfdump/Statistics.cpp | 3 |
11 files changed, 110 insertions, 16 deletions
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h index 4bbff49..2892930 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 @@ public: 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<dwarf::DwarfFormat> Format); bool isError() { return Error; } bool print(raw_ostream &OS, const DWARFExpression *Expr, const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH); @@ -107,7 +110,7 @@ public: : 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 @@ public: 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 @@ public: friend bool operator==(const iterator &, const iterator &); }; - DWARFExpression(DataExtractor Data, uint8_t AddressSize) - : Data(Data), AddressSize(AddressSize) { + DWARFExpression(DataExtractor Data, uint8_t AddressSize, + Optional<dwarf::DwarfFormat> Format = None) + : Data(Data), AddressSize(AddressSize), Format(Format) { assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2); } @@ -143,6 +147,7 @@ public: private: DataExtractor Data; uint8_t AddressSize; + Optional<dwarf::DwarfFormat> 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 cf1e269..25b973e 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 1d7ef35..fff3763 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 7c1280d..5b38b29 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 17f0b7f..f381263 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<uint8_t> 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 f93f329..81a6b5d 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<uint8_t> 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 379b88c..605236bc 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 <cassert> @@ -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<DwarfFormat> 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 c7d3974..4f12878 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 0000000..5031e14 --- /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 0000000..036e044 --- /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): <decoding error> + + .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 f1f37c9..18b4c40 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) { |