1 //===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the DIPrinter class, which is responsible for printing 10 // structures defined in DebugInfo/DIContext.h 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/DebugInfo/Symbolize/DIPrinter.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/DebugInfo/DIContext.h" 17 #include "llvm/Support/ErrorOr.h" 18 #include "llvm/Support/Format.h" 19 #include "llvm/Support/LineIterator.h" 20 #include "llvm/Support/MemoryBuffer.h" 21 #include "llvm/Support/Path.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <algorithm> 24 #include <cmath> 25 #include <cstddef> 26 #include <cstdint> 27 #include <memory> 28 #include <string> 29 30 namespace llvm { 31 namespace symbolize { 32 33 // Prints source code around in the FileName the Line. 34 void DIPrinter::printContext(const std::string &FileName, int64_t Line) { 35 if (PrintSourceContext <= 0) 36 return; 37 38 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 39 MemoryBuffer::getFile(FileName); 40 if (!BufOrErr) 41 return; 42 43 std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get()); 44 int64_t FirstLine = 45 std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2); 46 int64_t LastLine = FirstLine + PrintSourceContext; 47 size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine)); 48 49 for (line_iterator I = line_iterator(*Buf, false); 50 !I.is_at_eof() && I.line_number() <= LastLine; ++I) { 51 int64_t L = I.line_number(); 52 if (L >= FirstLine && L <= LastLine) { 53 OS << format_decimal(L, MaxLineNumberWidth); 54 if (L == Line) 55 OS << " >: "; 56 else 57 OS << " : "; 58 OS << *I << "\n"; 59 } 60 } 61 } 62 63 void DIPrinter::print(const DILineInfo &Info, bool Inlined) { 64 if (PrintFunctionNames) { 65 std::string FunctionName = Info.FunctionName; 66 if (FunctionName == DILineInfo::BadString) 67 FunctionName = DILineInfo::Addr2LineBadString; 68 69 StringRef Delimiter = PrintPretty ? " at " : "\n"; 70 StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : ""; 71 OS << Prefix << FunctionName << Delimiter; 72 } 73 std::string Filename = Info.FileName; 74 if (Filename == DILineInfo::BadString) 75 Filename = DILineInfo::Addr2LineBadString; 76 if (!Verbose) { 77 OS << Filename << ":" << Info.Line; 78 if (Style == OutputStyle::LLVM) 79 OS << ":" << Info.Column; 80 else if (Style == OutputStyle::GNU && Info.Discriminator != 0) 81 OS << " (discriminator " << Info.Discriminator << ")"; 82 OS << "\n"; 83 printContext(Filename, Info.Line); 84 return; 85 } 86 OS << " Filename: " << Filename << "\n"; 87 if (Info.StartLine) 88 OS << "Function start line: " << Info.StartLine << "\n"; 89 OS << " Line: " << Info.Line << "\n"; 90 OS << " Column: " << Info.Column << "\n"; 91 if (Info.Discriminator) 92 OS << " Discriminator: " << Info.Discriminator << "\n"; 93 } 94 95 DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) { 96 print(Info, false); 97 return *this; 98 } 99 100 DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) { 101 uint32_t FramesNum = Info.getNumberOfFrames(); 102 if (FramesNum == 0) { 103 print(DILineInfo(), false); 104 return *this; 105 } 106 for (uint32_t i = 0; i < FramesNum; i++) 107 print(Info.getFrame(i), i > 0); 108 return *this; 109 } 110 111 DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) { 112 std::string Name = Global.Name; 113 if (Name == DILineInfo::BadString) 114 Name = DILineInfo::Addr2LineBadString; 115 OS << Name << "\n"; 116 OS << Global.Start << " " << Global.Size << "\n"; 117 return *this; 118 } 119 120 DIPrinter &DIPrinter::operator<<(const DILocal &Local) { 121 if (Local.FunctionName.empty()) 122 OS << "??\n"; 123 else 124 OS << Local.FunctionName << '\n'; 125 126 if (Local.Name.empty()) 127 OS << "??\n"; 128 else 129 OS << Local.Name << '\n'; 130 131 if (Local.DeclFile.empty()) 132 OS << "??"; 133 else 134 OS << Local.DeclFile; 135 OS << ':' << Local.DeclLine << '\n'; 136 137 if (Local.FrameOffset) 138 OS << *Local.FrameOffset << ' '; 139 else 140 OS << "?? "; 141 142 if (Local.Size) 143 OS << *Local.Size << ' '; 144 else 145 OS << "?? "; 146 147 if (Local.TagOffset) 148 OS << *Local.TagOffset << '\n'; 149 else 150 OS << "??\n"; 151 return *this; 152 } 153 154 } // end namespace symbolize 155 } // end namespace llvm 156