aboutsummaryrefslogtreecommitdiff
path: root/libsframe/doc/sframe-spec.texi
diff options
context:
space:
mode:
Diffstat (limited to 'libsframe/doc/sframe-spec.texi')
-rw-r--r--libsframe/doc/sframe-spec.texi222
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