1
0
mirror of https://github.com/exaloop/codon.git synced 2025-06-03 15:03:52 +08:00

Refactor backtraces

This commit is contained in:
A. R. Shajii 2021-11-16 11:55:00 -05:00
parent e76b756226
commit 8dc2c45e88
7 changed files with 140 additions and 122 deletions

View File

@ -1,13 +1,57 @@
#include "debug_listener.h"
#include <algorithm>
#include <sstream>
#include "codon/runtime/lib.h"
namespace codon {
namespace {
std::string unmangleType(llvm::StringRef s) {
auto p = s.rsplit('.');
return (p.second.empty() ? p.first : p.second).str();
}
std::string unmangleFunc(llvm::StringRef s) {
// separate type and function
auto p = s.split(':');
llvm::StringRef func = s;
std::string type;
if (!p.second.empty()) {
type = unmangleType(p.first);
func = p.second;
}
// trim off ".<id>"
p = func.rsplit('.');
if (!p.second.empty() && p.second.find_if([](char c) { return !std::isdigit(c); }) ==
llvm::StringRef::npos)
func = p.first;
// trim off generics
func = func.split('[').first;
// trim off qualified name
p = func.rsplit('.');
if (!p.second.empty())
func = p.second;
if (!type.empty())
return type + "." + func.str();
else
return func.str();
}
std::string simplifyFile(llvm::StringRef s) {
auto p = s.rsplit('/');
return (p.second.empty() ? p.first : p.second).str();
}
} // namespace
void DebugListener::notifyObjectLoaded(ObjectKey key,
const llvm::object::ObjectFile &obj,
const llvm::RuntimeDyld::LoadedObjectInfo &L) {
intptr_t start = 0, stop = 0;
uintptr_t start = 0, stop = 0;
for (const auto &sec : obj.sections()) {
if (sec.isText()) {
start = L.getSectionLoadAddress(sec);
@ -25,15 +69,33 @@ void DebugListener::notifyFreeingObject(ObjectKey key) {
objects.end());
}
llvm::Expected<llvm::DILineInfo> DebugListener::symbolize(intptr_t pc) {
llvm::Expected<llvm::DILineInfo> DebugListener::symbolize(uintptr_t pc) {
for (const auto &o : objects) {
if (o.contains(pc)) {
return sym.symbolizeCode(o.getObject(),
{static_cast<uint64_t>(pc - o.getStart()),
llvm::object::SectionedAddress::UndefSection});
return sym.symbolizeCode(
o.getObject(),
{pc - o.getStart(), llvm::object::SectionedAddress::UndefSection});
}
}
return llvm::DILineInfo();
}
std::string DebugListener::getPrettyBacktrace(const std::vector<uintptr_t> &backtrace) {
auto invalid = [](const std::string &name) { return name == "<invalid>"; };
std::ostringstream buf;
buf << "\033[1mBacktrace:\033[0m\n";
for (auto pc : backtrace) {
auto src = symbolize(pc);
if (auto err = src.takeError())
break;
if (invalid(src->FunctionName) || invalid(src->FileName))
continue;
buf << " "
<< makeBacktraceFrameString(pc, unmangleFunc(src->FunctionName),
simplifyFile(src->FileName), src->Line, src->Column)
<< "\n";
}
return buf.str();
}
} // namespace codon

View File

@ -13,19 +13,19 @@ public:
private:
ObjectKey key;
const llvm::object::ObjectFile *object;
intptr_t start;
intptr_t stop;
uintptr_t start;
uintptr_t stop;
public:
ObjectInfo(ObjectKey key, const llvm::object::ObjectFile *object, intptr_t start,
intptr_t stop)
ObjectInfo(ObjectKey key, const llvm::object::ObjectFile *object, uintptr_t start,
uintptr_t stop)
: key(key), object(object), start(start), stop(stop) {}
ObjectKey getKey() const { return key; }
const llvm::object::ObjectFile &getObject() const { return *object; }
intptr_t getStart() const { return start; }
intptr_t getStop() const { return stop; }
bool contains(intptr_t pc) const { return start <= pc && pc < stop; }
uintptr_t getStart() const { return start; }
uintptr_t getStop() const { return stop; }
bool contains(uintptr_t pc) const { return start <= pc && pc < stop; }
};
private:
@ -39,7 +39,8 @@ private:
public:
DebugListener() : llvm::JITEventListener(), sym(), objects() {}
llvm::Expected<llvm::DILineInfo> symbolize(intptr_t pc);
llvm::Expected<llvm::DILineInfo> symbolize(uintptr_t pc);
std::string getPrettyBacktrace(const std::vector<uintptr_t> &backtrace);
};
} // namespace codon

