X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FDebugInfo%2FSymbolize%2FSymbolize.cpp;h=3da1963bb791da7424f85078215e871595e5d694;hp=aa24dd945d15bd3a035a8a162befbd6b3f8cee48;hb=9dcc66e06e5d5a2830a93aad80d5fa1e8343927a;hpb=561b5b7865df7ee6d037d5545c45d62d03315f6e diff --git a/lib/DebugInfo/Symbolize/Symbolize.cpp b/lib/DebugInfo/Symbolize/Symbolize.cpp index aa24dd945d1..3da1963bb79 100644 --- a/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -13,6 +13,8 @@ #include "llvm/DebugInfo/Symbolize/Symbolize.h" +#include "SymbolizableObjectFile.h" + #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" @@ -20,7 +22,7 @@ #include "llvm/DebugInfo/PDB/PDBContext.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" -#include "llvm/Object/SymbolSize.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" @@ -29,7 +31,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" -#include #include #if defined(_MSC_VER) @@ -46,273 +47,73 @@ namespace llvm { namespace symbolize { -// FIXME: Move this to llvm-symbolizer tool. -static bool error(std::error_code ec) { - if (!ec) - return false; - errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; - return true; -} - -static DILineInfoSpecifier -getDILineInfoSpecifier(const LLVMSymbolizer::Options &Opts) { - return DILineInfoSpecifier( - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - Opts.PrintFunctions); -} - -ModuleInfo::ModuleInfo(ObjectFile *Obj, std::unique_ptr DICtx) - : Module(Obj), DebugInfoContext(std::move(DICtx)) { - std::unique_ptr OpdExtractor; - uint64_t OpdAddress = 0; - // Find the .opd (function descriptor) section if any, for big-endian - // PowerPC64 ELF. - if (Module->getArch() == Triple::ppc64) { - for (section_iterator Section : Module->sections()) { - StringRef Name; - if (!error(Section->getName(Name)) && Name == ".opd") { - StringRef Data; - if (!error(Section->getContents(Data))) { - OpdExtractor.reset(new DataExtractor(Data, Module->isLittleEndian(), - Module->getBytesInAddress())); - OpdAddress = Section->getAddress(); - } - break; - } - } - } - std::vector> Symbols = - computeSymbolSizes(*Module); - for (auto &P : Symbols) - addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress); - - // If this is a COFF object and we didn't find any symbols, try the export - // table. - if (Symbols.empty()) { - if (auto *CoffObj = dyn_cast(Obj)) - addCoffExportSymbols(CoffObj); - } -} - -namespace { -struct OffsetNamePair { - uint32_t Offset; - StringRef Name; - bool operator<(const OffsetNamePair &R) const { - return Offset < R.Offset; - } -}; -} - -void ModuleInfo::addCoffExportSymbols(const COFFObjectFile *CoffObj) { - // Get all export names and offsets. - std::vector ExportSyms; - for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) { - StringRef Name; - uint32_t Offset; - if (error(Ref.getSymbolName(Name)) || error(Ref.getExportRVA(Offset))) - return; - ExportSyms.push_back(OffsetNamePair{Offset, Name}); - } - if (ExportSyms.empty()) - return; - - // Sort by ascending offset. - array_pod_sort(ExportSyms.begin(), ExportSyms.end()); - - // Approximate the symbol sizes by assuming they run to the next symbol. - // FIXME: This assumes all exports are functions. - uint64_t ImageBase = CoffObj->getImageBase(); - for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) { - OffsetNamePair &Export = *I; - // FIXME: The last export has a one byte size now. - uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1; - uint64_t SymbolStart = ImageBase + Export.Offset; - uint64_t SymbolSize = NextOffset - Export.Offset; - SymbolDesc SD = {SymbolStart, SymbolSize}; - Functions.insert(std::make_pair(SD, Export.Name)); - } -} - -void ModuleInfo::addSymbol(const SymbolRef &Symbol, uint64_t SymbolSize, - DataExtractor *OpdExtractor, uint64_t OpdAddress) { - SymbolRef::Type SymbolType = Symbol.getType(); - if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) - return; - ErrorOr SymbolAddressOrErr = Symbol.getAddress(); - if (error(SymbolAddressOrErr.getError())) - return; - uint64_t SymbolAddress = *SymbolAddressOrErr; - if (OpdExtractor) { - // For big-endian PowerPC64 ELF, symbols in the .opd section refer to - // function descriptors. The first word of the descriptor is a pointer to - // the function's code. - // For the purposes of symbolization, pretend the symbol's address is that - // of the function's code, not the descriptor. - uint64_t OpdOffset = SymbolAddress - OpdAddress; - uint32_t OpdOffset32 = OpdOffset; - if (OpdOffset == OpdOffset32 && - OpdExtractor->isValidOffsetForAddress(OpdOffset32)) - SymbolAddress = OpdExtractor->getAddress(&OpdOffset32); - } - ErrorOr SymbolNameOrErr = Symbol.getName(); - if (error(SymbolNameOrErr.getError())) - return; - StringRef SymbolName = *SymbolNameOrErr; - // Mach-O symbol table names have leading underscore, skip it. - if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_') - SymbolName = SymbolName.drop_front(); - // FIXME: If a function has alias, there are two entries in symbol table - // with same address size. Make sure we choose the correct one. - auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; - SymbolDesc SD = { SymbolAddress, SymbolSize }; - M.insert(std::make_pair(SD, SymbolName)); -} - -// Return true if this is a 32-bit x86 PE COFF module. -bool ModuleInfo::isWin32Module() const { - auto *CoffObject = dyn_cast(Module); - return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386; -} - -uint64_t ModuleInfo::getModulePreferredBase() const { - if (auto *CoffObject = dyn_cast(Module)) - return CoffObject->getImageBase(); - return 0; -} +ErrorOr LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, + uint64_t ModuleOffset) { + auto InfoOrErr = getOrCreateModuleInfo(ModuleName); + if (auto EC = InfoOrErr.getError()) + return EC; + SymbolizableModule *Info = InfoOrErr.get(); -bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, - std::string &Name, uint64_t &Addr, - uint64_t &Size) const { - const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects; - if (SymbolMap.empty()) - return false; - SymbolDesc SD = { Address, Address }; - auto SymbolIterator = SymbolMap.upper_bound(SD); - if (SymbolIterator == SymbolMap.begin()) - return false; - --SymbolIterator; - if (SymbolIterator->first.Size != 0 && - SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address) - return false; - Name = SymbolIterator->second.str(); - Addr = SymbolIterator->first.Addr; - Size = SymbolIterator->first.Size; - return true; -} + // If the user is giving us relative addresses, add the preferred base of the + // object to the offset before we do the query. It's what DIContext expects. + if (Opts.RelativeAddresses) + ModuleOffset += Info->getModulePreferredBase(); -DILineInfo ModuleInfo::symbolizeCode( - uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const { - DILineInfo LineInfo; - if (DebugInfoContext) { - LineInfo = DebugInfoContext->getLineInfoForAddress( - ModuleOffset, getDILineInfoSpecifier(Opts)); - } - // Override function name from symbol table if necessary. - if (Opts.PrintFunctions == FunctionNameKind::LinkageName && - Opts.UseSymbolTable) { - std::string FunctionName; - uint64_t Start, Size; - if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, - FunctionName, Start, Size)) { - LineInfo.FunctionName = FunctionName; - } - } + DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts.PrintFunctions, + Opts.UseSymbolTable); + if (Opts.Demangle) + LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info); return LineInfo; } -DIInliningInfo ModuleInfo::symbolizeInlinedCode( - uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const { - DIInliningInfo InlinedContext; - - if (DebugInfoContext) { - InlinedContext = DebugInfoContext->getInliningInfoForAddress( - ModuleOffset, getDILineInfoSpecifier(Opts)); - } - // Make sure there is at least one frame in context. - if (InlinedContext.getNumberOfFrames() == 0) { - InlinedContext.addFrame(DILineInfo()); - } - // Override the function name in lower frame with name from symbol table. - if (Opts.PrintFunctions == FunctionNameKind::LinkageName && - Opts.UseSymbolTable) { - DIInliningInfo PatchedInlinedContext; - for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { - DILineInfo LineInfo = InlinedContext.getFrame(i); - if (i == n - 1) { - std::string FunctionName; - uint64_t Start, Size; - if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, - FunctionName, Start, Size)) { - LineInfo.FunctionName = FunctionName; - } - } - PatchedInlinedContext.addFrame(LineInfo); - } - InlinedContext = PatchedInlinedContext; - } - return InlinedContext; -} - -bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name, - uint64_t &Start, uint64_t &Size) const { - return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start, - Size); -} - -const char LLVMSymbolizer::kBadString[] = "??"; - -std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, - uint64_t ModuleOffset) { - ModuleInfo *Info = getOrCreateModuleInfo(ModuleName); - if (!Info) - return printDILineInfo(DILineInfo(), Info); +ErrorOr +LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName, + uint64_t ModuleOffset) { + auto InfoOrErr = getOrCreateModuleInfo(ModuleName); + if (auto EC = InfoOrErr.getError()) + return EC; + SymbolizableModule *Info = InfoOrErr.get(); // If the user is giving us relative addresses, add the preferred base of the // object to the offset before we do the query. It's what DIContext expects. if (Opts.RelativeAddresses) ModuleOffset += Info->getModulePreferredBase(); - if (Opts.PrintInlining) { - DIInliningInfo InlinedContext = - Info->symbolizeInlinedCode(ModuleOffset, Opts); - uint32_t FramesNum = InlinedContext.getNumberOfFrames(); - assert(FramesNum > 0); - std::string Result; - for (uint32_t i = 0; i < FramesNum; i++) { - DILineInfo LineInfo = InlinedContext.getFrame(i); - Result += printDILineInfo(LineInfo, Info); + DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( + ModuleOffset, Opts.PrintFunctions, Opts.UseSymbolTable); + if (Opts.Demangle) { + for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { + auto *Frame = InlinedContext.getMutableFrame(i); + Frame->FunctionName = DemangleName(Frame->FunctionName, Info); } - return Result; } - DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts); - return printDILineInfo(LineInfo, Info); + return InlinedContext; } -std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, - uint64_t ModuleOffset) { - std::string Name = kBadString; - uint64_t Start = 0; - uint64_t Size = 0; - if (Opts.UseSymbolTable) { - if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { - // If the user is giving us relative addresses, add the preferred base of the - // object to the offset before we do the query. It's what DIContext expects. - if (Opts.RelativeAddresses) - ModuleOffset += Info->getModulePreferredBase(); - if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) - Name = DemangleName(Name, Info); - } - } - std::stringstream ss; - ss << Name << "\n" << Start << " " << Size << "\n"; - return ss.str(); +ErrorOr LLVMSymbolizer::symbolizeData(const std::string &ModuleName, + uint64_t ModuleOffset) { + auto InfoOrErr = getOrCreateModuleInfo(ModuleName); + if (auto EC = InfoOrErr.getError()) + return EC; + SymbolizableModule *Info = InfoOrErr.get(); + + // If the user is giving us relative addresses, add the preferred base of + // the object to the offset before we do the query. It's what DIContext + // expects. + if (Opts.RelativeAddresses) + ModuleOffset += Info->getModulePreferredBase(); + + DIGlobal Global = Info->symbolizeData(ModuleOffset); + if (Opts.Demangle) + Global.Name = DemangleName(Global.Name, Info); + return Global; } void LLVMSymbolizer::flush() { - Modules.clear(); + ObjectForUBPathAndArch.clear(); + BinaryForPath.clear(); ObjectPairForPathArch.clear(); - ObjectFileForArch.clear(); + Modules.clear(); } // For Path="/path/to/foo" and Basename="foo" assume that debug info is in @@ -424,97 +225,121 @@ ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, for (const auto &Path : Opts.DsymHints) { DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename)); } - for (const auto &path : DsymPaths) { - ErrorOr> BinaryOrErr = createBinary(path); - std::error_code EC = BinaryOrErr.getError(); - if (EC != errc::no_such_file_or_directory && !error(EC)) { - OwningBinary B = std::move(BinaryOrErr.get()); - ObjectFile *DbgObj = - getObjectFileFromBinary(B.getBinary(), ArchName); - const MachOObjectFile *MachDbgObj = - dyn_cast(DbgObj); - if (!MachDbgObj) continue; - if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) { - addOwningBinary(std::move(B)); - return DbgObj; - } - } + for (const auto &Path : DsymPaths) { + auto DbgObjOrErr = getOrCreateObject(Path, ArchName); + if (!DbgObjOrErr) + continue; + ObjectFile *DbgObj = DbgObjOrErr.get(); + const MachOObjectFile *MachDbgObj = dyn_cast(DbgObj); + if (!MachDbgObj) + continue; + if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) + return DbgObj; } return nullptr; } -LLVMSymbolizer::ObjectPair -LLVMSymbolizer::getOrCreateObjects(const std::string &Path, - const std::string &ArchName) { +ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path, + const ObjectFile *Obj, + const std::string &ArchName) { + std::string DebuglinkName; + uint32_t CRCHash; + std::string DebugBinaryPath; + if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash)) + return nullptr; + if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) + return nullptr; + auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); + if (!DbgObjOrErr) + return nullptr; + return DbgObjOrErr.get(); +} + +ErrorOr +LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, + const std::string &ArchName) { const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); if (I != ObjectPairForPathArch.end()) return I->second; - ObjectFile *Obj = nullptr; - ObjectFile *DbgObj = nullptr; - ErrorOr> BinaryOrErr = createBinary(Path); - if (!error(BinaryOrErr.getError())) { - OwningBinary &B = BinaryOrErr.get(); - Obj = getObjectFileFromBinary(B.getBinary(), ArchName); - if (!Obj) { - ObjectPair Res = std::make_pair(nullptr, nullptr); - ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res; - return Res; - } - addOwningBinary(std::move(B)); - if (auto MachObj = dyn_cast(Obj)) - DbgObj = lookUpDsymFile(Path, MachObj, ArchName); - // Try to locate the debug binary using .gnu_debuglink section. - if (!DbgObj) { - std::string DebuglinkName; - uint32_t CRCHash; - std::string DebugBinaryPath; - if (getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash) && - findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) { - BinaryOrErr = createBinary(DebugBinaryPath); - if (!error(BinaryOrErr.getError())) { - OwningBinary B = std::move(BinaryOrErr.get()); - DbgObj = getObjectFileFromBinary(B.getBinary(), ArchName); - addOwningBinary(std::move(B)); - } - } - } + + auto ObjOrErr = getOrCreateObject(Path, ArchName); + if (auto EC = ObjOrErr.getError()) { + ObjectPairForPathArch.insert( + std::make_pair(std::make_pair(Path, ArchName), EC)); + return EC; } + + ObjectFile *Obj = ObjOrErr.get(); + assert(Obj != nullptr); + ObjectFile *DbgObj = nullptr; + + if (auto MachObj = dyn_cast(Obj)) + DbgObj = lookUpDsymFile(Path, MachObj, ArchName); + if (!DbgObj) + DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName); if (!DbgObj) DbgObj = Obj; ObjectPair Res = std::make_pair(Obj, DbgObj); - ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res; + ObjectPairForPathArch.insert( + std::make_pair(std::make_pair(Path, ArchName), Res)); return Res; } -ObjectFile * -LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, - const std::string &ArchName) { - if (!Bin) - return nullptr; - ObjectFile *Res = nullptr; +ErrorOr +LLVMSymbolizer::getOrCreateObject(const std::string &Path, + const std::string &ArchName) { + const auto &I = BinaryForPath.find(Path); + Binary *Bin = nullptr; + if (I == BinaryForPath.end()) { + ErrorOr> BinOrErr = createBinary(Path); + if (auto EC = BinOrErr.getError()) { + BinaryForPath.insert(std::make_pair(Path, EC)); + return EC; + } + Bin = BinOrErr->getBinary(); + BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get()))); + } else if (auto EC = I->second.getError()) { + return EC; + } else { + Bin = I->second->getBinary(); + } + + assert(Bin != nullptr); + if (MachOUniversalBinary *UB = dyn_cast(Bin)) { - const auto &I = ObjectFileForArch.find( - std::make_pair(UB, ArchName)); - if (I != ObjectFileForArch.end()) - return I->second; - ErrorOr> ParsedObj = + const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); + if (I != ObjectForUBPathAndArch.end()) { + if (auto EC = I->second.getError()) + return EC; + return I->second->get(); + } + ErrorOr> ObjOrErr = UB->getObjectForArch(ArchName); - if (ParsedObj) { - Res = ParsedObj.get().get(); - ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get())); + if (auto EC = ObjOrErr.getError()) { + ObjectForUBPathAndArch.insert( + std::make_pair(std::make_pair(Path, ArchName), EC)); + return EC; } - ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; - } else if (Bin->isObject()) { - Res = cast(Bin); + ObjectFile *Res = ObjOrErr->get(); + ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName), + std::move(ObjOrErr.get()))); + return Res; } - return Res; + if (Bin->isObject()) { + return cast(Bin); + } + return object_error::arch_not_found; } -ModuleInfo * +ErrorOr LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { const auto &I = Modules.find(ModuleName); - if (I != Modules.end()) - return I->second.get(); + if (I != Modules.end()) { + auto &InfoOrErr = I->second; + if (auto EC = InfoOrErr.getError()) + return EC; + return InfoOrErr->get(); + } std::string BinaryName = ModuleName; std::string ArchName = Opts.DefaultArch; size_t ColonPos = ModuleName.find_last_of(':'); @@ -526,13 +351,14 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { ArchName = ArchStr; } } - ObjectPair Objects = getOrCreateObjects(BinaryName, ArchName); - - if (!Objects.first) { + auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName); + if (auto EC = ObjectsOrErr.getError()) { // Failed to find valid object file. - Modules.insert(make_pair(ModuleName, nullptr)); - return nullptr; + Modules.insert(std::make_pair(ModuleName, EC)); + return EC; } + ObjectPair Objects = ObjectsOrErr.get(); + std::unique_ptr Context; if (auto CoffObject = dyn_cast(Objects.first)) { // If this is a COFF object, assume it contains PDB debug information. If @@ -547,31 +373,14 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { if (!Context) Context.reset(new DWARFContextInMemory(*Objects.second)); assert(Context); - auto Info = llvm::make_unique(Objects.first, std::move(Context)); - ModuleInfo *Res = Info.get(); - Modules.emplace(ModuleName, std::move(Info)); - return Res; -} - -std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo, - ModuleInfo *ModInfo) const { - // By default, DILineInfo contains "" for function/filename it - // cannot fetch. We replace it to "??" to make our output closer to addr2line. - static const std::string kDILineInfoBadString = ""; - std::stringstream Result; - if (Opts.PrintFunctions != FunctionNameKind::None) { - std::string FunctionName = LineInfo.FunctionName; - if (FunctionName == kDILineInfoBadString) - FunctionName = kBadString; - else if (Opts.Demangle) - FunctionName = DemangleName(FunctionName, ModInfo); - Result << FunctionName << "\n"; - } - std::string Filename = LineInfo.FileName; - if (Filename == kDILineInfoBadString) - Filename = kBadString; - Result << Filename << ":" << LineInfo.Line << ":" << LineInfo.Column << "\n"; - return Result.str(); + auto InfoOrErr = + SymbolizableObjectFile::create(Objects.first, std::move(Context)); + auto InsertResult = + Modules.insert(std::make_pair(ModuleName, std::move(InfoOrErr))); + assert(InsertResult.second); + if (auto EC = InsertResult.first->second.getError()) + return EC; + return InsertResult.first->second->get(); } // Undo these various manglings for Win32 extern "C" functions: @@ -610,7 +419,7 @@ extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, #endif std::string LLVMSymbolizer::DemangleName(const std::string &Name, - ModuleInfo *ModInfo) { + const SymbolizableModule *ModInfo) { #if !defined(_MSC_VER) // We can spoil names of symbols with C linkage, so use an heuristic // approach to check if the name should be demangled. @@ -638,7 +447,7 @@ std::string LLVMSymbolizer::DemangleName(const std::string &Name, return (result == 0) ? Name : std::string(DemangledName); } #endif - if (ModInfo->isWin32Module()) + if (ModInfo && ModInfo->isWin32Module()) return std::string(demanglePE32ExternCFunc(Name)); return Name; }