xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp (revision d5b0e70f7e04d971691517ce1304d86a1e367e2e)
1 //===-- LLVMSymbolize.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implementation for LLVM symbolization library.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
14 
15 #include "SymbolizableObjectFile.h"
16 
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/BinaryFormat/COFF.h"
19 #include "llvm/Config/config.h"
20 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
21 #include "llvm/DebugInfo/PDB/PDB.h"
22 #include "llvm/DebugInfo/PDB/PDBContext.h"
23 #include "llvm/DebugInfo/Symbolize/DIFetcher.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/CRC.h"
29 #include "llvm/Support/Casting.h"
30 #include "llvm/Support/Compression.h"
31 #include "llvm/Support/DataExtractor.h"
32 #include "llvm/Support/Errc.h"
33 #include "llvm/Support/FileSystem.h"
34 #include "llvm/Support/MemoryBuffer.h"
35 #include "llvm/Support/Path.h"
36 #include <algorithm>
37 #include <cassert>
38 #include <cstring>
39 
40 namespace llvm {
41 namespace symbolize {
42 
43 template <typename T>
44 Expected<DILineInfo>
45 LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
46                                     object::SectionedAddress ModuleOffset) {
47 
48   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
49   if (!InfoOrErr)
50     return InfoOrErr.takeError();
51 
52   SymbolizableModule *Info = *InfoOrErr;
53 
54   // A null module means an error has already been reported. Return an empty
55   // result.
56   if (!Info)
57     return DILineInfo();
58 
59   // If the user is giving us relative addresses, add the preferred base of the
60   // object to the offset before we do the query. It's what DIContext expects.
61   if (Opts.RelativeAddresses)
62     ModuleOffset.Address += Info->getModulePreferredBase();
63 
64   DILineInfo LineInfo = Info->symbolizeCode(
65       ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
66       Opts.UseSymbolTable);
67   if (Opts.Demangle)
68     LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
69   return LineInfo;
70 }
71 
72 Expected<DILineInfo>
73 LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj,
74                               object::SectionedAddress ModuleOffset) {
75   return symbolizeCodeCommon(Obj, ModuleOffset);
76 }
77 
78 Expected<DILineInfo>
79 LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
80                               object::SectionedAddress ModuleOffset) {
81   return symbolizeCodeCommon(ModuleName, ModuleOffset);
82 }
83 
84 template <typename T>
85 Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
86     const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
87   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
88   if (!InfoOrErr)
89     return InfoOrErr.takeError();
90 
91   SymbolizableModule *Info = *InfoOrErr;
92 
93   // A null module means an error has already been reported. Return an empty
94   // result.
95   if (!Info)
96     return DIInliningInfo();
97 
98   // If the user is giving us relative addresses, add the preferred base of the
99   // object to the offset before we do the query. It's what DIContext expects.
100   if (Opts.RelativeAddresses)
101     ModuleOffset.Address += Info->getModulePreferredBase();
102 
103   DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
104       ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
105       Opts.UseSymbolTable);
106   if (Opts.Demangle) {
107     for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
108       auto *Frame = InlinedContext.getMutableFrame(i);
109       Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
110     }
111   }
112   return InlinedContext;
113 }
114 
115 Expected<DIInliningInfo>
116 LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj,
117                                      object::SectionedAddress ModuleOffset) {
118   return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
119 }
120 
121 Expected<DIInliningInfo>
122 LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
123                                      object::SectionedAddress ModuleOffset) {
124   return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
125 }
126 
127 template <typename T>
128 Expected<DIGlobal>
129 LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
130                                     object::SectionedAddress ModuleOffset) {
131 
132   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
133   if (!InfoOrErr)
134     return InfoOrErr.takeError();
135 
136   SymbolizableModule *Info = *InfoOrErr;
137   // A null module means an error has already been reported. Return an empty
138   // result.
139   if (!Info)
140     return DIGlobal();
141 
142   // If the user is giving us relative addresses, add the preferred base of
143   // the object to the offset before we do the query. It's what DIContext
144   // expects.
145   if (Opts.RelativeAddresses)
146     ModuleOffset.Address += Info->getModulePreferredBase();
147 
148   DIGlobal Global = Info->symbolizeData(ModuleOffset);
149   if (Opts.Demangle)
150     Global.Name = DemangleName(Global.Name, Info);
151   return Global;
152 }
153 
154 Expected<DIGlobal>
155 LLVMSymbolizer::symbolizeData(const ObjectFile &Obj,
156                               object::SectionedAddress ModuleOffset) {
157   return symbolizeDataCommon(Obj, ModuleOffset);
158 }
159 
160 Expected<DIGlobal>
161 LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
162                               object::SectionedAddress ModuleOffset) {
163   return symbolizeDataCommon(ModuleName, ModuleOffset);
164 }
165 
166 template <typename T>
167 Expected<std::vector<DILocal>>
168 LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
169                                      object::SectionedAddress ModuleOffset) {
170   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
171   if (!InfoOrErr)
172     return InfoOrErr.takeError();
173 
174   SymbolizableModule *Info = *InfoOrErr;
175   // A null module means an error has already been reported. Return an empty
176   // result.
177   if (!Info)
178     return std::vector<DILocal>();
179 
180   // If the user is giving us relative addresses, add the preferred base of
181   // the object to the offset before we do the query. It's what DIContext
182   // expects.
183   if (Opts.RelativeAddresses)
184     ModuleOffset.Address += Info->getModulePreferredBase();
185 
186   return Info->symbolizeFrame(ModuleOffset);
187 }
188 
189 Expected<std::vector<DILocal>>
190 LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj,
191                                object::SectionedAddress ModuleOffset) {
192   return symbolizeFrameCommon(Obj, ModuleOffset);
193 }
194 
195 Expected<std::vector<DILocal>>
196 LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
197                                object::SectionedAddress ModuleOffset) {
198   return symbolizeFrameCommon(ModuleName, ModuleOffset);
199 }
200 
201 void LLVMSymbolizer::flush() {
202   ObjectForUBPathAndArch.clear();
203   BinaryForPath.clear();
204   ObjectPairForPathArch.clear();
205   Modules.clear();
206 }
207 
208 namespace {
209 
210 // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
211 // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
212 // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
213 // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
214 std::string getDarwinDWARFResourceForPath(const std::string &Path,
215                                           const std::string &Basename) {
216   SmallString<16> ResourceName = StringRef(Path);
217   if (sys::path::extension(Path) != ".dSYM") {
218     ResourceName += ".dSYM";
219   }
220   sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
221   sys::path::append(ResourceName, Basename);
222   return std::string(ResourceName.str());
223 }
224 
225 bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
226   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
227       MemoryBuffer::getFileOrSTDIN(Path);
228   if (!MB)
229     return false;
230   return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer()));
231 }
232 
233 bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
234                              uint32_t &CRCHash) {
235   if (!Obj)
236     return false;
237   for (const SectionRef &Section : Obj->sections()) {
238     StringRef Name;
239     consumeError(Section.getName().moveInto(Name));
240 
241     Name = Name.substr(Name.find_first_not_of("._"));
242     if (Name == "gnu_debuglink") {
243       Expected<StringRef> ContentsOrErr = Section.getContents();
244       if (!ContentsOrErr) {
245         consumeError(ContentsOrErr.takeError());
246         return false;
247       }
248       DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0);
249       uint64_t Offset = 0;
250       if (const char *DebugNameStr = DE.getCStr(&Offset)) {
251         // 4-byte align the offset.
252         Offset = (Offset + 3) & ~0x3;
253         if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
254           DebugName = DebugNameStr;
255           CRCHash = DE.getU32(&Offset);
256           return true;
257         }
258       }
259       break;
260     }
261   }
262   return false;
263 }
264 
265 bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
266                              const MachOObjectFile *Obj) {
267   ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
268   ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
269   if (dbg_uuid.empty() || bin_uuid.empty())
270     return false;
271   return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
272 }
273 
274 template <typename ELFT>
275 Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> &Obj) {
276   auto PhdrsOrErr = Obj.program_headers();
277   if (!PhdrsOrErr) {
278     consumeError(PhdrsOrErr.takeError());
279     return {};
280   }
281   for (const auto &P : *PhdrsOrErr) {
282     if (P.p_type != ELF::PT_NOTE)
283       continue;
284     Error Err = Error::success();
285     for (auto N : Obj.notes(P, Err))
286       if (N.getType() == ELF::NT_GNU_BUILD_ID &&
287           N.getName() == ELF::ELF_NOTE_GNU)
288         return N.getDesc();
289     consumeError(std::move(Err));
290   }
291   return {};
292 }
293 
294 Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) {
295   Optional<ArrayRef<uint8_t>> BuildID;
296   if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
297     BuildID = getBuildID(O->getELFFile());
298   else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
299     BuildID = getBuildID(O->getELFFile());
300   else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
301     BuildID = getBuildID(O->getELFFile());
302   else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
303     BuildID = getBuildID(O->getELFFile());
304   else
305     llvm_unreachable("unsupported file format");
306   return BuildID;
307 }
308 
309 } // end anonymous namespace
310 
311 ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
312                                            const MachOObjectFile *MachExeObj,
313                                            const std::string &ArchName) {
314   // On Darwin we may find DWARF in separate object file in
315   // resource directory.
316   std::vector<std::string> DsymPaths;
317   StringRef Filename = sys::path::filename(ExePath);
318   DsymPaths.push_back(
319       getDarwinDWARFResourceForPath(ExePath, std::string(Filename)));
320   for (const auto &Path : Opts.DsymHints) {
321     DsymPaths.push_back(
322         getDarwinDWARFResourceForPath(Path, std::string(Filename)));
323   }
324   for (const auto &Path : DsymPaths) {
325     auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
326     if (!DbgObjOrErr) {
327       // Ignore errors, the file might not exist.
328       consumeError(DbgObjOrErr.takeError());
329       continue;
330     }
331     ObjectFile *DbgObj = DbgObjOrErr.get();
332     if (!DbgObj)
333       continue;
334     const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
335     if (!MachDbgObj)
336       continue;
337     if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
338       return DbgObj;
339   }
340   return nullptr;
341 }
342 
343 ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
344                                                   const ObjectFile *Obj,
345                                                   const std::string &ArchName) {
346   std::string DebuglinkName;
347   uint32_t CRCHash;
348   std::string DebugBinaryPath;
349   if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
350     return nullptr;
351   if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
352     return nullptr;
353   auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
354   if (!DbgObjOrErr) {
355     // Ignore errors, the file might not exist.
356     consumeError(DbgObjOrErr.takeError());
357     return nullptr;
358   }
359   return DbgObjOrErr.get();
360 }
361 
362 ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
363                                                 const ELFObjectFileBase *Obj,
364                                                 const std::string &ArchName) {
365   auto BuildID = getBuildID(Obj);
366   if (!BuildID)
367     return nullptr;
368   if (BuildID->size() < 2)
369     return nullptr;
370   std::string DebugBinaryPath;
371   if (!findDebugBinary(*BuildID, DebugBinaryPath))
372     return nullptr;
373   auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
374   if (!DbgObjOrErr) {
375     consumeError(DbgObjOrErr.takeError());
376     return nullptr;
377   }
378   return DbgObjOrErr.get();
379 }
380 
381 bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath,
382                                      const std::string &DebuglinkName,
383                                      uint32_t CRCHash, std::string &Result) {
384   SmallString<16> OrigDir(OrigPath);
385   llvm::sys::path::remove_filename(OrigDir);
386   SmallString<16> DebugPath = OrigDir;
387   // Try relative/path/to/original_binary/debuglink_name
388   llvm::sys::path::append(DebugPath, DebuglinkName);
389   if (checkFileCRC(DebugPath, CRCHash)) {
390     Result = std::string(DebugPath.str());
391     return true;
392   }
393   // Try relative/path/to/original_binary/.debug/debuglink_name
394   DebugPath = OrigDir;
395   llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
396   if (checkFileCRC(DebugPath, CRCHash)) {
397     Result = std::string(DebugPath.str());
398     return true;
399   }
400   // Make the path absolute so that lookups will go to
401   // "/usr/lib/debug/full/path/to/debug", not
402   // "/usr/lib/debug/to/debug"
403   llvm::sys::fs::make_absolute(OrigDir);
404   if (!Opts.FallbackDebugPath.empty()) {
405     // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
406     DebugPath = Opts.FallbackDebugPath;
407   } else {
408 #if defined(__NetBSD__)
409     // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
410     DebugPath = "/usr/libdata/debug";
411 #else
412     // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
413     DebugPath = "/usr/lib/debug";
414 #endif
415   }
416   llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
417                           DebuglinkName);
418   if (checkFileCRC(DebugPath, CRCHash)) {
419     Result = std::string(DebugPath.str());
420     return true;
421   }
422   return false;
423 }
424 
425 bool LLVMSymbolizer::findDebugBinary(const ArrayRef<uint8_t> BuildID,
426                                      std::string &Result) {
427   Optional<std::string> Path;
428   Path = LocalDIFetcher(Opts.DebugFileDirectory).fetchBuildID(BuildID);
429   if (Path) {
430     Result = std::move(*Path);
431     return true;
432   }
433 
434   // Try caller-provided debug info fetchers.
435   for (const std::unique_ptr<DIFetcher> &Fetcher : DIFetchers) {
436     Path = Fetcher->fetchBuildID(BuildID);
437     if (Path) {
438       Result = std::move(*Path);
439       return true;
440     }
441   }
442 
443   return false;
444 }
445 
446 Expected<LLVMSymbolizer::ObjectPair>
447 LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
448                                       const std::string &ArchName) {
449   auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
450   if (I != ObjectPairForPathArch.end())
451     return I->second;
452 
453   auto ObjOrErr = getOrCreateObject(Path, ArchName);
454   if (!ObjOrErr) {
455     ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName),
456                                   ObjectPair(nullptr, nullptr));
457     return ObjOrErr.takeError();
458   }
459 
460   ObjectFile *Obj = ObjOrErr.get();
461   assert(Obj != nullptr);
462   ObjectFile *DbgObj = nullptr;
463 
464   if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
465     DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
466   else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
467     DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
468   if (!DbgObj)
469     DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
470   if (!DbgObj)
471     DbgObj = Obj;
472   ObjectPair Res = std::make_pair(Obj, DbgObj);
473   ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
474   return Res;
475 }
476 
477 Expected<ObjectFile *>
478 LLVMSymbolizer::getOrCreateObject(const std::string &Path,
479                                   const std::string &ArchName) {
480   Binary *Bin;
481   auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
482   if (!Pair.second) {
483     Bin = Pair.first->second.getBinary();
484   } else {
485     Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
486     if (!BinOrErr)
487       return BinOrErr.takeError();
488     Pair.first->second = std::move(BinOrErr.get());
489     Bin = Pair.first->second.getBinary();
490   }
491 
492   if (!Bin)
493     return static_cast<ObjectFile *>(nullptr);
494 
495   if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
496     auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
497     if (I != ObjectForUBPathAndArch.end())
498       return I->second.get();
499 
500     Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
501         UB->getMachOObjectForArch(ArchName);
502     if (!ObjOrErr) {
503       ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
504                                      std::unique_ptr<ObjectFile>());
505       return ObjOrErr.takeError();
506     }
507     ObjectFile *Res = ObjOrErr->get();
508     ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
509                                    std::move(ObjOrErr.get()));
510     return Res;
511   }
512   if (Bin->isObject()) {
513     return cast<ObjectFile>(Bin);
514   }
515   return errorCodeToError(object_error::arch_not_found);
516 }
517 
518 Expected<SymbolizableModule *>
519 LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj,
520                                  std::unique_ptr<DIContext> Context,
521                                  StringRef ModuleName) {
522   auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context),
523                                                   Opts.UntagAddresses);
524   std::unique_ptr<SymbolizableModule> SymMod;
525   if (InfoOrErr)
526     SymMod = std::move(*InfoOrErr);
527   auto InsertResult = Modules.insert(
528       std::make_pair(std::string(ModuleName), std::move(SymMod)));
529   assert(InsertResult.second);
530   if (!InfoOrErr)
531     return InfoOrErr.takeError();
532   return InsertResult.first->second.get();
533 }
534 
535 Expected<SymbolizableModule *>
536 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
537   auto I = Modules.find(ModuleName);
538   if (I != Modules.end())
539     return I->second.get();
540 
541   std::string BinaryName = ModuleName;
542   std::string ArchName = Opts.DefaultArch;
543   size_t ColonPos = ModuleName.find_last_of(':');
544   // Verify that substring after colon form a valid arch name.
545   if (ColonPos != std::string::npos) {
546     std::string ArchStr = ModuleName.substr(ColonPos + 1);
547     if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
548       BinaryName = ModuleName.substr(0, ColonPos);
549       ArchName = ArchStr;
550     }
551   }
552   auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
553   if (!ObjectsOrErr) {
554     // Failed to find valid object file.
555     Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
556     return ObjectsOrErr.takeError();
557   }
558   ObjectPair Objects = ObjectsOrErr.get();
559 
560   std::unique_ptr<DIContext> Context;
561   // If this is a COFF object containing PDB info, use a PDBContext to
562   // symbolize. Otherwise, use DWARF.
563   if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
564     const codeview::DebugInfo *DebugInfo;
565     StringRef PDBFileName;
566     auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
567     if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
568 #if 0
569       using namespace pdb;
570       std::unique_ptr<IPDBSession> Session;
571 
572       PDB_ReaderType ReaderType =
573           Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
574       if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
575                                     Session)) {
576         Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
577         // Return along the PDB filename to provide more context
578         return createFileError(PDBFileName, std::move(Err));
579       }
580       Context.reset(new PDBContext(*CoffObject, std::move(Session)));
581 #else
582       return make_error<StringError>(
583           "PDB support not compiled in",
584           std::make_error_code(std::errc::not_supported));
585 #endif
586     }
587   }
588   if (!Context)
589     Context = DWARFContext::create(
590         *Objects.second, DWARFContext::ProcessDebugRelocations::Process,
591         nullptr, Opts.DWPName);
592   return createModuleInfo(Objects.first, std::move(Context), ModuleName);
593 }
594 
595 Expected<SymbolizableModule *>
596 LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
597   StringRef ObjName = Obj.getFileName();
598   auto I = Modules.find(ObjName);
599   if (I != Modules.end())
600     return I->second.get();
601 
602   std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
603   // FIXME: handle COFF object with PDB info to use PDBContext
604   return createModuleInfo(&Obj, std::move(Context), ObjName);
605 }
606 
607 namespace {
608 
609 // Undo these various manglings for Win32 extern "C" functions:
610 // cdecl       - _foo
611 // stdcall     - _foo@12
612 // fastcall    - @foo@12
613 // vectorcall  - foo@@12
614 // These are all different linkage names for 'foo'.
615 StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
616   // Remove any '_' or '@' prefix.
617   char Front = SymbolName.empty() ? '\0' : SymbolName[0];
618   if (Front == '_' || Front == '@')
619     SymbolName = SymbolName.drop_front();
620 
621   // Remove any '@[0-9]+' suffix.
622   if (Front != '?') {
623     size_t AtPos = SymbolName.rfind('@');
624     if (AtPos != StringRef::npos &&
625         all_of(drop_begin(SymbolName, AtPos + 1), isDigit))
626       SymbolName = SymbolName.substr(0, AtPos);
627   }
628 
629   // Remove any ending '@' for vectorcall.
630   if (SymbolName.endswith("@"))
631     SymbolName = SymbolName.drop_back();
632 
633   return SymbolName;
634 }
635 
636 } // end anonymous namespace
637 
638 std::string
639 LLVMSymbolizer::DemangleName(const std::string &Name,
640                              const SymbolizableModule *DbiModuleDescriptor) {
641   std::string Result;
642   if (nonMicrosoftDemangle(Name.c_str(), Result))
643     return Result;
644 
645   if (!Name.empty() && Name.front() == '?') {
646     // Only do MSVC C++ demangling on symbols starting with '?'.
647     int status = 0;
648     char *DemangledName = microsoftDemangle(
649         Name.c_str(), nullptr, nullptr, nullptr, &status,
650         MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention |
651                         MSDF_NoMemberType | MSDF_NoReturnType));
652     if (status != 0)
653       return Name;
654     Result = DemangledName;
655     free(DemangledName);
656     return Result;
657   }
658 
659   if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module())
660     return std::string(demanglePE32ExternCFunc(Name));
661   return Name;
662 }
663 
664 } // namespace symbolize
665 } // namespace llvm
666