Skip to content

Commit

Permalink
Implement runtime stacktraces (lcompilers#1344)
Browse files Browse the repository at this point in the history
Co-authored-by: Ondřej Čertík <ondrej@certik.us>
  • Loading branch information
Thirumalai-Shaktivel and certik committed Jan 13, 2023
1 parent 3340ff6 commit a5aa754
Show file tree
Hide file tree
Showing 27 changed files with 595 additions and 11 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ jobs:
echo "LFORTRAN_CMAKE_GENERATOR=Unix Makefiles" >> $GITHUB_ENV
echo "WIN=0" >> $GITHUB_ENV
echo "MACOS=0" >> $GITHUB_ENV
echo "ENABLE_RUNTIME_STACKTRACE=yes" >> $GITHUB_ENV
- name: Setup Platform (macOS)
if: contains(matrix.os, 'macos')
Expand All @@ -71,6 +72,7 @@ jobs:
echo "LFORTRAN_CMAKE_GENERATOR=Unix Makefiles" >> $GITHUB_ENV
echo "WIN=0" >> $GITHUB_ENV
echo "MACOS=1" >> $GITHUB_ENV
echo "ENABLE_RUNTIME_STACKTRACE=yes" >> $GITHUB_ENV
- name: Build (Linux / macOS)
shell: bash -l {0}
Expand All @@ -88,6 +90,7 @@ jobs:
set LFORTRAN_CMAKE_GENERATOR=Ninja
set WIN=1
set MACOS=0
set ENABLE_RUNTIME_STACKTRACE=no
call "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
xonsh ci\build.xsh
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ inst/bin/*
*.sln
*.dll
*.manifest
*_lines.txt
*_ldd.txt
*_lines.dat.txt

### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Global/macOS.gitignore

Expand Down
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,15 @@ if (WITH_STACKTRACE)
endif()
set(HAVE_LFORTRAN_STACKTRACE yes)
endif()
if (WITH_RUNTIME_STACKTRACE)
set(WITH_UNWIND yes)
if (APPLE)
set(WITH_MACHO yes)
else()
set(WITH_LINKH yes)
endif()
set(HAVE_RUNTIME_STACKTRACE yes)
endif()
if (WITH_BFD)
find_package(BFD REQUIRED)
set(HAVE_LFORTRAN_BFD yes)
Expand Down
1 change: 1 addition & 0 deletions build1.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ cmake \
-DWITH_LLVM=yes \
-DLPYTHON_BUILD_ALL=yes \
-DWITH_STACKTRACE=yes \
-DWITH_RUNTIME_STACKTRACE=yes \
-DWITH_LSP=no \
-DWITH_LFORTRAN_BINARY_MODFILES=no \
-DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH_LPYTHON;$CONDA_PREFIX" \
Expand Down
2 changes: 1 addition & 1 deletion ci/build.xsh
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ cd test-bld
# compiled in Release mode and we get link failures if we mix and match build
# modes:
BUILD_TYPE = "Release"
cmake -G $LFORTRAN_CMAKE_GENERATOR -DCMAKE_VERBOSE_MAKEFILE=ON -DWITH_LLVM=yes -DWITH_LSP=yes -DWITH_XEUS=yes -DCMAKE_PREFIX_PATH=$CONDA_PREFIX -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DWITH_LFORTRAN_BINARY_MODFILES=no -DCMAKE_BUILD_TYPE=@(BUILD_TYPE) ..
cmake -G $LFORTRAN_CMAKE_GENERATOR -DCMAKE_VERBOSE_MAKEFILE=ON -DWITH_LLVM=yes -DWITH_LSP=yes -DWITH_XEUS=yes -DCMAKE_PREFIX_PATH=$CONDA_PREFIX -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DWITH_LFORTRAN_BINARY_MODFILES=no -DCMAKE_BUILD_TYPE=@(BUILD_TYPE) -DWITH_RUNTIME_STACKTRACE=$ENABLE_RUNTIME_STACKTRACE ..
cmake --build . --target install -j16
./src/lpython/tests/test_lpython
#./src/bin/lpython < ../src/bin/example_input.txt
Expand Down
7 changes: 7 additions & 0 deletions run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def is_included(backend):
c = is_included("c")
wat = is_included("wat")
run = is_included("run")
run_with_dbg = is_included("run_with_dbg")
pass_ = test.get("pass", None)
optimization_passes = ["flip_sign", "div_to_mul", "fma", "sign_from_value",
"inline_function_calls", "loop_unroll",
Expand Down Expand Up @@ -117,5 +118,11 @@ def is_included(backend):
run_test(filename, "runtime", "lpython {infile}",
filename, update_reference, extra_args)

if run_with_dbg:
run_test(
filename, "run_dbg",
"lpython {infile} -g --debug-with-line-column --no-color",
filename, update_reference, extra_args)

if __name__ == "__main__":
tester_main("LPython", single_test)
18 changes: 18 additions & 0 deletions src/bin/dat_convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env python3

from struct import unpack
from sys import argv
from re import sub

lines = ""
with open(argv[1], "rb") as f:
lines = f.read()

list = []
for i in range(0, len(lines), 24):
list.append(sub('[(),]', '', str(unpack("3Q", lines[i:i+24]))))

with open(argv[1] + ".txt", "w") as f:
j = 0
for i in list:
f.write(i+'\n')
23 changes: 23 additions & 0 deletions src/bin/lpython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,29 @@ int main(int argc, char *argv[])
err = link_executable({tmp_o}, outfile, runtime_library_dir,
backend, static_link, true, compiler_options);
if (err != 0) return err;

if (compiler_options.emit_debug_info) {
// TODO: Replace the following hardcoded part
std::string cmd = "";
#ifdef HAVE_LFORTRAN_MACHO
cmd += "dsymutil " + basename + ".out && llvm-dwarfdump --debug-line "
+ basename + ".out.dSYM > ";
#else
cmd += "llvm-dwarfdump --debug-line " + basename + ".out > ";
#endif
cmd += basename + "_ldd.txt && (cd src/bin; ./dwarf_convert.py ../../"
+ basename + "_ldd.txt ../../" + basename + "_lines.txt ../../"
+ basename + "_lines.dat && ./dat_convert.py ../../"
+ basename + "_lines.dat)";
int status = system(cmd.c_str());
if ( status != 0 ) {
std::cerr << "Error in creating the files used to generate "
"the debug information. This might be caused because either"
"`llvm-dwarfdump` or `Python` are not available. "
"Please activate the CONDA environment and compile again.\n";
return status;
}
}
#else
std::cerr << "Compiling Python files to object files requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl;
return 1;
Expand Down
26 changes: 25 additions & 1 deletion src/libasr/codegen/asr_to_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5165,8 +5165,16 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
}

void visit_Assert(const ASR::Assert_t &x) {
if (compiler_options.emit_debug_info) debug_emit_loc(x);
this->visit_expr_wrapper(x.m_test, true);
create_if_else(tmp, []() {}, [=]() {
if (compiler_options.emit_debug_info) {
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile);
llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt(
1, compiler_options.use_colors));
call_print_stacktrace_addresses(context, *module, *builder,
{fmt_ptr, fmt_ptr1});
}
if (x.m_msg) {
char* s = ASR::down_cast<ASR::StringConstant_t>(x.m_msg)->m_s;
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("AssertionError: %s\n");
Expand Down Expand Up @@ -5949,6 +5957,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
}

void visit_Stop(const ASR::Stop_t &x) {
if (compiler_options.emit_debug_info) {
debug_emit_loc(x);
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile);
llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt(
1, compiler_options.use_colors));
call_print_stacktrace_addresses(context, *module, *builder,
{fmt_ptr, fmt_ptr1});
}
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("STOP\n");
print_error(context, *module, *builder, {fmt_ptr});
llvm::Value *exit_code;
Expand All @@ -5963,7 +5979,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
exit(context, *module, *builder, exit_code);
}

void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) {
void visit_ErrorStop(const ASR::ErrorStop_t &x) {
if (compiler_options.emit_debug_info) {
debug_emit_loc(x);
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile);
llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt(
1, compiler_options.use_colors));
call_print_stacktrace_addresses(context, *module, *builder,
{fmt_ptr, fmt_ptr1});
}
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("ERROR STOP\n");
print_error(context, *module, *builder, {fmt_ptr});
int exit_code_int = 1;
Expand Down
21 changes: 21 additions & 0 deletions src/libasr/codegen/llvm_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,27 @@ namespace LCompilers {
builder.CreateCall(fn_exit, {exit_code});
}

// Insert the following anywhere inside the LLVM backend to print
// addresses at runtime:
// call_print_stacktrace_addresses(context, *module, *builder, {filename, use_colors});
static inline void call_print_stacktrace_addresses(llvm::LLVMContext &context,
llvm::Module &module, llvm::IRBuilder<> &builder,
const std::vector<llvm::Value*> &args)
{
llvm::Function *fn = module.getFunction("print_stacktrace_addresses");
if (!fn) {
llvm::FunctionType *function_type = llvm::FunctionType::get(
llvm::Type::getVoidTy(context), {
llvm::Type::getInt8PtrTy(context),
llvm::Type::getInt1Ty(context)
}, true);
fn = llvm::Function::Create(function_type,
llvm::Function::ExternalLinkage, "print_stacktrace_addresses",
&module);
}
builder.CreateCall(fn, args);
}

namespace LLVM {

llvm::Value* CreateLoad(llvm::IRBuilder<> &builder, llvm::Value *x);
Expand Down
1 change: 1 addition & 0 deletions src/libasr/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

/* Define if stacktrace is enabled */
#cmakedefine HAVE_LFORTRAN_STACKTRACE
#cmakedefine HAVE_RUNTIME_STACKTRACE
#cmakedefine HAVE_LFORTRAN_BFD
#cmakedefine HAVE_LFORTRAN_DWARFDUMP
#cmakedefine HAVE_LFORTRAN_LINK
Expand Down
Loading

0 comments on commit a5aa754

Please sign in to comment.