summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimur Iskhodzhanov <timurrrr@google.com>2013-12-19 11:37:14 +0000
committerTimur Iskhodzhanov <timurrrr@google.com>2013-12-19 11:37:14 +0000
commite493a9976c6ff5aa7852c6c6f512b0ff60e3f5ce (patch)
tree795cdbcb5ca3290e70174af4a34c7b0d8a9dada0
parent7ec73b1145bb666a9f1048d044be44e03b6f40c5 (diff)
downloadllvm-e493a9976c6ff5aa7852c6c6f512b0ff60e3f5ce.tar.gz
llvm-e493a9976c6ff5aa7852c6c6f512b0ff60e3f5ce.tar.bz2
llvm-e493a9976c6ff5aa7852c6c6f512b0ff60e3f5ce.tar.xz
Teach the llvm-readobj COFF dumper to dump debug line tables from object files
Reviewed at http://llvm-reviews.chandlerc.com/D2425 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197674 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Support/COFF.h7
-rw-r--r--test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-i368bin0 -> 1631 bytes
-rw-r--r--test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-x86_64bin0 -> 1799 bytes
-rw-r--r--test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-i368bin0 -> 2155 bytes
-rw-r--r--test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-x86_64bin0 -> 2475 bytes
-rw-r--r--test/tools/llvm-readobj/codeview-linetables.test282
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp165
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp4
-rw-r--r--tools/llvm-readobj/llvm-readobj.h1
9 files changed, 459 insertions, 0 deletions
diff --git a/include/llvm/Support/COFF.h b/include/llvm/Support/COFF.h
index 9cc3989df0..2de01000a7 100644
--- a/include/llvm/Support/COFF.h
+++ b/include/llvm/Support/COFF.h
@@ -611,6 +611,13 @@ namespace COFF {
}
};
+ enum CodeViewLineTableIdentifiers {
+ DEBUG_SECTION_MAGIC = 0x4,
+ DEBUG_LINE_TABLE_SUBSECTION = 0xF2,
+ DEBUG_STRING_TABLE_SUBSECTION = 0xF3,
+ DEBUG_INDEX_SUBSECTION = 0xF4
+ };
+
} // End namespace COFF.
} // End namespace llvm.
diff --git a/test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-i368 b/test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-i368
new file mode 100644
index 0000000000..1672d3a542
--- /dev/null
+++ b/test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-i368
Binary files differ
diff --git a/test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-x86_64 b/test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-x86_64
new file mode 100644
index 0000000000..30bfe79bc3
--- /dev/null
+++ b/test/tools/llvm-readobj/Inputs/multifile-linetables.obj.coff-2012-x86_64
Binary files differ
diff --git a/test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-i368 b/test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-i368
new file mode 100644
index 0000000000..a0196ff2d7
--- /dev/null
+++ b/test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-i368
Binary files differ
diff --git a/test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-x86_64 b/test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-x86_64
new file mode 100644
index 0000000000..14f65ab2f6
--- /dev/null
+++ b/test/tools/llvm-readobj/Inputs/multifunction-linetables.obj.coff-2012-x86_64
Binary files differ
diff --git a/test/tools/llvm-readobj/codeview-linetables.test b/test/tools/llvm-readobj/codeview-linetables.test
new file mode 100644
index 0000000000..4854d7ac6a
--- /dev/null
+++ b/test/tools/llvm-readobj/codeview-linetables.test
@@ -0,0 +1,282 @@
+RUN: llvm-readobj -s -codeview-linetables %p/Inputs/multifunction-linetables.obj.coff-2012-i368 \
+RUN: | FileCheck %s -check-prefix MFUN32
+RUN: llvm-readobj -s -codeview-linetables %p/Inputs/multifunction-linetables.obj.coff-2012-x86_64 \
+RUN: | FileCheck %s -check-prefix MFUN64
+RUN: llvm-readobj -s -codeview-linetables %p/Inputs/multifile-linetables.obj.coff-2012-i368 \
+RUN: | FileCheck %s -check-prefix MFILE32
+RUN: llvm-readobj -s -codeview-linetables %p/Inputs/multifile-linetables.obj.coff-2012-x86_64 \
+RUN: | FileCheck %s -check-prefix MFILE64
+
+MFUN32: CodeViewLineTables [
+MFUN32-NEXT: Magic: 0x4
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF1
+MFUN32-NEXT: PayloadSize: 0x52
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF5
+MFUN32-NEXT: PayloadSize: 0x24
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF1
+MFUN32-NEXT: PayloadSize: 0x4B
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF2
+MFUN32-NEXT: PayloadSize: 0x30
+MFUN32: FunctionName: _x
+MFUN32-NEXT: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF5
+MFUN32-NEXT: PayloadSize: 0x24
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF1
+MFUN32-NEXT: PayloadSize: 0x4B
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF2
+MFUN32-NEXT: PayloadSize: 0x30
+MFUN32: FunctionName: _y
+MFUN32-NEXT: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF5
+MFUN32-NEXT: PayloadSize: 0x24
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF1
+MFUN32-NEXT: PayloadSize: 0x4B
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF2
+MFUN32-NEXT: PayloadSize: 0x40
+MFUN32: FunctionName: _f
+MFUN32-NEXT: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF4
+MFUN32-NEXT: PayloadSize: 0x18
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF3
+MFUN32-NEXT: PayloadSize: 0x46
+MFUN32: ]
+MFUN32-NEXT: Subsection [
+MFUN32-NEXT: Type: 0xF1
+MFUN32-NEXT: PayloadSize: 0x8
+MFUN32: ]
+MFUN32-NEXT: FunctionLineTable [
+MFUN32-NEXT: FunctionName: _x
+MFUN32-NEXT: CodeSize: 0xA
+MFUN32-NEXT: FilenameSegment [
+MFUN32-NEXT: Filename: d:\source.c
+MFUN32-NEXT: +0x0: 3
+MFUN32-NEXT: +0x3: 4
+MFUN32-NEXT: +0x8: 5
+MFUN32-NEXT: ]
+MFUN32-NEXT: ]
+MFUN32-NEXT: FunctionLineTable [
+MFUN32-NEXT: FunctionName: _y
+MFUN32-NEXT: CodeSize: 0xA
+MFUN32-NEXT: FilenameSegment [
+MFUN32-NEXT: Filename: d:\source.c
+MFUN32-NEXT: +0x0: 7
+MFUN32-NEXT: +0x3: 8
+MFUN32-NEXT: +0x8: 9
+MFUN32-NEXT: ]
+MFUN32-NEXT: ]
+MFUN32-NEXT: FunctionLineTable [
+MFUN32-NEXT: FunctionName: _f
+MFUN32-NEXT: CodeSize: 0x14
+MFUN32-NEXT: FilenameSegment [
+MFUN32-NEXT: Filename: d:\source.c
+MFUN32-NEXT: +0x0: 11
+MFUN32-NEXT: +0x3: 12
+MFUN32-NEXT: +0x8: 13
+MFUN32-NEXT: +0xD: 14
+MFUN32-NEXT: +0x12: 15
+MFUN32-NEXT: ]
+MFUN32-NEXT: ]
+MFUN32-NEXT: ]
+
+MFUN64: CodeViewLineTables [
+MFUN64-NEXT: Magic: 0x4
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF1
+MFUN64-NEXT: PayloadSize: 0x52
+MFUN64: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF1
+MFUN64-NEXT: PayloadSize: 0x4B
+MFUN64: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF2
+MFUN64-NEXT: PayloadSize: 0x30
+MFUN64: FunctionName: x
+MFUN64-NEXT: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF1
+MFUN64-NEXT: PayloadSize: 0x4B
+MFUN64: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF2
+MFUN64-NEXT: PayloadSize: 0x30
+MFUN64: FunctionName: y
+MFUN64-NEXT: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF1
+MFUN64-NEXT: PayloadSize: 0x4B
+MFUN64: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF2
+MFUN64-NEXT: PayloadSize: 0x40
+MFUN64: FunctionName: f
+MFUN64-NEXT: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF4
+MFUN64-NEXT: PayloadSize: 0x18
+MFUN64: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF3
+MFUN64-NEXT: PayloadSize: 0xD
+MFUN64: ]
+MFUN64-NEXT: Subsection [
+MFUN64-NEXT: Type: 0xF1
+MFUN64-NEXT: PayloadSize: 0x8
+MFUN64: ]
+MFUN64-NEXT: FunctionLineTable [
+MFUN64-NEXT: FunctionName: x
+MFUN64-NEXT: CodeSize: 0xE
+MFUN64-NEXT: FilenameSegment [
+MFUN64-NEXT: Filename: d:\source.c
+MFUN64-NEXT: +0x0: 3
+MFUN64-NEXT: +0x4: 4
+MFUN64-NEXT: +0x9: 5
+MFUN64-NEXT: ]
+MFUN64-NEXT: ]
+MFUN64-NEXT: FunctionLineTable [
+MFUN64-NEXT: FunctionName: y
+MFUN64-NEXT: CodeSize: 0xE
+MFUN64-NEXT: FilenameSegment [
+MFUN64-NEXT: Filename: d:\source.c
+MFUN64-NEXT: +0x0: 7
+MFUN64-NEXT: +0x4: 8
+MFUN64-NEXT: +0x9: 9
+MFUN64-NEXT: ]
+MFUN64-NEXT: ]
+MFUN64-NEXT: FunctionLineTable [
+MFUN64-NEXT: FunctionName: f
+MFUN64-NEXT: CodeSize: 0x18
+MFUN64-NEXT: FilenameSegment [
+MFUN64-NEXT: Filename: d:\source.c
+MFUN64-NEXT: +0x0: 11
+MFUN64-NEXT: +0x4: 12
+MFUN64-NEXT: +0x9: 13
+MFUN64-NEXT: +0xE: 14
+MFUN64-NEXT: +0x13: 15
+MFUN64-NEXT: ]
+MFUN64-NEXT: ]
+MFUN64-NEXT: ]
+
+MFILE32: CodeViewLineTables [
+MFILE32-NEXT: Magic: 0x4
+MFILE32-NEXT: Subsection [
+MFILE32-NEXT: Type: 0xF1
+MFILE32-NEXT: PayloadSize: 0x51
+MFILE32: ]
+MFILE32-NEXT: Subsection [
+MFILE32-NEXT: Type: 0xF5
+MFILE32-NEXT: PayloadSize: 0x24
+MFILE32: ]
+MFILE32-NEXT: Subsection [
+MFILE32-NEXT: Type: 0xF1
+MFILE32-NEXT: PayloadSize: 0x4B
+MFILE32: ]
+MFILE32-NEXT: Subsection [
+MFILE32-NEXT: Type: 0xF2
+MFILE32-NEXT: PayloadSize: 0x64
+MFILE32: FunctionName: _f
+MFILE32-NEXT: ]
+MFILE32-NEXT: Subsection [
+MFILE32-NEXT: Type: 0xF4
+MFILE32-NEXT: PayloadSize: 0x28
+MFILE32: ]
+MFILE32-NEXT: Subsection [
+MFILE32-NEXT: Type: 0xF3
+MFILE32-NEXT: PayloadSize: 0x57
+MFILE32: ]
+MFILE32-NEXT: Subsection [
+MFILE32-NEXT: Type: 0xF1
+MFILE32-NEXT: PayloadSize: 0x8
+MFILE32: ]
+MFILE32-NEXT: FunctionLineTable [
+MFILE32-NEXT: FunctionName: _f
+MFILE32-NEXT: CodeSize: 0x14
+MFILE32-NEXT: FilenameSegment [
+MFILE32-NEXT: Filename: d:\input.c
+MFILE32-NEXT: +0x0: 3
+MFILE32-NEXT: ]
+MFILE32-NEXT: FilenameSegment [
+MFILE32-NEXT: Filename: d:\one.c
+MFILE32-NEXT: +0x3: 1
+MFILE32-NEXT: ]
+MFILE32-NEXT: FilenameSegment [
+MFILE32-NEXT: Filename: d:\two.c
+MFILE32-NEXT: +0x8: 2
+MFILE32-NEXT: ]
+MFILE32-NEXT: FilenameSegment [
+MFILE32-NEXT: Filename: d:\one.c
+MFILE32-NEXT: +0xD: 7
+MFILE32-NEXT: +0x12: 8
+MFILE32-NEXT: ]
+MFILE32-NEXT: ]
+MFILE32-NEXT: ]
+
+MFILE64: CodeViewLineTables [
+MFILE64-NEXT: Magic: 0x4
+MFILE64-NEXT: Subsection [
+MFILE64-NEXT: Type: 0xF1
+MFILE64-NEXT: PayloadSize: 0x51
+MFILE64: ]
+MFILE64-NEXT: Subsection [
+MFILE64-NEXT: Type: 0xF1
+MFILE64-NEXT: PayloadSize: 0x4B
+MFILE64: ]
+MFILE64-NEXT: Subsection [
+MFILE64-NEXT: Type: 0xF2
+MFILE64-NEXT: PayloadSize: 0x64
+MFILE64: FunctionName: f
+MFILE64-NEXT: ]
+MFILE64-NEXT: Subsection [
+MFILE64-NEXT: Type: 0xF4
+MFILE64-NEXT: PayloadSize: 0x28
+MFILE64: ]
+MFILE64-NEXT: Subsection [
+MFILE64-NEXT: Type: 0xF3
+MFILE64-NEXT: PayloadSize: 0x1E
+MFILE64: ]
+MFILE64-NEXT: Subsection [
+MFILE64-NEXT: Type: 0xF1
+MFILE64-NEXT: PayloadSize: 0x8
+MFILE64: ]
+MFILE64-NEXT: FunctionLineTable [
+MFILE64-NEXT: FunctionName: f
+MFILE64-NEXT: CodeSize: 0x18
+MFILE64-NEXT: FilenameSegment [
+MFILE64-NEXT: Filename: d:\input.c
+MFILE64-NEXT: +0x0: 3
+MFILE64-NEXT: ]
+MFILE64-NEXT: FilenameSegment [
+MFILE64-NEXT: Filename: d:\one.c
+MFILE64-NEXT: +0x4: 1
+MFILE64-NEXT: ]
+MFILE64-NEXT: FilenameSegment [
+MFILE64-NEXT: Filename: d:\two.c
+MFILE64-NEXT: +0x9: 2
+MFILE64-NEXT: ]
+MFILE64-NEXT: FilenameSegment [
+MFILE64-NEXT: Filename: d:\one.c
+MFILE64-NEXT: +0xE: 7
+MFILE64-NEXT: +0x13: 8
+MFILE64-NEXT: ]
+MFILE64-NEXT: ]
+MFILE64-NEXT: ]
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index 2f309e30ec..411846b867 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -24,6 +24,8 @@
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Win64EH.h"
@@ -76,6 +78,8 @@ private:
void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs);
+ void printCodeViewLineTables(section_iterator SecI);
+
void cacheRelocations();
error_code getSectionContents(
@@ -648,6 +652,164 @@ void COFFDumper::printFileHeaders() {
}
}
+void COFFDumper::printCodeViewLineTables(section_iterator SecI) {
+ StringRef Data;
+ if (error(SecI->getContents(Data))) return;
+
+ SmallVector<StringRef, 10> FunctionNames;
+ StringMap<StringRef> FunctionLineTables;
+ StringRef FileIndexToStringOffsetTable;
+ StringRef StringTable;
+
+ ListScope D(W, "CodeViewLineTables");
+ {
+ DataExtractor DE(Data, true, 4);
+ uint32_t Offset = 0,
+ Magic = DE.getU32(&Offset);
+ W.printHex("Magic", Magic);
+ if (Magic != COFF::DEBUG_SECTION_MAGIC) {
+ error(object_error::parse_failed);
+ return;
+ }
+
+ bool Finished = false;
+ while (DE.isValidOffset(Offset) && !Finished) {
+ // The section consists of a number of subsection in the following format:
+ // |Type|PayloadSize|Payload...|
+ uint32_t SubSectionType = DE.getU32(&Offset),
+ PayloadSize = DE.getU32(&Offset);
+ ListScope S(W, "Subsection");
+ W.printHex("Type", SubSectionType);
+ W.printHex("PayloadSize", PayloadSize);
+ if (PayloadSize > Data.size() - Offset) {
+ error(object_error::parse_failed);
+ return;
+ }
+
+ // Print the raw contents to simplify debugging if anything goes wrong
+ // afterwards.
+ StringRef Contents = Data.substr(Offset, PayloadSize);
+ W.printBinaryBlock("Contents", Contents);
+
+ switch (SubSectionType) {
+ case COFF::DEBUG_LINE_TABLE_SUBSECTION: {
+ // Holds a PC to file:line table. Some data to parse this subsection is
+ // stored in the other subsections, so just check sanity and store the
+ // pointers for deferred processing.
+
+ if (PayloadSize < 12) {
+ // There should be at least three words to store two function
+ // relocations and size of the code.
+ error(object_error::parse_failed);
+ return;
+ }
+
+ StringRef FunctionName;
+ if (error(resolveSymbolName(RelocMap[Obj->getCOFFSection(SecI)], Offset,
+ FunctionName)))
+ return;
+ W.printString("FunctionName", FunctionName);
+ if (FunctionLineTables.count(FunctionName) != 0) {
+ // Saw debug info for this function already?
+ error(object_error::parse_failed);
+ return;
+ }
+
+ FunctionLineTables[FunctionName] = Contents;
+ FunctionNames.push_back(FunctionName);
+ break;
+ }
+ case COFF::DEBUG_STRING_TABLE_SUBSECTION:
+ if (PayloadSize == 0 || StringTable.data() != 0 ||
+ Contents.back() != '\0') {
+ // Empty or duplicate or non-null-terminated subsection.
+ error(object_error::parse_failed);
+ return;
+ }
+ StringTable = Contents;
+ break;
+ case COFF::DEBUG_INDEX_SUBSECTION:
+ // Holds the translation table from file indices
+ // to offsets in the string table.
+
+ if (PayloadSize == 0 || FileIndexToStringOffsetTable.data() != 0) {
+ // Empty or duplicate subsection.
+ error(object_error::parse_failed);
+ return;
+ }
+ FileIndexToStringOffsetTable = Contents;
+ break;
+ }
+ Offset += PayloadSize;
+
+ // Align the reading pointer by 4.
+ Offset += (-Offset) % 4;
+ }
+ }
+
+ // Dump the line tables now that we've read all the subsections and know all
+ // the required information.
+ for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) {
+ StringRef Name = FunctionNames[I];
+ ListScope S(W, "FunctionLineTable");
+ W.printString("FunctionName", Name);
+
+ DataExtractor DE(FunctionLineTables[Name], true, 4);
+ uint32_t Offset = 8; // Skip relocations.
+ uint32_t FunctionSize = DE.getU32(&Offset);
+ W.printHex("CodeSize", FunctionSize);
+ while (DE.isValidOffset(Offset)) {
+ // For each range of lines with the same filename, we have a segment
+ // in the line table. The filename string is accessed using double
+ // indirection to the string table subsection using the index subsection.
+ uint32_t OffsetInIndex = DE.getU32(&Offset),
+ SegmentLength = DE.getU32(&Offset),
+ FullSegmentSize = DE.getU32(&Offset);
+ if (FullSegmentSize != 12 + 8 * SegmentLength) {
+ error(object_error::parse_failed);
+ return;
+ }
+
+ uint32_t FilenameOffset;
+ {
+ DataExtractor SDE(FileIndexToStringOffsetTable, true, 4);
+ uint32_t OffsetInSDE = OffsetInIndex;
+ if (!SDE.isValidOffset(OffsetInSDE)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ FilenameOffset = SDE.getU32(&OffsetInSDE);
+ }
+
+ if (FilenameOffset == 0 || FilenameOffset + 1 >= StringTable.size() ||
+ StringTable.data()[FilenameOffset - 1] != '\0') {
+ // Each string in an F3 subsection should be preceded by a null
+ // character.
+ error(object_error::parse_failed);
+ return;
+ }
+
+ StringRef Filename(StringTable.data() + FilenameOffset);
+ ListScope S(W, "FilenameSegment");
+ W.printString("Filename", Filename);
+ for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset);
+ ++J) {
+ // Then go the (PC, LineNumber) pairs. The line number is stored in the
+ // least significant 31 bits of the respective word in the table.
+ uint32_t PC = DE.getU32(&Offset),
+ LineNumber = DE.getU32(&Offset) & 0x7fffffff;
+ if (PC >= FunctionSize) {
+ error(object_error::parse_failed);
+ return;
+ }
+ char Buffer[32];
+ format("+0x%X", PC).snprint(Buffer, 32);
+ W.printNumber(Buffer, LineNumber);
+ }
+ }
+ }
+}
+
void COFFDumper::printSections() {
error_code EC;
@@ -707,6 +869,9 @@ void COFFDumper::printSections() {
}
}
+ if (Name == ".debug$S" && opts::CodeViewLineTables)
+ printCodeViewLineTables(SecI);
+
if (opts::SectionData) {
StringRef Data;
if (error(SecI->getContents(Data))) break;
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index f84a72f461..c09be74dc7 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -128,6 +128,10 @@ namespace opts {
// -expand-relocs
cl::opt<bool> ExpandRelocs("expand-relocs",
cl::desc("Expand each shown relocation to multiple lines"));
+
+ // -codeview-linetables
+ cl::opt<bool> CodeViewLineTables("codeview-linetables",
+ cl::desc("Display CodeView line table information"));
} // namespace opts
static int ReturnValue = EXIT_SUCCESS;
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
index 3f756106c9..f0bba42e91 100644
--- a/tools/llvm-readobj/llvm-readobj.h
+++ b/tools/llvm-readobj/llvm-readobj.h
@@ -38,6 +38,7 @@ namespace opts {
extern llvm::cl::opt<bool> DynamicSymbols;
extern llvm::cl::opt<bool> UnwindInfo;
extern llvm::cl::opt<bool> ExpandRelocs;
+ extern llvm::cl::opt<bool> CodeViewLineTables;
} // namespace opts
#define LLVM_READOBJ_ENUM_ENT(ns, enum) \