diff --git a/llvm/test/tools/llvm-readobj/COFF/call-graph-profile-err.s b/llvm/test/tools/llvm-readobj/COFF/call-graph-profile-err.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/call-graph-profile-err.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s -o %t +# RUN: not llvm-readobj %t --cg-profile 2>&1 | FileCheck --check-prefix=ERR %s + +## In order to use --cg-profile option, the section ".llvm.call-graph-profile" +## should have two 4-byte fields representing the indexes of two symbols and +## one 8-byte fields representing the weight from first symbol to second +## symbol. +## The section in this test case has 9 bytes of data, so it's malformed. + +# ERR: error: '{{.*}}': Stream Error: The stream is too short to perform the requested operation. + +.section .test +a: +b: +c: +d: +e: + +.section ".llvm.call-graph-profile" + .long 10 ## Symbol index of a. + .long 11 ## Symbol index of b. + .byte 32 ## Weight from a to b. It is an error, since it should have a length of 8 bytes. diff --git a/llvm/test/tools/llvm-readobj/COFF/call-graph-profile.s b/llvm/test/tools/llvm-readobj/COFF/call-graph-profile.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/call-graph-profile.s @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s -o %t +# RUN: llvm-readobj %t --cg-profile | FileCheck %s + +# CHECK: CGProfile [ +# CHECK-NEXT: CGProfileEntry { +# CHECK-NEXT: From: a (10) +# CHECK-NEXT: To: b (11) +# CHECK-NEXT: Weight: 32 +# CHECK-NEXT: } +# CHECK-NEXT: CGProfileEntry { +# CHECK-NEXT: From: c (12) +# CHECK-NEXT: To: a (10) +# CHECK-NEXT: Weight: 11 +# CHECK-NEXT: } +# CHECK-NEXT: CGProfileEntry { +# CHECK-NEXT: From: d (13) +# CHECK-NEXT: To: e (14) +# CHECK-NEXT: Weight: 20 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.section .test +a: +b: +c: +d: +e: + +.section ".llvm.call-graph-profile" + .long 10 ## Symbol index of a. + .long 11 ## Symbol index of b. + .quad 32 ## Weight from a to b. + + .long 12 ## Symbol index of c. + .long 10 ## Symbol index of a. + .quad 11 ## Weight from c to a. + + .long 13 ## Symbol index of d. + .long 14 ## Symbol index of e. + .quad 20 ## Weight from d to e. diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -104,8 +104,10 @@ bool GHash) override; void printStackMap() const override; void printAddrsig() override; + void printCGProfile() override; private: + StringRef getSymbolName(uint32_t Index); void printSymbols() override; void printDynamicSymbols() override; void printSymbol(const SymbolRef &Sym); @@ -1516,16 +1518,8 @@ if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) reportError(errorCodeToError(EC), Obj->getFileName()); - Expected Linked = Obj->getSymbol(Aux->TagIndex); - if (!Linked) - reportError(Linked.takeError(), Obj->getFileName()); - - Expected LinkedName = Obj->getSymbolName(*Linked); - if (!LinkedName) - reportError(LinkedName.takeError(), Obj->getFileName()); - DictScope AS(W, "AuxWeakExternal"); - W.printNumber("Linked", *LinkedName, Aux->TagIndex); + W.printNumber("Linked", getSymbolName(Aux->TagIndex), Aux->TagIndex); W.printEnum ("Search", Aux->Characteristics, makeArrayRef(WeakExternalCharacteristics)); @@ -1570,19 +1564,11 @@ if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) reportError(errorCodeToError(EC), Obj->getFileName()); - Expected ReferredSym = - Obj->getSymbol(Aux->SymbolTableIndex); - if (!ReferredSym) - reportError(ReferredSym.takeError(), Obj->getFileName()); - - Expected ReferredName = Obj->getSymbolName(*ReferredSym); - if (!ReferredName) - reportError(ReferredName.takeError(), Obj->getFileName()); - DictScope AS(W, "AuxCLRToken"); W.printNumber("AuxType", Aux->AuxType); W.printNumber("Reserved", Aux->Reserved); - W.printNumber("SymbolTableIndex", *ReferredName, Aux->SymbolTableIndex); + W.printNumber("SymbolTableIndex", getSymbolName(Aux->SymbolTableIndex), + Aux->SymbolTableIndex); } else { W.startLine() << "\n"; @@ -1904,7 +1890,7 @@ } void COFFDumper::printStackMap() const { - object::SectionRef StackMapSection; + SectionRef StackMapSection; for (auto Sec : Obj->sections()) { StringRef Name; if (Expected NameOrErr = Sec.getName()) @@ -1918,7 +1904,7 @@ } } - if (StackMapSection == object::SectionRef()) + if (StackMapSection == SectionRef()) return; StringRef StackMapContents = @@ -1935,7 +1921,7 @@ } void COFFDumper::printAddrsig() { - object::SectionRef AddrsigSection; + SectionRef AddrsigSection; for (auto Sec : Obj->sections()) { StringRef Name; if (Expected NameOrErr = Sec.getName()) @@ -1949,7 +1935,7 @@ } } - if (AddrsigSection == object::SectionRef()) + if (AddrsigSection == SectionRef()) return; StringRef AddrsigContents = @@ -1967,19 +1953,58 @@ if (Err) reportError(createError(Err), Obj->getFileName()); - Expected Sym = Obj->getSymbol(SymIndex); - if (!Sym) - reportError(Sym.takeError(), Obj->getFileName()); + W.printNumber("Sym", getSymbolName(SymIndex), SymIndex); + Cur += Size; + } +} + +void COFFDumper::printCGProfile() { + SectionRef CGProfileSection; + for (SectionRef Sec : Obj->sections()) { + StringRef Name = unwrapOrError(Obj->getFileName(), Sec.getName()); + if (Name == ".llvm.call-graph-profile") { + CGProfileSection = Sec; + break; + } + } - Expected SymName = Obj->getSymbolName(*Sym); - if (!SymName) - reportError(SymName.takeError(), Obj->getFileName()); + if (CGProfileSection == SectionRef()) + return; - W.printNumber("Sym", *SymName, SymIndex); - Cur += Size; + StringRef CGProfileContents = + unwrapOrError(Obj->getFileName(), CGProfileSection.getContents()); + BinaryStreamReader Reader(CGProfileContents, llvm::support::little); + + ListScope L(W, "CGProfile"); + while (!Reader.empty()) { + uint32_t FromIndex, ToIndex; + uint64_t Count; + if (Error Err = Reader.readInteger(FromIndex)) + reportError(std::move(Err), Obj->getFileName()); + if (Error Err = Reader.readInteger(ToIndex)) + reportError(std::move(Err), Obj->getFileName()); + if (Error Err = Reader.readInteger(Count)) + reportError(std::move(Err), Obj->getFileName()); + + DictScope D(W, "CGProfileEntry"); + W.printNumber("From", getSymbolName(FromIndex), FromIndex); + W.printNumber("To", getSymbolName(ToIndex), ToIndex); + W.printNumber("Weight", Count); } } +StringRef COFFDumper::getSymbolName(uint32_t Index) { + Expected Sym = Obj->getSymbol(Index); + if (!Sym) + reportError(Sym.takeError(), Obj->getFileName()); + + Expected SymName = Obj->getSymbolName(*Sym); + if (!SymName) + reportError(SymName.takeError(), Obj->getFileName()); + + return *SymName; +} + void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer, ArrayRef> IpiRecords, ArrayRef> TpiRecords) { diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -528,6 +528,8 @@ Dumper->printCOFFResources(); if (opts::COFFLoadConfig) Dumper->printCOFFLoadConfig(); + if (opts::CGProfile) + Dumper->printCGProfile(); if (opts::Addrsig) Dumper->printAddrsig(); if (opts::CodeView)