View File

@ -103,42 +103,6 @@ llvm::Expected<std::string> JIT::run(const ir::Func *input,
return buffer.str();
}
std::pair<ir::Func *, std::vector<ir::Var *>>
JIT::transformSimplified(const ast::StmtPtr &simplified) {
auto *cache = compiler->getCache();
// LOG("-- {}", simplified->toString(1));
auto typechecked = ast::TypecheckVisitor::apply(cache, simplified);
std::vector<std::string> globalNames;
for (auto &g : cache->globals) {
if (!g.second)
globalNames.push_back(g.first);
}
// add newly realized functions
std::vector<ast::StmtPtr> v;
std::vector<ir::Func **> frs;
v.push_back(typechecked);
for (auto &p : cache->pendingRealizations) {
v.push_back(cache->functions[p.first].ast);
frs.push_back(&cache->functions[p.first].realizations[p.second]->ir);
}
auto func =
ast::TranslateVisitor::apply(cache, std::make_shared<ast::SuiteStmt>(v, false));
cache->jitCell++;
std::vector<ir::Var *> globalVars;
for (auto &g : globalNames) {
seqassert(cache->globals[g], "JIT global {} not set", g);
globalVars.push_back(cache->globals[g]);
}
for (auto &i : frs) {
seqassert(*i, "JIT fn not set");
globalVars.push_back(*i);
}
return {func, globalVars};
}
llvm::Expected<std::string> JIT::exec(const std::string &code) {
auto *cache = compiler->getCache();
ast::StmtPtr node = ast::parseCode(cache, JIT_FILENAME, code, /*startLine=*/0);
@ -155,8 +119,35 @@ llvm::Expected<std::string> JIT::exec(const std::string &code) {
simplified->stmts.push_back(s);
// TODO: unroll on errors...
auto p = transformSimplified(simplified);
return run(p.first, p.second);
auto *cache = compiler->getCache();
auto typechecked = ast::TypecheckVisitor::apply(cache, simplified);
std::vector<std::string> globalNames;
for (auto &g : cache->globals) {
if (!g.second)
globalNames.push_back(g.first);
}
// add newly realized functions
std::vector<ast::StmtPtr> v;
std::vector<ir::Func **> frs;
v.push_back(typechecked);
for (auto &p : cache->pendingRealizations) {
v.push_back(cache->functions[p.first].ast);
frs.push_back(&cache->functions[p.first].realizations[p.second]->ir);
}
auto func =
ast::TranslateVisitor::apply(cache, std::make_shared<ast::SuiteStmt>(v, false));
cache->jitCell++;
std::vector<ir::Var *> globalVars;
for (auto &g : globalNames) {
seqassert(cache->globals[g], "JIT global {} not set", g);
globalVars.push_back(cache->globals[g]);
}
for (auto &i : frs) {
seqassert(*i, "JIT fn not set");
globalVars.push_back(*i);
}
return run(func, globalVars);
} catch (const exc::ParserException &e) {
return llvm::make_error<error::ParserErrorInfo>(e);
}

View File

@ -22,14 +22,14 @@ private:
public:
explicit JIT(const std::string &argv0);
Compiler *getCompiler() const { return compiler.get(); }
Engine *getEngine() const { return engine.get(); }
llvm::Error init();
llvm::Expected<std::string> run(const ir::Func *input,
const std::vector<ir::Var *> &newGlobals = {});
llvm::Expected<std::string> exec(const std::string &code);
private:
std::pair<ir::Func *, std::vector<ir::Var *>>
transformSimplified(const ast::StmtPtr &simplified);
};
} // namespace jit

View File

