summaryrefslogtreecommitdiff
path: root/tools
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 /tools
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
Diffstat (limited to 'tools')
-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
3 files changed, 170 insertions, 0 deletions
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) \