]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
Merge r357342 from the clang1000-import branch:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / DebugInfo / Symbolize / SymbolizableObjectFile.cpp
1 //===- SymbolizableObjectFile.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 // Implementation of SymbolizableObjectFile class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "SymbolizableObjectFile.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/ADT/Triple.h"
17 #include "llvm/BinaryFormat/COFF.h"
18 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
19 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
20 #include "llvm/Object/COFF.h"
21 #include "llvm/Object/ObjectFile.h"
22 #include "llvm/Object/SymbolSize.h"
23 #include "llvm/Support/Casting.h"
24 #include "llvm/Support/DataExtractor.h"
25 #include "llvm/Support/Error.h"
26 #include <algorithm>
27 #include <cstdint>
28 #include <memory>
29 #include <string>
30 #include <system_error>
31 #include <utility>
32 #include <vector>
33
34 using namespace llvm;
35 using namespace object;
36 using namespace symbolize;
37
38 static DILineInfoSpecifier
39 getDILineInfoSpecifier(FunctionNameKind FNKind) {
40   return DILineInfoSpecifier(
41       DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FNKind);
42 }
43
44 ErrorOr<std::unique_ptr<SymbolizableObjectFile>>
45 SymbolizableObjectFile::create(const object::ObjectFile *Obj,
46                                std::unique_ptr<DIContext> DICtx) {
47   assert(DICtx);
48   std::unique_ptr<SymbolizableObjectFile> res(
49       new SymbolizableObjectFile(Obj, std::move(DICtx)));
50   std::unique_ptr<DataExtractor> OpdExtractor;
51   uint64_t OpdAddress = 0;
52   // Find the .opd (function descriptor) section if any, for big-endian
53   // PowerPC64 ELF.
54   if (Obj->getArch() == Triple::ppc64) {
55     for (section_iterator Section : Obj->sections()) {
56       StringRef Name;
57       if (auto EC = Section->getName(Name))
58         return EC;
59       if (Name == ".opd") {
60         Expected<StringRef> E = Section->getContents();
61         if (!E)
62           return errorToErrorCode(E.takeError());
63         OpdExtractor.reset(new DataExtractor(*E, Obj->isLittleEndian(),
64                                              Obj->getBytesInAddress()));
65         OpdAddress = Section->getAddress();
66         break;
67       }
68     }
69   }
70   std::vector<std::pair<SymbolRef, uint64_t>> Symbols =
71       computeSymbolSizes(*Obj);
72   for (auto &P : Symbols)
73     res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress);
74
75   // If this is a COFF object and we didn't find any symbols, try the export
76   // table.
77   if (Symbols.empty()) {
78     if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj))
79       if (auto EC = res->addCoffExportSymbols(CoffObj))
80         return EC;
81   }
82
83   std::vector<std::pair<SymbolDesc, StringRef>> &Fs = res->Functions,
84                                                 &Os = res->Objects;
85   auto Uniquify = [](std::vector<std::pair<SymbolDesc, StringRef>> &S) {
86     // Sort by (Addr,Size,Name). If several SymbolDescs share the same Addr,
87     // pick the one with the largest Size. This helps us avoid symbols with no
88     // size information (Size=0).
89     llvm::sort(S);
90     auto I = S.begin(), E = S.end(), J = S.begin();
91     while (I != E) {
92       auto OI = I;
93       while (++I != E && OI->first.Addr == I->first.Addr) {
94       }
95       *J++ = I[-1];
96     }
97     S.erase(J, S.end());
98   };
99   Uniquify(Fs);
100   Uniquify(Os);
101
102   return std::move(res);
103 }
104
105 SymbolizableObjectFile::SymbolizableObjectFile(const ObjectFile *Obj,
106                                                std::unique_ptr<DIContext> DICtx)
107     : Module(Obj), DebugInfoContext(std::move(DICtx)) {}
108
109 namespace {
110
111 struct OffsetNamePair {
112   uint32_t Offset;
113   StringRef Name;
114
115   bool operator<(const OffsetNamePair &R) const {
116     return Offset < R.Offset;
117   }
118 };
119
120 } // end anonymous namespace
121
122 std::error_code SymbolizableObjectFile::addCoffExportSymbols(
123     const COFFObjectFile *CoffObj) {
124   // Get all export names and offsets.
125   std::vector<OffsetNamePair> ExportSyms;
126   for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
127     StringRef Name;
128     uint32_t Offset;
129     if (auto EC = Ref.getSymbolName(Name))
130       return EC;
131     if (auto EC = Ref.getExportRVA(Offset))
132       return EC;
133     ExportSyms.push_back(OffsetNamePair{Offset, Name});
134   }
135   if (ExportSyms.empty())
136     return std::error_code();
137
138   // Sort by ascending offset.
139   array_pod_sort(ExportSyms.begin(), ExportSyms.end());
140
141   // Approximate the symbol sizes by assuming they run to the next symbol.
142   // FIXME: This assumes all exports are functions.
143   uint64_t ImageBase = CoffObj->getImageBase();
144   for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {
145     OffsetNamePair &Export = *I;
146     // FIXME: The last export has a one byte size now.
147     uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
148     uint64_t SymbolStart = ImageBase + Export.Offset;
149     uint64_t SymbolSize = NextOffset - Export.Offset;
150     SymbolDesc SD = {SymbolStart, SymbolSize};
151     Functions.emplace_back(SD, Export.Name);
152   }
153   return std::error_code();
154 }
155
156 std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
157                                                   uint64_t SymbolSize,
158                                                   DataExtractor *OpdExtractor,
159                                                   uint64_t OpdAddress) {
160   // Avoid adding symbols from an unknown/undefined section.
161   const ObjectFile *Obj = Symbol.getObject();
162   Expected<section_iterator> Sec = Symbol.getSection();
163   if (!Sec || (Obj && Obj->section_end() == *Sec))
164     return std::error_code();
165   Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
166   if (!SymbolTypeOrErr)
167     return errorToErrorCode(SymbolTypeOrErr.takeError());
168   SymbolRef::Type SymbolType = *SymbolTypeOrErr;
169   if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
170     return std::error_code();
171   Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
172   if (!SymbolAddressOrErr)
173     return errorToErrorCode(SymbolAddressOrErr.takeError());
174   uint64_t SymbolAddress = *SymbolAddressOrErr;
175   if (OpdExtractor) {
176     // For big-endian PowerPC64 ELF, symbols in the .opd section refer to
177     // function descriptors. The first word of the descriptor is a pointer to
178     // the function's code.
179     // For the purposes of symbolization, pretend the symbol's address is that
180     // of the function's code, not the descriptor.
181     uint64_t OpdOffset = SymbolAddress - OpdAddress;
182     uint32_t OpdOffset32 = OpdOffset;
183     if (OpdOffset == OpdOffset32 &&
184         OpdExtractor->isValidOffsetForAddress(OpdOffset32))
185       SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
186   }
187   Expected<StringRef> SymbolNameOrErr = Symbol.getName();
188   if (!SymbolNameOrErr)
189     return errorToErrorCode(SymbolNameOrErr.takeError());
190   StringRef SymbolName = *SymbolNameOrErr;
191   // Mach-O symbol table names have leading underscore, skip it.
192   if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
193     SymbolName = SymbolName.drop_front();
194   // FIXME: If a function has alias, there are two entries in symbol table
195   // with same address size. Make sure we choose the correct one.
196   auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
197   SymbolDesc SD = { SymbolAddress, SymbolSize };
198   M.emplace_back(SD, SymbolName);
199   return std::error_code();
200 }
201
202 // Return true if this is a 32-bit x86 PE COFF module.
203 bool SymbolizableObjectFile::isWin32Module() const {
204   auto *CoffObject = dyn_cast<COFFObjectFile>(Module);
205   return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
206 }
207
208 uint64_t SymbolizableObjectFile::getModulePreferredBase() const {
209   if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
210     return CoffObject->getImageBase();
211   return 0;
212 }
213
214 bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type,
215                                                     uint64_t Address,
216                                                     std::string &Name,
217                                                     uint64_t &Addr,
218                                                     uint64_t &Size) const {
219   const auto &Symbols = Type == SymbolRef::ST_Function ? Functions : Objects;
220   std::pair<SymbolDesc, StringRef> SD{{Address, UINT64_C(-1)}, StringRef()};
221   auto SymbolIterator = llvm::upper_bound(Symbols, SD);
222   if (SymbolIterator == Symbols.begin())
223     return false;
224   --SymbolIterator;
225   if (SymbolIterator->first.Size != 0 &&
226       SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
227     return false;
228   Name = SymbolIterator->second.str();
229   Addr = SymbolIterator->first.Addr;
230   Size = SymbolIterator->first.Size;
231   return true;
232 }
233
234 bool SymbolizableObjectFile::shouldOverrideWithSymbolTable(
235     FunctionNameKind FNKind, bool UseSymbolTable) const {
236   // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives
237   // better answers for linkage names than the DIContext. Otherwise, we are
238   // probably using PEs and PDBs, and we shouldn't do the override. PE files
239   // generally only contain the names of exported symbols.
240   return FNKind == FunctionNameKind::LinkageName && UseSymbolTable &&
241          isa<DWARFContext>(DebugInfoContext.get());
242 }
243
244 DILineInfo
245 SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
246                                       FunctionNameKind FNKind,
247                                       bool UseSymbolTable) const {
248   if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
249     ModuleOffset.SectionIndex =
250         getModuleSectionIndexForAddress(ModuleOffset.Address);
251   DILineInfo LineInfo = DebugInfoContext->getLineInfoForAddress(
252       ModuleOffset, getDILineInfoSpecifier(FNKind));
253
254   // Override function name from symbol table if necessary.
255   if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
256     std::string FunctionName;
257     uint64_t Start, Size;
258     if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
259                                FunctionName, Start, Size)) {
260       LineInfo.FunctionName = FunctionName;
261     }
262   }
263   return LineInfo;
264 }
265
266 DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
267     object::SectionedAddress ModuleOffset, FunctionNameKind FNKind,
268     bool UseSymbolTable) const {
269   if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
270     ModuleOffset.SectionIndex =
271         getModuleSectionIndexForAddress(ModuleOffset.Address);
272   DIInliningInfo InlinedContext = DebugInfoContext->getInliningInfoForAddress(
273       ModuleOffset, getDILineInfoSpecifier(FNKind));
274
275   // Make sure there is at least one frame in context.
276   if (InlinedContext.getNumberOfFrames() == 0)
277     InlinedContext.addFrame(DILineInfo());
278
279   // Override the function name in lower frame with name from symbol table.
280   if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
281     std::string FunctionName;
282     uint64_t Start, Size;
283     if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
284                                FunctionName, Start, Size)) {
285       InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1)
286           ->FunctionName = FunctionName;
287     }
288   }
289
290   return InlinedContext;
291 }
292
293 DIGlobal SymbolizableObjectFile::symbolizeData(
294     object::SectionedAddress ModuleOffset) const {
295   DIGlobal Res;
296   getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset.Address, Res.Name,
297                          Res.Start, Res.Size);
298   return Res;
299 }
300
301 std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame(
302     object::SectionedAddress ModuleOffset) const {
303   if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
304     ModuleOffset.SectionIndex =
305         getModuleSectionIndexForAddress(ModuleOffset.Address);
306   return DebugInfoContext->getLocalsForAddress(ModuleOffset);
307 }
308
309 /// Search for the first occurence of specified Address in ObjectFile.
310 uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress(
311     uint64_t Address) const {
312
313   for (SectionRef Sec : Module->sections()) {
314     if (!Sec.isText() || Sec.isVirtual())
315       continue;
316
317     if (Address >= Sec.getAddress() &&
318         Address < Sec.getAddress() + Sec.getSize())
319       return Sec.getIndex();
320   }
321
322   return object::SectionedAddress::UndefSection;
323 }