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 void PlainPrinterBase::printHeader(uint64_t Address) { 34 if (Config.PrintAddress) { 35 OS << "0x"; 36 OS.write_hex(Address); 37 StringRef Delimiter = Config.Pretty ? ": " : "\n"; 38 OS << Delimiter; 39 } 40 } 41 42 // Prints source code around in the FileName the Line. 43 void PlainPrinterBase::printContext(StringRef FileName, int64_t Line) { 44 if (Config.SourceContextLines <= 0) 45 return; 46 47 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 48 MemoryBuffer::getFile(FileName); 49 if (!BufOrErr) 50 return; 51 52 std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get()); 53 int64_t FirstLine = 54 std::max(static_cast<int64_t>(1), Line - Config.SourceContextLines / 2); 55 int64_t LastLine = FirstLine + Config.SourceContextLines; 56 size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine)); 57 58 for (line_iterator I = line_iterator(*Buf, false); 59 !I.is_at_eof() && I.line_number() <= LastLine; ++I) { 60 int64_t L = I.line_number(); 61 if (L >= FirstLine && L <= LastLine) { 62 OS << format_decimal(L, MaxLineNumberWidth); 63 if (L == Line) 64 OS << " >: "; 65 else 66 OS << " : "; 67 OS << *I << "\n"; 68 } 69 } 70 } 71 72 void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) { 73 if (Config.PrintFunctions) { 74 if (FunctionName == DILineInfo::BadString) 75 FunctionName = DILineInfo::Addr2LineBadString; 76 StringRef Delimiter = Config.Pretty ? " at " : "\n"; 77 StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : ""; 78 OS << Prefix << FunctionName << Delimiter; 79 } 80 } 81 82 void LLVMPrinter::printSimpleLocation(StringRef Filename, 83 const DILineInfo &Info) { 84 OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n'; 85 printContext(Filename, Info.Line); 86 } 87 88 void GNUPrinter::printSimpleLocation(StringRef Filename, 89 const DILineInfo &Info) { 90 OS << Filename << ':' << Info.Line; 91 if (Info.Discriminator) 92 OS << " (discriminator " << Info.Discriminator << ')'; 93 OS << '\n'; 94 printContext(Filename, Info.Line); 95 } 96 97 void PlainPrinterBase::printVerbose(StringRef Filename, 98 const DILineInfo &Info) { 99 OS << " Filename: " << Filename << '\n'; 100 if (Info.StartLine) { 101 OS << " Function start filename: " << Info.StartFileName << '\n'; 102 OS << " Function start line: " << Info.StartLine << '\n'; 103 } 104 OS << " Line: " << Info.Line << '\n'; 105 OS << " Column: " << Info.Column << '\n'; 106 if (Info.Discriminator) 107 OS << " Discriminator: " << Info.Discriminator << '\n'; 108 } 109 110 void LLVMPrinter::printFooter() { OS << '\n'; } 111 112 void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) { 113 printFunctionName(Info.FunctionName, Inlined); 114 StringRef Filename = Info.FileName; 115 if (Filename == DILineInfo::BadString) 116 Filename = DILineInfo::Addr2LineBadString; 117 if (Config.Verbose) 118 printVerbose(Filename, Info); 119 else 120 printSimpleLocation(Filename, Info); 121 } 122 123 void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) { 124 printHeader(Request.Address); 125 print(Info, false); 126 printFooter(); 127 } 128 129 void PlainPrinterBase::print(const Request &Request, 130 const DIInliningInfo &Info) { 131 printHeader(Request.Address); 132 uint32_t FramesNum = Info.getNumberOfFrames(); 133 if (FramesNum == 0) 134 print(DILineInfo(), false); 135 else 136 for (uint32_t I = 0; I < FramesNum; ++I) 137 print(Info.getFrame(I), I > 0); 138 printFooter(); 139 } 140 141 void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) { 142 printHeader(Request.Address); 143 StringRef Name = Global.Name; 144 if (Name == DILineInfo::BadString) 145 Name = DILineInfo::Addr2LineBadString; 146 OS << Name << "\n"; 147 OS << Global.Start << " " << Global.Size << "\n"; 148 printFooter(); 149 } 150 151 void PlainPrinterBase::print(const Request &Request, 152 const std::vector<DILocal> &Locals) { 153 printHeader(Request.Address); 154 if (Locals.empty()) 155 OS << DILineInfo::Addr2LineBadString << '\n'; 156 else 157 for (const DILocal &L : Locals) { 158 if (L.FunctionName.empty()) 159 OS << DILineInfo::Addr2LineBadString; 160 else 161 OS << L.FunctionName; 162 OS << '\n'; 163 164 if (L.Name.empty()) 165 OS << DILineInfo::Addr2LineBadString; 166 else 167 OS << L.Name; 168 OS << '\n'; 169 170 if (L.DeclFile.empty()) 171 OS << DILineInfo::Addr2LineBadString; 172 else 173 OS << L.DeclFile; 174 175 OS << ':' << L.DeclLine << '\n'; 176 177 if (L.FrameOffset) 178 OS << *L.FrameOffset; 179 else 180 OS << DILineInfo::Addr2LineBadString; 181 OS << ' '; 182 183 if (L.Size) 184 OS << *L.Size; 185 else 186 OS << DILineInfo::Addr2LineBadString; 187 OS << ' '; 188 189 if (L.TagOffset) 190 OS << *L.TagOffset; 191 else 192 OS << DILineInfo::Addr2LineBadString; 193 OS << '\n'; 194 } 195 printFooter(); 196 } 197 198 void PlainPrinterBase::printInvalidCommand(const Request &Request, 199 const ErrorInfoBase &ErrorInfo) { 200 OS << ErrorInfo.message() << '\n'; 201 } 202 203 bool PlainPrinterBase::printError(const Request &Request, 204 const ErrorInfoBase &ErrorInfo, 205 StringRef ErrorBanner) { 206 ES << ErrorBanner; 207 ErrorInfo.log(ES); 208 ES << '\n'; 209 // Print an empty struct too. 210 return true; 211 } 212 213 } // end namespace symbolize 214 } // end namespace llvm 215