Hello, I'm excited to announce that uftrace v0.17 is just released. This release comes with many bug fixes and a few new features. You can get it from the below link: https://github.com/namhyung/uftrace/releases/tag/v0.17 One notable change is the watchpoint support for global variables. This is still very limited but users can track changes of the given variable at the entry and the exit of each function. Please keep in mind that it doesn't use hardware debug registers and checks the value in softwawre. Currently it can only handle integer types. This is an example output of trivial test program called 'watchy' which changes a variable called 'global' multiple times. $ uftrace -W var:global ./watchy # DURATION TID FUNCTION [2736290] | main() { [2736290] | /* watch:var (global=1) */ [2736290] | foo() { [2736290] | /* watch:var (global=2) */ [2736290] | bar() { [2736290] | /* watch:var (global=3) */ 0.142 us [2736290] | } /* bar */ [2736290] | /* watch:var (global=4) */ 3.523 us [2736290] | } /* foo */ [2736290] | /* watch:var (global=5) */ 24.555 us [2736290] | } /* main */ Another important improvement is the dlopen support. From now on, it can capture arguments and return values as well as other debug info such as srcline. The below test program opens two libraries with dlopen(3) and calls functions in them. The lib_[abc] and foo are from the libraries and you can see the arguments the source code information. $ uftrace -a --srcline ./t-dlopen # DURATION TID FUNCTION [SOURCE] 0.747 us [2737082] | __monstartup(); 0.374 us [2737082] | __cxa_atexit(); [2737082] | main(1, 0x7ffed8abe788) { /* s-dlopen.c:5 */ [2737082] | dlopen("./libabc_test_lib.so", RTLD_LAZY) { 1.000 s [2737082] | /* linux:schedule */ 1.004 s [2737082] | } = 0x55eb7cb474c0; /* dlopen */ 11.505 us [2737082] | dlsym(0x55eb7cb474c0, "lib_a") = &lib_a; [2737082] | lib_a(1) { /* s-lib.c:10 */ [2737082] | lib_b(2) { /* s-lib.c:15 */ 4.867 us [2737082] | lib_c(1) = 0; /* s-lib.c:20 */ 6.624 us [2737082] | } = 1; /* lib_b */ 7.875 us [2737082] | } = 0; /* lib_a */ 98.767 us [2737082] | dlclose(0x55eb7cb474c0) = 0; [2737082] | dlopen("./libfoo.so", RTLD_LAZY) { 1.000 s [2737082] | /* linux:schedule */ 1.015 s [2737082] | } = 0x55eb7cb474c0; /* dlopen */ 9.467 us [2737082] | dlsym(0x55eb7cb474c0, "foo") = &foo; [2737082] | foo(1) { /* s-libfoo.cpp:12 */ 0.285 us [2737082] | AAA::bar(1); 5.261 us [2737082] | } /* foo */ 95.406 us [2737082] | dlclose(0x55eb7cb474c0) = 0; 2.020 s [2737082] | } = 0; /* main */ But this also comes with a cost. Now it needs to exchange the internal data structure to track arguments and others when dlopen is called. For now it needs to wait for 1 second before releasing the old one. Thank you all for making uftrace more useful, efficient and portable! Namhyung