Commit d60914ca authored by Kenton Varda's avatar Kenton Varda

Include file/line of stack trace locations in exception description, if possible.

parent 6632dc8d
......@@ -157,6 +157,8 @@ void inlineRequireFailure(
kj::arrayPtr(name##_stack, name##_size) : name##_heap
#endif
#define KJ_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
// =======================================================================================
// Template metaprogramming helpers.
......
......@@ -46,8 +46,8 @@ public:
void onRecoverableException(Exception&& exception) override {
text += "recoverable exception: ";
auto what = str(exception);
// Discard the last line of "what" because it is a stack trace.
const char* end = strrchr(what.cStr(), '\n');
// Discard the stack trace.
const char* end = strstr(what.cStr(), "\nstack: ");
if (end == nullptr) {
text += what.cStr();
} else {
......@@ -59,8 +59,8 @@ public:
void onFatalException(Exception&& exception) override {
text += "fatal exception: ";
auto what = str(exception);
// Discard the last line of "what" because it is a stack trace.
const char* end = strrchr(what.cStr(), '\n');
// Discard the stack trace.
const char* end = strstr(what.cStr(), "\nstack: ");
if (end == nullptr) {
text += what.cStr();
} else {
......
......@@ -29,8 +29,61 @@
#include <stdlib.h>
#include <exception>
#if defined(__linux__) && !defined(NDEBUG)
#include <stdio.h>
#endif
namespace kj {
namespace {
String getStackSymbols(ArrayPtr<void* const> trace) {
#if defined(__linux__) && !defined(NDEBUG)
// Get executable name from /proc/self/exe, then pass it and the stack trace to addr2line to
// get file/line pairs.
char exe[512];
ssize_t n = readlink("/proc/self/exe", exe, sizeof(exe));
if (n < 0 || n >= sizeof(exe)) {
return nullptr;
}
exe[n] = '\0';
String lines[6];
FILE* p = popen(str("addr2line -e ", exe, ' ', strArray(trace, " ")).cStr(), "r");
if (p == nullptr) {
return nullptr;
}
char line[512];
size_t i = 0;
while (i < KJ_ARRAY_SIZE(lines) && fgets(line, sizeof(line), p) != nullptr) {
// Don't include exception-handling infrastructure in stack trace.
if (i == 0 &&
(strstr(line, "kj/exception.") != nullptr ||
strstr(line, "kj/debug.") != nullptr)) {
continue;
}
size_t len = strlen(line);
if (len > 0 && line[len-1] == '\n') line[len-1] = '\0';
lines[i++] = str("\n", line);
}
// Skip remaining input.
while (fgets(line, sizeof(line), p) != nullptr) {}
pclose(p);
return strArray(arrayPtr(lines, i), "");
#else
return nullptr;
#endif
}
} // namespace
ArrayPtr<const char> KJ_STRINGIFY(Exception::Nature nature) {
static const char* NATURE_STRINGS[] = {
"requirement not met",
......@@ -87,7 +140,7 @@ String KJ_STRINGIFY(const Exception& e) {
e.getFile(), ":", e.getLine(), ": ", e.getNature(),
e.getDurability() == Exception::Durability::TEMPORARY ? " (temporary)" : "",
e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
"\nstack: ", strArray(e.getStackTrace(), " "));
"\nstack: ", strArray(e.getStackTrace(), " "), getStackSymbols(e.getStackTrace()));
}
Exception::Exception(Nature nature, Durability durability, const char* file, int line,
......
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