Skip to content

[runtime] Add platform independent version of dladdr() / Dl_info #5969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 15 additions & 20 deletions stdlib/public/runtime/Errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <unistd.h>
#endif
#include <stdarg.h>
#include "ImageInspection.h"
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Mutex.h"
#include "swift/Basic/Demangle.h"
Expand All @@ -38,14 +39,11 @@
#if !defined(_MSC_VER)
#include <cxxabi.h>
#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 <execinfo.h>
// We are only using dlfcn.h in code that is invoked on non cygwin/android
// platforms. So I am putting it here.
#include <dlfcn.h>
#endif

#ifdef __APPLE__
Expand All @@ -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");
Expand All @@ -95,27 +93,24 @@ 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;
}

/// 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;
Expand All @@ -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
Expand All @@ -142,7 +137,7 @@ static void dumpStackTraceEntry(unsigned index, void *framePC) {
"<unavailable> + %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)));
}
}

Expand Down
8 changes: 8 additions & 0 deletions stdlib/public/runtime/ImageInspection.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
#include <cstdint>

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.
Expand All @@ -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
13 changes: 13 additions & 0 deletions stdlib/public/runtime/ImageInspectionELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
14 changes: 14 additions & 0 deletions stdlib/public/runtime/ImageInspectionMachO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
#include <assert.h>
#include <dlfcn.h>

using namespace swift;

Expand Down Expand Up @@ -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__)
18 changes: 18 additions & 0 deletions stdlib/public/runtime/ImageInspectionWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
9 changes: 3 additions & 6 deletions stdlib/public/runtime/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
#include "swift/Runtime/Mutex.h"
#include "ImageInspection.h"
#include "Private.h"
#if !defined(_WIN32)
#include <dlfcn.h>
#endif

using namespace swift;

Expand All @@ -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 "<unknown addr>";
return info.dli_sname;
return info.symbolName;
};

switch (auto kind = getTypeKind()) {
Expand Down