otp icon indicating copy to clipboard operation
otp copied to clipboard

Tracing: Allow traced function to return current stack trace

Open sidkshatriya opened this issue 3 years ago • 5 comments

Recently in #5305 the caller_line option was added (PR is not yet merged to master but this PR is complete). This feature allows match spec bodies to return the calling function name with the call site position using message.

The next logical request would be to allow a new match spec body tracing option stack_trace that will allow traced functions to return their whole stack trace.

Justification for feature Is this feature useful? I think so. But better than that -- this feature is already available today in the Redbug Erlang tracer. The Redbug tracer has the the ability to return the stack trace of a function via stack

e.g.

redbug:start('test_mod:some_func->stack', [{msgs, 400}, {time, 10000}])

When you think about it, how is the Redbug tracer implementing this feature without any tracing primitives that give you a stack trace??? The answer is simple, Redbug uses tracing option process_dump to first obtain a full process dump.

This process dump is later parsed for the all Return addr lines to construct the stack trace (see here)

As this is currently implemented:

  • It is inefficient because a lot of other data is collected during the process_dump
  • It is fragile because tomorrow if the process dump text output changes a bit, the functionality will break
  • Currently the stack trace provided is a bit crude because it only has the function names. We can provide source file and location just like we did for caller_line. This will make the stack trace more useful

This is a useful functionality and in my view Erlang/OTP should provide a primitive for traced functions to return stack traces.

Implementation The implementation looks relatively straightforward. I have looked at the stack dump related code within the process_dump routines in otp source. With the experience I got on #5305 I think I can implement it. But before I spend any time on this problem I'd like to ask if this is something you'd like to see implemented.

cc: @garazdawi @jhogberg

P.S. There are the usual issues with the stack trace looking funny when return_trace is used. However, this problem is present with Redbug even today because it consults the process dump Return Addr lines to construct the stack trace. You will see a lot of non-useful "undefined" frames (non-useful to humans anyways) when return_trace is in effect.

sidkshatriya avatar Oct 28 '21 21:10 sidkshatriya

Yes, this is something that we would like to have and we would appreciate help implementing it.

Something to keep in mind when looking at this is that the stack trace has to follow the max-depth of system_flag(backtrace_depth) and we think that it should also be possible to specify a smaller max-depth in the match spec. That is something like this:

[{'_',[],[{message,{current_stacktrace,2}}]}] %% depth is minimum of 2 and system_flag(backtrace_depth)
[{'_',[],[{message,{current_stacktrace}}]}] %% depth is system_flag(backtrace_depth)

garazdawi avatar Oct 29 '21 15:10 garazdawi

The implementation looks relatively straightforward. I have looked at the stack dump related code within the process_dump routines in otp source. With the experience I got on #5305 I think I can implement it. But before I spend any time on this problem I'd like to ask if this is something you'd like to see implemented.

cc: @garazdawi @jhogberg

P.S. There are the usual issues with the stack trace looking funny when return_trace is used. However, this problem is present with Redbug even today because it consults the process dump Return Addr lines to construct the stack trace. You will see a lot of non-useful "undefined" frames (non-useful to humans anyways) when return_trace is in effect.

To save you some time, look at how current_stacktrace in erl_bif_info.c is implemented, it uses the internal stack crawling routines that take care of all edge cases surrounding tracing, alternate frame layouts, honoring backtrace depth, etc. It should make this about as straightforward as #5305.

As an aside, I think line numbers should be added to stack traces in process_dump just to make crash dumps easier to read. It'll require changing all tools that inspect that format (e.g. crashdump_viewer and apparently redbug too) though, so maybe in another PR.

jhogberg avatar Oct 30 '21 01:10 jhogberg

@sidkshatriya is there any update on this? I'd love this feature. I would like to use it to get the caller of a traced function that is defined in my project. Would be really helpful.

kanes115 avatar Sep 15 '22 19:09 kanes115

Based on your requirement, you can use caller_line or caller.

See https://www.erlang.org/doc/apps/erts/match_spec.html

(This issue pertains to return the whole stack trace)

sidkshatriya avatar Sep 15 '22 20:09 sidkshatriya

Sorry for the confusion but I meant I'd like to have the callstack in some sane form (exactly what this issue is about). I'd like to iterate over calls on the callstack to get to the first call that is done by a module defined in my project. If I just use caller I can get some intermediary function call like Enum.map or :erlang.apply.

kanes115 avatar Sep 16 '22 08:09 kanes115