public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] Comments around tricky DWARF expressions
@ 2021-12-10 16:50 Matthew Malcomson
  0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2021-12-10 16:50 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b4b22d8614e375b5d41d62da510e885d0ed191b4

commit b4b22d8614e375b5d41d62da510e885d0ed191b4
Author: Matthew Malcomson <matthew.malcomson@arm.com>
Date:   Fri Dec 10 16:31:26 2021 +0000

    Comments around tricky DWARF expressions
    
    There are three unwinder information directives which make use of DWARF
    expressions.  These DWARF expressions describe an operation on a DWARF
    stack machine.  The unwinder parses these operations in
    `execute_cfa_program` and executes them in `execute_stack_op`.
    
    There are three dwarf directives which make use of this abstract
    machine: DW_CFA_expression, DW_CFA_val_expression, and
    DW_CFA_def_cfa_expression.  These indicate that the following DWARF
    machine operations calculate the location at which a register can be
    found, the value that should be in a register, and the value that
    represents the CFA of this frame respectively.
    
    For these expressions to work with capabilities they must perform their
    operations in such a way that the provenance is maintained.  For
    example, binary operations performed on the top two items of the stack
    must be performed by the execution routine in such a way that provenance
    is taken from the item which the producer intended.  This means that
    producer and consumer must agree.
    
    As it happens the current implementation in libgcc takes provenance in
    binary expressions from the earlier operand on the stack.  Similarly,
    all expressions that GCC emits would want provenance to come from the
    earlier operand on the stack -- see how the `and` expression is formed
    for `build_cfa_aligned_loc`, and observe that the `REG_CFA_EXPRESSION`
    note is only used for `reg+offset` and ends up just using instructions
    which encode "register plus constant" directly (e.g. `DW_OP_fbreg`,
    `DW_OP_breg<N>` operations).
    The LLVM unwinder also takes provenance from the earlier operand, and
    the idea seems to combine nicely with the fact that the evaluation of a
    `DW_CFA_expression` and `DW_CFA_val_expression` start with an "initial
    value" of the CFA placed on the DWARF stack (from which provenance seems
    likely to be taken for `DW_CFA_expression`).
    
    We make this decision more concrete and explicit by adjusting the types
    of the first and second operand when evaluating binary operations in
    `execute_stack_op`.
    
    It should be mentioned that these expressions are rarely used.  GCC does
    not emit `DW_CFA_val_expression` (even though it is implemented in the
    backend no RTL emitted reaches this point) or
    `DW_CFA_def_cfa_expression` (the codepath has an existing assertion that
    we never hit this).  It is also impossible to emit `DW_CFA_expression`
    for Morello at the moment (requirements on capabilities mean we would
    not emit the RTL `(set sp (and sp <const_int>))` and we disable SVE for
    Morello).
    The LLVM unwinder does not implement `DW_CFA_val_expression` for
    capabilities.
    
    We tested this by temporarily modifying GCC to always emit the
    `DW_CFA_expression` instructions that it could emit and ensuring that
    the unwinder could correctly fetch the registers from the stack.  Since
    the unwinder could fetch these registers the provenance was known to
    have been preserved.

Diff:
---
 gcc/dwarf2cfi.c     | 13 +++++++++++++
 libgcc/unwind-dw2.c | 28 ++++++++++++++++++++++++++--
 2 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index 4ba1a695a24..650fd7e03bf 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -3341,6 +3341,13 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
 	case DW_CFA_def_cfa_expression:
 	case DW_CFA_expression:
 	case DW_CFA_val_expression:
+	  /* MORELLO Note that these expressions require the *first* operand
+	     put onto the stack to be where we want to take provenance from.
+	     It happens that this is already the case for all ways that we can
+	     get here.  However, it is still a new requirement that is very
+	     tricky to maintain given that most targets will not know about the
+	     requirement and we have nothing alerting us if the requirement is
+	     broken  */
 	  output_cfa_loc (cfi, for_eh);
 	  break;
 
@@ -3457,6 +3464,12 @@ output_cfi_directive (FILE *f, dw_cfi_ref cfi)
     case DW_CFA_def_cfa_expression:
     case DW_CFA_expression:
     case DW_CFA_val_expression:
+      /* MORELLO Note that these expressions require the *first* operand put
+	 onto the stack to be where we want to take provenance from.  It
+	 happens that this is already the case for all ways that we can get
+	 here.  However, it is still a new requirement that is very tricky to
+	 maintain given that most targets will not know about the requirement
+	 and we have nothing alerting us if the requirement is broken  */
       if (f != asm_out_file)
 	{
 	  fprintf (f, "\t.cfi_%scfa_%sexpression ...\n",
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
index ddfb4e00879..2b964a0e495 100644
--- a/libgcc/unwind-dw2.c
+++ b/libgcc/unwind-dw2.c
@@ -593,6 +593,15 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
 	  break;
 
 	case DW_OP_addr:
+	  /* For capability architectures this is likely wrong.  The `op_ptr`
+	     will be unaligned, and the `.eh_frame` section is usually
+	     read-only (so the runtime will be unable to perform a relocation
+	     in it to give us a valid capability).
+	     Not much we can do here for such invalid Morello debug
+	     information.  Since this is somewhat experimental we crash rather
+	     than try to carry on.  If it gets seen by our users we'll look
+	     into why GCC is emitting such a directive.  The `read_pointer`
+	     call crashes for us.  */
 	  result = (_Unwind_CapWord) (_Unwind_Ptr) read_pointer (op_ptr);
 	  op_ptr += sizeof (void *);
 	  break;
@@ -853,8 +862,23 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
 	case DW_OP_gt:
 	case DW_OP_ne:
 	  {
-	    /* Binary operations.  */
-	    _Unwind_CapWord first, second;
+	    /* Binary operations.
+	       N.B. for capabilities this raises the question of where
+	       provenance should come from.  In this respect producer and
+	       consumer should both agree.
+
+	       This is not going to actually be a problem, for now we just
+	       choose the second item on the stack to take provenance from to
+	       avoid compiler warnings.
+
+	       MORELLO TODO Sort this out.
+		 While it would be nice to specify this, as it stands GCC does
+		 not emit unwind information which would end up here for
+		 Morello, and the unwind information it emits that ends up here
+		 for non-Morello architectures is done in the order that would
+		 satisfy the provenance choice above.  */
+	    _Unwind_CapWord second;
+	    _Unwind_Word first;
 	    gcc_assert (stack_elt >= 2);
 	    stack_elt -= 2;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-12-10 16:50 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-10 16:50 [gcc(refs/vendors/ARM/heads/morello)] Comments around tricky DWARF expressions Matthew Malcomson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).