diff --git a/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h b/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h --- a/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h +++ b/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h @@ -27,7 +27,7 @@ class DIPrinter { public: - enum class OutputStyle { LLVM, GNU }; + enum class OutputStyle { LLVM, GNU, YAML }; private: raw_ostream &OS; diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp --- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp +++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -27,7 +28,57 @@ #include #include +LLVM_YAML_IS_SEQUENCE_VECTOR(DILineInfo) +struct DIInliningInfoYaml { + std::vector Frames; +}; + namespace llvm { + +namespace yaml { + +template <> struct MappingTraits { + static void mapping(IO &IO, DILineInfo &Value) { + Optional EmptySource; + IO.mapOptional("Source", Value.Source); + IO.mapOptional("FunctionName", Value.FunctionName, DILineInfo::BadString); + IO.mapOptional("StartFileName", Value.StartFileName, DILineInfo::BadString); + IO.mapOptional("StartLine", Value.StartLine, 0); + IO.mapOptional("FileName", Value.FileName, DILineInfo::BadString); + IO.mapOptional("Line", Value.Line, 0); + IO.mapOptional("Column", Value.Column, 0); + IO.mapOptional("Discriminator", Value.Discriminator, 0); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, DIInliningInfoYaml &Value) { + IO.mapRequired("Frames", Value.Frames); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, DIGlobal &Value) { + IO.mapOptional("Name", Value.Name, DILineInfo::BadString); + IO.mapOptional("Start", Value.Start, 0); + IO.mapOptional("Size", Value.Size, 0); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, DILocal &Value) { + IO.mapOptional("FunctionName", Value.FunctionName, ""); + IO.mapOptional("Name", Value.Name, ""); + IO.mapOptional("DeclFile", Value.DeclFile, ""); + IO.mapOptional("DeclLine", Value.DeclLine, 0); + IO.mapOptional("FrameOffset", Value.FrameOffset); + IO.mapOptional("Size", Value.Size); + IO.mapOptional("TagOffset", Value.TagOffset); + } +}; + +} // namespace yaml + namespace symbolize { // Prints source code around in the FileName the Line. @@ -61,6 +112,13 @@ } void DIPrinter::print(const DILineInfo &Info, bool Inlined) { + if (Style == OutputStyle::YAML) { + llvm::yaml::Output YOut(OS); + DILineInfo Val = Info; // copy: YOut<< requires mutability. + YOut << Val; + return; + } + if (PrintFunctionNames) { std::string FunctionName = Info.FunctionName; if (FunctionName == DILineInfo::BadString) @@ -101,6 +159,16 @@ DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) { uint32_t FramesNum = Info.getNumberOfFrames(); + + if (Style == OutputStyle::YAML) { + llvm::yaml::Output YOut(OS); + DIInliningInfoYaml Val; + for (uint32_t i = 0; i < FramesNum; i++) + Val.Frames.push_back(Info.getFrame(i)); + YOut << Val; + return *this; + } + if (FramesNum == 0) { print(DILineInfo(), false); return *this; @@ -111,6 +179,13 @@ } DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) { + if (Style == OutputStyle::YAML) { + llvm::yaml::Output YOut(OS); + DIGlobal Val = Global; // copy: YOut<< requires mutability. + YOut << Val; + return *this; + } + std::string Name = Global.Name; if (Name == DILineInfo::BadString) Name = DILineInfo::Addr2LineBadString; @@ -120,6 +195,13 @@ } DIPrinter &DIPrinter::operator<<(const DILocal &Local) { + if (Style == OutputStyle::YAML) { + llvm::yaml::Output YOut(OS); + DILocal Val = Local; // copy: YOut<< requires mutability. + YOut << Val; + return *this; + } + if (Local.FunctionName.empty()) OS << "??\n"; else diff --git a/llvm/test/tools/llvm-symbolizer/output-style-yaml.test b/llvm/test/tools/llvm-symbolizer/output-style-yaml.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/output-style-yaml.test @@ -0,0 +1,25 @@ +This test checks YAML output. + +RUN: llvm-symbolizer --output-style=YAML -e %p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck %s + +CHECK: some text +CHECK-NEXT: --- +CHECK-NEXT: Frames: +CHECK-NEXT: - FunctionName: inctwo +CHECK-NEXT: StartFileName: '/tmp{{\\|/}}x.c' +CHECK-NEXT: StartLine: 2 +CHECK-NEXT: FileName: '/tmp{{\\|/}}x.c' +CHECK-NEXT: Line: 3 +CHECK-NEXT: Column: 3 +CHECK-NEXT: - FunctionName: inc +CHECK-NEXT: StartFileName: '/tmp{{\\|/}}x.c' +CHECK-NEXT: StartLine: 6 +CHECK-NEXT: FileName: '/tmp{{\\|/}}x.c' +CHECK-NEXT: Line: 7 +CHECK-NEXT: - FunctionName: main +CHECK-NEXT: StartFileName: '/tmp{{\\|/}}x.c' +CHECK-NEXT: StartLine: 12 +CHECK-NEXT: FileName: '/tmp{{\\|/}}x.c' +CHECK-NEXT: Line: 14 +CHECK-NEXT: ... +CHECK-NEXT: some text2 diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp --- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -311,9 +311,13 @@ auto OutputStyle = IsAddr2Line ? DIPrinter::OutputStyle::GNU : DIPrinter::OutputStyle::LLVM; if (const opt::Arg *A = Args.getLastArg(OPT_output_style_EQ)) { - OutputStyle = strcmp(A->getValue(), "GNU") == 0 - ? DIPrinter::OutputStyle::GNU - : DIPrinter::OutputStyle::LLVM; + if (strcmp(A->getValue(), "YAML") == 0) { + OutputStyle = DIPrinter::OutputStyle::YAML; + } else if (strcmp(A->getValue(), "GNU") == 0) { + OutputStyle = DIPrinter::OutputStyle::GNU; + } else { + OutputStyle = DIPrinter::OutputStyle::LLVM; + } } LLVMSymbolizer Symbolizer(Opts);