This diff implements the reconstruction algorithm for the call tree and
add tests.
See TraceDumper.h for documentation and explanations.
One important detail is that the tree objects are in TraceDumper, even
though Trace.h is a better home. I'm leaving that as future work.
Another detail is that this code is as slow as dumping the entire
symolicated trace, which is not that bad tbh. The reason is that we use
symbols throughout the algorithm and we are not being careful about
memory and speed. This is also another area for future improvement.
Lastly, I made sure that incomplete traces work, i.e. you start tracing
very deep in the stack or failures randomly appear in the trace. Besides
that, inline functions are recognized and the linker is identified correctly.
For example, tracing the following code generates the following call tree
#include <iostream> using namespace std; __attribute__((always_inline)) inline int mult(int x, int y) { int f = x * y; f++; f *= f; return f; } int foo(int x) { int z = mult(x, x - 1); z++; return z; } int main() { int x = 12; int z = foo(x); cout << z << endl; }
(lldb) thread trace dump function-calls thread #1: tid = 1187473 [call tree #0] inline`main + 8 at inline.cpp:19:7 to 20:14 [1, 5] inline`foo(int) at inline.cpp:12:16 to 13:15 [6, 13] inline`foo(int) + 22 [inlined] mult(int, int) at inline.cpp:6:7 to 9:10 [14, 21] inline`foo(int) + 49 at inline.cpp:13:15 to 16:1 [22, 26] inline`main + 25 at inline.cpp:20:14 to 21:11 [27, 31] inline`symbol stub for: std::ostream::operator<<(int) to <+11> [32, 34] inline`inline[0x00000000004006b0] to inline[0x00000000004006b6] [35, 36] ld-2.28.so`_dl_runtime_resolve_xsavec to 126:0 [37, 60] ld-2.28.so`.annobin__dl_relocate_object.end to 94:16 [61, 115] ld-2.28.so`_dl_lookup_symbol_x to 855:9 [116, 245] ld-2.28.so`do_lookup_x to 430:10 [246, 422] ld-2.28.so`.annobin_dl_lookup.c to 88:21 [423, 451] ld-2.28.so`strcmp to 2227:0 [452, 476] ld-2.28.so`.annobin_dl_lookup.c + 109 to 116:12 [477, 496] ld-2.28.so`strcmp to 2227:0 [497, 521] ld-2.28.so`.annobin_dl_lookup.c + 316 to 161:1 [522, 530] ld-2.28.so`do_lookup_x + 910 to 569:1 [531, 565] ld-2.28.so`_dl_lookup_symbol_x + 289 to 948:1 [566, 600] ld-2.28.so`.annobin__dl_relocate_object.end + 216 to 162:1 [601, 635] ld-2.28.so`_dl_runtime_resolve_xsavec + 126 to 153:0 [636, 650] libstdc++.so.6`std::ostream::operator<<(int) to <+31> [652, 662] libstdc++.so.6` + 3520 to <+3524> [663, 664] libstdc++.so.6`std::ostream& std::ostream::_M_insert<long>(long) to <+49> [665, 681] libstdc++.so.6` + 13072 to <+13076> [682, 683] libstdc++.so.6`std::ostream::sentry::sentry(std::ostream&) to <+112> [684, 706] libstdc++.so.6`std::ostream& std::ostream::_M_insert<long>(long) + 54 to <+275> [707, 723] libstdc++.so.6` + 5920 to <+5924> [724, 725] libstdc++.so.6`std::ctype<char>::_M_widen_init() const to <+319> [726, 1802] libstdc++.so.6` + 10288 to <+10292> [1803, 1804] libc.so.6`__memcmp_avx2_movbe to <+212> [1805, 1850] libstdc++.so.6`std::ctype<char>::_M_widen_init() const + 324 to <+362> [1851, 1860] libstdc++.so.6`std::ostream& std::ostream::_M_insert<long>(long) + 280 to <+134> [1861, 1881] libstdc++.so.6`std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char>>>::do_put(std::ostreambuf_iterator<char, std::char_traits<char>>, std::ios_base&, char, long) const to <+8> [1882, 1884] libstdc++.so.6` + 8336 to <+8340> [1885, 1886] libstdc++.so.6`std::ostreambuf_iterator<char, std::char_traits<char>> std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char>>>::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char>>, std::ios_base&, char, long) const to <+67> [1887, 1907] libstdc++.so.6`std::__use_cache<std::__numpunct_cache<char>>::operator()(std::locale const&) const to <+24> [1908, 1916] libstdc++.so.6` + 4192 to <+4196> [1917, 1918] libstdc++.so.6`std::locale::id::_M_id() const to <+50> [1919, 1924] libstdc++.so.6`std::__use_cache<std::__numpunct_cache<char>>::operator()(std::locale const&) const + 29 to <+63> [1925, 1937] libstdc++.so.6`std::ostreambuf_iterator<char, std::char_traits<char>> std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char>>>::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char>>, std::ios_base&, char, long) const + 72 to <+200> [1938, 1966] libstdc++.so.6`int std::__int_to_char<char, unsigned long>(char*, unsigned long, char const*, std::_Ios_Fmtflags, bool) to <+83> [1967, 2040] libstdc++.so.6`std::ostreambuf_iterator<char, std::char_traits<char>> std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char>>>::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char>>, std::ios_base&, char, long) const + 205 to <+325> [2041, 2068] libstdc++.so.6`__gnu_cxx::stdio_sync_filebuf<char, std::char_traits<char>>::xsputn(char const*, long) to <+19> [2069, 2074] libstdc++.so.6` + 11600 to <+11604> [2075, 2076] libc.so.6`_IO_fwrite to <+216> [2078, 2126] libc.so.6`_IO_file_xsputn@@GLIBC_2.2.5 to <+266> [2127, 2160] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 to <+403> [2161, 2176] libc.so.6`_IO_doallocbuf to <+77> [2177, 2196] libc.so.6`_IO_file_doallocate to <+93> [2197, 2219] libc.so.6`_IO_file_stat to <+15> [2220, 2224] libc.so.6`__fxstat64 to <+31> [2226, 2237] libc.so.6`_IO_file_doallocate + 99 to <+139> [2238, 2261] libc.so.6` + 160 to <+164> [2262, 2263] libc.so.6`malloc to <+137> [2264, 2302] libc.so.6`_int_malloc to <+1254> [2303, 2466] libc.so.6`malloc + 142 to <+199> [2467, 2479] libc.so.6`_IO_file_doallocate + 144 to <+169> [2480, 2487] libc.so.6`_IO_setb to <+55> [2488, 2506] libc.so.6`_IO_file_doallocate + 174 to <+213> [2507, 2515] libc.so.6`_IO_doallocbuf + 80 to <+131> [2516, 2521] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 + 408 to <+231> [2522, 2556] libc.so.6`_IO_do_write@@GLIBC_2.2.5 to <+11> [2557, 2561] libc.so.6`_IO_file_xsputn@@GLIBC_2.2.5 + 271 to <+332> [2562, 2581] libc.so.6`_IO_default_xsputn to <+110> [2582, 2615] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 to <+108> [2616, 2649] libc.so.6`_IO_default_xsputn + 113 to <+110> [2650, 2668] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 to <+108> [2669, 2702] libc.so.6`_IO_default_xsputn + 113 to <+110> [2703, 2721] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 to <+108> [2722, 2755] libc.so.6`_IO_default_xsputn + 113 to <+110> [2756, 2774] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 to <+108> [2775, 2808] libc.so.6`_IO_default_xsputn + 113 to <+110> [2809, 2827] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 to <+108> [2828, 2861] libc.so.6`_IO_default_xsputn + 113 to <+198> [2862, 2880] libc.so.6`_IO_file_xsputn@@GLIBC_2.2.5 + 337 to <+143> [2881, 2892] libc.so.6`_IO_fwrite + 220 to <+332> [2893, 2917] libstdc++.so.6`std::ostreambuf_iterator<char, std::char_traits<char>> std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char>>>::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char>>, std::ios_base&, char, long) const + 328 to <+379> [2918, 2934] libstdc++.so.6`std::ostream& std::ostream::_M_insert<long>(long) + 137 to <+165> [2935, 2938] libstdc++.so.6` + 3056 to <+3060> [2939, 2940] libstdc++.so.6`std::ostream::sentry::~sentry() to <+80> [2941, 2947] libstdc++.so.6`std::ostream& std::ostream::_M_insert<long>(long) + 170 to <+207> [2948, 2959] inline`main + 43 at inline.cpp:21:16 to 21:16 [2960, 2962] inline`symbol stub for: std::ostream::operator<<(std::ostream& (*)(std::ostream&)) to <+11> [2963, 2965] inline`inline[0x00000000004006b0] to inline[0x00000000004006b6] [2966, 2967] ld-2.28.so`_dl_runtime_resolve_xsavec to 126:0 [2968, 2991] ld-2.28.so`.annobin__dl_relocate_object.end to 94:16 [2992, 3046] ld-2.28.so`_dl_lookup_symbol_x to 855:9 [3047, 3232] ld-2.28.so`do_lookup_x to 430:10 [3233, 3401] ld-2.28.so`.annobin_dl_lookup.c to 88:21 [3402, 3430] ld-2.28.so`strcmp to 2227:0 [3431, 3481] ld-2.28.so`.annobin_dl_lookup.c + 109 to 116:12 [3482, 3501] ld-2.28.so`strcmp to 2227:0 [3502, 3526] ld-2.28.so`.annobin_dl_lookup.c + 316 to 161:1 [3527, 3535] ld-2.28.so`do_lookup_x + 910 to 569:1 [3536, 3570] ld-2.28.so`_dl_lookup_symbol_x + 289 to 948:1 [3571, 3605] ld-2.28.so`.annobin__dl_relocate_object.end + 216 to 162:1 [3606, 3640] ld-2.28.so`_dl_runtime_resolve_xsavec + 126 to 153:0 [3641, 3655] libstdc++.so.6`std::ostream::operator<<(std::ostream& (*)(std::ostream&)) to <+4> [3656, 3657] inline`symbol stub for: std::basic_ostream<char, std::char_traits<char>>& std::endl<char, std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&) to <+11> [3658, 3660] inline`inline[0x00000000004006b0] to inline[0x00000000004006b6] [3661, 3662] ld-2.28.so`_dl_runtime_resolve_xsavec to 126:0 [3663, 3686] ld-2.28.so`.annobin__dl_relocate_object.end to 94:16 [3687, 3741] ld-2.28.so`_dl_lookup_symbol_x to 855:9 [3742, 4263] ld-2.28.so`do_lookup_x to 430:10 [4264, 4372] ld-2.28.so`.annobin_dl_lookup.c to 161:1 [4373, 4395] ld-2.28.so`do_lookup_x + 910 to 430:10 [4396, 4513] ld-2.28.so`.annobin_dl_lookup.c to 88:21 [4514, 4542] ld-2.28.so`strcmp to 2227:0 [4543, 4663] ld-2.28.so`.annobin_dl_lookup.c + 109 to 116:12 [4664, 4683] ld-2.28.so`strcmp to 2227:0 [4684, 4708] ld-2.28.so`.annobin_dl_lookup.c + 316 to 161:1 [4709, 4717] ld-2.28.so`do_lookup_x + 910 to 569:1 [4718, 4752] ld-2.28.so`_dl_lookup_symbol_x + 289 to 948:1 [4753, 4787] ld-2.28.so`.annobin__dl_relocate_object.end + 216 to 162:1 [4788, 4822] ld-2.28.so`_dl_runtime_resolve_xsavec + 126 to 153:0 [4823, 4837] libstdc++.so.6`std::basic_ostream<char, std::char_traits<char>>& std::endl<char, std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&) to <+46> [4838, 4852] libstdc++.so.6` + 2672 to <+2676> [4853, 4854] libstdc++.so.6`std::ostream::put(char) to <+43> [4855, 4868] libstdc++.so.6` + 13072 to <+13076> [4869, 4870] libstdc++.so.6`std::ostream::sentry::sentry(std::ostream&) to <+112> [4871, 4893] libstdc++.so.6`std::ostream::put(char) + 48 to <+135> [4894, 4904] libstdc++.so.6`__gnu_cxx::stdio_sync_filebuf<char, std::char_traits<char>>::overflow(int) to <+17> [4905, 4911] libstdc++.so.6` + 8208 to <+8212> [4912, 4913] libc.so.6`_IO_putc to <+278> [4914, 4925] libc.so.6`__overflow to <+73> [4926, 4943] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 to <+254> [4944, 4977] libc.so.6`_IO_do_write@@GLIBC_2.2.5 to <+20> [4978, 4983] libc.so.6`new_do_write to <+90> [4984, 5011] libc.so.6`_IO_file_write@@GLIBC_2.2.5 to <+40> [5012, 5030] libc.so.6`write to <+32> [5031, 5041] libc.so.6`_IO_file_write@@GLIBC_2.2.5 + 45 to <+141> [5042, 5059] libc.so.6`new_do_write + 95 to <+178> [5060, 5084] libc.so.6`_IO_do_write@@GLIBC_2.2.5 + 25 to <+37> [5085, 5090] libc.so.6`_IO_file_overflow@@GLIBC_2.2.5 + 259 to <+108> [5091, 5097] libstdc++.so.6`std::ostream::put(char) + 138 to <+90> [5098, 5101] libstdc++.so.6` + 3056 to <+3060> [5102, 5103] libstdc++.so.6`std::ostream::sentry::~sentry() to <+80> [5104, 5110] libstdc++.so.6`std::ostream::put(char) + 95 to <+122> [5111, 5119] libstdc++.so.6`std::basic_ostream<char, std::char_traits<char>>& std::endl<char, std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&) + 51 to <+60> [5120, 5124] libstdc++.so.6` + 7696 to <+7700> [5125, 5126] libstdc++.so.6`std::ostream::flush() to <+31> [5127, 5136] libstdc++.so.6`__gnu_cxx::stdio_sync_filebuf<char, std::char_traits<char>>::sync() to <+8> [5137, 5139] libstdc++.so.6` + 13344 to <+13348> [5140, 5141] libc.so.6`_IO_fflush to <+158> [5142, 5173] libc.so.6`_IO_file_sync@@GLIBC_2.2.5 to <+172> [5174, 5191] libc.so.6`_IO_fflush + 161 to <+249> [5192, 5210] libstdc++.so.6`std::ostream::flush() + 34 to <+43> [5211, 5215]
nit