19 #include "llvm/Config/config.h"
43 #pragma comment(lib, "dbghelp.lib")
46 #ifdef IMAGE_FILE_MACHINE_I386
47 #undef IMAGE_FILE_MACHINE_I386
55 uint64_t ModuleOffset) {
57 if (
auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
58 Info = InfoOrErr.get();
60 return InfoOrErr.takeError();
81 uint64_t ModuleOffset) {
83 if (
auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
84 Info = InfoOrErr.get();
86 return InfoOrErr.takeError();
106 return InlinedContext;
110 uint64_t ModuleOffset) {
112 if (
auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
113 Info = InfoOrErr.get();
115 return InfoOrErr.takeError();
135 ObjectForUBPathAndArch.clear();
136 BinaryForPath.clear();
137 ObjectPairForPathArch.clear();
147 std::string getDarwinDWARFResourceForPath(
148 const std::string &Path,
const std::string &Basename) {
151 ResourceName +=
".dSYM";
155 return ResourceName.
str();
158 bool checkFileCRC(StringRef Path,
uint32_t CRCHash) {
159 ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
166 bool findDebugBinary(
const std::string &OrigPath,
167 const std::string &DebuglinkName,
uint32_t CRCHash,
168 std::string &Result) {
169 std::string OrigRealPath = OrigPath;
170 #if defined(HAVE_REALPATH)
171 if (
char *
RP = realpath(OrigPath.c_str(),
nullptr)) {
176 SmallString<16> OrigDir(OrigRealPath);
178 SmallString<16> DebugPath = OrigDir;
181 if (checkFileCRC(DebugPath, CRCHash)) {
182 Result = DebugPath.str();
186 DebugPath = OrigRealPath;
188 if (checkFileCRC(DebugPath, CRCHash)) {
189 Result = DebugPath.str();
193 DebugPath =
"/usr/lib/debug";
196 if (checkFileCRC(DebugPath, CRCHash)) {
197 Result = DebugPath.str();
203 bool getGNUDebuglinkContents(
const ObjectFile *Obj, std::string &DebugName,
207 for (
const SectionRef &
Section : Obj->sections()) {
210 Name = Name.substr(Name.find_first_not_of(
"._"));
211 if (Name ==
"gnu_debuglink") {
214 DataExtractor DE(Data, Obj->isLittleEndian(), 0);
216 if (
const char *DebugNameStr = DE.getCStr(&Offset)) {
218 Offset = (Offset + 3) & ~0x3;
219 if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
220 DebugName = DebugNameStr;
221 CRCHash = DE.getU32(&Offset);
231 bool darwinDsymMatchesBinary(
const MachOObjectFile *DbgObj,
232 const MachOObjectFile *Obj) {
233 ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
234 ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
235 if (dbg_uuid.empty() || bin_uuid.empty())
237 return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
242 ObjectFile *LLVMSymbolizer::lookUpDsymFile(
const std::string &ExePath,
243 const MachOObjectFile *MachExeObj,
const std::string &ArchName) {
246 std::vector<std::string> DsymPaths;
248 DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename));
249 for (
const auto &Path : Opts.
DsymHints) {
250 DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename));
252 for (
const auto &Path : DsymPaths) {
253 auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
259 ObjectFile *DbgObj = DbgObjOrErr.get();
262 const MachOObjectFile *MachDbgObj =
dyn_cast<
const MachOObjectFile>(DbgObj);
265 if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
271 ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(
const std::string &Path,
272 const ObjectFile *Obj,
273 const std::string &ArchName) {
274 std::string DebuglinkName;
276 std::string DebugBinaryPath;
277 if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
279 if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
281 auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
287 return DbgObjOrErr.get();
290 Expected<LLVMSymbolizer::ObjectPair>
291 LLVMSymbolizer::getOrCreateObjectPair(
const std::string &Path,
292 const std::string &ArchName) {
293 const auto &
I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
294 if (
I != ObjectPairForPathArch.end()) {
298 auto ObjOrErr = getOrCreateObject(Path, ArchName);
300 ObjectPairForPathArch.insert(std::make_pair(std::make_pair(Path, ArchName),
301 ObjectPair(
nullptr,
nullptr)));
302 return ObjOrErr.takeError();
305 ObjectFile *Obj = ObjOrErr.get();
307 ObjectFile *DbgObj =
nullptr;
309 if (
auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
310 DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
312 DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
315 ObjectPair Res = std::make_pair(Obj, DbgObj);
316 ObjectPairForPathArch.insert(
317 std::make_pair(std::make_pair(Path, ArchName), Res));
321 Expected<ObjectFile *>
322 LLVMSymbolizer::getOrCreateObject(
const std::string &Path,
323 const std::string &ArchName) {
324 const auto &
I = BinaryForPath.find(Path);
325 Binary *Bin =
nullptr;
326 if (
I == BinaryForPath.end()) {
327 Expected<OwningBinary<Binary>> BinOrErr =
createBinary(Path);
329 BinaryForPath.insert(std::make_pair(Path, OwningBinary<Binary>()));
330 return BinOrErr.takeError();
332 Bin = BinOrErr->getBinary();
333 BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get())));
335 Bin =
I->second.getBinary();
339 return static_cast<ObjectFile *
>(
nullptr);
341 if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
342 const auto &
I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
343 if (
I != ObjectForUBPathAndArch.end()) {
344 return I->second.get();
346 Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
347 UB->getObjectForArch(ArchName);
349 ObjectForUBPathAndArch.insert(std::make_pair(
350 std::make_pair(Path, ArchName), std::unique_ptr<ObjectFile>()));
351 return ObjOrErr.takeError();
353 ObjectFile *Res = ObjOrErr->get();
354 ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName),
355 std::move(ObjOrErr.get())));
358 if (Bin->isObject()) {
359 return cast<ObjectFile>(Bin);
364 Expected<SymbolizableModule *>
365 LLVMSymbolizer::getOrCreateModuleInfo(
const std::string &ModuleName) {
366 const auto &
I = Modules.find(ModuleName);
367 if (
I != Modules.end()) {
368 return I->second.get();
370 std::string BinaryName = ModuleName;
372 size_t ColonPos = ModuleName.find_last_of(
':');
374 if (ColonPos != std::string::npos) {
375 std::string ArchStr = ModuleName.substr(ColonPos + 1);
377 BinaryName = ModuleName.substr(0, ColonPos);
381 auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
385 std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
386 return ObjectsOrErr.takeError();
388 ObjectPair Objects = ObjectsOrErr.get();
390 std::unique_ptr<DIContext>
Context;
393 if (
auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
394 const codeview::DebugInfo *DebugInfo;
395 StringRef PDBFileName;
396 auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
397 if (!EC && DebugInfo !=
nullptr && !PDBFileName.empty()) {
399 std::unique_ptr<IPDBSession> Session;
401 Objects.first->getFileName(), Session)) {
403 std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
404 return std::move(Err);
406 Context.reset(
new PDBContext(*CoffObject, std::move(Session)));
410 Context.reset(
new DWARFContextInMemory(*Objects.second));
414 std::unique_ptr<SymbolizableModule> SymMod;
416 SymMod = std::move(InfoOrErr.get());
418 Modules.insert(std::make_pair(ModuleName, std::move(SymMod)));
419 assert(InsertResult.second);
420 if (
auto EC = InfoOrErr.getError())
422 return InsertResult.first->second.get();
433 StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
435 char Front = SymbolName.empty() ?
'\0' : SymbolName[0];
436 if (Front ==
'_' || Front ==
'@')
437 SymbolName = SymbolName.drop_front();
441 size_t AtPos = SymbolName.rfind(
'@');
443 std::all_of(SymbolName.begin() + AtPos + 1, SymbolName.end(),
444 [](
char C) {
return C >=
'0' &&
C <=
'9'; })) {
445 SymbolName = SymbolName.substr(0, AtPos);
450 if (SymbolName.endswith(
"@"))
451 SymbolName = SymbolName.drop_back();
458 #if !defined(_MSC_VER)
460 extern "C" char *
__cxa_demangle(
const char *mangled_name,
char *output_buffer,
461 size_t *length,
int *
status);
466 #if !defined(_MSC_VER)
469 if (Name.substr(0, 2) ==
"_Z") {
474 std::string Result = DemangledName;
479 if (!Name.empty() && Name.front() ==
'?') {
481 char DemangledName[1024] = {0};
482 DWORD result = ::UnDecorateSymbolName(
483 Name.c_str(), DemangledName, 1023,
484 UNDNAME_NO_ACCESS_SPECIFIERS |
485 UNDNAME_NO_ALLOCATION_LANGUAGE |
486 UNDNAME_NO_THROW_SIGNATURES |
487 UNDNAME_NO_MEMBER_TYPE |
488 UNDNAME_NO_MS_KEYWORDS |
489 UNDNAME_NO_FUNCTION_RETURNS);
490 return (result == 0) ? Name : std::string(DemangledName);
494 return std::string(demanglePE32ExternCFunc(Name));
DILineInfo * getMutableFrame(unsigned Index)
static ErrorOr< std::unique_ptr< SymbolizableObjectFile > > create(object::ObjectFile *Obj, std::unique_ptr< DIContext > DICtx)
virtual DIGlobal symbolizeData(uint64_t ModuleOffset) const =0
virtual DILineInfo symbolizeCode(uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const =0
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly...
virtual bool isWin32Module() const =0
DILineInfo - a format-neutral container for source line information.
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr)
Create a Binary from Source, autodetecting the file type.
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
void remove_filename(SmallVectorImpl< char > &path)
Remove the last component from path unless it is the root dir.
Expected< DILineInfo > symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset)
Tagged union holding either a T or a Error.
StringRef extension(StringRef path)
Get extension.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
static std::string DemangleName(const std::string &Name, const SymbolizableModule *ModInfo)
uint32_t getNumberOfFrames() const
StringRef filename(StringRef path)
Get filename.
Error loadDataForEXE(PDB_ReaderType Type, StringRef Path, std::unique_ptr< IPDBSession > &Session)
virtual DIInliningInfo symbolizeInlinedCode(uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const =0
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
DIInliningInfo - a format-neutral container for inlined code description.
std::vector< std::string > DsymHints
FunctionNameKind PrintFunctions
void consumeError(Error Err)
Consume a Error without doing anything.
StringRef relative_path(StringRef path)
Get relative path.
char * __cxa_demangle(const char *mangled_name, char *output_buffer, size_t *length, int *status)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
uint32_t crc32(StringRef Buffer)
StringRef str() const
Explicit conversion to StringRef.
virtual uint64_t getModulePreferredBase() const =0
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
Expected< DIInliningInfo > symbolizeInlinedCode(const std::string &ModuleName, uint64_t ModuleOffset)
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
StringRef - Represent a constant reference to a string, i.e.
std::error_code status(const Twine &path, file_status &result)
Get file status as if by POSIX stat().
Expected< DIGlobal > symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset)
DIGlobal - container for description of a global variable.