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 // By default, DILineInfo contains "<invalid>" for function/filename it 34 // cannot fetch. We replace it to "??" to make our output closer to addr2line. 35 static const char kDILineInfoBadString[] = "<invalid>"; 36 static const char kBadString[] = "??"; 37 38 // Prints source code around in the FileName the Line. 39 void DIPrinter::printContext(const std::string &FileName, int64_t Line) { 40 if (PrintSourceContext <= 0) 41 return; 42 43 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 44 MemoryBuffer::getFile(FileName); 45 if (!BufOrErr) 46 return; 47 48 std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get()); 49 int64_t FirstLine = 50 std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2); 51 int64_t LastLine = FirstLine + PrintSourceContext; 52 size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine)); 53 54 for (line_iterator I = line_iterator(*Buf, false); 55 !I.is_at_eof() && I.line_number() <= LastLine; ++I) { 56 int64_t L = I.line_number(); 57 if (L >= FirstLine && L <= LastLine) { 58 OS << format_decimal(L, MaxLineNumberWidth); 59 if (L == Line) 60 OS << " >: "; 61 else 62 OS << " : "; 63 OS << *I << "\n"; 64 } 65 } 66 } 67 68 void DIPrinter::print(const DILineInfo &Info, bool Inlined) { 69 if (PrintFunctionNames) { 70 std::string FunctionName = Info.FunctionName; 71 if (FunctionName == kDILineInfoBadString) 72 FunctionName = kBadString; 73 74 StringRef Delimiter = PrintPretty ? " at " : "\n"; 75 StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : ""; 76 OS << Prefix << FunctionName << Delimiter; 77 } 78 std::string Filename = Info.FileName; 79 if (Filename == kDILineInfoBadString) 80 Filename = kBadString; 81 else if (Basenames) 82 Filename = llvm::sys::path::filename(Filename); 83 if (!Verbose) { 84 OS << Filename << ":" << Info.Line; 85 if (Style == OutputStyle::LLVM) 86 OS << ":" << Info.Column; 87 OS << "\n"; 88 printContext(Filename, Info.Line); 89 return; 90 } 91 OS << " Filename: " << Filename << "\n"; 92 if (Info.StartLine) 93 OS << "Function start line: " << Info.StartLine << "\n"; 94 OS << " Line: " << Info.Line << "\n"; 95 OS << " Column: " << Info.Column << "\n"; 96 if (Info.Discriminator) 97 OS << " Discriminator: " << Info.Discriminator << "\n"; 98 } 99 100 DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) { 101 print(Info, false); 102 return *this; 103 } 104 105 DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) { 106 uint32_t FramesNum = Info.getNumberOfFrames(); 107 if (FramesNum == 0) { 108 print(DILineInfo(), false); 109 return *this; 110 } 111 for (uint32_t i = 0; i < FramesNum; i++) 112 print(Info.getFrame(i), i > 0); 113 return *this; 114 } 115 116 DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) { 117 std::string Name = Global.Name; 118 if (Name == kDILineInfoBadString) 119 Name = kBadString; 120 OS << Name << "\n"; 121 OS << Global.Start << " " << Global.Size << "\n"; 122 return *this; 123 } 124 125 DIPrinter &DIPrinter::operator<<(const DILocal &Local) { 126 OS << Local.FunctionName << '\n'; 127 OS << Local.Name << '\n'; 128 if (Local.DeclFile.empty()) 129 OS << "??"; 130 else 131 OS << Local.DeclFile; 132 OS << ':' << Local.DeclLine << '\n'; 133 if (Local.FrameOffset) 134 OS << *Local.FrameOffset << ' '; 135 else 136 OS << "?? "; 137 if (Local.Size) 138 OS << *Local.Size << ' '; 139 else 140 OS << "?? "; 141 if (Local.TagOffset) 142 OS << *Local.TagOffset << '\n'; 143 else 144 OS << "??\n"; 145 return *this; 146 } 147 148 } // end namespace symbolize 149 } // end namespace llvm 150