1 //===-- SymbolizableObjectFile.cpp ----------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Implementation of SymbolizableObjectFile class.
12 //===----------------------------------------------------------------------===//
14 #include "SymbolizableObjectFile.h"
15 #include "llvm/Object/SymbolSize.h"
16 #include "llvm/Support/DataExtractor.h"
21 using namespace object;
23 static DILineInfoSpecifier
24 getDILineInfoSpecifier(FunctionNameKind FNKind) {
25 return DILineInfoSpecifier(
26 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FNKind);
29 ErrorOr<std::unique_ptr<SymbolizableObjectFile>>
30 SymbolizableObjectFile::create(object::ObjectFile *Obj,
31 std::unique_ptr<DIContext> DICtx) {
32 std::unique_ptr<SymbolizableObjectFile> res(
33 new SymbolizableObjectFile(Obj, std::move(DICtx)));
34 std::unique_ptr<DataExtractor> OpdExtractor;
35 uint64_t OpdAddress = 0;
36 // Find the .opd (function descriptor) section if any, for big-endian
38 if (Obj->getArch() == Triple::ppc64) {
39 for (section_iterator Section : Obj->sections()) {
42 if (auto EC = Section->getName(Name))
45 if (auto EC = Section->getContents(Data))
47 OpdExtractor.reset(new DataExtractor(Data, Obj->isLittleEndian(),
48 Obj->getBytesInAddress()));
49 OpdAddress = Section->getAddress();
54 std::vector<std::pair<SymbolRef, uint64_t>> Symbols =
55 computeSymbolSizes(*Obj);
56 for (auto &P : Symbols)
57 res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress);
59 // If this is a COFF object and we didn't find any symbols, try the export
61 if (Symbols.empty()) {
62 if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj))
63 if (auto EC = res->addCoffExportSymbols(CoffObj))
66 return std::move(res);
69 SymbolizableObjectFile::SymbolizableObjectFile(ObjectFile *Obj,
70 std::unique_ptr<DIContext> DICtx)
71 : Module(Obj), DebugInfoContext(std::move(DICtx)) {}
74 struct OffsetNamePair {
77 bool operator<(const OffsetNamePair &R) const {
78 return Offset < R.Offset;
83 std::error_code SymbolizableObjectFile::addCoffExportSymbols(
84 const COFFObjectFile *CoffObj) {
85 // Get all export names and offsets.
86 std::vector<OffsetNamePair> ExportSyms;
87 for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
90 if (auto EC = Ref.getSymbolName(Name))
92 if (auto EC = Ref.getExportRVA(Offset))
94 ExportSyms.push_back(OffsetNamePair{Offset, Name});
96 if (ExportSyms.empty())
97 return std::error_code();
99 // Sort by ascending offset.
100 array_pod_sort(ExportSyms.begin(), ExportSyms.end());
102 // Approximate the symbol sizes by assuming they run to the next symbol.
103 // FIXME: This assumes all exports are functions.
104 uint64_t ImageBase = CoffObj->getImageBase();
105 for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {
106 OffsetNamePair &Export = *I;
107 // FIXME: The last export has a one byte size now.
108 uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
109 uint64_t SymbolStart = ImageBase + Export.Offset;
110 uint64_t SymbolSize = NextOffset - Export.Offset;
111 SymbolDesc SD = {SymbolStart, SymbolSize};
112 Functions.insert(std::make_pair(SD, Export.Name));
114 return std::error_code();
117 std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
119 DataExtractor *OpdExtractor,
120 uint64_t OpdAddress) {
121 SymbolRef::Type SymbolType = Symbol.getType();
122 if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
123 return std::error_code();
124 ErrorOr<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
125 if (auto EC = SymbolAddressOrErr.getError())
127 uint64_t SymbolAddress = *SymbolAddressOrErr;
129 // For big-endian PowerPC64 ELF, symbols in the .opd section refer to
130 // function descriptors. The first word of the descriptor is a pointer to
131 // the function's code.
132 // For the purposes of symbolization, pretend the symbol's address is that
133 // of the function's code, not the descriptor.
134 uint64_t OpdOffset = SymbolAddress - OpdAddress;
135 uint32_t OpdOffset32 = OpdOffset;
136 if (OpdOffset == OpdOffset32 &&
137 OpdExtractor->isValidOffsetForAddress(OpdOffset32))
138 SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
140 ErrorOr<StringRef> SymbolNameOrErr = Symbol.getName();
141 if (auto EC = SymbolNameOrErr.getError())
143 StringRef SymbolName = *SymbolNameOrErr;
144 // Mach-O symbol table names have leading underscore, skip it.
145 if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_')
146 SymbolName = SymbolName.drop_front();
147 // FIXME: If a function has alias, there are two entries in symbol table
148 // with same address size. Make sure we choose the correct one.
149 auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
150 SymbolDesc SD = { SymbolAddress, SymbolSize };
151 M.insert(std::make_pair(SD, SymbolName));
152 return std::error_code();
155 // Return true if this is a 32-bit x86 PE COFF module.
156 bool SymbolizableObjectFile::isWin32Module() const {
157 auto *CoffObject = dyn_cast<COFFObjectFile>(Module);
158 return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
161 uint64_t SymbolizableObjectFile::getModulePreferredBase() const {
162 if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
163 return CoffObject->getImageBase();
167 bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type,
171 uint64_t &Size) const {
172 const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects;
173 if (SymbolMap.empty())
175 SymbolDesc SD = { Address, Address };
176 auto SymbolIterator = SymbolMap.upper_bound(SD);
177 if (SymbolIterator == SymbolMap.begin())
180 if (SymbolIterator->first.Size != 0 &&
181 SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
183 Name = SymbolIterator->second.str();
184 Addr = SymbolIterator->first.Addr;
185 Size = SymbolIterator->first.Size;
189 DILineInfo SymbolizableObjectFile::symbolizeCode(uint64_t ModuleOffset,
190 FunctionNameKind FNKind,
191 bool UseSymbolTable) const {
193 if (DebugInfoContext) {
194 LineInfo = DebugInfoContext->getLineInfoForAddress(
195 ModuleOffset, getDILineInfoSpecifier(FNKind));
197 // Override function name from symbol table if necessary.
198 if (FNKind == FunctionNameKind::LinkageName && UseSymbolTable) {
199 std::string FunctionName;
200 uint64_t Start, Size;
201 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
202 FunctionName, Start, Size)) {
203 LineInfo.FunctionName = FunctionName;
209 DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
210 uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const {
211 DIInliningInfo InlinedContext;
213 if (DebugInfoContext)
214 InlinedContext = DebugInfoContext->getInliningInfoForAddress(
215 ModuleOffset, getDILineInfoSpecifier(FNKind));
216 // Make sure there is at least one frame in context.
217 if (InlinedContext.getNumberOfFrames() == 0)
218 InlinedContext.addFrame(DILineInfo());
220 // Override the function name in lower frame with name from symbol table.
221 if (FNKind == FunctionNameKind::LinkageName && UseSymbolTable) {
222 std::string FunctionName;
223 uint64_t Start, Size;
224 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
225 FunctionName, Start, Size)) {
226 InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1)
227 ->FunctionName = FunctionName;
231 return InlinedContext;
234 DIGlobal SymbolizableObjectFile::symbolizeData(uint64_t ModuleOffset) const {
236 getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Res.Name, Res.Start,
241 } // namespace symbolize