Index: lld/test/COFF/pdb-procid-remapping.test =================================================================== --- lld/test/COFF/pdb-procid-remapping.test +++ lld/test/COFF/pdb-procid-remapping.test @@ -14,6 +14,7 @@ CHECK-NEXT: 136 | S_FRAMEPROC [size = 32] CHECK-NEXT: size = 40, padding size = 0, offset to padding = 0 CHECK-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK-NEXT: local fp reg = NONE, param fp reg = NONE CHECK-NEXT: flags = has async eh | opt speed CHECK-NEXT: 168 | S_END [size = 4] CHECK-LABEL: Mod 0001 | @@ -23,6 +24,7 @@ CHECK-NEXT: 136 | S_FRAMEPROC [size = 32] CHECK-NEXT: size = 0, padding size = 0, offset to padding = 0 CHECK-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK-NEXT: local fp reg = NONE, param fp reg = NONE CHECK-NEXT: flags = has async eh | opt speed CHECK-NEXT: 168 | S_END [size = 4] CHECK-LABEL: Mod 0002 | Index: llvm/include/llvm/DebugInfo/CodeView/CodeView.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CodeView.h +++ llvm/include/llvm/DebugInfo/CodeView/CodeView.h @@ -231,6 +231,8 @@ Inlined = 0x00000800, StrictSecurityChecks = 0x00001000, SafeBuffers = 0x00002000, + EncodedLocalBasePointerMask = 0x0000C000, + EncodedParamBasePointerMask = 0x00030000, ProfileGuidedOptimization = 0x00040000, ValidProfileCounts = 0x00080000, OptimizedForSpeed = 0x00100000, Index: llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -28,9 +29,9 @@ CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types, CodeViewContainer Container, std::unique_ptr ObjDelegate, - bool PrintRecordBytes) + Optional CPU, bool PrintRecordBytes) : W(W), Types(Types), Container(Container), - ObjDelegate(std::move(ObjDelegate)), + ObjDelegate(std::move(ObjDelegate)), MaybeCPUType(CPU), PrintRecordBytes(PrintRecordBytes) {} /// Dumps one type record. Returns false if there was a type parsing error, @@ -43,12 +44,14 @@ /// parse error, and true otherwise. Error dump(const CVSymbolArray &Symbols); + Optional maybeGetCPUType() const { return MaybeCPUType; } + private: ScopedPrinter &W; TypeCollection &Types; CodeViewContainer Container; std::unique_ptr ObjDelegate; - + Optional MaybeCPUType; bool PrintRecordBytes; }; } // end namespace codeview Index: llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -761,7 +761,49 @@ uint16_t SectionIdOfExceptionHandler; FrameProcedureOptions Flags; + /// Extract the register this frame uses to refer to local variables. + RegisterId getLocalFPReg(CPUType CPU) const { + return decodeFPReg((uint32_t(Flags) >> 14U) & 0x3U, CPU); + } + + /// Extract the register this frame uses to refer to parameters. + RegisterId getParamFPReg(CPUType CPU) const { + return decodeFPReg((uint32_t(Flags) >> 16U) & 0x3U, CPU); + } + uint32_t RecordOffset; + +private: + static RegisterId decodeFPReg(uint32_t EncodedFPReg, CPUType CPU) { + assert(EncodedFPReg < 4); + switch (CPU) { + // FIXME: Add ARM and AArch64 variants here. + default: + break; + case CPUType::Intel8080: + case CPUType::Intel8086: + case CPUType::Intel80286: + case CPUType::Intel80386: + case CPUType::Intel80486: + case CPUType::Pentium: + case CPUType::PentiumPro: + case CPUType::Pentium3: + switch (EncodedFPReg) { + case 0: return RegisterId::NONE; + case 1: return RegisterId::VFRAME; + case 2: return RegisterId::EBP; + case 3: return RegisterId::EBX; + } + case CPUType::X64: + switch (EncodedFPReg) { + case 0: return RegisterId::NONE; + case 1: return RegisterId::RSP; + case 2: return RegisterId::RBP; + case 3: return RegisterId::R13; + } + } + return RegisterId::NONE; + } }; // S_CALLSITEINFO Index: llvm/lib/DebugInfo/CodeView/EnumTables.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/EnumTables.cpp +++ llvm/lib/DebugInfo/CodeView/EnumTables.cpp @@ -200,6 +200,8 @@ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined), CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks), CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedLocalBasePointerMask), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedParamBasePointerMask), CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization), CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts), CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed), Index: llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -32,8 +32,9 @@ class CVSymbolDumperImpl : public SymbolVisitorCallbacks { public: CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate, - ScopedPrinter &W, bool PrintRecordBytes) - : Types(Types), ObjDelegate(ObjDelegate), W(W), + ScopedPrinter &W, Optional CPU, + bool PrintRecordBytes) + : Types(Types), ObjDelegate(ObjDelegate), W(W), MaybeCPUType(CPU), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} /// CVSymbolVisitor overrides. @@ -46,6 +47,8 @@ Error visitSymbolEnd(CVSymbol &Record) override; Error visitUnknownSymbol(CVSymbol &Record) override; + Optional maybeGetCPUType() const { return MaybeCPUType; } + private: void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, uint32_t RelocationOffset); @@ -56,6 +59,9 @@ SymbolDumpDelegate *ObjDelegate; ScopedPrinter &W; + /// Save the machine or CPU type when dumping a compile symbols. + Optional MaybeCPUType; + bool PrintRecordBytes; bool InFunctionScope; }; @@ -235,6 +241,7 @@ W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames()); W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames()); W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames()); + MaybeCPUType = Compile2.Machine; std::string FrontendVersion; { raw_string_ostream Out(FrontendVersion); @@ -258,6 +265,7 @@ W.printEnum("Language", Compile3.getLanguage(), getSourceLanguageNames()); W.printFlags("Flags", Compile3.getFlags(), getCompileSym3FlagNames()); W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames()); + MaybeCPUType = Compile3.Machine; std::string FrontendVersion; { raw_string_ostream Out(FrontendVersion); @@ -415,6 +423,15 @@ FrameProc.SectionIdOfExceptionHandler); W.printFlags("Flags", static_cast(FrameProc.Flags), getFrameProcSymFlagNames()); + + // Look up the register names if we can. + if (MaybeCPUType) { + CPUType CPU = *MaybeCPUType; + W.printEnum("LocalFPReg", uint16_t(FrameProc.getLocalFPReg(CPU)), + getRegisterNames()); + W.printEnum("ParamFPReg", uint16_t(FrameProc.getParamFPReg(CPU)), + getRegisterNames()); + } return Error::success(); } @@ -625,21 +642,29 @@ Error CVSymbolDumper::dump(CVRecord &Record) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get(), Container); - CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, MaybeCPUType, + PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); CVSymbolVisitor Visitor(Pipeline); - return Visitor.visitSymbolRecord(Record); + auto Err = Visitor.visitSymbolRecord(Record); + if (auto CPU = Dumper.maybeGetCPUType()) + MaybeCPUType = CPU; + return Err; } Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get(), Container); - CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, MaybeCPUType, + PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); CVSymbolVisitor Visitor(Pipeline); - return Visitor.visitSymbolStream(Symbols); + auto Err = Visitor.visitSymbolStream(Symbols); + if (auto CPU = Dumper.maybeGetCPUType()) + MaybeCPUType = CPU; + return Err; } Index: llvm/test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-headers.test +++ llvm/test/DebugInfo/PDB/pdbdump-headers.test @@ -487,6 +487,7 @@ ALL-NEXT: 164 | S_FRAMEPROC [size = 32] ALL-NEXT: size = 0, padding size = 0, offset to padding = 0 ALL-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +ALL-NEXT: local fp reg = EBP, param fp reg = EBP ALL-NEXT: flags = has async eh | opt speed ALL-NEXT: 196 | S_END [size = 4] ALL-NEXT: 200 | S_BUILDINFO [size = 8] BuildId = `0x100E` Index: llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h =================================================================== --- llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h +++ llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h @@ -53,6 +53,11 @@ std::string idIndex(codeview::TypeIndex TI) const; LinePrinter &P; + + /// Dumping certain records requires knowing what machine this is. The + /// S_COMPILE3 record will tell us, but if we don't see one, default to X64. + codeview::CPUType CompilationCPU = codeview::CPUType::X64; + bool RecordBytes; const SymbolGroup *SymGroup = nullptr; codeview::LazyRandomTypeCollection &Ids; @@ -61,4 +66,4 @@ } // namespace pdb } // namespace llvm -#endif \ No newline at end of file +#endif Index: llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp =================================================================== --- llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp +++ llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -490,6 +490,7 @@ AutoIndent Indent(P, 7); SourceLanguage Lang = static_cast( Compile2.Flags & CompileSym2Flags::SourceLanguageMask); + CompilationCPU = Compile2.Machine; P.formatLine("machine = {0}, ver = {1}, language = {2}", formatMachineType(Compile2.Machine), Compile2.Version, formatSourceLanguage(Lang)); @@ -510,6 +511,7 @@ AutoIndent Indent(P, 7); SourceLanguage Lang = static_cast( Compile3.Flags & CompileSym3Flags::SourceLanguageMask); + CompilationCPU = Compile3.Machine; P.formatLine("machine = {0}, Ver = {1}, language = {2}", formatMachineType(Compile3.Machine), Compile3.Version, formatSourceLanguage(Lang)); @@ -629,6 +631,9 @@ FP.BytesOfCalleeSavedRegisters, formatSegmentOffset(FP.SectionIdOfExceptionHandler, FP.OffsetOfExceptionHandler)); + P.formatLine("local fp reg = {0}, param fp reg = {1}", + formatRegisterId(FP.getLocalFPReg(CompilationCPU)), + formatRegisterId(FP.getParamFPReg(CompilationCPU))); P.formatLine("flags = {0}", formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags)); return Error::success(); Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -179,6 +179,8 @@ DebugStringTableSubsectionRef CVStringTable; + Optional MaybeCPUType; + ScopedPrinter &Writer; BinaryByteStream TypeContents; LazyRandomTypeCollection Types; @@ -1150,7 +1152,7 @@ auto CODD = llvm::make_unique(*this, Section, Obj, SectionContents); CVSymbolDumper CVSD(W, Types, CodeViewContainer::ObjectFile, std::move(CODD), - opts::CodeViewSubsectionBytes); + MaybeCPUType, opts::CodeViewSubsectionBytes); CVSymbolArray Symbols; BinaryStreamReader Reader(BinaryData, llvm::support::little); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) { @@ -1163,6 +1165,8 @@ W.flush(); error(std::move(EC)); } + if (auto CPU = CVSD.maybeGetCPUType()) + MaybeCPUType = CPU; W.flush(); }