[llvm] r220526 - PR21189: Teach llvm-readobj to dump bits of COFF symbol subsections required to debug using VS2012+
Timur Iskhodzhanov
timurrrr at google.com
Thu Oct 23 15:25:31 PDT 2014
Author: timurrrr
Date: Thu Oct 23 17:25:31 2014
New Revision: 220526
URL: http://llvm.org/viewvc/llvm-project?rev=220526&view=rev
Log:
PR21189: Teach llvm-readobj to dump bits of COFF symbol subsections required to debug using VS2012+
Reviewed at http://reviews.llvm.org/D5755
Thanks to Andrey Guskov for his help investigating this!
Modified:
llvm/trunk/include/llvm/Support/COFF.h
llvm/trunk/test/tools/llvm-readobj/codeview-linetables.test
llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
Modified: llvm/trunk/include/llvm/Support/COFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/COFF.h?rev=220526&r1=220525&r2=220526&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/COFF.h (original)
+++ llvm/trunk/include/llvm/Support/COFF.h Thu Oct 23 17:25:31 2014
@@ -662,9 +662,14 @@ namespace COFF {
enum CodeViewLineTableIdentifiers {
DEBUG_SECTION_MAGIC = 0x4,
+ DEBUG_SYMBOL_SUBSECTION = 0xF1,
DEBUG_LINE_TABLE_SUBSECTION = 0xF2,
DEBUG_STRING_TABLE_SUBSECTION = 0xF3,
- DEBUG_INDEX_SUBSECTION = 0xF4
+ DEBUG_INDEX_SUBSECTION = 0xF4,
+
+ // Symbol subsections are split into records of different types.
+ DEBUG_SYMBOL_TYPE_PROC_START = 0x1147,
+ DEBUG_SYMBOL_TYPE_PROC_END = 0x114F
};
inline bool isReservedSectionNumber(int32_t SectionNumber) {
Modified: llvm/trunk/test/tools/llvm-readobj/codeview-linetables.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/codeview-linetables.test?rev=220526&r1=220525&r2=220526&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/codeview-linetables.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/codeview-linetables.test Thu Oct 23 17:25:31 2014
@@ -40,6 +40,12 @@ MFUN32: ]
MFUN32-NEXT: Subsection [
MFUN32-NEXT: Type: 0xF1
MFUN32-NEXT: PayloadSize: 0x4B
+MFUN32: ProcStart {
+MFUN32-NEXT: FunctionName: x
+MFUN32-NEXT: Section: _x
+MFUN32-NEXT: CodeSize: 0xA
+MFUN32-NEXT: }
+MFUN32-NEXT: ProcEnd
MFUN32: ]
MFUN32-NEXT: Subsection [
MFUN32-NEXT: Type: 0xF2
@@ -53,6 +59,12 @@ MFUN32: ]
MFUN32-NEXT: Subsection [
MFUN32-NEXT: Type: 0xF1
MFUN32-NEXT: PayloadSize: 0x4B
+MFUN32: ProcStart {
+MFUN32-NEXT: FunctionName: y
+MFUN32-NEXT: Section: _y
+MFUN32-NEXT: CodeSize: 0xA
+MFUN32-NEXT: }
+MFUN32-NEXT: ProcEnd
MFUN32: ]
MFUN32-NEXT: Subsection [
MFUN32-NEXT: Type: 0xF2
@@ -66,6 +78,12 @@ MFUN32: ]
MFUN32-NEXT: Subsection [
MFUN32-NEXT: Type: 0xF1
MFUN32-NEXT: PayloadSize: 0x4B
+MFUN32: ProcStart {
+MFUN32-NEXT: FunctionName: f
+MFUN32-NEXT: Section: _f
+MFUN32-NEXT: CodeSize: 0x14
+MFUN32-NEXT: }
+MFUN32-NEXT: ProcEnd
MFUN32: ]
MFUN32-NEXT: Subsection [
MFUN32-NEXT: Type: 0xF2
@@ -127,6 +145,12 @@ MFUN64: ]
MFUN64-NEXT: Subsection [
MFUN64-NEXT: Type: 0xF1
MFUN64-NEXT: PayloadSize: 0x4B
+MFUN64: ProcStart {
+MFUN64-NEXT: FunctionName: x
+MFUN64-NEXT: Section: x
+MFUN64-NEXT: CodeSize: 0xE
+MFUN64-NEXT: }
+MFUN64-NEXT: ProcEnd
MFUN64: ]
MFUN64-NEXT: Subsection [
MFUN64-NEXT: Type: 0xF2
@@ -136,6 +160,12 @@ MFUN64-NEXT: ]
MFUN64-NEXT: Subsection [
MFUN64-NEXT: Type: 0xF1
MFUN64-NEXT: PayloadSize: 0x4B
+MFUN64: ProcStart {
+MFUN64-NEXT: FunctionName: y
+MFUN64-NEXT: Section: y
+MFUN64-NEXT: CodeSize: 0xE
+MFUN64-NEXT: }
+MFUN64-NEXT: ProcEnd
MFUN64: ]
MFUN64-NEXT: Subsection [
MFUN64-NEXT: Type: 0xF2
@@ -145,6 +175,12 @@ MFUN64-NEXT: ]
MFUN64-NEXT: Subsection [
MFUN64-NEXT: Type: 0xF1
MFUN64-NEXT: PayloadSize: 0x4B
+MFUN64: ProcStart {
+MFUN64-NEXT: FunctionName: f
+MFUN64-NEXT: Section: f
+MFUN64-NEXT: CodeSize: 0x18
+MFUN64-NEXT: }
+MFUN64-NEXT: ProcEnd
MFUN64: ]
MFUN64-NEXT: Subsection [
MFUN64-NEXT: Type: 0xF2
@@ -234,6 +270,12 @@ MFILE32: ]
MFILE32-NEXT: Subsection [
MFILE32-NEXT: Type: 0xF1
MFILE32-NEXT: PayloadSize: 0x4B
+MFILE32: ProcStart {
+MFILE32-NEXT: FunctionName: f
+MFILE32-NEXT: Section: _f
+MFILE32-NEXT: CodeSize: 0x14
+MFILE32-NEXT: }
+MFILE32-NEXT: ProcEnd
MFILE32: ]
MFILE32-NEXT: Subsection [
MFILE32-NEXT: Type: 0xF2
@@ -284,6 +326,12 @@ MFILE64: ]
MFILE64-NEXT: Subsection [
MFILE64-NEXT: Type: 0xF1
MFILE64-NEXT: PayloadSize: 0x4B
+MFILE64: ProcStart {
+MFILE64-NEXT: FunctionName: f
+MFILE64-NEXT: Section: f
+MFILE64-NEXT: CodeSize: 0x18
+MFILE64-NEXT: }
+MFILE64-NEXT: ProcEnd
MFILE64: ]
MFILE64-NEXT: Subsection [
MFILE64-NEXT: Type: 0xF2
@@ -344,23 +392,33 @@ RUN: | FileCheck %s -check-prefix MCOM
RUN: llvm-readobj -s -codeview-linetables %p/Inputs/comdat-function-linetables.obj.coff-2013-i386 \
RUN: | FileCheck %s -check-prefix MCOMDAT
+MCOMDAT: ProcStart {
+MCOMDAT-NEXT: FunctionName: f
+MCOMDAT-NEXT: Section: ?f@@YAHXZ
+MCOMDAT-NEXT: CodeSize: 0x7
+MCOMDAT-NEXT: }
MCOMDAT: FunctionLineTable [
-MCOMDAT-NEXT: FunctionName: ?f@@YAHXZ
-MCOMDAT-NEXT: CodeSize: 0x7
-MCOMDAT-NEXT: FilenameSegment [
-MCOMDAT-NEXT: Filename: c:\src\test.cc
-MCOMDAT-NEXT: +0x0: 2
-MCOMDAT-NEXT: +0x3: 3
-MCOMDAT-NEXT: +0x5: 4
-MCOMDAT-NEXT: ]
-MCOMDAT-NEXT: ]
+MCOMDAT-NEXT: FunctionName: ?f@@YAHXZ
+MCOMDAT-NEXT: CodeSize: 0x7
+MCOMDAT-NEXT: FilenameSegment [
+MCOMDAT-NEXT: Filename: c:\src\test.cc
+MCOMDAT-NEXT: +0x0: 2
+MCOMDAT-NEXT: +0x3: 3
+MCOMDAT-NEXT: +0x5: 4
+MCOMDAT-NEXT: ]
+MCOMDAT-NEXT: ]
+MCOMDAT: ProcStart {
+MCOMDAT-NEXT: FunctionName: g
+MCOMDAT-NEXT: Section: ?g@@YAHXZ
+MCOMDAT-NEXT: CodeSize: 0x7
+MCOMDAT-NEXT: }
MCOMDAT: FunctionLineTable [
-MCOMDAT-NEXT: FunctionName: ?g@@YAHXZ
-MCOMDAT-NEXT: CodeSize: 0x7
-MCOMDAT-NEXT: FilenameSegment [
-MCOMDAT-NEXT: Filename: c:\src\test.cc
-MCOMDAT-NEXT: +0x0: 7
-MCOMDAT-NEXT: +0x3: 8
-MCOMDAT-NEXT: +0x5: 9
-MCOMDAT-NEXT: ]
-MCOMDAT-NEXT: ]
+MCOMDAT-NEXT: FunctionName: ?g@@YAHXZ
+MCOMDAT-NEXT: CodeSize: 0x7
+MCOMDAT-NEXT: FilenameSegment [
+MCOMDAT-NEXT: Filename: c:\src\test.cc
+MCOMDAT-NEXT: +0x0: 7
+MCOMDAT-NEXT: +0x3: 8
+MCOMDAT-NEXT: +0x5: 9
+MCOMDAT-NEXT: ]
+MCOMDAT-NEXT: ]
Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=220526&r1=220525&r2=220526&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Thu Oct 23 17:25:31 2014
@@ -69,6 +69,10 @@ private:
void printCodeViewLineTables(const SectionRef &Section);
+ void printCodeViewSymbolsSubsection(StringRef Subsection,
+ const SectionRef &Section,
+ uint32_t Offset);
+
void cacheRelocations();
std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset,
@@ -444,6 +448,7 @@ void COFFDumper::printCodeViewLineTables
ListScope D(W, "CodeViewLineTables");
{
+ // FIXME: Add more offset correctness checks.
DataExtractor DE(Data, true, 4);
uint32_t Offset = 0,
Magic = DE.getU32(&Offset);
@@ -473,6 +478,9 @@ void COFFDumper::printCodeViewLineTables
W.printBinaryBlock("Contents", Contents);
switch (SubSectionType) {
+ case COFF::DEBUG_SYMBOL_SUBSECTION:
+ printCodeViewSymbolsSubsection(Contents, Section, Offset);
+ break;
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
@@ -592,6 +600,80 @@ void COFFDumper::printCodeViewLineTables
}
}
+void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
+ const SectionRef &Section,
+ uint32_t OffsetInSection) {
+ if (Subsection.size() == 0) {
+ error(object_error::parse_failed);
+ return;
+ }
+ DataExtractor DE(Subsection, true, 4);
+ uint32_t Offset = 0;
+
+ // Function-level subsections have "procedure start" and "procedure end"
+ // commands that should come in pairs and surround relevant info.
+ bool InFunctionScope = false;
+ while (DE.isValidOffset(Offset)) {
+ // Read subsection segments one by one.
+ uint16_t Size = DE.getU16(&Offset);
+ // The section size includes the size of the type identifier.
+ if (Size < 2 || !DE.isValidOffsetForDataOfSize(Offset, Size)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ Size -= 2;
+ uint16_t Type = DE.getU16(&Offset);
+ switch (Type) {
+ case COFF::DEBUG_SYMBOL_TYPE_PROC_START: {
+ DictScope S(W, "ProcStart");
+ if (InFunctionScope || Size < 36) {
+ error(object_error::parse_failed);
+ return;
+ }
+ InFunctionScope = true;
+
+ // We're currently interested in a limited subset of fields in this
+ // segment, just ignore the rest of the fields for now.
+ uint8_t Unused[12];
+ DE.getU8(&Offset, Unused, 12);
+ uint32_t CodeSize = DE.getU32(&Offset);
+ DE.getU8(&Offset, Unused, 12);
+ StringRef SectionName;
+ if (error(resolveSymbolName(Obj->getCOFFSection(Section),
+ OffsetInSection + Offset, SectionName)))
+ return;
+ Offset += 4;
+ DE.getU8(&Offset, Unused, 3);
+ StringRef FunctionName = DE.getCStr(&Offset);
+ if (!DE.isValidOffset(Offset)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ W.printString("FunctionName", FunctionName);
+ W.printString("Section", SectionName);
+ W.printHex("CodeSize", CodeSize);
+
+ break;
+ }
+ case COFF::DEBUG_SYMBOL_TYPE_PROC_END: {
+ W.startLine() << "ProcEnd\n";
+ if (!InFunctionScope || Size > 0) {
+ error(object_error::parse_failed);
+ return;
+ }
+ InFunctionScope = false;
+ break;
+ }
+ default:
+ Offset += Size;
+ break;
+ }
+ }
+
+ if (InFunctionScope)
+ error(object_error::parse_failed);
+}
+
void COFFDumper::printSections() {
ListScope SectionsD(W, "Sections");
int SectionNumber = 0;
More information about the llvm-commits
mailing list