]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gas: sframe: partially process DWARF unwind info in CFI_escape
authorIndu Bhagat <indu.bhagat@oracle.com>
Wed, 26 Feb 2025 21:50:49 +0000 (13:50 -0800)
committerIndu Bhagat <indu.bhagat@oracle.com>
Wed, 26 Feb 2025 21:50:49 +0000 (13:50 -0800)
CFI_escape is most commonly used to include DWARF expressions in the
unwind information.  One may also use CFI_escape to add OS-specific CFI
opcodes.  Up until now, SFrame generation process would skip generating
SFrame FDE at the mere sight of a CFI_escape opcode.

Fine tune the handling of CFI_escape for SFrame generation by explicitly
checking for few "harmless" (in context of SFrame generation)
CFI_escape DWARF info:
  - DW_CFA_expression affecting registers of no significance to SFrame
    stack trace info
  - DW_CFA_value_offset affecting registers of no significance to SFrame
    stack trace info

Expose the current cfi_escape_data structure in dw2gencfi.c to the
relevant header file to allow SFrame generation APIs to use it too.

Valid unwind info may be split across multiple .cfi_escape directives.
Conversely, it is also allowed to simply put multiple DWARF expressions
and/or operations in a single .cfi_escape directive.  Handling all of
these cases correctly will need parsing/processing that is not deemed
worth the effort in context of SFrame generation; We continue to skip
generating SFrame FDE for these cases and warn the user.

In future, SFrame stack trace format may support non-SP/FP as base
register (albeit in limited form).  Add an explicit check in
sframe_xlate_do_escape_expr (to test against the current CFA register)
to ensure the functionality continues to work.

Use differentiated warning text in sframe_xlate_do_val_offset to avoid
confusion to the user as the same function is used for handling
.cfi_val_offset and .cfi_escape DW_CFA_val_offset,...

Also, add a common test with DWARF reg 12 which is non SP / FP on x86_64
and aarch64 (and s390x too).

gas/
* gas/dw2gencfi.c (struct cfi_escape_data): Move from ...
* gas/dw2gencfi.h (struct cfi_escape_data): ... to.
* gas/gen-sframe.c (sframe_xlate_do_val_offset): Include string
for .cfi_escape conditionally.
(sframe_xlate_do_escape_expr): New definition.
(sframe_xlate_do_escape_val_offset): Likewise.
(sframe_xlate_do_cfi_escape): Likewise.
(sframe_do_cfi_insn): Handle CFI_escape explicitly.

gas/testsuite/
* gas/cfi-sframe/cfi-sframe.exp: Add new tests.
* gas/cfi-sframe/cfi-sframe-common-9.d: New test.
* gas/cfi-sframe/cfi-sframe-common-9.s: New test.
* gas/cfi-sframe/cfi-sframe-x86_64-empty-1.d: New test.
* gas/cfi-sframe/cfi-sframe-x86_64-empty-1.s: New test.
* gas/cfi-sframe/cfi-sframe-x86_64-empty-2.d: New test.
* gas/cfi-sframe/cfi-sframe-x86_64-empty-2.s: New test.
* gas/cfi-sframe/cfi-sframe-x86_64-empty-3.d: New test.
* gas/cfi-sframe/cfi-sframe-x86_64-empty-3.s: New test.

