Commit 13d606da authored by Kenton Varda's avatar Kenton Varda

Generate ASLR-friendly numeric stack traces.

parent bacf9744
......@@ -29,6 +29,7 @@
#include <exception>
#include <new>
#include <signal.h>
#include <stdint.h>
#ifndef _WIN32
#include <sys/mman.h>
#endif
......@@ -51,6 +52,10 @@
#include <pthread.h>
#endif
#if KJ_HAS_LIBDL
#include "dlfcn.h"
#endif
namespace kj {
StringPtr KJ_STRINGIFY(LogSeverity severity) {
......@@ -285,10 +290,33 @@ String stringifyStackTrace(ArrayPtr<void* const> trace) {
#endif
}
String stringifyStackTraceAddresses(ArrayPtr<void* const> trace) {
#if KJ_HAS_LIBDL
return strArray(KJ_MAP(addr, trace) {
Dl_info info;
// Shared libraries are mapped near the end of the address space while the executable is mapped
// near the beginning. We want to print addresses in the executable as raw addresses, not
// offsets, since that's what addr2line expects for executables. For shared libraries it
// expects offsets. In any case, most frames are likely to be in the main executable so it
// makes the output cleaner if we don't repeatedly write its name.
if (reinterpret_cast<uintptr_t>(addr) >= 0x400000000000ull && dladdr(addr, &info)) {
uintptr_t offset = reinterpret_cast<uintptr_t>(addr) -
reinterpret_cast<uintptr_t>(info.dli_fbase);
return kj::str(info.dli_fname, '@', reinterpret_cast<void*>(offset));
} else {
return kj::str(addr);
}
}, " ");
#else
// TODO(someday): Support other platforms.
return kj::strArray(trace, " ");
#endif
}
String getStackTrace() {
void* space[32];
auto trace = getStackTrace(space, 2);
return kj::str(kj::strArray(trace, " "), stringifyStackTrace(trace));
return kj::str(stringifyStackTraceAddresses(trace), stringifyStackTrace(trace));
}
#if _WIN32 && _M_X64
......@@ -310,7 +338,8 @@ BOOL WINAPI breakHandler(DWORD type) {
void* traceSpace[32];
auto trace = getStackTrace(traceSpace, 2, thread, context);
ResumeThread(thread);
auto message = kj::str("*** Received CTRL+C. stack: ", strArray(trace, " "),
auto message = kj::str("*** Received CTRL+C. stack: ",
stringifyStackTraceAddresses(trace),
stringifyStackTrace(trace), '\n');
FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
} else {
......@@ -345,7 +374,7 @@ void crashHandler(int signo, siginfo_t* info, void* context) {
auto trace = getStackTrace(traceSpace, 2);
auto message = kj::str("*** Received signal #", signo, ": ", strsignal(signo),
"\nstack: ", strArray(trace, " "),
"\nstack: ", stringifyStackTraceAddresses(trace),
stringifyStackTrace(trace), '\n');
FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
......@@ -492,7 +521,8 @@ String KJ_STRINGIFY(const Exception& e) {
return str(strArray(contextText, ""),
e.getFile(), ":", e.getLine(), ": ", e.getType(),
e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
e.getStackTrace().size() > 0 ? "\nstack: " : "", strArray(e.getStackTrace(), " "),
e.getStackTrace().size() > 0 ? "\nstack: " : "",
stringifyStackTraceAddresses(e.getStackTrace()),
stringifyStackTrace(e.getStackTrace()));
}
......@@ -725,7 +755,8 @@ private:
// anyway.
getExceptionCallback().logMessage(severity, e.getFile(), e.getLine(), 0, str(
e.getType(), e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
e.getStackTrace().size() > 0 ? "\nstack: " : "", strArray(e.getStackTrace(), " "),
e.getStackTrace().size() > 0 ? "\nstack: " : "",
stringifyStackTraceAddresses(e.getStackTrace()),
stringifyStackTrace(e.getStackTrace()), "\n"));
}
};
......
......@@ -354,6 +354,14 @@ String stringifyStackTrace(ArrayPtr<void* const>);
// Convert the stack trace to a string with file names and line numbers. This may involve executing
// suprocesses.
String stringifyStackTraceAddresses(ArrayPtr<void* const> trace);
// Construct a string containing just enough information about a stack trace to be able to convert
// it to file and line numbers later using offline tools. This produces a sequence of
// space-separated code location identifiers. Each identifier may be an absolute address
// (hex number starting with 0x) or may be a module-relative address "<module>@0x<hex>". The
// latter case is preferred when ASLR is in effect and has loaded different modules at different
// addresses.
String getStackTrace();
// Get a stack trace right now and stringify it. Useful for debugging.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment