Outputs S_DEFRANGE_REGISTER_REL symbols for optimized local variables that are
on the stack, consisting of the stack register, the offset, and the code range
for which this applies.

gcc/
        * dwarf2codeview.cc (enum cv_sym_type): Add S_DEFRANGE_REGISTER_REL.
        (write_defrange_register_rel): New function.
        (write_optimized_local_variable_loc): Add fbloc param, and call
        write_defrange_register_rel.
        (write_optimized_local_variable): Add fbloc param.
        (write_optimized_function_vars): Add fbloc param.
---
 gcc/dwarf2codeview.cc | 128 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 119 insertions(+), 9 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 15253978968..74bbf6bc1d7 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -79,6 +79,7 @@ enum cv_sym_type {
   S_COMPILE3 = 0x113c,
   S_LOCAL = 0x113e,
   S_DEFRANGE_REGISTER = 0x1141,
+  S_DEFRANGE_REGISTER_REL = 0x1145,
   S_LPROC32_ID = 0x1146,
   S_GPROC32_ID = 0x1147,
   S_PROC_ID_END = 0x114f
@@ -2409,10 +2410,113 @@ write_defrange_register (dw_loc_descr_ref expr, rtx 
range_start, rtx range_end)
   targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
 }
 
+/* Write an S_DEFRANGE_REGISTER_REL symbol, which describes a range for which
+   an S_LOCAL variable is held in memory given by the value of a certain
+   register plus an offset.  */
+
+static void
+write_defrange_register_rel (dw_loc_descr_ref expr, dw_loc_descr_ref fbloc,
+                            rtx range_start, rtx range_end)
+{
+  unsigned int label_num = ++sym_label_num;
+  uint16_t regno;
+  int offset;
+
+  /* This is defrange_register_rel in binutils and DEFRANGESYMREGISTERREL in
+     Microsoft's cvinfo.h:
+
+      struct lvar_addr_range
+      {
+       uint32_t offset;
+       uint16_t section;
+       uint16_t length;
+      } ATTRIBUTE_PACKED;
+
+      struct lvar_addr_gap {
+       uint16_t offset;
+       uint16_t length;
+      } ATTRIBUTE_PACKED;
+
+      struct defrange_register_rel
+      {
+       uint16_t size;
+       uint16_t kind;
+       uint16_t reg;
+       uint16_t offset_parent;
+       uint32_t offset_register;
+       struct lvar_addr_range range;
+       struct lvar_addr_gap gaps[];
+      } 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 (expr->dw_loc_oprnd1.val_class != dw_val_class_unsigned_const)
+    return;
+
+  offset += expr->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_DEFRANGE_REGISTER_REL);
+  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);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, 0);
+  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);
+
+  asm_fprintf (asm_out_file, "\t.secrel32 ");
+  output_addr_const (asm_out_file, range_start);
+  fputc ('\n', asm_out_file);
+
+  asm_fprintf (asm_out_file, "\t.secidx ");
+  output_addr_const (asm_out_file, range_start);
+  fputc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  output_addr_const (asm_out_file, range_end);
+  fputs (" - ", asm_out_file);
+  output_addr_const (asm_out_file, range_start);
+  putc ('\n', asm_out_file);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+}
+
 /* Try to write an S_DEFRANGE_* symbol for the given DWARF location.  */
 
 static void
-write_optimized_local_variable_loc (dw_loc_descr_ref expr, rtx range_start,
+write_optimized_local_variable_loc (dw_loc_descr_ref expr,
+                                   dw_loc_descr_ref fbloc, rtx range_start,
                                    rtx range_end)
 {
   if (expr->dw_loc_next)
@@ -2462,6 +2566,10 @@ write_optimized_local_variable_loc (dw_loc_descr_ref 
expr, rtx range_start,
       write_defrange_register (expr, range_start, range_end);
       break;
 
+    case DW_OP_fbreg:
+      write_defrange_register_rel (expr, fbloc, range_start, range_end);
+      break;
+
     default:
       break;
     }
@@ -2473,7 +2581,8 @@ write_optimized_local_variable_loc (dw_loc_descr_ref 
expr, rtx range_start,
    place for the whole block we need to write an S_LOCAL.  */
 
 static void
-write_optimized_local_variable (dw_die_ref die, rtx block_start, rtx block_end)
+write_optimized_local_variable (dw_die_ref die, dw_loc_descr_ref fbloc,
+                               rtx block_start, rtx block_end)
 {
   dw_attr_node *loc;
   dw_loc_list_ref loc_list;
@@ -2499,8 +2608,8 @@ write_optimized_local_variable (dw_die_ref die, rtx 
block_start, rtx block_end)
          if (loc_list->end)
            range_end = gen_rtx_SYMBOL_REF (Pmode, loc_list->end);
 
-         write_optimized_local_variable_loc (loc_list->expr, range_start,
-                                             range_end);
+         write_optimized_local_variable_loc (loc_list->expr, fbloc,
+                                             range_start, range_end);
 
          loc_list = loc_list->dw_loc_next;
        }
@@ -2509,7 +2618,7 @@ write_optimized_local_variable (dw_die_ref die, rtx 
block_start, rtx block_end)
     case dw_val_class_loc:
       write_s_local (die);
 
-      write_optimized_local_variable_loc (loc->dw_attr_val.v.val_loc,
+      write_optimized_local_variable_loc (loc->dw_attr_val.v.val_loc, fbloc,
                                          block_start, block_end);
       break;
 
@@ -2763,7 +2872,8 @@ write_unoptimized_function_vars (dw_die_ref die, 
dw_loc_descr_ref fbloc)
    locations, so some degree of "optimized out"s is inevitable.  */
 
 static void
-write_optimized_function_vars (dw_die_ref die,  rtx block_start, rtx block_end)
+write_optimized_function_vars (dw_die_ref die, dw_loc_descr_ref fbloc,
+                              rtx block_start, rtx block_end)
 {
   dw_die_ref first_child, c;
 
@@ -2781,7 +2891,7 @@ write_optimized_function_vars (dw_die_ref die,  rtx 
block_start, rtx block_end)
       {
       case DW_TAG_formal_parameter:
       case DW_TAG_variable:
-       write_optimized_local_variable (c, block_start, block_end);
+       write_optimized_local_variable (c, fbloc, block_start, block_end);
        break;
 
       case DW_TAG_lexical_block:
@@ -2816,7 +2926,7 @@ write_optimized_function_vars (dw_die_ref die,  rtx 
block_start, rtx block_end)
 
          rtx_high = gen_rtx_SYMBOL_REF (Pmode, label_high);
 
-         write_optimized_function_vars (c, rtx_low, rtx_high);
+         write_optimized_function_vars (c, fbloc, rtx_low, rtx_high);
 
          break;
        }
@@ -2960,7 +3070,7 @@ write_function (codeview_symbol *s)
     fbloc = frame_base->dw_attr_val.v.val_loc;
 
   if (flag_var_tracking)
-    write_optimized_function_vars (s->function.die, rtx_low, rtx_high);
+    write_optimized_function_vars (s->function.die, fbloc, rtx_low, rtx_high);
   else
     write_unoptimized_function_vars (s->function.die, fbloc);
 
-- 
2.44.2

Reply via email to