[3/3] doc: sframe: add appendix for generating stack traces
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
Add an appendix to provide a rough outline to show how to generate stack
traces using the SFrame format. Such content should hopefully aid the
reader assimmilate the information in the specification.
libsframe/
* doc/sframe-spec.texi: Add new appendix.
---
libsframe/doc/sframe-spec.texi | 54 ++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
@@ -823,6 +823,60 @@ Hence, in summary:
@item 3 @tab FP = CFA + offset3
@end multitable
+@appendix Generating stack traces using SFrame
+
+Following pseudocode highlights how SFrame provides a simple, fast and
+low-overhead mechanism to generate stack traces.
+
+For sake of brevity, only the core algorithm to get the @emph{next frame}
+(given the current frame) is outlined below. Needless to say that for
+generating accurate and useful stack traces, several other aspects will need
+attention: finding and decoding bits of SFrame section(s) in the program
+binary, symbolization of addresses, to name a few. That said, establishing the
+first frame should be trivial:
+
+@noindent
+@code{@ @ @ @ // frame 0} @*
+@code{@ @ @ @ frame->pc = current_IP;} @*
+@code{@ @ @ @ frame->sp = get_reg_value (REG_SP);} @*
+@code{@ @ @ @ frame->fp = get_reg_value (REG_FP);}
+
+Next, given frame N, generating stack trace needs us to get frame N+1. This
+can be done as follows:
+
+@code {int err = get_next_frame (&frame, pc, sp, fp);}
+
+where @code{get_next_frame} populates the RA, SP, and FP values in the provided
+@code{frame} object and return the error code, if any. In the following code,
+the @code{sframe_*} functions fetch information from the SFrame section.
+
+@noindent
+@code{@ @ @ @ fre = sframe_find_fre (pc);} @*
+@code{@ @ @ @ if (fre)} @*
+@code{@ @ @ @ @ @ @ @ base_reg = fre->base_fp_p ? REG_FP : REG_SP;} @*
+@code{@ @ @ @ @ @ @ @ cfa_offset = sframe_fre_get_cfa_offset (fre);} @*
+@code{@ @ @ @ @ @ @ @ // Get fixed RA offset or stack offset from FRE as applicable.} @*
+@code{@ @ @ @ @ @ @ @ ra_offset = sframe_fre_get_ra_offset (fre);} @*
+@code{@ @ @ @ @ @ @ @ fp_offset = sframe_fre_get_fp_offset (fre);} @*
+@code{@ @ @ @ @ @ @ @ } @*
+@code{@ @ @ @ @ @ @ @ cfa = base_reg + cfa_offset;} @*
+@code{@ @ @ @ @ @ @ @ frame->sp = cfa;} @*
+@code{@ @ @ @ @ @ @ @ } @*
+@code{@ @ @ @ @ @ @ @ ra_stack_loc = cfa + ra_offset;} @*
+@code{@ @ @ @ @ @ @ @ // Get the address stored in the stack location.} @*
+@code{@ @ @ @ @ @ @ @ frame->pc = read_value (ra_stack_loc);} @*
+@code{@ @ @ @ @ @ @ @ } @*
+@code{@ @ @ @ @ @ @ @ if (fp_offset is VALID)} @*
+@code{@ @ @ @ @ @ @ @ @ @ @ @ fp_stack_loc = cfa + fp_offset;} @*
+@code{@ @ @ @ @ @ @ @ @ @ @ @ // Get the value stored in the stack location.} @*
+@code{@ @ @ @ @ @ @ @ @ @ @ @ frame->fp = read_value (fp_stack_loc);} @*
+@code{@ @ @ @ @ @ @ @ else} @*
+@code{@ @ @ @ @ @ @ @ @ @ @ @ // continue to use the value of fp as it has not} @*
+@code{@ @ @ @ @ @ @ @ @ @ @ @ // been clobbered by the current frame yet.} @*
+@code{@ @ @ @ @ @ @ @ @ @ @ @ frame->fp = fp;} @*
+@code{@ @ @ @ else} @*
+@code{@ @ @ @ @ @ @ @ ret = ERR_NO_SFRAME_FRE}
+
@node Index
@unnumbered Index