From 26f9a0c5297ec09a2b057bcb818d64c9414f5f01 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 21 Sep 2017 20:15:30 +0000 Subject: [PATCH] [dwarfdump] Add verbose output for .debug-line section This patch adds dumping of line table instructions as well as the final state at each specified pc value in verbose mode. This is essentially the same as the default in Darwin's dwarfdump. Dumping the actual line table opcodes can be particularly useful for something like debugging a bad `.debug_line` section. Differential revision: https://reviews.llvm.org/D37971 llvm-svn: 313910 --- .../llvm/DebugInfo/DWARF/DWARFDebugLine.h | 3 +- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 10 +- llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 81 +++++- .../DebugInfo/Generic/unconditional-branch.ll | 2 +- llvm/test/DebugInfo/MIR/X86/empty-inline.mir | 34 +-- llvm/test/DebugInfo/Mips/delay-slot.ll | 2 +- .../ARM/dwarf-asm-multiple-sections-dwarf-2.s | 12 +- .../test/MC/ARM/dwarf-asm-multiple-sections.s | 13 +- .../MC/ARM/dwarf-asm-nonstandard-section.s | 12 +- llvm/test/MC/ARM/dwarf-asm-single-section.s | 12 +- llvm/test/MC/MachO/gen-dwarf.s | 58 ++-- .../dsymutil/X86/basic-linking-bundle.test | 8 +- .../tools/dsymutil/X86/basic-linking-x86.test | 236 ++++++++-------- .../X86/basic-lto-dw4-linking-x86.test | 206 +++++++------- .../dsymutil/X86/basic-lto-linking-x86.test | 254 +++++++++--------- .../tools/dsymutil/X86/multiple-inputs.test | 16 +- llvm/test/tools/llvm-dwarfdump/X86/brief.s | 15 +- .../tools/llvm-dwarfdump/X86/verbose.test | 25 ++ 18 files changed, 552 insertions(+), 447 deletions(-) create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/verbose.test diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h index 0c8f98aa62f9..a4d8c0dd716d 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -217,7 +217,8 @@ public: void clear(); /// Parse prologue and all rows. - bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr); + bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + raw_ostream *OS = nullptr); using RowVector = std::vector; using RowIter = RowVector::const_iterator; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 69a4fe64b754..59cf636e6043 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -335,8 +335,14 @@ void DWARFContext::dump( isLittleEndian(), savedAddressByteSize); DWARFDebugLine::LineTable LineTable; uint32_t Offset = *StmtOffset; - LineTable.parse(lineData, &Offset); - LineTable.dump(OS); + // Verbose dumping is done during parsing and not on the intermediate + // representation. + if (DumpOpts.Verbose) { + LineTable.parse(lineData, &Offset, &OS); + } else { + LineTable.parse(lineData, &Offset); + LineTable.dump(OS); + } } } } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 7d180564e9f7..bd8dd0d0ede5 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -394,7 +394,7 @@ DWARFDebugLine::getOrParseLineTable(const DWARFDataExtractor &DebugLineData, } bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, - uint32_t *OffsetPtr) { + uint32_t *OffsetPtr, raw_ostream *OS) { const uint32_t DebugLineOffset = *OffsetPtr; clear(); @@ -405,14 +405,23 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, return false; } + if (OS) + Prologue.dump(*OS); + const uint32_t EndOffset = DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength(); ParsingState State(this); while (*OffsetPtr < EndOffset) { + if (OS) + *OS << format("0x%08.08" PRIx32 ": ", *OffsetPtr); + uint8_t Opcode = DebugLineData.getU8(OffsetPtr); + if (OS) + *OS << format("%02.02" PRIx8 " ", Opcode); + if (Opcode == 0) { // Extended Opcodes always start with a zero opcode followed by // a uleb128 length so you can skip ones you don't know about @@ -421,6 +430,8 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, uint32_t ArgSize = Len - (*OffsetPtr - ExtOffset); uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr); + if (OS) + *OS << LNExtendedString(SubOpcode); switch (SubOpcode) { case DW_LNE_end_sequence: // Set the end_sequence register of the state machine to true and @@ -432,6 +443,11 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // of the sequence. State.Row.EndSequence = true; State.appendRowToMatrix(*OffsetPtr); + if (OS) { + *OS << "\n"; + OS->indent(12); + State.Row.dump(*OS); + } State.resetRowAndSequence(); break; @@ -443,6 +459,8 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // that affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. State.Row.Address = DebugLineData.getRelocatedAddress(OffsetPtr); + if (OS) + *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address); break; case DW_LNE_define_file: @@ -473,11 +491,18 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); Prologue.FileNames.push_back(FileEntry); + if (OS) + *OS << " (" << FileEntry.Name.str() + << ", dir=" << FileEntry.DirIdx << ", mod_time=" + << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime) + << ", length=" << FileEntry.Length << ")"; } break; case DW_LNE_set_discriminator: State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Discriminator << ")"; break; default: @@ -487,6 +512,8 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, break; } } else if (Opcode < Prologue.OpcodeBase) { + if (OS) + *OS << LNStandardString(Opcode); switch (Opcode) { // Standard Opcodes case DW_LNS_copy: @@ -494,32 +521,49 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // current values of the state-machine registers. Then set // the basic_block register to false. State.appendRowToMatrix(*OffsetPtr); + if (OS) { + *OS << "\n"; + OS->indent(12); + State.Row.dump(*OS); + *OS << "\n"; + } break; case DW_LNS_advance_pc: // Takes a single unsigned LEB128 operand, multiplies it by the // min_inst_length field of the prologue, and adds the // result to the address register of the state machine. - State.Row.Address += - DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength; + { + uint64_t AddrOffset = + DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength; + State.Row.Address += AddrOffset; + if (OS) + *OS << " (" << AddrOffset << ")"; + } break; case DW_LNS_advance_line: // Takes a single signed LEB128 operand and adds that value to // the line register of the state machine. State.Row.Line += DebugLineData.getSLEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Line << ")"; break; case DW_LNS_set_file: // Takes a single unsigned LEB128 operand and stores it in the file // register of the state machine. State.Row.File = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.File << ")"; break; case DW_LNS_set_column: // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. State.Row.Column = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Column << ")"; break; case DW_LNS_negate_stmt: @@ -551,6 +595,9 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, uint64_t AddrOffset = (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; State.Row.Address += AddrOffset; + if (OS) + *OS + << format(" (0x%16.16" PRIx64 ")", AddrOffset); } break; @@ -564,7 +611,13 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // judge when the computation of a special opcode overflows and // requires the use of DW_LNS_advance_pc. Such assemblers, however, // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. - State.Row.Address += DebugLineData.getU16(OffsetPtr); + { + uint16_t PCOffset = DebugLineData.getU16(OffsetPtr); + State.Row.Address += PCOffset; + if (OS) + *OS + << format(" (0x%16.16" PRIx64 ")", PCOffset); + } break; case DW_LNS_set_prologue_end: @@ -583,6 +636,8 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. State.Row.Isa = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Isa << ")"; break; default: @@ -592,8 +647,12 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, { assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size()); uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1]; - for (uint8_t I = 0; I < OpcodeLength; ++I) - DebugLineData.getULEB128(OffsetPtr); + for (uint8_t I = 0; I < OpcodeLength; ++I) { + uint64_t Value = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << format("Skipping ULEB128 value: 0x%16.16" PRIx64 ")\n", + Value); + } } break; } @@ -638,10 +697,20 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, Prologue.LineBase + (AdjustOpcode % Prologue.LineRange); State.Row.Line += LineOffset; State.Row.Address += AddrOffset; + + if (OS) { + *OS << "address += " << ((uint32_t)AdjustOpcode) + << ", line += " << LineOffset << "\n"; + OS->indent(12); + State.Row.dump(*OS); + } + State.appendRowToMatrix(*OffsetPtr); // Reset discriminator to 0. State.Row.Discriminator = 0; } + if(OS) + *OS << "\n"; } if (!State.Sequence.Empty) { diff --git a/llvm/test/DebugInfo/Generic/unconditional-branch.ll b/llvm/test/DebugInfo/Generic/unconditional-branch.ll index 169843d9355c..232622086d0e 100644 --- a/llvm/test/DebugInfo/Generic/unconditional-branch.ll +++ b/llvm/test/DebugInfo/Generic/unconditional-branch.ll @@ -2,7 +2,7 @@ ; PR 19261 ; RUN: %llc_dwarf -fast-isel=false -O0 -filetype=obj %s -o %t -; RUN: llvm-dwarfdump -v %t | FileCheck %s +; RUN: llvm-dwarfdump -a %t | FileCheck %s ; CHECK: {{0x[0-9a-f]+}} 1 0 1 0 0 is_stmt ; CHECK: {{0x[0-9a-f]+}} 2 0 1 0 0 is_stmt diff --git a/llvm/test/DebugInfo/MIR/X86/empty-inline.mir b/llvm/test/DebugInfo/MIR/X86/empty-inline.mir index 3c325cd53970..5e3274d13c82 100644 --- a/llvm/test/DebugInfo/MIR/X86/empty-inline.mir +++ b/llvm/test/DebugInfo/MIR/X86/empty-inline.mir @@ -1,10 +1,10 @@ -# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump -v - | FileCheck %s +# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump -a - | FileCheck %s # # This testcase has an implicit def pseudo-iunstruction with a debug location. # # CHECK: .debug_info contents: # CHECK: DW_TAG_subprogram -# CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +# CHECK: DW_AT_low_pc (0x0000000000000000) # CHECK-NOT: DW_TAG # CHECK: DW_AT_specification {{.*}} "_ZN1C5m_fn3Ev" # CHECK-NOT: DW_TAG @@ -20,38 +20,38 @@ source_filename = "t.ll" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx" - + %class.E = type { %class.D } %class.D = type { %class.B } %class.B = type { %class.A, %class.A } %class.A = type { i8 } %class.C = type <{ %class.E*, %class.B, [2 x i8] }> - + @a = local_unnamed_addr global %class.E* null, align 4 - + define i32 @_ZN1C5m_fn3Ev(%class.C* nocapture) local_unnamed_addr align 2 !dbg !6 { %2 = alloca %class.B, align 1 %3 = load %class.E*, %class.E** @a, align 4 %4 = icmp eq %class.E* %3, null br i1 %4, label %10, label %5 - + ;