https://gcc.gnu.org/g:65b5c4afcfd439e7897b88f6c27d4a33a4c9c124

commit r15-5825-g65b5c4afcfd439e7897b88f6c27d4a33a4c9c124
Author: Mark Harmstone <m...@harmstone.com>
Date:   Tue Nov 19 00:55:25 2024 +0000

    Write S_INLINEELINES CodeView subsection
    
    When outputting the .debug$S CodeView section, also write an
    S_INLINEELINES subsection, which records the filename and line number of
    the start of each inlined function.
    
    gcc/
            * dwarf2codeview.cc (DEBUG_S_INLINEELINES): Define.
            (CV_INLINEE_SOURCE_LINE_SIGNATURE): Define.
            (struct codeview_inlinee_lines): Define.
            (struct inlinee_lines_hasher): Define.
            (func_htab, inlinee_lines_htab): New global variables.
            (get_file_id): New function.
            (codeview_source_line): Move file_id logic to get_file_id.
            (write_inlinee_lines_entry): New function.
            (write_inlinee_lines): New function.
            (codeview_debug_finish): Call write_inlinee_lines, and free 
func_htab
            and inlinee_lines_htab.
            (get_func_id): New function.
            (add_function): Move func_id logic to get_func_id.
            (codeview_abstract_function): New function.
            * dwarf2codeview.h (codeview_abstract_function): Add declaration.
            * dwarf2out.cc (dwarf2out_abstract_function): Call
            codeview_abstract_function if outputting CodeView debug info.

Diff:
---
 gcc/dwarf2codeview.cc | 251 +++++++++++++++++++++++++++++++++++++++++++-------
 gcc/dwarf2codeview.h  |   1 +
 gcc/dwarf2out.cc      |   5 +
 3 files changed, 224 insertions(+), 33 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 63ac5356427a..18a75135352c 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #define DEBUG_S_LINES          0xf2
 #define DEBUG_S_STRINGTABLE     0xf3
 #define DEBUG_S_FILECHKSMS      0xf4
+#define DEBUG_S_INLINEELINES   0xf6
 
 #define CHKSUM_TYPE_MD5                1
 
@@ -53,6 +54,8 @@ along with GCC; see the file COPYING3.  If not see
 #define CV_CFL_C               0x00
 #define CV_CFL_CXX             0x01
 
+#define CV_INLINEE_SOURCE_LINE_SIGNATURE       0x0
+
 #define FIRST_TYPE             0x1000
 
 #define LINE_LABEL     "Lcvline"
@@ -1141,6 +1144,14 @@ struct codeview_line_block
   codeview_line *lines, *last_line;
 };
 
+struct codeview_inlinee_lines
+{
+  codeview_inlinee_lines *next;
+  uint32_t func_id;
+  uint32_t file_id;
+  uint32_t starting_line;
+};
+
 struct codeview_function
 {
   codeview_function *next;
@@ -1417,6 +1428,21 @@ struct method_hasher : nofree_ptr_hash <struct 
codeview_method>
   }
 };
 
+struct inlinee_lines_hasher : free_ptr_hash <struct codeview_inlinee_lines>
+{
+  typedef uint32_t compare_type;
+
+  static hashval_t hash (const codeview_inlinee_lines *il)
+  {
+    return il->func_id;
+  }
+
+  static bool equal (const codeview_inlinee_lines *il, uint32_t func_id)
+  {
+    return il->func_id == func_id;
+  }
+};
+
 static unsigned int line_label_num;
 static unsigned int func_label_num;
 static unsigned int sym_label_num;
@@ -1429,10 +1455,11 @@ static codeview_function *funcs, *last_func, *cur_func;
 static const char* last_filename;
 static uint32_t last_file_id;
 static codeview_symbol *sym, *last_sym;
-static hash_table<die_hasher> *types_htab;
+static hash_table<die_hasher> *types_htab, *func_htab;
 static codeview_custom_type *custom_types, *last_custom_type;
 static codeview_deferred_type *deferred_types, *last_deferred_type;
 static hash_table<string_id_hasher> *string_id_htab;
