brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.4 KiB · 29fd4d9 Raw
394 lines · 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-exception6//7//===----------------------------------------------------------------------===//8//9// Implementation of SymbolizableObjectFile class.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/BinaryFormat/COFF.h"16#include "llvm/DebugInfo/DWARF/DWARFContext.h"17#include "llvm/Object/COFF.h"18#include "llvm/Object/ELFObjectFile.h"19#include "llvm/Object/ObjectFile.h"20#include "llvm/Object/SymbolSize.h"21#include "llvm/Support/Casting.h"22#include "llvm/Support/DataExtractor.h"23#include "llvm/TargetParser/Triple.h"24 25using namespace llvm;26using namespace object;27using namespace symbolize;28 29Expected<std::unique_ptr<SymbolizableObjectFile>>30SymbolizableObjectFile::create(const object::ObjectFile *Obj,31                               std::unique_ptr<DIContext> DICtx,32                               bool UntagAddresses) {33  assert(DICtx);34  std::unique_ptr<SymbolizableObjectFile> res(35      new SymbolizableObjectFile(Obj, std::move(DICtx), UntagAddresses));36  std::unique_ptr<DataExtractor> OpdExtractor;37  uint64_t OpdAddress = 0;38  // Find the .opd (function descriptor) section if any, for big-endian39  // PowerPC64 ELF.40  if (Obj->getArch() == Triple::ppc64) {41    for (section_iterator Section : Obj->sections()) {42      Expected<StringRef> NameOrErr = Section->getName();43      if (!NameOrErr)44        return NameOrErr.takeError();45 46      if (*NameOrErr == ".opd") {47        Expected<StringRef> E = Section->getContents();48        if (!E)49          return E.takeError();50        OpdExtractor.reset(new DataExtractor(*E, Obj->isLittleEndian(),51                                             Obj->getBytesInAddress()));52        OpdAddress = Section->getAddress();53        break;54      }55    }56  }57  std::vector<std::pair<SymbolRef, uint64_t>> Symbols =58      computeSymbolSizes(*Obj);59  for (auto &P : Symbols)60    if (Error E =61            res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress))62      return std::move(E);63 64  // If this is a COFF object and we didn't find any symbols, try the export65  // table.66  if (Symbols.empty()) {67    if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj))68      if (Error E = res->addCoffExportSymbols(CoffObj))69        return std::move(E);70  }71 72  std::vector<SymbolDesc> &SS = res->Symbols;73  // Sort by (Addr,Size,Name). If several SymbolDescs share the same Addr,74  // pick the one with the largest Size. This helps us avoid symbols with no75  // size information (Size=0).76  llvm::stable_sort(SS);77  auto I = SS.begin(), E = SS.end(), J = SS.begin();78  while (I != E) {79    auto OI = I;80    while (++I != E && OI->Addr == I->Addr) {81    }82    *J++ = I[-1];83  }84  SS.erase(J, SS.end());85 86  return std::move(res);87}88 89SymbolizableObjectFile::SymbolizableObjectFile(const ObjectFile *Obj,90                                               std::unique_ptr<DIContext> DICtx,91                                               bool UntagAddresses)92    : Module(Obj), DebugInfoContext(std::move(DICtx)),93      UntagAddresses(UntagAddresses) {}94 95namespace {96 97struct OffsetNamePair {98  uint32_t Offset;99  StringRef Name;100 101  bool operator<(const OffsetNamePair &R) const {102    return Offset < R.Offset;103  }104};105 106} // end anonymous namespace107 108Error SymbolizableObjectFile::addCoffExportSymbols(109    const COFFObjectFile *CoffObj) {110  // Get all export names and offsets.111  std::vector<OffsetNamePair> ExportSyms;112  for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {113    StringRef Name;114    uint32_t Offset;115    if (auto EC = Ref.getSymbolName(Name))116      return EC;117    if (auto EC = Ref.getExportRVA(Offset))118      return EC;119    ExportSyms.push_back(OffsetNamePair{Offset, Name});120  }121  if (ExportSyms.empty())122    return Error::success();123 124  // Sort by ascending offset.125  array_pod_sort(ExportSyms.begin(), ExportSyms.end());126 127  // Approximate the symbol sizes by assuming they run to the next symbol.128  // FIXME: This assumes all exports are functions.129  uint64_t ImageBase = CoffObj->getImageBase();130  for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {131    OffsetNamePair &Export = *I;132    // FIXME: The last export has a one byte size now.133    uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;134    uint64_t SymbolStart = ImageBase + Export.Offset;135    uint64_t SymbolSize = NextOffset - Export.Offset;136    Symbols.push_back({SymbolStart, SymbolSize, Export.Name, 0});137  }138  return Error::success();139}140 141Error SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,142                                        uint64_t SymbolSize,143                                        DataExtractor *OpdExtractor,144                                        uint64_t OpdAddress) {145  // Avoid adding symbols from an unknown/undefined section.146  const ObjectFile &Obj = *Symbol.getObject();147  Expected<StringRef> SymbolNameOrErr = Symbol.getName();148  if (!SymbolNameOrErr)149    return SymbolNameOrErr.takeError();150  StringRef SymbolName = *SymbolNameOrErr;151 152  uint32_t ELFSymIdx =153      Obj.isELF() ? ELFSymbolRef(Symbol).getRawDataRefImpl().d.b : 0;154  Expected<section_iterator> Sec = Symbol.getSection();155  if (!Sec || Obj.section_end() == *Sec) {156    if (Obj.isELF()) {157      // Store the (index, filename) pair for a file symbol.158      ELFSymbolRef ESym(Symbol);159      if (ESym.getELFType() == ELF::STT_FILE)160        FileSymbols.emplace_back(ELFSymIdx, SymbolName);161    }162    return Error::success();163  }164 165  Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();166  if (!SymbolTypeOrErr)167    return SymbolTypeOrErr.takeError();168  SymbolRef::Type SymbolType = *SymbolTypeOrErr;169  if (Obj.isELF()) {170    // Ignore any symbols coming from sections that don't have runtime171    // allocated memory.172    if ((elf_section_iterator(*Sec)->getFlags() & ELF::SHF_ALLOC) == 0)173      return Error::success();174 175    // Allow function and data symbols. Additionally allow STT_NONE, which are176    // common for functions defined in assembly.177    uint8_t Type = ELFSymbolRef(Symbol).getELFType();178    if (Type != ELF::STT_NOTYPE && Type != ELF::STT_FUNC &&179        Type != ELF::STT_OBJECT && Type != ELF::STT_GNU_IFUNC)180      return Error::success();181    // Some STT_NOTYPE symbols are not desired. This excludes STT_SECTION and182    // ARM mapping symbols.183    uint32_t Flags = cantFail(Symbol.getFlags());184    if (Flags & SymbolRef::SF_FormatSpecific)185      return Error::success();186  } else if (SymbolType != SymbolRef::ST_Function &&187             SymbolType != SymbolRef::ST_Data) {188    return Error::success();189  }190 191  Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();192  if (!SymbolAddressOrErr)193    return SymbolAddressOrErr.takeError();194  uint64_t SymbolAddress = *SymbolAddressOrErr;195  if (UntagAddresses) {196    // For kernel addresses, bits 56-63 need to be set, so we sign extend bit 55197    // into bits 56-63 instead of masking them out.198    SymbolAddress &= (1ull << 56) - 1;199    SymbolAddress = (int64_t(SymbolAddress) << 8) >> 8;200  }201  if (OpdExtractor) {202    // For big-endian PowerPC64 ELF, symbols in the .opd section refer to203    // function descriptors. The first word of the descriptor is a pointer to204    // the function's code.205    // For the purposes of symbolization, pretend the symbol's address is that206    // of the function's code, not the descriptor.207    uint64_t OpdOffset = SymbolAddress - OpdAddress;208    if (OpdExtractor->isValidOffsetForAddress(OpdOffset))209      SymbolAddress = OpdExtractor->getAddress(&OpdOffset);210  }211  // Mach-O symbol table names have leading underscore, skip it.212  if (Module->isMachO())213    SymbolName.consume_front("_");214 215  if (Obj.isELF() && ELFSymbolRef(Symbol).getBinding() != ELF::STB_LOCAL)216    ELFSymIdx = 0;217  Symbols.push_back({SymbolAddress, SymbolSize, SymbolName, ELFSymIdx});218  return Error::success();219}220 221// Return true if this is a 32-bit x86 PE COFF module.222bool SymbolizableObjectFile::isWin32Module() const {223  auto *CoffObject = dyn_cast<COFFObjectFile>(Module);224  return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;225}226 227uint64_t SymbolizableObjectFile::getModulePreferredBase() const {228  if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))229    return CoffObject->getImageBase();230  return 0;231}232 233bool SymbolizableObjectFile::getNameFromSymbolTable(234    uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size,235    std::string &FileName) const {236  SymbolDesc SD{Address, UINT64_C(-1), StringRef(), 0};237  auto SymbolIterator = llvm::upper_bound(Symbols, SD);238  if (SymbolIterator == Symbols.begin())239    return false;240  --SymbolIterator;241  if (SymbolIterator->Size != 0 &&242      SymbolIterator->Addr + SymbolIterator->Size <= Address)243    return false;244  Name = SymbolIterator->Name.str();245  Addr = SymbolIterator->Addr;246  Size = SymbolIterator->Size;247 248  if (SymbolIterator->ELFLocalSymIdx != 0) {249    // If this is an ELF local symbol, find the STT_FILE symbol preceding250    // SymbolIterator to get the filename. The ELF spec requires the STT_FILE251    // symbol (if present) precedes the other STB_LOCAL symbols for the file.252    assert(Module->isELF());253    auto It = llvm::upper_bound(254        FileSymbols,255        std::make_pair(SymbolIterator->ELFLocalSymIdx, StringRef()));256    if (It != FileSymbols.begin())257      FileName = It[-1].second.str();258  }259  return true;260}261 262bool SymbolizableObjectFile::shouldOverrideWithSymbolTable(263    FunctionNameKind FNKind, bool UseSymbolTable) const {264  // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives265  // better answers for linkage names than the DIContext. Otherwise, we are266  // probably using PEs and PDBs, and we shouldn't do the override. PE files267  // generally only contain the names of exported symbols.268  return FNKind == FunctionNameKind::LinkageName && UseSymbolTable &&269         isa<DWARFContext>(DebugInfoContext.get());270}271 272DILineInfo273SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,274                                      DILineInfoSpecifier LineInfoSpecifier,275                                      bool UseSymbolTable) const {276  if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)277    ModuleOffset.SectionIndex =278        getModuleSectionIndexForAddress(ModuleOffset.Address);279  DILineInfo LineInfo;280  std::optional<DILineInfo> DBGLineInfo =281      DebugInfoContext->getLineInfoForAddress(ModuleOffset, LineInfoSpecifier);282  if (DBGLineInfo)283    LineInfo = *DBGLineInfo;284 285  // Override function name from symbol table if necessary.286  if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {287    std::string FunctionName, FileName;288    uint64_t Start, Size;289    if (getNameFromSymbolTable(ModuleOffset.Address, FunctionName, Start, Size,290                               FileName)) {291      LineInfo.FunctionName = FunctionName;292      LineInfo.StartAddress = Start;293      // Only use the filename from symbol table if the debug info for the294      // address is missing.295      if (!DBGLineInfo && !FileName.empty())296        LineInfo.FileName = FileName;297    }298  }299  return LineInfo;300}301 302DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(303    object::SectionedAddress ModuleOffset,304    DILineInfoSpecifier LineInfoSpecifier, bool UseSymbolTable) const {305  if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)306    ModuleOffset.SectionIndex =307        getModuleSectionIndexForAddress(ModuleOffset.Address);308  DIInliningInfo InlinedContext = DebugInfoContext->getInliningInfoForAddress(309      ModuleOffset, LineInfoSpecifier);310 311  // Make sure there is at least one frame in context.312  bool EmptyFrameAdded = false;313  if (InlinedContext.getNumberOfFrames() == 0) {314    EmptyFrameAdded = true;315    InlinedContext.addFrame(DILineInfo());316  }317 318  // Override the function name in lower frame with name from symbol table.319  if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {320    std::string FunctionName, FileName;321    uint64_t Start, Size;322    if (getNameFromSymbolTable(ModuleOffset.Address, FunctionName, Start, Size,323                               FileName)) {324      DILineInfo *LI = InlinedContext.getMutableFrame(325          InlinedContext.getNumberOfFrames() - 1);326      LI->FunctionName = FunctionName;327      LI->StartAddress = Start;328      // Only use the filename from symbol table if the debug info for the329      // address is missing.330      if (EmptyFrameAdded && !FileName.empty())331        LI->FileName = FileName;332    }333  }334 335  return InlinedContext;336}337 338DIGlobal SymbolizableObjectFile::symbolizeData(339    object::SectionedAddress ModuleOffset) const {340  DIGlobal Res;341  std::string FileName;342  getNameFromSymbolTable(ModuleOffset.Address, Res.Name, Res.Start, Res.Size,343                         FileName);344  Res.DeclFile = FileName;345 346  // Try and get a better filename:lineno pair from the debuginfo, if present.347  std::optional<DILineInfo> DL =348      DebugInfoContext->getLineInfoForDataAddress(ModuleOffset);349  if (DL && DL->Line != 0) {350    Res.DeclFile = DL->FileName;351    Res.DeclLine = DL->Line;352  }353  return Res;354}355 356std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame(357    object::SectionedAddress ModuleOffset) const {358  if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)359    ModuleOffset.SectionIndex =360        getModuleSectionIndexForAddress(ModuleOffset.Address);361  return DebugInfoContext->getLocalsForAddress(ModuleOffset);362}363 364std::vector<object::SectionedAddress>365SymbolizableObjectFile::findSymbol(StringRef Symbol, uint64_t Offset) const {366  std::vector<object::SectionedAddress> Result;367  for (const SymbolDesc &Sym : Symbols) {368    if (Sym.Name == Symbol) {369      uint64_t Addr = Sym.Addr;370      if (Offset < Sym.Size)371        Addr += Offset;372      object::SectionedAddress A{Addr, getModuleSectionIndexForAddress(Addr)};373      Result.push_back(A);374    }375  }376  return Result;377}378 379/// Search for the first occurence of specified Address in ObjectFile.380uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress(381    uint64_t Address) const {382 383  for (SectionRef Sec : Module->sections()) {384    if (!Sec.isText() || Sec.isVirtual())385      continue;386 387    if (Address >= Sec.getAddress() &&388        Address < Sec.getAddress() + Sec.getSize())389      return Sec.getIndex();390  }391 392  return object::SectionedAddress::UndefSection;393}394