Skip to content

Commit a5aa754

Browse files
Implement runtime stacktraces (#1344)
Co-authored-by: Ondřej Čertík <[email protected]>
1 parent 3340ff6 commit a5aa754

27 files changed

+595
-11
lines changed

.github/workflows/CI.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ jobs:
6363
echo "LFORTRAN_CMAKE_GENERATOR=Unix Makefiles" >> $GITHUB_ENV
6464
echo "WIN=0" >> $GITHUB_ENV
6565
echo "MACOS=0" >> $GITHUB_ENV
66+
echo "ENABLE_RUNTIME_STACKTRACE=yes" >> $GITHUB_ENV
6667
6768
- name: Setup Platform (macOS)
6869
if: contains(matrix.os, 'macos')
@@ -71,6 +72,7 @@ jobs:
7172
echo "LFORTRAN_CMAKE_GENERATOR=Unix Makefiles" >> $GITHUB_ENV
7273
echo "WIN=0" >> $GITHUB_ENV
7374
echo "MACOS=1" >> $GITHUB_ENV
75+
echo "ENABLE_RUNTIME_STACKTRACE=yes" >> $GITHUB_ENV
7476
7577
- name: Build (Linux / macOS)
7678
shell: bash -l {0}
@@ -88,6 +90,7 @@ jobs:
8890
set LFORTRAN_CMAKE_GENERATOR=Ninja
8991
set WIN=1
9092
set MACOS=0
93+
set ENABLE_RUNTIME_STACKTRACE=no
9194
call "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
9295
xonsh ci\build.xsh
9396

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ inst/bin/*
8484
*.sln
8585
*.dll
8686
*.manifest
87+
*_lines.txt
88+
*_ldd.txt
89+
*_lines.dat.txt
8790

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

CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,15 @@ if (WITH_STACKTRACE)
243243
endif()
244244
set(HAVE_LFORTRAN_STACKTRACE yes)
245245
endif()
246+
if (WITH_RUNTIME_STACKTRACE)
247+
set(WITH_UNWIND yes)
248+
if (APPLE)
249+
set(WITH_MACHO yes)
250+
else()
251+
set(WITH_LINKH yes)
252+
endif()
253+
set(HAVE_RUNTIME_STACKTRACE yes)
254+
endif()
246255
if (WITH_BFD)
247256
find_package(BFD REQUIRED)
248257
set(HAVE_LFORTRAN_BFD yes)

build1.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ cmake \
88
-DWITH_LLVM=yes \
99
-DLPYTHON_BUILD_ALL=yes \
1010
-DWITH_STACKTRACE=yes \
11+
-DWITH_RUNTIME_STACKTRACE=yes \
1112
-DWITH_LSP=no \
1213
-DWITH_LFORTRAN_BINARY_MODFILES=no \
1314
-DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH_LPYTHON;$CONDA_PREFIX" \

ci/build.xsh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ cd test-bld
5151
# compiled in Release mode and we get link failures if we mix and match build
5252
# modes:
5353
BUILD_TYPE = "Release"
54-
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) ..
54+
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 ..
5555
cmake --build . --target install -j16
5656
./src/lpython/tests/test_lpython
5757
#./src/bin/lpython < ../src/bin/example_input.txt

run_tests.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def is_included(backend):
2727
c = is_included("c")
2828
wat = is_included("wat")
2929
run = is_included("run")
30+
run_with_dbg = is_included("run_with_dbg")
3031
pass_ = test.get("pass", None)
3132
optimization_passes = ["flip_sign", "div_to_mul", "fma", "sign_from_value",
3233
"inline_function_calls", "loop_unroll",
@@ -117,5 +118,11 @@ def is_included(backend):
117118
run_test(filename, "runtime", "lpython {infile}",
118119
filename, update_reference, extra_args)
119120

121+
if run_with_dbg:
122+
run_test(
123+
filename, "run_dbg",
124+
"lpython {infile} -g --debug-with-line-column --no-color",
125+
filename, update_reference, extra_args)
126+
120127
if __name__ == "__main__":
121128
tester_main("LPython", single_test)

src/bin/dat_convert.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env python3
2+
3+
from struct import unpack
4+
from sys import argv
5+
from re import sub
6+
7+
lines = ""
8+
with open(argv[1], "rb") as f:
9+
lines = f.read()
10+
11+
list = []
12+
for i in range(0, len(lines), 24):
13+
list.append(sub('[(),]', '', str(unpack("3Q", lines[i:i+24]))))
14+
15+
with open(argv[1] + ".txt", "w") as f:
16+
j = 0
17+
for i in list:
18+
f.write(i+'\n')

src/bin/lpython.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,29 @@ int main(int argc, char *argv[])
16391639
err = link_executable({tmp_o}, outfile, runtime_library_dir,
16401640
backend, static_link, true, compiler_options);
16411641
if (err != 0) return err;
1642+
1643+
if (compiler_options.emit_debug_info) {
1644+
// TODO: Replace the following hardcoded part
1645+
std::string cmd = "";
1646+
#ifdef HAVE_LFORTRAN_MACHO
1647+
cmd += "dsymutil " + basename + ".out && llvm-dwarfdump --debug-line "
1648+
+ basename + ".out.dSYM > ";
1649+
#else
1650+
cmd += "llvm-dwarfdump --debug-line " + basename + ".out > ";
1651+
#endif
1652+
cmd += basename + "_ldd.txt && (cd src/bin; ./dwarf_convert.py ../../"
1653+
+ basename + "_ldd.txt ../../" + basename + "_lines.txt ../../"
1654+
+ basename + "_lines.dat && ./dat_convert.py ../../"
1655+
+ basename + "_lines.dat)";
1656+
int status = system(cmd.c_str());
1657+
if ( status != 0 ) {
1658+
std::cerr << "Error in creating the files used to generate "
1659+
"the debug information. This might be caused because either"
1660+
"`llvm-dwarfdump` or `Python` are not available. "
1661+
"Please activate the CONDA environment and compile again.\n";
1662+
return status;
1663+
}
1664+
}
16421665
#else
16431666
std::cerr << "Compiling Python files to object files requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl;
16441667
return 1;

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5165,8 +5165,16 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
51655165
}
51665166

51675167
void visit_Assert(const ASR::Assert_t &x) {
5168+
if (compiler_options.emit_debug_info) debug_emit_loc(x);
51685169
this->visit_expr_wrapper(x.m_test, true);
51695170
create_if_else(tmp, []() {}, [=]() {
5171+
if (compiler_options.emit_debug_info) {
5172+
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile);
5173+
llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt(
5174+
1, compiler_options.use_colors));
5175+
call_print_stacktrace_addresses(context, *module, *builder,
5176+
{fmt_ptr, fmt_ptr1});
5177+
}
51705178
if (x.m_msg) {
51715179
char* s = ASR::down_cast<ASR::StringConstant_t>(x.m_msg)->m_s;
51725180
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("AssertionError: %s\n");
@@ -5949,6 +5957,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
59495957
}
59505958

59515959
void visit_Stop(const ASR::Stop_t &x) {
5960+
if (compiler_options.emit_debug_info) {
5961+
debug_emit_loc(x);
5962+
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile);
5963+
llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt(
5964+
1, compiler_options.use_colors));
5965+
call_print_stacktrace_addresses(context, *module, *builder,
5966+
{fmt_ptr, fmt_ptr1});
5967+
}
59525968
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("STOP\n");
59535969
print_error(context, *module, *builder, {fmt_ptr});
59545970
llvm::Value *exit_code;
@@ -5963,7 +5979,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
59635979
exit(context, *module, *builder, exit_code);
59645980
}
59655981

5966-
void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) {
5982+
void visit_ErrorStop(const ASR::ErrorStop_t &x) {
5983+
if (compiler_options.emit_debug_info) {
5984+
debug_emit_loc(x);
5985+
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile);
5986+
llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt(
5987+
1, compiler_options.use_colors));
5988+
call_print_stacktrace_addresses(context, *module, *builder,
5989+
{fmt_ptr, fmt_ptr1});
5990+
}
59675991
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("ERROR STOP\n");
59685992
print_error(context, *module, *builder, {fmt_ptr});
59695993
int exit_code_int = 1;

src/libasr/codegen/llvm_utils.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,27 @@ namespace LCompilers {
5656
builder.CreateCall(fn_exit, {exit_code});
5757
}
5858

59+
// Insert the following anywhere inside the LLVM backend to print
60+
// addresses at runtime:
61+
// call_print_stacktrace_addresses(context, *module, *builder, {filename, use_colors});
62+
static inline void call_print_stacktrace_addresses(llvm::LLVMContext &context,
63+
llvm::Module &module, llvm::IRBuilder<> &builder,
64+
const std::vector<llvm::Value*> &args)
65+
{
66+
llvm::Function *fn = module.getFunction("print_stacktrace_addresses");
67+
if (!fn) {
68+
llvm::FunctionType *function_type = llvm::FunctionType::get(
69+
llvm::Type::getVoidTy(context), {
70+
llvm::Type::getInt8PtrTy(context),
71+
llvm::Type::getInt1Ty(context)
72+
}, true);
73+
fn = llvm::Function::Create(function_type,
74+
llvm::Function::ExternalLinkage, "print_stacktrace_addresses",
75+
&module);
76+
}
77+
builder.CreateCall(fn, args);
78+
}
79+
5980
namespace LLVM {
6081

6182
llvm::Value* CreateLoad(llvm::IRBuilder<> &builder, llvm::Value *x);

src/libasr/config.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
/* Define if stacktrace is enabled */
1717
#cmakedefine HAVE_LFORTRAN_STACKTRACE
18+
#cmakedefine HAVE_RUNTIME_STACKTRACE
1819
#cmakedefine HAVE_LFORTRAN_BFD
1920
#cmakedefine HAVE_LFORTRAN_DWARFDUMP
2021
#cmakedefine HAVE_LFORTRAN_LINK

0 commit comments

Comments
 (0)