+static hash_table<inlinee_lines_hasher> *inlinee_lines_htab;
 
 static uint32_t get_type_num (dw_die_ref type, bool in_struct, bool 
no_fwd_ref);
 static uint32_t get_type_num_subroutine_type (dw_die_ref type, bool in_struct,
@@ -1442,6 +1469,39 @@ static uint32_t get_type_num_subroutine_type (dw_die_ref 
type, bool in_struct,
 static void write_cv_padding (size_t padding);
 static void flush_deferred_types (void);
 
+/* Return the file ID corresponding to a given source filename.  */
+
+static uint32_t
+get_file_id (const char *filename)
+{
+  codeview_source_file *sf = files;
+
+  if (filename == last_filename)
+    return last_file_id;
+
+  while (sf)
+    {
+      if (!strcmp (sf->filename, filename))
+       {
+         uint32_t file_id;
+
+         /* 0x18 is the size of the checksum entry for each file.
+            0x6 bytes for the header, plus 0x10 bytes for the hash,
+            then padded to a multiple of 4.  */
+
+         file_id = sf->file_num * 0x18;
+         last_filename = filename;
+         last_file_id = file_id;
+
+         return file_id;
+       }
+
+      sf = sf->next;
+    }
+
+  return 0;
+}
+
 /* Allocate and initialize a codeview_function struct.  */
 
 static codeview_function *
@@ -1472,7 +1532,7 @@ void
 codeview_source_line (unsigned int line_no, const char *filename)
 {
   codeview_line *l;
-  uint32_t file_id = last_file_id;
+  uint32_t file_id = get_file_id (filename);
   unsigned int label_num = ++line_label_num;
 
   targetm.asm_out.internal_label (asm_out_file, LINE_LABEL, label_num);
@@ -1486,28 +1546,6 @@ codeview_source_line (unsigned int line_no, const char 
*filename)
       cur_func = f;
     }
 
-  if (filename != last_filename)
-    {
-      codeview_source_file *sf = files;
-
-      while (sf)
-       {
-         if (!strcmp (sf->filename, filename))
-           {
-             /* 0x18 is the size of the checksum entry for each file.
-                0x6 bytes for the header, plus 0x10 bytes for the hash,
-                then padded to a multiple of 4.  */
-
-             file_id = sf->file_num * 0x18;
-             last_filename = filename;
-             last_file_id = file_id;
-             break;
-           }
-
-         sf = sf->next;
-       }
-    }
-
   if (!cur_func->last_block || cur_func->last_block->file_id != file_id)
     {
       codeview_line_block *b;
@@ -1906,6 +1944,66 @@ write_line_numbers (void)
     }
 }
 
+/* Write an entry in the S_INLINEELINES subsection of .debug$S.  */
+
+static int
+write_inlinee_lines_entry (codeview_inlinee_lines **slot,
+                          void *ctx ATTRIBUTE_UNUSED)
+{
+  codeview_inlinee_lines *il = *slot;
+
+  /* The inlinee lines data consists of a version uint32_t (0), followed by
+     an array of struct inlinee_source_line:
+
+      struct inlinee_source_line
+      {
+         uint32_t function_id;
+         uint32_t file_id;
+         uint32_t line_no;
+      };
+
+    (see InlineeSourceLine in cvinfo.h)
+  */
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, il->func_id);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, il->file_id);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, il->starting_line);
+  putc ('\n', asm_out_file);
+
+  return 1;
+}
+
+/* Write the S_INLINEELINES subsection of .debug$S, which lists the filename
+   and line number for the start of each inlined function.  */
+
+static void
+write_inlinee_lines (void)
+{
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, DEBUG_S_INLINEELINES);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  asm_fprintf (asm_out_file,
+              "%LLcv_inlineelines_end - %LLcv_inlineelines_start\n");
+  asm_fprintf (asm_out_file, "%LLcv_inlineelines_start:\n");
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, CV_INLINEE_SOURCE_LINE_SIGNATURE);
+  putc ('\n', asm_out_file);
+
+  inlinee_lines_htab->traverse <void*, write_inlinee_lines_entry> (NULL);
+
+  asm_fprintf (asm_out_file, "%LLcv_inlineelines_end:\n");
+}
+
 /* Treat cold sections as separate functions, for the purposes of line
    numbers.  */
 
@@ -4755,6 +4853,10 @@ codeview_debug_finish (void)
   write_strings_table ();
   write_source_files ();
   write_line_numbers ();
+
+  if (inlinee_lines_htab)
+    write_inlinee_lines ();
+
   write_codeview_symbols ();
 
   /* If we reference a nested struct but not its parent, add_deferred_type
@@ -4793,8 +4895,14 @@ codeview_debug_finish (void)
   if (types_htab)
     delete types_htab;
 
+  if (func_htab)
+    delete func_htab;
+
   if (string_id_htab)
     delete string_id_htab;
+
+  if (inlinee_lines_htab)
+    delete inlinee_lines_htab;
 }
 
 /* Translate a DWARF base type (DW_TAG_base_type) into its CodeView
@@ -6714,20 +6822,29 @@ add_lf_mfunc_id (dw_die_ref die, const char *name)
   return ct->num;
 }
 
-/* Process a DW_TAG_subprogram DIE, and add an S_GPROC32_ID or S_LPROC32_ID
-   symbol for this.  */
+/* Generate a new LF_FUNC_ID or LF_MFUNC_ID type for a DW_TAG_subprogram DIE
+   and return its number, or return the existing type number if already
+   present.  */
 
