Outputs CodeView S_REGREL32 symbols for unoptimized local variables that
are stored on the stack. This includes a change to dwarf2out.cc to make
it easier to extract the function frame base without having to worry
about the function prologue or epilogue.

gcc/
        * dwarf2codeview.cc (enum cv_sym_type): Add S_REGREL32.
        (write_fbreg_variable): New function.
        (write_unoptimized_local_variable): Add fblock parameter, and handle
        DW_OP_fbreg locations.
        (write_unoptimized_function_vars): Add fbloc parameter.
        (write_function): Extract frame base from DWARF.
        * dwarf2out.cc (convert_cfa_to_fb_loc_list): Output simplified frame
        base information for CodeView.
---
 gcc/dwarf2codeview.cc | 105 +++++++++++++++++++++++++++++++++++++++---
 gcc/dwarf2out.cc      |  23 +++++++++
 2 files changed, 122 insertions(+), 6 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 4596408f2bb..e01515a0ec4 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -75,6 +75,7 @@ enum cv_sym_type {
   S_REGISTER = 0x1106,
   S_LDATA32 = 0x110c,
   S_GDATA32 = 0x110d,
+  S_REGREL32 = 0x1111,
   S_COMPILE3 = 0x113c,
   S_LPROC32_ID = 0x1146,
   S_GPROC32_ID = 0x1147,
@@ -2195,12 +2196,94 @@ write_s_register (dw_die_ref die, dw_loc_descr_ref 
loc_ref)
   targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
 }
 
+/* Write an S_REGREL32 symbol in order to represent an unoptimized stack
+   variable.  The memory address is given by a register value plus an offset,
+   so we need to parse the function's DW_AT_frame_base attribute for this.  */
+
+static void
+write_fbreg_variable (dw_die_ref die, dw_loc_descr_ref loc_ref,
+                     dw_loc_descr_ref fbloc)
+{
+  unsigned int label_num = ++sym_label_num;
+  const char *name = get_AT_string (die, DW_AT_name);
+  uint32_t type;
+  uint16_t regno;
+  int offset;
+
+  /* This is struct regrel in binutils and REGREL32 in Microsoft's cvinfo.h:
+
+    struct regrel
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t offset;
+      uint32_t type;
+      uint16_t reg;
+      char name[];
+    } ATTRIBUTE_PACKED;
+  */
+
+  if (!fbloc)
+    return;
+
+  if (fbloc->dw_loc_opc >= DW_OP_breg0 && fbloc->dw_loc_opc <= DW_OP_breg31)
+    {
+      regno = dwarf_reg_to_cv (fbloc->dw_loc_opc - DW_OP_breg0);
+      offset = fbloc->dw_loc_oprnd1.v.val_int;
+    }
+  else if (fbloc->dw_loc_opc == DW_OP_bregx)
+    {
+      regno = dwarf_reg_to_cv (fbloc->dw_loc_oprnd1.v.val_int);
+      offset = fbloc->dw_loc_oprnd2.v.val_int;
+    }
+  else
+    {
+      return;
+    }
+
+  if (loc_ref->dw_loc_oprnd1.val_class != dw_val_class_unsigned_const)
+    return;
+
+  offset += loc_ref->dw_loc_oprnd1.v.val_int;
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  asm_fprintf (asm_out_file,
+              "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n",
+              label_num, label_num);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, S_REGREL32);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, offset);
+  putc ('\n', asm_out_file);
+
+  type = get_type_num (get_AT_ref (die, DW_AT_type), false, false);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, regno);
+  putc ('\n', asm_out_file);
+
+  ASM_OUTPUT_ASCII (asm_out_file, name, strlen (name) + 1);
+
+  ASM_OUTPUT_ALIGN (asm_out_file, 2);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+}
+
 /* Write a symbol representing an unoptimized variable within a function, if
    we're able to translate the DIE's DW_AT_location into its CodeView
    equivalent.  */
 
 static void
-write_unoptimized_local_variable (dw_die_ref die)
+write_unoptimized_local_variable (dw_die_ref die, dw_loc_descr_ref fbloc)
 {
   dw_attr_node *loc;
   dw_loc_descr_ref loc_ref;
@@ -2258,6 +2341,10 @@ write_unoptimized_local_variable (dw_die_ref die)
       write_s_register (die, loc_ref);
       break;
 
+    case DW_OP_fbreg:
+      write_fbreg_variable (die, loc_ref, fbloc);
+      break;
+
     default:
       break;
     }
@@ -2390,7 +2477,7 @@ write_s_end (void)
    or blocks that we encounter.  */
 
 static void
-write_unoptimized_function_vars (dw_die_ref die)
+write_unoptimized_function_vars (dw_die_ref die, dw_loc_descr_ref fbloc)
 {
   dw_die_ref first_child, c;
 
@@ -2408,14 +2495,14 @@ write_unoptimized_function_vars (dw_die_ref die)
       {
       case DW_TAG_formal_parameter:
       case DW_TAG_variable:
-       write_unoptimized_local_variable (c);
+       write_unoptimized_local_variable (c, fbloc);
        break;
 
       case DW_TAG_lexical_block:
        {
          bool block_started = write_s_block32 (c);
 
-         write_unoptimized_function_vars (c);
+         write_unoptimized_function_vars (c, fbloc);
 
          if (block_started)
            write_s_end ();
@@ -2437,9 +2524,10 @@ static void
 write_function (codeview_symbol *s)
 {
   unsigned int label_num = ++sym_label_num;
-  dw_attr_node *loc_low, *loc_high;
+  dw_attr_node *loc_low, *loc_high, *frame_base;
   const char *label_low, *label_high;
   rtx rtx_low, rtx_high;
+  dw_loc_descr_ref fbloc = NULL;
 
   /* This is struct procsym in binutils and PROCSYM32 in Microsoft's cvinfo.h:
 
@@ -2555,7 +2643,12 @@ write_function (codeview_symbol *s)
 
   targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
 
-  write_unoptimized_function_vars (s->function.die);
+  frame_base = get_AT (s->function.die, DW_AT_frame_base);
+
+  if (frame_base && frame_base->dw_attr_val.val_class == dw_val_class_loc)
+    fbloc = frame_base->dw_attr_val.v.val_loc;
+
+  write_unoptimized_function_vars (s->function.die, fbloc);
 
   /* Output the S_PROC_ID_END record.  */
 
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 357efaa5990..d5144714c6e 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -21183,6 +21183,29 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
   list = NULL;
 
   memset (&next_cfa, 0, sizeof (next_cfa));
+
+#ifdef CODEVIEW_DEBUGGING_INFO
+  /* We can write simplified frame base information for CodeView, as we're
+     not using it for rewinding.  */
+  if (codeview_debuginfo_p ())
+    {
+      int dwreg = DEBUGGER_REGNO (cfun->machine->fs.cfa_reg->u.reg.regno);
+
+      next_cfa.reg.set_by_dwreg (dwreg);
+      next_cfa.offset = cfun->machine->fs.fp_valid
+       ? cfun->machine->fs.fp_offset : cfun->machine->fs.sp_offset;
+
+      *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
+                                fde->dw_fde_begin, 0,
+                                fde->dw_fde_second_begin
+                                ? fde->dw_fde_second_end : fde->dw_fde_end, 0,
+                                section);
+      maybe_gen_llsym (list);
+
+      return list;
+    }
+#endif
+
   next_cfa.reg.set_by_dwreg (INVALID_REGNUM);
   remember = next_cfa;
 
-- 
2.44.2

Reply via email to