diff mbox series

[1/3] Write CodeView information about local static variables

Message ID 20240813002426.5453-1-mark@harmstone.com
State New
Headers show
Series [1/3] Write CodeView information about local static variables | expand

Commit Message

Mark Harmstone Aug. 13, 2024, 12:24 a.m. UTC
Outputs CodeView S_LDATA32 symbols, for static variables within
functions, along with S_BLOCK32 and S_END for the beginning and end of
lexical blocks.

gcc/
	* dwarf2codeview.cc (enum cv_sym_type): Add S_END and S_BLOCK32.
	(write_local_s_ldata32): New function.
	(write_unoptimized_local_variable): New function.
	(write_s_block32): New function.
	(write_s_end): New function.
	(write_unoptimized_function_vars): New function.
	(write_function): Call write_unoptimized_function_vars.
---
 gcc/dwarf2codeview.cc | 258 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 258 insertions(+)

Comments

Jeff Law Aug. 14, 2024, 4:09 a.m. UTC | #1
On 8/12/24 6:24 PM, Mark Harmstone wrote:
> Outputs CodeView S_LDATA32 symbols, for static variables within
> functions, along with S_BLOCK32 and S_END for the beginning and end of
> lexical blocks.
> 
> gcc/
> 	* dwarf2codeview.cc (enum cv_sym_type): Add S_END and S_BLOCK32.
> 	(write_local_s_ldata32): New function.
> 	(write_unoptimized_local_variable): New function.
> 	(write_s_block32): New function.
> 	(write_s_end): New function.
> 	(write_unoptimized_function_vars): New function.
> 	(write_function): Call write_unoptimized_function_vars.
This series is fine.  I'm not particularly jazzed about how much target 
specific data shows up in patch #2.  It's probably safe to assume the 
mapping of register number of the codeview number doesn't match the 
dwarf map.  It's probably also safe to assume we're not supporting 
codeview on any targets other than x86 and ix86?

jeff
Mark Harmstone Aug. 16, 2024, 8:50 p.m. UTC | #2
Thanks Jeff. No, CodeView is effectively Windows-specific - it relies on PE for reporting the PDB filename, and COFF for the .secidx relocation. I might look into moving these bits into the config once I get down to plumbing it for aarch64-w64-mingw32.

Mark

On 14/08/2024 05:09, Jeff Law wrote:
> 
> 
> On 8/12/24 6:24 PM, Mark Harmstone wrote:
>> Outputs CodeView S_LDATA32 symbols, for static variables within
>> functions, along with S_BLOCK32 and S_END for the beginning and end of
>> lexical blocks.
>>
>> gcc/
>>     * dwarf2codeview.cc (enum cv_sym_type): Add S_END and S_BLOCK32.
>>     (write_local_s_ldata32): New function.
>>     (write_unoptimized_local_variable): New function.
>>     (write_s_block32): New function.
>>     (write_s_end): New function.
>>     (write_unoptimized_function_vars): New function.
>>     (write_function): Call write_unoptimized_function_vars.
> This series is fine.  I'm not particularly jazzed about how much target specific data shows up in patch #2.  It's probably safe to assume the mapping of register number of the codeview number doesn't match the dwarf map.  It's probably also safe to assume we're not supporting codeview on any targets other than x86 and ix86?
> 
> jeff
diff mbox series

Patch

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 7e4faaa9388..cb2d64bfcc6 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -70,6 +70,8 @@  along with GCC; see the file COPYING3.  If not see
 /* This is enum SYM_ENUM_e in Microsoft's cvinfo.h.  */
 
 enum cv_sym_type {
+  S_END = 0x0006,
+  S_BLOCK32 = 0x1103,
   S_LDATA32 = 0x110c,
   S_GDATA32 = 0x110d,
   S_COMPILE3 = 0x113c,
@@ -986,6 +988,260 @@  end:
   free (s->data_symbol.name);
 }
 
