LCOV - code coverage report
Current view: top level - lib/DebugInfo/Symbolize - SymbolizableObjectFile.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 72 104 69.2 %
Date: 2018-10-20 13:21:21 Functions: 8 12 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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"
      19             : #include "llvm/DebugInfo/DWARF/DWARFContext.h"
      20             : #include "llvm/DebugInfo/Symbolize/SymbolizableModule.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"
      25             : #include "llvm/Support/DataExtractor.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             : 
      39             : static DILineInfoSpecifier
      40             : getDILineInfoSpecifier(FunctionNameKind FNKind) {
      41             :   return DILineInfoSpecifier(
      42             :       DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FNKind);
      43             : }
      44             : 
      45             : ErrorOr<std::unique_ptr<SymbolizableObjectFile>>
      46         202 : SymbolizableObjectFile::create(object::ObjectFile *Obj,
      47             :                                std::unique_ptr<DIContext> DICtx) {
      48             :   std::unique_ptr<SymbolizableObjectFile> res(
      49         202 :       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         202 :   if (Obj->getArch() == Triple::ppc64) {
      55           5 :     for (section_iterator Section : Obj->sections()) {
      56           5 :       StringRef Name;
      57           5 :       StringRef Data;
      58           5 :       if (auto EC = Section->getName(Name))
      59             :         return EC;
      60             :       if (Name == ".opd") {
      61           1 :         if (auto EC = Section->getContents(Data))
      62             :           return EC;
      63           1 :         OpdExtractor.reset(new DataExtractor(Data, Obj->isLittleEndian(),
      64           1 :                                              Obj->getBytesInAddress()));
      65           1 :         OpdAddress = Section->getAddress();
      66           1 :         break;
      67             :       }
      68             :     }
      69             :   }
      70             :   std::vector<std::pair<SymbolRef, uint64_t>> Symbols =
      71         202 :       computeSymbolSizes(*Obj);
      72    13172129 :   for (auto &P : Symbols)
      73    13171927 :     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         202 :   if (Symbols.empty()) {
      78             :     if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj))
      79           0 :       if (auto EC = res->addCoffExportSymbols(CoffObj))
      80           0 :         return EC;
      81             :   }
      82             :   return std::move(res);
      83             : }
      84             : 
      85         202 : SymbolizableObjectFile::SymbolizableObjectFile(ObjectFile *Obj,
      86         202 :                                                std::unique_ptr<DIContext> DICtx)
      87         404 :     : Module(Obj), DebugInfoContext(std::move(DICtx)) {}
      88             : 
      89             : namespace {
      90             : 
      91             : struct OffsetNamePair {
      92             :   uint32_t Offset;
      93             :   StringRef Name;
      94             : 
      95           0 :   bool operator<(const OffsetNamePair &R) const {
      96           0 :     return Offset < R.Offset;
      97             :   }
      98             : };
      99             : 
     100             : } // end anonymous namespace
     101             : 
     102           0 : std::error_code SymbolizableObjectFile::addCoffExportSymbols(
     103             :     const COFFObjectFile *CoffObj) {
     104             :   // Get all export names and offsets.
     105             :   std::vector<OffsetNamePair> ExportSyms;
     106           0 :   for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
     107           0 :     StringRef Name;
     108             :     uint32_t Offset;
     109           0 :     if (auto EC = Ref.getSymbolName(Name))
     110           0 :       return EC;
     111           0 :     if (auto EC = Ref.getExportRVA(Offset))
     112           0 :       return EC;
     113           0 :     ExportSyms.push_back(OffsetNamePair{Offset, Name});
     114             :   }
     115           0 :   if (ExportSyms.empty())
     116           0 :     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           0 :   uint64_t ImageBase = CoffObj->getImageBase();
     124           0 :   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           0 :     uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
     128           0 :     uint64_t SymbolStart = ImageBase + Export.Offset;
     129           0 :     uint64_t SymbolSize = NextOffset - Export.Offset;
     130             :     SymbolDesc SD = {SymbolStart, SymbolSize};
     131           0 :     Functions.insert(std::make_pair(SD, Export.Name));
     132             :   }
     133           0 :   return std::error_code();
     134             : }
     135             : 
     136    13171927 : 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    13171927 :   if (!SymbolTypeOrErr)
     142           0 :     return errorToErrorCode(SymbolTypeOrErr.takeError());
     143    13171927 :   SymbolRef::Type SymbolType = *SymbolTypeOrErr;
     144    13171927 :   if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
     145       44665 :     return std::error_code();
     146             :   Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
     147    13127262 :   if (!SymbolAddressOrErr)
     148           0 :     return errorToErrorCode(SymbolAddressOrErr.takeError());
     149    13127262 :   uint64_t SymbolAddress = *SymbolAddressOrErr;
     150    13127262 :   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           3 :     uint64_t OpdOffset = SymbolAddress - OpdAddress;
     157           3 :     uint32_t OpdOffset32 = OpdOffset;
     158           3 :     if (OpdOffset == OpdOffset32 &&
     159             :         OpdExtractor->isValidOffsetForAddress(OpdOffset32))
     160             :       SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
     161             :   }
     162             :   Expected<StringRef> SymbolNameOrErr = Symbol.getName();
     163    13127262 :   if (!SymbolNameOrErr)
     164           0 :     return errorToErrorCode(SymbolNameOrErr.takeError());
     165    13127262 :   StringRef SymbolName = *SymbolNameOrErr;
     166             :   // Mach-O symbol table names have leading underscore, skip it.
     167    26254524 :   if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
     168          53 :     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    13127262 :   auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
     172             :   SymbolDesc SD = { SymbolAddress, SymbolSize };
     173    13127262 :   M.insert(std::make_pair(SD, SymbolName));
     174    13127262 :   return std::error_code();
     175             : }
     176             : 
     177             : // Return true if this is a 32-bit x86 PE COFF module.
     178         428 : bool SymbolizableObjectFile::isWin32Module() const {
     179         428 :   auto *CoffObject = dyn_cast<COFFObjectFile>(Module);
     180           0 :   return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
     181             : }
     182             : 
     183           0 : uint64_t SymbolizableObjectFile::getModulePreferredBase() const {
     184           0 :   if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
     185           0 :     return CoffObject->getImageBase();
     186             :   return 0;
     187             : }
     188             : 
     189         954 : bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type,
     190             :                                                     uint64_t Address,
     191             :                                                     std::string &Name,
     192             :                                                     uint64_t &Addr,
     193             :                                                     uint64_t &Size) const {
     194         954 :   const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects;
     195         954 :   if (SymbolMap.empty())
     196             :     return false;
     197             :   SymbolDesc SD = { Address, Address };
     198             :   auto SymbolIterator = SymbolMap.upper_bound(SD);
     199         950 :   if (SymbolIterator == SymbolMap.begin())
     200             :     return false;
     201             :   --SymbolIterator;
     202         950 :   if (SymbolIterator->first.Size != 0 &&
     203         930 :       SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
     204             :     return false;
     205        1898 :   Name = SymbolIterator->second.str();
     206         949 :   Addr = SymbolIterator->first.Addr;
     207         949 :   Size = SymbolIterator->first.Size;
     208         949 :   return true;
     209             : }
     210             : 
     211        1339 : 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        1339 :   return FNKind == FunctionNameKind::LinkageName && UseSymbolTable &&
     218        1339 :          isa<DWARFContext>(DebugInfoContext.get());
     219             : }
     220             : 
     221         672 : DILineInfo SymbolizableObjectFile::symbolizeCode(uint64_t ModuleOffset,
     222             :                                                  FunctionNameKind FNKind,
     223             :                                                  bool UseSymbolTable) const {
     224         672 :   DILineInfo LineInfo;
     225         672 :   if (DebugInfoContext) {
     226         672 :     LineInfo = DebugInfoContext->getLineInfoForAddress(
     227         672 :         ModuleOffset, getDILineInfoSpecifier(FNKind));
     228             :   }
     229             :   // Override function name from symbol table if necessary.
     230         672 :   if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
     231             :     std::string FunctionName;
     232             :     uint64_t Start, Size;
     233         288 :     if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
     234             :                                FunctionName, Start, Size)) {
     235         285 :       LineInfo.FunctionName = FunctionName;
     236             :     }
     237             :   }
     238         672 :   return LineInfo;
     239             : }
     240             : 
     241         667 : DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
     242             :     uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const {
     243             :   DIInliningInfo InlinedContext;
     244             : 
     245         667 :   if (DebugInfoContext)
     246         667 :     InlinedContext = DebugInfoContext->getInliningInfoForAddress(
     247         667 :         ModuleOffset, getDILineInfoSpecifier(FNKind));
     248             :   // Make sure there is at least one frame in context.
     249         667 :   if (InlinedContext.getNumberOfFrames() == 0)
     250         774 :     InlinedContext.addFrame(DILineInfo());
     251             : 
     252             :   // Override the function name in lower frame with name from symbol table.
     253         667 :   if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) {
     254             :     std::string FunctionName;
     255             :     uint64_t Start, Size;
     256         666 :     if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
     257             :                                FunctionName, Start, Size)) {
     258         664 :       InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1)
     259         664 :           ->FunctionName = FunctionName;
     260             :     }
     261             :   }
     262             : 
     263         667 :   return InlinedContext;
     264             : }
     265             : 
     266           0 : DIGlobal SymbolizableObjectFile::symbolizeData(uint64_t ModuleOffset) const {
     267             :   DIGlobal Res;
     268           0 :   getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Res.Name, Res.Start,
     269           0 :                          Res.Size);
     270           0 :   return Res;
     271             : }

Generated by: LCOV version 1.13