[Development report #5] Improve the kinst DTrace provider
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 18 Mar 2023 20:37:36 UTC
I changed the implementation of inline function tracing in dt_sugar to append new probes to the main clause list rather than create separate probes for each one of the inline copies found. Before: # dtrace -dn 'kinst::cam_iosched_has_more_trim:entry' dtrace:::ERROR { ((self->%error) = 0x1); } kinst::cam_iosched_get_trim:13 { } kinst::cam_iosched_next_bio:13 { } kinst::cam_iosched_schedule:40 { } After: # dtrace -dn 'kinst::cam_iosched_has_more_trim:entry' kinst::cam_iosched_get_trim:13, kinst::cam_iosched_next_bio:13, kinst::cam_iosched_schedule:40 { } This turned out to be way simpler and cleaner than the original, broken, mechanism, which was to get a deep copy of the main clause list and copy its predicates and actions to the new clauses. In my last report I mentioned that for return probes, the return offset given by DWARF corresponds to the instruction after the return one, and so I manually went one instruction back to get the correct offset. I realized that doing this unconditionally didn't exactly work as expected, but not doing this didn't work either, because sometimes we end up outside the inline copy's and/or the caller function's bounds. To fix this, we go back one instruction if one of the following conditions is met: - The address returned by DWARF corresponds to the last instruction of the caller function, which in this case (see previous report) is outside the caller function altogether. - If the inline low/high boundaries are given by DW_AT_ranges, we go back one instruction only at the last range. - If the boundaries are given by DW_AT_lowpc/DW_AT_highpc, we always go back one instruction, otherwise we'll end up outside the inline function's bounds. kinst up until now was ignoring any function whose first instruction wasn't `push %rbp`, but doing this means we couldn't trace functions that just happen to `push %rbp` after the first instruction. I modified kinst to instead look if there's a `push %rbp` anywhere in the function. This however still isn't quite complete because kinst did and still does ignore functions that do not `push %rbp` at all, which in some cases is correct, because such functions usually correspond to exception handlers, but there are functions such as cpu_switch(), or leaf functions with their frame pointer omitted (if compiled without `-mno-omit-leaf-frame-pointer`) which are safe to trace, but kinst cannot. Christos