]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / DebugInfo / GSYM / FunctionInfo.cpp
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/GsymReader.h"
12 #include "llvm/DebugInfo/GSYM/LineTable.h"
13 #include "llvm/DebugInfo/GSYM/InlineInfo.h"
14 #include "llvm/Support/DataExtractor.h"
15
16 using namespace llvm;
17 using namespace gsym;
18
19 /// FunctionInfo information type that is used to encode the optional data
20 /// that is associated with a FunctionInfo object.
21 enum InfoType : uint32_t {
22   EndOfList = 0u,
23   LineTableInfo = 1u,
24   InlineInfo = 2u
25 };
26
27 raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const FunctionInfo &FI) {
28   OS << '[' << HEX64(FI.Range.Start) << '-' << HEX64(FI.Range.End) << "): "
29      << "Name=" << HEX32(FI.Name) << '\n' << FI.OptLineTable << FI.Inline;
30   return OS;
31 }
32
33 llvm::Expected<FunctionInfo> FunctionInfo::decode(DataExtractor &Data,
34                                                   uint64_t BaseAddr) {
35   FunctionInfo FI;
36   FI.Range.Start = BaseAddr;
37   uint64_t Offset = 0;
38   if (!Data.isValidOffsetForDataOfSize(Offset, 4))
39     return createStringError(std::errc::io_error,
40         "0x%8.8" PRIx64 ": missing FunctionInfo Size", Offset);
41   FI.Range.End = FI.Range.Start + Data.getU32(&Offset);
42   if (!Data.isValidOffsetForDataOfSize(Offset, 4))
43     return createStringError(std::errc::io_error,
44         "0x%8.8" PRIx64 ": missing FunctionInfo Name", Offset);
45   FI.Name = Data.getU32(&Offset);
46   if (FI.Name == 0)
47     return createStringError(std::errc::io_error,
48         "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x%8.8x",
49         Offset - 4, FI.Name);
50   bool Done = false;
51   while (!Done) {
52     if (!Data.isValidOffsetForDataOfSize(Offset, 4))
53       return createStringError(std::errc::io_error,
54           "0x%8.8" PRIx64 ": missing FunctionInfo InfoType value", Offset);
55     const uint32_t IT = Data.getU32(&Offset);
56     if (!Data.isValidOffsetForDataOfSize(Offset, 4))
57       return createStringError(std::errc::io_error,
58           "0x%8.8" PRIx64 ": missing FunctionInfo InfoType length", Offset);
59     const uint32_t InfoLength = Data.getU32(&Offset);
60     if (!Data.isValidOffsetForDataOfSize(Offset, InfoLength))
61       return createStringError(std::errc::io_error,
62           "0x%8.8" PRIx64 ": missing FunctionInfo data for InfoType %u",
63           Offset, IT);
64     DataExtractor InfoData(Data.getData().substr(Offset, InfoLength),
65                            Data.isLittleEndian(),
66                            Data.getAddressSize());
67     switch (IT) {
68       case InfoType::EndOfList:
69         Done = true;
70         break;
71
72       case InfoType::LineTableInfo:
73         if (Expected<LineTable> LT = LineTable::decode(InfoData, BaseAddr))
74           FI.OptLineTable = std::move(LT.get());
75         else
76           return LT.takeError();
77         break;
78
79       case InfoType::InlineInfo:
80         if (Expected<InlineInfo> II = InlineInfo::decode(InfoData, BaseAddr))
81           FI.Inline = std::move(II.get());
82         else
83           return II.takeError();
84         break;
85
86       default:
87         return createStringError(std::errc::io_error,
88                                  "0x%8.8" PRIx64 ": unsupported InfoType %u",
89                                  Offset-8, IT);
90     }
91     Offset += InfoLength;
92   }
93   return std::move(FI);
94 }
95
96 llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &O) const {
97   if (!isValid())
98     return createStringError(std::errc::invalid_argument,
99         "attempted to encode invalid FunctionInfo object");
100   // Align FunctionInfo data to a 4 byte alignment.
101   O.alignTo(4);
102   const uint64_t FuncInfoOffset = O.tell();
103   // Write the size in bytes of this function as a uint32_t. This can be zero
104   // if we just have a symbol from a symbol table and that symbol has no size.
105   O.writeU32(size());
106   // Write the name of this function as a uint32_t string table offset.
107   O.writeU32(Name);
108
109   if (OptLineTable.hasValue()) {
110     O.writeU32(InfoType::LineTableInfo);
111     // Write a uint32_t length as zero for now, we will fix this up after
112     // writing the LineTable out with the number of bytes that were written.
113     O.writeU32(0);
114     const auto StartOffset = O.tell();
115     llvm::Error err = OptLineTable->encode(O, Range.Start);
116     if (err)
117       return std::move(err);
118     const auto Length = O.tell() - StartOffset;
119     if (Length > UINT32_MAX)
120         return createStringError(std::errc::invalid_argument,
121             "LineTable length is greater than UINT32_MAX");
122     // Fixup the size of the LineTable data with the correct size.
123     O.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
124   }
125
126   // Write out the inline function info if we have any and if it is valid.
127   if (Inline.hasValue()) {
128     O.writeU32(InfoType::InlineInfo);
129     // Write a uint32_t length as zero for now, we will fix this up after
130     // writing the LineTable out with the number of bytes that were written.
131     O.writeU32(0);
132     const auto StartOffset = O.tell();
133     llvm::Error err = Inline->encode(O, Range.Start);
134     if (err)
135       return std::move(err);
136     const auto Length = O.tell() - StartOffset;
137     if (Length > UINT32_MAX)
138         return createStringError(std::errc::invalid_argument,
139             "InlineInfo length is greater than UINT32_MAX");
140     // Fixup the size of the InlineInfo data with the correct size.
141     O.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
142   }
143
144   // Terminate the data chunks with and end of list with zero size
145   O.writeU32(InfoType::EndOfList);
146   O.writeU32(0);
147   return FuncInfoOffset;
148 }
149
150
151 llvm::Expected<LookupResult> FunctionInfo::lookup(DataExtractor &Data,
152                                                   const GsymReader &GR,
153                                                   uint64_t FuncAddr,
154                                                   uint64_t Addr) {
155   LookupResult LR;
156   LR.LookupAddr = Addr;
157   LR.FuncRange.Start = FuncAddr;
158   uint64_t Offset = 0;
159   LR.FuncRange.End = FuncAddr + Data.getU32(&Offset);
160   uint32_t NameOffset = Data.getU32(&Offset);
161   // The "lookup" functions doesn't report errors as accurately as the "decode"
162   // function as it is meant to be fast. For more accurage errors we could call
163   // "decode".
164   if (!Data.isValidOffset(Offset))
165     return createStringError(std::errc::io_error,
166                               "FunctionInfo data is truncated");
167   // This function will be called with the result of a binary search of the
168   // address table, we must still make sure the address does not fall into a
169   // gap between functions are after the last function.
170   if (Addr >= LR.FuncRange.End)
171     return createStringError(std::errc::io_error,
172         "address 0x%" PRIx64 " is not in GSYM", Addr);
173
174   if (NameOffset == 0)
175     return createStringError(std::errc::io_error,
176         "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x00000000",
177         Offset - 4);
178   LR.FuncName = GR.getString(NameOffset);
179   bool Done = false;
180   Optional<LineEntry> LineEntry;
181   Optional<DataExtractor> InlineInfoData;
182   while (!Done) {
183     if (!Data.isValidOffsetForDataOfSize(Offset, 8))
184       return createStringError(std::errc::io_error,
185                                "FunctionInfo data is truncated");
186     const uint32_t IT = Data.getU32(&Offset);
187     const uint32_t InfoLength = Data.getU32(&Offset);
188     const StringRef InfoBytes = Data.getData().substr(Offset, InfoLength);
189     if (InfoLength != InfoBytes.size())
190       return createStringError(std::errc::io_error,
191                                "FunctionInfo data is truncated");
192     DataExtractor InfoData(InfoBytes, Data.isLittleEndian(),
193                            Data.getAddressSize());
194     switch (IT) {
195       case InfoType::EndOfList:
196         Done = true;
197         break;
198
199       case InfoType::LineTableInfo:
200         if (auto ExpectedLE = LineTable::lookup(InfoData, FuncAddr, Addr))
201           LineEntry = ExpectedLE.get();
202         else
203           return ExpectedLE.takeError();
204         break;
205
206       case InfoType::InlineInfo:
207         // We will parse the inline info after our line table, but only if
208         // we have a line entry.
209         InlineInfoData = InfoData;
210         break;
211
212       default:
213         break;
214     }
215     Offset += InfoLength;
216   }
217
218   if (!LineEntry) {
219     // We don't have a valid line entry for our address, fill in our source
220     // location as best we can and return.
221     SourceLocation SrcLoc;
222     SrcLoc.Name = LR.FuncName;
223     LR.Locations.push_back(SrcLoc);
224     return LR;
225   }
226
227   Optional<FileEntry> LineEntryFile = GR.getFile(LineEntry->File);
228   if (!LineEntryFile)
229     return createStringError(std::errc::invalid_argument,
230                               "failed to extract file[%" PRIu32 "]",
231                               LineEntry->File);
232
233   SourceLocation SrcLoc;
234   SrcLoc.Name = LR.FuncName;
235   SrcLoc.Dir = GR.getString(LineEntryFile->Dir);
236   SrcLoc.Base = GR.getString(LineEntryFile->Base);
237   SrcLoc.Line = LineEntry->Line;
238   LR.Locations.push_back(SrcLoc);
239   // If we don't have inline information, we are done.
240   if (!InlineInfoData)
241     return LR;
242   // We have inline information. Try to augment the lookup result with this
243   // data.
244   llvm::Error Err = InlineInfo::lookup(GR, *InlineInfoData, FuncAddr, Addr,
245                                        LR.Locations);
246   if (Err)
247     return std::move(Err);
248   return LR;
249 }