mirror of
https://github.com/exaloop/codon.git
synced 2025-06-03 15:03:52 +08:00
Refactor backtraces
This commit is contained in:
parent
e76b756226
commit
8dc2c45e88
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user