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