LLVM  8.0.1
SymbolizableObjectFile.cpp
Go to the documentation of this file.
1 //===- SymbolizableObjectFile.cpp -----------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Implementation of SymbolizableObjectFile class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "SymbolizableObjectFile.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ADT/Triple.h"
18 #include "llvm/BinaryFormat/COFF.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/ObjectFile.h"
23 #include "llvm/Object/SymbolSize.h"
24 #include "llvm/Support/Casting.h"
26 #include "llvm/Support/Error.h"
27 #include <algorithm>
28 #include <cstdint>
29 #include <memory>
30 #include <string>
31 #include <system_error>
32 #include <utility>
33 #include <vector>
34 
35 using namespace llvm;
36 using namespace object;
37 using namespace symbolize;
38 
41  return DILineInfoSpecifier(
43 }
44 
46 SymbolizableObjectFile::create(object::ObjectFile *Obj,
47  std::unique_ptr<DIContext> 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()) {
58  if (auto EC = Section->getName(Name))
59  return EC;
60  if (Name == ".opd") {
61  if (auto EC = Section->getContents(Data))
62  return EC;
63  OpdExtractor.reset(new DataExtractor(Data, 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  return std::move(res);
83 }
84 
85 SymbolizableObjectFile::SymbolizableObjectFile(ObjectFile *Obj,
86  std::unique_ptr<DIContext> DICtx)
87  : Module(Obj), DebugInfoContext(std::move(DICtx)) {}
88 
89 namespace {
90 
91 struct OffsetNamePair {
94 
95  bool operator<(const OffsetNamePair &R) const {
96  return Offset < R.Offset;
97  }
98 };
99 
100 } // end anonymous namespace
101 
102 std::error_code SymbolizableObjectFile::addCoffExportSymbols(
103  const COFFObjectFile *CoffObj) {
104  // Get all export names and offsets.
105  std::vector<OffsetNamePair> ExportSyms;
106  for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
107  StringRef Name;
109  if (auto EC = Ref.getSymbolName(Name))
110  return EC;
111  if (auto EC = Ref.getExportRVA(Offset))
112  return EC;
113  ExportSyms.push_back(OffsetNamePair{Offset, Name});
114  }
115  if (ExportSyms.empty())
116  return std::error_code();
117 
118  // Sort by ascending offset.
119  array_pod_sort(ExportSyms.begin(), ExportSyms.end());
120 
121  // Approximate the symbol sizes by assuming they run to the next symbol.
122  // FIXME: This assumes all exports are functions.
123  uint64_t ImageBase = CoffObj->getImageBase();
124  for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {
125  OffsetNamePair &Export = *I;
126  // FIXME: The last export has a one byte size now.
127  uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
128  uint64_t SymbolStart = ImageBase + Export.Offset;
129  uint64_t SymbolSize = NextOffset - Export.Offset;
130  SymbolDesc SD = {SymbolStart, SymbolSize};
131  Functions.insert(std::make_pair(SD, Export.Name));
132  }
133  return std::error_code();
134 }
135 
136 std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
137  uint64_t SymbolSize,
138  DataExtractor *OpdExtractor,
139  uint64_t OpdAddress) {
140  Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
141  if (!SymbolTypeOrErr)
142  return errorToErrorCode(SymbolTypeOrErr.takeError());
143  SymbolRef::Type SymbolType = *SymbolTypeOrErr;
144  if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
145  return std::error_code();
146  Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
147  if (!SymbolAddressOrErr)
148  return errorToErrorCode(SymbolAddressOrErr.takeError());
149  uint64_t SymbolAddress = *SymbolAddressOrErr;
150  if (OpdExtractor) {
151  // For big-endian PowerPC64 ELF, symbols in the .opd section refer to
152  // function descriptors. The first word of the descriptor is a pointer to
153  // the function's code.
154  // For the purposes of symbolization, pretend the symbol's address is that
155  // of the function's code, not the descriptor.
156  uint64_t OpdOffset = SymbolAddress - OpdAddress;
157  uint32_t OpdOffset32 = OpdOffset;
158  if (OpdOffset == OpdOffset32 &&
159  OpdExtractor->isValidOffsetForAddress(OpdOffset32))
160  SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
161  }
162  Expected<StringRef> SymbolNameOrErr = Symbol.getName();
163  if (!SymbolNameOrErr)
164  return errorToErrorCode(SymbolNameOrErr.takeError());
165  StringRef SymbolName = *SymbolNameOrErr;
166  // Mach-O symbol table names have leading underscore, skip it.
167  if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
168  SymbolName = SymbolName.drop_front();
169  // FIXME: If a function has alias, there are two entries in symbol table
170  // with same address size. Make sure we choose the correct one.
171  auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
172  SymbolDesc SD = { SymbolAddress, SymbolSize };
173  M.insert(std::make_pair(SD, SymbolName));
174  return std::error_code();
175 }
176 
177 // Return true if this is a 32-bit x86 PE COFF module.
178 bool SymbolizableObjectFile::isWin32Module() const {
179  auto *CoffObject = dyn_cast<COFFObjectFile>(Module);
180  return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
181 }
182 
183 uint64_t SymbolizableObjectFile::getModulePreferredBase() const {
184  if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
185  return CoffObject->getImageBase();
186  return 0;
187 }
188 
189 bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type,
190  uint64_t Address,
191  std::string &Name,
192  uint64_t &Addr,
193  uint64_t &Size) const {
194  const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects;
195  if (SymbolMap.empty())
196  return false;
197  SymbolDesc SD = { Address, Address };
198  auto SymbolIterator = SymbolMap.upper_bound(SD);
199  if (SymbolIterator == SymbolMap.begin())
200  return false;
201  --SymbolIterator;
202  if (SymbolIterator->first.Size != 0 &&
203  SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
204  return false;
205  Name = SymbolIterator->second.str();
206  Addr = SymbolIterator->first.Addr;
207  Size = SymbolIterator->first.Size;
208  return true;
209 }
210 
211 bool SymbolizableObjectFile::shouldOverrideWithSymbolTable(
212  FunctionNameKind FNKind, bool UseSymbolTable) const {
213  // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives
214  // better answers for linkage names than the DIContext. Otherwise, we are
215  // probably using PEs and PDBs, and we shouldn't do the override. PE files
216  // generally only contain the names of exported symbols.
217  return FNKind == FunctionNameKind::LinkageName && UseSymbolTable &&
218  isa<DWARFContext>(DebugInfoContext.get());
219 }
220 
221 DILineInfo SymbolizableObjectFile::symbolizeCode(uint64_t ModuleOffset,
222  FunctionNameKind FNKind,
223  bool UseSymbolTable) const {
224  DILineInfo LineInfo;
225  if (DebugInfoContext) {
226  LineInfo = DebugInfoContext->getLineInfoForAddress(
227  ModuleOffset, getDILineInfoSpecifier(FNKind));
228  }
229  // Override function name from symbol table if necessary.
230  if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
231  std::string FunctionName;
232  uint64_t Start, Size;
233  if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
234  FunctionName, Start, Size)) {
235  LineInfo.FunctionName = FunctionName;
236  }
237  }
238  return LineInfo;
239 }
240 
241 DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
242  uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const {
243  DIInliningInfo InlinedContext;
244 
245  if (DebugInfoContext)
246  InlinedContext = DebugInfoContext->getInliningInfoForAddress(
247  ModuleOffset, getDILineInfoSpecifier(FNKind));
248  // Make sure there is at least one frame in context.
249  if (InlinedContext.getNumberOfFrames() == 0)
250  InlinedContext.addFrame(DILineInfo());
251 
252  // Override the function name in lower frame with name from symbol table.
253  if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
254  std::string FunctionName;
255  uint64_t Start, Size;
256  if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
257  FunctionName, Start, Size)) {
258  InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1)
259  ->FunctionName = FunctionName;
260  }
261  }
262 
263  return InlinedContext;
264 }
265 
266 DIGlobal SymbolizableObjectFile::symbolizeData(uint64_t ModuleOffset) const {
267  DIGlobal Res;
268  getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Res.Name, Res.Start,
269  Res.Size);
270  return Res;
271 }
Represents either an error or a value T.
Definition: ErrorOr.h:57
bool isValidOffsetForAddress(uint32_t offset) const
Test the availability of enough bytes of data for a pointer from offset.
DILineInfo * getMutableFrame(unsigned Index)
Definition: DIContext.h:89
This class represents lattice values for constants.
Definition: AllocatorList.h:24
Expected< StringRef > getName() const
Definition: ObjectFile.h:359
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:65
bool operator<(const DataRefImpl &a, const DataRefImpl &b)
Definition: SymbolicFile.h:63
This class is the base class for all object file types.
Definition: ObjectFile.h:202
void addFrame(const DILineInfo &Frame)
Definition: DIContext.h:98
DINameKind
A DINameKind is passed to name search methods to specify a preference regarding the type of name reso...
Definition: DIContext.h:119
Error takeError()
Take ownership of the stored error.
Definition: Error.h:553
static DILineInfoSpecifier getDILineInfoSpecifier(FunctionNameKind FNKind)
A format-neutral container for source line information.
Definition: DIContext.h:31
amdgpu Simplify well known AMD library false Value Value const Twine & Name
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
The access may reference the value stored in memory.
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
bool empty() const
Definition: Module.h:604
uint64_t Start
Definition: DIContext.h:111
section_iterator_range sections() const
Definition: ObjectFile.h:292
uint32_t getNumberOfFrames() const
Definition: DIContext.h:94
#define P(N)
void array_pod_sort(IteratorTy Start, IteratorTy End)
array_pod_sort - This sorts an array with the specified start and end extent.
Definition: STLExtras.h:1083
virtual uint8_t getBytesInAddress() const =0
The number of bytes used to represent an address in this object file format.
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
Controls which fields of DILineInfo container should be filled with data.
Definition: DIContext.h:123
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
A format-neutral container for inlined code description.
Definition: DIContext.h:78
uint64_t getAddress(uint32_t *offset_ptr) const
Extract an pointer from *offset_ptr.
DenseMap< SymbolStringPtr, JITEvaluatedSymbol > SymbolMap
A map from symbol names (as SymbolStringPtrs) to JITSymbols (address/flags pairs).
Definition: Core.h:48
Expected< uint64_t > getAddress() const
Returns the symbol virtual address (i.e.
Definition: ObjectFile.h:363
bool isLittleEndian() const
Definition: Binary.h:131
uint16_t getMachine() const
Definition: COFF.h:812
Expected< SymbolRef::Type > getType() const
Definition: ObjectFile.h:383
std::string Name
Definition: DIContext.h:110
std::string FunctionName
Definition: DIContext.h:33
virtual Triple::ArchType getArch() const =0
uint64_t Size
Definition: DIContext.h:112
std::vector< std::pair< SymbolRef, uint64_t > > computeSymbolSizes(const ObjectFile &O)
Definition: SymbolSize.cpp:41
This is a value type class that represents a single symbol in the list of symbols in the object file...
Definition: ObjectFile.h:141
iterator begin()
Definition: DenseMap.h:100
#define I(x, y, z)
Definition: MD5.cpp:58
iterator_range< export_directory_iterator > export_directories() const
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:323
uint32_t Size
Definition: Profile.cpp:47
LLVM_NODISCARD bool empty() const
Definition: DenseMap.h:123
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
std::error_code errorToErrorCode(Error Err)
Helper for converting an ECError to a std::error_code.
Definition: Error.cpp:94
Container for description of a global variable.
Definition: DIContext.h:109