1 //===- InlineInfo.cpp -------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/DebugInfo/GSYM/FileEntry.h" 11 #include "llvm/DebugInfo/GSYM/FileWriter.h" 12 #include "llvm/DebugInfo/GSYM/InlineInfo.h" 13 #include "llvm/Support/DataExtractor.h" 14 #include <algorithm> 15 #include <inttypes.h> 16 17 using namespace llvm; 18 using namespace gsym; 19 20 21 raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const InlineInfo &II) { 22 if (!II.isValid()) 23 return OS; 24 bool First = true; 25 for (auto Range : II.Ranges) { 26 if (First) 27 First = false; 28 else 29 OS << ' '; 30 OS << Range; 31 } 32 OS << " Name = " << HEX32(II.Name) << ", CallFile = " << II.CallFile 33 << ", CallLine = " << II.CallFile << '\n'; 34 for (const auto &Child : II.Children) 35 OS << Child; 36 return OS; 37 } 38 39 static bool getInlineStackHelper(const InlineInfo &II, uint64_t Addr, 40 std::vector<const InlineInfo *> &InlineStack) { 41 if (II.Ranges.contains(Addr)) { 42 // If this is the top level that represents the concrete function, 43 // there will be no name and we shoud clear the inline stack. Otherwise 44 // we have found an inline call stack that we need to insert. 45 if (II.Name != 0) 46 InlineStack.insert(InlineStack.begin(), &II); 47 for (const auto &Child : II.Children) { 48 if (::getInlineStackHelper(Child, Addr, InlineStack)) 49 break; 50 } 51 return !InlineStack.empty(); 52 } 53 return false; 54 } 55 56 llvm::Optional<InlineInfo::InlineArray> InlineInfo::getInlineStack(uint64_t Addr) const { 57 InlineArray Result; 58 if (getInlineStackHelper(*this, Addr, Result)) 59 return Result; 60 return llvm::None; 61 } 62 63 /// Decode an InlineInfo in Data at the specified offset. 64 /// 65 /// A local helper function to decode InlineInfo objects. This function is 66 /// called recursively when parsing child InlineInfo objects. 67 /// 68 /// \param Data The data extractor to decode from. 69 /// \param Offset The offset within \a Data to decode from. 70 /// \param BaseAddr The base address to use when decoding address ranges. 71 /// \returns An InlineInfo or an error describing the issue that was 72 /// encountered during decoding. 73 static llvm::Expected<InlineInfo> decode(DataExtractor &Data, uint64_t &Offset, 74 uint64_t BaseAddr) { 75 InlineInfo Inline; 76 if (!Data.isValidOffset(Offset)) 77 return createStringError(std::errc::io_error, 78 "0x%8.8" PRIx64 ": missing InlineInfo address ranges data", Offset); 79 Inline.Ranges.decode(Data, BaseAddr, Offset); 80 if (Inline.Ranges.empty()) 81 return Inline; 82 if (!Data.isValidOffsetForDataOfSize(Offset, 1)) 83 return createStringError(std::errc::io_error, 84 "0x%8.8" PRIx64 ": missing InlineInfo uint8_t indicating children", 85 Offset); 86 bool HasChildren = Data.getU8(&Offset) != 0; 87 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 88 return createStringError(std::errc::io_error, 89 "0x%8.8" PRIx64 ": missing InlineInfo uint32_t for name", Offset); 90 Inline.Name = Data.getU32(&Offset); 91 if (!Data.isValidOffset(Offset)) 92 return createStringError(std::errc::io_error, 93 "0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call file", Offset); 94 Inline.CallFile = (uint32_t)Data.getULEB128(&Offset); 95 if (!Data.isValidOffset(Offset)) 96 return createStringError(std::errc::io_error, 97 "0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call line", Offset); 98 Inline.CallLine = (uint32_t)Data.getULEB128(&Offset); 99 if (HasChildren) { 100 // Child address ranges are encoded relative to the first address in the 101 // parent InlineInfo object. 102 const auto ChildBaseAddr = Inline.Ranges[0].Start; 103 while (true) { 104 llvm::Expected<InlineInfo> Child = decode(Data, Offset, ChildBaseAddr); 105 if (!Child) 106 return Child.takeError(); 107 // InlineInfo with empty Ranges termintes a child sibling chain. 108 if (Child.get().Ranges.empty()) 109 break; 110 Inline.Children.emplace_back(std::move(*Child)); 111 } 112 } 113 return Inline; 114 } 115 116 llvm::Expected<InlineInfo> InlineInfo::decode(DataExtractor &Data, 117 uint64_t BaseAddr) { 118 uint64_t Offset = 0; 119 return ::decode(Data, Offset, BaseAddr); 120 } 121 122 llvm::Error InlineInfo::encode(FileWriter &O, uint64_t BaseAddr) const { 123 // Users must verify the InlineInfo is valid prior to calling this funtion. 124 // We don't want to emit any InlineInfo objects if they are not valid since 125 // it will waste space in the GSYM file. 126 if (!isValid()) 127 return createStringError(std::errc::invalid_argument, 128 "attempted to encode invalid InlineInfo object"); 129 Ranges.encode(O, BaseAddr); 130 bool HasChildren = !Children.empty(); 131 O.writeU8(HasChildren); 132 O.writeU32(Name); 133 O.writeULEB(CallFile); 134 O.writeULEB(CallLine); 135 if (HasChildren) { 136 // Child address ranges are encoded as relative to the first 137 // address in the Ranges for this object. This keeps the offsets 138 // small and allows for efficient encoding using ULEB offsets. 139 const uint64_t ChildBaseAddr = Ranges[0].Start; 140 for (const auto &Child : Children) { 141 // Make sure all child address ranges are contained in the parent address 142 // ranges. 143 for (const auto &ChildRange: Child.Ranges) { 144 if (!Ranges.contains(ChildRange)) 145 return createStringError(std::errc::invalid_argument, 146 "child range not contained in parent"); 147 } 148 llvm::Error Err = Child.encode(O, ChildBaseAddr); 149 if (Err) 150 return Err; 151 } 152 153 // Terminate child sibling chain by emitting a zero. This zero will cause 154 // the decodeAll() function above to return false and stop the decoding 155 // of child InlineInfo objects that are siblings. 156 O.writeULEB(0); 157 } 158 return Error::success(); 159 } 160