From c17ca759aa935543322857296aedba505bd6235a Mon Sep 17 00:00:00 2001 From: Simon Evans Date: Tue, 29 Nov 2016 00:05:11 +0000 Subject: [PATCH] [runtime] Add platform independent version of dladdr() / Dl_info - Win32 does not support dlfcn.h, Dl_info or dladdr() so add lookupSymbol() as a wrapper for ELF/MachO/Win32 - Win32 version needs an implementation, currently it just returns an error for `cannot lookup address' --- stdlib/public/runtime/Errors.cpp | 35 ++++++++----------- stdlib/public/runtime/ImageInspection.h | 8 +++++ stdlib/public/runtime/ImageInspectionELF.cpp | 13 +++++++ .../public/runtime/ImageInspectionMachO.cpp | 14 ++++++++ .../public/runtime/ImageInspectionWin32.cpp | 18 ++++++++++ stdlib/public/runtime/ProtocolConformance.cpp | 9 ++--- 6 files changed, 71 insertions(+), 26 deletions(-) diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 1c51d3c111bcd..0fe66370fa4bc 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -30,6 +30,7 @@ #include #endif #include +#include "ImageInspection.h" #include "swift/Runtime/Debug.h" #include "swift/Runtime/Mutex.h" #include "swift/Basic/Demangle.h" @@ -38,14 +39,11 @@ #if !defined(_MSC_VER) #include #endif -#if SWIFT_SUPPORTS_BACKTRACE_REPORTING +#if SWIFT_SUPPORTS_BACKTRACE_REPORTING // execinfo.h is not available on Android. Checks in this file ensure that // fatalError behaves as expected, but without stack traces. #include -// We are only using dlfcn.h in code that is invoked on non cygwin/android -// platforms. So I am putting it here. -#include #endif #ifdef __APPLE__ @@ -62,26 +60,26 @@ using namespace swift; #if SWIFT_SUPPORTS_BACKTRACE_REPORTING -static bool getSymbolNameAddr(llvm::StringRef libraryName, Dl_info dlinfo, +static bool getSymbolNameAddr(llvm::StringRef libraryName, SymbolInfo syminfo, std::string &symbolName, uintptr_t &addrOut) { // If we failed to find a symbol and thus dlinfo->dli_sname is nullptr, we // need to use the hex address. - bool hasUnavailableAddress = dlinfo.dli_sname == nullptr; + bool hasUnavailableAddress = syminfo.symbolName == nullptr; if (hasUnavailableAddress) { return false; } // Ok, now we know that we have some sort of "real" name. Set the outAddr. - addrOut = uintptr_t(dlinfo.dli_saddr); + addrOut = uintptr_t(syminfo.symbolAddress); // First lets try to demangle using cxxabi. If this fails, we will try to // demangle with swift. We are taking advantage of __cxa_demangle actually // providing failure status instead of just returning the original string like // swift demangle. int status; - char *demangled = abi::__cxa_demangle(dlinfo.dli_sname, 0, 0, &status); + char *demangled = abi::__cxa_demangle(syminfo.symbolName, 0, 0, &status); if (status == 0) { assert(demangled != nullptr && "If __cxa_demangle succeeds, demangled " "should never be nullptr"); @@ -95,7 +93,7 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName, Dl_info dlinfo, // Otherwise, try to demangle with swift. If swift fails to demangle, it will // just pass through the original output. symbolName = demangleSymbolAsString( - dlinfo.dli_sname, strlen(dlinfo.dli_sname), + syminfo.symbolName, strlen(syminfo.symbolName), Demangle::DemangleOptions::SimplifiedUIDemangleOptions()); return true; } @@ -103,19 +101,16 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName, Dl_info dlinfo, /// This function dumps one line of a stack trace. It is assumed that \p address /// is the address of the stack frame at index \p index. static void dumpStackTraceEntry(unsigned index, void *framePC) { - Dl_info dlinfo; + SymbolInfo syminfo; - // 0 is failure for dladdr. We do not use nullptr since it is an int - // argument. This violates normal unix patterns. See man page for dladdr on OS - // X. - if (0 == dladdr(framePC, &dlinfo)) { + // 0 is failure for lookupSymbol + if (0 == lookupSymbol(framePC, &syminfo)) { return; } - // According to the man page of dladdr, if dladdr returns non-zero, then we - // know that it must have fname, fbase set. Thus, we find the library name - // here. - StringRef libraryName = StringRef(dlinfo.dli_fname).rsplit('/').second; + // If lookupSymbol succeeded then fileName is non-null. Thus, we find the + // library name here. + StringRef libraryName = StringRef(syminfo.fileName).rsplit('/').second; // Next we get the symbol name that we are going to use in our backtrace. std::string symbolName; @@ -124,7 +119,7 @@ static void dumpStackTraceEntry(unsigned index, void *framePC) { // we just get HexAddr + 0. uintptr_t symbolAddr = uintptr_t(framePC); bool foundSymbol = - getSymbolNameAddr(libraryName, dlinfo, symbolName, symbolAddr); + getSymbolNameAddr(libraryName, syminfo, symbolName, symbolAddr); // We do not use %p here for our pointers since the format is implementation // defined. This makes it logically impossible to check the output. Forcing @@ -142,7 +137,7 @@ static void dumpStackTraceEntry(unsigned index, void *framePC) { " + %td\n"; fprintf(stderr, backtraceEntryFormat, index, libraryName.data(), uintptr_t(framePC), - ptrdiff_t(uintptr_t(framePC) - uintptr_t(dlinfo.dli_fbase))); + ptrdiff_t(uintptr_t(framePC) - uintptr_t(syminfo.baseAddress))); } } diff --git a/stdlib/public/runtime/ImageInspection.h b/stdlib/public/runtime/ImageInspection.h index 5bdd4ad336d9b..9a6aa123fd435 100644 --- a/stdlib/public/runtime/ImageInspection.h +++ b/stdlib/public/runtime/ImageInspection.h @@ -22,6 +22,13 @@ #include namespace swift { + // This is a platform independent version of Dl_info from dlfcn.h + struct SymbolInfo { + const char *fileName; + void *baseAddress; + const char *symbolName; + void *symbolAddress; + }; /// Load the metadata from the image necessary to find a type's /// protocol conformance. @@ -37,6 +44,7 @@ void addImageProtocolConformanceBlockCallback(const void *start, void addImageTypeMetadataRecordBlockCallback(const void *start, uintptr_t size); +int lookupSymbol(const void *address, SymbolInfo *info); } // end namespace swift #endif // SWIFT_RUNTIME_IMAGE_INSPECTION_H diff --git a/stdlib/public/runtime/ImageInspectionELF.cpp b/stdlib/public/runtime/ImageInspectionELF.cpp index b771acf682652..9b9b4ef0b7c41 100644 --- a/stdlib/public/runtime/ImageInspectionELF.cpp +++ b/stdlib/public/runtime/ImageInspectionELF.cpp @@ -98,4 +98,17 @@ void swift::initializeTypeMetadataRecordLookup() { dl_iterate_phdr(iteratePHDRCallback, &TypeMetadataRecordArgs); } +int swift::lookupSymbol(const void *address, SymbolInfo *info) { + Dl_info dlinfo; + if (dladdr(address, &dlinfo) == 0) { + return 0; + } + + info->fileName = dlinfo.dli_fname; + info->baseAddress = dlinfo.dli_fbase; + info->symbolName = dlinfo.dli_sname; + info->symbolAddress = dlinfo.dli_saddr; + return 1; +} + #endif // defined(__ELF__) || defined(__ANDROID__) diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp index 05b0d59834dda..97dcb272cf35c 100644 --- a/stdlib/public/runtime/ImageInspectionMachO.cpp +++ b/stdlib/public/runtime/ImageInspectionMachO.cpp @@ -22,6 +22,7 @@ #include #include #include +#include using namespace swift; @@ -70,4 +71,17 @@ void swift::initializeTypeMetadataRecordLookup() { } +int swift::lookupSymbol(const void *address, SymbolInfo *info) { + Dl_info dlinfo; + if (dladdr(address, &dlinfo) == 0) { + return 0; + } + + info->fileName = dlinfo.dli_fname; + info->baseAddress = dlinfo.dli_fbase; + info->symbolName = dlinfo.dli_sname; + info->symbolAddress = dlinfo.dli_saddr; + return 1; +} + #endif // defined(__APPLE__) && defined(__MACH__) diff --git a/stdlib/public/runtime/ImageInspectionWin32.cpp b/stdlib/public/runtime/ImageInspectionWin32.cpp index 4116a966cf8ff..4e8dbc0f35a8e 100644 --- a/stdlib/public/runtime/ImageInspectionWin32.cpp +++ b/stdlib/public/runtime/ImageInspectionWin32.cpp @@ -217,4 +217,22 @@ void swift::initializeTypeMetadataRecordLookup() { _swift_dl_iterate_phdr(_addImageCallback, &TypeMetadataRecordsArgs); } + +int swift::lookupSymbol(const void *address, SymbolInfo *info) { +#if defined(__CYGWIN__) + Dl_info dlinfo; + if (dladdr(address, &dlinfo) == 0) { + return 0; + } + + info->fileName = dlinfo.dli_fname; + info->baseAddress = dlinfo.dli_fbase; + info->symbolName = dli_info.dli_sname; + info->symbolAddress = dli_saddr; + return 1; +#else + return 0; +#endif // __CYGWIN__ +} + #endif // defined(_MSC_VER) || defined(__CYGWIN__) diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index 2f068a6dbe74a..0c051cbdc8cd5 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -21,9 +21,6 @@ #include "swift/Runtime/Mutex.h" #include "ImageInspection.h" #include "Private.h" -#if !defined(_WIN32) -#include -#endif using namespace swift; @@ -37,11 +34,11 @@ static const char *class_getName(const ClassMetadata* type) { template<> void ProtocolConformanceRecord::dump() const { auto symbolName = [&](const void *addr) -> const char * { - Dl_info info; - int ok = dladdr(addr, &info); + SymbolInfo info; + int ok = lookupSymbol(addr, &info); if (!ok) return ""; - return info.dli_sname; + return info.symbolName; }; switch (auto kind = getTypeKind()) {