blob: a92fe123c3b742f915000e7a847ea317a4d8a896 [file] [log] [blame]
Eugene Zelenko44d95122017-02-09 01:09:54 +00001//===- SymbolizableObjectFile.cpp -----------------------------------------===//
Alexey Samsonov8df3a072015-10-29 22:21:37 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Alexey Samsonov8df3a072015-10-29 22:21:37 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Implementation of SymbolizableObjectFile class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "SymbolizableObjectFile.h"
Eugene Zelenko44d95122017-02-09 01:09:54 +000014#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/ADT/Triple.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000017#include "llvm/BinaryFormat/COFF.h"
Reid Klecknerc038e2d2015-11-13 17:00:36 +000018#include "llvm/DebugInfo/DWARF/DWARFContext.h"
Eugene Zelenko44d95122017-02-09 01:09:54 +000019#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
20#include "llvm/Object/COFF.h"
21#include "llvm/Object/ObjectFile.h"
22#include "llvm/Object/SymbolSize.h"
Eugene Zelenko44d95122017-02-09 01:09:54 +000023#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>
Alexey Samsonov8df3a072015-10-29 22:21:37 +000033
Eugene Zelenko44d95122017-02-09 01:09:54 +000034using namespace llvm;
Alexey Samsonov8df3a072015-10-29 22:21:37 +000035using namespace object;
Eugene Zelenko44d95122017-02-09 01:09:54 +000036using namespace symbolize;
Alexey Samsonov8df3a072015-10-29 22:21:37 +000037
38static DILineInfoSpecifier
39getDILineInfoSpecifier(FunctionNameKind FNKind) {
40 return DILineInfoSpecifier(
41 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FNKind);
42}
43
44ErrorOr<std::unique_ptr<SymbolizableObjectFile>>
45SymbolizableObjectFile::create(object::ObjectFile *Obj,
46 std::unique_ptr<DIContext> DICtx) {
47 std::unique_ptr<SymbolizableObjectFile> res(
48 new SymbolizableObjectFile(Obj, std::move(DICtx)));
49 std::unique_ptr<DataExtractor> OpdExtractor;
50 uint64_t OpdAddress = 0;
51 // Find the .opd (function descriptor) section if any, for big-endian
52 // PowerPC64 ELF.
53 if (Obj->getArch() == Triple::ppc64) {
54 for (section_iterator Section : Obj->sections()) {
55 StringRef Name;
56 StringRef Data;
57 if (auto EC = Section->getName(Name))
58 return EC;
59 if (Name == ".opd") {
60 if (auto EC = Section->getContents(Data))
61 return EC;
62 OpdExtractor.reset(new DataExtractor(Data, Obj->isLittleEndian(),
63 Obj->getBytesInAddress()));
64 OpdAddress = Section->getAddress();
65 break;
66 }
67 }
68 }
69 std::vector<std::pair<SymbolRef, uint64_t>> Symbols =
70 computeSymbolSizes(*Obj);
71 for (auto &P : Symbols)
72 res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress);
73
74 // If this is a COFF object and we didn't find any symbols, try the export
75 // table.
76 if (Symbols.empty()) {
77 if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj))
78 if (auto EC = res->addCoffExportSymbols(CoffObj))
79 return EC;
80 }
Fangrui Songafb54fd2019-04-05 12:52:04 +000081
82 std::vector<std::pair<SymbolDesc, StringRef>> &Fs = res->Functions,
83 &Os = res->Objects;
84 llvm::sort(Fs);
85 Fs.erase(std::unique(Fs.begin(), Fs.end()), Fs.end());
86 llvm::sort(Os);
87 Os.erase(std::unique(Os.begin(), Os.end()), Os.end());
88
Alexey Samsonov8df3a072015-10-29 22:21:37 +000089 return std::move(res);
90}
91
92SymbolizableObjectFile::SymbolizableObjectFile(ObjectFile *Obj,
93 std::unique_ptr<DIContext> DICtx)
94 : Module(Obj), DebugInfoContext(std::move(DICtx)) {}
95
96namespace {
Eugene Zelenko44d95122017-02-09 01:09:54 +000097
Alexey Samsonov8df3a072015-10-29 22:21:37 +000098struct OffsetNamePair {
99 uint32_t Offset;
100 StringRef Name;
Eugene Zelenko44d95122017-02-09 01:09:54 +0000101
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000102 bool operator<(const OffsetNamePair &R) const {
103 return Offset < R.Offset;
104 }
105};
Eugene Zelenko44d95122017-02-09 01:09:54 +0000106
107} // end anonymous namespace
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000108
109std::error_code SymbolizableObjectFile::addCoffExportSymbols(
110 const COFFObjectFile *CoffObj) {
111 // Get all export names and offsets.
112 std::vector<OffsetNamePair> ExportSyms;
113 for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
114 StringRef Name;
115 uint32_t Offset;
116 if (auto EC = Ref.getSymbolName(Name))
117 return EC;
118 if (auto EC = Ref.getExportRVA(Offset))
119 return EC;
120 ExportSyms.push_back(OffsetNamePair{Offset, Name});
121 }
122 if (ExportSyms.empty())
123 return std::error_code();
124
125 // Sort by ascending offset.
126 array_pod_sort(ExportSyms.begin(), ExportSyms.end());
127
128 // Approximate the symbol sizes by assuming they run to the next symbol.
129 // FIXME: This assumes all exports are functions.
130 uint64_t ImageBase = CoffObj->getImageBase();
131 for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {
132 OffsetNamePair &Export = *I;
133 // FIXME: The last export has a one byte size now.
134 uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
135 uint64_t SymbolStart = ImageBase + Export.Offset;
136 uint64_t SymbolSize = NextOffset - Export.Offset;
137 SymbolDesc SD = {SymbolStart, SymbolSize};
Fangrui Songafb54fd2019-04-05 12:52:04 +0000138 Functions.emplace_back(SD, Export.Name);
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000139 }
140 return std::error_code();
141}
142
143std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
144 uint64_t SymbolSize,
145 DataExtractor *OpdExtractor,
146 uint64_t OpdAddress) {
Matt Davis123be5d2019-02-14 23:50:35 +0000147 // Avoid adding symbols from an unknown/undefined section.
148 const ObjectFile *Obj = Symbol.getObject();
149 Expected<section_iterator> Sec = Symbol.getSection();
150 if (!Sec || (Obj && Obj->section_end() == *Sec))
151 return std::error_code();
Kevin Enderby7bd8d992016-05-02 20:28:12 +0000152 Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
153 if (!SymbolTypeOrErr)
154 return errorToErrorCode(SymbolTypeOrErr.takeError());
Kevin Enderby5afbc1c2016-03-23 20:27:00 +0000155 SymbolRef::Type SymbolType = *SymbolTypeOrErr;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000156 if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
157 return std::error_code();
Kevin Enderby931cb652016-06-24 18:24:42 +0000158 Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
159 if (!SymbolAddressOrErr)
160 return errorToErrorCode(SymbolAddressOrErr.takeError());
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000161 uint64_t SymbolAddress = *SymbolAddressOrErr;
162 if (OpdExtractor) {
163 // For big-endian PowerPC64 ELF, symbols in the .opd section refer to
164 // function descriptors. The first word of the descriptor is a pointer to
165 // the function's code.
166 // For the purposes of symbolization, pretend the symbol's address is that
167 // of the function's code, not the descriptor.
168 uint64_t OpdOffset = SymbolAddress - OpdAddress;
169 uint32_t OpdOffset32 = OpdOffset;
Fangrui Songf78650a2018-07-30 19:41:25 +0000170 if (OpdOffset == OpdOffset32 &&
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000171 OpdExtractor->isValidOffsetForAddress(OpdOffset32))
172 SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
173 }
Kevin Enderby81e8b7d2016-04-20 21:24:34 +0000174 Expected<StringRef> SymbolNameOrErr = Symbol.getName();
175 if (!SymbolNameOrErr)
176 return errorToErrorCode(SymbolNameOrErr.takeError());
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000177 StringRef SymbolName = *SymbolNameOrErr;
178 // Mach-O symbol table names have leading underscore, skip it.
Eugene Zelenko44d95122017-02-09 01:09:54 +0000179 if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000180 SymbolName = SymbolName.drop_front();
181 // FIXME: If a function has alias, there are two entries in symbol table
182 // with same address size. Make sure we choose the correct one.
183 auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
184 SymbolDesc SD = { SymbolAddress, SymbolSize };
Fangrui Songafb54fd2019-04-05 12:52:04 +0000185 M.emplace_back(SD, SymbolName);
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000186 return std::error_code();
187}
188
189// Return true if this is a 32-bit x86 PE COFF module.
190bool SymbolizableObjectFile::isWin32Module() const {
191 auto *CoffObject = dyn_cast<COFFObjectFile>(Module);
192 return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
193}
194
195uint64_t SymbolizableObjectFile::getModulePreferredBase() const {
196 if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
197 return CoffObject->getImageBase();
198 return 0;
199}
200
201bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type,
202 uint64_t Address,
203 std::string &Name,
204 uint64_t &Addr,
205 uint64_t &Size) const {
Fangrui Songafb54fd2019-04-05 12:52:04 +0000206 const auto &Symbols = Type == SymbolRef::ST_Function ? Functions : Objects;
207 std::pair<SymbolDesc, StringRef> SD{{Address, UINT64_C(-1)}, StringRef()};
Fangrui Songe2622b32019-04-04 11:08:45 +0000208 // SymbolDescs are sorted by (Addr,Size), if several SymbolDescs share the
209 // same Addr, pick the one with the largest Size. This helps us avoid symbols
210 // with no size information (Size=0).
Fangrui Songafb54fd2019-04-05 12:52:04 +0000211 auto SymbolIterator = llvm::upper_bound(Symbols, SD);
212 if (SymbolIterator == Symbols.begin())
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000213 return false;
214 --SymbolIterator;
215 if (SymbolIterator->first.Size != 0 &&
216 SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
217 return false;
218 Name = SymbolIterator->second.str();
219 Addr = SymbolIterator->first.Addr;
220 Size = SymbolIterator->first.Size;
221 return true;
222}
223
Reid Klecknerc038e2d2015-11-13 17:00:36 +0000224bool SymbolizableObjectFile::shouldOverrideWithSymbolTable(
225 FunctionNameKind FNKind, bool UseSymbolTable) const {
226 // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives
227 // better answers for linkage names than the DIContext. Otherwise, we are
228 // probably using PEs and PDBs, and we shouldn't do the override. PE files
229 // generally only contain the names of exported symbols.
230 return FNKind == FunctionNameKind::LinkageName && UseSymbolTable &&
231 isa<DWARFContext>(DebugInfoContext.get());
232}
233
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000234DILineInfo
235SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
236 FunctionNameKind FNKind,
237 bool UseSymbolTable) const {
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000238 DILineInfo LineInfo;
Alexey Lapshinb2c4b8b2019-03-23 08:08:40 +0000239
240 if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
241 ModuleOffset.SectionIndex =
242 getModuleSectionIndexForAddress(ModuleOffset.Address);
243
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000244 if (DebugInfoContext) {
245 LineInfo = DebugInfoContext->getLineInfoForAddress(
246 ModuleOffset, getDILineInfoSpecifier(FNKind));
247 }
248 // Override function name from symbol table if necessary.
Reid Klecknerc038e2d2015-11-13 17:00:36 +0000249 if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000250 std::string FunctionName;
251 uint64_t Start, Size;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000252 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000253 FunctionName, Start, Size)) {
254 LineInfo.FunctionName = FunctionName;
255 }
256 }
257 return LineInfo;
258}
259
260DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000261 object::SectionedAddress ModuleOffset, FunctionNameKind FNKind,
262 bool UseSymbolTable) const {
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000263 DIInliningInfo InlinedContext;
264
Alexey Lapshinb2c4b8b2019-03-23 08:08:40 +0000265 if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
266 ModuleOffset.SectionIndex =
267 getModuleSectionIndexForAddress(ModuleOffset.Address);
268
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000269 if (DebugInfoContext)
270 InlinedContext = DebugInfoContext->getInliningInfoForAddress(
271 ModuleOffset, getDILineInfoSpecifier(FNKind));
272 // Make sure there is at least one frame in context.
273 if (InlinedContext.getNumberOfFrames() == 0)
274 InlinedContext.addFrame(DILineInfo());
275
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000276 // Override the function name in lower frame with name from symbol table.
Reid Klecknerc038e2d2015-11-13 17:00:36 +0000277 if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
Alexey Samsonove46bd742015-10-30 00:02:55 +0000278 std::string FunctionName;
279 uint64_t Start, Size;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000280 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
Alexey Samsonove46bd742015-10-30 00:02:55 +0000281 FunctionName, Start, Size)) {
282 InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1)
283 ->FunctionName = FunctionName;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000284 }
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000285 }
Alexey Samsonove46bd742015-10-30 00:02:55 +0000286
287 return InlinedContext;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000288}
289
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000290DIGlobal SymbolizableObjectFile::symbolizeData(
291 object::SectionedAddress ModuleOffset) const {
Alexey Samsonov76f7ecb2015-10-29 23:49:19 +0000292 DIGlobal Res;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000293 getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset.Address, Res.Name,
294 Res.Start, Res.Size);
Alexey Samsonov76f7ecb2015-10-29 23:49:19 +0000295 return Res;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000296}
Alexey Lapshinb2c4b8b2019-03-23 08:08:40 +0000297
298/// Search for the first occurence of specified Address in ObjectFile.
299uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress(
300 uint64_t Address) const {
301
302 for (SectionRef Sec : Module->sections()) {
303 if (!Sec.isText() || Sec.isVirtual())
304 continue;
305
306 if (Address >= Sec.getAddress() &&
307 Address <= Sec.getAddress() + Sec.getSize()) {
308 return Sec.getIndex();
309 }
310 }
311
312 return object::SectionedAddress::UndefSection;
313}