-
Notifications
You must be signed in to change notification settings - Fork 171
Implement runtime stacktraces #1344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement runtime stacktraces #1344
Conversation
43580a1
to
d3df449
Compare
I added unwind_callback in the intrinsics. |
Yes, I would check manually that the addresses that this returns are correct. I would also expose this so that the user can call it. Let's put it into ltypes, something like "ltypes.get_stacktrace_addresses()". |
Here is how to print the runtime stacktrace: diff --git a/examples/expr2.py b/examples/expr2.py
index 2e66f1e58..f58eda174 100644
--- a/examples/expr2.py
+++ b/examples/expr2.py
@@ -1,6 +1,13 @@
+def g():
+ assert True
+
+def f():
+ g()
+
def main0():
x: i32
x = (2+3)*5
+ f()
print(x)
main0()
diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp
index e7144a025..de974de8d 100644
--- a/src/libasr/codegen/asr_to_llvm.cpp
+++ b/src/libasr/codegen/asr_to_llvm.cpp
@@ -4900,6 +4900,7 @@ public:
}
void visit_Assert(const ASR::Assert_t &x) {
+ call_print_stacktrace_addresses(context, *module, *builder, {});
this->visit_expr_wrapper(x.m_test, true);
create_if_else(tmp, []() {}, [=]() {
if (x.m_msg) { This prints: $ lpython examples/expr2.py
0 10008b8bb
1 10008b9d3
2 100067e53
3 100067e43
4 100067e6f
5 100067e33
6 100067e9f
25 |
if (info->dlpi_phdr[i].p_type == PT_LOAD) { | ||
ElfW(Addr) min_addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; | ||
ElfW(Addr) max_addr = min_addr + info->dlpi_phdr[i].p_memsz; | ||
printf("%lx\n", d->current_pc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prints 0
, I think the value is not passed correctly.
@certik any idea why does this prints 0
?
if (dl_iterate_phdr(shared_lib_callback, &d) == 0) { | ||
// printf("%d %lx %lx\n", i, d->pc[i], d->local_pc); | ||
// printf("%lx\n", d->current_pc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, it prints the correct value.
struct dl_phdr_info { | ||
ElfW(Addr) dlpi_addr; | ||
const char *dlpi_name; | ||
const ElfW(Phdr) *dlpi_phdr; | ||
ElfW(Half) dlpi_phnum; | ||
}; | ||
|
||
extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *, | ||
size_t, void *), void *__data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the problem can be caused by this as well.
I added this because we get the following warning and error
home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1208:32: warning: ‘struct dl_phdr_info’ declared inside parameter list will not be visible outside of this definition or declaration
1208 | int shared_lib_callback(struct dl_phdr_info *info,
| ^~~~~~~~~~~~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c: In function ‘shared_lib_callback’:
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1211:29: error: invalid use of undefined type ‘struct dl_phdr_info’
1211 | for (int i = 0; i < info->dlpi_phnum; i++) {
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1212:17: error: invalid use of undefined type ‘struct dl_phdr_info’
1212 | if (info->dlpi_phdr[i].p_type == PT_LOAD) {
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1213:39: error: invalid use of undefined type ‘struct dl_phdr_info’
1213 | ElfW(Addr) min_addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1213:57: error: invalid use of undefined type ‘struct dl_phdr_info’
1213 | ElfW(Addr) min_addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1214:50: error: invalid use of undefined type ‘struct dl_phdr_info’
1214 | ElfW(Addr) max_addr = min_addr + info->dlpi_phdr[i].p_memsz;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1220:51: error: invalid use of undefined type ‘struct dl_phdr_info’
1220 | d->local_pc = d->current_pc - info->dlpi_addr;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1221:37: error: invalid use of undefined type ‘struct dl_phdr_info’
1221 | printf("%lx\n", info->dlpi_addr);
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1208:32: warning: ‘struct dl_phdr_info’ declared inside parameter list will not be visible outside of this definition or declaration
1208 | int shared_lib_callback(struct dl_phdr_info *info,
| ^~~~~~~~~~~~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c: In function ‘shared_lib_callback’:
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1211:29: error: invalid use of undefined type ‘struct dl_phdr_info’
1211 | for (int i = 0; i < info->dlpi_phnum; i++) {
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1212:17: error: invalid use of undefined type ‘struct dl_phdr_info’
1212 | if (info->dlpi_phdr[i].p_type == PT_LOAD) {
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1213:39: error: invalid use of undefined type ‘struct dl_phdr_info’
1213 | ElfW(Addr) min_addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1213:57: error: invalid use of undefined type ‘struct dl_phdr_info’
1213 | ElfW(Addr) min_addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1214:50: error: invalid use of undefined type ‘struct dl_phdr_info’
1214 | ElfW(Addr) max_addr = min_addr + info->dlpi_phdr[i].p_memsz;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1220:51: error: invalid use of undefined type ‘struct dl_phdr_info’
1220 | d->local_pc = d->current_pc - info->dlpi_addr;
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1221:37: error: invalid use of undefined type ‘struct dl_phdr_info’
1221 | printf("%lx\n", info->dlpi_addr);
| ^~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c: In function ‘print_stacktrace_addresses’:
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1235:13: warning: implicit declaration of function ‘dl_iterate_phdr’ [-Wimplicit-function-declaration]
1235 | if (dl_iterate_phdr(shared_lib_callback, &d) == 0) {
| ^~~~~~~~~~~~~~~
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c: In function ‘print_stacktrace_addresses’:
/home/thirumalai/Open_Source/lpython/src/libasr/runtime/lfortran_intrinsics.c:1235:13: warning: implicit declaration of function ‘dl_iterate_phdr’ [-Wimplicit-function-declaration]
1235 | if (dl_iterate_phdr(shared_lib_callback, &d) == 0) {
| ^~~~~~~~~~~~~~~
make[2]: *** [src/runtime/legacy/CMakeFiles/lpython_runtime_static.dir/build.make:76: src/runtime/legacy/CMakeFiles/lpython_runtime_static.dir/__/__/libasr/runtime/lfortran_intrinsics.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:477: src/runtime/legacy/CMakeFiles/lpython_runtime_static.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
make[2]: *** [src/runtime/legacy/CMakeFiles/lpython_runtime.dir/build.make:76: src/runtime/legacy/CMakeFiles/lpython_runtime.dir/__/__/libasr/runtime/lfortran_intrinsics.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:451: src/runtime/legacy/CMakeFiles/lpython_runtime.dir/all] Error 2
Not sure, we just need to debug it. |
I was able to debug and fix the issue: /home/thirumalai/Open_Source/lpython/src/bin/../runtime/liblpython_runtime.so
0 7fba4418ed0b: pc
7d0b: local_pc
/home/thirumalai/Open_Source/lpython/src/bin/../runtime/liblpython_runtime.so
1 7fba4418ef23: pc
7f23: local_pc
2 55bf57cca167: pc
1167: local_pc
3 55bf57cca155: pc
1155: local_pc
4 55bf57cca175: pc
1175: local_pc
5 55bf57cca145: pc
1145: local_pc
6 55bf57cca185: pc
1185: local_pc
/lib/x86_64-linux-gnu/libc.so.6
7 7fba43e90d8f: pc
29d8f: local_pc
/lib/x86_64-linux-gnu/libc.so.6
8 7fba43e90e3f: pc
29e3f: local_pc
9 55bf57cca074: pc
1074: local_pc and llvm_dwarfdump: Address Line Column File ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x0000000000001140 0 0 1 0 0 is_stmt
0x0000000000001141 10 1 1 0 0 is_stmt prologue_end
0x0000000000001150 0 0 1 0 0 is_stmt
0x0000000000001151 2 5 1 0 0 is_stmt prologue_end
0x0000000000001160 0 0 1 0 0 is_stmt
0x0000000000001161 5 5 1 0 0 is_stmt prologue_end
0x0000000000001170 0 0 1 0 0 is_stmt
0x0000000000001171 8 5 1 0 0 is_stmt prologue_end
0x0000000000001180 0 0 1 0 0 is_stmt
0x0000000000001181 1 1 1 0 0 is_stmt prologue_end
0x000000000000118a 1 1 1 0 0 is_stmt end_sequence I think we are getting the almost near address. 1 def f():
2 g()
3
4 def g():
5 assert True
6
7 def main0():
8 f()
9
10 main0()
11
12 # Not implemented yet in LPython:
13 #if __name__ == "__main__":
14 # main() |
Now, I will try to map the address and report back. |
4784db2
to
56ca046
Compare
@certik how does A: 144 $ cat lines.txt
1
examples/expr2.py
6 Are the above contents correct? is this the expected output from dwarf_convert? |
56ca046
to
e4708ff
Compare
lpython/src/bin/dwarf_convert.py Lines 160 to 162 in 08b04b0
From above code, the contents seem to be correct print (addr, line)
4417 10
4433 2
4449 5
4481 8
4497 1
4506 1 How do I unpack this correctly? |
Why convert to |
e4708ff
to
c7b8953
Compare
Here is the current ouput: examples/expr2.py: 140371440169592
# main()
examples/expr2.py: 8
f()
examples/expr2.py: 5
assert True
examples/expr2.py: 1
def f():
examples/expr2.py: 2
g()
examples/expr2.py: 140371440169592
# main() There are some bugs, I will debug it tomorrow. |
Excellent progress! I'll have time to meet next week if you need my help. This is good. |
This PR is ready for review! There are two things to do next:
|
Reproduce the output using: $ lpython examples/expr2.py -g --debug-with-line-column -o a.out
$ llvm-dwarfdump --debug-line a.out > a.txt
$ (cd src/bin; ./dwarf_convert.py ../../a.txt ../../lines.txt ../../lines.dat)
$ ./src/bin/dat_convert.py lines.dat
$ ./a.out
File "examples/expr2.py", line 5
assert True
File "examples/expr2.py", line 2
g()
File "examples/expr2.py", line 8
f()
File "examples/expr2.py", line 10
main0()
File "examples/expr2.py", line 1
def f():
File "examples/expr2.py", line 10
main0() |
Awesome, very good! I think this is pretty much it, now we just need to polish this. |
src/libasr/codegen/asr_to_llvm.cpp
Outdated
llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile); | ||
call_print_stacktrace_addresses(context, *module, *builder, {fmt_ptr}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two lines should be moved below into the create_if_else
branch.
@@ -1165,3 +1171,177 @@ LFORTRAN_API void _lpython_close(int64_t fd) | |||
exit(1); | |||
} | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrap this into #ifdef HAVE_LFORTRAN_UNWIND
@@ -6,6 +6,9 @@ | |||
#include <inttypes.h> | |||
#include <stdbool.h> | |||
|
|||
#include <unwind.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move into .c and wrap with #ifdef HAVE_LFORTRAN_UNWIND
@@ -6,6 +6,9 @@ | |||
#include <inttypes.h> | |||
#include <stdbool.h> | |||
|
|||
#include <unwind.h> | |||
#include <ctype.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to .c
@@ -18,6 +21,33 @@ struct _lfortran_complex_64 { | |||
double re, im; | |||
}; | |||
|
|||
// Runtime Stacktrace | |||
#define LCOMPILERS_MAX_STACKTRACE_LENGTH 200 | |||
char *binary_filename; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move into .c
// Styles and Colors | ||
#define DIM "\033[2m" | ||
#define BOLD "\033[1m" | ||
#define S_RESET "\033[0m" | ||
#define MAGENTA "\033[35m" | ||
#define C_RESET "\033[39m" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to .c
224291a
to
066ea44
Compare
…TRACE ifdef block
72909ad
to
264bbdb
Compare
264bbdb
to
70323bb
Compare
Finally, I was able to pass all the tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks good enough to merge. Rebase or squash the history before merging.
Thanks for the approval and guidance |
No description provided.