-static void
-add_function (dw_die_ref die)
+static uint32_t
+get_func_id (dw_die_ref die)
 {
   const char *name = get_AT_string (die, DW_AT_name);
-  uint32_t func_id_type;
-  codeview_symbol *s;
   dw_die_ref spec = get_AT_ref (die, DW_AT_specification);
   bool do_mfunc_id = false;
+  codeview_type **slot, *t;
+  uint32_t num;
 
   if (!name)
-    return;
+    return 0;
+
+  if (!func_htab)
+    func_htab = new hash_table<die_hasher> (10);
+
+  slot = func_htab->find_slot_with_hash (die, htab_hash_pointer (die), INSERT);
+
+  if (slot && *slot)
+    return (*slot)->num;
 
   if (spec && dw_get_die_parent (spec))
     {
@@ -6745,9 +6862,33 @@ add_function (dw_die_ref die)
     }
 
   if (do_mfunc_id)
-    func_id_type = add_lf_mfunc_id (die, name);
+    num = add_lf_mfunc_id (die, name);
   else
-    func_id_type = add_lf_func_id (die, name);
+    num = add_lf_func_id (die, name);
+
+  t = (codeview_type *) xmalloc (sizeof (codeview_type));
+
+  t->die = die;
+  t->num = num;
+  t->is_fwd_ref = false;
+
+  *slot = t;
+
+  return num;
+}
+
+/* Process a DW_TAG_subprogram DIE, and add an S_GPROC32_ID or S_LPROC32_ID
+   symbol for this.  */
+
+static void
+add_function (dw_die_ref die)
+{
+  uint32_t func_id_type;
+  codeview_symbol *s;
+
+  func_id_type = get_func_id (die);
+  if (func_id_type == 0)
+    return;
 
   /* Add an S_GPROC32_ID / S_LPROC32_ID symbol.  */
 
@@ -6771,6 +6912,50 @@ add_function (dw_die_ref die)
   last_sym = s;
 }
 
+/* If we have encountered a new inlined function, add this to
+   inlinee_lines_htab so that it can be output to the S_INLINEELINES subsection
+   of .debug$S.  */
+
+void
+codeview_abstract_function (tree decl)
+{
+  codeview_inlinee_lines *il, **slot;
+  dw_die_ref die;
+  uint32_t func_id;
+  struct dwarf_file_data *file;
+
+  if (!DECL_DECLARED_INLINE_P (decl))
+    return;
+
+  die = lookup_decl_die (decl);
+  if (!die)
+    return;
+
+  func_id = get_func_id (die);
+  if (func_id == 0)
+    return;
+
+  file = get_AT_file (die, DW_AT_decl_file);
+  if (!file)
+    return;
+
+  if (!inlinee_lines_htab)
+    inlinee_lines_htab = new hash_table<inlinee_lines_hasher> (10);
+
+  slot = inlinee_lines_htab->find_slot_with_hash (func_id, func_id, INSERT);
+  if (*slot)
+    return;
+
+  il = (codeview_inlinee_lines *) xmalloc (sizeof (codeview_inlinee_lines));
+
+  il->next = NULL;
+  il->func_id = func_id;
+  il->file_id = get_file_id (file->filename);
+  il->starting_line = get_AT_unsigned (die, DW_AT_decl_line);
+
+  *slot = il;
+}
+
 /* Loop through the DIEs that have been output for our TU, and add CodeView
    symbols for them.  */
 
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index 367334d68cbf..3829bab093dd 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -97,5 +97,6 @@ extern void codeview_end_epilogue (void);
 extern void codeview_debug_early_finish (dw_die_ref die);
 extern void codeview_begin_block (unsigned int, unsigned int, tree);
 extern void codeview_end_block (unsigned int, unsigned int);
+extern void codeview_abstract_function (tree);
 
 #endif /* GCC_DWARF2CODEVIEW_H */
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index e913c52fd626..1ee2ee57821b 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -23408,6 +23408,11 @@ dwarf2out_abstract_function (tree decl)
   if (DECL_IGNORED_P (decl))
     return;
 
+#ifdef CODEVIEW_DEBUGGING_INFO
+  if (codeview_debuginfo_p ())
+    codeview_abstract_function (decl);
+#endif
+
   /* In LTO we're all set.  We already created abstract instances
      early and we want to avoid creating a concrete instance of that
      if we don't output it.  */

Reply via email to