1 //===- FunctionInfo.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 #include "llvm/DebugInfo/GSYM/FunctionInfo.h" 10 #include "llvm/DebugInfo/GSYM/FileWriter.h" 11 #include "llvm/DebugInfo/GSYM/LineTable.h" 12 #include "llvm/DebugInfo/GSYM/InlineInfo.h" 13 #include "llvm/Support/DataExtractor.h" 14 15 using namespace llvm; 16 using namespace gsym; 17 18 /// FunctionInfo information type that is used to encode the optional data 19 /// that is associated with a FunctionInfo object. 20 enum InfoType : uint32_t { 21 EndOfList = 0u, 22 LineTableInfo = 1u, 23 InlineInfo = 2u 24 }; 25 26 raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const FunctionInfo &FI) { 27 OS << '[' << HEX64(FI.Range.Start) << '-' << HEX64(FI.Range.End) << "): " 28 << "Name=" << HEX32(FI.Name) << '\n' << FI.OptLineTable << FI.Inline; 29 return OS; 30 } 31 32 llvm::Expected<FunctionInfo> FunctionInfo::decode(DataExtractor &Data, 33 uint64_t BaseAddr) { 34 FunctionInfo FI; 35 FI.Range.Start = BaseAddr; 36 uint64_t Offset = 0; 37 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 38 return createStringError(std::errc::io_error, 39 "0x%8.8" PRIx64 ": missing FunctionInfo Size", Offset); 40 FI.Range.End = FI.Range.Start + Data.getU32(&Offset); 41 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 42 return createStringError(std::errc::io_error, 43 "0x%8.8" PRIx64 ": missing FunctionInfo Name", Offset); 44 FI.Name = Data.getU32(&Offset); 45 if (FI.Name == 0) 46 return createStringError(std::errc::io_error, 47 "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x%8.8x", 48 Offset - 4, FI.Name); 49 bool Done = false; 50 while (!Done) { 51 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 52 return createStringError(std::errc::io_error, 53 "0x%8.8" PRIx64 ": missing FunctionInfo InfoType value", Offset); 54 const uint32_t IT = Data.getU32(&Offset); 55 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 56 return createStringError(std::errc::io_error, 57 "0x%8.8" PRIx64 ": missing FunctionInfo InfoType length", Offset); 58 const uint32_t InfoLength = Data.getU32(&Offset); 59 if (!Data.isValidOffsetForDataOfSize(Offset, InfoLength)) 60 return createStringError(std::errc::io_error, 61 "0x%8.8" PRIx64 ": missing FunctionInfo data for InfoType %u", 62 Offset, IT); 63 DataExtractor InfoData(Data.getData().substr(Offset, InfoLength), 64 Data.isLittleEndian(), 65 Data.getAddressSize()); 66 switch (IT) { 67 case InfoType::EndOfList: 68 Done = true; 69 break; 70 71 case InfoType::LineTableInfo: 72 if (Expected<LineTable> LT = LineTable::decode(InfoData, BaseAddr)) 73 FI.OptLineTable = std::move(LT.get()); 74 else 75 return LT.takeError(); 76 break; 77 78 case InfoType::InlineInfo: 79 if (Expected<InlineInfo> II = InlineInfo::decode(InfoData, BaseAddr)) 80 FI.Inline = std::move(II.get()); 81 else 82 return II.takeError(); 83 break; 84 85 default: 86 return createStringError(std::errc::io_error, 87 "0x%8.8" PRIx64 ": unsupported InfoType %u", 88 Offset-8, IT); 89 } 90 Offset += InfoLength; 91 } 92 return std::move(FI); 93 } 94 95 llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &O) const { 96 if (!isValid()) 97 return createStringError(std::errc::invalid_argument, 98 "attempted to encode invalid FunctionInfo object"); 99 // Align FunctionInfo data to a 4 byte alignment. 100 O.alignTo(4); 101 const uint64_t FuncInfoOffset = O.tell(); 102 // Write the size in bytes of this function as a uint32_t. This can be zero 103 // if we just have a symbol from a symbol table and that symbol has no size. 104 O.writeU32(size()); 105 // Write the name of this function as a uint32_t string table offset. 106 O.writeU32(Name); 107 108 if (OptLineTable.hasValue()) { 109 O.writeU32(InfoType::LineTableInfo); 110 // Write a uint32_t length as zero for now, we will fix this up after 111 // writing the LineTable out with the number of bytes that were written. 112 O.writeU32(0); 113 const auto StartOffset = O.tell(); 114 llvm::Error err = OptLineTable->encode(O, Range.Start); 115 if (err) 116 return std::move(err); 117 const off_t Length = O.tell() - StartOffset; 118 if (Length > UINT32_MAX) 119 return createStringError(std::errc::invalid_argument, 120 "LineTable length is greater than UINT32_MAX"); 121 // Fixup the size of the LineTable data with the correct size. 122 O.fixup32(static_cast<uint32_t>(Length), StartOffset - 4); 123 } 124 125 // Write out the inline function info if we have any and if it is valid. 126 if (Inline.hasValue()) { 127 O.writeU32(InfoType::InlineInfo); 128 // Write a uint32_t length as zero for now, we will fix this up after 129 // writing the LineTable out with the number of bytes that were written. 130 O.writeU32(0); 131 const auto StartOffset = O.tell(); 132 llvm::Error err = Inline->encode(O, Range.Start); 133 if (err) 134 return std::move(err); 135 const off_t Length = O.tell() - StartOffset; 136 if (Length > UINT32_MAX) 137 return createStringError(std::errc::invalid_argument, 138 "InlineInfo length is greater than UINT32_MAX"); 139 // Fixup the size of the InlineInfo data with the correct size. 140 O.fixup32(static_cast<uint32_t>(Length), StartOffset - 4); 141 } 142 143 // Terminate the data chunks with and end of list with zero size 144 O.writeU32(InfoType::EndOfList); 145 O.writeU32(0); 146 return FuncInfoOffset; 147 } 148