blob: f0a97827c036f34b1bfab2b8fb49427334233906 [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 }
81 return std::move(res);
82}
83
84SymbolizableObjectFile::SymbolizableObjectFile(ObjectFile *Obj,
85 std::unique_ptr<DIContext> DICtx)
86 : Module(Obj), DebugInfoContext(std::move(DICtx)) {}
87
88namespace {
Eugene Zelenko44d95122017-02-09 01:09:54 +000089
Alexey Samsonov8df3a072015-10-29 22:21:37 +000090struct OffsetNamePair {
91 uint32_t Offset;
92 StringRef Name;
Eugene Zelenko44d95122017-02-09 01:09:54 +000093
Alexey Samsonov8df3a072015-10-29 22:21:37 +000094 bool operator<(const OffsetNamePair &R) const {
95 return Offset < R.Offset;
96 }
97};
Eugene Zelenko44d95122017-02-09 01:09:54 +000098
99} // end anonymous namespace
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000100
101std::error_code SymbolizableObjectFile::addCoffExportSymbols(
102 const COFFObjectFile *CoffObj) {
103 // Get all export names and offsets.
104 std::vector<OffsetNamePair> ExportSyms;
105 for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
106 StringRef Name;
107 uint32_t Offset;
108 if (auto EC = Ref.getSymbolName(Name))
109 return EC;
110 if (auto EC = Ref.getExportRVA(Offset))
111 return EC;
112 ExportSyms.push_back(OffsetNamePair{Offset, Name});
113 }
114 if (ExportSyms.empty())
115 return std::error_code();
116
117 // Sort by ascending offset.
118 array_pod_sort(ExportSyms.begin(), ExportSyms.end());
119
120 // Approximate the symbol sizes by assuming they run to the next symbol.
121 // FIXME: This assumes all exports are functions.
122 uint64_t ImageBase = CoffObj->getImageBase();
123 for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {
124 OffsetNamePair &Export = *I;
125 // FIXME: The last export has a one byte size now.
126 uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
127 uint64_t SymbolStart = ImageBase + Export.Offset;
128 uint64_t SymbolSize = NextOffset - Export.Offset;
129 SymbolDesc SD = {SymbolStart, SymbolSize};
130 Functions.insert(std::make_pair(SD, Export.Name));
131 }
132 return std::error_code();
133}
134
135std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
136 uint64_t SymbolSize,
137 DataExtractor *OpdExtractor,
138 uint64_t OpdAddress) {
Matt Davis123be5d2019-02-14 23:50:35 +0000139 // Avoid adding symbols from an unknown/undefined section.
140 const ObjectFile *Obj = Symbol.getObject();
141 Expected<section_iterator> Sec = Symbol.getSection();
142 if (!Sec || (Obj && Obj->section_end() == *Sec))
143 return std::error_code();
Kevin Enderby7bd8d992016-05-02 20:28:12 +0000144 Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
145 if (!SymbolTypeOrErr)
146 return errorToErrorCode(SymbolTypeOrErr.takeError());
Kevin Enderby5afbc1c2016-03-23 20:27:00 +0000147 SymbolRef::Type SymbolType = *SymbolTypeOrErr;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000148 if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
149 return std::error_code();
Kevin Enderby931cb652016-06-24 18:24:42 +0000150 Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
151 if (!SymbolAddressOrErr)
152 return errorToErrorCode(SymbolAddressOrErr.takeError());
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000153 uint64_t SymbolAddress = *SymbolAddressOrErr;
154 if (OpdExtractor) {
155 // For big-endian PowerPC64 ELF, symbols in the .opd section refer to
156 // function descriptors. The first word of the descriptor is a pointer to
157 // the function's code.
158 // For the purposes of symbolization, pretend the symbol's address is that
159 // of the function's code, not the descriptor.
160 uint64_t OpdOffset = SymbolAddress - OpdAddress;
161 uint32_t OpdOffset32 = OpdOffset;
Fangrui Songf78650a2018-07-30 19:41:25 +0000162 if (OpdOffset == OpdOffset32 &&
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000163 OpdExtractor->isValidOffsetForAddress(OpdOffset32))
164 SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
165 }
Kevin Enderby81e8b7d2016-04-20 21:24:34 +0000166 Expected<StringRef> SymbolNameOrErr = Symbol.getName();
167 if (!SymbolNameOrErr)
168 return errorToErrorCode(SymbolNameOrErr.takeError());
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000169 StringRef SymbolName = *SymbolNameOrErr;
170 // Mach-O symbol table names have leading underscore, skip it.
Eugene Zelenko44d95122017-02-09 01:09:54 +0000171 if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000172 SymbolName = SymbolName.drop_front();
173 // FIXME: If a function has alias, there are two entries in symbol table
174 // with same address size. Make sure we choose the correct one.
175 auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
176 SymbolDesc SD = { SymbolAddress, SymbolSize };
177 M.insert(std::make_pair(SD, SymbolName));
178 return std::error_code();
179}
180
181// Return true if this is a 32-bit x86 PE COFF module.
182bool SymbolizableObjectFile::isWin32Module() const {
183 auto *CoffObject = dyn_cast<COFFObjectFile>(Module);
184 return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
185}
186
187uint64_t SymbolizableObjectFile::getModulePreferredBase() const {
188 if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
189 return CoffObject->getImageBase();
190 return 0;
191}
192
193bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type,
194 uint64_t Address,
195 std::string &Name,
196 uint64_t &Addr,
197 uint64_t &Size) const {
198 const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects;
199 if (SymbolMap.empty())
200 return false;
201 SymbolDesc SD = { Address, Address };
202 auto SymbolIterator = SymbolMap.upper_bound(SD);
203 if (SymbolIterator == SymbolMap.begin())
204 return false;
205 --SymbolIterator;
206 if (SymbolIterator->first.Size != 0 &&
207 SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
208 return false;
209 Name = SymbolIterator->second.str();
210 Addr = SymbolIterator->first.Addr;
211 Size = SymbolIterator->first.Size;
212 return true;
213}
214
Reid Klecknerc038e2d2015-11-13 17:00:36 +0000215bool SymbolizableObjectFile::shouldOverrideWithSymbolTable(
216 FunctionNameKind FNKind, bool UseSymbolTable) const {
217 // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives
218 // better answers for linkage names than the DIContext. Otherwise, we are
219 // probably using PEs and PDBs, and we shouldn't do the override. PE files
220 // generally only contain the names of exported symbols.
221 return FNKind == FunctionNameKind::LinkageName && UseSymbolTable &&
222 isa<DWARFContext>(DebugInfoContext.get());
223}
224
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000225DILineInfo
226SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
227 FunctionNameKind FNKind,
228 bool UseSymbolTable) const {
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000229 DILineInfo LineInfo;
230 if (DebugInfoContext) {
231 LineInfo = DebugInfoContext->getLineInfoForAddress(
232 ModuleOffset, getDILineInfoSpecifier(FNKind));
233 }
234 // Override function name from symbol table if necessary.
Reid Klecknerc038e2d2015-11-13 17:00:36 +0000235 if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000236 std::string FunctionName;
237 uint64_t Start, Size;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000238 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000239 FunctionName, Start, Size)) {
240 LineInfo.FunctionName = FunctionName;
241 }
242 }
243 return LineInfo;
244}
245
246DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000247 object::SectionedAddress ModuleOffset, FunctionNameKind FNKind,
248 bool UseSymbolTable) const {
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000249 DIInliningInfo InlinedContext;
250
251 if (DebugInfoContext)
252 InlinedContext = DebugInfoContext->getInliningInfoForAddress(
253 ModuleOffset, getDILineInfoSpecifier(FNKind));
254 // Make sure there is at least one frame in context.
255 if (InlinedContext.getNumberOfFrames() == 0)
256 InlinedContext.addFrame(DILineInfo());
257
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000258 // Override the function name in lower frame with name from symbol table.
Reid Klecknerc038e2d2015-11-13 17:00:36 +0000259 if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
Alexey Samsonove46bd742015-10-30 00:02:55 +0000260 std::string FunctionName;
261 uint64_t Start, Size;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000262 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
Alexey Samsonove46bd742015-10-30 00:02:55 +0000263 FunctionName, Start, Size)) {
264 InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1)
265 ->FunctionName = FunctionName;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000266 }
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000267 }
Alexey Samsonove46bd742015-10-30 00:02:55 +0000268
269 return InlinedContext;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000270}
271
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000272DIGlobal SymbolizableObjectFile::symbolizeData(
273 object::SectionedAddress ModuleOffset) const {
Alexey Samsonov76f7ecb2015-10-29 23:49:19 +0000274 DIGlobal Res;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000275 getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset.Address, Res.Name,
276 Res.Start, Res.Size);
Alexey Samsonov76f7ecb2015-10-29 23:49:19 +0000277 return Res;
Alexey Samsonov8df3a072015-10-29 22:21:37 +0000278}