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 filename: " << Info.StartFileName << "\n"; 89 OS << " Function start line: " << Info.StartLine << "\n"; 90 } 91 OS << " Line: " << Info.Line << "\n"; 92 OS << " Column: " << Info.Column << "\n"; 93 if (Info.Discriminator) 94 OS << " Discriminator: " << Info.Discriminator << "\n"; 95 } 96 97 DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) { 98 print(Info, false); 99 return *this; 100 } 101 102 DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) { 103 uint32_t FramesNum = Info.getNumberOfFrames(); 104 if (FramesNum == 0) { 105 print(DILineInfo(), false); 106 return *this; 107 } 108 for (uint32_t i = 0; i < FramesNum; i++) 109 print(Info.getFrame(i), i > 0); 110 return *this; 111 } 112 113 DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) { 114 std::string Name = Global.Name; 115 if (Name == DILineInfo::BadString) 116 Name = DILineInfo::Addr2LineBadString; 117 OS << Name << "\n"; 118 OS << Global.Start << " " << Global.Size << "\n"; 119 return *this; 120 } 121 122 DIPrinter &DIPrinter::operator<<(const DILocal &Local) { 123 if (Local.FunctionName.empty()) 124 OS << "??\n"; 125 else 126 OS << Local.FunctionName << '\n'; 127 128 if (Local.Name.empty()) 129 OS << "??\n"; 130 else 131 OS << Local.Name << '\n'; 132 133 if (Local.DeclFile.empty()) 134 OS << "??"; 135 else 136 OS << Local.DeclFile; 137 OS << ':' << Local.DeclLine << '\n'; 138 139 if (Local.FrameOffset) 140 OS << *Local.FrameOffset << ' '; 141 else 142 OS << "?? "; 143 144 if (Local.Size) 145 OS << *Local.Size << ' '; 146 else 147 OS << "?? "; 148 149 if (Local.TagOffset) 150 OS << *Local.TagOffset << '\n'; 151 else 152 OS << "??\n"; 153 return *this; 154 } 155 156 } // end namespace symbolize 157 } // end namespace llvm 158