@ -236,9 +236,11 @@ SEQ_FUNC void seq_terminate(void *exc) {
buf << "\n\033[1mBacktrace:\033[0m\n";
for (unsigned i = 0; i < bt->count; i++) {
auto *frame = &bt->frames[i];
buf << " [\033[33m0x" << std::hex << frame->pc << std::dec
<< "\033[0m] \033[32m" << frame->function << "\033[0m " << frame->filename
<< ":" << frame->lineno << "\n";
buf << " "
<< codon::makeBacktraceFrameString(frame->pc, std::string(frame->function),
std::string(frame->filename),
frame->lineno)
<< "\n";
}
}
}
@ -587,3 +589,23 @@ SEQ_FUNC int64_t seq_exc_offset() {
SEQ_FUNC uint64_t seq_exc_class() {
return genClass(ourBaseExcpClassChars, sizeof(ourBaseExcpClassChars));
}
std::string codon::makeBacktraceFrameString(uintptr_t pc, const std::string &func,
const std::string &file, int line,
int col) {
std::ostringstream buf;
buf << "[\033[33m0x" << std::hex << pc << std::dec << "\033[0m]";
if (!func.empty()) {
buf << " \033[32m" << func << "\033[0m";
if (!file.empty()) {
buf << " at \033[36m" << file << "\033[0m";
if (line != 0) {
buf << ":\033[33m" << line << "\033[0m";
if (col != 0) {
buf << ":\033[33m" << col << "\033[0m";
}
}
}
}
return buf.str();
}

View File

@ -101,4 +101,8 @@ public:
int getCol() const { return col; }
std::vector<uintptr_t> getBacktrace() const { return backtrace; }
};
std::string makeBacktraceFrameString(uintptr_t pc, const std::string &func = "",
const std::string &file = "", int line = 0,
int col = 0);
} // namespace codon

View File

@ -379,48 +379,6 @@ void LLVMVisitor::compile(const std::string &filename,
}
}
namespace {
std::string unmangleType(llvm::StringRef s) {
auto p = s.rsplit('.');
return (p.second.empty() ? p.first : p.second).str();
}
std::string unmangleFunc(llvm::StringRef s) {
// separate type and function
auto p = s.split(':');
llvm::StringRef func = s;
std::string type;
if (!p.second.empty()) {
type = unmangleType(p.first);
func = p.second;
}
// trim off ".<id>"
p = func.rsplit('.');
if (!p.second.empty() && p.second.find_if([](char c) { return !std::isdigit(c); }) ==
llvm::StringRef::npos)
func = p.first;
// trim off generics
func = func.split('[').first;
// trim off qualified name
p = func.rsplit('.');
if (!p.second.empty())
func = p.second;
if (!type.empty())
return type + "." + func.str();
else
return func.str();
}
std::string simplifyFile(llvm::StringRef s) {
auto p = s.rsplit('/');
return (p.second.empty() ? p.first : p.second).str();
}
} // namespace
void LLVMVisitor::run(const std::vector<std::string> &args,
const std::vector<std::string> &libs, const char *const *envp) {
runLLVMPipeline();
@ -446,28 +404,8 @@ void LLVMVisitor::run(const std::vector<std::string> &args,
eng->runFunctionAsMain(main, args, envp);
} catch (const JITError &e) {
fmt::print(stderr, "{}", e.getOutput());
if (db.debug) {
llvm::symbolize::LLVMSymbolizer sym;
auto invalid = [](const std::string &name) { return name == "<invalid>"; };
fmt::print(stderr, "\n\033[1mBacktrace:\033[0m\n");
for (auto pc : e.getBacktrace()) {
auto src = dbListener->symbolize(pc);
if (auto err = src.takeError())
break;
if (invalid(src->FunctionName) || invalid(src->FileName))
continue;
auto func = unmangleFunc(src->FunctionName);
auto file = simplifyFile(src->FileName);
auto line = src->Line;
auto col = src->Column;
fmt::print(stderr,
" [\033[33m0x{:016x}\033[0m] \033[32m{}\033[0m at "
"\033[36m{}\033[0m:\033[33m{}\033[0m:\033[33m{}\033[0m\n",
pc, func, file, line, col);
}
}
if (db.debug)
fmt::print(stderr, "\n{}", dbListener->getPrettyBacktrace(e.getBacktrace()));
std::abort();
}
delete eng;