diff mbox series

[01/11] Output CodeView data about variables

Message ID 20240618001713.24034-2-mark@harmstone.com
State New
Headers show
Series CodeView variables and type system | expand

Commit Message

Mark Harmstone June 18, 2024, 12:17 a.m. UTC
Parse the DW_TAG_variable DIEs, and outputs S_GDATA32 (for global variables)
and S_LDATA32 (static global variables) symbols into the .debug$S section.

    gcc/
            * dwarf2codeview.cc (S_LDATA32, S_GDATA32): Define.
            (struct codeview_symbol): New structure.
            (sym, last_sym): New variables.
            (write_data_symbol): New function.
            (write_codeview_symbols): Call write_data_symbol.
            (add_variable, codeview_debug_early_finish): New functions.
            * dwarf2codeview.h (codeview_debug_early_finish): Prototype.
            * dwarf2out.cc
            (dwarf2out_early_finish): Call codeview_debug_early_finish.
---
 gcc/dwarf2codeview.cc | 160 ++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2codeview.h  |   1 +
 gcc/dwarf2out.cc      |   5 ++
 3 files changed, 166 insertions(+)

Comments

Jeff Law June 23, 2024, 11:50 p.m. UTC | #1
On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Parse the DW_TAG_variable DIEs, and outputs S_GDATA32 (for global variables)
> and S_LDATA32 (static global variables) symbols into the .debug$S section.
> 
>      gcc/
>              * dwarf2codeview.cc (S_LDATA32, S_GDATA32): Define.
>              (struct codeview_symbol): New structure.
>              (sym, last_sym): New variables.
>              (write_data_symbol): New function.
>              (write_codeview_symbols): Call write_data_symbol.
>              (add_variable, codeview_debug_early_finish): New functions.
>              * dwarf2codeview.h (codeview_debug_early_finish): Prototype.
>              * dwarf2out.cc
>              (dwarf2out_early_finish): Call codeview_debug_early_finish.
Thanks.  I've pushed this to the trunk.

Just one question.  I note you use #defines for the various constants. 
Any reason not to use a const object?  At least with those you can print 
them in a debugger rather than having to look them up in the source code.

Just a thought.  Naturally I'll be working my way through the rest of 
this kit.

jeff
diff mbox series

Patch

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index db776d79be4..60e84635971 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -46,6 +46,8 @@  along with GCC; see the file COPYING3.  If not see
 
 #define CHKSUM_TYPE_MD5		1
 
+#define S_LDATA32		0x110c
+#define S_GDATA32		0x110d
 #define S_COMPILE3		0x113c
 
 #define CV_CFL_80386		0x03
@@ -129,6 +131,22 @@  struct codeview_function
   codeview_line_block *blocks, *last_block;
 };
 
+struct codeview_symbol
+{
+  codeview_symbol *next;
+  uint16_t kind;
+
+  union
+  {
+    struct
+    {
+      uint32_t type;
+      char *name;
+      dw_die_ref die;
+    } data_symbol;
+  };
+};
+
 static unsigned int line_label_num;
 static unsigned int func_label_num;
 static unsigned int sym_label_num;
@@ -140,6 +158,7 @@  static codeview_string *strings, *last_string;
 static codeview_function *funcs, *last_func;
 static const char* last_filename;
 static uint32_t last_file_id;
+static codeview_symbol *sym, *last_sym;
 
 /* Record new line number against the current function.  */
 
@@ -698,6 +717,77 @@  write_compile3_symbol (void)
   targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
 }
 
+/* Write an S_GDATA32 symbol, representing a global variable, or an S_LDATA32
+   symbol, for a static global variable.  */
+
+static void
+write_data_symbol (codeview_symbol *s)
+{
+  unsigned int label_num = ++sym_label_num;
+  dw_attr_node *loc;
+  dw_loc_descr_ref loc_ref;
+
+  /* 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;
+  */
+
+  /* Extract the DW_AT_location attribute from the DIE, and make sure it's in
+     in a format we can parse.  */
+
+  loc = get_AT (s->data_symbol.die, DW_AT_location);
+  if (!loc)
+    goto end;
+
+  if (loc->dw_attr_val.val_class != dw_val_class_loc)
+    goto end;
+
+  loc_ref = loc->dw_attr_val.v.val_loc;
+  if (!loc_ref || loc_ref->dw_loc_opc != DW_OP_addr)
+    goto end;
+
+  /* Output the S_GDATA32 / S_LDATA32 record.  */
+
+  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->kind);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, s->data_symbol.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, s->data_symbol.name,
+		    strlen (s->data_symbol.name) + 1);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+
+end:
+  free (s->data_symbol.name);
+}
+
 /* Write the CodeView symbols into the .debug$S section.  */
 
 static void
@@ -714,6 +804,22 @@  write_codeview_symbols (void)
 
   write_compile3_symbol ();
 
+  while (sym)
+    {
+      codeview_symbol *n = sym->next;
+
+      switch (sym->kind)
+	{
+	case S_LDATA32:
+	case S_GDATA32:
+	  write_data_symbol (sym);
+	  break;
+	}
+
+      free (sym);
+      sym = n;
+    }
+
   asm_fprintf (asm_out_file, "%LLcv_syms_end:\n");
 }
 
@@ -734,4 +840,58 @@  codeview_debug_finish (void)
   write_codeview_symbols ();
 }
 
+/* Process a DW_TAG_variable DIE, and add an S_GDATA32 or S_LDATA32 symbol for
+   this.  */
+
+static void
+add_variable (dw_die_ref die)
+{
+  codeview_symbol *s;
+  const char *name;
+
+  name = get_AT_string (die, DW_AT_name);
+  if (!name)
+    return;
+
+  s = (codeview_symbol *) xmalloc (sizeof (codeview_symbol));
+
+  s->next = NULL;
+  s->kind = get_AT (die, DW_AT_external) ? S_GDATA32 : S_LDATA32;
+  s->data_symbol.type = 0;
+  s->data_symbol.name = xstrdup (name);
+  s->data_symbol.die = die;
+
+  if (last_sym)
+    last_sym->next = s;
+  else
+    sym = s;
+
+  last_sym = s;
+}
+
+/* Loop through the DIEs that have been output for our TU, and add CodeView
+   symbols for them.  */
+
+void
+codeview_debug_early_finish (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
+    {
+      if (dw_get_die_tag (c) == DW_TAG_variable)
+	add_variable (c);
+
+      c = dw_get_die_sib (c);
+    }
+  while (c != first_child);
+}
+
 #endif
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index b6421b62d2e..ac4c2fd21c2 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -30,5 +30,6 @@  extern void codeview_source_line (unsigned int, const char *);
 extern void codeview_start_source_file (const char *);
 extern void codeview_switch_text_section ();
 extern void codeview_end_epilogue (void);
+extern void codeview_debug_early_finish (dw_die_ref die);
 
 #endif /* GCC_DWARF2CODEVIEW_H */
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 5b064ffd78a..f6939b60077 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -33208,6 +33208,11 @@  dwarf2out_early_finish (const char *filename)
       ctf_debug_early_finish (filename);
     }
 
+#ifdef CODEVIEW_DEBUGGING_INFO
+  if (codeview_debuginfo_p ())
+    codeview_debug_early_finish (comp_unit_die ());
+#endif
+
   /* Do not generate DWARF assembler now when not producing LTO bytecode.  */
   if ((!flag_generate_lto && !flag_generate_offload)
       /* FIXME: Disable debug info generation for (PE-)COFF targets since the