12 files changed:
gas/dw2gencfi.c
gas/dw2gencfi.h
gas/gen-sframe.c
gas/testsuite/gas/cfi-sframe/cfi-sframe-common-9.d [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-common-9.s [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-1.d [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-1.s [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-2.d [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-2.s [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-3.d [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-3.s [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe.exp

index 012af0ff33e025dc07215faff0761dcdb5c1b65f..41e15cd1463b65ef5a3f40cb77821cf05a1c2475 100644 (file)
@@ -368,12 +368,6 @@ generic_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
 }
 #endif
 
-struct cfi_escape_data
-{
-  struct cfi_escape_data *next;
-  expressionS exp;
-};
-
 struct cie_entry
 {
   struct cie_entry *next;
index 42eb3863a0a55341aaaf23ae14cf46ee345bee9b..9b0e5979c0d452a85a064f49b13277fbea625cf2 100644 (file)
@@ -93,6 +93,12 @@ extern void cfi_add_CFA_restore_state (void);
 #define MULTIPLE_FRAME_SECTIONS (SUPPORT_FRAME_LINKONCE || SUPPORT_COMPACT_EH \
                                 || TARGET_MULTIPLE_EH_FRAME_SECTIONS)
 
+struct cfi_escape_data
+{
+  struct cfi_escape_data *next;
+  expressionS exp;
+};
+
 struct cfi_insn_data
 {
   struct cfi_insn_data *next;
index 13478efab6b966626a7016ea98360a0b12846b33..947faf366d3d2dd40450f535c737068438c1ce5f 100644 (file)
@@ -1117,11 +1117,15 @@ sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
 }
 
 /* Translate DW_CFA_val_offset into SFrame context.
-   Return SFRAME_XLATE_OK if success.  */
+   Return SFRAME_XLATE_OK if success.
+
+   When CFI_ESC_P is true, the CFI_INSN is hand-crafted using CFI_escape
+   data.  See sframe_xlate_do_escape_val_offset.  */
 
 static int
-sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
-                           struct cfi_insn_data *cfi_insn)
+sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
+                           const struct cfi_insn_data *cfi_insn,
+                           bool cfi_esc_p)
 {
   /* Previous value of register is CFA + offset.  However, if the specified
      register is not interesting (SP, FP, or RA reg), the current
@@ -1134,7 +1138,8 @@ sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
       /* Ignore SP reg, if offset matches assumed default rule.  */
       || (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG && cfi_insn->u.ri.offset != 0))
     {
-      as_warn (_("skipping SFrame FDE; %s register %u in .cfi_val_offset"),
+      as_warn (_("skipping SFrame FDE; %s with %s reg %u"),
+              cfi_esc_p ? ".cfi_escape DW_CFA_val_offset" : ".cfi_val_offset",
               sframe_register_name (cfi_insn->u.ri.reg), cfi_insn->u.ri.reg);
       return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
     }
@@ -1310,6 +1315,221 @@ sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
   return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
 }
 
+/* Handle DW_CFA_expression in .cfi_escape.
+
+   As with sframe_xlate_do_cfi_escape, the intent of this function is to detect
+   only the simple-to-process but common cases, where skipping over the escape
+   expr data does not affect correctness of the SFrame stack trace data.
+
+   Sets CALLER_WARN_P for skipped cases (and returns SFRAME_XLATE_OK) where the
+   caller must warn.  The caller then must also set
+   SFRAME_XLATE_ERR_NOTREPRESENTED for their callers.  */
+
+static int
+sframe_xlate_do_escape_expr (const struct sframe_xlate_ctx *xlate_ctx,
+                            const struct cfi_insn_data *cfi_insn,
+                            bool *caller_warn_p)
+{
+  const struct cfi_escape_data *e = cfi_insn->u.esc;
+  int err = SFRAME_XLATE_OK;
+  unsigned int reg = 0;
+  unsigned int i = 0;
+
+  /* Check roughly for an expression
+     DW_CFA_expression: r1 (rdx) (DW_OP_bregN (reg): OFFSET).  */
+#define CFI_ESC_NUM_EXP 4
+  offsetT items[CFI_ESC_NUM_EXP] = {0};
+  while (e->next)
+    {
+      e = e->next;
+      if ((i == 2 && (items[1] != 2)) /* Expected len of 2 in DWARF expr.  */
+         /* We do not care for the exact values of items[2] and items[3],
+            so an explicit check for O_constant isnt necessary either.  */
+         || i >= CFI_ESC_NUM_EXP || (i < 2 && e->exp.X_op != O_constant))
+       goto warn_and_exit;
+      items[i] = e->exp.X_add_number;
+      i++;
+    }
+
+  if (i <= CFI_ESC_NUM_EXP - 1)
+    goto warn_and_exit;
+
+  /* reg operand to DW_CFA_expression is ULEB128.  For the purpose at hand,
+     however, the register value will be less than 128 (CFI_ESC_NUM_EXP set
+     to 4).  See an extended comment in sframe_xlate_do_escape_expr for why
+     reading ULEB is okay to skip without sacrificing correctness.  */
+  reg = items[0];
+#undef CFI_ESC_NUM_EXP
+
+  if (reg == SFRAME_CFA_SP_REG || reg == SFRAME_CFA_FP_REG
+#ifdef SFRAME_FRE_RA_TRACKING
+      || (sframe_ra_tracking_p () && reg == SFRAME_CFA_RA_REG)
+#endif
+      || reg == xlate_ctx->cur_fre->cfa_base_reg)
+    {
+      as_warn (_("skipping SFrame FDE; "
+                ".cfi_escape DW_CFA_expression with %s reg %u"),
+              sframe_register_name (reg), reg);
+      err = SFRAME_XLATE_ERR_NOTREPRESENTED;
+    }
+  /* else safe to skip, so continue to return SFRAME_XLATE_OK.  */
+
+  return err;
+
+warn_and_exit:
+  *caller_warn_p = true;
+  return err;
+}
+
+/* Handle DW_CFA_val_offset in .cfi_escape.
+
+   As with sframe_xlate_do_cfi_escape, the intent of this function is to detect
+   only the simple-to-process but common cases, where skipping over the escape
+   expr data does not affect correctness of the SFrame stack trace data.
+
+   Sets CALLER_WARN_P for skipped cases (and returns SFRAME_XLATE_OK) where the
+   caller must warn.  The caller then must also set
+   SFRAME_XLATE_ERR_NOTREPRESENTED for their callers.  */
+
+static int
+sframe_xlate_do_escape_val_offset (const struct sframe_xlate_ctx *xlate_ctx,
+                                  const struct cfi_insn_data *cfi_insn,
+                                  bool *caller_warn_p)
+{
+  const struct cfi_escape_data *e = cfi_insn->u.esc;
+  int err = SFRAME_XLATE_OK;
+  unsigned int i = 0;
+  unsigned int reg;
+  offsetT offset;
+
+  /* Check for (DW_CFA_val_offset reg scaled_offset) sequence.  */
+#define CFI_ESC_NUM_EXP 2
+  offsetT items[CFI_ESC_NUM_EXP] = {0};
+  while (e->next)
+    {
+      e = e->next;
+      if (i >= CFI_ESC_NUM_EXP || e->exp.X_op != O_constant)
+       goto warn_and_exit;
+      items[i] = e->exp.X_add_number;
+      i++;
+    }
+  if (i <= CFI_ESC_NUM_EXP - 1)
+    goto warn_and_exit;
+
+  /* Both arguments to DW_CFA_val_offset are ULEB128.  Especially with APX (on
+     x86) we're going to see DWARF register numbers above 127, for the extended
+     GPRs.  And large enough stack frames would also require multi-byte offset
+     representation.  However, since we limit our focus on cases when
+     CFI_ESC_NUM_EXP is 2, reading ULEB can be skipped.  IOW, although not
+     ideal, SFrame FDE generation in case of an APX register in
+     DW_CFA_val_offset is being skipped (PS: this does _not_ mean incorrect
+     SFrame stack trace data).
+
+     Recall that the intent here is to check for simple and prevalent cases,
+     when feasible.  */
+
+  reg = items[0];
+  offset = items[1];
+#undef CFI_ESC_NUM_EXP
+
+  /* Invoke sframe_xlate_do_val_offset itself for checking.  */
+  struct cfi_insn_data temp = {
+    .insn = DW_CFA_val_offset,
+    .u = {
+      .ri = {
+       .reg = reg,
+       .offset = offset * DWARF2_CIE_DATA_ALIGNMENT
+      }
+    }
+  };
+  err = sframe_xlate_do_val_offset (xlate_ctx, &temp, true);
+  return err;
+
+warn_and_exit:
+  *caller_warn_p = true;
+  return err;
+}
+
+/* Handle CFI_escape in SFrame context.
+
+   .cfi_escape CFI directive allows the user to add arbitrary data to the
+   unwind info.  DWARF expressions commonly follow after CFI_escape (fake CFI)
+   DWARF opcode.  One might also use CFI_escape to add OS-specific CFI opcodes
+   even.
+
+   Complex unwind info added using .cfi_escape directive _may_ be of no
+   consequence for SFrame when the affected registers are not SP, FP, RA or
+   CFA.  The challenge in confirming the afore-mentioned is that it needs full
+   parsing (and validation) of the data presented after .cfi_escape.  Here we
+   take a case-by-case approach towards skipping _some_ instances of
+   .cfi_escape: skip those that can be *easily* determined to be harmless in
+   the context of SFrame stack trace information.
+
+   This function partially processes data following .cfi_escape and returns
+   SFRAME_XLATE_OK if OK to skip.  */
+
+static int
+sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
+                           const struct cfi_insn_data *cfi_insn)
+{
+  const struct cfi_escape_data *e;
+  bool warn_p = false;
+  int err = SFRAME_XLATE_OK;
+  offsetT firstop;
+
+  e = cfi_insn->u.esc;
+
+  if (!e)
+    return SFRAME_XLATE_ERR_INVAL;
+
+  if (e->exp.X_op != O_constant)
+    return SFRAME_XLATE_ERR_NOTREPRESENTED;
+
+  firstop = e->exp.X_add_number;
+  switch (firstop)
+    {
+    case DW_CFA_nop:
+      /* One or more nops together are harmless for SFrame.  */
+      while (e->next)
+       {
+         e = e->next;
+         if (e->exp.X_op != O_constant || e->exp.X_add_number != DW_CFA_nop)
+           {
+             warn_p = true;
+             break;
+           }
+       }
+      break;
+
+    case DW_CFA_expression:
+      err = sframe_xlate_do_escape_expr (xlate_ctx, cfi_insn, &warn_p);
+      break;
+
+    case DW_CFA_val_offset:
+      err = sframe_xlate_do_escape_val_offset (xlate_ctx, cfi_insn, &warn_p);
+      break;
+
+    /* FIXME - Also add processing for DW_CFA_GNU_args_size in future?  */
+
+    default:
+      warn_p = true;
+      break;
+    }
+
+  if (warn_p)
+    {
+      /* In all other cases (e.g., DW_CFA_def_cfa_expression or other
+        OS-specific CFI opcodes), skip inspecting the DWARF expression.
+        This may impact the asynchronicity due to loss of coverage.
+        Continue to warn the user and bail out.  */
+      as_warn (_("skipping SFrame FDE; .cfi_escape with op (%#lx)"),
+              (unsigned long)firstop);
+      err = SFRAME_XLATE_ERR_NOTREPRESENTED;
+    }
+
+  return err;
+}
+
 /* Returns the DWARF call frame instruction name or fake CFI name for the
    specified CFI opcode, or NULL if the value is not recognized.  */
 
@@ -1384,7 +1604,7 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
       err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
       break;
     case DW_CFA_val_offset:
-      err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn);
+      err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn, false);
       break;
     case DW_CFA_remember_state:
       err = sframe_xlate_do_remember_state (xlate_ctx);
@@ -1406,6 +1626,9 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
     case DW_CFA_register:
       err = sframe_xlate_do_register (xlate_ctx, cfi_insn);
       break;
+    case CFI_escape:
+      err = sframe_xlate_do_cfi_escape (xlate_ctx, cfi_insn);
+      break;
     /* Following CFI opcodes are not processed at this time.
        These do not impact the coverage of the basic stack tracing
        information as conveyed in the SFrame format.  */
@@ -1413,8 +1636,7 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
     case DW_CFA_same_value:
       break;
     default:
-      /* Following skipped operations do, however, impact the asynchronicity:
-         - CFI_escape.  */
+      /* Other skipped operations may, however, impact the asynchronicity.  */
       {
        const char *cfi_name = sframe_get_cfi_name (op);
 
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-9.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-9.d
new file mode 100644 (file)
index 0000000..80c9235
--- /dev/null
@@ -0,0 +1,22 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_escape test
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: NONE
+#?    CFA fixed FP offset: \-?\d+
+#?    CFA fixed RA offset: \-?\d+
+    Num FDEs: 1
+    Num FREs: 2
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 8 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+16 +u +[uf] +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-9.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-9.s
new file mode 100644 (file)
index 0000000..3ecde7e
--- /dev/null
@@ -0,0 +1,18 @@
+## CFI_escape may be used to encode DWARF expressions among other things.
+## Depending on the register applicable for the DWARF expression, skipping
+## SFrame FDE may be OK: SFrame stack trace information is relevant for SP, FP
+## and RA only.  In this test, CFI_escape is safe to skip (does not affect
+## correctness of SFrame data).  The register 0xc is non SP / FP on both
+## aarch64 and x86_64.
+       .cfi_startproc
+       .long 0
+       .cfi_def_cfa_offset 16
+# DW_CFA_expression,reg 0xc,length 2,DW_OP_breg6,SLEB(-8)
+       .cfi_escape 0x10,0xc,0x2,0x76,0x78
+# DW_CFA_nop
+       .cfi_escape 0x0
+       .cfi_escape 0x0,0x0,0x0,0x0
+# DW_CFA_val_offset,reg 0xc,ULEB scaled offset
+       .cfi_escape 0x14,0xc,0x4
+       .long 0
+       .cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-1.d
new file mode 100644 (file)
index 0000000..0123994
--- /dev/null
@@ -0,0 +1,17 @@
+#as: --gsframe
+#warning: skipping SFrame FDE; \.cfi_escape DW\_CFA\_expression with SP reg 7
+#objdump: --sframe=.sframe
+#name: CFI_escape with register of significance to SFrame
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: NONE
+#?    CFA fixed FP offset: \-?\d+
+#?    CFA fixed RA offset: \-?\d+
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-1.s
new file mode 100644 (file)
index 0000000..cfb1a95
--- /dev/null
@@ -0,0 +1,11 @@
+## CFI_escape may be used to encode DWARF expressions among other things.
+## In this test, a DWARF expression involving a register of interest (REG_SP on
+## x86_64, which is also the CFA in the current FRE) is seen.  SFrame
+## generation, is skipped and a warning issued to the user.
+       .cfi_startproc
+       .long 0
+       .cfi_def_cfa_offset 16
+# DW_CFA_expression,reg 0x7,length 2,DW_OP_breg6,SLEB(-8)
+       .cfi_escape 0x10,0x7,0x2,0x76,0x78
+       .long 0
+       .cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-2.d
new file mode 100644 (file)
index 0000000..482803b
--- /dev/null
@@ -0,0 +1,17 @@
+#as: --gsframe
+#warning: skipping SFrame FDE; \.cfi\_escape DW\_CFA\_val\_offset with FP reg 6
+#objdump: --sframe=.sframe
+#name: CFI_escape with register of significance to SFrame II
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: NONE
+#?    CFA fixed FP offset: \-?\d+
+#?    CFA fixed RA offset: \-?\d+
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-2.s
new file mode 100644 (file)
index 0000000..90e108e
--- /dev/null
@@ -0,0 +1,11 @@
+## CFI_escape may be used to encode DWARF expressions among other things.
+## In this test, a DWARF expression involving a register of interest (REG_SP on
+## x86_64, which is also the CFA in the current FRE) is seen.  SFrame
+## generation, is skipped and a warning issued to the user.
+       .cfi_startproc
+       .long 0
+       .cfi_def_cfa_offset 16
+# DW_CFA_val_offset,rbp,ULEB scaled offset(16)
+       .cfi_escape 0x14,0x6,0x2
+       .long 0
+       .cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-3.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-3.d
new file mode 100644 (file)
index 0000000..177fb21
--- /dev/null
@@ -0,0 +1,17 @@
+#as: --gsframe
+#warning: skipping SFrame FDE; \.cfi\_escape with op \(0x14\)
+#objdump: --sframe=.sframe
+#name: CFI_escape with multiple DWARF expr
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: NONE
+#?    CFA fixed FP offset: \-?\d+
+#?    CFA fixed RA offset: \-?\d+
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-3.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-3.s
new file mode 100644 (file)
index 0000000..b6af0c3
--- /dev/null
@@ -0,0 +1,12 @@
+## CFI_escape may be used to encode DWARF expressions among other things.
+## In this test, a stream of valid DWARF information is presented in a
+## single CFI_escape.  Parsing such cases is currently not deemed worth the
+## effort.  So, such cases are skipped for SFrame FDE generation and a
+## warning issued to the user.
+       .cfi_startproc
+       .long 0
+       .cfi_def_cfa_offset 16
+# DW_CFA_val_offset,rcx,ULEB scaled offset(16), DW_CFA_expr,r10,length,DW_OP_deref,SLEB(-8)
+       .cfi_escape 0x14,0x2,0x2,0x10,0xa,0x2,0x76,0x78
+       .long 0
+       .cfi_endproc
index b119b9da73d4abcceb8b3c8cfef1906a2247fe5e..a09946635c20e41cc91e28774325503a80faaa40 100644 (file)
@@ -78,6 +78,7 @@ if  { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]) \
     run_dump_test "cfi-sframe-common-6"
     run_dump_test "cfi-sframe-common-7"
     run_dump_test "cfi-sframe-common-8"
+    run_dump_test "cfi-sframe-common-9"
 
     run_dump_test "common-empty-1"
     run_dump_test "common-empty-2"
@@ -89,6 +90,9 @@ if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then {
     if { [gas_x86_64_check] } then {
        set ASFLAGS "$ASFLAGS --64"
        run_dump_test "cfi-sframe-x86_64-1"
+       run_dump_test "cfi-sframe-x86_64-empty-1"
+       run_dump_test "cfi-sframe-x86_64-empty-2"
+       run_dump_test "cfi-sframe-x86_64-empty-3"
        set ASFLAGS "$old_ASFLAGS"
     }
 }