LCOV - code coverage report
Current view: top level - lib/DebugInfo/Symbolize - Symbolize.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 135 177 76.3 %
Date: 2018-10-20 13:21:21 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- LLVMSymbolize.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 for LLVM symbolization library.
      11             : //
      12             : //===----------------------------------------------------------------------===//
      13             : 
      14             : #include "llvm/DebugInfo/Symbolize/Symbolize.h"
      15             : 
      16             : #include "SymbolizableObjectFile.h"
      17             : 
      18             : #include "llvm/ADT/STLExtras.h"
      19             : #include "llvm/BinaryFormat/COFF.h"
      20             : #include "llvm/Config/config.h"
      21             : #include "llvm/DebugInfo/DWARF/DWARFContext.h"
      22             : #include "llvm/DebugInfo/PDB/PDB.h"
      23             : #include "llvm/DebugInfo/PDB/PDBContext.h"
      24             : #include "llvm/Demangle/Demangle.h"
      25             : #include "llvm/Object/COFF.h"
      26             : #include "llvm/Object/MachO.h"
      27             : #include "llvm/Object/MachOUniversal.h"
      28             : #include "llvm/Support/Casting.h"
      29             : #include "llvm/Support/Compression.h"
      30             : #include "llvm/Support/DataExtractor.h"
      31             : #include "llvm/Support/Errc.h"
      32             : #include "llvm/Support/FileSystem.h"
      33             : #include "llvm/Support/MemoryBuffer.h"
      34             : #include "llvm/Support/Path.h"
      35             : #include <algorithm>
      36             : #include <cassert>
      37             : #include <cstdlib>
      38             : #include <cstring>
      39             : 
      40             : #if defined(_MSC_VER)
      41             : #include <Windows.h>
      42             : 
      43             : // This must be included after windows.h.
      44             : #include <DbgHelp.h>
      45             : #pragma comment(lib, "dbghelp.lib")
      46             : 
      47             : // Windows.h conflicts with our COFF header definitions.
      48             : #ifdef IMAGE_FILE_MACHINE_I386
      49             : #undef IMAGE_FILE_MACHINE_I386
      50             : #endif
      51             : #endif
      52             : 
      53             : namespace llvm {
      54             : namespace symbolize {
      55             : 
      56             : Expected<DILineInfo>
      57         772 : LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
      58             :                               uint64_t ModuleOffset, StringRef DWPName) {
      59             :   SymbolizableModule *Info;
      60         772 :   if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName, DWPName))
      61         741 :     Info = InfoOrErr.get();
      62             :   else
      63             :     return InfoOrErr.takeError();
      64             : 
      65             :   // A null module means an error has already been reported. Return an empty
      66             :   // result.
      67         741 :   if (!Info)
      68         138 :     return DILineInfo();
      69             : 
      70             :   // If the user is giving us relative addresses, add the preferred base of the
      71             :   // object to the offset before we do the query. It's what DIContext expects.
      72         672 :   if (Opts.RelativeAddresses)
      73           0 :     ModuleOffset += Info->getModulePreferredBase();
      74             : 
      75             :   DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts.PrintFunctions,
      76        1344 :                                             Opts.UseSymbolTable);
      77         672 :   if (Opts.Demangle)
      78         514 :     LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
      79             :   return LineInfo;
      80             : }
      81             : 
      82             : Expected<DIInliningInfo>
      83         670 : LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
      84             :                                      uint64_t ModuleOffset, StringRef DWPName) {
      85             :   SymbolizableModule *Info;
      86         670 :   if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName, DWPName))
      87         667 :     Info = InfoOrErr.get();
      88             :   else
      89             :     return InfoOrErr.takeError();
      90             : 
      91             :   // A null module means an error has already been reported. Return an empty
      92             :   // result.
      93         667 :   if (!Info)
      94           0 :     return DIInliningInfo();
      95             : 
      96             :   // If the user is giving us relative addresses, add the preferred base of the
      97             :   // object to the offset before we do the query. It's what DIContext expects.
      98         667 :   if (Opts.RelativeAddresses)
      99           0 :     ModuleOffset += Info->getModulePreferredBase();
     100             : 
     101             :   DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
     102         667 :       ModuleOffset, Opts.PrintFunctions, Opts.UseSymbolTable);
     103         667 :   if (Opts.Demangle) {
     104        1126 :     for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
     105         569 :       auto *Frame = InlinedContext.getMutableFrame(i);
     106        1138 :       Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
     107             :     }
     108             :   }
     109             :   return InlinedContext;
     110             : }
     111             : 
     112           0 : Expected<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
     113             :                                                  uint64_t ModuleOffset) {
     114             :   SymbolizableModule *Info;
     115           0 :   if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
     116           0 :     Info = InfoOrErr.get();
     117             :   else
     118             :     return InfoOrErr.takeError();
     119             : 
     120             :   // A null module means an error has already been reported. Return an empty
     121             :   // result.
     122           0 :   if (!Info)
     123           0 :     return DIGlobal();
     124             : 
     125             :   // If the user is giving us relative addresses, add the preferred base of
     126             :   // the object to the offset before we do the query. It's what DIContext
     127             :   // expects.
     128           0 :   if (Opts.RelativeAddresses)
     129           0 :     ModuleOffset += Info->getModulePreferredBase();
     130             : 
     131           0 :   DIGlobal Global = Info->symbolizeData(ModuleOffset);
     132           0 :   if (Opts.Demangle)
     133           0 :     Global.Name = DemangleName(Global.Name, Info);
     134             :   return Global;
     135             : }
     136             : 
     137        1727 : void LLVMSymbolizer::flush() {
     138             :   ObjectForUBPathAndArch.clear();
     139             :   BinaryForPath.clear();
     140             :   ObjectPairForPathArch.clear();
     141             :   Modules.clear();
     142        1727 : }
     143             : 
     144             : namespace {
     145             : 
     146             : // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
     147             : // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
     148             : // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
     149             : // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
     150          21 : std::string getDarwinDWARFResourceForPath(
     151             :     const std::string &Path, const std::string &Basename) {
     152             :   SmallString<16> ResourceName = StringRef(Path);
     153          42 :   if (sys::path::extension(Path) != ".dSYM") {
     154             :     ResourceName += ".dSYM";
     155             :   }
     156          21 :   sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
     157          21 :   sys::path::append(ResourceName, Basename);
     158          21 :   return ResourceName.str();
     159             : }
     160             : 
     161          95 : bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
     162             :   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
     163          95 :       MemoryBuffer::getFileOrSTDIN(Path);
     164          95 :   if (!MB)
     165             :     return false;
     166           4 :   return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer());
     167             : }
     168             : 
     169          34 : bool findDebugBinary(const std::string &OrigPath,
     170             :                      const std::string &DebuglinkName, uint32_t CRCHash,
     171             :                      std::string &Result) {
     172             :   std::string OrigRealPath = OrigPath;
     173             : #if defined(HAVE_REALPATH)
     174          34 :   if (char *RP = realpath(OrigPath.c_str(), nullptr)) {
     175             :     OrigRealPath = RP;
     176          34 :     free(RP);
     177             :   }
     178             : #endif
     179             :   SmallString<16> OrigDir(OrigRealPath);
     180          34 :   llvm::sys::path::remove_filename(OrigDir);
     181             :   SmallString<16> DebugPath = OrigDir;
     182             :   // Try /path/to/original_binary/debuglink_name
     183          34 :   llvm::sys::path::append(DebugPath, DebuglinkName);
     184          34 :   if (checkFileCRC(DebugPath, CRCHash)) {
     185           3 :     Result = DebugPath.str();
     186           3 :     return true;
     187             :   }
     188             :   // Try /path/to/original_binary/.debug/debuglink_name
     189             :   DebugPath = OrigDir;
     190          31 :   llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
     191          31 :   if (checkFileCRC(DebugPath, CRCHash)) {
     192           1 :     Result = DebugPath.str();
     193           1 :     return true;
     194             :   }
     195             : #if defined(__NetBSD__)
     196             :   // Try /usr/libdata/debug/path/to/original_binary/debuglink_name
     197             :   DebugPath = "/usr/libdata/debug";
     198             : #else
     199             :   // Try /usr/lib/debug/path/to/original_binary/debuglink_name
     200             :   DebugPath = "/usr/lib/debug";
     201             : #endif
     202          30 :   llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
     203             :                           DebuglinkName);
     204          30 :   if (checkFileCRC(DebugPath, CRCHash)) {
     205           0 :     Result = DebugPath.str();
     206           0 :     return true;
     207             :   }
     208             :   return false;
     209             : }
     210             : 
     211         196 : bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
     212             :                              uint32_t &CRCHash) {
     213         196 :   if (!Obj)
     214             :     return false;
     215        6777 :   for (const SectionRef &Section : Obj->sections()) {
     216        6615 :     StringRef Name;
     217        6615 :     Section.getName(Name);
     218       13230 :     Name = Name.substr(Name.find_first_not_of("._"));
     219             :     if (Name == "gnu_debuglink") {
     220          34 :       StringRef Data;
     221          34 :       Section.getContents(Data);
     222          34 :       DataExtractor DE(Data, Obj->isLittleEndian(), 0);
     223          34 :       uint32_t Offset = 0;
     224          34 :       if (const char *DebugNameStr = DE.getCStr(&Offset)) {
     225             :         // 4-byte align the offset.
     226          34 :         Offset = (Offset + 3) & ~0x3;
     227             :         if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
     228             :           DebugName = DebugNameStr;
     229          34 :           CRCHash = DE.getU32(&Offset);
     230          34 :           return true;
     231             :         }
     232             :       }
     233           0 :       break;
     234             :     }
     235             :   }
     236         162 :   return false;
     237             : }
     238             : 
     239           3 : bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
     240             :                              const MachOObjectFile *Obj) {
     241           3 :   ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
     242           3 :   ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
     243           3 :   if (dbg_uuid.empty() || bin_uuid.empty())
     244             :     return false;
     245           3 :   return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
     246             : }
     247             : 
     248             : } // end anonymous namespace
     249             : 
     250          19 : ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
     251             :     const MachOObjectFile *MachExeObj, const std::string &ArchName) {
     252             :   // On Darwin we may find DWARF in separate object file in
     253             :   // resource directory.
     254          19 :   std::vector<std::string> DsymPaths;
     255          19 :   StringRef Filename = sys::path::filename(ExePath);
     256          44 :   DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename));
     257          21 :   for (const auto &Path : Opts.DsymHints) {
     258           5 :     DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename));
     259             :   }
     260          36 :   for (const auto &Path : DsymPaths) {
     261          20 :     auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
     262          20 :     if (!DbgObjOrErr) {
     263             :       // Ignore errors, the file might not exist.
     264          14 :       consumeError(DbgObjOrErr.takeError());
     265          14 :       continue;
     266             :     }
     267           6 :     ObjectFile *DbgObj = DbgObjOrErr.get();
     268           6 :     if (!DbgObj)
     269             :       continue;
     270             :     const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
     271             :     if (!MachDbgObj)
     272             :       continue;
     273           3 :     if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
     274             :       return DbgObj;
     275             :   }
     276             :   return nullptr;
     277             : }
     278             : 
     279         196 : ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
     280             :                                                   const ObjectFile *Obj,
     281             :                                                   const std::string &ArchName) {
     282             :   std::string DebuglinkName;
     283             :   uint32_t CRCHash;
     284             :   std::string DebugBinaryPath;
     285         196 :   if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
     286             :     return nullptr;
     287          34 :   if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
     288             :     return nullptr;
     289           4 :   auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
     290           4 :   if (!DbgObjOrErr) {
     291             :     // Ignore errors, the file might not exist.
     292           0 :     consumeError(DbgObjOrErr.takeError());
     293           0 :     return nullptr;
     294             :   }
     295           4 :   return DbgObjOrErr.get();
     296             : }
     297             : 
     298             : Expected<LLVMSymbolizer::ObjectPair>
     299         236 : LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
     300             :                                       const std::string &ArchName) {
     301         236 :   const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
     302         236 :   if (I != ObjectPairForPathArch.end()) {
     303             :     return I->second;
     304             :   }
     305             : 
     306         233 :   auto ObjOrErr = getOrCreateObject(Path, ArchName);
     307         233 :   if (!ObjOrErr) {
     308          34 :     ObjectPairForPathArch.insert(std::make_pair(std::make_pair(Path, ArchName),
     309             :                                                 ObjectPair(nullptr, nullptr)));
     310             :     return ObjOrErr.takeError();
     311             :   }
     312             : 
     313         199 :   ObjectFile *Obj = ObjOrErr.get();
     314             :   assert(Obj != nullptr);
     315             :   ObjectFile *DbgObj = nullptr;
     316             : 
     317             :   if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
     318          19 :     DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
     319         199 :   if (!DbgObj)
     320         196 :     DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
     321         199 :   if (!DbgObj)
     322             :     DbgObj = Obj;
     323             :   ObjectPair Res = std::make_pair(Obj, DbgObj);
     324             :   ObjectPairForPathArch.insert(
     325         199 :       std::make_pair(std::make_pair(Path, ArchName), Res));
     326             :   return Res;
     327             : }
     328             : 
     329             : Expected<ObjectFile *>
     330         257 : LLVMSymbolizer::getOrCreateObject(const std::string &Path,
     331             :                                   const std::string &ArchName) {
     332             :   const auto &I = BinaryForPath.find(Path);
     333             :   Binary *Bin = nullptr;
     334         257 :   if (I == BinaryForPath.end()) {
     335         248 :     Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
     336         248 :     if (!BinOrErr) {
     337          47 :       BinaryForPath.insert(std::make_pair(Path, OwningBinary<Binary>()));
     338             :       return BinOrErr.takeError();
     339             :     }
     340             :     Bin = BinOrErr->getBinary();
     341         201 :     BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get())));
     342             :   } else {
     343             :     Bin = I->second.getBinary();
     344             :   }
     345             : 
     346         210 :   if (!Bin)
     347             :     return static_cast<ObjectFile *>(nullptr);
     348             : 
     349             :   if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
     350          12 :     const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
     351          12 :     if (I != ObjectForUBPathAndArch.end()) {
     352             :       return I->second.get();
     353             :     }
     354             :     Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
     355          36 :         UB->getObjectForArch(ArchName);
     356          12 :     if (!ObjOrErr) {
     357           1 :       ObjectForUBPathAndArch.insert(std::make_pair(
     358           1 :           std::make_pair(Path, ArchName), std::unique_ptr<ObjectFile>()));
     359             :       return ObjOrErr.takeError();
     360             :     }
     361             :     ObjectFile *Res = ObjOrErr->get();
     362          11 :     ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName),
     363             :                                                  std::move(ObjOrErr.get())));
     364             :     return Res;
     365             :   }
     366         390 :   if (Bin->isObject()) {
     367             :     return cast<ObjectFile>(Bin);
     368             :   }
     369           0 :   return errorCodeToError(object_error::arch_not_found);
     370             : }
     371             : 
     372             : Expected<SymbolizableModule *>
     373        1442 : LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName,
     374             :                                       StringRef DWPName) {
     375             :   const auto &I = Modules.find(ModuleName);
     376        1442 :   if (I != Modules.end()) {
     377             :     return I->second.get();
     378             :   }
     379             :   std::string BinaryName = ModuleName;
     380             :   std::string ArchName = Opts.DefaultArch;
     381             :   size_t ColonPos = ModuleName.find_last_of(':');
     382             :   // Verify that substring after colon form a valid arch name.
     383         236 :   if (ColonPos != std::string::npos) {
     384           6 :     std::string ArchStr = ModuleName.substr(ColonPos + 1);
     385           6 :     if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
     386          12 :       BinaryName = ModuleName.substr(0, ColonPos);
     387             :       ArchName = ArchStr;
     388             :     }
     389             :   }
     390         236 :   auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
     391         236 :   if (!ObjectsOrErr) {
     392             :     // Failed to find valid object file.
     393             :     Modules.insert(
     394          34 :         std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
     395             :     return ObjectsOrErr.takeError();
     396             :   }
     397         202 :   ObjectPair Objects = ObjectsOrErr.get();
     398             : 
     399             :   std::unique_ptr<DIContext> Context;
     400             :   // If this is a COFF object containing PDB info, use a PDBContext to
     401             :   // symbolize. Otherwise, use DWARF.
     402             :   if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
     403             :     const codeview::DebugInfo *DebugInfo;
     404           0 :     StringRef PDBFileName;
     405           0 :     auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
     406           0 :     if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
     407             :       using namespace pdb;
     408           0 :       std::unique_ptr<IPDBSession> Session;
     409           0 :       if (auto Err = loadDataForEXE(PDB_ReaderType::DIA,
     410           0 :                                     Objects.first->getFileName(), Session)) {
     411             :         Modules.insert(
     412           0 :             std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
     413             :         // Return along the PDB filename to provide more context
     414           0 :         return createFileError(PDBFileName, std::move(Err));
     415             :       }
     416           0 :       Context.reset(new PDBContext(*CoffObject, std::move(Session)));
     417             :     }
     418             :   }
     419         202 :   if (!Context)
     420         202 :     Context = DWARFContext::create(*Objects.second, nullptr,
     421             :                                    DWARFContext::defaultErrorHandler, DWPName);
     422             :   assert(Context);
     423             :   auto InfoOrErr =
     424         404 :       SymbolizableObjectFile::create(Objects.first, std::move(Context));
     425             :   std::unique_ptr<SymbolizableModule> SymMod;
     426         202 :   if (InfoOrErr)
     427             :     SymMod = std::move(InfoOrErr.get());
     428             :   auto InsertResult =
     429         202 :       Modules.insert(std::make_pair(ModuleName, std::move(SymMod)));
     430             :   assert(InsertResult.second);
     431         202 :   if (auto EC = InfoOrErr.getError())
     432           0 :     return errorCodeToError(EC);
     433             :   return InsertResult.first->second.get();
     434             : }
     435             : 
     436             : namespace {
     437             : 
     438             : // Undo these various manglings for Win32 extern "C" functions:
     439             : // cdecl       - _foo
     440             : // stdcall     - _foo@12
     441             : // fastcall    - @foo@12
     442             : // vectorcall  - foo@@12
     443             : // These are all different linkage names for 'foo'.
     444           0 : StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
     445             :   // Remove any '_' or '@' prefix.
     446           0 :   char Front = SymbolName.empty() ? '\0' : SymbolName[0];
     447           0 :   if (Front == '_' || Front == '@')
     448           0 :     SymbolName = SymbolName.drop_front();
     449             : 
     450             :   // Remove any '@[0-9]+' suffix.
     451           0 :   if (Front != '?') {
     452           0 :     size_t AtPos = SymbolName.rfind('@');
     453           0 :     if (AtPos != StringRef::npos &&
     454           0 :         std::all_of(SymbolName.begin() + AtPos + 1, SymbolName.end(),
     455           0 :                     [](char C) { return C >= '0' && C <= '9'; })) {
     456           0 :       SymbolName = SymbolName.substr(0, AtPos);
     457             :     }
     458             :   }
     459             : 
     460             :   // Remove any ending '@' for vectorcall.
     461             :   if (SymbolName.endswith("@"))
     462           0 :     SymbolName = SymbolName.drop_back();
     463             : 
     464           0 :   return SymbolName;
     465             : }
     466             : 
     467             : } // end anonymous namespace
     468             : 
     469             : std::string
     470         826 : LLVMSymbolizer::DemangleName(const std::string &Name,
     471             :                              const SymbolizableModule *DbiModuleDescriptor) {
     472             :   // We can spoil names of symbols with C linkage, so use an heuristic
     473             :   // approach to check if the name should be demangled.
     474        1652 :   if (Name.substr(0, 2) == "_Z") {
     475         398 :     int status = 0;
     476         398 :     char *DemangledName = itaniumDemangle(Name.c_str(), nullptr, nullptr, &status);
     477         398 :     if (status != 0)
     478             :       return Name;
     479         398 :     std::string Result = DemangledName;
     480         398 :     free(DemangledName);
     481             :     return Result;
     482             :   }
     483             : 
     484             : #if defined(_MSC_VER)
     485             :   if (!Name.empty() && Name.front() == '?') {
     486             :     // Only do MSVC C++ demangling on symbols starting with '?'.
     487             :     char DemangledName[1024] = {0};
     488             :     DWORD result = ::UnDecorateSymbolName(
     489             :         Name.c_str(), DemangledName, 1023,
     490             :         UNDNAME_NO_ACCESS_SPECIFIERS |       // Strip public, private, protected
     491             :             UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc
     492             :             UNDNAME_NO_THROW_SIGNATURES |    // Strip throw() specifications
     493             :             UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
     494             :             UNDNAME_NO_MS_KEYWORDS | // Strip all MS extension keywords
     495             :             UNDNAME_NO_FUNCTION_RETURNS); // Strip function return types
     496             :     return (result == 0) ? Name : std::string(DemangledName);
     497             :   }
     498             : #endif
     499         428 :   if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module())
     500           0 :     return std::string(demanglePE32ExternCFunc(Name));
     501             :   return Name;
     502             : }
     503             : 
     504             : } // namespace symbolize
     505             : } // namespace llvm

Generated by: LCOV version 1.13