+/* Write an S_LDATA32 symbol, representing a static variable within a function.
+   This symbol can also appear outside of a function block - see
+   write_data_symbol.  */
+
+static void
+write_local_s_ldata32 (dw_die_ref die, dw_loc_descr_ref loc_ref)
+{
+  unsigned int label_num = ++sym_label_num;
+  const char *name = get_AT_string (die, DW_AT_name);
+  uint32_t type;
+
+  /* This is struct datasym in binutils:
+
+      struct datasym
+      {
+	uint16_t size;
+	uint16_t kind;
+	uint32_t type;
+	uint32_t offset;
+	uint16_t section;
+	char name[];
+      } ATTRIBUTE_PACKED;
+  */
+
+  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_LDATA32);
+  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);
+
+  asm_fprintf (asm_out_file, "\t.secrel32 ");
+  output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr);
+  fputc ('\n', asm_out_file);
+
+  asm_fprintf (asm_out_file, "\t.secidx ");
+  output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr);
+  fputc ('\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)
+{
+  dw_attr_node *loc;
+  dw_loc_descr_ref loc_ref;
+
+  loc = get_AT (die, DW_AT_location);
+  if (!loc)
+    return;
+
+  if (loc->dw_attr_val.val_class != dw_val_class_loc)
+    return;
+
+  loc_ref = loc->dw_attr_val.v.val_loc;
+  if (!loc_ref)
+    return;
+
+  switch (loc_ref->dw_loc_opc)
+    {
+    case DW_OP_addr:
+      write_local_s_ldata32 (die, loc_ref);
+      break;
+
+    default:
+      break;
+    }
+}
+
+/* Translate a DW_TAG_lexical_block DIE into an S_BLOCK32 symbol, representing
+   a block within an unoptimized function.  Returns false if we're not able
+   to resolve the location, which will prevent the caller from issuing an
+   unneeded S_END.  */
+
+static bool
+write_s_block32 (dw_die_ref die)
+{
+  unsigned int label_num = ++sym_label_num;
+  dw_attr_node *loc_low, *loc_high;
+  const char *label_low, *label_high;
+  rtx rtx_low, rtx_high;
+
+  /* This is struct blocksym in binutils and BLOCKSYM32 in Microsoft's
+     cvinfo.h:
+
+    struct blocksym
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t parent;
+      uint32_t end;
+      uint32_t len;
+      uint32_t offset;
+      uint16_t section;
+      char name[];
+    } ATTRIBUTE_PACKED;
+  */
+
+  loc_low = get_AT (die, DW_AT_low_pc);
+  if (!loc_low)
+    return false;
+
+  if (loc_low->dw_attr_val.val_class != dw_val_class_lbl_id)
+    return false;
+
+  label_low = loc_low->dw_attr_val.v.val_lbl_id;
+  if (!label_low)
+    return false;
+
+  rtx_low = gen_rtx_SYMBOL_REF (Pmode, label_low);
+
+  loc_high = get_AT (die, DW_AT_high_pc);
+  if (!loc_high)
+    return false;
+
+  if (loc_high->dw_attr_val.val_class != dw_val_class_high_pc)
+    return false;
+
+  label_high = loc_high->dw_attr_val.v.val_lbl_id;
+  if (!label_high)
+    return false;
+
+  rtx_high = gen_rtx_SYMBOL_REF (Pmode, label_high);
+
+  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_BLOCK32);
+  putc ('\n', asm_out_file);
+
+  /* The parent and end fields get filled in by the linker.  */
+
+  fputs (integer_asm_op (4, 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, 0);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  output_addr_const (asm_out_file, rtx_high);
+  fputs (" - ", asm_out_file);
+  output_addr_const (asm_out_file, rtx_low);
+  putc ('\n', asm_out_file);
+
+  asm_fprintf (asm_out_file, "\t.secrel32 ");
+  output_addr_const (asm_out_file, rtx_low);
+  fputc ('\n', asm_out_file);
+
+  asm_fprintf (asm_out_file, "\t.secidx ");
+  output_addr_const (asm_out_file, rtx_low);
+  fputc ('\n', asm_out_file);
+
+  ASM_OUTPUT_ASCII (asm_out_file, "", 1);
+
+  ASM_OUTPUT_ALIGN (asm_out_file, 2);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+
+  return true;
+}
+
+/* Write an S_END symbol, which is used to finish off a number of different
+   symbol types.  Here we use it to mark the S_BLOCK32 as finished.  */
+
+static void
+write_s_end (void)
+{
+  unsigned int label_num = ++sym_label_num;
+
+  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_END);
+  putc ('\n', asm_out_file);
+
+  ASM_OUTPUT_ALIGN (asm_out_file, 2);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+}
+
+/* Loop through the DIEs in an unoptimized function, writing out any variables
+   or blocks that we encounter.  */
+
+static void
+write_unoptimized_function_vars (dw_die_ref die)
+{
+  dw_die_ref first_child, c;
+
+  first_child = dw_get_die_child (die);
+
+  if (!first_child)
+    return;
+
+  c = first_child;
+  do
+  {
+    c = dw_get_die_sib (c);
+
+    switch (dw_get_die_tag (c))
+      {
+      case DW_TAG_variable:
+	write_unoptimized_local_variable (c);
+	break;
+
+      case DW_TAG_lexical_block:
+	{
+	  bool block_started = write_s_block32 (c);
+
+	  write_unoptimized_function_vars (c);
+
+	  if (block_started)
+	    write_s_end ();
+
+	  break;
+	}
+
+      default:
+	break;
+      }
+  }
+  while (c != first_child);
+}
+
 /* Write an S_GPROC32_ID symbol, representing a global function, or an
    S_LPROC32_ID symbol, for a static function.  */
 
@@ -1111,6 +1367,8 @@  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);
+
   /* Output the S_PROC_ID_END record.  */
 
   label_num = ++sym_label_num;