diff options
Diffstat (limited to 'libsframe/doc/sframe-spec.texi')
-rw-r--r-- | libsframe/doc/sframe-spec.texi | 222 |
1 files changed, 194 insertions, 28 deletions
diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi index bb2b35a..c1730ad 100644 --- a/libsframe/doc/sframe-spec.texi +++ b/libsframe/doc/sframe-spec.texi @@ -52,6 +52,11 @@ low-overhead mechanism to generate stack traces. @menu * Introduction:: * SFrame Section:: +* ABI/arch-specific Definition:: + +Appendices +* Generating Stack Traces using SFrame:: + * Index:: @end menu @@ -399,7 +404,7 @@ in the format. @end multitable The presence of an explicit identification of ABI/arch in SFrame may allow -stack trace generators to make certain ABI-specific decisions. +stack trace generators to make certain ABI/arch-specific decisions. @node SFrame Function Descriptor Entries @section SFrame FDE @@ -612,41 +617,42 @@ identifier to reflect the chosen SFrame FRE type is stored in the @cindex SFrame FRE The SFrame frame row entry sub-section contains the core of the stack trace -information. +information. An SFrame frame row entry (FRE) is a self-sufficient record +containing SFrame stack trace information for a range of contiguous +(instruction) addresses, starting at the specified offset from the start of the +function. -An SFrame frame row entry is a self-sufficient record containing SFrame stack -trace information for a range of contiguous addresses, starting at the -specified offset from the start of the function. Each SFrame frame row entry -is followed by S*N bytes, where: +Each SFrame FRE encodes the stack offsets to recover the CFA, FP and RA (where +applicable) for the respective instruction addresses. To encode this +information, each SFrame FRE is followed by S*N bytes, where: @itemize @minus @item -@code{S} is the size of the stack frame offset for the FRE, and +@code{S} is the size of a stack offset for the FRE, and @item -@code{N} is the number of stack frame offsets in the FRE +@code{N} is the number of stack offsets in the FRE @end itemize -The stack offsets, following the FRE, are interpreted in order as follows: +The entities @code{S}, @code{N} are encoded in the SFrame FRE info word, via +the @code{fre_offset_size} and the @code{fre_offset_count} respectively. More +information about the precise encoding and range of values for @code{S} and +@code{N} is provided later in the @xref{The SFrame FRE Info Word}. -@itemize @minus -@item -The first offset is always used to locate the CFA, by interpreting it as: -CFA = @code{BASE_REG} + offset1. -@item -If RA is being tracked, the second offset is always used to locate the RA, by -interpreting it as: RA = CFA + offset2. If RA is @emph{not} being tracked -@emph{and} FP is being tracked, the second offset will be used to locate the -FP, by interpreting it as: FP = CFA + offset2. -@item -If both RA and FP are being tracked, the third offset will be used to locate -the FP, by interpreting it as FP = CFA + offset3. -@end itemize +@cindex Provisions for future ABIs +It is important to underline here that although the canonical interpretation +of these bytes is as stack offsets (to recover CFA, FP and RA), these bytes +@emph{may} be used by future ABIs/architectures to convey other information on +a per SFrame FRE basis. -The entities @code{S}, @code{N} and @code{BASE_REG} are identified using the -SFrame FRE info word, a.k.a. the @code{sframe_fre_info} -@xref{The SFrame FRE Info Word}. +In summary, SFrame file format, by design, supports a variable number of stack +offsets at the tail end of each SFrame FRE. To keep the SFrame file +format specification flexible yet extensible, the interpretation of the stack +offsets is ABI/arch-specific. The precise interpretation of the FRE stack +offsets in the currently supported ABIs/architectures is covered in the +ABI/arch-specific definition of the SFrame file format, +@xref{ABI/arch-specific Definition}. -Following are the definitions of the allowed SFrame FRE: +Next, the definitions of the three SFrame FRE types are as follows: @example typedef struct sframe_frame_row_entry_addr1 @@ -683,7 +689,7 @@ SFrame FRE applies. The value encoded in the @code{sfre_start_address} field is the offset in bytes of the start address of the SFrame FRE, from the start address of the function. -Further FRE types may be added in future. +Further SFrame FRE types may be added in future. @menu * The SFrame FRE Info Word:: @@ -710,7 +716,8 @@ SFRAME_FRE_OFFSET_4B. @item 1-4 @tab @code{fre_offset_count} -@tab A value of upto 3 is allowed to track all three of CFA, FP and RA. +@tab A max value of 15 is allowed. Typically, a value of upto 3 is sufficient +for most ABIs to track all three of CFA, FP and RA. @item 0 @tab @code{fre_cfa_base_reg_id} @@ -741,6 +748,165 @@ long. @end multitable +@node ABI/arch-specific Definition +@chapter ABI/arch-specific Definition +@cindex ABI/arch-specific Definition + +This section covers the ABI/arch-specific definition of the SFrame file format. + +Currently, the only part of the SFrame file format definition that is +ABI/arch-specific is the interpretation of the variable number of bytes at the +tail end of each SFrame FRE. Currently, these bytes are only used for +representing stack offsets (for all the currently supported ABIs). It is +recommended to peruse this section along with @xref{SFrame Frame Row Entries} +for clarity of context. + +Future ABIs must specify the algorithm for identifying the appropriate SFrame +FRE stack offsets in this chapter. This should inevitably include the +blueprint for interpreting the variable number of bytes at the tail end of the +SFrame FRE for the specific ABI/arch. Any further provisions, e.g., using the +auxiliary SFrame header, etc., if used, must also be outlined here. + +@menu +* AMD64:: +* AArch64:: +@end menu + +@node AMD64 +@section AMD64 + +Irrespective of the ABI, the first stack offset is always used to locate the +CFA, by interpreting it as: CFA = @code{BASE_REG} + offset1. The +identification of the @code{BASE_REG} is done by using the +@code{fre_cfa_base_reg_id} field in the SFrame FRE info word. + +In AMD64, the return address (RA) is always saved on stack when a function +call is executed. Further, AMD64 ABI mandates that the RA be saved at a +@code{fixed offset} from the CFA when entering a new function. This means +that the RA does not need to be tracked per SFrame FRE. The fixed offset is +encoded in the SFrame file format in the field @code{sfh_cfa_fixed_ra_offset} +in the SFrame header. @xref{SFrame Header}. + +Hence, the second stack offset (in the SFrame FRE), when present, will be used +to locate the FP, by interpreting it as: FP = CFA + offset2. + +Hence, in summary: + +@multitable {Offset ID} {Interpretation in AMD64 in AMD64} +@headitem Offset ID @tab Interpretation in AMD64 +@item 1 @tab CFA = @code{BASE_REG} + offset1 +@item 2 @tab FP = CFA + offset2 +@end multitable + +@node AArch64 +@section AArch64 + +Irrespective of the ABI, the first stack offset is always used to locate the +CFA, by interpreting it as: CFA = @code{BASE_REG} + offset1. The +identification of the @code{BASE_REG} is done by using the +@code{fre_cfa_base_reg_id} field in the SFrame FRE info word. + +In AARCH64, the AAPCS64 standard specifies that the Frame Record saves both FP +and LR (a.k.a the RA). However, the standard does not mandate the precise +location in the function where the frame record is created, if at all. Hence +the need to track RA in the SFrame stack trace format. As RA is being tracked +in this ABI, the second stack offset is always used to locate the RA, by +interpreting it as: RA = CFA + offset2. The third stack offset will be used to +locate the FP, by interpreting it as: FP = CFA + offset3. + +Given the nature of things, the number of stack offsets seen on AARCH64 per +SFrame FRE is either 1 or 3. + +Hence, in summary: + +@multitable {Offset ID} {Interpretation in AArch64 in X} +@headitem Offset ID @tab Interpretation in AArch64 +@item 1 @tab CFA = @code{BASE_REG} + offset1 +@item 2 @tab RA = CFA + offset2 +@item 3 @tab FP = CFA + offset3 +@end multitable + +@node Generating Stack Traces using SFrame +@appendix Generating Stack Traces using SFrame + +Using some C-like pseudocode, this section highlights how SFrame provides a +simple, fast and low-overhead mechanism to generate stack traces. 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. + +In the current context, a @code{frame} is the abstract construct that +encapsulates the following information: +@itemize @minus +@item +program counter (PC), +@item +stack pointer (SP), and +@item +frame pointer (FP) +@end itemize + +With that said, establishing the first @code{frame} should be trivial: + +@example + // frame 0 + frame->pc = current_IP; + frame->sp = get_reg_value (REG_SP); + frame->fp = get_reg_value (REG_FP); +@end example + +where @code{REG_SP} and @code{REG_FP} are are ABI-designated stack pointer and +frame pointer registers respectively. + +Next, given frame N, generating stack trace needs us to get frame N+1. This +can be done as follows: + +@example + // Get the PC, SP, and FP for frame N. + pc = frame->pc; + sp = frame->sp; + fp = frame->fp; + // Populate frame N+1. + int err = get_next_frame (&next_frame, pc, sp, fp); +@end example + +where given the values of the program counter, stack pointer and frame pointer +from frame N, @code{get_next_frame} populates the provided @code{next_frame} +object and returns the error code, if any. In the following pseudocode for +@code{get_next_frame}, the @code{sframe_*} functions fetch information from the +SFrame section. + +@example + fre = sframe_find_fre (pc); + if (fre) + // Whether the base register for CFA tracking is REG_FP. + base_reg_val = sframe_fre_base_reg_fp_p (fre) ? fp : sp; + // Get the CFA stack offset from the FRE. + cfa_offset = sframe_fre_get_cfa_offset (fre); + // Get the fixed RA offset or FRE stack offset as applicable. + ra_offset = sframe_fre_get_ra_offset (fre); + // Get the fixed FP offset or FRE stack offset as applicable. + fp_offset = sframe_fre_get_fp_offset (fre); + + cfa = base_reg_val + cfa_offset; + next_frame->sp = cfa; + + ra_stack_loc = cfa + ra_offset; + // Get the address stored in the stack location. + next_frame->pc = read_value (ra_stack_loc); + + if (fp_offset is VALID) + fp_stack_loc = cfa + fp_offset; + // Get the value stored in the stack location. + next_frame->fp = read_value (fp_stack_loc); + else + // Continue to use the value of fp as it has not + // been clobbered by the current frame yet. + next_frame->fp = fp; + else + ret = ERR_NO_SFRAME_FRE; +@end example + @node Index @unnumbered Index |