public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v2 0/6] btf: refactor and add pruning option
@ 2024-05-02 17:11 David Faust
  2024-05-02 17:11 ` [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission David Faust
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: David Faust @ 2024-05-02 17:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: indu.bhagat, jose.marchesi, cupertino.miranda

[Changes from v1: Fix missing btfout.cc changes in patch 3 which
 prevent the patch from building as reported by Linaro CI.  Those
 changes are then removed/overwritten in patch 4, so the resulting
 code before patch 3 and after patch 4 is identical to v1. ]

This patch series signficantly refactors the BTF generation in gcc,
making it simpler and easier to understand, extend and maintain.

It also introduces an optional algorithm to "prune" BTF information
before emission.  This pruning is meant to be used for BPF programs,
to alleviate the massive bloating of BPF progams caused by including
Linux kernel internal headers.  The pruning is designed to be almost
equivalent to that performed unconditionally by the LLVM BPF backend
when generating BTF information, for compatibility purposes.

While the changes are fairly significant, there is very little actual
change in emitted BTF information (unless pruning is enabled), other
than bug fixes and additions to the assembler debug comments.

Patch 1 restructures the emission of CTF and BTF information, with the
result that CTF is always completely generated and emitted before any
BTF-related procedures are run.

Patch 2 takes advantage of that change, and removes the restriction on
generating both CTF and BTF in the same compiler run, allowing for any
combinaion of -gdwarf, -gctf and -gbtf.

Patch 3 changes the data structures shared by CTF and BTF to use
pointers rather than type IDs for all inter-type references.  This
change is completely transparent to both CTF and BTF.

Patch 4 heavily refactors btfout.cc to take advantage of the prior
changes and significantly simplify the BTF implementation.  The changes
are nearly transparent, however some small but important improvements
are also made possible by the refactor, such as fixing PR113566.

Patch 5 adds a new option to perform pruning of the BTF information
before emission.  This is intended to be used for BPF programs which
often include kernel headers, and in many cases reduces the size of
the resulting BTF information by a factor of 10.

Patch 6 makes BTF pruning work with BPF CO-RE, and enables the pruning
by default in the BPF backend.

Tested on x86_64-linux-gnu, and on x86_64-linux-gnu host for
bpf-unknown-none target.

Also heavily tested with Linux kernel BPF selftests.
No known regressions.

David Faust (6):
  ctf, btf: restructure CTF/BTF emission
  opts: allow any combination of DWARF, CTF, BTF
  ctf: use pointers instead of IDs internally
  btf: refactor and simplify implementation
  btf: add -fprune-btf option
  bpf,btf: enable BTF pruning by default for BPF

 gcc/btfout.cc                                 | 1645 ++++++++++-------
 gcc/common.opt                                |    4 +
 gcc/config/bpf/bpf.cc                         |    5 +
 gcc/config/bpf/btfext-out.cc                  |   12 +-
 gcc/config/bpf/core-builtins.cc               |   73 +-
 gcc/ctfc.cc                                   |  139 +-
 gcc/ctfc.h                                    |   86 +-
 gcc/ctfout.cc                                 |   19 +-
 gcc/doc/invoke.texi                           |   23 +
 gcc/dwarf2ctf.cc                              |  300 ++-
 gcc/dwarf2ctf.h                               |    2 +-
 gcc/dwarf2out.cc                              |    4 +-
 gcc/opts.cc                                   |   19 +-
 gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c  |   25 +
 gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c  |   33 +
 gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c  |   35 +
 .../gcc.dg/debug/btf/btf-variables-5.c        |    2 +-
 17 files changed, 1399 insertions(+), 1027 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c

-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission
  2024-05-02 17:11 [PATCH v2 0/6] btf: refactor and add pruning option David Faust
@ 2024-05-02 17:11 ` David Faust
  2024-05-03 21:02   ` Indu Bhagat
  2024-05-02 17:11 ` [PATCH v2 2/6] opts: allow any combination of DWARF, CTF, BTF David Faust
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: David Faust @ 2024-05-02 17:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: indu.bhagat, jose.marchesi, cupertino.miranda

This commit makes some structural changes to the CTF/BTF debug info
emission.  In particular:

 a) CTF is new always fully generated and emitted before any
    BTF-related procedures are run.  This means that BTF-related
    functions can change, even irreversibly, the shared in-memory
    representation used by the two formats without issue.

 b) BTF generation has fewer entry points, and is cleanly divided
    into early_finish and finish.

 c) BTF is now always emitted at finish (called from dwarf2out_finish),
    rather than being emitted at early_finish for targets other than
    BPF CO-RE.  Note that this change alone does not alter the contents
    of BTF at all, regardless of whether it would have previously been
    emitted at early_finish or finish.

The changes are transparent to both CTF and BTF emission.

gcc/
	* btfout.cc (btf_init_postprocess): Rename to...
	(btf_early_finish): ...this.
	(btf_output): Rename to...
	(btf_finish): ...this.
	* ctfc.h: Analogous changes.
	* dwarf2ctf.cc (ctf_debug_early_finish): Conditionally call
	btf_early_finish or ctf_finalize as appropriate.
	(ctf_debug_finish): Always call btf_finish here if generating
	BTF info.
	(ctf_debug_finalize, ctf_debug_init_postprocess): Delete.
	* dwarf2out.cc (dwarf2out_early_finish): Remove call to
	ctf_debug_init_postprocess.
---
 gcc/btfout.cc    | 28 +++++++++++++++++++++++++
 gcc/ctfc.h       |  4 ++--
 gcc/dwarf2ctf.cc | 54 +++++++++++-------------------------------------
 gcc/dwarf2out.cc |  2 --
 4 files changed, 42 insertions(+), 46 deletions(-)

diff --git a/gcc/btfout.cc b/gcc/btfout.cc
index 07f066a4706..1b6a9ed811f 100644
--- a/gcc/btfout.cc
+++ b/gcc/btfout.cc
@@ -1491,6 +1491,34 @@ btf_finalize (void)
   tu_ctfc = NULL;
 }
 
+/* Initial entry point of BTF generation, called at early_finish () after
+   CTF information has possibly been output.  Translate all CTF information
+   to BTF, and do any processing that must be done early, such as creating
+   BTF_KIND_FUNC records.  */
+
+void
+btf_early_finish (void)
+{
+  btf_init_postprocess ();
+}
+
+/* Late entry point for BTF generation, called from dwarf2out_finish ().
+   Complete and emit BTF information.  */
+
+void
+btf_finish (const char * filename)
+{
+  btf_output (filename);
+
+  /* If compiling for BPF with CO-RE info, we cannot deallocate until after
+     CO-RE information is created, which happens very late in BPF backend.
+     Therefore, the deallocation (i.e. btf_finalize ()) is delayed until
+     TARGET_ASM_FILE_END for BPF CO-RE.  */
+  if (!btf_with_core_debuginfo_p ())
+    btf_finalize ();
+}
+
+
 /* Traversal function for all BTF_KIND_FUNC type records.  */
 
 bool
diff --git a/gcc/ctfc.h b/gcc/ctfc.h
index fa188bf2f5a..e7bd93901cf 100644
--- a/gcc/ctfc.h
+++ b/gcc/ctfc.h
@@ -384,8 +384,8 @@ extern void ctf_init (void);
 extern void ctf_output (const char * filename);
 extern void ctf_finalize (void);
 
-extern void btf_output (const char * filename);
-extern void btf_init_postprocess (void);
+extern void btf_early_finish (void);
+extern void btf_finish (const char * filename);
 extern void btf_finalize (void);
 
 extern ctf_container_ref ctf_get_tu_ctfc (void);
diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
index dc59569fe56..ec94982e4b1 100644
--- a/gcc/dwarf2ctf.cc
+++ b/gcc/dwarf2ctf.cc
@@ -933,30 +933,6 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
   return type_id;
 }
 
-/* Prepare for output and write out the CTF debug information.  */
-
-static void
-ctf_debug_finalize (const char *filename, bool btf)
-{
-  if (btf)
-    {
-      btf_output (filename);
-      /* btf_finalize when compiling BPF applciations gets deallocated by the
-	 BPF target in bpf_file_end.  */
-      if (btf_debuginfo_p () && !btf_with_core_debuginfo_p ())
-	btf_finalize ();
-    }
-
-  else
-    {
-      /* Emit the collected CTF information.  */
-      ctf_output (filename);
-
-      /* Reset the CTF state.  */
-      ctf_finalize ();
-    }
-}
-
 bool
 ctf_do_die (dw_die_ref die)
 {
@@ -996,27 +972,21 @@ ctf_debug_init (void)
   add_name_attribute (ctf_unknown_die, "unknown");
 }
 
-/* Preprocess the CTF debug information after initialization.  */
-
-void
-ctf_debug_init_postprocess (bool btf)
-{
-  /* Only BTF requires postprocessing right after init.  */
-  if (btf)
-    btf_init_postprocess ();
-}
-
 /* Early finish CTF/BTF debug info.  */
 
 void
 ctf_debug_early_finish (const char * filename)
 {
-  /* Emit CTF debug info early always.  */
-  if (ctf_debug_info_level > CTFINFO_LEVEL_NONE
-      /* Emit BTF debug info early if CO-RE relocations are not
-	 required.  */
-      || (btf_debuginfo_p () && !btf_with_core_debuginfo_p ()))
-    ctf_debug_finalize (filename, btf_debuginfo_p ());
+  /* Emit the collected CTF information.  */
+  if (ctf_debug_info_level > CTFINFO_LEVEL_NONE)
+    ctf_output (filename);
+
+  if (btf_debuginfo_p ())
+    /* If BTF will also be emitted, start translation to BTF.  */
+    btf_early_finish ();
+  else
+    /* Otherwise, done with the CTF container.  */
+    ctf_finalize ();
 }
 
 /* Finish CTF/BTF debug info emission.  */
@@ -1027,8 +997,8 @@ ctf_debug_finish (const char * filename)
   /* Emit BTF debug info here when CO-RE relocations need to be generated.
      BTF with CO-RE relocations needs to be generated when CO-RE is in effect
      for the BPF target.  */
-  if (btf_debuginfo_p () && btf_with_core_debuginfo_p ())
-    ctf_debug_finalize (filename, btf_debuginfo_p ());
+  if (btf_debuginfo_p ())
+    btf_finish (filename);
 }
 
 #include "gt-dwarf2ctf.h"
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 1b0e8b5a5b2..1664934ccc3 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -33168,8 +33168,6 @@ dwarf2out_early_finish (const char *filename)
       ctf_debug_do_cu (comp_unit_die ());
       for (limbo_die_node *node = limbo_die_list; node; node = node->next)
 	ctf_debug_do_cu (node->die);
-      /* Post process the debug data in the CTF container if necessary.  */
-      ctf_debug_init_postprocess (btf_debuginfo_p ());
 
       ctf_debug_early_finish (filename);
     }
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 2/6] opts: allow any combination of DWARF, CTF, BTF
  2024-05-02 17:11 [PATCH v2 0/6] btf: refactor and add pruning option David Faust
  2024-05-02 17:11 ` [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission David Faust
@ 2024-05-02 17:11 ` David Faust
  2024-05-02 17:11 ` [PATCH v2 3/6] ctf: use pointers instead of IDs internally David Faust
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: David Faust @ 2024-05-02 17:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: indu.bhagat, jose.marchesi, cupertino.miranda

Previously it was not supported to generate both CTF and BTF debug info
in the same compiler run, as both formats made incompatible changes to
the same internal data structures.

With the structural change in the prior patch, in particular the
guarantee that CTF will always be fully emitted before any BTF
translation occurs, there is no longer anything preventing generation
of both CTF and BTF at the same time.  This patch changes option parsing
to allow any combination of -gdwarf, -gctf, and -gbtf at the same time.

gcc/
	* opts.cc (set_debug_level): Allow any combination of -gdwarf,
	-gctf and -gbtf at the same time.
---
 gcc/opts.cc | 19 ++++++-------------
 1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/gcc/opts.cc b/gcc/opts.cc
index 3333600e0ea..0a00eb6e2da 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -3488,21 +3488,14 @@ set_debug_level (uint32_t dinfo, int extended, const char *arg,
     }
   else
     {
-      /* Make and retain the choice if both CTF and DWARF debug info are to
-	 be generated.  */
-      if (((dinfo == DWARF2_DEBUG) || (dinfo == CTF_DEBUG))
+      /* Any combination of DWARF, CTF and BTF is allowed together.  */
+      if (((dinfo == DWARF2_DEBUG) || (dinfo == CTF_DEBUG) || (dinfo == BTF_DEBUG))
 	  && ((opts->x_write_symbols == (DWARF2_DEBUG|CTF_DEBUG))
+	      || (opts->x_write_symbols == (DWARF2_DEBUG|BTF_DEBUG))
+	      || (opts->x_write_symbols == (CTF_DEBUG|BTF_DEBUG))
 	      || (opts->x_write_symbols == DWARF2_DEBUG)
-	      || (opts->x_write_symbols == CTF_DEBUG)))
-	{
-	  opts->x_write_symbols |= dinfo;
-	  opts_set->x_write_symbols |= dinfo;
-	}
-      /* However, CTF and BTF are not allowed together at this time.  */
-      else if (((dinfo == DWARF2_DEBUG) || (dinfo == BTF_DEBUG))
-	       && ((opts->x_write_symbols == (DWARF2_DEBUG|BTF_DEBUG))
-		   || (opts->x_write_symbols == DWARF2_DEBUG)
-		   || (opts->x_write_symbols == BTF_DEBUG)))
+	      || (opts->x_write_symbols == CTF_DEBUG)
+	      || (opts->x_write_symbols == BTF_DEBUG)))
 	{
 	  opts->x_write_symbols |= dinfo;
 	  opts_set->x_write_symbols |= dinfo;
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 3/6] ctf: use pointers instead of IDs internally
  2024-05-02 17:11 [PATCH v2 0/6] btf: refactor and add pruning option David Faust
  2024-05-02 17:11 ` [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission David Faust
  2024-05-02 17:11 ` [PATCH v2 2/6] opts: allow any combination of DWARF, CTF, BTF David Faust
@ 2024-05-02 17:11 ` David Faust
  2024-05-03 21:04   ` Indu Bhagat
  2024-05-02 17:11 ` [PATCH v2 4/6] btf: refactor and simplify implementation David Faust
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: David Faust @ 2024-05-02 17:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: indu.bhagat, jose.marchesi, cupertino.miranda

This patch replaces all inter-type references in the ctfc internal data
structures with pointers, rather than the references-by-ID which were
used previously.

A couple of small updates in the BPF backend are included to make it
compatible with the change.

This change is only to the in-memory representation of various CTF
structures to make them easier to work with in various cases.  It is
outwardly transparent; there is no change in emitted CTF.

gcc/
	* btfout.cc (btf_dvd_emit_preprocess_cb, btf_emit_preprocess)
	(btf_dmd_representable_bitfield_p, btf_asm_array, btf_asm_varent)
	(btf_asm_sou_member, btf_asm_func_arg, btf_init_postprocess):
	Adapt to structural changes in ctf_* structs.
	* ctfc.h (struct ctf_dtdef): Add forward declaration.
	(struct ctf_arinfo, struct ctf_funcinfo, struct ctf_sliceinfo)
	(struct ctf_itype, struct ctf_dmdef, struct ctf_func_arg)
	(struct ctf_dvdef): Use pointers instead of type IDs for
	references to other types.
	(struct ctf_dtdef): Add ref_type member.
	(ctf_type_exists): Use pointer instead of type ID.
	(ctf_add_reftype, ctf_add_enum, ctf_add_slice, ctf_add_float)
	(ctf_add_integer, ctf_add_unknown, ctf_add_pointer)
	(ctf_add_array, ctf_add_forward, ctf_add_typedef)
	(ctf_add_function, ctf_add_sou, ctf_add_enumerator)
	(ctf_add_variable): Likewise. Return pointer instead of ID.
	(ctf_lookup_tree_type): Return pointer to type instead of ID.
	* ctfc.cc: Analogous changes.
	* ctfout.cc (ctf_asm_type, ctf_asm_slice, ctf_asm_varent)
	(ctf_asm_sou_lmember, ctf_asm_sou_member, ctf_asm_func_arg)
	(output_ctf_objt_info): Adapt to changes.
	* dwarf2ctf.cc (gen_ctf_type, gen_ctf_void_type)
	(gen_ctf_unknown_type, gen_ctf_base_type, gen_ctf_pointer_type)
	(gen_ctf_subrange_type, gen_ctf_array_type, gen_ctf_typedef)
	(gen_ctf_modifier_type, gen_ctf_sou_type, gen_ctf_function_type)
	(gen_ctf_enumeration_type, gen_ctf_variable, gen_ctf_function)
	(gen_ctf_type, ctf_do_die): Likewise.
	* config/bpf/btfext-out.cc (struct btf_ext_core_reloc): Use
	pointer instead of type ID.
	(bpf_core_reloc_add, bpf_core_get_sou_member_index)
	(output_btfext_core_sections): Adapt to above changes.
	* config/bpf/core-builtins.cc (process_type): Likewise.
---
 gcc/btfout.cc                   |  35 ++---
 gcc/config/bpf/btfext-out.cc    |  12 +-
 gcc/config/bpf/core-builtins.cc |   3 +-
 gcc/ctfc.cc                     | 137 +++++++++---------
 gcc/ctfc.h                      |  61 ++++----
 gcc/ctfout.cc                   |  19 +--
 gcc/dwarf2ctf.cc                | 244 +++++++++++++++-----------------
 7 files changed, 252 insertions(+), 259 deletions(-)

diff --git a/gcc/btfout.cc b/gcc/btfout.cc
index 1b6a9ed811f..14a503a4f80 100644
--- a/gcc/btfout.cc
+++ b/gcc/btfout.cc
@@ -626,7 +626,8 @@ btf_dvd_emit_preprocess_cb (ctf_dvdef_ref *slot, ctf_container_ref arg_ctfc)
     return 1;
 
   /* Do not add variables which refer to unsupported types.  */
-  if (!voids.contains (var->dvd_type) && btf_removed_type_p (var->dvd_type))
+  if (!voids.contains (var->dvd_type->dtd_type)
+      && btf_removed_type_p (var->dvd_type->dtd_type))
     return 1;
 
   arg_ctfc->ctfc_vars_list[num_vars_added] = var;
@@ -716,7 +717,7 @@ btf_emit_preprocess (ctf_container_ref ctfc)
 static bool
 btf_dmd_representable_bitfield_p (ctf_container_ref ctfc, ctf_dmdef_t *dmd)
 {
-  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type];
+  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
 
   if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
     {
@@ -913,8 +914,8 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
 static void
 btf_asm_array (ctf_container_ref ctfc, ctf_arinfo_t arr)
 {
-  btf_asm_type_ref ("bta_elem_type", ctfc, arr.ctr_contents);
-  btf_asm_type_ref ("bta_index_type", ctfc, arr.ctr_index);
+  btf_asm_type_ref ("bta_elem_type", ctfc, arr.ctr_contents->dtd_type);
+  btf_asm_type_ref ("bta_index_type", ctfc, arr.ctr_index->dtd_type);
   dw2_asm_output_data (4, arr.ctr_nelems, "bta_nelems");
 }
 
@@ -927,7 +928,7 @@ btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
 		       (*(btf_var_ids->get (var)) + num_types_added + 1),
 		       var->dvd_name);
   dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_VAR, 0, 0), "btv_info");
-  btf_asm_type_ref ("btv_type", ctfc, var->dvd_type);
+  btf_asm_type_ref ("btv_type", ctfc, var->dvd_type->dtd_type);
   dw2_asm_output_data (4, var->dvd_visibility, "btv_linkage");
 }
 
@@ -937,8 +938,8 @@ btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
 static void
 btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
 {
-  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type];
-  ctf_id_t base_type = dmd->dmd_type;
+  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
+  ctf_id_t base_type = dmd->dmd_type->dtd_type;
   uint64_t sou_offset = dmd->dmd_offset;
 
   dw2_asm_output_data (4, dmd->dmd_name_offset,
@@ -959,7 +960,7 @@ btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
 	  sou_offset |= ((bits & 0xff) << 24);
 
 	  /* Refer to the base type of the slice.  */
-	  base_type = ref_type->dtd_u.dtu_slice.cts_type;
+	  base_type = ref_type->dtd_u.dtu_slice.cts_type->dtd_type;
 	}
       else
 	{
@@ -1003,9 +1004,11 @@ btf_asm_func_arg (ctf_container_ref ctfc, ctf_func_arg_t * farg,
   else
     dw2_asm_output_data (4, 0, "farg_name");
 
-  btf_asm_type_ref ("farg_type", ctfc, (btf_removed_type_p (farg->farg_type)
-					? BTF_VOID_TYPEID
-					: farg->farg_type));
+  ctf_id_t ref_id = BTF_VOID_TYPEID;
+  if (farg->farg_type && !btf_removed_type_p (farg->farg_type->dtd_type))
+    ref_id = farg->farg_type->dtd_type;
+
+  btf_asm_type_ref ("farg_type", ctfc, ref_id);
 }
 
 /* Asm'out a BTF_KIND_FUNC type.  */
@@ -1381,7 +1384,7 @@ btf_init_postprocess (void)
      to create the const modifier type (if needed) now, before making the types
      list.  So we can't avoid iterating with FOR_EACH_VARIABLE here, and then
      again when creating the DATASEC entries.  */
-  ctf_id_t constvoid_id = CTF_NULL_TYPEID;
+  ctf_dtdef_ref constvoid_dtd = NULL;
   varpool_node *var;
   FOR_EACH_VARIABLE (var)
     {
@@ -1400,10 +1403,10 @@ btf_init_postprocess (void)
 	    continue;
 
 	  /* Create the 'const' modifier type for void.  */
-	  if (constvoid_id == CTF_NULL_TYPEID)
-	    constvoid_id = ctf_add_reftype (tu_ctfc, CTF_ADD_ROOT,
-					    dvd->dvd_type, CTF_K_CONST, NULL);
-	  dvd->dvd_type = constvoid_id;
+	  if (constvoid_dtd == NULL)
+            constvoid_dtd = ctf_add_reftype (tu_ctfc, CTF_ADD_ROOT,
+                                             dvd->dvd_type, CTF_K_CONST, NULL);
+	  dvd->dvd_type = constvoid_dtd;
 	}
     }
 
diff --git a/gcc/config/bpf/btfext-out.cc b/gcc/config/bpf/btfext-out.cc
index 7ec438fd1d1..ce596e33643 100644
--- a/gcc/config/bpf/btfext-out.cc
+++ b/gcc/config/bpf/btfext-out.cc
@@ -134,7 +134,7 @@ struct GTY ((chain_next ("%h.next"))) btf_ext_lineinfo
 
 /* Internal representation of a BPF CO-RE relocation record.  */
 struct GTY ((chain_next ("%h.next"))) btf_ext_core_reloc {
-  unsigned int bpfcr_type;		/* BTF type ID of container.  */
+  ctf_dtdef_ref bpfcr_type;		/* BTF type of container.  */
   unsigned int  bpfcr_astr_off;		/* Offset of access string in .BTF
 					   string table.  */
   rtx_code_label * bpfcr_insn_label;	/* RTX label attached to instruction
@@ -296,13 +296,14 @@ bpf_core_reloc_add (const tree type, const char * section_name,
   struct btf_ext_core_reloc *bpfcr = bpf_create_core_reloc (section_name, &sec);
 
   ctf_container_ref ctfc = ctf_get_tu_ctfc ();
+  ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, type);
 
   /* Buffer the access string in the auxiliary strtab.  */
   bpfcr->bpfcr_astr_off = 0;
   gcc_assert (accessor != NULL);
   bpfcr->bpfcr_astr_off = btf_ext_add_string (accessor);
 
-  bpfcr->bpfcr_type = get_btf_id (ctf_lookup_tree_type (ctfc, type));
+  bpfcr->bpfcr_type = dtd;
   bpfcr->bpfcr_insn_label = label;
   bpfcr->bpfcr_kind = kind;
 
@@ -341,7 +342,7 @@ bpf_core_get_sou_member_index (ctf_container_ref ctfc, const tree node)
       for (dmd = dtd->dtd_u.dtu_members;
            dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
         {
-	  bool field_has_btf = get_btf_id (dmd->dmd_type) <= BTF_MAX_TYPE;
+	  bool field_has_btf = (dmd->dmd_type && dmd->dmd_type->dtd_type <= BTF_MAX_TYPE);
 
 	  if (field == node)
 	    return field_has_btf ? i : -1;
@@ -574,8 +575,9 @@ output_btfext_core_sections (void)
 				 false);
 	      char *str = xstrdup (pp_formatted_text (&pp));
 
-	      dw2_asm_output_data (4, bpfcr->bpfcr_type, "bpfcr_type (%s)",
-				   str);
+	      uint32_t type_id =
+		bpfcr->bpfcr_type ? bpfcr->bpfcr_type->dtd_type : 0;
+	      dw2_asm_output_data (4, type_id, "bpfcr_type (%s)", str);
 	      dw2_asm_output_data (4, bpfcr->bpfcr_astr_off + str_aux_off,
 				   "bpfcr_astr_off (\"%s\")",
 				   bpfcr->info.accessor_str);
diff --git a/gcc/config/bpf/core-builtins.cc b/gcc/config/bpf/core-builtins.cc
index 829acea98f7..d5a7de825ad 100644
--- a/gcc/config/bpf/core-builtins.cc
+++ b/gcc/config/bpf/core-builtins.cc
@@ -1021,7 +1021,8 @@ process_type (struct cr_builtins *data)
       && data->default_value != NULL)
   {
     ctf_container_ref ctfc = ctf_get_tu_ctfc ();
-    unsigned int btf_id = get_btf_id (ctf_lookup_tree_type (ctfc, ret.type));
+    ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, ret.type);
+    unsigned int btf_id = dtd ? dtd->dtd_type : 0;
     data->rtx_default_value = expand_normal (build_int_cst (integer_type_node,
 							    btf_id));
   }
diff --git a/gcc/ctfc.cc b/gcc/ctfc.cc
index 67711606ab8..d8f1037b4e0 100644
--- a/gcc/ctfc.cc
+++ b/gcc/ctfc.cc
@@ -373,9 +373,9 @@ ctf_add_cuname (ctf_container_ref ctfc, const char * filename)
    ctf_dvd_lookup, as applicable, to ascertain that the CTF type or the CTF
    variable respectively does not already exist, and then add it.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name,
-		 ctf_dtdef_ref * rp, dw_die_ref die)
+		 dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
   ctf_id_t type;
@@ -397,18 +397,16 @@ ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name,
 
   ctf_dtd_insert (ctfc, dtd);
 
-  *rp = dtd;
-  return type;
+  return dtd;
 }
 
-static ctf_id_t
+static ctf_dtdef_ref
 ctf_add_encoded (ctf_container_ref ctfc, uint32_t flag, const char * name,
 		 const ctf_encoding_t * ep, uint32_t kind, dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type;
 
-  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, name, die);
 
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
 
@@ -424,83 +422,81 @@ ctf_add_encoded (ctf_container_ref ctfc, uint32_t flag, const char * name,
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
-ctf_id_t
-ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+ctf_dtdef_ref
+ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_dtdef_ref ref,
 		 uint32_t kind, dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type;
 
-  gcc_assert (ref <= CTF_MAX_TYPE);
+  gcc_assert (ref != NULL);
 
-  type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, NULL, die);
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
   /* Caller of this API must guarantee that a CTF type with id = ref already
      exists.  This will also be validated for us at link-time.  */
-  dtd->dtd_data.ctti_type = (uint32_t) ref;
+  dtd->dtd_data.ctti_type = (uint32_t) ref->dtd_type;
+  dtd->ref_type = ref;
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_forward (ctf_container_ref ctfc, uint32_t flag, const char * name,
 		 uint32_t kind, dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type = 0;
 
-  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, name, die);
 
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
   dtd->dtd_data.ctti_type = kind;
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_typedef (ctf_container_ref ctfc, uint32_t flag, const char * name,
-		 ctf_id_t ref, dw_die_ref die)
+		 ctf_dtdef_ref ref, dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type;
 
-  gcc_assert (ref <= CTF_MAX_TYPE);
+  gcc_assert (ref != NULL);
   /* Nameless Typedefs are not expected.  */
   gcc_assert ((name != NULL) && strcmp (name, ""));
 
-  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, name, die);
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_TYPEDEF, flag, 0);
   /* Caller of this API must guarantee that a CTF type with id = ref already
      exists.  This will also be validated for us at link-time.  */
-  dtd->dtd_data.ctti_type = (uint32_t) ref;
+  dtd->dtd_data.ctti_type = (uint32_t) ref->dtd_type;
+  dtd->ref_type = ref;
 
   gcc_assert (dtd->dtd_type != dtd->dtd_data.ctti_type);
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
-ctf_id_t
-ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+ctf_dtdef_ref
+ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_dtdef_ref ref,
 	       uint32_t bit_offset, uint32_t bit_size, dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type;
   uint32_t roundup_nbytes;
 
   gcc_assert ((bit_size <= 255) && (bit_offset <= 255));
 
-  gcc_assert (ref <= CTF_MAX_TYPE);
+  gcc_assert (ref != NULL);
 
-  type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, NULL, die);
 
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
 
@@ -514,49 +510,48 @@ ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
 
   /* Caller of this API must guarantee that a CTF type with id = ref already
      exists.  This will also be validated for us at link-time.  */
-  dtd->dtd_u.dtu_slice.cts_type = (uint32_t) ref;
+  dtd->dtd_u.dtu_slice.cts_type = ref;
   dtd->dtd_u.dtu_slice.cts_bits = bit_size;
   dtd->dtd_u.dtu_slice.cts_offset = bit_offset;
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_float (ctf_container_ref ctfc, uint32_t flag,
 	       const char * name, const ctf_encoding_t * ep, dw_die_ref die)
 {
   return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_FLOAT, die));
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_integer (ctf_container_ref ctfc, uint32_t flag,
 		 const char * name, const ctf_encoding_t * ep, dw_die_ref die)
 {
   return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_INTEGER, die));
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_unknown (ctf_container_ref ctfc, uint32_t flag,
 		 const char * name, const ctf_encoding_t * ep, dw_die_ref die)
 {
   return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_UNKNOWN, die));
 }
 
-ctf_id_t
-ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+ctf_dtdef_ref
+ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_dtdef_ref ref,
 		 dw_die_ref die)
 {
   return (ctf_add_reftype (ctfc, flag, ref, CTF_K_POINTER, die));
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
 	       dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type;
 
   gcc_assert (arp);
 
@@ -564,7 +559,7 @@ ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
      arp->ctr_index are already added.  This will also be validated for us at
      link-time.  */
 
-  type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, NULL, die);
 
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
   dtd->dtd_data.ctti_size = 0;
@@ -572,15 +567,14 @@ ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
 	      HOST_WIDE_INT size, bool eunsigned, dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type;
 
   /* In the compiler, no need to handle the case of promoting forwards to
      enums.  This comment is simply to note a divergence from libctf.  */
@@ -595,7 +589,7 @@ ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
 	= CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
     }
 
-  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, name, die);
 
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
 
@@ -608,11 +602,11 @@ ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
 int
-ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
+ctf_add_enumerator (ctf_container_ref ctfc, ctf_dtdef_ref enum_dtd, const char * name,
 		    HOST_WIDE_INT value, dw_die_ref die)
 {
   ctf_dmdef_t * dmd;
@@ -622,7 +616,7 @@ ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
      addded.  This will also be validated for us at link-time.  */
   ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
   gcc_assert (dtd);
-  gcc_assert (dtd->dtd_type == enid);
+  gcc_assert (dtd == enum_dtd);
   gcc_assert (name);
 
   kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
@@ -646,7 +640,7 @@ ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
 
   /* Buffer the strings in the CTF string table.  */
   dmd->dmd_name = ctf_add_string (ctfc, name, &(dmd->dmd_name_offset));
-  dmd->dmd_type = CTF_NULL_TYPEID;
+  dmd->dmd_type = NULL;
   dmd->dmd_offset = 0;
 
   dmd->dmd_value = value;
@@ -662,7 +656,7 @@ ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
 
 int
 ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou,
-		       const char * name, ctf_id_t type,
+		       const char * name, ctf_dtdef_ref type,
 		       uint64_t bit_offset)
 {
   ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, sou);
@@ -702,7 +696,7 @@ ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou,
 }
 
 int
-ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref,
+ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_dtdef_ref ref,
 		  dw_die_ref die, unsigned int external_vis,
 		  dw_die_ref die_var_decl)
 {
@@ -747,16 +741,16 @@ ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref,
 
 int
 ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
-		      const char * name, ctf_id_t type)
+		      const char * name, ctf_dtdef_ref arg_dtd)
 {
-  ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, func);
+  ctf_dtdef_ref func_dtd = ctf_dtd_lookup (ctfc, func);
   ctf_func_arg_t * farg;
   uint32_t vlen;
 
   /* The function to which argument is being added must already exist.  */
-  gcc_assert (dtd);
+  gcc_assert (func_dtd);
   /* The number of args must have been non-zero.  */
-  vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
+  vlen = CTF_V2_INFO_VLEN (func_dtd->dtd_data.ctti_info);
   gcc_assert (vlen);
 
   farg = ggc_cleared_alloc<ctf_func_arg_t> ();
@@ -766,9 +760,9 @@ ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
      these strings to avoid unnecessary bloat in CTF section in CTF V3.  */
   farg->farg_name = ctf_add_string (ctfc, name, &(farg->farg_name_offset),
 				    CTF_AUX_STRTAB);
-  farg->farg_type = type;
+  farg->farg_type = arg_dtd;
 
-  ctf_farg_list_append (&dtd->dtd_u.dtu_argv, farg);
+  ctf_farg_list_append (&func_dtd->dtd_u.dtu_argv, farg);
 
   /* For aux_str, keep ctfc_aux_strlen updated for debugging.  */
   if ((name != NULL) && strcmp (name, ""))
@@ -777,13 +771,12 @@ ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
   return 0;
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name,
 		  const ctf_funcinfo_t * ctc, dw_die_ref die,
 		  bool from_global_func, int linkage)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type;
   uint32_t vlen;
 
   gcc_assert (ctc);
@@ -791,27 +784,27 @@ ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name,
   vlen = ctc->ctc_argc;
   gcc_assert (vlen <= CTF_MAX_VLEN);
 
-  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, name, die);
 
   dtd->from_global_func = from_global_func;
   dtd->linkage = linkage;
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
+  dtd->ref_type = ctc->ctc_return;
   /* Caller must make sure CTF types for ctc->ctc_return are already added.  */
-  dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return;
+  dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return->dtd_type;
   /* Caller must make sure CTF types for function arguments are already added
      via ctf_add_function_arg () API.  */
 
   ctfc->ctfc_num_stypes++;
 
-  return type;
+  return dtd;
 }
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name,
 	     uint32_t kind, size_t size, dw_die_ref die)
 {
   ctf_dtdef_ref dtd;
-  ctf_id_t type = 0;
 
   gcc_assert ((kind == CTF_K_STRUCT) || (kind == CTF_K_UNION));
 
@@ -828,7 +821,7 @@ ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name,
 	= CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
     }
 
-  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+  dtd = ctf_add_generic (ctfc, flag, name, die);
 
   dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
 
@@ -845,23 +838,23 @@ ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name,
       ctfc->ctfc_num_stypes++;
     }
 
-  return type;
+  return dtd;
 }
 
 /* Given a TREE_TYPE node, return the CTF type ID for that type.  */
 
-ctf_id_t
+ctf_dtdef_ref
 ctf_lookup_tree_type (ctf_container_ref ctfc, const tree type)
 {
   dw_die_ref die = lookup_type_die (type);
   if (die == NULL)
-    return CTF_NULL_TYPEID;
+    return NULL;
 
   ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
   if (dtd == NULL)
-    return CTF_NULL_TYPEID;
+    return NULL;
 
-  return dtd->dtd_type;
+  return dtd;
 }
 
 /* Check if CTF for TYPE has already been generated.  Mainstay for
@@ -870,7 +863,7 @@ ctf_lookup_tree_type (ctf_container_ref ctfc, const tree type)
 
 bool
 ctf_type_exists (ctf_container_ref ctfc, dw_die_ref type,
-		 ctf_id_t * type_id)
+		 ctf_dtdef_ref * dtd)
 {
   bool exists = false;
   ctf_dtdef_ref ctf_type_seen = ctf_dtd_lookup (ctfc, type);
@@ -879,7 +872,7 @@ ctf_type_exists (ctf_container_ref ctfc, dw_die_ref type,
     {
       exists = true;
       /* CTF type for this type exists.  */
-      *type_id = ctf_type_seen->dtd_type;
+      *dtd = ctf_type_seen;
     }
 
   return exists;
diff --git a/gcc/ctfc.h b/gcc/ctfc.h
index e7bd93901cf..cfc805db7b5 100644
--- a/gcc/ctfc.h
+++ b/gcc/ctfc.h
@@ -48,6 +48,8 @@ along with GCC; see the file COPYING3.  If not see
 
 typedef uint64_t ctf_id_t;
 
+struct ctf_dtdef;
+
 /* CTF string table element (list node).  */
 
 typedef struct GTY ((chain_next ("%h.cts_next"))) ctf_string
@@ -81,23 +83,23 @@ typedef struct GTY (()) ctf_encoding
 
 typedef struct GTY (()) ctf_arinfo
 {
-  ctf_id_t ctr_contents;	/* Type of array contents.  */
-  ctf_id_t ctr_index;		/* Type of array index.  */
-  unsigned int ctr_nelems;	/* Number of elements.  */
+  struct ctf_dtdef * ctr_contents; /* Type of array contents.  */
+  struct ctf_dtdef * ctr_index;	   /* Type of array index.  */
+  unsigned int ctr_nelems;	   /* Number of elements.  */
 } ctf_arinfo_t;
 
 /* Function information for CTF generation.  */
 
 typedef struct GTY (()) ctf_funcinfo
 {
-  ctf_id_t ctc_return;		/* Function return type.  */
-  unsigned int ctc_argc;	/* Number of typed arguments to function.  */
-  unsigned int ctc_flags;	/* Function attributes (see below).  */
+  struct ctf_dtdef * ctc_return; /* Function return type.  */
+  unsigned int ctc_argc;	 /* Number of typed arguments to function.  */
+  unsigned int ctc_flags;	 /* Function attributes (see below).  */
 } ctf_funcinfo_t;
 
 typedef struct GTY (()) ctf_sliceinfo
 {
-  unsigned int cts_type;	/* Reference CTF type.  */
+  struct ctf_dtdef * cts_type;	/* Reference CTF type.  */
   unsigned short cts_offset;	/* Offset in bits of the first bit.  */
   unsigned short cts_bits;	/* Size in bits.  */
 } ctf_sliceinfo_t;
@@ -130,7 +132,7 @@ typedef struct GTY (()) ctf_itype
 typedef struct GTY ((chain_next ("%h.dmd_next"))) ctf_dmdef
 {
   const char * dmd_name;	/* Name of this member.  */
-  ctf_id_t dmd_type;		/* Type of this member (for sou).  */
+  struct ctf_dtdef * dmd_type;	/* Type of this member (for sou).  */
   uint32_t dmd_name_offset;	/* Offset of the name in str table.  */
   uint64_t dmd_offset;		/* Offset of this member in bits (for sou).  */
   HOST_WIDE_INT dmd_value;	/* Value of this member (for enum).  */
@@ -143,7 +145,7 @@ typedef struct GTY ((chain_next ("%h.dmd_next"))) ctf_dmdef
 
 typedef struct GTY (()) ctf_func_arg
 {
-  ctf_id_t farg_type;		  /* Type identifier of the argument.  */
+  struct ctf_dtdef * farg_type;	  /* Type of the argument.  */
   const char * farg_name;	  /* Name of the argument.  */
   uint32_t farg_name_offset;	  /* Offset of the name in str table.  */
   struct ctf_func_arg * farg_next;/* A list node.  */
@@ -158,6 +160,7 @@ struct GTY ((for_user)) ctf_dtdef
   dw_die_ref dtd_key;	      /* Type key for hashing.  */
   const char * dtd_name;      /* Name associated with definition (if any).  */
   ctf_id_t dtd_type;	      /* Type identifier for this definition.  */
+  struct ctf_dtdef *ref_type; /* Type referred to by this type (if any).  */
   ctf_itype_t dtd_data;	      /* Type node.  */
   bool from_global_func; /* Whether this type was added from a global
 			    function.  */
@@ -188,7 +191,7 @@ struct GTY ((for_user)) ctf_dvdef
   const char * dvd_name;	/* Name associated with variable.  */
   uint32_t dvd_name_offset;	/* Offset of the name in str table.  */
   unsigned int dvd_visibility;	/* External visibility.  0=static,1=global.  */
-  ctf_id_t dvd_type;		/* Type of variable.  */
+  struct ctf_dtdef * dvd_type;	/* Type of variable.  */
 };
 
 typedef struct ctf_dvdef ctf_dvdef_t;
@@ -390,7 +393,7 @@ extern void btf_finalize (void);
 
 extern ctf_container_ref ctf_get_tu_ctfc (void);
 
-extern bool ctf_type_exists (ctf_container_ref, dw_die_ref, ctf_id_t *);
+extern bool ctf_type_exists (ctf_container_ref, dw_die_ref, ctf_dtdef_ref *);
 
 extern void ctf_add_cuname (ctf_container_ref, const char *);
 
@@ -404,41 +407,41 @@ extern bool ctf_dvd_ignore_lookup (const ctf_container_ref ctfc,
 extern const char * ctf_add_string (ctf_container_ref, const char *,
 				    uint32_t *, int);
 
-extern ctf_id_t ctf_add_reftype (ctf_container_ref, uint32_t, ctf_id_t,
+extern ctf_dtdef_ref ctf_add_reftype (ctf_container_ref, uint32_t, ctf_dtdef_ref,
 				 uint32_t, dw_die_ref);
-extern ctf_id_t ctf_add_enum (ctf_container_ref, uint32_t, const char *,
+extern ctf_dtdef_ref ctf_add_enum (ctf_container_ref, uint32_t, const char *,
 			      HOST_WIDE_INT, bool, dw_die_ref);
-extern ctf_id_t ctf_add_slice (ctf_container_ref, uint32_t, ctf_id_t,
+extern ctf_dtdef_ref ctf_add_slice (ctf_container_ref, uint32_t, ctf_dtdef_ref,
 			       uint32_t, uint32_t, dw_die_ref);
-extern ctf_id_t ctf_add_float (ctf_container_ref, uint32_t, const char *,
+extern ctf_dtdef_ref ctf_add_float (ctf_container_ref, uint32_t, const char *,
 			       const ctf_encoding_t *, dw_die_ref);
-extern ctf_id_t ctf_add_integer (ctf_container_ref, uint32_t, const char *,
+extern ctf_dtdef_ref ctf_add_integer (ctf_container_ref, uint32_t, const char *,
 				 const ctf_encoding_t *, dw_die_ref);
-extern ctf_id_t ctf_add_unknown (ctf_container_ref, uint32_t, const char *,
+extern ctf_dtdef_ref ctf_add_unknown (ctf_container_ref, uint32_t, const char *,
 				 const ctf_encoding_t *, dw_die_ref);
-extern ctf_id_t ctf_add_pointer (ctf_container_ref, uint32_t, ctf_id_t,
+extern ctf_dtdef_ref ctf_add_pointer (ctf_container_ref, uint32_t, ctf_dtdef_ref,
 				 dw_die_ref);
-extern ctf_id_t ctf_add_array (ctf_container_ref, uint32_t,
+extern ctf_dtdef_ref ctf_add_array (ctf_container_ref, uint32_t,
 			       const ctf_arinfo_t *, dw_die_ref);
-extern ctf_id_t ctf_add_forward (ctf_container_ref, uint32_t, const char *,
+extern ctf_dtdef_ref ctf_add_forward (ctf_container_ref, uint32_t, const char *,
 				 uint32_t, dw_die_ref);
-extern ctf_id_t ctf_add_typedef (ctf_container_ref, uint32_t, const char *,
-				 ctf_id_t, dw_die_ref);
-extern ctf_id_t ctf_add_function (ctf_container_ref, uint32_t, const char *,
+extern ctf_dtdef_ref ctf_add_typedef (ctf_container_ref, uint32_t, const char *,
+				 ctf_dtdef_ref, dw_die_ref);
+extern ctf_dtdef_ref ctf_add_function (ctf_container_ref, uint32_t, const char *,
 				  const ctf_funcinfo_t *, dw_die_ref, bool, int);
-extern ctf_id_t ctf_add_sou (ctf_container_ref, uint32_t, const char *,
+extern ctf_dtdef_ref ctf_add_sou (ctf_container_ref, uint32_t, const char *,
 			     uint32_t, size_t, dw_die_ref);
 
-extern int ctf_add_enumerator (ctf_container_ref, ctf_id_t, const char *,
+extern int ctf_add_enumerator (ctf_container_ref, ctf_dtdef_ref, const char *,
 			       HOST_WIDE_INT, dw_die_ref);
 extern int ctf_add_member_offset (ctf_container_ref, dw_die_ref, const char *,
-				  ctf_id_t, uint64_t);
+				  ctf_dtdef_ref, uint64_t);
 extern int ctf_add_function_arg (ctf_container_ref, dw_die_ref,
-				 const char *, ctf_id_t);
-extern int ctf_add_variable (ctf_container_ref, const char *, ctf_id_t,
+				 const char *, ctf_dtdef_ref);
+extern int ctf_add_variable (ctf_container_ref, const char *, ctf_dtdef_ref,
 			     dw_die_ref, unsigned int, dw_die_ref);
 
-extern ctf_id_t ctf_lookup_tree_type (ctf_container_ref, const tree);
+extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
 extern ctf_id_t get_btf_id (ctf_id_t);
 
 typedef bool (*funcs_traverse_callback) (ctf_dtdef_ref, void *);
diff --git a/gcc/ctfout.cc b/gcc/ctfout.cc
index ee082b5fd01..dd686703ebc 100644
--- a/gcc/ctfout.cc
+++ b/gcc/ctfout.cc
@@ -380,7 +380,7 @@ ctf_asm_type (ctf_dtdef_ref type)
 static void
 ctf_asm_slice (ctf_dtdef_ref type)
 {
-  dw2_asm_output_data (4, type->dtd_u.dtu_slice.cts_type, "cts_type");
+  dw2_asm_output_data (4, (uint32_t) type->dtd_u.dtu_slice.cts_type->dtd_type, "cts_type");
   dw2_asm_output_data (2, type->dtd_u.dtu_slice.cts_offset, "cts_offset");
   dw2_asm_output_data (2, type->dtd_u.dtu_slice.cts_bits, "cts_bits");
 }
@@ -390,8 +390,8 @@ ctf_asm_slice (ctf_dtdef_ref type)
 static void
 ctf_asm_array (ctf_dtdef_ref dtd)
 {
-  dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_contents, "cta_contents");
-  dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_index, "cta_index");
+  dw2_asm_output_data (4, (uint32_t) dtd->dtd_u.dtu_arr.ctr_contents->dtd_type, "cta_contents");
+  dw2_asm_output_data (4, (uint32_t) dtd->dtd_u.dtu_arr.ctr_index->dtd_type, "cta_index");
   dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_nelems, "cta_nelems");
 }
 
@@ -403,7 +403,7 @@ ctf_asm_varent (ctf_dvdef_ref var)
   /* Output the reference to the name in the string table.  */
   dw2_asm_output_data (4, var->dvd_name_offset, "ctv_name");
   /* Output the type index.  */
-  dw2_asm_output_data (4, var->dvd_type, "ctv_typeidx");
+  dw2_asm_output_data (4, (uint32_t) var->dvd_type->dtd_type, "ctv_typeidx");
 }
 
 /* Asm'out a member of CTF struct or union, represented by ctf_lmember_t.  */
@@ -414,7 +414,7 @@ ctf_asm_sou_lmember (ctf_dmdef_t * dmd)
   dw2_asm_output_data (4, dmd->dmd_name_offset, "ctlm_name");
   dw2_asm_output_data (4, CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset),
 		       "ctlm_offsethi");
-  dw2_asm_output_data (4, dmd->dmd_type, "ctlm_type");
+  dw2_asm_output_data (4, (uint32_t) dmd->dmd_type->dtd_type, "ctlm_type");
   dw2_asm_output_data (4, CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset),
 		       "ctlm_offsetlo");
 }
@@ -426,7 +426,7 @@ ctf_asm_sou_member (ctf_dmdef_t * dmd)
 {
   dw2_asm_output_data (4, dmd->dmd_name_offset, "ctm_name");
   dw2_asm_output_data (4, dmd->dmd_offset, "ctm_offset");
-  dw2_asm_output_data (4, dmd->dmd_type, "ctm_type");
+  dw2_asm_output_data (4, (uint32_t) dmd->dmd_type->dtd_type, "ctm_type");
 }
 
 /* Asm'out an enumerator constant.  */
@@ -443,7 +443,10 @@ ctf_asm_enum_const (ctf_dmdef_t * dmd)
 static void
 ctf_asm_func_arg (ctf_func_arg_t * farg)
 {
-  dw2_asm_output_data (4, farg->farg_type, "dtu_argv");
+  /* farg_type may be NULL, indicating varargs.  */
+  dw2_asm_output_data (4, farg->farg_type
+		       ? (uint32_t) farg->farg_type->dtd_type
+		       : 0, "dtu_argv");
 }
 
 /* CTF writeout to asm file.  */
@@ -537,7 +540,7 @@ output_ctf_obj_info (ctf_container_ref ctfc)
       var = ctfc->ctfc_gobjts_list[i];
 
       /* CTF type ID corresponding to the type of the variable.  */
-      dw2_asm_output_data (4, var->dvd_type, "objtinfo_var_type");
+      dw2_asm_output_data (4, (uint32_t) var->dvd_type->dtd_type, "objtinfo_var_type");
     }
 
 }
diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
index ec94982e4b1..f16b5ceee74 100644
--- a/gcc/dwarf2ctf.cc
+++ b/gcc/dwarf2ctf.cc
@@ -29,7 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* Forward declarations for some routines defined in this file.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_type (ctf_container_ref, dw_die_ref);
 
 /* All the DIE structures we handle come from the DWARF information
@@ -156,7 +156,7 @@ ctf_get_die_loc_col (dw_die_ref die)
 
 /* Generate CTF for the void type.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_void_type (ctf_container_ref ctfc)
 {
   ctf_encoding_t ctf_encoding = {0, 0, 0};
@@ -174,10 +174,10 @@ gen_ctf_void_type (ctf_container_ref ctfc)
 
 /* Generate CTF type of unknown kind.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_unknown_type (ctf_container_ref ctfc)
 {
-  ctf_id_t unknown_type_id;
+  ctf_dtdef_ref dtd;
 
   /* In CTF, the unknown type is encoded as a 0 byte sized type with kind
      CTF_K_UNKNOWN.  Create an encoding object merely to reuse the underlying
@@ -187,11 +187,11 @@ gen_ctf_unknown_type (ctf_container_ref ctfc)
 
   gcc_assert (ctf_unknown_die != NULL);
   /* Type de-duplication.  */
-  if (!ctf_type_exists (ctfc, ctf_unknown_die, &unknown_type_id))
-    unknown_type_id = ctf_add_unknown (ctfc, CTF_ADD_ROOT, "unknown",
-				       &ctf_encoding, ctf_unknown_die);
+  if (!ctf_type_exists (ctfc, ctf_unknown_die, &dtd))
+    dtd = ctf_add_unknown (ctfc, CTF_ADD_ROOT, "unknown",
+			   &ctf_encoding, ctf_unknown_die);
 
-  return unknown_type_id;
+  return dtd;
 }
 
 /* Sizes of entities can be given in bytes or bits.  This function
@@ -217,10 +217,10 @@ ctf_die_bitsize (dw_die_ref die)
    Important: the caller of this API must make sure that duplicate types are
    not added.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
 {
-  ctf_id_t type_id = CTF_NULL_TYPEID;
+  ctf_dtdef_ref dtd = NULL;
 
   ctf_encoding_t ctf_encoding = {0, 0, 0};
 
@@ -236,8 +236,8 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
       ctf_encoding.cte_bits = 0;
 
       gcc_assert (name_string);
-      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
-				 &ctf_encoding, type);
+      dtd = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+			     &ctf_encoding, type);
 
       break;
     case DW_ATE_boolean:
@@ -246,8 +246,8 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
       ctf_encoding.cte_bits = bit_size;
 
       gcc_assert (name_string);
-      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
-				 &ctf_encoding, type);
+      dtd = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+			     &ctf_encoding, type);
       break;
     case DW_ATE_float:
       {
@@ -269,7 +269,7 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
 	  break;
 
 	ctf_encoding.cte_bits = bit_size;
-	type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+	dtd = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
 				 &ctf_encoding, type);
 
 	break;
@@ -291,7 +291,7 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
 	ctf_encoding.cte_format |= CTF_INT_SIGNED;
 
       ctf_encoding.cte_bits = bit_size;
-      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+      dtd = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
 				 &ctf_encoding, type);
       break;
 
@@ -315,7 +315,7 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
 	  break;
 
 	ctf_encoding.cte_bits = bit_size;
-	type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+	dtd = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
 				 &ctf_encoding, type);
 	break;
       }
@@ -324,41 +324,39 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
       break;
     }
 
-  return type_id;
+  return dtd;
 }
 
 /* Generate CTF for a pointer type.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_pointer_type (ctf_container_ref ctfc, dw_die_ref ptr_type)
 {
-  ctf_id_t type_id = CTF_NULL_TYPEID;
-  ctf_id_t ptr_type_id = CTF_NULL_TYPEID;
+  ctf_dtdef_ref pointed_dtd, pointer_dtd;
   dw_die_ref pointed_type_die = ctf_get_AT_type (ptr_type);
 
-  type_id = gen_ctf_type (ctfc, pointed_type_die);
+  pointed_dtd = gen_ctf_type (ctfc, pointed_type_die);
 
   /* Type de-duplication.
      Consult the ctfc_types hash again before adding the CTF pointer type
      because there can be cases where a pointer type may have been added by
      the gen_ctf_type call above.  */
-  if (ctf_type_exists (ctfc, ptr_type, &ptr_type_id))
-    return ptr_type_id;
+  if (!ctf_type_exists (ctfc, ptr_type, &pointer_dtd))
+    pointer_dtd = ctf_add_pointer (ctfc, CTF_ADD_ROOT, pointed_dtd, ptr_type);
 
-  ptr_type_id = ctf_add_pointer (ctfc, CTF_ADD_ROOT, type_id, ptr_type);
-  return ptr_type_id;
+  return pointer_dtd;
 }
 
 /* Recursively generate CTF for array dimensions starting at DIE C (of type
    DW_TAG_subrange_type) until DIE LAST (of type DW_TAG_subrange_type) is
    reached.  ARRAY_ELEMS_TYPE_ID is base type for the array.  */
 
-static ctf_id_t
-gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_id_t array_elems_type_id,
+static ctf_dtdef_ref
+gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_dtdef_ref array_elems_type,
 		       dw_die_ref c, dw_die_ref last)
 {
   ctf_arinfo_t arinfo;
-  ctf_id_t array_node_type_id = CTF_NULL_TYPEID;
+  ctf_dtdef_ref array_dtd;
 
   dw_attr_node *upper_bound_at;
   dw_die_ref array_index_type;
@@ -398,30 +396,29 @@ gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_id_t array_elems_type_id,
   arinfo.ctr_index = gen_ctf_type (ctfc, array_index_type);
 
   if (c == last)
-    arinfo.ctr_contents = array_elems_type_id;
+    arinfo.ctr_contents = array_elems_type;
   else
-    arinfo.ctr_contents = gen_ctf_subrange_type (ctfc, array_elems_type_id,
+    arinfo.ctr_contents = gen_ctf_subrange_type (ctfc, array_elems_type,
 						 dw_get_die_sib (c), last);
 
-  if (!ctf_type_exists (ctfc, c, &array_node_type_id))
-    array_node_type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, c);
+  if (!ctf_type_exists (ctfc, c, &array_dtd))
+    array_dtd = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, c);
 
-  return array_node_type_id;
+  return array_dtd;
 }
 
 /* Generate CTF for an ARRAY_TYPE.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_array_type (ctf_container_ref ctfc,
 		    dw_die_ref array_type)
 {
   dw_die_ref first, last, array_elems_type;
-  ctf_id_t array_elems_type_id = CTF_NULL_TYPEID;
-  ctf_id_t array_type_id = CTF_NULL_TYPEID;
+  ctf_dtdef_ref array_dtd, elem_dtd;
 
   int vector_type_p = get_AT_flag (array_type, DW_AT_GNU_vector);
   if (vector_type_p)
-    return array_elems_type_id;
+    return NULL;
 
   /* Find the first and last array dimension DIEs.  */
   last = dw_get_die_child (array_type);
@@ -429,41 +426,36 @@ gen_ctf_array_type (ctf_container_ref ctfc,
 
   /* Type de-duplication.
      Consult the ctfc_types before adding CTF type for the first dimension.  */
-  if (!ctf_type_exists (ctfc, first, &array_type_id))
+  if (!ctf_type_exists (ctfc, first, &array_dtd))
     {
       array_elems_type = ctf_get_AT_type (array_type);
       /* First, register the type of the array elements if needed.  */
-      array_elems_type_id = gen_ctf_type (ctfc, array_elems_type);
+      elem_dtd = gen_ctf_type (ctfc, array_elems_type);
 
-      array_type_id = gen_ctf_subrange_type (ctfc, array_elems_type_id, first,
-					     last);
+      array_dtd = gen_ctf_subrange_type (ctfc, elem_dtd, first, last);
     }
 
-  return array_type_id;
+  return array_dtd;
 }
 
 /* Generate CTF for a typedef.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_typedef (ctf_container_ref ctfc, dw_die_ref tdef)
 {
-  ctf_id_t tdef_type_id, tid;
+  ctf_dtdef_ref tdef_dtd, dtd;
   const char *tdef_name = get_AT_string (tdef, DW_AT_name);
   dw_die_ref tdef_type = ctf_get_AT_type (tdef);
 
-  tid = gen_ctf_type (ctfc, tdef_type);
+  dtd = gen_ctf_type (ctfc, tdef_type);
 
   /* Type de-duplication.
      This is necessary because the ctf for the typedef may have been already
      added due to the gen_ctf_type call above.  */
-  if (!ctf_type_exists (ctfc, tdef, &tdef_type_id))
-  {
-    tdef_type_id = ctf_add_typedef (ctfc, CTF_ADD_ROOT,
-				    tdef_name,
-				    tid,
-				    tdef);
-  }
-  return tdef_type_id;
+  if (!ctf_type_exists (ctfc, tdef, &tdef_dtd))
+    tdef_dtd = ctf_add_typedef (ctfc, CTF_ADD_ROOT, tdef_name, dtd, tdef);
+
+  return tdef_dtd;
 }
 
 /* Generate CTF for a type modifier.
@@ -475,11 +467,11 @@ gen_ctf_typedef (ctf_container_ref ctfc, dw_die_ref tdef)
    For all other cases, this function returns a CTF_NULL_TYPEID;
 */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_modifier_type (ctf_container_ref ctfc, dw_die_ref modifier)
 {
   uint32_t kind = CTF_K_MAX;
-  ctf_id_t modifier_type_id, qual_type_id;
+  ctf_dtdef_ref dtd, modifier_dtd;
   dw_die_ref qual_type = ctf_get_AT_type (modifier);
 
   switch (dw_get_die_tag (modifier))
@@ -493,33 +485,31 @@ gen_ctf_modifier_type (ctf_container_ref ctfc, dw_die_ref modifier)
     }
 
   /* Register the type for which this modifier applies.  */
-  qual_type_id = gen_ctf_type (ctfc, qual_type);
+  dtd = gen_ctf_type (ctfc, qual_type);
 
   /* Skip generating a CTF modifier record for _Atomic as there is no
      representation for it.  */
   if (dw_get_die_tag (modifier) == DW_TAG_atomic_type)
-    return qual_type_id;
+    return dtd;
 
   gcc_assert (kind != CTF_K_MAX);
   /* Now register the modifier itself.  */
-  if (!ctf_type_exists (ctfc, modifier, &modifier_type_id))
-    modifier_type_id = ctf_add_reftype (ctfc, CTF_ADD_ROOT,
-					qual_type_id, kind,
-					modifier);
+  if (!ctf_type_exists (ctfc, modifier, &modifier_dtd))
+    modifier_dtd = ctf_add_reftype (ctfc, CTF_ADD_ROOT, dtd, kind, modifier);
 
-  return modifier_type_id;
+  return modifier_dtd;
 }
 
 /* Generate CTF for a struct type.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
 {
   uint32_t bit_size = ctf_die_bitsize (sou);
   int declaration_p = get_AT_flag (sou, DW_AT_declaration);
   const char *sou_name = get_AT_string (sou, DW_AT_name);
 
-  ctf_id_t sou_type_id;
+  ctf_dtdef_ref sou_dtd;
 
   /* An incomplete structure or union type is represented in DWARF by
      a structure or union DIE that does not have a size attribute and
@@ -531,10 +521,10 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
 
   /* This is a complete struct or union type.  Generate a CTF type for
      it if it doesn't exist already.  */
-  if (!ctf_type_exists (ctfc, sou, &sou_type_id))
-    sou_type_id = ctf_add_sou (ctfc, CTF_ADD_ROOT,
-			       sou_name, kind, bit_size / 8,
-			       sou);
+  if (!ctf_type_exists (ctfc, sou, &sou_dtd))
+    sou_dtd = ctf_add_sou (ctfc, CTF_ADD_ROOT,
+			   sou_name, kind, bit_size / 8,
+			   sou);
 
   /* Now process the struct members.  */
   {
@@ -547,7 +537,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
 	  const char *field_name;
 	  dw_die_ref field_type;
 	  HOST_WIDE_INT field_location;
-	  ctf_id_t field_type_id;
+	  ctf_dtdef_ref field_dtd;
 
 	  c = dw_get_die_sib (c);
 
@@ -556,7 +546,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
 	  field_location = ctf_get_AT_data_member_location (c);
 
 	  /* Generate the field type.  */
-	  field_type_id = gen_ctf_type (ctfc, field_type);
+	  field_dtd = gen_ctf_type (ctfc, field_type);
 
 	  /* If this is a bit-field, then wrap the field type
 	     generated above with a CTF slice.  */
@@ -610,29 +600,29 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
 		 surely something to look at for the next format version bump
 		 for CTF.  */
 	      if (bitsize <= 255 && (bitpos - field_location) <= 255)
-		field_type_id = ctf_add_slice (ctfc, CTF_ADD_NONROOT,
-					       field_type_id,
+		field_dtd = ctf_add_slice (ctfc, CTF_ADD_NONROOT,
+					       field_dtd,
 					       bitpos - field_location,
 					       bitsize, c);
 	      else
-		field_type_id = gen_ctf_unknown_type (ctfc);
+		field_dtd = gen_ctf_unknown_type (ctfc);
 	    }
 
 	  /* Add the field type to the struct or union type.  */
 	  ctf_add_member_offset (ctfc, sou,
 				 field_name,
-				 field_type_id,
+				 field_dtd,
 				 field_location);
 	}
       while (c != dw_get_die_child (sou));
   }
 
-  return sou_type_id;
+  return sou_dtd;
 }
 
 /* Generate CTF for a function type.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
 		       bool from_global_func)
 {
@@ -643,17 +633,16 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
   uint32_t num_args = 0;
   int linkage = get_AT_flag (function, DW_AT_external);
 
-  ctf_id_t return_type_id;
-  ctf_id_t function_type_id;
+  ctf_dtdef_ref return_dtd, function_dtd;
 
   /* First, add the return type.  */
-  return_type_id = gen_ctf_type (ctfc, return_type);
-  func_info.ctc_return = return_type_id;
+  return_dtd = gen_ctf_type (ctfc, return_type);
+  func_info.ctc_return = return_dtd;
 
   /* Type de-duplication.
      Consult the ctfc_types hash before adding the CTF function type.  */
-  if (ctf_type_exists (ctfc, function, &function_type_id))
-    return function_type_id;
+  if (ctf_type_exists (ctfc, function, &function_dtd))
+    return function_dtd;
 
   /* Do a first pass on the formals to determine the number of
      arguments, and whether the function type gets a varargs.  */
@@ -681,12 +670,12 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
   func_info.ctc_argc = num_args;
 
   /* Type de-duplication has already been performed by now.  */
-  function_type_id = ctf_add_function (ctfc, CTF_ADD_ROOT,
-				       function_name,
-				       (const ctf_funcinfo_t *)&func_info,
-				       function,
-				       from_global_func,
-                                       linkage);
+  function_dtd = ctf_add_function (ctfc, CTF_ADD_ROOT,
+				   function_name,
+				   (const ctf_funcinfo_t *)&func_info,
+				   function,
+				   from_global_func,
+				   linkage);
 
   /* Second pass on formals: generate the CTF types corresponding to
      them and add them as CTF function args.  */
@@ -694,7 +683,7 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
     dw_die_ref c;
     unsigned int i = 0;
     const char *arg_name;
-    ctf_id_t arg_type;
+    ctf_dtdef_ref arg_type;
 
     c = dw_get_die_child (function);
     if (c)
@@ -706,7 +695,7 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
 	    {
 	      gcc_assert (i == num_args - 1);
 	      /* Add an argument with type 0 and no name.  */
-	      ctf_add_function_arg (ctfc, function, "", 0);
+	      ctf_add_function_arg (ctfc, function, "", NULL);
 	    }
 	  else if (dw_get_die_tag (c) == DW_TAG_formal_parameter)
 	    {
@@ -723,12 +712,12 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
       while (c != dw_get_die_child (function));
   }
 
-  return function_type_id;
+  return function_dtd;
 }
 
 /* Generate CTF for an enumeration type.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
 {
   const char *enum_name = get_AT_string (enumeration, DW_AT_name);
@@ -736,7 +725,7 @@ gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
   unsigned int signedness = get_AT_unsigned (enumeration, DW_AT_encoding);
   int declaration_p = get_AT_flag (enumeration, DW_AT_declaration);
 
-  ctf_id_t enumeration_type_id;
+  ctf_dtdef_ref enum_dtd;
 
   /* If this is an incomplete enum, generate a CTF forward for it and
      be done.  */
@@ -756,10 +745,10 @@ gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
     }
 
   /* Generate a CTF type for the enumeration.  */
-  enumeration_type_id = ctf_add_enum (ctfc, CTF_ADD_ROOT,
-				      enum_name, bit_size / 8,
-				      (signedness == DW_ATE_unsigned),
-				      enumeration);
+  enum_dtd = ctf_add_enum (ctfc, CTF_ADD_ROOT,
+			   enum_name, bit_size / 8,
+			   (signedness == DW_ATE_unsigned),
+			   enumeration);
 
   /* Process the enumerators.  */
   {
@@ -787,13 +776,13 @@ gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
 	  else
 	    value_wide_int = AT_int (enumerator_value);
 
-	  ctf_add_enumerator (ctfc, enumeration_type_id,
+	  ctf_add_enumerator (ctfc, enum_dtd,
 			      enumerator_name, value_wide_int, enumeration);
 	}
       while (c != dw_get_die_child (enumeration));
   }
 
-  return enumeration_type_id;
+  return enum_dtd;
 }
 
 /* Add a CTF variable record for the given input DWARF DIE.  */
@@ -804,7 +793,7 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
   const char *var_name = get_AT_string (die, DW_AT_name);
   dw_die_ref var_type = ctf_get_AT_type (die);
   unsigned int external_vis = get_AT_flag (die, DW_AT_external);
-  ctf_id_t var_type_id;
+  ctf_dtdef_ref var_dtd;
 
   /* Avoid duplicates.  */
   if (ctf_dvd_lookup (ctfc, die))
@@ -822,11 +811,10 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
   dw_die_ref decl = get_AT_ref (die, DW_AT_specification);
 
   /* Add the type of the variable.  */
-  var_type_id = gen_ctf_type (ctfc, var_type);
+  var_dtd = gen_ctf_type (ctfc, var_type);
 
   /* Generate the new CTF variable and update global counter.  */
-  (void) ctf_add_variable (ctfc, var_name, var_type_id, die, external_vis,
-			   decl);
+  (void) ctf_add_variable (ctfc, var_name, var_dtd, die, external_vis, decl);
   /* Skip updating the number of global objects at this time.  This is updated
      later after pre-processing as some CTF variable records although
      generated now, will not be emitted later.  [PR105089].  */
@@ -837,10 +825,10 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
 static void
 gen_ctf_function (ctf_container_ref ctfc, dw_die_ref die)
 {
-  ctf_id_t function_type_id;
+  ctf_dtdef_ref function_dtd;
   /* Type de-duplication.
      Consult the ctfc_types hash before adding the CTF function type.  */
-  if (ctf_type_exists (ctfc, die, &function_type_id))
+  if (ctf_type_exists (ctfc, die, &function_dtd))
     return;
 
   /* Add the type of the function and update the global functions
@@ -859,41 +847,41 @@ gen_ctf_function (ctf_container_ref ctfc, dw_die_ref die)
    If the given DIE is not recognized as a type, then this function
    returns CTF_NULL_TYPEID.  */
 
-static ctf_id_t
+static ctf_dtdef_ref
 gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
 {
-  ctf_id_t type_id;
+  ctf_dtdef_ref dtd = NULL;
   int unrecog_die = false;
 
-  if (ctf_type_exists (ctfc, die, &type_id))
-    return type_id;
+  if (ctf_type_exists (ctfc, die, &dtd))
+    return dtd;
 
   switch (dw_get_die_tag (die))
     {
     case DW_TAG_base_type:
-      type_id = gen_ctf_base_type (ctfc, die);
+      dtd = gen_ctf_base_type (ctfc, die);
       break;
     case DW_TAG_pointer_type:
-      type_id = gen_ctf_pointer_type (ctfc, die);
+      dtd = gen_ctf_pointer_type (ctfc, die);
       break;
     case DW_TAG_typedef:
-      type_id = gen_ctf_typedef (ctfc, die);
+      dtd = gen_ctf_typedef (ctfc, die);
       break;
     case DW_TAG_array_type:
-      type_id = gen_ctf_array_type (ctfc, die);
+      dtd = gen_ctf_array_type (ctfc, die);
       break;
     case DW_TAG_structure_type:
-      type_id = gen_ctf_sou_type (ctfc, die, CTF_K_STRUCT);
+      dtd = gen_ctf_sou_type (ctfc, die, CTF_K_STRUCT);
       break;
     case DW_TAG_union_type:
-      type_id = gen_ctf_sou_type (ctfc, die, CTF_K_UNION);
+      dtd = gen_ctf_sou_type (ctfc, die, CTF_K_UNION);
       break;
     case DW_TAG_subroutine_type:
-      type_id = gen_ctf_function_type (ctfc, die,
-				       false /* from_global_func */);
+      dtd = gen_ctf_function_type (ctfc, die,
+				   false /* from_global_func */);
       break;
     case DW_TAG_enumeration_type:
-      type_id = gen_ctf_enumeration_type (ctfc, die);
+      dtd = gen_ctf_enumeration_type (ctfc, die);
       break;
     case DW_TAG_atomic_type:
       /* FALLTHROUGH */
@@ -902,35 +890,35 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
     case DW_TAG_restrict_type:
       /* FALLTHROUGH */
     case DW_TAG_volatile_type:
-      type_id = gen_ctf_modifier_type (ctfc, die);
+      dtd = gen_ctf_modifier_type (ctfc, die);
       break;
     case DW_TAG_unspecified_type:
       {
 	const char *name = get_AT_string (die, DW_AT_name);
 
 	if (name && strcmp (name, "void") == 0)
-	  type_id = gen_ctf_void_type (ctfc);
+	  dtd = gen_ctf_void_type (ctfc);
 	else
-	  type_id = CTF_NULL_TYPEID;
+	  dtd = NULL;
 
 	break;
       }
     case DW_TAG_reference_type:
-      type_id = CTF_NULL_TYPEID;
+      dtd = NULL;
       break;
     default:
       /* Unrecognized DIE.  */
       unrecog_die = true;
-      type_id = CTF_NULL_TYPEID;
+      dtd = NULL;
       break;
     }
 
   /* For all types unrepresented in CTF, use an explicit CTF type of kind
      CTF_K_UNKNOWN.  */
-  if ((type_id == CTF_NULL_TYPEID) && (!unrecog_die))
-    type_id = gen_ctf_unknown_type (ctfc);
+  if ((dtd == NULL) && (!unrecog_die))
+    dtd = gen_ctf_unknown_type (ctfc);
 
-  return type_id;
+  return dtd;
 }
 
 bool
@@ -951,7 +939,7 @@ ctf_do_die (dw_die_ref die)
       return false;
     }
   else
-    return gen_ctf_type (tu_ctfc, die) == CTF_NULL_TYPEID;
+    return (gen_ctf_type (tu_ctfc, die) == NULL);
 }
 
 /* Initialize CTF subsystem for CTF debug info generation.  */
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 4/6] btf: refactor and simplify implementation
  2024-05-02 17:11 [PATCH v2 0/6] btf: refactor and add pruning option David Faust
                   ` (2 preceding siblings ...)
  2024-05-02 17:11 ` [PATCH v2 3/6] ctf: use pointers instead of IDs internally David Faust
@ 2024-05-02 17:11 ` David Faust
  2024-05-03 21:06   ` Indu Bhagat
  2024-05-02 17:11 ` [PATCH v2 5/6] btf: add -fprune-btf option David Faust
  2024-05-02 17:11 ` [PATCH v2 6/6] bpf,btf: enable BTF pruning by default for BPF David Faust
  5 siblings, 1 reply; 13+ messages in thread
From: David Faust @ 2024-05-02 17:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: indu.bhagat, jose.marchesi, cupertino.miranda

This patch heavily refactors btfout.cc to take advantage of the
structural changes in the prior commits.

Now that inter-type references are internally stored as simply pointers,
all the painful, brittle, confusing infrastructure that was used in the
process of converting CTF type IDs to BTF type IDs can be thrown out.
This greatly simplifies the entire process of converting from CTF to
BTF, making the code cleaner, easier to read, and easier to maintain.

In addition, we no longer need to worry about destructive changes in
internal data structures used commonly by CTF and BTF, which allows
deleting several ancillary data structures previously used in btfout.cc.

This is nearly transparent, but a few improvements have also been made:

 1) BTF_KIND_FUNC records are now _always_ constructed at early_finish,
    allowing us to construct records even for functions which are later
    inlined by optimizations. DATASEC entries for functions are only
    constructed at late_finish, to avoid incorrectly generating entries
    for functions which get inlined.

 2) BTF_KIND_VAR records and DATASEC entries for them are now always
    constructed at (late) finish, which avoids cases where we could
    incorrectly create records for variables which were completely
    optimized away. This fixes PR debug/113566.

 3) Some additional assembler comments have been added with more
    information for debugging.

gcc/
	* btfout.cc (struct btf_datasec_entry): New.
	(struct btf_datasec): Add `id' member.  Change `entries' to use
	new struct btf_datasec_entry.
	(func_map): New hash_map.
	(max_translated_id): New.
	(btf_var_ids, btf_id_map, holes, voids, num_vars_added)
	(num_types_added, num_types_created): Delete.
	(btf_absolute_var_id, btf_relative_var_id, btf_absolute_func_id)
	(btf_relative_func_id, btf_absolute_datasec_id, init_btf_id_map)
	(get_btf_id, set_btf_id, btf_emit_id_p): Delete.
	(btf_removed_type_p): Delete.
	(btf_dtd_kind, btf_emit_type_p): New helpers.
	(btf_fwd_to_enum_p, btf_calc_num_vbytes): Use them.
	(btf_collect_datasec): Delete.
	(btf_dtd_postprocess_cb, btf_dvd_emit_preprocess_cb)
	(btf_dtd_emit_preprocess_cb, btf_emit_preprocess): Delete.
	(btf_dmd_representable_bitfield_p): Adapt to type reference changes
	and delete now-unused ctfc argument.
	(btf_asm_datasec_type_ref): Delete.
	(btf_asm_type_ref): Adapt to type reference changes, simplify.
	(btf_asm_type): Likewise. Mark struct/union types with bitfield
	members.
	(btf_asm_array): Adapt to data structure changes.
	(btf_asm_varent): Likewise.
	(btf_asm_sou_member): Likewise. Ensure non-bitfield members are
	correctly re-encoded if struct or union contains any bitfield.
	(btf_asm_func_arg, btf_asm_func_type, btf_asm_datasec_entry)
	(btf_asm_datasec_type): Adapt to data structure changes.
	(output_btf_header): Adapt to other changes, simplify type
	length calculation, add info to assembler comments.
	(output_btf_vars): Adapt to other changes.
	(output_btf_strs): Fix overlong lines.
	(output_asm_btf_sou_fields, output_asm_btf_enum_list)
	(output_asm_btf_func_args_list, output_asm_btf_vlen_bytes)
	(output_asm_btf_type, output_btf_types, output_btf_func_types)
	(output_btf_datasec_types): Adapt to other changes.
	(btf_init_postprocess): Delete.
	(btf_output): Change to only perform output.
	(btf_early_add_const_void, btf_early_add_func_records): New.
	(btf_early_finish): Use them here. New.
	(btf_datasec_push_entry): Adapt to data structure changes.
	(btf_datasec_add_func, btf_datasec_add_var): New.
	(btf_late_add_func_datasec_entries): New.
	(btf_emit_variable_p): New helper.
	(btf_late_add_vars): Use it here. New.
	(btf_type_list_cb, btf_late_collect_translated_types): New.
	(btf_late_assign_func_ids, btf_late_assign_var_ids)
	(btf_late_assign_datasec_ids): New.
	(btf_finish): Remove unused argument. Call new btf_late*
	functions and btf_output.
	(btf_finalize): Adapt to data structure changes.
	* ctfc.h (struct ctf_dtdef): Convert existing boolean flags to
	BOOL_BITFIELD and reorder.
	(struct ctf_dvdef): Add dvd_id member.
	(btf_finish): Remove argument from prototype.
	(get_btf_id): Delete prototype.
	(funcs_traverse_callback, traverse_btf_func_types): Add an
	explanatory comment.
	* dwarf2ctf.cc (ctf_debug_finish): Remove unused argument.
	* dwarf2ctf.h: Analogous change.
	* dwarf2out.cc: Likewise.
---
 gcc/btfout.cc    | 1256 +++++++++++++++++++---------------------------
 gcc/ctfc.h       |   17 +-
 gcc/dwarf2ctf.cc |    4 +-
 gcc/dwarf2ctf.h  |    2 +-
 gcc/dwarf2out.cc |    2 +-
 5 files changed, 539 insertions(+), 742 deletions(-)

diff --git a/gcc/btfout.cc b/gcc/btfout.cc
index 14a503a4f80..0af0bd39fc7 100644
--- a/gcc/btfout.cc
+++ b/gcc/btfout.cc
@@ -68,53 +68,44 @@ static char btf_info_section_label[MAX_BTF_LABEL_BYTES];
 
 #define BTF_INVALID_TYPEID 0xFFFFFFFF
 
-/* Mapping of CTF variables to the IDs they will be assigned when they are
-   converted to BTF_KIND_VAR type records. Strictly accounts for the index
-   from the start of the variable type entries, does not include the number
-   of types emitted prior to the variable records.  */
-static GTY (()) hash_map <ctf_dvdef_ref, unsigned> *btf_var_ids;
-
-/* Mapping of type IDs from original CTF ID to BTF ID. Types do not map
-   1-to-1 from CTF to BTF. To avoid polluting the CTF container when updating
-   type references-by-ID, we use this map instead.  */
-static ctf_id_t * btf_id_map = NULL;
-
-/* Information for creating the BTF_KIND_DATASEC records.  */
+/* Internal representation of an entry in a BTF_KIND_DATASEC record.  */
+struct btf_datasec_entry
+{
+  union {
+    ctf_dvdef_ref dvd; /* Reference to the underlying variable represented.  */
+    ctf_dtdef_ref dtd; /* Reference to the underlying type represented.  */
+  };
+  bool is_var;	       /* True iff this entry represents a variable.  */
+  uint32_t size;       /* Size of variable or function, in bytes.
+			  For functions, always zero at compile time.  */
+};
+
+/* Internal representation of a BTF_KIND_DATASEC record.  */
 typedef struct btf_datasec
 {
-  const char *name;                    /* Section name, e.g. ".bss".  */
-  uint32_t name_offset;                /* Offset to name in string table.  */
-  vec<struct btf_var_secinfo> entries; /* Variable entries in this section.  */
+  ctf_id_t id;                           /* BTF type ID of this record.  */
+  const char *name;                      /* Section name, e.g. ".bss".  */
+  uint32_t name_offset;                  /* Offset to name in string table.  */
+  vec<struct btf_datasec_entry> entries; /* Entries in this section.  */
 } btf_datasec_t;
 
 /* One BTF_KIND_DATASEC record is created for each output data section which
    will hold at least one variable.  */
 static vec<btf_datasec_t> datasecs;
 
-/* Holes occur for types which are present in the CTF container, but are either
-   non-representable or redundant in BTF.  */
-static vec<ctf_id_t> holes;
-
-/* CTF definition(s) of void. Only one definition of void should be generated.
-   We should not encounter more than one definition of void, but use a vector
-   to be safe.  */
-static vec<ctf_id_t> voids;
-
 /* Functions in BTF have two separate type records - one for the prototype
    (BTF_KIND_FUNC_PROTO), as well as a BTF_KIND_FUNC. CTF_K_FUNCTION types
    map closely to BTF_KIND_FUNC_PROTO, but the BTF_KIND_FUNC records must be
    created. This vector holds them.  */
 static GTY (()) vec<ctf_dtdef_ref, va_gc> *funcs;
 
-/* The number of BTF variables added to the TU CTF container.  */
-static unsigned int num_vars_added = 0;
-
-/* The number of BTF types added to the TU CTF container.  */
-static unsigned int num_types_added = 0;
+/* Maps BTF_KIND_FUNC_PROTO to the BTF_KIND_FUNC record for it.  Used when
+   creating DATASEC entries.  */
+static GTY (()) hash_map<ctf_dtdef_ref, ctf_dtdef_ref> *func_map;
 
-/* The number of types synthesized for BTF that do not correspond to
-   CTF types.  */
-static unsigned int num_types_created = 0;
+/* Highest BTF ID assigned to any regular type translated from CTF.
+   Does not include BTF_KIND_{VAR,FUNC,DATASEC} types.  */
+static ctf_id_t max_translated_id = 0;
 
 /* Name strings for BTF kinds.
    Note: the indices here must match the type defines in btf.h.  */
@@ -160,6 +151,16 @@ get_btf_kind (uint32_t ctf_kind)
   return BTF_KIND_UNKN;
 }
 
+/* Convenience wrapper around get_btf_kind for the common case.  */
+
+static uint32_t
+btf_dtd_kind (ctf_dtdef_ref dtd)
+{
+  if (!dtd)
+    return BTF_KIND_UNKN;
+  return get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
+}
+
 /* Some BTF types, like BTF_KIND_FUNC_PROTO, are anonymous.  The machinery
    in btfout to emit BTF, may reset dtd_data->ctti_name, but does not update
    the name in the ctf_dtdef_ref type object (deliberate choice).  This
@@ -173,101 +174,20 @@ get_btf_type_name (ctf_dtdef_ref dtd)
   return (dtd->dtd_data.ctti_name) ? dtd->dtd_name : anon;
 }
 
-/* Helper routines to map between 'relative' and 'absolute' IDs.
-
-   In BTF all records (including variables) are output in one long list, and all
-   inter-type references are via index into that list.  But internally since we
-   a) translate from CTF, which separates variable records from regular types
-   and b) create some additional types after the fact, things like VAR and FUNC
-   records are stored in separate vectors with their own indices.  These
-   functions map between the 'relative' IDs (i.e.  indices in their respective
-   containers) and 'absolute' IDs (i.e.  indices in the final contiguous
-   output list), which goes in order:
-     all normal type records translated from CTF
-     all BTF_KIND_VAR records
-     all BTF_KIND_FUNC records (synthesized split function records)
-     all BTF_KIND_DATASEC records (synthesized)
-
-   The extra '+ 1's below are to account for the implicit "void" record, which
-   has index 0 but isn't actually contained in the type list.  */
-
-/* Return the final BTF ID of the variable at relative index REL.  */
-
-static ctf_id_t
-btf_absolute_var_id (ctf_id_t rel)
-{
-  return rel + (num_types_added + 1);
-}
-
-/* Return the relative index of the variable with final BTF ID ABS.  */
-
-static ctf_id_t
-btf_relative_var_id (ctf_id_t abs)
-{
-  return abs - (num_types_added + 1);
-}
-
-/* Return the final BTF ID of the func record at relative index REL.  */
-
-static ctf_id_t
-btf_absolute_func_id (ctf_id_t rel)
-{
-  return rel + (num_types_added + 1) + num_vars_added;
-}
-
-/* Return the relative index of the func record with final BTF ID ABS.  */
-
-static ctf_id_t
-btf_relative_func_id (ctf_id_t abs)
-{
-  return abs - ((num_types_added + 1) + num_vars_added);
-}
-
-/* Return the final BTF ID of the datasec record at relative index REL.  */
-
-static ctf_id_t
-btf_absolute_datasec_id (ctf_id_t rel)
+static bool
+btf_emit_type_p (ctf_dtdef_ref dtd)
 {
-  return rel + (num_types_added + 1) + num_vars_added + funcs->length ();
-}
-
+  uint32_t kind = btf_dtd_kind (dtd);
 
-/* Allocate the btf_id_map, and initialize elements to BTF_INVALID_TYPEID.  */
+  if (kind == BTF_KIND_UNKN)
+    /* This type is not representable in BTF.  */
+    return false;
 
-static void
-init_btf_id_map (size_t len)
-{
-  btf_id_map = XNEWVEC (ctf_id_t, len);
+  if (kind == BTF_KIND_INT && dtd->dtd_data.ctti_size == 0)
+    /* This is a (redundant) definition of void.  */
+    return false;
 
-  btf_id_map[0] = BTF_VOID_TYPEID;
-  for (size_t i = 1; i < len; i++)
-    btf_id_map[i] = BTF_INVALID_TYPEID;
-}
-
-/* Return the BTF type ID of CTF type ID KEY, or BTF_INVALID_TYPEID if the CTF
-   type with ID KEY does not map to a BTF type.  */
-
-ctf_id_t
-get_btf_id (ctf_id_t key)
-{
-  return btf_id_map[key];
-}
-
-/* Set the CTF type ID KEY to map to BTF type ID VAL.  */
-
-static inline void
-set_btf_id (ctf_id_t key, ctf_id_t val)
-{
-  btf_id_map[key] = val;
-}
-
-/* Return TRUE iff the given CTF type ID maps to a BTF type which will
-   be emitted.  */
-static inline bool
-btf_emit_id_p (ctf_id_t id)
-{
-  return ((btf_id_map[id] != BTF_VOID_TYPEID)
-	  && (btf_id_map[id] <= BTF_MAX_TYPE));
+  return true;
 }
 
 /* Return true if DTD is a forward-declared enum.  The BTF representation
@@ -276,9 +196,8 @@ btf_emit_id_p (ctf_id_t id)
 static bool
 btf_fwd_to_enum_p (ctf_dtdef_ref dtd)
 {
-  uint32_t btf_kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
-
-  return (btf_kind == BTF_KIND_FWD && dtd->dtd_data.ctti_type == CTF_K_ENUM);
+  uint32_t kind = btf_dtd_kind (dtd);
+  return (kind == BTF_KIND_FWD && dtd->dtd_data.ctti_type == CTF_K_ENUM);
 }
 
 /* Each BTF type can be followed additional, variable-length information
@@ -290,7 +209,7 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
 {
   uint64_t vlen_bytes = 0;
 
-  uint32_t kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
+  uint32_t kind = btf_dtd_kind (dtd);
   uint32_t vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
 
   switch (kind)
@@ -360,41 +279,6 @@ init_btf_sections (void)
 			       BTF_INFO_SECTION_LABEL, btf_label_num++);
 }
 
-/* Push a BTF datasec variable entry INFO into the datasec named SECNAME,
-   creating the datasec if it does not already exist.  */
-
-static void
-btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
-			struct btf_var_secinfo info)
-{
-  if (secname == NULL)
-    return;
-
-  for (size_t i = 0; i < datasecs.length (); i++)
-    if (strcmp (datasecs[i].name, secname) == 0)
-      {
-	datasecs[i].entries.safe_push (info);
-	return;
-      }
-
-  /* If we don't already have a datasec record for secname, make one.  */
-
-  uint32_t str_off;
-  ctf_add_string (ctfc, secname, &str_off, CTF_AUX_STRTAB);
-  if (strcmp (secname, ""))
-    ctfc->ctfc_aux_strlen += strlen (secname) + 1;
-
-  btf_datasec_t ds;
-  ds.name = secname;
-  ds.name_offset = str_off;
-
-  ds.entries.create (0);
-  ds.entries.safe_push (info);
-
-  datasecs.safe_push (ds);
-}
-
-
 /* Return the section name, as of interest to btf_collect_datasec, for the
    given symtab node.  Note that this deliberately returns NULL for objects
    which do not go in a section btf_collect_datasec cares about.  */
@@ -423,301 +307,15 @@ get_section_name (symtab_node *node)
   return section_name;
 }
 
-/* Construct all BTF_KIND_DATASEC records for CTFC. One such record is created
-   for each non-empty data-containing section in the output. Each record is
-   followed by a variable number of entries describing the variables stored
-   in that section.  */
-
-static void
-btf_collect_datasec (ctf_container_ref ctfc)
-{
-  cgraph_node *func;
-  FOR_EACH_FUNCTION (func)
-    {
-      dw_die_ref die = lookup_decl_die (func->decl);
-      if (die == NULL)
-	continue;
-
-      ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
-      if (dtd == NULL)
-	continue;
-
-      if (DECL_EXTERNAL (func->decl)
-	  && (lookup_attribute ("kernel_helper",
-				DECL_ATTRIBUTES (func->decl))) != NULL_TREE)
-	continue;
-
-      /* Functions actually get two types: a BTF_KIND_FUNC_PROTO, and
-	 also a BTF_KIND_FUNC.  But the CTF container only allocates one
-	 type per function, which matches closely with BTF_KIND_FUNC_PROTO.
-	 For each such function, also allocate a BTF_KIND_FUNC entry.
-	 These will be output later.  */
-      ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
-      func_dtd->dtd_data = dtd->dtd_data;
-      func_dtd->dtd_data.ctti_type = dtd->dtd_type;
-      func_dtd->linkage = dtd->linkage;
-      func_dtd->dtd_name = dtd->dtd_name;
-      /* +1 for the sentinel type not in the types map.  */
-      func_dtd->dtd_type = num_types_added + num_types_created + 1;
-
-      /* Only the BTF_KIND_FUNC type actually references the name. The
-	 BTF_KIND_FUNC_PROTO is always anonymous.  */
-      dtd->dtd_data.ctti_name = 0;
-
-      vec_safe_push (funcs, func_dtd);
-      num_types_created++;
-
-      /* Mark any 'extern' funcs and add DATASEC entries for them.  */
-      if (DECL_EXTERNAL (func->decl))
-	{
-	  func_dtd->linkage = BTF_FUNC_EXTERN;
-
-	  const char *section_name = get_section_name (func);
-	  /* Note: get_section_name () returns NULL for functions in text
-	     section.  This is intentional, since we do not want to generate
-	     DATASEC entries for them.  */
-	  if (section_name == NULL)
-	    continue;
-
-	  struct btf_var_secinfo info;
-
-	  info.type = func_dtd->dtd_type;
-
-	  /* Both zero at compile time.  */
-	  info.size = 0;
-	  info.offset = 0;
-
-	  btf_datasec_push_entry (ctfc, section_name, info);
-	}
-    }
-
-  varpool_node *node;
-  FOR_EACH_VARIABLE (node)
-    {
-      dw_die_ref die = lookup_decl_die (node->decl);
-      if (die == NULL)
-	continue;
-
-      ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
-      if (dvd == NULL)
-	continue;
-
-      /* Mark extern variables.  */
-      if (DECL_EXTERNAL (node->decl))
-	{
-	  dvd->dvd_visibility = BTF_VAR_GLOBAL_EXTERN;
-
-	  /* PR112849: avoid assuming a section for extern decls without
-	     an explicit section, which would result in incorrectly
-	     emitting a BTF_KIND_DATASEC entry for them.  */
-	  if (node->get_section () == NULL)
-	    continue;
-	}
-
-      const char *section_name = get_section_name (node);
-      if (section_name == NULL)
-	continue;
-
-      struct btf_var_secinfo info;
-
-      info.type = 0;
-      unsigned int *var_id = btf_var_ids->get (dvd);
-      if (var_id)
-	info.type = btf_absolute_var_id (*var_id);
-      else
-	continue;
-
-      info.size = 0;
-      tree size = DECL_SIZE_UNIT (node->decl);
-      if (tree_fits_uhwi_p (size))
-	info.size = tree_to_uhwi (size);
-      else if (VOID_TYPE_P (TREE_TYPE (node->decl)))
-	info.size = 1;
-
-      /* Offset is left as 0 at compile time, to be filled in by loaders such
-	 as libbpf.  */
-      info.offset = 0;
-
-      btf_datasec_push_entry (ctfc, section_name, info);
-    }
-
-  num_types_created += datasecs.length ();
-}
-
-/* Return true if the type ID is that of a type which will not be emitted (for
-   example, if it is not representable in BTF).  */
-
-static bool
-btf_removed_type_p (ctf_id_t id)
-{
-  return holes.contains (id);
-}
-
-/* Adjust the given type ID to account for holes and duplicate definitions of
-   void.  */
-
-static ctf_id_t
-btf_adjust_type_id (ctf_id_t id)
-{
-  size_t n;
-  ctf_id_t i = 0;
-
-  /* Do not adjust invalid type markers.  */
-  if (id == BTF_INVALID_TYPEID)
-    return id;
-
-  for (n = 0; n < voids.length (); n++)
-    if (id == voids[n])
-      return BTF_VOID_TYPEID;
-
-  for (n = 0; n < holes.length (); n++)
-    {
-      if (holes[n] < id)
-	i++;
-      else if (holes[n] == id)
-	return BTF_VOID_TYPEID;
-    }
-
-  return id - i;
-}
-
-/* Postprocessing callback routine for types.  */
-
-int
-btf_dtd_postprocess_cb (ctf_dtdef_ref *slot, ctf_container_ref arg_ctfc)
-{
-  ctf_dtdef_ref ctftype = (ctf_dtdef_ref) * slot;
-
-  size_t index = ctftype->dtd_type;
-  gcc_assert (index <= arg_ctfc->ctfc_types->elements ());
-
-  uint32_t ctf_kind, btf_kind;
-
-  ctf_kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
-  btf_kind = get_btf_kind (ctf_kind);
-
-  if (btf_kind == BTF_KIND_UNKN)
-    /* This type is not representable in BTF. Create a hole.  */
-    holes.safe_push (ctftype->dtd_type);
-
-  else if (btf_kind == BTF_KIND_INT && ctftype->dtd_data.ctti_size == 0)
-    {
-      /* This is a (redundant) definition of void.  */
-      voids.safe_push (ctftype->dtd_type);
-      holes.safe_push (ctftype->dtd_type);
-    }
-
-  arg_ctfc->ctfc_types_list[index] = ctftype;
-
-  return 1;
-}
-
-/* Preprocessing callback routine for variables.  */
-
-int
-btf_dvd_emit_preprocess_cb (ctf_dvdef_ref *slot, ctf_container_ref arg_ctfc)
-{
-  ctf_dvdef_ref var = (ctf_dvdef_ref) * slot;
-
-  /* If this is an extern variable declaration with a defining declaration
-     later, skip it so that only the defining declaration is emitted.
-     This is the same case, fix and reasoning as in CTF; see PR105089.  */
-  if (ctf_dvd_ignore_lookup (arg_ctfc, var->dvd_key))
-    return 1;
-
-  /* Do not add variables which refer to unsupported types.  */
-  if (!voids.contains (var->dvd_type->dtd_type)
-      && btf_removed_type_p (var->dvd_type->dtd_type))
-    return 1;
-
-  arg_ctfc->ctfc_vars_list[num_vars_added] = var;
-  btf_var_ids->put (var, num_vars_added);
-
-  num_vars_added++;
-  num_types_created++;
-
-  return 1;
-}
-
-/* Preprocessing callback routine for types.  */
-
-static void
-btf_dtd_emit_preprocess_cb (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
-{
-  if (!btf_emit_id_p (dtd->dtd_type))
-    return;
-
-  ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
-}
-
-/* Preprocess the CTF information to prepare for BTF output.  BTF is almost a
-   subset of CTF, with many small differences in encoding, and lacking support
-   for some types (notably floating point formats).
-
-   During the preprocessing pass:
-   - Ascertain that the sorted list of types has been prepared.  For the BTF
-     generation process, this is taken care of by the btf_init_postprocess ().
-
-   - BTF_KIND_FUNC and BTF_KIND_DATASEC records are constructed. These types do
-     not have analogues in CTF (the analogous type to CTF_K_FUNCTION is
-     BTF_KIND_FUNC_PROTO), but can be relatively easily deduced from CTF
-     information.
-
-   - Construct BTF_KIND_VAR records, representing variables.
-
-   - Calculate the total size in bytes of variable-length information following
-     BTF type records. This is used for outputting the BTF header.
-
-   After preprocessing, all BTF information is ready to be output:
-   - ctfc->ctfc_types_list holdstypes converted from CTF types. This does not
-     include KIND_VAR, KIND_FUNC, nor KIND_DATASEC types. These types have been
-     re-encoded to the appropriate representation in BTF.
-   - ctfc->ctfc_vars_list holds all variables which should be output.
-     Variables of unsupported types are not present in this list.
-   - Vector 'funcs' holds all BTF_KIND_FUNC types, one to match each
-     BTF_KIND_FUNC_PROTO.
-   - Vector 'datasecs' holds all BTF_KIND_DATASEC types.  */
-
-static void
-btf_emit_preprocess (ctf_container_ref ctfc)
-{
-  size_t num_ctf_types = ctfc->ctfc_types->elements ();
-  size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
-  size_t i;
-
-  if (num_ctf_types)
-    {
-      gcc_assert (ctfc->ctfc_types_list);
-      /* Preprocess the types.  */
-      for (i = 1; i <= num_ctf_types; i++)
-	btf_dtd_emit_preprocess_cb (ctfc, ctfc->ctfc_types_list[i]);
-    }
-
-  btf_var_ids = hash_map<ctf_dvdef_ref, unsigned int>::create_ggc (100);
-
-  if (num_ctf_vars)
-    {
-      /* Allocate and construct the list of variables. While BTF variables are
-	 not distinct from types (in that variables are simply types with
-	 BTF_KIND_VAR), it is simpler to maintain a separate list of variables
-	 and append them to the types list during output.  */
-      ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars);
-      ctfc->ctfc_vars->traverse<ctf_container_ref, btf_dvd_emit_preprocess_cb>
-	(ctfc);
-
-      ctfc->ctfc_num_vlen_bytes += (num_vars_added * sizeof (struct btf_var));
-    }
-
-  btf_collect_datasec (ctfc);
-}
-
 /* Return true iff DMD is a member description of a bit-field which can be
    validly represented in BTF.  */
 
 static bool
-btf_dmd_representable_bitfield_p (ctf_container_ref ctfc, ctf_dmdef_t *dmd)
+btf_dmd_representable_bitfield_p (ctf_dmdef_t *dmd)
 {
-  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
+  ctf_dtdef_ref ref_type = dmd->dmd_type;
+  if (!ref_type)
+    return false;
 
   if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
     {
@@ -739,76 +337,34 @@ btf_dmd_representable_bitfield_p (ctf_container_ref ctfc, ctf_dmdef_t *dmd)
 /* Asm'out a reference to another BTF type.  */
 
 static void
-btf_asm_type_ref (const char *prefix, ctf_container_ref ctfc, ctf_id_t ctf_id)
+btf_asm_type_ref (const char *prefix, ctf_dtdef_ref dtd)
 {
-  ctf_id_t btf_id = get_btf_id (ctf_id);
-  if (btf_id == BTF_VOID_TYPEID || btf_id == BTF_INVALID_TYPEID)
-    {
-      /* There is no explicit void type.
-	 Also handle any invalid refs that made it this far, just in case.  */
-      dw2_asm_output_data (4, btf_id, "%s: void", prefix);
-    }
+  if (!dtd || !btf_emit_type_p (dtd))
+    dw2_asm_output_data (4, BTF_VOID_TYPEID, "%s: void", prefix);
   else
     {
-      gcc_assert (btf_id <= num_types_added);
-
-      /* Ref to a standard type in the types list.  Note: take care that we
-	 must index the type list by the original CTF id, not the BTF id.  */
-      ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[ctf_id];
-      uint32_t ref_kind
-	= get_btf_kind (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info));
-
-      const char *kind_name = btf_fwd_to_enum_p (ref_type)
-	? btf_kind_name (BTF_KIND_ENUM)
-	: btf_kind_name (ref_kind);
-
-      dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_%s '%s')",
-			   prefix, kind_name,
-			   get_btf_type_name (ref_type));
+      uint32_t kind = btf_dtd_kind (dtd);
+      if (btf_fwd_to_enum_p (dtd))
+	kind = BTF_KIND_ENUM;
+      else if (kind == BTF_KIND_FUNC_PROTO && dtd->dtd_type > max_translated_id)
+	kind = BTF_KIND_FUNC;
+
+      dw2_asm_output_data (4, dtd->dtd_type, "%s: (BTF_KIND_%s '%s')",
+			   prefix, btf_kind_name (kind),
+			   get_btf_type_name (dtd));
     }
 }
 
-/* Asm'out a reference to a BTF_KIND_VAR or BTF_KIND_FUNC type.  These type
-   kinds are BTF-specific, and should only be referred to by entries in
-   BTF_KIND_DATASEC records.  */
-
-static void
-btf_asm_datasec_type_ref (const char *prefix, ctf_container_ref ctfc,
-			  ctf_id_t btf_id)
-{
-  if (btf_id >= num_types_added + 1
-      && btf_id < num_types_added + num_vars_added + 1)
-    {
-      /* Ref to a variable.  Should only appear in DATASEC entries.  */
-      ctf_id_t var_id = btf_relative_var_id (btf_id);
-      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[var_id];
-      dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_VAR '%s')",
-			   prefix, dvd->dvd_name);
-
-    }
-  else if (btf_id >= num_types_added + num_vars_added + 1)
-    {
-      /* Ref to a FUNC record.  */
-      size_t func_id = btf_relative_func_id (btf_id);
-      ctf_dtdef_ref ref_type = (*funcs)[func_id];
-      dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_FUNC '%s')",
-			   prefix, get_btf_type_name (ref_type));
-    }
-  else
-    /* The caller should not be calling this.  */
-    gcc_unreachable ();
-}
-
 /* Asm'out a BTF type. This routine is responsible for the bulk of the task
    of converting CTF types to their BTF representation.  */
 
 static void
-btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+btf_asm_type (ctf_dtdef_ref dtd)
 {
   uint32_t btf_kind, btf_kflag, btf_vlen, btf_size;
   uint32_t ctf_info = dtd->dtd_data.ctti_info;
 
-  btf_kind = get_btf_kind (CTF_V2_INFO_KIND (ctf_info));
+  btf_kind = btf_dtd_kind (dtd);
   btf_size = dtd->dtd_data.ctti_size;
   btf_vlen = CTF_V2_INFO_VLEN (ctf_info);
 
@@ -827,17 +383,17 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
 
   if (btf_kind == BTF_KIND_STRUCT || btf_kind == BTF_KIND_UNION)
     {
-      /* If a struct/union has ANY bitfield members, set kflag=1.
-	 Note that we must also change the encoding of every member to encode
-	 both member bitfield size (stealing most-significant 8 bits) and bit
-	 offset (LS 24 bits). This is done during preprocessing.  */
+      /* If a struct/union has ANY bitfield members, set kflag=1.  */
       ctf_dmdef_t *dmd;
       for (dmd = dtd->dtd_u.dtu_members;
 	   dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
 	{
 	  /* Set kflag if this member is a representable bitfield.  */
-	  if (btf_dmd_representable_bitfield_p (ctfc, dmd))
-	    btf_kflag = 1;
+	  if (btf_dmd_representable_bitfield_p (dmd))
+	    {
+	      btf_kflag = 1;
+	      break;
+	    }
 	}
     }
 
@@ -871,7 +427,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
 		    : BTF_KF_ENUM_SIGNED;
       if (dtd->dtd_data.ctti_size == 0x8)
 	btf_kind = BTF_KIND_ENUM64;
-   }
+    }
 
   /* PR debug/112656.  BTF_KIND_FUNC_PROTO is always anonymous.  */
   else if (btf_kind == BTF_KIND_FUNC_PROTO)
@@ -879,7 +435,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
 
   dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
 		       "TYPE %" PRIu64 " BTF_KIND_%s '%s'",
-		       get_btf_id (dtd->dtd_type), btf_kind_name (btf_kind),
+		       dtd->dtd_type, btf_kind_name (btf_kind),
 		       get_btf_type_name (dtd));
   dw2_asm_output_data (4, BTF_TYPE_INFO (btf_kind, btf_kflag, btf_vlen),
 		       "btt_info: kind=%u, kflag=%u, vlen=%u",
@@ -905,30 +461,29 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
       break;
     }
 
-  ctf_id_t ref_id = dtd->dtd_data.ctti_type;
-  btf_asm_type_ref ("btt_type", ctfc, ref_id);
+  btf_asm_type_ref ("btt_type", dtd->ref_type);
 }
 
 /* Asm'out the variable information following a BTF_KIND_ARRAY.  */
 
 static void
-btf_asm_array (ctf_container_ref ctfc, ctf_arinfo_t arr)
+btf_asm_array (ctf_arinfo_t arr)
 {
-  btf_asm_type_ref ("bta_elem_type", ctfc, arr.ctr_contents->dtd_type);
-  btf_asm_type_ref ("bta_index_type", ctfc, arr.ctr_index->dtd_type);
+  btf_asm_type_ref ("bta_elem_type", arr.ctr_contents);
+  btf_asm_type_ref ("bta_index_type", arr.ctr_index);
   dw2_asm_output_data (4, arr.ctr_nelems, "bta_nelems");
 }
 
 /* Asm'out a BTF_KIND_VAR.  */
 
 static void
-btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
+btf_asm_varent (ctf_dvdef_ref var)
 {
-  dw2_asm_output_data (4, var->dvd_name_offset, "TYPE %u BTF_KIND_VAR '%s'",
-		       (*(btf_var_ids->get (var)) + num_types_added + 1),
-		       var->dvd_name);
+  dw2_asm_output_data (4, var->dvd_name_offset,
+                       "TYPE %" PRIu64 " BTF_KIND_VAR '%s'",
+                       var->dvd_id, var->dvd_name);
   dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_VAR, 0, 0), "btv_info");
-  btf_asm_type_ref ("btv_type", ctfc, var->dvd_type->dtd_type);
+  btf_asm_type_ref ("btv_type", var->dvd_type);
   dw2_asm_output_data (4, var->dvd_visibility, "btv_linkage");
 }
 
@@ -936,23 +491,22 @@ btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
    BTF_KIND_UNION.  */
 
 static void
-btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
+btf_asm_sou_member (ctf_dmdef_t * dmd, unsigned int idx)
 {
-  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
-  ctf_id_t base_type = dmd->dmd_type->dtd_type;
+  ctf_dtdef_ref base_type = dmd->dmd_type;
   uint64_t sou_offset = dmd->dmd_offset;
 
   dw2_asm_output_data (4, dmd->dmd_name_offset,
 		       "MEMBER '%s' idx=%u",
 		       dmd->dmd_name, idx);
 
-  /* Re-encode bitfields to BTF representation.  */
-  if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
+  if (base_type
+      && CTF_V2_INFO_KIND (base_type->dtd_data.ctti_info) == CTF_K_SLICE)
     {
-      if (btf_dmd_representable_bitfield_p (ctfc, dmd))
+      if (btf_dmd_representable_bitfield_p (dmd))
 	{
-	  unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset;
-	  unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits;
+	  unsigned short word_offset = base_type->dtd_u.dtu_slice.cts_offset;
+	  unsigned short bits = base_type->dtd_u.dtu_slice.cts_bits;
 
 	  /* Pack the bit offset and bitfield size together.  */
 	  sou_offset += word_offset;
@@ -960,17 +514,17 @@ btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
 	  sou_offset |= ((bits & 0xff) << 24);
 
 	  /* Refer to the base type of the slice.  */
-	  base_type = ref_type->dtd_u.dtu_slice.cts_type->dtd_type;
+	  base_type = base_type->dtd_u.dtu_slice.cts_type;
 	}
       else
 	{
 	  /* Bitfield cannot be represented in BTF.  Emit the member as having
 	     'void' type.  */
-	  base_type = BTF_VOID_TYPEID;
+	  base_type = NULL;
 	}
     }
 
-  btf_asm_type_ref ("btm_type", ctfc, base_type);
+  btf_asm_type_ref ("btm_type", base_type);
   dw2_asm_output_data (4, sou_offset, "btm_offset");
 }
 
@@ -993,86 +547,68 @@ btf_asm_enum_const (unsigned int size, ctf_dmdef_t * dmd, unsigned int idx)
 /* Asm'out a function parameter description following a BTF_KIND_FUNC_PROTO.  */
 
 static void
-btf_asm_func_arg (ctf_container_ref ctfc, ctf_func_arg_t * farg,
-		  size_t stroffset)
+btf_asm_func_arg (ctf_func_arg_t * farg, size_t stroffset)
 {
   /* If the function arg does not have a name, refer to the null string at
      the start of the string table. This ensures correct encoding for varargs
      '...' arguments.  */
   if ((farg->farg_name != NULL) && strcmp (farg->farg_name, ""))
-    dw2_asm_output_data (4, farg->farg_name_offset + stroffset, "farg_name");
+    dw2_asm_output_data (4, farg->farg_name_offset + stroffset,
+			 "farg_name '%s'", farg->farg_name);
   else
-    dw2_asm_output_data (4, 0, "farg_name");
-
-  ctf_id_t ref_id = BTF_VOID_TYPEID;
-  if (farg->farg_type && !btf_removed_type_p (farg->farg_type->dtd_type))
-    ref_id = farg->farg_type->dtd_type;
+    dw2_asm_output_data (4, 0, "farg_name ''");
 
-  btf_asm_type_ref ("farg_type", ctfc, ref_id);
+  btf_asm_type_ref ("farg_type", farg->farg_type);
 }
 
 /* Asm'out a BTF_KIND_FUNC type.  */
 
 static void
-btf_asm_func_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd, ctf_id_t id)
+btf_asm_func_type (ctf_dtdef_ref dtd)
 {
-  ctf_id_t ref_id = dtd->dtd_data.ctti_type;
   dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
 		       "TYPE %" PRIu64 " BTF_KIND_FUNC '%s'",
-		       btf_absolute_func_id (id), get_btf_type_name (dtd));
+		       dtd->dtd_type, get_btf_type_name (dtd));
   dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_FUNC, 0, dtd->linkage),
 		       "btt_info: kind=%u, kflag=%u, linkage=%u",
 		       BTF_KIND_FUNC, 0, dtd->linkage);
-  btf_asm_type_ref ("btt_type", ctfc, ref_id);
+  btf_asm_type_ref ("btt_type", dtd->ref_type);
 }
 
-/* Collect the name for the DATASEC reference required to be output as a
-   symbol. */
+/* Asm'out a variable entry following a BTF_KIND_DATASEC.  */
 
-static const char *
-get_name_for_datasec_entry (ctf_container_ref ctfc, ctf_id_t ref_id)
+static void
+btf_asm_datasec_entry (struct btf_datasec_entry entry)
 {
-  if (ref_id >= num_types_added + 1
-      && ref_id < num_types_added + num_vars_added + 1)
+  const char *symbol_name = NULL;
+  if (entry.is_var)
     {
-      /* Ref to a variable.  Should only appear in DATASEC entries.  */
-      ctf_id_t var_id = btf_relative_var_id (ref_id);
-      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[var_id];
-      return dvd->dvd_name;
+      symbol_name = entry.dvd->dvd_name;
+      dw2_asm_output_data (4, entry.dvd->dvd_id,
+			   "bts_type: (BTF_KIND_VAR '%s')", symbol_name);
     }
-  else if (ref_id >= num_types_added + num_vars_added + 1)
+  else
     {
-      /* Ref to a FUNC record.  */
-      size_t func_id = btf_relative_func_id (ref_id);
-      ctf_dtdef_ref ref_type = (*funcs)[func_id];
-      return get_btf_type_name (ref_type);
+      symbol_name = entry.dtd->dtd_name;
+      btf_asm_type_ref ("bts_type", entry.dtd);
     }
-  return NULL;
-}
-
-/* Asm'out a variable entry following a BTF_KIND_DATASEC.  */
 
-static void
-btf_asm_datasec_entry (ctf_container_ref ctfc, struct btf_var_secinfo info)
-{
-  const char *symbol_name = get_name_for_datasec_entry (ctfc, info.type);
-  btf_asm_datasec_type_ref ("bts_type", ctfc, info.type);
   if (!btf_with_core_debuginfo_p () || symbol_name == NULL)
-    dw2_asm_output_data (4, info.offset, "bts_offset");
+    dw2_asm_output_data (4, 0, "bts_offset");
   else
     dw2_asm_output_offset (4, symbol_name, NULL, "bts_offset");
-  dw2_asm_output_data (4, info.size, "bts_size");
+
+  dw2_asm_output_data (4, entry.size, "bts_size");
 }
 
 /* Asm'out a whole BTF_KIND_DATASEC, including its variable entries.  */
 
 static void
-btf_asm_datasec_type (ctf_container_ref ctfc, btf_datasec_t ds, ctf_id_t id,
-		      size_t stroffset)
+btf_asm_datasec_type (btf_datasec_t ds)
 {
-  dw2_asm_output_data (4, ds.name_offset + stroffset,
+  dw2_asm_output_data (4, ds.name_offset,
 		       "TYPE %" PRIu64 " BTF_KIND_DATASEC '%s'",
-		       btf_absolute_datasec_id (id), ds.name);
+		       ds.id, ds.name);
   dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_DATASEC, 0,
 					 ds.entries.length ()),
 		       "btt_info: n_entries=%u", ds.entries.length ());
@@ -1080,7 +616,7 @@ btf_asm_datasec_type (ctf_container_ref ctfc, btf_datasec_t ds, ctf_id_t id,
      loaders such as libbpf.  */
   dw2_asm_output_data (4, 0, "btt_size");
   for (size_t i = 0; i < ds.entries.length (); i++)
-    btf_asm_datasec_entry (ctfc, ds.entries[i]);
+    btf_asm_datasec_entry (ds.entries[i]);
 }
 
 /* Compute and output the header information for a .BTF section.  */
@@ -1099,20 +635,11 @@ output_btf_header (ctf_container_ref ctfc)
 
    uint32_t type_off = 0, type_len = 0;
    uint32_t str_off = 0, str_len = 0;
-   uint32_t datasec_vlen_bytes = 0;
 
    if (!ctfc_is_empty_container (ctfc))
      {
-       for (size_t i = 0; i < datasecs.length (); i++)
-	 {
-	   datasec_vlen_bytes += ((datasecs[i].entries.length ())
-				  * sizeof (struct btf_var_secinfo));
-	 }
-
        /* Total length (bytes) of the types section.  */
-       type_len = (num_types_added * sizeof (struct btf_type))
-	 + (num_types_created * sizeof (struct btf_type))
-	 + datasec_vlen_bytes
+       type_len = ctfc->ctfc_num_types * sizeof (struct btf_type)
 	 + ctfc->ctfc_num_vlen_bytes;
 
        str_off = type_off + type_len;
@@ -1124,7 +651,9 @@ output_btf_header (ctf_container_ref ctfc)
    /* Offset of type section.  */
    dw2_asm_output_data (4, type_off, "type_off");
    /* Length of type section in bytes.  */
-   dw2_asm_output_data (4, type_len, "type_len");
+   dw2_asm_output_data (4, type_len, "type_len: ntypes=%u, vlen=%u",
+			(uint32_t) ctfc->ctfc_num_types,
+			(uint32_t) ctfc->ctfc_num_vlen_bytes);
     /* Offset of string section.  */
    dw2_asm_output_data (4, str_off, "str_off");
     /* Length of string section in bytes.  */
@@ -1137,11 +666,11 @@ static void
 output_btf_vars (ctf_container_ref ctfc)
 {
   size_t i;
-  size_t num_ctf_vars = num_vars_added;
+  size_t num_ctf_vars = ctfc->ctfc_vars_list_count;
   if (num_ctf_vars)
     {
       for (i = 0; i < num_ctf_vars; i++)
-	btf_asm_varent (ctfc, ctfc->ctfc_vars_list[i]);
+	btf_asm_varent (ctfc->ctfc_vars_list[i]);
     }
 }
 
@@ -1156,7 +685,8 @@ output_btf_strs (ctf_container_ref ctfc)
 
   while (ctf_string)
     {
-      dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_string, str_pos = 0x%x", str_pos);
+      dw2_asm_output_nstring (ctf_string->cts_str, -1,
+			      "btf_string, str_pos = 0x%x", str_pos);
       str_pos += strlen(ctf_string->cts_str) + 1;
       ctf_string = ctf_string->cts_next;
     }
@@ -1164,7 +694,8 @@ output_btf_strs (ctf_container_ref ctfc)
   ctf_string = ctfc->ctfc_aux_strtable.ctstab_head;
   while (ctf_string)
     {
-      dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_aux_string, str_pos = 0x%x", str_pos);
+      dw2_asm_output_nstring (ctf_string->cts_str, -1,
+			      "btf_aux_string, str_pos = 0x%x", str_pos);
       str_pos += strlen(ctf_string->cts_str) + 1;
       ctf_string = ctf_string->cts_next;
     }
@@ -1174,7 +705,7 @@ output_btf_strs (ctf_container_ref ctfc)
    BTF_KIND_UNION type.  */
 
 static void
-output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+output_asm_btf_sou_fields (ctf_dtdef_ref dtd)
 {
   ctf_dmdef_t * dmd;
 
@@ -1182,7 +713,7 @@ output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
   for (dmd = dtd->dtd_u.dtu_members;
        dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
     {
-      btf_asm_sou_member (ctfc, dmd, idx);
+      btf_asm_sou_member (dmd, idx);
       idx++;
     }
 }
@@ -1190,8 +721,7 @@ output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
 /* Output all enumerator constants following a BTF_KIND_ENUM{,64}.  */
 
 static void
-output_asm_btf_enum_list (ctf_container_ref ARG_UNUSED (ctfc),
-			  ctf_dtdef_ref dtd)
+output_asm_btf_enum_list (ctf_dtdef_ref dtd)
 {
   ctf_dmdef_t * dmd;
 
@@ -1214,7 +744,7 @@ output_asm_btf_func_args_list (ctf_container_ref ctfc,
   ctf_func_arg_t * farg;
   for (farg = dtd->dtd_u.dtu_argv;
        farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
-    btf_asm_func_arg (ctfc, farg, farg_name_offset);
+    btf_asm_func_arg (farg, farg_name_offset);
 }
 
 /* Output the variable portion of a BTF type record. The information depends
@@ -1225,7 +755,7 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
 {
   uint32_t btf_kind, encoding;
 
-  btf_kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
+  btf_kind = btf_dtd_kind (dtd);
 
   if (btf_kind == BTF_KIND_UNKN)
     return;
@@ -1238,8 +768,7 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
       if (dtd->dtd_data.ctti_size < 1)
 	break;
 
-      /* In BTF the CHAR `encoding' seems to not be used, so clear it
-         here.  */
+      /* In BTF the CHAR `encoding' seems to not be used, so clear it here.  */
       dtd->dtd_u.dtu_enc.cte_format &= ~BTF_INT_CHAR;
 
       encoding = BTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
@@ -1250,16 +779,16 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
       break;
 
     case BTF_KIND_ARRAY:
-      btf_asm_array (ctfc, dtd->dtd_u.dtu_arr);
+      btf_asm_array (dtd->dtd_u.dtu_arr);
       break;
 
     case BTF_KIND_STRUCT:
     case BTF_KIND_UNION:
-      output_asm_btf_sou_fields (ctfc, dtd);
+      output_asm_btf_sou_fields (dtd);
       break;
 
     case BTF_KIND_ENUM:
-      output_asm_btf_enum_list (ctfc, dtd);
+      output_asm_btf_enum_list (dtd);
       break;
 
     case BTF_KIND_FUNC_PROTO:
@@ -1289,9 +818,9 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
 static void
 output_asm_btf_type (ctf_container_ref ctfc, ctf_dtdef_ref type)
 {
-  if (btf_emit_id_p (type->dtd_type))
+  if (btf_emit_type_p (type))
     {
-      btf_asm_type (ctfc, type);
+      btf_asm_type (type);
       output_asm_btf_vlen_bytes (ctfc, type);
     }
 }
@@ -1303,7 +832,9 @@ static void
 output_btf_types (ctf_container_ref ctfc)
 {
   size_t i;
-  size_t num_types = ctfc->ctfc_types->elements ();
+  size_t num_types;
+  num_types = ctfc->ctfc_types->elements ();
+
   if (num_types)
     {
       for (i = 1; i <= num_types; i++)
@@ -1314,76 +845,45 @@ output_btf_types (ctf_container_ref ctfc)
 /* Output all BTF_KIND_FUNC type records.  */
 
 static void
-output_btf_func_types (ctf_container_ref ctfc)
+output_btf_func_types (void)
 {
   ctf_dtdef_ref ref;
   unsigned i;
   FOR_EACH_VEC_ELT (*funcs, i, ref)
-    btf_asm_func_type (ctfc, ref, i);
+    btf_asm_func_type (ref);
 }
 
 /* Output all BTF_KIND_DATASEC records.  */
 
 static void
-output_btf_datasec_types (ctf_container_ref ctfc)
+output_btf_datasec_types (void)
 {
-  size_t name_offset = ctfc_get_strtab_len (ctfc, CTF_STRTAB);
-
-  for (size_t i = 0; i < datasecs.length(); i++)
-    btf_asm_datasec_type (ctfc, datasecs[i], i, name_offset);
+  for (size_t i = 0; i < datasecs.length (); i++)
+    btf_asm_datasec_type (datasecs[i]);
 }
 
-/* Postprocess the CTF debug data post initialization.
-
-   During the postprocess pass:
-
-   - Prepare the sorted list of BTF types.
-
-     The sorted list of BTF types is, firstly, used for lookup (during the BTF
-     generation process) of CTF/BTF types given a typeID.
-
-     Secondly, in the emitted BTF section, BTF Types need to be in the sorted
-     order of their type IDs.  The BTF types section is viewed as an array,
-     with type IDs used to index into that array.  It is essential that every
-     type be placed at the exact index corresponding to its ID, or else
-     references to that type from other types will no longer be correct.
-
-   - References to void types are converted to reference BTF_VOID_TYPEID. In
-     CTF, a distinct type is used to encode void.
-
-   - Bitfield struct/union members are converted to BTF encoding. CTF uses
-     slices to encode bitfields, but BTF does not have slices and encodes
-     bitfield information directly in the variable-length btf_member
-     descriptions following the struct or union type.
-
-   - Unrepresentable types are removed. We cannot have any invalid BTF types
-     appearing in the output so they must be removed, and type ids of other
-     types and references adjust accordingly. This also involves ensuring that
-     BTF descriptions of struct members referring to unrepresentable types are
-     not emitted, as they would be nonsensical.
-
-   - Adjust inner- and inter-type references-by-ID to account for removed
-     types, and construct the types list.  */
+/* Write out all BTF debug info.  */
 
 void
-btf_init_postprocess (void)
+btf_output (ctf_container_ref ctfc)
 {
-  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
-
-  holes.create (0);
-  voids.create (0);
+  output_btf_header (ctfc);
+  output_btf_types (ctfc);
+  output_btf_vars (ctfc);
+  output_btf_func_types ();
+  output_btf_datasec_types ();
+  output_btf_strs (ctfc);
+}
 
-  num_types_added = 0;
-  num_types_created = 0;
+/* Workaround for 'const void' variables.  These variables are sometimes used
+   in eBPF programs to address kernel symbols.  DWARF does not generate const
+   qualifier on void type, so we would incorrectly emit these variables
+   without the const qualifier.  Find any such variables, and update them to
+   refer to a new 'const' modifier type for void.  */
 
-  /* Workaround for 'const void' variables.  These variables are sometimes used
-     in eBPF programs to address kernel symbols.  DWARF does not generate const
-     qualifier on void type, so we would incorrectly emit these variables
-     without the const qualifier.
-     Unfortunately we need the TREE node to know it was const, and we need
-     to create the const modifier type (if needed) now, before making the types
-     list.  So we can't avoid iterating with FOR_EACH_VARIABLE here, and then
-     again when creating the DATASEC entries.  */
+static void
+btf_early_add_const_void (ctf_container_ref ctfc)
+{
   ctf_dtdef_ref constvoid_dtd = NULL;
   varpool_node *var;
   FOR_EACH_VARIABLE (var)
@@ -1398,120 +898,389 @@ btf_init_postprocess (void)
 	  if (die == NULL)
 	    continue;
 
-	  ctf_dvdef_ref dvd = ctf_dvd_lookup (tu_ctfc, die);
+	  ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
 	  if (dvd == NULL)
 	    continue;
 
 	  /* Create the 'const' modifier type for void.  */
 	  if (constvoid_dtd == NULL)
-            constvoid_dtd = ctf_add_reftype (tu_ctfc, CTF_ADD_ROOT,
-                                             dvd->dvd_type, CTF_K_CONST, NULL);
+	    constvoid_dtd = ctf_add_reftype (ctfc, CTF_ADD_ROOT,
+					     dvd->dvd_type, CTF_K_CONST, NULL);
 	  dvd->dvd_type = constvoid_dtd;
 	}
     }
+}
 
-  size_t i;
-  size_t num_ctf_types = tu_ctfc->ctfc_types->elements ();
+/* Functions actually get two type records: a BTF_KIND_FUNC_PROTO, and also a
+   BTF_KIND_FUNC.  But the CTF container only allocates one type per function,
+   which matches closely with BTF_KIND_FUNC_PROTO.  For each such function,
+   construct a BTF_KIND_FUNC entry.  This is done early, because we want FUNC
+   records even for functions which are later inlined by optimizations.  */
 
-  if (num_ctf_types)
+static void
+btf_early_add_func_records (ctf_container_ref ctfc)
+{
+  cgraph_node *func;
+  FOR_EACH_FUNCTION (func)
     {
-      init_btf_id_map (num_ctf_types + 1);
-
-      /* Allocate the types list and traverse all types, placing each type
-	 at the index according to its ID.  Add 1 because type ID 0 always
-	 represents VOID.  */
-      tu_ctfc->ctfc_types_list
-	= ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1);
-      tu_ctfc->ctfc_types->traverse<ctf_container_ref, btf_dtd_postprocess_cb>
-	(tu_ctfc);
-
-      /* Build mapping of CTF type ID -> BTF type ID, and count total number
-	 of valid BTF types added.  */
-      for (i = 1; i <= num_ctf_types; i++)
-	{
-	  ctf_dtdef_ref dtd = tu_ctfc->ctfc_types_list[i];
-	  ctf_id_t btfid = btf_adjust_type_id (dtd->dtd_type);
-	  set_btf_id (dtd->dtd_type, btfid);
-	  if (btfid < BTF_MAX_TYPE && (btfid != BTF_VOID_TYPEID))
-	    num_types_added ++;
-	}
+      dw_die_ref die = lookup_decl_die (func->decl);
+      if (die == NULL)
+	continue;
+
+      ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
+      if (dtd == NULL)
+	continue;
+
+      /* Do not add FUNC records for kernel helpers.  */
+      if (DECL_EXTERNAL (func->decl)
+	  && (lookup_attribute ("kernel_helper",
+				DECL_ATTRIBUTES (func->decl))) != NULL_TREE)
+	continue;
+
+      ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
+      func_dtd->dtd_data = dtd->dtd_data;
+      func_dtd->dtd_data.ctti_type = dtd->dtd_type;
+      func_dtd->ref_type = dtd;
+      func_dtd->linkage = dtd->linkage;
+      func_dtd->dtd_name = dtd->dtd_name;
+      /* Type ID will be assigned just before output.  */
+
+      /* Only the BTF_KIND_FUNC type actually references the name. The
+	 BTF_KIND_FUNC_PROTO is always anonymous.  */
+      dtd->dtd_data.ctti_name = 0;
+
+      /* Mark 'extern' funcs.  */
+      if (DECL_EXTERNAL (func->decl))
+	func_dtd->linkage = BTF_FUNC_EXTERN;
+
+      /* Buffer newly created FUNC records.  We cannot simply insert them
+	 into the types map, because types are keyed by their DWARF DIE,
+	 and we have no unique DIE to use as a key since the FUNC_PROTOs
+	 are already present in the map.  */
+      vec_safe_push (funcs, func_dtd);
+      func_map->put (dtd, func_dtd);
     }
 }
 
-/* Process and output all BTF data. Entry point of btfout.  */
+/* Initial entry point of BTF generation, called at early_finish () after
+   CTF information has possibly been output.  Translate all CTF information
+   to BTF, and do any processing that must be done early, such as creating
+   BTF_KIND_FUNC records.  */
 
 void
-btf_output (const char * filename)
+btf_early_finish (void)
 {
   ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
 
-  init_btf_sections ();
-
-  datasecs.create (0);
   vec_alloc (funcs, 16);
+  func_map = hash_map<ctf_dtdef_ref, ctf_dtdef_ref>::create_ggc (16);
+
+  btf_early_add_const_void (tu_ctfc);
+  btf_early_add_func_records (tu_ctfc);
+}
+
+/* Push a BTF datasec entry ENTRY into the datasec named SECNAME,
+   creating the datasec record if it does not already exist.  */
+
+static void
+btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
+			struct btf_datasec_entry entry)
+{
+  if (secname == NULL)
+    return;
+
+  /* If we already have a datasec record for the appropriate section,
+     append the new entry to it.  */
+  for (size_t i = 0; i < datasecs.length (); i++)
+    if (strcmp (datasecs[i].name, secname) == 0)
+      {
+	datasecs[i].entries.safe_push (entry);
+	return;
+      }
+
+  /* If we don't already have a datasec record for secname, make one.  */
+  uint32_t str_off;
+  ctf_add_string (ctfc, secname, &str_off, CTF_AUX_STRTAB);
+  if (strcmp (secname, ""))
+    ctfc->ctfc_aux_strlen += strlen (secname) + 1;
 
-  ctf_add_cuname (tu_ctfc, filename);
+  /* Note: ID will be assigned just before output.  */
+  btf_datasec_t ds;
+  ds.name = secname;
+  ds.name_offset = str_off;
 
-  btf_emit_preprocess (tu_ctfc);
+  /* Insert the entry into the new datasec record.  */
+  ds.entries.create (1);
+  ds.entries.quick_push (entry);
 
-  output_btf_header (tu_ctfc);
-  output_btf_types (tu_ctfc);
-  output_btf_vars (tu_ctfc);
-  output_btf_func_types (tu_ctfc);
-  output_btf_datasec_types (tu_ctfc);
-  output_btf_strs (tu_ctfc);
+  /* Insert the datasec record itself.  */
+  datasecs.safe_push (ds);
 }
 
-/* Reset all state for BTF generation so that we can rerun the compiler within
-   the same process.  */
+/* Create a datasec entry for a function, and insert it into the datasec
+   record for the appropriate section.  Create the record if it does not
+   yet exist.  */
 
-void
-btf_finalize (void)
+static void
+btf_datasec_add_func (ctf_container_ref ctfc, cgraph_node *func,
+		      ctf_dtdef_ref func_dtd)
 {
-  btf_info_section = NULL;
+  const char *section_name = get_section_name (func);
 
-  /* Clear preprocessing state.  */
-  num_vars_added = 0;
-  num_types_added = 0;
-  num_types_created = 0;
+  /* Note: get_section_name () returns NULL for functions in text
+     section.  This is intentional, since we do not want to generate
+     DATASEC entries for them.  */
+  if (section_name == NULL)
+    return;
 
-  holes.release ();
-  voids.release ();
-  for (size_t i = 0; i < datasecs.length (); i++)
-    datasecs[i].entries.release ();
-  datasecs.release ();
+  struct btf_datasec_entry entry;
+  gcc_assert (func_dtd);
+  entry.dtd = func_dtd;
+  entry.is_var = false;
 
-  funcs = NULL;
+  /* Size is left as zero at compile time, to be filled in by loaders
+     such as libbpf.  */
+  entry.size = 0;
 
-  btf_var_ids->empty ();
-  btf_var_ids = NULL;
+  btf_datasec_push_entry (ctfc, section_name, entry);
+}
 
-  free (btf_id_map);
-  btf_id_map = NULL;
+/* Create a datasec entry for a variable, and insert it into the datasec
+   record for the appropriate section.  Create the record if it does not
+   yet exist.  */
 
-  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
-  ctfc_delete_container (tu_ctfc);
-  tu_ctfc = NULL;
+static void
+btf_datasec_add_var (ctf_container_ref ctfc, varpool_node *var,
+		     ctf_dvdef_ref dvd)
+{
+  /* PR112849: avoid assuming a section for extern decls without
+     an explicit section, which would result in incorrectly
+     emitting a BTF_KIND_DATASEC entry for them.  */
+  if (DECL_EXTERNAL (var->decl) && var->get_section () == NULL)
+    return;
+
+  const char *section_name = get_section_name (var);
+  if (section_name == NULL)
+    return;
+
+  gcc_assert (dvd);
+  struct btf_datasec_entry entry;
+  entry.dvd = dvd;
+  entry.is_var = true;
+  entry.size = 0;
+
+  tree size = DECL_SIZE_UNIT (var->decl);
+  if (tree_fits_uhwi_p (size))
+    entry.size = tree_to_uhwi (size);
+  else if (VOID_TYPE_P (TREE_TYPE (var->decl)))
+    entry.size = 1;
+
+  btf_datasec_push_entry (ctfc, section_name, entry);
 }
 
-/* Initial entry point of BTF generation, called at early_finish () after
-   CTF information has possibly been output.  Translate all CTF information
-   to BTF, and do any processing that must be done early, such as creating
-   BTF_KIND_FUNC records.  */
+/* Add datasec entries for functions to CTFC.  */
 
-void
-btf_early_finish (void)
+static void
+btf_late_add_func_datasec_entries (ctf_container_ref ctfc)
+{
+  /* We need to create FUNC records at early_finish, so that we have them
+     even for functions which are later inlined by optimization passes.
+     But on the other hand, we do not want datasec entries for such functions,
+     so only create the datasec entries for them late.  This loop will not
+     hit functions which have already been inlined.  */
+  cgraph_node *func;
+  FOR_EACH_FUNCTION (func)
+    {
+      dw_die_ref die = lookup_decl_die (func->decl);
+      if (die == NULL)
+	continue;
+
+      ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
+      if (dtd == NULL)
+	continue;
+
+      ctf_dtdef_ref *pdtd = func_map->get (dtd);
+      if (pdtd && DECL_EXTERNAL (func->decl))
+	btf_datasec_add_func (ctfc, func, *pdtd);
+    }
+}
+
+/* Helper function used to determine whether or not a BTF_KIND_VAR record
+   for the variable VAR shall be emitted.  */
+
+static bool
+btf_emit_variable_p (ctf_container_ref ctfc, varpool_node *var,
+		     ctf_dvdef_ref *pdvd)
+{
+  dw_die_ref die = lookup_decl_die (var->decl);
+  if (die == NULL)
+    return false;
+
+  ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
+  if (dvd == NULL)
+    return false;
+
+  /* If this is an extern variable declaration with a defining declaration
+     later, skip it so that only the defining declaration is emitted.
+     This is the same case, fix and reasoning as in CTF; see PR105089.  */
+  if (ctf_dvd_ignore_lookup (ctfc, dvd->dvd_key))
+    return false;
+
+  /* Skip variables with unrepresentable types.  */
+  if (!btf_emit_type_p (dvd->dvd_type))
+    return false;
+
+  *pdvd = dvd;
+  return true;
+}
+
+/* Add BTF_KIND_VAR records for variables.  */
+
+static void
+btf_late_add_vars (ctf_container_ref ctfc)
+{
+  size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
+
+  ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars);
+
+  varpool_node *var;
+  ctf_dvdef_ref dvd;
+  FOR_EACH_VARIABLE (var)
+    {
+      if (!btf_emit_variable_p (ctfc, var, &dvd))
+	continue;
+
+      /* Mark 'extern' variables.  */
+      if (DECL_EXTERNAL (var->decl))
+	dvd->dvd_visibility = BTF_VAR_GLOBAL_EXTERN;
+
+      /* Add the variable to the vars list.  */
+      ctfc->ctfc_vars_list[ctfc->ctfc_vars_list_count++] = dvd;
+
+      /* Add a BTF_KIND_DATASEC entry for the variable.  */
+      btf_datasec_add_var (ctfc, var, dvd);
+    }
+}
+
+/* Callback used by btf_late_assign_type_ids to insert types into their initial
+   positions in the type list.  */
+
+static int
+btf_type_list_cb (ctf_dtdef_ref *slot, ctf_container_ref ctfc)
+{
+  ctf_dtdef_ref dtd = *slot;
+  ctfc->ctfc_types_list[dtd->dtd_type] = dtd;
+  return 1;
+}
+
+/* Construct the initial type list and assign BTF IDs for all types translated
+   from CTF.  */
+
+static void
+btf_late_collect_translated_types (ctf_container_ref ctfc)
+{
+  size_t num_ctf_types = ctfc->ctfc_types->elements ();
+
+  /* First, place each type at its CTF-assigned index in the list.
+     The '+1' here and below is to account for the implicit void type with
+     ID 0.  There is no real type at index 0 in the list.  */
+  ctfc->ctfc_types_list = ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1);
+  ctfc->ctfc_types->traverse<ctf_container_ref, btf_type_list_cb> (ctfc);
+
+  /* Now, pass through the list and adjust IDs to account for types which will
+     not be emitted.  This results in each type that will be emitted in BTF
+     being assigned an appropriate ID.  Note that types which will not be
+     emitted remain in the list; they are skipped at output time.  */
+  unsigned int skip = 0;
+  for (size_t i = 1; i <= num_ctf_types; i++)
+    {
+      ctf_dtdef_ref dtd = ctfc->ctfc_types_list[i];
+      if (!btf_emit_type_p (dtd))
+	{
+	  dtd->dtd_type = BTF_INVALID_TYPEID;
+	  skip += 1;
+	  continue;
+	}
+
+      dtd->dtd_type -= skip;
+      ctfc->ctfc_num_types++;
+      ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
+    }
+
+  max_translated_id = ctfc->ctfc_num_types;
+  ctfc->ctfc_nextid = ctfc->ctfc_num_types + 1;
+}
+
+/* Assign BTF IDs for FUNC records and account for their size.  */
+
+static void
+btf_late_assign_func_ids (ctf_container_ref ctfc)
+{
+  ctf_dtdef_ref dtd;
+  unsigned int i;
+  FOR_EACH_VEC_ELT (*funcs, i, dtd)
+    {
+      dtd->dtd_type = ctfc->ctfc_nextid++;
+      ctfc->ctfc_num_types++;
+    }
+}
+
+/* Assign BTF IDs for variables and account for their size.  */
+
+static void
+btf_late_assign_var_ids (ctf_container_ref ctfc)
+{
+  for (size_t i = 0; i < ctfc->ctfc_vars_list_count; i++)
+    {
+      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
+      ctf_id_t id = ctfc->ctfc_nextid++;
+      gcc_assert (id <= BTF_MAX_TYPE);
+      dvd->dvd_id = id;
+
+      ctfc->ctfc_num_types++;
+      ctfc->ctfc_num_vlen_bytes += sizeof (struct btf_var);
+    }
+}
+
+/* Assign BTF IDs for datasec records and account for their size.  */
+
+static void
+btf_late_assign_datasec_ids (ctf_container_ref ctfc)
 {
-  btf_init_postprocess ();
+  for (size_t i = 0; i < datasecs.length (); i++)
+    {
+      datasecs[i].id = ctfc->ctfc_nextid++;
+      datasecs[i].name_offset += ctfc_get_strtab_len (ctfc, CTF_STRTAB);
+      ctfc->ctfc_num_types++;
+      ctfc->ctfc_num_vlen_bytes += (datasecs[i].entries.length ()
+				    * sizeof (struct btf_var_secinfo));
+    }
 }
 
 /* Late entry point for BTF generation, called from dwarf2out_finish ().
    Complete and emit BTF information.  */
 
 void
-btf_finish (const char * filename)
+btf_finish (void)
 {
-  btf_output (filename);
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+  init_btf_sections ();
+
+  datasecs.create (0);
+
+  tu_ctfc->ctfc_num_types = 0;
+  tu_ctfc->ctfc_num_vlen_bytes = 0;
+  tu_ctfc->ctfc_vars_list_count = 0;
+
+  btf_late_add_vars (tu_ctfc);
+  btf_late_collect_translated_types (tu_ctfc);
+  btf_late_add_func_datasec_entries (tu_ctfc);
+  btf_late_assign_var_ids (tu_ctfc);
+  btf_late_assign_func_ids (tu_ctfc);
+  btf_late_assign_datasec_ids (tu_ctfc);
+
+  /* Finally, write out the complete .BTF section.  */
+  btf_output (tu_ctfc);
 
   /* If compiling for BPF with CO-RE info, we cannot deallocate until after
      CO-RE information is created, which happens very late in BPF backend.
@@ -1521,6 +1290,27 @@ btf_finish (const char * filename)
     btf_finalize ();
 }
 
+/* Reset all state for BTF generation so that we can rerun the compiler within
+   the same process.  */
+
+void
+btf_finalize (void)
+{
+  btf_info_section = NULL;
+  max_translated_id = 0;
+
+  for (size_t i = 0; i < datasecs.length (); i++)
+    datasecs[i].entries.release ();
+  datasecs.release ();
+
+  funcs = NULL;
+  func_map->empty ();
+  func_map = NULL;
+
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+  ctfc_delete_container (tu_ctfc);
+  tu_ctfc = NULL;
+}
 
 /* Traversal function for all BTF_KIND_FUNC type records.  */
 
diff --git a/gcc/ctfc.h b/gcc/ctfc.h
index cfc805db7b5..90421c72c09 100644
--- a/gcc/ctfc.h
+++ b/gcc/ctfc.h
@@ -162,10 +162,14 @@ struct GTY ((for_user)) ctf_dtdef
   ctf_id_t dtd_type;	      /* Type identifier for this definition.  */
   struct ctf_dtdef *ref_type; /* Type referred to by this type (if any).  */
   ctf_itype_t dtd_data;	      /* Type node.  */
-  bool from_global_func; /* Whether this type was added from a global
-			    function.  */
   uint32_t linkage;           /* Used in function types.  0=local, 1=global.  */
-  bool dtd_enum_unsigned;     /* Enum signedness.  */
+
+  /* Whether this type was added from a global function.  */
+  BOOL_BITFIELD from_global_func : 1;
+  /* Enum signedness.  */
+  BOOL_BITFIELD dtd_enum_unsigned : 1;
+  /* Lots of spare bits.  */
+
   union GTY ((desc ("ctf_dtu_d_union_selector (&%1)")))
   {
     /* struct, union, or enum.  */
@@ -192,6 +196,7 @@ struct GTY ((for_user)) ctf_dvdef
   uint32_t dvd_name_offset;	/* Offset of the name in str table.  */
   unsigned int dvd_visibility;	/* External visibility.  0=static,1=global.  */
   struct ctf_dtdef * dvd_type;	/* Type of variable.  */
+  ctf_id_t dvd_id;		/* ID of this variable.  Only used for BTF.  */
 };
 
 typedef struct ctf_dvdef ctf_dvdef_t;
@@ -388,7 +393,7 @@ extern void ctf_output (const char * filename);
 extern void ctf_finalize (void);
 
 extern void btf_early_finish (void);
-extern void btf_finish (const char * filename);
+extern void btf_finish (void);
 extern void btf_finalize (void);
 
 extern ctf_container_ref ctf_get_tu_ctfc (void);
@@ -442,7 +447,9 @@ extern int ctf_add_variable (ctf_container_ref, const char *, ctf_dtdef_ref,
 			     dw_die_ref, unsigned int, dw_die_ref);
 
 extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
-extern ctf_id_t get_btf_id (ctf_id_t);
+
+/* Callback and traversal function for BTF_KIND_FUNC records.  Used by BPF
+   target for BPF CO-RE implementation.  */
 
 typedef bool (*funcs_traverse_callback) (ctf_dtdef_ref, void *);
 bool traverse_btf_func_types (funcs_traverse_callback, void *);
diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
index f16b5ceee74..ac195c1a862 100644
--- a/gcc/dwarf2ctf.cc
+++ b/gcc/dwarf2ctf.cc
@@ -980,13 +980,13 @@ ctf_debug_early_finish (const char * filename)
 /* Finish CTF/BTF debug info emission.  */
 
 void
-ctf_debug_finish (const char * filename)
+ctf_debug_finish ()
 {
   /* Emit BTF debug info here when CO-RE relocations need to be generated.
      BTF with CO-RE relocations needs to be generated when CO-RE is in effect
      for the BPF target.  */
   if (btf_debuginfo_p ())
-    btf_finish (filename);
+    btf_finish ();
 }
 
 #include "gt-dwarf2ctf.h"
diff --git a/gcc/dwarf2ctf.h b/gcc/dwarf2ctf.h
index 46184325bae..f8a181a9762 100644
--- a/gcc/dwarf2ctf.h
+++ b/gcc/dwarf2ctf.h
@@ -32,7 +32,7 @@ extern void ctf_debug_init (void);
 extern void ctf_debug_init_postprocess (bool);
 extern bool ctf_do_die (dw_die_ref);
 extern void ctf_debug_early_finish (const char *);
-extern void ctf_debug_finish (const char *);
+extern void ctf_debug_finish (void);
 
 /* Wrappers for CTF/BTF to fetch information from GCC DWARF DIE.  Used in
    ctfc.cc.
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 1664934ccc3..794b94ca80b 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -32276,7 +32276,7 @@ dwarf2out_finish (const char *filename)
   /* Generate CTF/BTF debug info.  */
   if ((ctf_debug_info_level > CTFINFO_LEVEL_NONE
        || btf_debuginfo_p ()) && lang_GNU_C ())
-    ctf_debug_finish (filename);
+    ctf_debug_finish ();
 
   /* Skip emitting DWARF if not required.  */
   if (!dwarf_debuginfo_p ())
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 5/6] btf: add -fprune-btf option
  2024-05-02 17:11 [PATCH v2 0/6] btf: refactor and add pruning option David Faust
                   ` (3 preceding siblings ...)
  2024-05-02 17:11 ` [PATCH v2 4/6] btf: refactor and simplify implementation David Faust
@ 2024-05-02 17:11 ` David Faust
  2024-05-03 21:08   ` Indu Bhagat
  2024-05-02 17:11 ` [PATCH v2 6/6] bpf,btf: enable BTF pruning by default for BPF David Faust
  5 siblings, 1 reply; 13+ messages in thread
From: David Faust @ 2024-05-02 17:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: indu.bhagat, jose.marchesi, cupertino.miranda

This patch adds a new option, -fprune-btf, to control BTF debug info
generation.

As the name implies, this option enables a kind of "pruning" of the BTF
information before it is emitted.  When enabled, rather than emitting
all type information translated from DWARF, only information for types
directly used in the source program is emitted.

The primary purpose of this pruning is to reduce the amount of
unnecessary BTF information emitted, especially for BPF programs.  It is
very common for BPF programs to incldue Linux kernel internal headers in
order to have access to kernel data structures.  However, doing so often
has the side effect of also adding type definitions for a large number
of types which are not actually used by nor relevant to the program.
In these cases, -fprune-btf commonly reduces the size of the resulting
BTF information by approximately 10x.  This both slims down the size of
the resulting object and reduces the time required by the BPF loader to
verify the program and its BTF information.

Note that the pruning implemented in this patch follows the same rules
as the BTF pruning performed unconditionally by LLVM's BPF backend when
generating BTF.  In particular, the main sources of pruning are:

  1) Only generate BTF for types used by variables and functions at
     the file scope.

  2) Avoid emitting full BTF for struct and union types which are only
     pointed-to by members of other struct/union types.  In these cases,
     the full BTF_KIND_STRUCT or BTF_KIND_UNION which would normally
     be emitted is replaced with a BTF_KIND_FWD, as though the
     underlying type was a forward-declared struct or union type.

gcc/
	* btfout.cc (btf_minimal_types): New hash set.
	(struct btf_fixup): New.
	(fixups, forwards): New vecs.
	(btf_output): Calculate num_types depending on flag_prune_btf.
	(btf_early_finsih): New initialization for flag_prune_btf.
	(btf_mark_full_type_used): Likewise.
	(btf_minimal_add_type): New function.
	(btf_minimal_type_list_cb): Likewise.
	(btf_late_collect_pruned_types): Likewise.
	(btf_late_add_vars): Handle special case for variables in ".maps"
	section when generating BTF for BPF CO-RE target.
	(btf_late_finish): Use btf_late_collect_pruned_types when
	flag_prune_btf in effect.  Move some initialization to btf_early_finish.
	(btf_finalize): Additional deallocation for flag_prune_btf.
	* common.opt (fprune-btf): New flag.
	* ctfc.cc (init_ctf_strtable): Make non-static.
	* ctfc.h (struct ctf_dtdef): Add visited_children_p boolean flag.
	(init_ctf_strtable, ctfc_delete_strtab): Make extern.
	* doc/invoke.texi (Debugging Options): Document -fprune-btf.

gcc/testsuite/
	* gcc.dg/debug/btf/btf-prune-1.c: New test.
	* gcc.dg/debug/btf/btf-prune-2.c: Likewise.
	* gcc.dg/debug/btf/btf-prune-3.c: Likewise.
---
 gcc/btfout.cc                                | 394 ++++++++++++++++++-
 gcc/common.opt                               |   4 +
 gcc/ctfc.cc                                  |   2 +-
 gcc/ctfc.h                                   |   5 +
 gcc/doc/invoke.texi                          |  20 +
 gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c |  25 ++
 gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c |  33 ++
 gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c |  35 ++
 8 files changed, 511 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c

diff --git a/gcc/btfout.cc b/gcc/btfout.cc
index 0af0bd39fc7..93d56492bbe 100644
--- a/gcc/btfout.cc
+++ b/gcc/btfout.cc
@@ -833,7 +833,10 @@ output_btf_types (ctf_container_ref ctfc)
 {
   size_t i;
   size_t num_types;
-  num_types = ctfc->ctfc_types->elements ();
+  if (flag_prune_btf)
+    num_types = max_translated_id;
+  else
+    num_types = ctfc->ctfc_types->elements ();
 
   if (num_types)
     {
@@ -962,6 +965,211 @@ btf_early_add_func_records (ctf_container_ref ctfc)
     }
 }
 
+/* The set of types used directly in the source program, and any types manually
+   marked as used.  This is the set of types which will be emitted when
+   pruning (-fprune-btf) is enabled.  */
+static GTY (()) hash_set<ctf_dtdef_ref> *btf_minimal_types;
+
+/* Fixup used to avoid unnecessary pointer chasing for types.  A fixup is
+   created when a structure or union member is a pointer to another struct
+   or union type.  In such cases, avoid emitting full type information for
+   the pointee struct or union type (which may be quite large), unless that
+   type is used directly elsewhere.  */
+struct btf_fixup
+{
+  ctf_dtdef_ref pointer_dtd; /* Type node to which the fixup is applied.  */
+  ctf_dtdef_ref pointee_dtd; /* Original type node referred to by pointer_dtd.
+				If this concrete type is not otherwise used,
+				then a forward is created.  */
+};
+
+/* Stores fixups while processing types.  */
+static vec<struct btf_fixup> fixups;
+
+/* For fixups where the underlying type is not used in the end, a BTF_KIND_FWD
+   is created and emitted.  This vector stores them.  */
+static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
+
+/* Recursively add type DTD and any types it references to the used set.
+   Return a type that should be used for references to DTD - usually DTD itself,
+   but may be NULL if DTD corresponds to a type which will not be emitted.
+   CHECK_PTR is true if one of the predecessors in recursive calls is a struct
+   or union member.  SEEN_PTR is true if CHECK_PTR is true AND one of the
+   predecessors was a pointer type.  These two flags are used to avoid chasing
+   pointers to struct/union only used from pointer members.  For such types, we
+   will emit a forward instead of the full type information.  */
+
+static ctf_dtdef_ref
+btf_minimal_add_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
+		      bool check_ptr, bool seen_ptr)
+{
+  if (dtd == NULL)
+    return NULL;
+
+  uint32_t ctf_kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
+  uint32_t kind = get_btf_kind (ctf_kind);
+
+  /* Check whether the type has already been added.  */
+  if (btf_minimal_types->contains (dtd))
+    {
+      /* It's possible the type was already added as a fixup, but that we now
+	 have a concrete use of it.  */
+      switch (kind)
+	{
+	case BTF_KIND_PTR:
+	case BTF_KIND_TYPEDEF:
+	case BTF_KIND_CONST:
+	case BTF_KIND_VOLATILE:
+	case BTF_KIND_RESTRICT:
+	  if (check_ptr)
+	    /* Type was previously added as a fixup, and that's OK.  */
+	    return dtd;
+	  else
+	    {
+	      /* The type was previously added as a fixup, but now we have
+		 a concrete use of it.  Remove the fixup.  */
+	      for (size_t i = 0; i < fixups.length (); i++)
+		if (fixups[i].pointer_dtd == dtd)
+		  fixups.unordered_remove (i);
+
+	      /* Add the concrete base type.  */
+	      dtd->ref_type = btf_minimal_add_type (ctfc, dtd->ref_type,
+						    check_ptr, seen_ptr);
+	      return dtd;
+	    }
+	default:
+	  return dtd;
+	}
+    }
+
+  if (ctf_kind == CTF_K_SLICE)
+    {
+      /* Bitfield.  Add the underlying type to the used set, but leave
+	 the reference to the bitfield.  The slice type won't be emitted,
+	 but we need the information in it when writing out the bitfield
+	 encoding.  */
+      btf_minimal_add_type (ctfc, dtd->dtd_u.dtu_slice.cts_type,
+			    check_ptr, seen_ptr);
+      return dtd;
+    }
+
+  /* Skip redundant definitions of void and types with no BTF encoding.  */
+  if ((kind == BTF_KIND_INT && dtd->dtd_data.ctti_size == 0)
+      || (kind == BTF_KIND_UNKN))
+    return NULL;
+
+  /* Add the type itself, and assign its id.
+     Do this before recursing to handle things like linked list structures.  */
+  gcc_assert (ctfc->ctfc_nextid <= BTF_MAX_TYPE);
+  dtd->dtd_type = ctfc->ctfc_nextid++;
+  btf_minimal_types->add (dtd);
+  ctf_add_string (ctfc, dtd->dtd_name, &(dtd->dtd_data.ctti_name), CTF_STRTAB);
+  ctfc->ctfc_num_types++;
+  ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
+
+  /* Recursively add types referenced by this type.  */
+  switch (kind)
+    {
+    case BTF_KIND_INT:
+    case BTF_KIND_FLOAT:
+    case BTF_KIND_FWD:
+      /* Leaf kinds which do not refer to any other types.  */
+      break;
+
+    case BTF_KIND_FUNC:
+    case BTF_KIND_VAR:
+      /* Root kinds; no type we are visiting may refer to these.  */
+      gcc_unreachable ();
+
+    case BTF_KIND_PTR:
+    case BTF_KIND_TYPEDEF:
+    case BTF_KIND_CONST:
+    case BTF_KIND_VOLATILE:
+    case BTF_KIND_RESTRICT:
+      {
+	/* These type kinds refer to exactly one other type.  */
+	if (check_ptr && !seen_ptr)
+	  seen_ptr = (kind == BTF_KIND_PTR);
+
+	/* Try to avoid chasing pointers to struct/union types if the
+	   underlying type isn't used.  */
+	if (check_ptr && seen_ptr)
+	  {
+	    ctf_dtdef_ref ref = dtd->ref_type;
+	    uint32_t ref_kind = btf_dtd_kind (ref);
+
+	    if ((ref_kind == BTF_KIND_STRUCT || ref_kind == BTF_KIND_UNION)
+		&& !btf_minimal_types->contains (ref))
+	      {
+		struct btf_fixup fixup;
+		fixup.pointer_dtd = dtd;
+		fixup.pointee_dtd = ref;
+		fixups.safe_push (fixup);
+		break;
+	      }
+	  }
+
+	/* Add the type to which this type refers.  */
+	dtd->ref_type = btf_minimal_add_type (ctfc, dtd->ref_type,
+					      check_ptr, seen_ptr);
+	break;
+      }
+    case BTF_KIND_ARRAY:
+      {
+	/* Add element and index types.  */
+	ctf_arinfo_t *arr = &(dtd->dtd_u.dtu_arr);
+	arr->ctr_contents = btf_minimal_add_type (ctfc, arr->ctr_contents,
+						  false, false);
+	arr->ctr_index = btf_minimal_add_type (ctfc, arr->ctr_index,
+					       false, false);
+	break;
+      }
+    case BTF_KIND_STRUCT:
+    case BTF_KIND_UNION:
+    case BTF_KIND_ENUM:
+    case BTF_KIND_ENUM64:
+      {
+	/* Add members.  */
+	ctf_dmdef_t *dmd;
+	for (dmd = dtd->dtd_u.dtu_members;
+	     dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
+	  {
+	    /* Add member type for struct/union members.  For enums, only the
+	       enumerator names are needed.  */
+	    if (kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION)
+	      dmd->dmd_type = btf_minimal_add_type (ctfc, dmd->dmd_type,
+						    true, false);
+	    ctf_add_string (ctfc, dmd->dmd_name, &(dmd->dmd_name_offset),
+			    CTF_STRTAB);
+	  }
+	break;
+      }
+    case BTF_KIND_FUNC_PROTO:
+      {
+	/* Add return type.  */
+	dtd->ref_type = btf_minimal_add_type (ctfc, dtd->ref_type,
+					      false, false);
+
+	/* Add arg types.  */
+	ctf_func_arg_t * farg;
+	for (farg = dtd->dtd_u.dtu_argv;
+	     farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
+	  {
+	    farg->farg_type = btf_minimal_add_type (ctfc, farg->farg_type,
+						    false, false);
+	    /* Note: argument names are stored in the auxilliary string table,
+	       since CTF does not include arg names.  That table has not been
+	       cleared, so no need to re-add argument names here.  */
+	  }
+	break;
+      }
+    default:
+      return NULL;
+    }
+
+  return dtd;
+}
+
 /* Initial entry point of BTF generation, called at early_finish () after
    CTF information has possibly been output.  Translate all CTF information
    to BTF, and do any processing that must be done early, such as creating
@@ -977,6 +1185,27 @@ btf_early_finish (void)
 
   btf_early_add_const_void (tu_ctfc);
   btf_early_add_func_records (tu_ctfc);
+
+  /* Note: from here on, destructive changes are made to the TU CTFC to
+     translate CTF to BTF.  These fields are reset to count BTF types etc.  */
+  tu_ctfc->ctfc_num_types = 0;
+  tu_ctfc->ctfc_num_vlen_bytes = 0;
+  tu_ctfc->ctfc_vars_list_count = 0;
+
+  if (flag_prune_btf)
+    {
+      btf_minimal_types
+	= hash_set<ctf_dtdef_ref>::create_ggc (tu_ctfc->ctfc_types->elements ());
+      tu_ctfc->ctfc_nextid = 1;
+      fixups.create (1);
+
+      /* Empty the string table, which was already populated with strings for
+	 all types translated from DWARF.  We may only need a very small subset
+	 of these strings; those will be re-added below.  */
+      ctfc_delete_strtab (&tu_ctfc->ctfc_strtable);
+      init_ctf_strtable (&tu_ctfc->ctfc_strtable);
+      tu_ctfc->ctfc_strlen++;
+    }
 }
 
 /* Push a BTF datasec entry ENTRY into the datasec named SECNAME,
@@ -1134,6 +1363,51 @@ btf_emit_variable_p (ctf_container_ref ctfc, varpool_node *var,
   return true;
 }
 
+
+/* Recursively mark T and all children types as used to prevent them
+   being pruned.  */
+
+static void
+btf_mark_full_type_used (ctf_container_ref ctfc, tree t)
+{
+  ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, t);
+  if (!dtd)
+    return;
+
+  if (dtd->visited_children_p)
+    return;
+
+  btf_minimal_add_type (ctfc, dtd, false, false);
+  dtd->visited_children_p = true;
+
+  /* Note that it is only necessary here to visit descendents which may be
+     pruned by replacing with a forward, i.e. pointed-to struct/union types.  */
+  switch (TREE_CODE (t))
+    {
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      btf_mark_full_type_used (ctfc, TREE_TYPE (t));
+      break;
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+      {
+	tree member = TYPE_FIELDS (t);
+	while (member != NULL_TREE)
+	  {
+	    if (DECL_ABSTRACT_ORIGIN (member))
+	      continue;
+
+	    btf_mark_full_type_used (ctfc, TREE_TYPE (member));
+	    member = DECL_CHAIN (member);
+	  }
+	break;
+      }
+    default:
+      break;
+    }
+}
+
 /* Add BTF_KIND_VAR records for variables.  */
 
 static void
@@ -1159,6 +1433,14 @@ btf_late_add_vars (ctf_container_ref ctfc)
 
       /* Add a BTF_KIND_DATASEC entry for the variable.  */
       btf_datasec_add_var (ctfc, var, dvd);
+
+      /* Special case: for BPF CO-RE, the .maps section is special.
+	 Full type info for anything in .maps is always required.  */
+      const char *section = var->get_section ();
+      if (section && (strcmp (section, ".maps") == 0)
+	  && btf_with_core_debuginfo_p () && flag_prune_btf)
+	btf_mark_full_type_used (ctfc, TREE_TYPE (var->decl));
+
     }
 }
 
@@ -1257,6 +1539,88 @@ btf_late_assign_datasec_ids (ctf_container_ref ctfc)
     }
 }
 
+/* Callback used for assembling the only-used-types list.  Note that this is
+   the same as btf_type_list_cb above, but the hash_set traverse requires a
+   different function signature.  */
+
+static bool
+btf_minimal_type_list_cb (const ctf_dtdef_ref& dtd, ctf_container_ref ctfc)
+{
+  ctfc->ctfc_types_list[dtd->dtd_type] = dtd;
+  return true;
+}
+
+/* Collect the set of types reachable from global variables and functions.
+   This is the minimal set of types, used when generating pruned BTF.  */
+
+static void
+btf_late_collect_pruned_types (ctf_container_ref ctfc)
+{
+  vec_alloc (forwards, 1);
+
+  /* Add types used from functions.  */
+  ctf_dtdef_ref dtd;
+  size_t i;
+  FOR_EACH_VEC_ELT (*funcs, i, dtd)
+    {
+      btf_minimal_add_type (ctfc, dtd->ref_type, false, false);
+      ctf_add_string (ctfc, dtd->dtd_name, &(dtd->dtd_data.ctti_name),
+		      CTF_STRTAB);
+    }
+
+  /* Add types used from global variables.  */
+  for (i = 0; i < ctfc->ctfc_vars_list_count; i++)
+    {
+      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
+      btf_minimal_add_type (ctfc, dvd->dvd_type, false, false);
+      ctf_add_string (ctfc, dvd->dvd_name, &(dvd->dvd_name_offset), CTF_STRTAB);
+    }
+
+  /* Process fixups. If the base type was never added, create a forward for it
+     and adjust the reference to point to that.  If it was added, then nothing
+     needs to change.  */
+  for (i = 0; i < fixups.length (); i++)
+    {
+      struct btf_fixup *fx = &fixups[i];
+      if (!btf_minimal_types->contains (fx->pointee_dtd))
+	{
+	  /* The underlying type is not used.  Create a forward.  */
+	  ctf_dtdef_ref fwd = ggc_cleared_alloc<ctf_dtdef_t> ();
+	  ctf_id_t id = ctfc->ctfc_nextid++;
+	  gcc_assert (id <= BTF_MAX_TYPE);
+
+	  bool union_p = (btf_dtd_kind (fx->pointee_dtd) == BTF_KIND_UNION);
+
+	  fwd->dtd_name = fx->pointee_dtd->dtd_name;
+	  fwd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FORWARD, union_p, 0);
+	  fwd->dtd_type = id;
+	  ctfc->ctfc_num_types++;
+	  ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (fwd);
+	  ctf_add_string (ctfc, fwd->dtd_name, &(fwd->dtd_data.ctti_name),
+			  CTF_STRTAB);
+
+	  /* Update the pointer to point to the forward.  */
+	  fx->pointer_dtd->ref_type = fwd;
+	  vec_safe_push (forwards, fwd);
+	}
+    }
+
+  /* Construct the resulting pruned type list.  */
+  ctfc->ctfc_types_list
+    = ggc_vec_alloc<ctf_dtdef_ref> (btf_minimal_types->elements () + 1
+				    + vec_safe_length (forwards));
+
+  btf_minimal_types->traverse<ctf_container_ref, btf_minimal_type_list_cb>
+    (ctfc);
+
+  /* Insert the newly created forwards into the regular types list too.  */
+  FOR_EACH_VEC_ELT (*forwards, i, dtd)
+    ctfc->ctfc_types_list[dtd->dtd_type] = dtd;
+
+  max_translated_id = btf_minimal_types->elements ()
+    + vec_safe_length (forwards);
+}
+
 /* Late entry point for BTF generation, called from dwarf2out_finish ().
    Complete and emit BTF information.  */
 
@@ -1268,13 +1632,22 @@ btf_finish (void)
 
   datasecs.create (0);
 
-  tu_ctfc->ctfc_num_types = 0;
-  tu_ctfc->ctfc_num_vlen_bytes = 0;
-  tu_ctfc->ctfc_vars_list_count = 0;
-
   btf_late_add_vars (tu_ctfc);
-  btf_late_collect_translated_types (tu_ctfc);
+  if (flag_prune_btf)
+    {
+      /* Collect pruned set of BTF types and prepare for emission.
+	 This includes only types directly used in file-scope variables and
+	 function return/argument types.  */
+      btf_late_collect_pruned_types (tu_ctfc);
+    }
+  else
+    {
+      /* Collect all BTF types and prepare for emission.
+	 This includes all types translated from DWARF.  */
+      btf_late_collect_translated_types (tu_ctfc);
+    }
   btf_late_add_func_datasec_entries (tu_ctfc);
+
   btf_late_assign_var_ids (tu_ctfc);
   btf_late_assign_func_ids (tu_ctfc);
   btf_late_assign_datasec_ids (tu_ctfc);
@@ -1307,6 +1680,15 @@ btf_finalize (void)
   func_map->empty ();
   func_map = NULL;
 
+  if (flag_prune_btf)
+    {
+      btf_minimal_types->empty ();
+      btf_minimal_types = NULL;
+
+      fixups.release ();
+      forwards = NULL;
+    }
+
   ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
   ctfc_delete_container (tu_ctfc);
   tu_ctfc = NULL;
diff --git a/gcc/common.opt b/gcc/common.opt
index ad348844775..c430cfd0428 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2578,6 +2578,10 @@ fpatchable-function-entry=
 Common Var(flag_patchable_function_entry) Joined Optimization
 Insert NOP instructions at each function entry.
 
+fprune-btf
+Common Var(flag_prune_btf) Init(0)
+Generate minimal BTF debug info.
+
 frandom-seed
 Common Var(common_deferred_options) Defer
 
diff --git a/gcc/ctfc.cc b/gcc/ctfc.cc
index d8f1037b4e0..7681af8542d 100644
--- a/gcc/ctfc.cc
+++ b/gcc/ctfc.cc
@@ -913,7 +913,7 @@ ctfc_get_dvd_srcloc (ctf_dvdef_ref dvd, ctf_srcloc_ref loc)
 /* Initialize the CTF string table.
    The first entry in the CTF string table (empty string) is added.  */
 
-static void
+void
 init_ctf_strtable (ctf_strtable_t * strtab)
 {
   strtab->ctstab_head = NULL;
diff --git a/gcc/ctfc.h b/gcc/ctfc.h
index 90421c72c09..bd3d98ffed9 100644
--- a/gcc/ctfc.h
+++ b/gcc/ctfc.h
@@ -168,6 +168,8 @@ struct GTY ((for_user)) ctf_dtdef
   BOOL_BITFIELD from_global_func : 1;
   /* Enum signedness.  */
   BOOL_BITFIELD dtd_enum_unsigned : 1;
+  /* Already visited children of this type, e.g. struct members.  */
+  BOOL_BITFIELD visited_children_p : 1;
   /* Lots of spare bits.  */
 
   union GTY ((desc ("ctf_dtu_d_union_selector (&%1)")))
@@ -369,6 +371,9 @@ extern unsigned int ctfc_get_num_ctf_vars (ctf_container_ref);
 
 extern ctf_strtable_t * ctfc_get_strtab (ctf_container_ref, int);
 
+extern void init_ctf_strtable (ctf_strtable_t *);
+extern void ctfc_delete_strtab (ctf_strtable_t *);
+
 /* Get the length of the specified string table in the CTF container.  */
 
 extern size_t ctfc_get_strtab_len (ctf_container_ref, int);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9456ced468a..2908afff7c6 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -533,6 +533,7 @@ Objective-C and Objective-C++ Dialects}.
 -gvms -gz@r{[}=@var{type}@r{]}
 -gsplit-dwarf  -gdescribe-dies  -gno-describe-dies
 -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section
+-fprune-btf -fno-prune-btf
 -fno-eliminate-unused-debug-types
 -femit-struct-debug-baseonly  -femit-struct-debug-reduced
 -femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]}
@@ -12234,6 +12235,25 @@ compressed debug sections, the option is rejected.  Otherwise, if the
 assembler does not support them, @option{-gz} is silently ignored when
 producing object files.
 
+@opindex fprune-btf
+@opindex fno-prune-btf
+@item -fprune-btf
+@itemx -fno-prune-btf
+Prune BTF information before emission.  When pruning, only type
+information for types used by global variables and file-scope functions
+will be emitted.  If compiling for the BPF target with BPF CO-RE
+enabled, type information will also be emitted for types used in BPF
+CO-RE relocations.  In addition, struct and union types which are only
+referred to via pointers from members of other struct or union types
+shall be pruned and replaced with BTF_KIND_FWD, as though those types
+were only present in the input as forward declarations.
+
+This option substantially reduces the size of produced BTF information,
+but at significant loss in the amount of detailed type information.
+It is primarily useful when compiling for the BPF target, to minimize
+the size of the resulting object, and to eliminate BTF information
+which is not immediately relevant to the BPF program loading process.
+
 @opindex femit-struct-debug-baseonly
 @item -femit-struct-debug-baseonly
 Emit debug information for struct-like types
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c
new file mode 100644
index 00000000000..3c9b59a07ec
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c
@@ -0,0 +1,25 @@
+/* Simple test of -fprune-btf option operation.
+   Since 'struct foo' is not used, no BTF shall be emitted for it.  */
+
+/* { dg-do compile } */
+/* { dg-options "-gbtf -fprune-btf -dA" } */
+
+/* No BTF info for 'struct foo' nor types used only by it.  */
+/* { dg-final { scan-assembler-not "BTF_KIND_STRUCT 'foo'" } } */
+/* { dg-final { scan-assembler-not "BTF_KIND_INT 'char'" } } */
+
+/* We should get BTF info for 'struct bar' since it is used.  */
+/* { dg-final { scan-assembler "BTF_KIND_STRUCT 'bar'"} } */
+
+struct foo {
+  int a;
+  char c;
+};
+
+struct bar {
+  int x;
+  long z[4];
+};
+
+struct bar a_bar;
+
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c
new file mode 100644
index 00000000000..20183dffcc7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c
@@ -0,0 +1,33 @@
+/* Test that -fprune-btf does not chase pointer-to-struct members.  */
+
+/* { dg-do compile } */
+/* { dg-options "-gbtf -fprune-btf -dA" } */
+
+/* Only use of B is via a pointer member of C.
+   Full BTF for B is replaced with a forward.  */
+/* { dg-final { scan-assembler-not "BTF_KIND_STRUCT 'B'" } } */
+/* { dg-final { scan-assembler-times "TYPE \[0-9\]+ BTF_KIND_FWD 'B'" 1 } } */
+
+/* Detailed info for B is omitted, and A is otherwise unused.  */
+/* { dg-final { scan-assembler-not "BTF_KIND_\[A-Z\]+ 'A'" } } */
+
+/* { dg-final { scan-assembler "BTF_KIND_STRUCT 'C'" } } */
+
+struct A;
+
+struct B {
+  int x;
+  int (*do_A_thing) (int, int);
+  struct A *other;
+};
+
+struct C {
+  unsigned int x;
+  struct B * a;
+};
+
+int
+foo (struct C *c)
+{
+  return c->x;
+}
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c
new file mode 100644
index 00000000000..57a079cf0b4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c
@@ -0,0 +1,35 @@
+/* Test that -fprune-btf */
+
+/* { dg-do compile } */
+/* { dg-options "-gbtf -fprune-btf -dA" } */
+
+/* We expect full BTF information each struct.  */
+/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_FWD 'file'" } } */
+/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_STRUCT 'A'" } } */
+/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_STRUCT 'B'" } } */
+/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_STRUCT 'C'" } } */
+
+struct file;
+
+struct A {
+  void *private;
+  long (*read)(struct file *, char *, unsigned long);
+  long (*write)(struct file *, const char *, unsigned long);
+};
+
+struct B {
+  unsigned int x;
+  struct A **as;
+};
+
+struct C {
+  struct A *arr_a[4];
+  struct A *lone_a;
+  unsigned int z;
+};
+
+unsigned int
+foo (struct B *b, struct C *c)
+{
+  return b->x + c->z;
+}
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 6/6] bpf,btf: enable BTF pruning by default for BPF
  2024-05-02 17:11 [PATCH v2 0/6] btf: refactor and add pruning option David Faust
                   ` (4 preceding siblings ...)
  2024-05-02 17:11 ` [PATCH v2 5/6] btf: add -fprune-btf option David Faust
@ 2024-05-02 17:11 ` David Faust
  2024-05-03 21:12   ` Indu Bhagat
  5 siblings, 1 reply; 13+ messages in thread
From: David Faust @ 2024-05-02 17:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: indu.bhagat, jose.marchesi, cupertino.miranda

This patch enables -fprune-btf by default in the BPF backend when
generating BTF information, and fixes BPF CO-RE generation when using
-fprune-btf.

When generating BPF CO-RE information, we must ensure that types used
in CO-RE relocations always have sufficient BTF information emited so
that the CO-RE relocations can be processed by a BPF loader.  The BTF
pruning algorithm on its own does not have sufficient information to
determine which types are used in a BPF CO-RE relocation, so this
information must be supplied by the BPF backend, using a new
btf_mark_type_used function.

Co-authored-by: Cupertino Miranda <cupertino.miranda@oracle.com>

gcc/
	* btfout.cc (btf_mark_type_used): New.
	* ctfc.h (btf_mark_type_used): Declare it here.
	* config/bpf/bpf.cc (bpf_option_override): Enable -fprune-btf
	by default if -gbtf is enabled.
	* config/bpf/bcore-builtins.cc (extra_fn): New typedef.
	(compute_field_expr): Add callback parameter, and call it if supplied.
	Fix computation for MEM_REF.
	(mark_component_type_as_used): New.
	(bpf_mark_types_as_used): Likewise.
	(bpf_expand_core_builtin): Call here.
	* doc/invoke.texi (Debugging Options): Note that -fprune-btf is
	enabled by default for BPF target when generating BTF.

gcc/testsuite/
	* gcc.dg/debug/btf/btf-variables-5.c: Add -fno-prune-btf to dg-options.
---
 gcc/btfout.cc                                 | 22 ++++++
 gcc/config/bpf/bpf.cc                         |  5 ++
 gcc/config/bpf/core-builtins.cc               | 70 +++++++++++++++++--
 gcc/ctfc.h                                    |  1 +
 gcc/doc/invoke.texi                           |  3 +
 .../gcc.dg/debug/btf/btf-variables-5.c        |  2 +-
 6 files changed, 96 insertions(+), 7 deletions(-)

diff --git a/gcc/btfout.cc b/gcc/btfout.cc
index 93d56492bbe..da2c9d35be9 100644
--- a/gcc/btfout.cc
+++ b/gcc/btfout.cc
@@ -1539,6 +1539,28 @@ btf_late_assign_datasec_ids (ctf_container_ref ctfc)
     }
 }
 
+
+/* Manually mark that type T is used to ensure it will not be pruned.
+   Used by the BPF backend when generating BPF CO-RE to mark types used
+   in CO-RE relocations.  */
+
+void
+btf_mark_type_used (tree t)
+{
+  /* If we are not going to prune anyway, this is a no-op.  */
+  if (!flag_prune_btf)
+    return;
+
+  gcc_assert (TYPE_P (t));
+  ctf_container_ref ctfc = ctf_get_tu_ctfc ();
+  ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, t);
+
+  if (!dtd)
+    return;
+
+  btf_minimal_add_type (ctfc, dtd, false, false);
+}
+
 /* Callback used for assembling the only-used-types list.  Note that this is
    the same as btf_type_list_cb above, but the hash_set traverse requires a
    different function signature.  */
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index e6ea211a2c6..75303ce8f46 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -221,6 +221,11 @@ bpf_option_override (void)
       && !(target_flags_explicit & MASK_BPF_CORE))
     target_flags |= MASK_BPF_CORE;
 
+  /* -gbtf implies -fprune-btf for BPF target.  */
+  if (btf_debuginfo_p ())
+    SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+			 flag_prune_btf, true);
+
   /* Determine available features from ISA setting (-mcpu=).  */
   if (bpf_has_jmpext == -1)
     bpf_has_jmpext = (bpf_isa >= ISA_V2);
diff --git a/gcc/config/bpf/core-builtins.cc b/gcc/config/bpf/core-builtins.cc
index d5a7de825ad..1b91b1c0d25 100644
--- a/gcc/config/bpf/core-builtins.cc
+++ b/gcc/config/bpf/core-builtins.cc
@@ -624,13 +624,20 @@ bpf_core_get_index (const tree node, bool *valid)
 
    ALLOW_ENTRY_CAST is an input arguments and specifies if the function should
    consider as valid expressions in which NODE entry is a cast expression (or
-   tree code nop_expr).  */
+   tree code nop_expr).
+
+   EXTRA_FN is a callback function to allow extra functionality with this
+   function traversal. Currently used for marking used type during expand
+   pass.  */
+
+typedef void (*extra_fn) (tree);
 
 static unsigned char
 compute_field_expr (tree node, unsigned int *accessors,
 		    bool *valid,
 		    tree *access_node,
-		    bool allow_entry_cast = true)
+		    bool allow_entry_cast = true,
+		    extra_fn callback = NULL)
 {
   unsigned char n = 0;
   unsigned int fake_accessors[MAX_NR_ACCESSORS];
@@ -647,6 +654,9 @@ compute_field_expr (tree node, unsigned int *accessors,
 
   *access_node = node;
 
+  if (callback != NULL)
+    callback (node);
+
   switch (TREE_CODE (node))
     {
     case INDIRECT_REF:
@@ -664,17 +674,19 @@ compute_field_expr (tree node, unsigned int *accessors,
     case COMPONENT_REF:
       n = compute_field_expr (TREE_OPERAND (node, 0), accessors,
 			      valid,
-			      access_node, false);
+			      access_node, false, callback);
       accessors[n] = bpf_core_get_index (TREE_OPERAND (node, 1), valid);
       return n + 1;
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
-    case MEM_REF:
       n = compute_field_expr (TREE_OPERAND (node, 0), accessors,
 			      valid,
-			      access_node, false);
+			      access_node, false, callback);
       accessors[n++] = bpf_core_get_index (node, valid);
       return n;
+    case MEM_REF:
+      accessors[0] = bpf_core_get_index (node, valid);
+      return 1;
     case NOP_EXPR:
       if (allow_entry_cast == true)
 	{
@@ -683,7 +695,7 @@ compute_field_expr (tree node, unsigned int *accessors,
 	}
       n = compute_field_expr (TREE_OPERAND (node, 0), accessors,
 			      valid,
-			      access_node, false);
+			      access_node, false, callback);
       return n;
 
     case ADDR_EXPR:
@@ -1549,6 +1561,50 @@ bpf_resolve_overloaded_core_builtin (location_t loc, tree fndecl,
   return construct_builtin_core_reloc (loc, fndecl, args, argsvec->length ());
 }
 
+/* Callback function for bpf_mark_field_expr_types_as_used.  */
+
+static void
+mark_component_type_as_used (tree node)
+{
+  if (TREE_CODE (node) == COMPONENT_REF)
+    btf_mark_type_used (TREE_TYPE (TREE_OPERAND (node, 0)));
+}
+
+/* Find and mark used struct/union types for BTF pruning.  */
+
+static void
+bpf_mark_types_as_used (struct cr_builtins *data)
+{
+  tree expr = data->expr;
+  switch (data->kind)
+    {
+    case BPF_RELO_FIELD_BYTE_OFFSET:
+    case BPF_RELO_FIELD_BYTE_SIZE:
+    case BPF_RELO_FIELD_EXISTS:
+    case BPF_RELO_FIELD_SIGNED:
+    case BPF_RELO_FIELD_LSHIFT_U64:
+    case BPF_RELO_FIELD_RSHIFT_U64:
+      if (TREE_CODE (expr) == ADDR_EXPR)
+	expr = TREE_OPERAND (expr, 0);
+
+      expr = root_for_core_field_info (expr);
+      compute_field_expr (data->expr, NULL, NULL, NULL, false,
+			  mark_component_type_as_used);
+      break;
+    case BPF_RELO_TYPE_ID_LOCAL:
+    case BPF_RELO_TYPE_ID_TARGET:
+    case BPF_RELO_TYPE_EXISTS:
+    case BPF_RELO_TYPE_SIZE:
+    case BPF_RELO_ENUMVAL_EXISTS:
+    case BPF_RELO_ENUMVAL_VALUE:
+    case BPF_RELO_TYPE_MATCHES:
+      btf_mark_type_used (data->type);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Used in bpf_expand_builtin.  This function is called in RTL expand stage to
    convert the internal __builtin_core_reloc in unspec:UNSPEC_CORE_RELOC RTL,
    which will contain a third argument that is the index in the vec collected
@@ -1567,6 +1623,8 @@ bpf_expand_core_builtin (tree exp, enum bpf_builtins code)
 	tree index = CALL_EXPR_ARG (exp, 0);
 	struct cr_builtins *data = get_builtin_data (TREE_INT_CST_LOW (index));
 
+	bpf_mark_types_as_used (data);
+
 	rtx v = expand_normal (data->default_value);
 	rtx i = expand_normal (index);
 	  return gen_rtx_UNSPEC (DImode,
diff --git a/gcc/ctfc.h b/gcc/ctfc.h
index bd3d98ffed9..99873a0b15c 100644
--- a/gcc/ctfc.h
+++ b/gcc/ctfc.h
@@ -458,6 +458,7 @@ extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
 
 typedef bool (*funcs_traverse_callback) (ctf_dtdef_ref, void *);
 bool traverse_btf_func_types (funcs_traverse_callback, void *);
+extern void btf_mark_type_used (tree);
 
 /* CTF section does not emit location information; at this time, location
    information is needed for BTF CO-RE use-cases.  */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2908afff7c6..f8778cdf7cc 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12254,6 +12254,9 @@ It is primarily useful when compiling for the BPF target, to minimize
 the size of the resulting object, and to eliminate BTF information
 which is not immediately relevant to the BPF program loading process.
 
+This option is enabled by default for the BPF target when generating
+BTF information.
+
 @opindex femit-struct-debug-baseonly
 @item -femit-struct-debug-baseonly
 Emit debug information for struct-like types
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c b/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c
index 8aae76cacab..c146b90abf9 100644
--- a/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c
@@ -5,7 +5,7 @@
    with 'global' linkage. However two array types will be generated.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O0 -gbtf -dA" } */
+/* { dg-options "-O0 -gbtf -dA -fno-prune-btf" } */
 
 /* Expect 1 variable with global (1) linkage.  */
 /* { dg-final { scan-assembler-times "\[\t \]0xe000000\[\t \]+\[^\n\]*btv_info" 1 } } */
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission
  2024-05-02 17:11 ` [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission David Faust
@ 2024-05-03 21:02   ` Indu Bhagat
  2024-05-06 17:48     ` David Faust
  0 siblings, 1 reply; 13+ messages in thread
From: Indu Bhagat @ 2024-05-03 21:02 UTC (permalink / raw)
  To: David Faust, gcc-patches; +Cc: jose.marchesi, cupertino.miranda

On 5/2/24 10:11, David Faust wrote:
> This commit makes some structural changes to the CTF/BTF debug info
> emission.  In particular:
> 
>   a) CTF is new always fully generated and emitted before any
>      BTF-related procedures are run.  This means that BTF-related
>      functions can change, even irreversibly, the shared in-memory
>      representation used by the two formats without issue.
> 
>   b) BTF generation has fewer entry points, and is cleanly divided
>      into early_finish and finish.
> 
>   c) BTF is now always emitted at finish (called from dwarf2out_finish),
>      rather than being emitted at early_finish for targets other than
>      BPF CO-RE.  Note that this change alone does not alter the contents
>      of BTF at all, regardless of whether it would have previously been
>      emitted at early_finish or finish.
> 

This will necessitate that we disallow -gbtf with -flto for non-BPF 
targets.  Emitting BTF always at dwarf2out_finish will not work with LTO.

> The changes are transparent to both CTF and BTF emission.
> 
> gcc/
> 	* btfout.cc (btf_init_postprocess): Rename to...
> 	(btf_early_finish): ...this.
> 	(btf_output): Rename to...
> 	(btf_finish): ...this.
> 	* ctfc.h: Analogous changes.
> 	* dwarf2ctf.cc (ctf_debug_early_finish): Conditionally call
> 	btf_early_finish or ctf_finalize as appropriate.
> 	(ctf_debug_finish): Always call btf_finish here if generating
> 	BTF info.
> 	(ctf_debug_finalize, ctf_debug_init_postprocess): Delete.
> 	* dwarf2out.cc (dwarf2out_early_finish): Remove call to
> 	ctf_debug_init_postprocess.
> ---
>   gcc/btfout.cc    | 28 +++++++++++++++++++++++++
>   gcc/ctfc.h       |  4 ++--
>   gcc/dwarf2ctf.cc | 54 +++++++++++-------------------------------------
>   gcc/dwarf2out.cc |  2 --
>   4 files changed, 42 insertions(+), 46 deletions(-)
> 
> diff --git a/gcc/btfout.cc b/gcc/btfout.cc
> index 07f066a4706..1b6a9ed811f 100644
> --- a/gcc/btfout.cc
> +++ b/gcc/btfout.cc
> @@ -1491,6 +1491,34 @@ btf_finalize (void)
>     tu_ctfc = NULL;
>   }
>   
> +/* Initial entry point of BTF generation, called at early_finish () after
> +   CTF information has possibly been output.  Translate all CTF information
> +   to BTF, and do any processing that must be done early, such as creating
> +   BTF_KIND_FUNC records.  */
> +
> +void
> +btf_early_finish (void)
> +{
> +  btf_init_postprocess ();
> +}
> +
> +/* Late entry point for BTF generation, called from dwarf2out_finish ().
> +   Complete and emit BTF information.  */
> +
> +void
> +btf_finish (const char * filename)
> +{
> +  btf_output (filename);
> +
> +  /* If compiling for BPF with CO-RE info, we cannot deallocate until after
> +     CO-RE information is created, which happens very late in BPF backend.
> +     Therefore, the deallocation (i.e. btf_finalize ()) is delayed until
> +     TARGET_ASM_FILE_END for BPF CO-RE.  */
> +  if (!btf_with_core_debuginfo_p ())
> +    btf_finalize ();
> +}
> +
> +
>   /* Traversal function for all BTF_KIND_FUNC type records.  */
>   
>   bool
> diff --git a/gcc/ctfc.h b/gcc/ctfc.h
> index fa188bf2f5a..e7bd93901cf 100644
> --- a/gcc/ctfc.h
> +++ b/gcc/ctfc.h
> @@ -384,8 +384,8 @@ extern void ctf_init (void);
>   extern void ctf_output (const char * filename);
>   extern void ctf_finalize (void);
>   
> -extern void btf_output (const char * filename);
> -extern void btf_init_postprocess (void);
> +extern void btf_early_finish (void);
> +extern void btf_finish (const char * filename);
>   extern void btf_finalize (void);
>   
>   extern ctf_container_ref ctf_get_tu_ctfc (void);
> diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
> index dc59569fe56..ec94982e4b1 100644
> --- a/gcc/dwarf2ctf.cc
> +++ b/gcc/dwarf2ctf.cc
> @@ -933,30 +933,6 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
>     return type_id;
>   }
>   
> -/* Prepare for output and write out the CTF debug information.  */
> -
> -static void
> -ctf_debug_finalize (const char *filename, bool btf)
> -{
> -  if (btf)
> -    {
> -      btf_output (filename);
> -      /* btf_finalize when compiling BPF applciations gets deallocated by the
> -	 BPF target in bpf_file_end.  */
> -      if (btf_debuginfo_p () && !btf_with_core_debuginfo_p ())
> -	btf_finalize ();
> -    }
> -
> -  else
> -    {
> -      /* Emit the collected CTF information.  */
> -      ctf_output (filename);
> -
> -      /* Reset the CTF state.  */
> -      ctf_finalize ();
> -    }
> -}
> -
>   bool
>   ctf_do_die (dw_die_ref die)
>   {
> @@ -996,27 +972,21 @@ ctf_debug_init (void)
>     add_name_attribute (ctf_unknown_die, "unknown");
>   }
>   
> -/* Preprocess the CTF debug information after initialization.  */
> -
> -void
> -ctf_debug_init_postprocess (bool btf)
> -{
> -  /* Only BTF requires postprocessing right after init.  */
> -  if (btf)
> -    btf_init_postprocess ();
> -}
> -
>   /* Early finish CTF/BTF debug info.  */
>   
>   void
>   ctf_debug_early_finish (const char * filename)
>   {
> -  /* Emit CTF debug info early always.  */
> -  if (ctf_debug_info_level > CTFINFO_LEVEL_NONE
> -      /* Emit BTF debug info early if CO-RE relocations are not
> -	 required.  */
> -      || (btf_debuginfo_p () && !btf_with_core_debuginfo_p ()))
> -    ctf_debug_finalize (filename, btf_debuginfo_p ());
> +  /* Emit the collected CTF information.  */
> +  if (ctf_debug_info_level > CTFINFO_LEVEL_NONE)
> +    ctf_output (filename);
> +
> +  if (btf_debuginfo_p ())
> +    /* If BTF will also be emitted, start translation to BTF.  */
> +    btf_early_finish ();
> +  else
> +    /* Otherwise, done with the CTF container.  */
> +    ctf_finalize ();
>   }
>   
>   /* Finish CTF/BTF debug info emission.  */
> @@ -1027,8 +997,8 @@ ctf_debug_finish (const char * filename)
>     /* Emit BTF debug info here when CO-RE relocations need to be generated.
>        BTF with CO-RE relocations needs to be generated when CO-RE is in effect
>        for the BPF target.  */
> -  if (btf_debuginfo_p () && btf_with_core_debuginfo_p ())
> -    ctf_debug_finalize (filename, btf_debuginfo_p ());
> +  if (btf_debuginfo_p ())
> +    btf_finish (filename);
>   }
>   
>   #include "gt-dwarf2ctf.h"
> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
> index 1b0e8b5a5b2..1664934ccc3 100644
> --- a/gcc/dwarf2out.cc
> +++ b/gcc/dwarf2out.cc
> @@ -33168,8 +33168,6 @@ dwarf2out_early_finish (const char *filename)
>         ctf_debug_do_cu (comp_unit_die ());
>         for (limbo_die_node *node = limbo_die_list; node; node = node->next)
>   	ctf_debug_do_cu (node->die);
> -      /* Post process the debug data in the CTF container if necessary.  */
> -      ctf_debug_init_postprocess (btf_debuginfo_p ());
>   
>         ctf_debug_early_finish (filename);
>       }


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 3/6] ctf: use pointers instead of IDs internally
  2024-05-02 17:11 ` [PATCH v2 3/6] ctf: use pointers instead of IDs internally David Faust
@ 2024-05-03 21:04   ` Indu Bhagat
  0 siblings, 0 replies; 13+ messages in thread
From: Indu Bhagat @ 2024-05-03 21:04 UTC (permalink / raw)
  To: David Faust, gcc-patches; +Cc: jose.marchesi, cupertino.miranda

On 5/2/24 10:11, David Faust wrote:
> This patch replaces all inter-type references in the ctfc internal data
> structures with pointers, rather than the references-by-ID which were
> used previously.
> 
> A couple of small updates in the BPF backend are included to make it
> compatible with the change.
> 
> This change is only to the in-memory representation of various CTF
> structures to make them easier to work with in various cases.  It is
> outwardly transparent; there is no change in emitted CTF.
> 
> gcc/
> 	* btfout.cc (btf_dvd_emit_preprocess_cb, btf_emit_preprocess)
> 	(btf_dmd_representable_bitfield_p, btf_asm_array, btf_asm_varent)
> 	(btf_asm_sou_member, btf_asm_func_arg, btf_init_postprocess):
> 	Adapt to structural changes in ctf_* structs.
> 	* ctfc.h (struct ctf_dtdef): Add forward declaration.
> 	(struct ctf_arinfo, struct ctf_funcinfo, struct ctf_sliceinfo)
> 	(struct ctf_itype, struct ctf_dmdef, struct ctf_func_arg)
> 	(struct ctf_dvdef): Use pointers instead of type IDs for
> 	references to other types.
> 	(struct ctf_dtdef): Add ref_type member.
> 	(ctf_type_exists): Use pointer instead of type ID.
> 	(ctf_add_reftype, ctf_add_enum, ctf_add_slice, ctf_add_float)
> 	(ctf_add_integer, ctf_add_unknown, ctf_add_pointer)
> 	(ctf_add_array, ctf_add_forward, ctf_add_typedef)
> 	(ctf_add_function, ctf_add_sou, ctf_add_enumerator)
> 	(ctf_add_variable): Likewise. Return pointer instead of ID.
> 	(ctf_lookup_tree_type): Return pointer to type instead of ID.
> 	* ctfc.cc: Analogous changes.
> 	* ctfout.cc (ctf_asm_type, ctf_asm_slice, ctf_asm_varent)
> 	(ctf_asm_sou_lmember, ctf_asm_sou_member, ctf_asm_func_arg)
> 	(output_ctf_objt_info): Adapt to changes.
> 	* dwarf2ctf.cc (gen_ctf_type, gen_ctf_void_type)
> 	(gen_ctf_unknown_type, gen_ctf_base_type, gen_ctf_pointer_type)
> 	(gen_ctf_subrange_type, gen_ctf_array_type, gen_ctf_typedef)
> 	(gen_ctf_modifier_type, gen_ctf_sou_type, gen_ctf_function_type)
> 	(gen_ctf_enumeration_type, gen_ctf_variable, gen_ctf_function)
> 	(gen_ctf_type, ctf_do_die): Likewise.
> 	* config/bpf/btfext-out.cc (struct btf_ext_core_reloc): Use
> 	pointer instead of type ID.
> 	(bpf_core_reloc_add, bpf_core_get_sou_member_index)
> 	(output_btfext_core_sections): Adapt to above changes.
> 	* config/bpf/core-builtins.cc (process_type): Likewise.
> ---
>   gcc/btfout.cc                   |  35 ++---
>   gcc/config/bpf/btfext-out.cc    |  12 +-
>   gcc/config/bpf/core-builtins.cc |   3 +-
>   gcc/ctfc.cc                     | 137 +++++++++---------
>   gcc/ctfc.h                      |  61 ++++----
>   gcc/ctfout.cc                   |  19 +--
>   gcc/dwarf2ctf.cc                | 244 +++++++++++++++-----------------
>   7 files changed, 252 insertions(+), 259 deletions(-)
> 
> diff --git a/gcc/config/bpf/btfext-out.cc b/gcc/config/bpf/btfext-out.cc
> index 7ec438fd1d1..ce596e33643 100644
> --- a/gcc/config/bpf/btfext-out.cc
> +++ b/gcc/config/bpf/btfext-out.cc
> @@ -134,7 +134,7 @@ struct GTY ((chain_next ("%h.next"))) btf_ext_lineinfo
>   
>   /* Internal representation of a BPF CO-RE relocation record.  */
>   struct GTY ((chain_next ("%h.next"))) btf_ext_core_reloc {
> -  unsigned int bpfcr_type;		/* BTF type ID of container.  */
> +  ctf_dtdef_ref bpfcr_type;		/* BTF type of container.  */

I find the comment "BTF type of container" associated with the member 
confusing.  May be we say " BTF type involved with the reloc " or 
something like that ?

>     unsigned int  bpfcr_astr_off;		/* Offset of access string in .BTF
>   					   string table.  */
>     rtx_code_label * bpfcr_insn_label;	/* RTX label attached to instruction
> @@ -296,13 +296,14 @@ bpf_core_reloc_add (const tree type, const char * section_name,
>     struct btf_ext_core_reloc *bpfcr = bpf_create_core_reloc (section_name, &sec);
>   
>     ctf_container_ref ctfc = ctf_get_tu_ctfc ();
> +  ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, type);
>   
>     /* Buffer the access string in the auxiliary strtab.  */
>     bpfcr->bpfcr_astr_off = 0;
>     gcc_assert (accessor != NULL);
>     bpfcr->bpfcr_astr_off = btf_ext_add_string (accessor);
>   
> -  bpfcr->bpfcr_type = get_btf_id (ctf_lookup_tree_type (ctfc, type));
> +  bpfcr->bpfcr_type = dtd;
>     bpfcr->bpfcr_insn_label = label;
>     bpfcr->bpfcr_kind = kind;
>   
> @@ -341,7 +342,7 @@ bpf_core_get_sou_member_index (ctf_container_ref ctfc, const tree node)
>         for (dmd = dtd->dtd_u.dtu_members;
>              dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
>           {
> -	  bool field_has_btf = get_btf_id (dmd->dmd_type) <= BTF_MAX_TYPE;
> +	  bool field_has_btf = (dmd->dmd_type && dmd->dmd_type->dtd_type <= BTF_MAX_TYPE);
>   
>   	  if (field == node)
>   	    return field_has_btf ? i : -1;
> @@ -574,8 +575,9 @@ output_btfext_core_sections (void)
>   				 false);
>   	      char *str = xstrdup (pp_formatted_text (&pp));
>   
> -	      dw2_asm_output_data (4, bpfcr->bpfcr_type, "bpfcr_type (%s)",
> -				   str);
> +	      uint32_t type_id =
> +		bpfcr->bpfcr_type ? bpfcr->bpfcr_type->dtd_type : 0;

Use BTF_VOID_TYPEID ?

> +	      dw2_asm_output_data (4, type_id, "bpfcr_type (%s)", str);
>   	      dw2_asm_output_data (4, bpfcr->bpfcr_astr_off + str_aux_off,
>   				   "bpfcr_astr_off (\"%s\")",
>   				   bpfcr->info.accessor_str);
> diff --git a/gcc/config/bpf/core-builtins.cc b/gcc/config/bpf/core-builtins.cc
> index 829acea98f7..d5a7de825ad 100644
> --- a/gcc/config/bpf/core-builtins.cc
> +++ b/gcc/config/bpf/core-builtins.cc
> @@ -1021,7 +1021,8 @@ process_type (struct cr_builtins *data)
>         && data->default_value != NULL)
>     {
>       ctf_container_ref ctfc = ctf_get_tu_ctfc ();
> -    unsigned int btf_id = get_btf_id (ctf_lookup_tree_type (ctfc, ret.type));
> +    ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, ret.type);
> +    unsigned int btf_id = dtd ? dtd->dtd_type : 0;

Use BTF_VOID_TYPEID ?

>       data->rtx_default_value = expand_normal (build_int_cst (integer_type_node,
>   							    btf_id));
>     }
> diff --git a/gcc/ctfc.cc b/gcc/ctfc.cc
> index 67711606ab8..d8f1037b4e0 100644
> --- a/gcc/ctfc.cc
> +++ b/gcc/ctfc.cc
> @@ -373,9 +373,9 @@ ctf_add_cuname (ctf_container_ref ctfc, const char * filename)
>      ctf_dvd_lookup, as applicable, to ascertain that the CTF type or the CTF
>      variable respectively does not already exist, and then add it.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name,
> -		 ctf_dtdef_ref * rp, dw_die_ref die)
> +		 dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
>     ctf_id_t type;
> @@ -397,18 +397,16 @@ ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   
>     ctf_dtd_insert (ctfc, dtd);
>   
> -  *rp = dtd;
> -  return type;
> +  return dtd;
>   }
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   ctf_add_encoded (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   		 const ctf_encoding_t * ep, uint32_t kind, dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type;
>   
> -  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, name, die);
>   
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
>   
> @@ -424,83 +422,81 @@ ctf_add_encoded (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
> -ctf_id_t
> -ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
> +ctf_dtdef_ref
> +ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_dtdef_ref ref,
>   		 uint32_t kind, dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type;
>   
> -  gcc_assert (ref <= CTF_MAX_TYPE);
> +  gcc_assert (ref != NULL);
>   
> -  type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, NULL, die);
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
>     /* Caller of this API must guarantee that a CTF type with id = ref already
>        exists.  This will also be validated for us at link-time.  */
> -  dtd->dtd_data.ctti_type = (uint32_t) ref;
> +  dtd->dtd_data.ctti_type = (uint32_t) ref->dtd_type;
> +  dtd->ref_type = ref;
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_forward (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   		 uint32_t kind, dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type = 0;
>   
> -  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, name, die);
>   
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
>     dtd->dtd_data.ctti_type = kind;
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_typedef (ctf_container_ref ctfc, uint32_t flag, const char * name,
> -		 ctf_id_t ref, dw_die_ref die)
> +		 ctf_dtdef_ref ref, dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type;
>   
> -  gcc_assert (ref <= CTF_MAX_TYPE);
> +  gcc_assert (ref != NULL);
>     /* Nameless Typedefs are not expected.  */
>     gcc_assert ((name != NULL) && strcmp (name, ""));
>   
> -  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, name, die);
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_TYPEDEF, flag, 0);
>     /* Caller of this API must guarantee that a CTF type with id = ref already
>        exists.  This will also be validated for us at link-time.  */
> -  dtd->dtd_data.ctti_type = (uint32_t) ref;
> +  dtd->dtd_data.ctti_type = (uint32_t) ref->dtd_type;
> +  dtd->ref_type = ref;
>   
>     gcc_assert (dtd->dtd_type != dtd->dtd_data.ctti_type);
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
> -ctf_id_t
> -ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
> +ctf_dtdef_ref
> +ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_dtdef_ref ref,
>   	       uint32_t bit_offset, uint32_t bit_size, dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type;
>     uint32_t roundup_nbytes;
>   
>     gcc_assert ((bit_size <= 255) && (bit_offset <= 255));
>   
> -  gcc_assert (ref <= CTF_MAX_TYPE);
> +  gcc_assert (ref != NULL);
>   
> -  type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, NULL, die);
>   
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
>   
> @@ -514,49 +510,48 @@ ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
>   
>     /* Caller of this API must guarantee that a CTF type with id = ref already
>        exists.  This will also be validated for us at link-time.  */
> -  dtd->dtd_u.dtu_slice.cts_type = (uint32_t) ref;
> +  dtd->dtd_u.dtu_slice.cts_type = ref;
>     dtd->dtd_u.dtu_slice.cts_bits = bit_size;
>     dtd->dtd_u.dtu_slice.cts_offset = bit_offset;
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_float (ctf_container_ref ctfc, uint32_t flag,
>   	       const char * name, const ctf_encoding_t * ep, dw_die_ref die)
>   {
>     return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_FLOAT, die));
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_integer (ctf_container_ref ctfc, uint32_t flag,
>   		 const char * name, const ctf_encoding_t * ep, dw_die_ref die)
>   {
>     return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_INTEGER, die));
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_unknown (ctf_container_ref ctfc, uint32_t flag,
>   		 const char * name, const ctf_encoding_t * ep, dw_die_ref die)
>   {
>     return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_UNKNOWN, die));
>   }
>   
> -ctf_id_t
> -ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
> +ctf_dtdef_ref
> +ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_dtdef_ref ref,
>   		 dw_die_ref die)
>   {
>     return (ctf_add_reftype (ctfc, flag, ref, CTF_K_POINTER, die));
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
>   	       dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type;
>   
>     gcc_assert (arp);
>   
> @@ -564,7 +559,7 @@ ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
>        arp->ctr_index are already added.  This will also be validated for us at
>        link-time.  */
>   
> -  type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, NULL, die);
>   
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
>     dtd->dtd_data.ctti_size = 0;
> @@ -572,15 +567,14 @@ ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   	      HOST_WIDE_INT size, bool eunsigned, dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type;
>   
>     /* In the compiler, no need to handle the case of promoting forwards to
>        enums.  This comment is simply to note a divergence from libctf.  */
> @@ -595,7 +589,7 @@ ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   	= CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
>       }
>   
> -  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, name, die);
>   
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
>   
> @@ -608,11 +602,11 @@ ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
>   int
> -ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
> +ctf_add_enumerator (ctf_container_ref ctfc, ctf_dtdef_ref enum_dtd, const char * name,
>   		    HOST_WIDE_INT value, dw_die_ref die)
>   {
>     ctf_dmdef_t * dmd;
> @@ -622,7 +616,7 @@ ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
>        addded.  This will also be validated for us at link-time.  */
>     ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
>     gcc_assert (dtd);
> -  gcc_assert (dtd->dtd_type == enid);
> +  gcc_assert (dtd == enum_dtd);
>     gcc_assert (name);
>   
>     kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
> @@ -646,7 +640,7 @@ ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
>   
>     /* Buffer the strings in the CTF string table.  */
>     dmd->dmd_name = ctf_add_string (ctfc, name, &(dmd->dmd_name_offset));
> -  dmd->dmd_type = CTF_NULL_TYPEID;
> +  dmd->dmd_type = NULL;
>     dmd->dmd_offset = 0;
>   
>     dmd->dmd_value = value;
> @@ -662,7 +656,7 @@ ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
>   
>   int
>   ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou,
> -		       const char * name, ctf_id_t type,
> +		       const char * name, ctf_dtdef_ref type,
>   		       uint64_t bit_offset)
>   {
>     ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, sou);
> @@ -702,7 +696,7 @@ ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou,
>   }
>   
>   int
> -ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref,
> +ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_dtdef_ref ref,
>   		  dw_die_ref die, unsigned int external_vis,
>   		  dw_die_ref die_var_decl)
>   {
> @@ -747,16 +741,16 @@ ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref,
>   
>   int
>   ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
> -		      const char * name, ctf_id_t type)
> +		      const char * name, ctf_dtdef_ref arg_dtd)
>   {
> -  ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, func);
> +  ctf_dtdef_ref func_dtd = ctf_dtd_lookup (ctfc, func);
>     ctf_func_arg_t * farg;
>     uint32_t vlen;
>   
>     /* The function to which argument is being added must already exist.  */
> -  gcc_assert (dtd);
> +  gcc_assert (func_dtd);
>     /* The number of args must have been non-zero.  */
> -  vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
> +  vlen = CTF_V2_INFO_VLEN (func_dtd->dtd_data.ctti_info);
>     gcc_assert (vlen);
>   
>     farg = ggc_cleared_alloc<ctf_func_arg_t> ();
> @@ -766,9 +760,9 @@ ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
>        these strings to avoid unnecessary bloat in CTF section in CTF V3.  */
>     farg->farg_name = ctf_add_string (ctfc, name, &(farg->farg_name_offset),
>   				    CTF_AUX_STRTAB);
> -  farg->farg_type = type;
> +  farg->farg_type = arg_dtd;
>   
> -  ctf_farg_list_append (&dtd->dtd_u.dtu_argv, farg);
> +  ctf_farg_list_append (&func_dtd->dtd_u.dtu_argv, farg);
>   
>     /* For aux_str, keep ctfc_aux_strlen updated for debugging.  */
>     if ((name != NULL) && strcmp (name, ""))
> @@ -777,13 +771,12 @@ ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
>     return 0;
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   		  const ctf_funcinfo_t * ctc, dw_die_ref die,
>   		  bool from_global_func, int linkage)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type;
>     uint32_t vlen;
>   
>     gcc_assert (ctc);
> @@ -791,27 +784,27 @@ ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name,
>     vlen = ctc->ctc_argc;
>     gcc_assert (vlen <= CTF_MAX_VLEN);
>   
> -  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, name, die);
>   
>     dtd->from_global_func = from_global_func;
>     dtd->linkage = linkage;
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
> +  dtd->ref_type = ctc->ctc_return;
>     /* Caller must make sure CTF types for ctc->ctc_return are already added.  */
> -  dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return;
> +  dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return->dtd_type;
>     /* Caller must make sure CTF types for function arguments are already added
>        via ctf_add_function_arg () API.  */
>   
>     ctfc->ctfc_num_stypes++;
>   
> -  return type;
> +  return dtd;
>   }
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   	     uint32_t kind, size_t size, dw_die_ref die)
>   {
>     ctf_dtdef_ref dtd;
> -  ctf_id_t type = 0;
>   
>     gcc_assert ((kind == CTF_K_STRUCT) || (kind == CTF_K_UNION));
>   
> @@ -828,7 +821,7 @@ ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name,
>   	= CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
>       }
>   
> -  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
> +  dtd = ctf_add_generic (ctfc, flag, name, die);
>   
>     dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
>   
> @@ -845,23 +838,23 @@ ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name,
>         ctfc->ctfc_num_stypes++;
>       }
>   
> -  return type;
> +  return dtd;
>   }
>   
>   /* Given a TREE_TYPE node, return the CTF type ID for that type.  */
>   
> -ctf_id_t
> +ctf_dtdef_ref
>   ctf_lookup_tree_type (ctf_container_ref ctfc, const tree type)
>   {
>     dw_die_ref die = lookup_type_die (type);
>     if (die == NULL)
> -    return CTF_NULL_TYPEID;
> +    return NULL;
>   
>     ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
>     if (dtd == NULL)
> -    return CTF_NULL_TYPEID;
> +    return NULL;
>   
> -  return dtd->dtd_type;
> +  return dtd;
>   }
>   
>   /* Check if CTF for TYPE has already been generated.  Mainstay for
> @@ -870,7 +863,7 @@ ctf_lookup_tree_type (ctf_container_ref ctfc, const tree type)
>   
>   bool
>   ctf_type_exists (ctf_container_ref ctfc, dw_die_ref type,
> -		 ctf_id_t * type_id)
> +		 ctf_dtdef_ref * dtd)
>   {
>     bool exists = false;
>     ctf_dtdef_ref ctf_type_seen = ctf_dtd_lookup (ctfc, type);
> @@ -879,7 +872,7 @@ ctf_type_exists (ctf_container_ref ctfc, dw_die_ref type,
>       {
>         exists = true;
>         /* CTF type for this type exists.  */
> -      *type_id = ctf_type_seen->dtd_type;
> +      *dtd = ctf_type_seen;
>       }
>   
>     return exists;
> diff --git a/gcc/ctfc.h b/gcc/ctfc.h
> index e7bd93901cf..cfc805db7b5 100644
> --- a/gcc/ctfc.h
> +++ b/gcc/ctfc.h
> @@ -48,6 +48,8 @@ along with GCC; see the file COPYING3.  If not see
>   
>   typedef uint64_t ctf_id_t;
>   
> +struct ctf_dtdef;
> +

Should we bring the other typdefs too here and use them consistently 
from here onwards ?

+ typedef struct ctf_dtdef ctf_dtdef_t;
+ typedef ctf_dtdef_t * ctf_dtdef_ref;

Earlier the only usages of the above were after struct ctf_dtdef was 
defined.

>   /* CTF string table element (list node).  */
>   
>   typedef struct GTY ((chain_next ("%h.cts_next"))) ctf_string
> @@ -81,23 +83,23 @@ typedef struct GTY (()) ctf_encoding
>   
>   typedef struct GTY (()) ctf_arinfo
>   {
> -  ctf_id_t ctr_contents;	/* Type of array contents.  */
> -  ctf_id_t ctr_index;		/* Type of array index.  */
> -  unsigned int ctr_nelems;	/* Number of elements.  */
> +  struct ctf_dtdef * ctr_contents; /* Type of array contents.  */
> +  struct ctf_dtdef * ctr_index;	   /* Type of array index.  */

So this will be:

ctf_dtdef_ref ctr_contents;
ctf_dtdef_ref ctr_index;

and so on for each usage of struct ctf_dtdef * below.

> +  unsigned int ctr_nelems;	   /* Number of elements.  */
>   } ctf_arinfo_t;
>   
>   /* Function information for CTF generation.  */
>   
>   typedef struct GTY (()) ctf_funcinfo
>   {
> -  ctf_id_t ctc_return;		/* Function return type.  */
> -  unsigned int ctc_argc;	/* Number of typed arguments to function.  */
> -  unsigned int ctc_flags;	/* Function attributes (see below).  */
> +  struct ctf_dtdef * ctc_return; /* Function return type.  */
> +  unsigned int ctc_argc;	 /* Number of typed arguments to function.  */
> +  unsigned int ctc_flags;	 /* Function attributes (see below).  */
>   } ctf_funcinfo_t;
>   
>   typedef struct GTY (()) ctf_sliceinfo
>   {
> -  unsigned int cts_type;	/* Reference CTF type.  */
> +  struct ctf_dtdef * cts_type;	/* Reference CTF type.  */
>     unsigned short cts_offset;	/* Offset in bits of the first bit.  */
>     unsigned short cts_bits;	/* Size in bits.  */
>   } ctf_sliceinfo_t;
> @@ -130,7 +132,7 @@ typedef struct GTY (()) ctf_itype
>   typedef struct GTY ((chain_next ("%h.dmd_next"))) ctf_dmdef
>   {
>     const char * dmd_name;	/* Name of this member.  */
> -  ctf_id_t dmd_type;		/* Type of this member (for sou).  */
> +  struct ctf_dtdef * dmd_type;	/* Type of this member (for sou).  */
>     uint32_t dmd_name_offset;	/* Offset of the name in str table.  */
>     uint64_t dmd_offset;		/* Offset of this member in bits (for sou).  */
>     HOST_WIDE_INT dmd_value;	/* Value of this member (for enum).  */
> @@ -143,7 +145,7 @@ typedef struct GTY ((chain_next ("%h.dmd_next"))) ctf_dmdef
>   
>   typedef struct GTY (()) ctf_func_arg
>   {
> -  ctf_id_t farg_type;		  /* Type identifier of the argument.  */
> +  struct ctf_dtdef * farg_type;	  /* Type of the argument.  */
>     const char * farg_name;	  /* Name of the argument.  */
>     uint32_t farg_name_offset;	  /* Offset of the name in str table.  */
>     struct ctf_func_arg * farg_next;/* A list node.  */
> @@ -158,6 +160,7 @@ struct GTY ((for_user)) ctf_dtdef
>     dw_die_ref dtd_key;	      /* Type key for hashing.  */
>     const char * dtd_name;      /* Name associated with definition (if any).  */
>     ctf_id_t dtd_type;	      /* Type identifier for this definition.  */
> +  struct ctf_dtdef *ref_type; /* Type referred to by this type (if any).  */
>     ctf_itype_t dtd_data;	      /* Type node.  */
>     bool from_global_func; /* Whether this type was added from a global
>   			    function.  */
> @@ -188,7 +191,7 @@ struct GTY ((for_user)) ctf_dvdef
>     const char * dvd_name;	/* Name associated with variable.  */
>     uint32_t dvd_name_offset;	/* Offset of the name in str table.  */
>     unsigned int dvd_visibility;	/* External visibility.  0=static,1=global.  */
> -  ctf_id_t dvd_type;		/* Type of variable.  */
> +  struct ctf_dtdef * dvd_type;	/* Type of variable.  */
>   };
>   
>   typedef struct ctf_dvdef ctf_dvdef_t;
> @@ -390,7 +393,7 @@ extern void btf_finalize (void);
>   
>   extern ctf_container_ref ctf_get_tu_ctfc (void);
>   
> -extern bool ctf_type_exists (ctf_container_ref, dw_die_ref, ctf_id_t *);
> +extern bool ctf_type_exists (ctf_container_ref, dw_die_ref, ctf_dtdef_ref *);
>   
>   extern void ctf_add_cuname (ctf_container_ref, const char *);
>   
> @@ -404,41 +407,41 @@ extern bool ctf_dvd_ignore_lookup (const ctf_container_ref ctfc,
>   extern const char * ctf_add_string (ctf_container_ref, const char *,
>   				    uint32_t *, int);
>   
> -extern ctf_id_t ctf_add_reftype (ctf_container_ref, uint32_t, ctf_id_t,
> +extern ctf_dtdef_ref ctf_add_reftype (ctf_container_ref, uint32_t, ctf_dtdef_ref,
>   				 uint32_t, dw_die_ref);
> -extern ctf_id_t ctf_add_enum (ctf_container_ref, uint32_t, const char *,
> +extern ctf_dtdef_ref ctf_add_enum (ctf_container_ref, uint32_t, const char *,
>   			      HOST_WIDE_INT, bool, dw_die_ref);
> -extern ctf_id_t ctf_add_slice (ctf_container_ref, uint32_t, ctf_id_t,
> +extern ctf_dtdef_ref ctf_add_slice (ctf_container_ref, uint32_t, ctf_dtdef_ref,
>   			       uint32_t, uint32_t, dw_die_ref);
> -extern ctf_id_t ctf_add_float (ctf_container_ref, uint32_t, const char *,
> +extern ctf_dtdef_ref ctf_add_float (ctf_container_ref, uint32_t, const char *,
>   			       const ctf_encoding_t *, dw_die_ref);
> -extern ctf_id_t ctf_add_integer (ctf_container_ref, uint32_t, const char *,
> +extern ctf_dtdef_ref ctf_add_integer (ctf_container_ref, uint32_t, const char *,
>   				 const ctf_encoding_t *, dw_die_ref);
> -extern ctf_id_t ctf_add_unknown (ctf_container_ref, uint32_t, const char *,
> +extern ctf_dtdef_ref ctf_add_unknown (ctf_container_ref, uint32_t, const char *,
>   				 const ctf_encoding_t *, dw_die_ref);
> -extern ctf_id_t ctf_add_pointer (ctf_container_ref, uint32_t, ctf_id_t,
> +extern ctf_dtdef_ref ctf_add_pointer (ctf_container_ref, uint32_t, ctf_dtdef_ref,
>   				 dw_die_ref);
> -extern ctf_id_t ctf_add_array (ctf_container_ref, uint32_t,
> +extern ctf_dtdef_ref ctf_add_array (ctf_container_ref, uint32_t,
>   			       const ctf_arinfo_t *, dw_die_ref);
> -extern ctf_id_t ctf_add_forward (ctf_container_ref, uint32_t, const char *,
> +extern ctf_dtdef_ref ctf_add_forward (ctf_container_ref, uint32_t, const char *,
>   				 uint32_t, dw_die_ref);
> -extern ctf_id_t ctf_add_typedef (ctf_container_ref, uint32_t, const char *,
> -				 ctf_id_t, dw_die_ref);
> -extern ctf_id_t ctf_add_function (ctf_container_ref, uint32_t, const char *,
> +extern ctf_dtdef_ref ctf_add_typedef (ctf_container_ref, uint32_t, const char *,
> +				 ctf_dtdef_ref, dw_die_ref);
> +extern ctf_dtdef_ref ctf_add_function (ctf_container_ref, uint32_t, const char *,
>   				  const ctf_funcinfo_t *, dw_die_ref, bool, int);
> -extern ctf_id_t ctf_add_sou (ctf_container_ref, uint32_t, const char *,
> +extern ctf_dtdef_ref ctf_add_sou (ctf_container_ref, uint32_t, const char *,
>   			     uint32_t, size_t, dw_die_ref);
>   
> -extern int ctf_add_enumerator (ctf_container_ref, ctf_id_t, const char *,
> +extern int ctf_add_enumerator (ctf_container_ref, ctf_dtdef_ref, const char *,
>   			       HOST_WIDE_INT, dw_die_ref);
>   extern int ctf_add_member_offset (ctf_container_ref, dw_die_ref, const char *,
> -				  ctf_id_t, uint64_t);
> +				  ctf_dtdef_ref, uint64_t);
>   extern int ctf_add_function_arg (ctf_container_ref, dw_die_ref,
> -				 const char *, ctf_id_t);
> -extern int ctf_add_variable (ctf_container_ref, const char *, ctf_id_t,
> +				 const char *, ctf_dtdef_ref);
> +extern int ctf_add_variable (ctf_container_ref, const char *, ctf_dtdef_ref,
>   			     dw_die_ref, unsigned int, dw_die_ref);
>   
> -extern ctf_id_t ctf_lookup_tree_type (ctf_container_ref, const tree);
> +extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
>   extern ctf_id_t get_btf_id (ctf_id_t);
>   
>   typedef bool (*funcs_traverse_callback) (ctf_dtdef_ref, void *);
> diff --git a/gcc/ctfout.cc b/gcc/ctfout.cc
> index ee082b5fd01..dd686703ebc 100644
> --- a/gcc/ctfout.cc
> +++ b/gcc/ctfout.cc
> @@ -380,7 +380,7 @@ ctf_asm_type (ctf_dtdef_ref type)
>   static void
>   ctf_asm_slice (ctf_dtdef_ref type)
>   {
> -  dw2_asm_output_data (4, type->dtd_u.dtu_slice.cts_type, "cts_type");
> +  dw2_asm_output_data (4, (uint32_t) type->dtd_u.dtu_slice.cts_type->dtd_type, "cts_type");

What do you think about introducing an access method / macro (say 
ctfc_get_type_id or such) for getting the dtd_type from given ctf_dtdef_ref.

So instead of

  (uint32_t) type->dtd_u.dtu_slice.cts_type->dtd_type

we use

  ctfc_get_type_id (type->dtd_u.dtu_slice.cts_type)

>     dw2_asm_output_data (2, type->dtd_u.dtu_slice.cts_offset, "cts_offset");
>     dw2_asm_output_data (2, type->dtd_u.dtu_slice.cts_bits, "cts_bits");
>   }
> @@ -390,8 +390,8 @@ ctf_asm_slice (ctf_dtdef_ref type)
>   static void
>   ctf_asm_array (ctf_dtdef_ref dtd)
>   {
> -  dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_contents, "cta_contents");
> -  dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_index, "cta_index");
> +  dw2_asm_output_data (4, (uint32_t) dtd->dtd_u.dtu_arr.ctr_contents->dtd_type, "cta_contents");
> +  dw2_asm_output_data (4, (uint32_t) dtd->dtd_u.dtu_arr.ctr_index->dtd_type, "cta_index");
>     dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_nelems, "cta_nelems");
>   }
>   
> @@ -403,7 +403,7 @@ ctf_asm_varent (ctf_dvdef_ref var)
>     /* Output the reference to the name in the string table.  */
>     dw2_asm_output_data (4, var->dvd_name_offset, "ctv_name");
>     /* Output the type index.  */
> -  dw2_asm_output_data (4, var->dvd_type, "ctv_typeidx");
> +  dw2_asm_output_data (4, (uint32_t) var->dvd_type->dtd_type, "ctv_typeidx");
>   }
>   
>   /* Asm'out a member of CTF struct or union, represented by ctf_lmember_t.  */
> @@ -414,7 +414,7 @@ ctf_asm_sou_lmember (ctf_dmdef_t * dmd)
>     dw2_asm_output_data (4, dmd->dmd_name_offset, "ctlm_name");
>     dw2_asm_output_data (4, CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset),
>   		       "ctlm_offsethi");
> -  dw2_asm_output_data (4, dmd->dmd_type, "ctlm_type");
> +  dw2_asm_output_data (4, (uint32_t) dmd->dmd_type->dtd_type, "ctlm_type");
>     dw2_asm_output_data (4, CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset),
>   		       "ctlm_offsetlo");
>   }
> @@ -426,7 +426,7 @@ ctf_asm_sou_member (ctf_dmdef_t * dmd)
>   {
>     dw2_asm_output_data (4, dmd->dmd_name_offset, "ctm_name");
>     dw2_asm_output_data (4, dmd->dmd_offset, "ctm_offset");
> -  dw2_asm_output_data (4, dmd->dmd_type, "ctm_type");
> +  dw2_asm_output_data (4, (uint32_t) dmd->dmd_type->dtd_type, "ctm_type");
>   }
>   
>   /* Asm'out an enumerator constant.  */
> @@ -443,7 +443,10 @@ ctf_asm_enum_const (ctf_dmdef_t * dmd)
>   static void
>   ctf_asm_func_arg (ctf_func_arg_t * farg)
>   {
> -  dw2_asm_output_data (4, farg->farg_type, "dtu_argv");
> +  /* farg_type may be NULL, indicating varargs.  */
> +  dw2_asm_output_data (4, farg->farg_type
> +		       ? (uint32_t) farg->farg_type->dtd_type
> +		       : 0, "dtu_argv");
>   }
>   
>   /* CTF writeout to asm file.  */
> @@ -537,7 +540,7 @@ output_ctf_obj_info (ctf_container_ref ctfc)
>         var = ctfc->ctfc_gobjts_list[i];
>   
>         /* CTF type ID corresponding to the type of the variable.  */
> -      dw2_asm_output_data (4, var->dvd_type, "objtinfo_var_type");
> +      dw2_asm_output_data (4, (uint32_t) var->dvd_type->dtd_type, "objtinfo_var_type");
>       }
>   
>   }
> diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
> index ec94982e4b1..f16b5ceee74 100644
> --- a/gcc/dwarf2ctf.cc
> +++ b/gcc/dwarf2ctf.cc
> @@ -29,7 +29,7 @@ along with GCC; see the file COPYING3.  If not see
>   
>   /* Forward declarations for some routines defined in this file.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_type (ctf_container_ref, dw_die_ref);
>   
>   /* All the DIE structures we handle come from the DWARF information
> @@ -156,7 +156,7 @@ ctf_get_die_loc_col (dw_die_ref die)
>   
>   /* Generate CTF for the void type.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_void_type (ctf_container_ref ctfc)
>   {
>     ctf_encoding_t ctf_encoding = {0, 0, 0};
> @@ -174,10 +174,10 @@ gen_ctf_void_type (ctf_container_ref ctfc)
>   
>   /* Generate CTF type of unknown kind.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_unknown_type (ctf_container_ref ctfc)
>   {
> -  ctf_id_t unknown_type_id;
> +  ctf_dtdef_ref dtd;
>   
>     /* In CTF, the unknown type is encoded as a 0 byte sized type with kind
>        CTF_K_UNKNOWN.  Create an encoding object merely to reuse the underlying
> @@ -187,11 +187,11 @@ gen_ctf_unknown_type (ctf_container_ref ctfc)
>   
>     gcc_assert (ctf_unknown_die != NULL);
>     /* Type de-duplication.  */
> -  if (!ctf_type_exists (ctfc, ctf_unknown_die, &unknown_type_id))
> -    unknown_type_id = ctf_add_unknown (ctfc, CTF_ADD_ROOT, "unknown",
> -				       &ctf_encoding, ctf_unknown_die);
> +  if (!ctf_type_exists (ctfc, ctf_unknown_die, &dtd))
> +    dtd = ctf_add_unknown (ctfc, CTF_ADD_ROOT, "unknown",
> +			   &ctf_encoding, ctf_unknown_die);
>   
> -  return unknown_type_id;
> +  return dtd;
>   }
>   
>   /* Sizes of entities can be given in bytes or bits.  This function
> @@ -217,10 +217,10 @@ ctf_die_bitsize (dw_die_ref die)
>      Important: the caller of this API must make sure that duplicate types are
>      not added.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
>   {
> -  ctf_id_t type_id = CTF_NULL_TYPEID;
> +  ctf_dtdef_ref dtd = NULL;
>   
>     ctf_encoding_t ctf_encoding = {0, 0, 0};
>   
> @@ -236,8 +236,8 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
>         ctf_encoding.cte_bits = 0;
>   
>         gcc_assert (name_string);
> -      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
> -				 &ctf_encoding, type);
> +      dtd = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
> +			     &ctf_encoding, type);
>   
>         break;
>       case DW_ATE_boolean:
> @@ -246,8 +246,8 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
>         ctf_encoding.cte_bits = bit_size;
>   
>         gcc_assert (name_string);
> -      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
> -				 &ctf_encoding, type);
> +      dtd = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
> +			     &ctf_encoding, type);
>         break;
>       case DW_ATE_float:
>         {
> @@ -269,7 +269,7 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
>   	  break;
>   
>   	ctf_encoding.cte_bits = bit_size;
> -	type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
> +	dtd = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
>   				 &ctf_encoding, type);
>   
>   	break;
> @@ -291,7 +291,7 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
>   	ctf_encoding.cte_format |= CTF_INT_SIGNED;
>   
>         ctf_encoding.cte_bits = bit_size;
> -      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
> +      dtd = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
>   				 &ctf_encoding, type);
>         break;
>   
> @@ -315,7 +315,7 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
>   	  break;
>   
>   	ctf_encoding.cte_bits = bit_size;
> -	type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
> +	dtd = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
>   				 &ctf_encoding, type);
>   	break;
>         }
> @@ -324,41 +324,39 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
>         break;
>       }
>   
> -  return type_id;
> +  return dtd;
>   }
>   
>   /* Generate CTF for a pointer type.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_pointer_type (ctf_container_ref ctfc, dw_die_ref ptr_type)
>   {
> -  ctf_id_t type_id = CTF_NULL_TYPEID;
> -  ctf_id_t ptr_type_id = CTF_NULL_TYPEID;
> +  ctf_dtdef_ref pointed_dtd, pointer_dtd;
>     dw_die_ref pointed_type_die = ctf_get_AT_type (ptr_type);
>   
> -  type_id = gen_ctf_type (ctfc, pointed_type_die);
> +  pointed_dtd = gen_ctf_type (ctfc, pointed_type_die);
>   
>     /* Type de-duplication.
>        Consult the ctfc_types hash again before adding the CTF pointer type
>        because there can be cases where a pointer type may have been added by
>        the gen_ctf_type call above.  */
> -  if (ctf_type_exists (ctfc, ptr_type, &ptr_type_id))
> -    return ptr_type_id;
> +  if (!ctf_type_exists (ctfc, ptr_type, &pointer_dtd))
> +    pointer_dtd = ctf_add_pointer (ctfc, CTF_ADD_ROOT, pointed_dtd, ptr_type);
>   
> -  ptr_type_id = ctf_add_pointer (ctfc, CTF_ADD_ROOT, type_id, ptr_type);
> -  return ptr_type_id;
> +  return pointer_dtd;
>   }
>   
>   /* Recursively generate CTF for array dimensions starting at DIE C (of type
>      DW_TAG_subrange_type) until DIE LAST (of type DW_TAG_subrange_type) is
>      reached.  ARRAY_ELEMS_TYPE_ID is base type for the array.  */
>   
> -static ctf_id_t
> -gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_id_t array_elems_type_id,
> +static ctf_dtdef_ref
> +gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_dtdef_ref array_elems_type,
>   		       dw_die_ref c, dw_die_ref last)
>   {
>     ctf_arinfo_t arinfo;
> -  ctf_id_t array_node_type_id = CTF_NULL_TYPEID;
> +  ctf_dtdef_ref array_dtd;
>   
>     dw_attr_node *upper_bound_at;
>     dw_die_ref array_index_type;
> @@ -398,30 +396,29 @@ gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_id_t array_elems_type_id,
>     arinfo.ctr_index = gen_ctf_type (ctfc, array_index_type);
>   
>     if (c == last)
> -    arinfo.ctr_contents = array_elems_type_id;
> +    arinfo.ctr_contents = array_elems_type;
>     else
> -    arinfo.ctr_contents = gen_ctf_subrange_type (ctfc, array_elems_type_id,
> +    arinfo.ctr_contents = gen_ctf_subrange_type (ctfc, array_elems_type,
>   						 dw_get_die_sib (c), last);
>   
> -  if (!ctf_type_exists (ctfc, c, &array_node_type_id))
> -    array_node_type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, c);
> +  if (!ctf_type_exists (ctfc, c, &array_dtd))
> +    array_dtd = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, c);
>   
> -  return array_node_type_id;
> +  return array_dtd;
>   }
>   
>   /* Generate CTF for an ARRAY_TYPE.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_array_type (ctf_container_ref ctfc,
>   		    dw_die_ref array_type)
>   {
>     dw_die_ref first, last, array_elems_type;
> -  ctf_id_t array_elems_type_id = CTF_NULL_TYPEID;
> -  ctf_id_t array_type_id = CTF_NULL_TYPEID;
> +  ctf_dtdef_ref array_dtd, elem_dtd;
>   
>     int vector_type_p = get_AT_flag (array_type, DW_AT_GNU_vector);
>     if (vector_type_p)
> -    return array_elems_type_id;
> +    return NULL;
>   
>     /* Find the first and last array dimension DIEs.  */
>     last = dw_get_die_child (array_type);
> @@ -429,41 +426,36 @@ gen_ctf_array_type (ctf_container_ref ctfc,
>   
>     /* Type de-duplication.
>        Consult the ctfc_types before adding CTF type for the first dimension.  */
> -  if (!ctf_type_exists (ctfc, first, &array_type_id))
> +  if (!ctf_type_exists (ctfc, first, &array_dtd))
>       {
>         array_elems_type = ctf_get_AT_type (array_type);
>         /* First, register the type of the array elements if needed.  */
> -      array_elems_type_id = gen_ctf_type (ctfc, array_elems_type);
> +      elem_dtd = gen_ctf_type (ctfc, array_elems_type);
>   
> -      array_type_id = gen_ctf_subrange_type (ctfc, array_elems_type_id, first,
> -					     last);
> +      array_dtd = gen_ctf_subrange_type (ctfc, elem_dtd, first, last);
>       }
>   
> -  return array_type_id;
> +  return array_dtd;
>   }
>   
>   /* Generate CTF for a typedef.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_typedef (ctf_container_ref ctfc, dw_die_ref tdef)
>   {
> -  ctf_id_t tdef_type_id, tid;
> +  ctf_dtdef_ref tdef_dtd, dtd;
>     const char *tdef_name = get_AT_string (tdef, DW_AT_name);
>     dw_die_ref tdef_type = ctf_get_AT_type (tdef);
>   
> -  tid = gen_ctf_type (ctfc, tdef_type);
> +  dtd = gen_ctf_type (ctfc, tdef_type);
>   
>     /* Type de-duplication.
>        This is necessary because the ctf for the typedef may have been already
>        added due to the gen_ctf_type call above.  */
> -  if (!ctf_type_exists (ctfc, tdef, &tdef_type_id))
> -  {
> -    tdef_type_id = ctf_add_typedef (ctfc, CTF_ADD_ROOT,
> -				    tdef_name,
> -				    tid,
> -				    tdef);
> -  }
> -  return tdef_type_id;
> +  if (!ctf_type_exists (ctfc, tdef, &tdef_dtd))
> +    tdef_dtd = ctf_add_typedef (ctfc, CTF_ADD_ROOT, tdef_name, dtd, tdef);
> +
> +  return tdef_dtd;
>   }
>   
>   /* Generate CTF for a type modifier.
> @@ -475,11 +467,11 @@ gen_ctf_typedef (ctf_container_ref ctfc, dw_die_ref tdef)
>      For all other cases, this function returns a CTF_NULL_TYPEID;
>   */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_modifier_type (ctf_container_ref ctfc, dw_die_ref modifier)
>   {
>     uint32_t kind = CTF_K_MAX;
> -  ctf_id_t modifier_type_id, qual_type_id;
> +  ctf_dtdef_ref dtd, modifier_dtd;
>     dw_die_ref qual_type = ctf_get_AT_type (modifier);
>   
>     switch (dw_get_die_tag (modifier))
> @@ -493,33 +485,31 @@ gen_ctf_modifier_type (ctf_container_ref ctfc, dw_die_ref modifier)
>       }
>   
>     /* Register the type for which this modifier applies.  */
> -  qual_type_id = gen_ctf_type (ctfc, qual_type);
> +  dtd = gen_ctf_type (ctfc, qual_type);
>   
>     /* Skip generating a CTF modifier record for _Atomic as there is no
>        representation for it.  */
>     if (dw_get_die_tag (modifier) == DW_TAG_atomic_type)
> -    return qual_type_id;
> +    return dtd;
>   
>     gcc_assert (kind != CTF_K_MAX);
>     /* Now register the modifier itself.  */
> -  if (!ctf_type_exists (ctfc, modifier, &modifier_type_id))
> -    modifier_type_id = ctf_add_reftype (ctfc, CTF_ADD_ROOT,
> -					qual_type_id, kind,
> -					modifier);
> +  if (!ctf_type_exists (ctfc, modifier, &modifier_dtd))
> +    modifier_dtd = ctf_add_reftype (ctfc, CTF_ADD_ROOT, dtd, kind, modifier);
>   
> -  return modifier_type_id;
> +  return modifier_dtd;
>   }
>   
>   /* Generate CTF for a struct type.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
>   {
>     uint32_t bit_size = ctf_die_bitsize (sou);
>     int declaration_p = get_AT_flag (sou, DW_AT_declaration);
>     const char *sou_name = get_AT_string (sou, DW_AT_name);
>   
> -  ctf_id_t sou_type_id;
> +  ctf_dtdef_ref sou_dtd;
>   
>     /* An incomplete structure or union type is represented in DWARF by
>        a structure or union DIE that does not have a size attribute and
> @@ -531,10 +521,10 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
>   
>     /* This is a complete struct or union type.  Generate a CTF type for
>        it if it doesn't exist already.  */
> -  if (!ctf_type_exists (ctfc, sou, &sou_type_id))
> -    sou_type_id = ctf_add_sou (ctfc, CTF_ADD_ROOT,
> -			       sou_name, kind, bit_size / 8,
> -			       sou);
> +  if (!ctf_type_exists (ctfc, sou, &sou_dtd))
> +    sou_dtd = ctf_add_sou (ctfc, CTF_ADD_ROOT,
> +			   sou_name, kind, bit_size / 8,
> +			   sou);
>   
>     /* Now process the struct members.  */
>     {
> @@ -547,7 +537,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
>   	  const char *field_name;
>   	  dw_die_ref field_type;
>   	  HOST_WIDE_INT field_location;
> -	  ctf_id_t field_type_id;
> +	  ctf_dtdef_ref field_dtd;
>   
>   	  c = dw_get_die_sib (c);
>   
> @@ -556,7 +546,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
>   	  field_location = ctf_get_AT_data_member_location (c);
>   
>   	  /* Generate the field type.  */
> -	  field_type_id = gen_ctf_type (ctfc, field_type);
> +	  field_dtd = gen_ctf_type (ctfc, field_type);
>   
>   	  /* If this is a bit-field, then wrap the field type
>   	     generated above with a CTF slice.  */
> @@ -610,29 +600,29 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
>   		 surely something to look at for the next format version bump
>   		 for CTF.  */
>   	      if (bitsize <= 255 && (bitpos - field_location) <= 255)
> -		field_type_id = ctf_add_slice (ctfc, CTF_ADD_NONROOT,
> -					       field_type_id,
> +		field_dtd = ctf_add_slice (ctfc, CTF_ADD_NONROOT,
> +					       field_dtd,
>   					       bitpos - field_location,
>   					       bitsize, c);
>   	      else
> -		field_type_id = gen_ctf_unknown_type (ctfc);
> +		field_dtd = gen_ctf_unknown_type (ctfc);
>   	    }
>   
>   	  /* Add the field type to the struct or union type.  */
>   	  ctf_add_member_offset (ctfc, sou,
>   				 field_name,
> -				 field_type_id,
> +				 field_dtd,
>   				 field_location);
>   	}
>         while (c != dw_get_die_child (sou));
>     }
>   
> -  return sou_type_id;
> +  return sou_dtd;
>   }
>   
>   /* Generate CTF for a function type.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
>   		       bool from_global_func)
>   {
> @@ -643,17 +633,16 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
>     uint32_t num_args = 0;
>     int linkage = get_AT_flag (function, DW_AT_external);
>   
> -  ctf_id_t return_type_id;
> -  ctf_id_t function_type_id;
> +  ctf_dtdef_ref return_dtd, function_dtd;
>   
>     /* First, add the return type.  */
> -  return_type_id = gen_ctf_type (ctfc, return_type);
> -  func_info.ctc_return = return_type_id;
> +  return_dtd = gen_ctf_type (ctfc, return_type);
> +  func_info.ctc_return = return_dtd;
>   
>     /* Type de-duplication.
>        Consult the ctfc_types hash before adding the CTF function type.  */
> -  if (ctf_type_exists (ctfc, function, &function_type_id))
> -    return function_type_id;
> +  if (ctf_type_exists (ctfc, function, &function_dtd))
> +    return function_dtd;
>   
>     /* Do a first pass on the formals to determine the number of
>        arguments, and whether the function type gets a varargs.  */
> @@ -681,12 +670,12 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
>     func_info.ctc_argc = num_args;
>   
>     /* Type de-duplication has already been performed by now.  */
> -  function_type_id = ctf_add_function (ctfc, CTF_ADD_ROOT,
> -				       function_name,
> -				       (const ctf_funcinfo_t *)&func_info,
> -				       function,
> -				       from_global_func,
> -                                       linkage);
> +  function_dtd = ctf_add_function (ctfc, CTF_ADD_ROOT,
> +				   function_name,
> +				   (const ctf_funcinfo_t *)&func_info,
> +				   function,
> +				   from_global_func,
> +				   linkage);
>   
>     /* Second pass on formals: generate the CTF types corresponding to
>        them and add them as CTF function args.  */
> @@ -694,7 +683,7 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
>       dw_die_ref c;
>       unsigned int i = 0;
>       const char *arg_name;
> -    ctf_id_t arg_type;
> +    ctf_dtdef_ref arg_type;
>   
>       c = dw_get_die_child (function);
>       if (c)
> @@ -706,7 +695,7 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
>   	    {
>   	      gcc_assert (i == num_args - 1);
>   	      /* Add an argument with type 0 and no name.  */
> -	      ctf_add_function_arg (ctfc, function, "", 0);
> +	      ctf_add_function_arg (ctfc, function, "", NULL);
>   	    }
>   	  else if (dw_get_die_tag (c) == DW_TAG_formal_parameter)
>   	    {
> @@ -723,12 +712,12 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
>         while (c != dw_get_die_child (function));
>     }
>   
> -  return function_type_id;
> +  return function_dtd;
>   }
>   
>   /* Generate CTF for an enumeration type.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
>   {
>     const char *enum_name = get_AT_string (enumeration, DW_AT_name);
> @@ -736,7 +725,7 @@ gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
>     unsigned int signedness = get_AT_unsigned (enumeration, DW_AT_encoding);
>     int declaration_p = get_AT_flag (enumeration, DW_AT_declaration);
>   
> -  ctf_id_t enumeration_type_id;
> +  ctf_dtdef_ref enum_dtd;
>   
>     /* If this is an incomplete enum, generate a CTF forward for it and
>        be done.  */
> @@ -756,10 +745,10 @@ gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
>       }
>   
>     /* Generate a CTF type for the enumeration.  */
> -  enumeration_type_id = ctf_add_enum (ctfc, CTF_ADD_ROOT,
> -				      enum_name, bit_size / 8,
> -				      (signedness == DW_ATE_unsigned),
> -				      enumeration);
> +  enum_dtd = ctf_add_enum (ctfc, CTF_ADD_ROOT,
> +			   enum_name, bit_size / 8,
> +			   (signedness == DW_ATE_unsigned),
> +			   enumeration);
>   
>     /* Process the enumerators.  */
>     {
> @@ -787,13 +776,13 @@ gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
>   	  else
>   	    value_wide_int = AT_int (enumerator_value);
>   
> -	  ctf_add_enumerator (ctfc, enumeration_type_id,
> +	  ctf_add_enumerator (ctfc, enum_dtd,
>   			      enumerator_name, value_wide_int, enumeration);
>   	}
>         while (c != dw_get_die_child (enumeration));
>     }
>   
> -  return enumeration_type_id;
> +  return enum_dtd;
>   }
>   
>   /* Add a CTF variable record for the given input DWARF DIE.  */
> @@ -804,7 +793,7 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
>     const char *var_name = get_AT_string (die, DW_AT_name);
>     dw_die_ref var_type = ctf_get_AT_type (die);
>     unsigned int external_vis = get_AT_flag (die, DW_AT_external);
> -  ctf_id_t var_type_id;
> +  ctf_dtdef_ref var_dtd;
>   
>     /* Avoid duplicates.  */
>     if (ctf_dvd_lookup (ctfc, die))
> @@ -822,11 +811,10 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
>     dw_die_ref decl = get_AT_ref (die, DW_AT_specification);
>   
>     /* Add the type of the variable.  */
> -  var_type_id = gen_ctf_type (ctfc, var_type);
> +  var_dtd = gen_ctf_type (ctfc, var_type);
>   
>     /* Generate the new CTF variable and update global counter.  */
> -  (void) ctf_add_variable (ctfc, var_name, var_type_id, die, external_vis,
> -			   decl);
> +  (void) ctf_add_variable (ctfc, var_name, var_dtd, die, external_vis, decl);
>     /* Skip updating the number of global objects at this time.  This is updated
>        later after pre-processing as some CTF variable records although
>        generated now, will not be emitted later.  [PR105089].  */
> @@ -837,10 +825,10 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
>   static void
>   gen_ctf_function (ctf_container_ref ctfc, dw_die_ref die)
>   {
> -  ctf_id_t function_type_id;
> +  ctf_dtdef_ref function_dtd;
>     /* Type de-duplication.
>        Consult the ctfc_types hash before adding the CTF function type.  */
> -  if (ctf_type_exists (ctfc, die, &function_type_id))
> +  if (ctf_type_exists (ctfc, die, &function_dtd))
>       return;
>   
>     /* Add the type of the function and update the global functions
> @@ -859,41 +847,41 @@ gen_ctf_function (ctf_container_ref ctfc, dw_die_ref die)
>      If the given DIE is not recognized as a type, then this function
>      returns CTF_NULL_TYPEID.  */
>   
> -static ctf_id_t
> +static ctf_dtdef_ref
>   gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
>   {
> -  ctf_id_t type_id;
> +  ctf_dtdef_ref dtd = NULL;
>     int unrecog_die = false;
>   
> -  if (ctf_type_exists (ctfc, die, &type_id))
> -    return type_id;
> +  if (ctf_type_exists (ctfc, die, &dtd))
> +    return dtd;
>   
>     switch (dw_get_die_tag (die))
>       {
>       case DW_TAG_base_type:
> -      type_id = gen_ctf_base_type (ctfc, die);
> +      dtd = gen_ctf_base_type (ctfc, die);
>         break;
>       case DW_TAG_pointer_type:
> -      type_id = gen_ctf_pointer_type (ctfc, die);
> +      dtd = gen_ctf_pointer_type (ctfc, die);
>         break;
>       case DW_TAG_typedef:
> -      type_id = gen_ctf_typedef (ctfc, die);
> +      dtd = gen_ctf_typedef (ctfc, die);
>         break;
>       case DW_TAG_array_type:
> -      type_id = gen_ctf_array_type (ctfc, die);
> +      dtd = gen_ctf_array_type (ctfc, die);
>         break;
>       case DW_TAG_structure_type:
> -      type_id = gen_ctf_sou_type (ctfc, die, CTF_K_STRUCT);
> +      dtd = gen_ctf_sou_type (ctfc, die, CTF_K_STRUCT);
>         break;
>       case DW_TAG_union_type:
> -      type_id = gen_ctf_sou_type (ctfc, die, CTF_K_UNION);
> +      dtd = gen_ctf_sou_type (ctfc, die, CTF_K_UNION);
>         break;
>       case DW_TAG_subroutine_type:
> -      type_id = gen_ctf_function_type (ctfc, die,
> -				       false /* from_global_func */);
> +      dtd = gen_ctf_function_type (ctfc, die,
> +				   false /* from_global_func */);
>         break;
>       case DW_TAG_enumeration_type:
> -      type_id = gen_ctf_enumeration_type (ctfc, die);
> +      dtd = gen_ctf_enumeration_type (ctfc, die);
>         break;
>       case DW_TAG_atomic_type:
>         /* FALLTHROUGH */
> @@ -902,35 +890,35 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
>       case DW_TAG_restrict_type:
>         /* FALLTHROUGH */
>       case DW_TAG_volatile_type:
> -      type_id = gen_ctf_modifier_type (ctfc, die);
> +      dtd = gen_ctf_modifier_type (ctfc, die);
>         break;
>       case DW_TAG_unspecified_type:
>         {
>   	const char *name = get_AT_string (die, DW_AT_name);
>   
>   	if (name && strcmp (name, "void") == 0)
> -	  type_id = gen_ctf_void_type (ctfc);
> +	  dtd = gen_ctf_void_type (ctfc);
>   	else
> -	  type_id = CTF_NULL_TYPEID;
> +	  dtd = NULL;
>   
>   	break;
>         }
>       case DW_TAG_reference_type:
> -      type_id = CTF_NULL_TYPEID;
> +      dtd = NULL;
>         break;
>       default:
>         /* Unrecognized DIE.  */
>         unrecog_die = true;
> -      type_id = CTF_NULL_TYPEID;
> +      dtd = NULL;
>         break;
>       }
>   
>     /* For all types unrepresented in CTF, use an explicit CTF type of kind
>        CTF_K_UNKNOWN.  */
> -  if ((type_id == CTF_NULL_TYPEID) && (!unrecog_die))
> -    type_id = gen_ctf_unknown_type (ctfc);
> +  if ((dtd == NULL) && (!unrecog_die))
> +    dtd = gen_ctf_unknown_type (ctfc);
>   
> -  return type_id;
> +  return dtd;
>   }
>   
>   bool
> @@ -951,7 +939,7 @@ ctf_do_die (dw_die_ref die)
>         return false;
>       }
>     else
> -    return gen_ctf_type (tu_ctfc, die) == CTF_NULL_TYPEID;
> +    return (gen_ctf_type (tu_ctfc, die) == NULL);
>   }
>   
>   /* Initialize CTF subsystem for CTF debug info generation.  */


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 4/6] btf: refactor and simplify implementation
  2024-05-02 17:11 ` [PATCH v2 4/6] btf: refactor and simplify implementation David Faust
@ 2024-05-03 21:06   ` Indu Bhagat
  0 siblings, 0 replies; 13+ messages in thread
From: Indu Bhagat @ 2024-05-03 21:06 UTC (permalink / raw)
  To: David Faust, gcc-patches; +Cc: jose.marchesi, cupertino.miranda

On 5/2/24 10:11, David Faust wrote:
> This patch heavily refactors btfout.cc to take advantage of the
> structural changes in the prior commits.
> 
> Now that inter-type references are internally stored as simply pointers,
> all the painful, brittle, confusing infrastructure that was used in the
> process of converting CTF type IDs to BTF type IDs can be thrown out.
> This greatly simplifies the entire process of converting from CTF to
> BTF, making the code cleaner, easier to read, and easier to maintain.
> 
> In addition, we no longer need to worry about destructive changes in
> internal data structures used commonly by CTF and BTF, which allows
> deleting several ancillary data structures previously used in btfout.cc.
> 
> This is nearly transparent, but a few improvements have also been made:
> 
>   1) BTF_KIND_FUNC records are now _always_ constructed at early_finish,
>      allowing us to construct records even for functions which are later
>      inlined by optimizations. DATASEC entries for functions are only
>      constructed at late_finish, to avoid incorrectly generating entries
>      for functions which get inlined.
> 
>   2) BTF_KIND_VAR records and DATASEC entries for them are now always
>      constructed at (late) finish, which avoids cases where we could
>      incorrectly create records for variables which were completely
>      optimized away. This fixes PR debug/113566.
> 

I am a bit unsure ATM, how this commit will look like once we revisit 
where the BTF is generated for BPF and non-BPF backends.  Since patch 
1/6 moved everything to (late)finish, but that will be problematic, I 
would like to defer reviewing this until the approach for 
afore-mentioned patch is pinned.

>   3) Some additional assembler comments have been added with more
>      information for debugging.
> 
> gcc/
> 	* btfout.cc (struct btf_datasec_entry): New.
> 	(struct btf_datasec): Add `id' member.  Change `entries' to use
> 	new struct btf_datasec_entry.
> 	(func_map): New hash_map.
> 	(max_translated_id): New.
> 	(btf_var_ids, btf_id_map, holes, voids, num_vars_added)
> 	(num_types_added, num_types_created): Delete.
> 	(btf_absolute_var_id, btf_relative_var_id, btf_absolute_func_id)
> 	(btf_relative_func_id, btf_absolute_datasec_id, init_btf_id_map)
> 	(get_btf_id, set_btf_id, btf_emit_id_p): Delete.
> 	(btf_removed_type_p): Delete.
> 	(btf_dtd_kind, btf_emit_type_p): New helpers.
> 	(btf_fwd_to_enum_p, btf_calc_num_vbytes): Use them.
> 	(btf_collect_datasec): Delete.
> 	(btf_dtd_postprocess_cb, btf_dvd_emit_preprocess_cb)
> 	(btf_dtd_emit_preprocess_cb, btf_emit_preprocess): Delete.
> 	(btf_dmd_representable_bitfield_p): Adapt to type reference changes
> 	and delete now-unused ctfc argument.
> 	(btf_asm_datasec_type_ref): Delete.
> 	(btf_asm_type_ref): Adapt to type reference changes, simplify.
> 	(btf_asm_type): Likewise. Mark struct/union types with bitfield
> 	members.
> 	(btf_asm_array): Adapt to data structure changes.
> 	(btf_asm_varent): Likewise.
> 	(btf_asm_sou_member): Likewise. Ensure non-bitfield members are
> 	correctly re-encoded if struct or union contains any bitfield.
> 	(btf_asm_func_arg, btf_asm_func_type, btf_asm_datasec_entry)
> 	(btf_asm_datasec_type): Adapt to data structure changes.
> 	(output_btf_header): Adapt to other changes, simplify type
> 	length calculation, add info to assembler comments.
> 	(output_btf_vars): Adapt to other changes.
> 	(output_btf_strs): Fix overlong lines.
> 	(output_asm_btf_sou_fields, output_asm_btf_enum_list)
> 	(output_asm_btf_func_args_list, output_asm_btf_vlen_bytes)
> 	(output_asm_btf_type, output_btf_types, output_btf_func_types)
> 	(output_btf_datasec_types): Adapt to other changes.
> 	(btf_init_postprocess): Delete.
> 	(btf_output): Change to only perform output.
> 	(btf_early_add_const_void, btf_early_add_func_records): New.
> 	(btf_early_finish): Use them here. New.
> 	(btf_datasec_push_entry): Adapt to data structure changes.
> 	(btf_datasec_add_func, btf_datasec_add_var): New.
> 	(btf_late_add_func_datasec_entries): New.
> 	(btf_emit_variable_p): New helper.
> 	(btf_late_add_vars): Use it here. New.
> 	(btf_type_list_cb, btf_late_collect_translated_types): New.
> 	(btf_late_assign_func_ids, btf_late_assign_var_ids)
> 	(btf_late_assign_datasec_ids): New.
> 	(btf_finish): Remove unused argument. Call new btf_late*
> 	functions and btf_output.
> 	(btf_finalize): Adapt to data structure changes.
> 	* ctfc.h (struct ctf_dtdef): Convert existing boolean flags to
> 	BOOL_BITFIELD and reorder.
> 	(struct ctf_dvdef): Add dvd_id member.
> 	(btf_finish): Remove argument from prototype.
> 	(get_btf_id): Delete prototype.
> 	(funcs_traverse_callback, traverse_btf_func_types): Add an
> 	explanatory comment.
> 	* dwarf2ctf.cc (ctf_debug_finish): Remove unused argument.
> 	* dwarf2ctf.h: Analogous change.
> 	* dwarf2out.cc: Likewise.
> ---
>   gcc/btfout.cc    | 1256 +++++++++++++++++++---------------------------
>   gcc/ctfc.h       |   17 +-
>   gcc/dwarf2ctf.cc |    4 +-
>   gcc/dwarf2ctf.h  |    2 +-
>   gcc/dwarf2out.cc |    2 +-
>   5 files changed, 539 insertions(+), 742 deletions(-)
> 
> diff --git a/gcc/btfout.cc b/gcc/btfout.cc
> index 14a503a4f80..0af0bd39fc7 100644
> --- a/gcc/btfout.cc
> +++ b/gcc/btfout.cc
> @@ -68,53 +68,44 @@ static char btf_info_section_label[MAX_BTF_LABEL_BYTES];
>   
>   #define BTF_INVALID_TYPEID 0xFFFFFFFF
>   
> -/* Mapping of CTF variables to the IDs they will be assigned when they are
> -   converted to BTF_KIND_VAR type records. Strictly accounts for the index
> -   from the start of the variable type entries, does not include the number
> -   of types emitted prior to the variable records.  */
> -static GTY (()) hash_map <ctf_dvdef_ref, unsigned> *btf_var_ids;
> -
> -/* Mapping of type IDs from original CTF ID to BTF ID. Types do not map
> -   1-to-1 from CTF to BTF. To avoid polluting the CTF container when updating
> -   type references-by-ID, we use this map instead.  */
> -static ctf_id_t * btf_id_map = NULL;
> -
> -/* Information for creating the BTF_KIND_DATASEC records.  */
> +/* Internal representation of an entry in a BTF_KIND_DATASEC record.  */
> +struct btf_datasec_entry
> +{
> +  union {
> +    ctf_dvdef_ref dvd; /* Reference to the underlying variable represented.  */
> +    ctf_dtdef_ref dtd; /* Reference to the underlying type represented.  */
> +  };
> +  bool is_var;	       /* True iff this entry represents a variable.  */
> +  uint32_t size;       /* Size of variable or function, in bytes.
> +			  For functions, always zero at compile time.  */
> +};
> +
> +/* Internal representation of a BTF_KIND_DATASEC record.  */
>   typedef struct btf_datasec
>   {
> -  const char *name;                    /* Section name, e.g. ".bss".  */
> -  uint32_t name_offset;                /* Offset to name in string table.  */
> -  vec<struct btf_var_secinfo> entries; /* Variable entries in this section.  */
> +  ctf_id_t id;                           /* BTF type ID of this record.  */
> +  const char *name;                      /* Section name, e.g. ".bss".  */
> +  uint32_t name_offset;                  /* Offset to name in string table.  */
> +  vec<struct btf_datasec_entry> entries; /* Entries in this section.  */
>   } btf_datasec_t;
>   
>   /* One BTF_KIND_DATASEC record is created for each output data section which
>      will hold at least one variable.  */
>   static vec<btf_datasec_t> datasecs;
>   
> -/* Holes occur for types which are present in the CTF container, but are either
> -   non-representable or redundant in BTF.  */
> -static vec<ctf_id_t> holes;
> -
> -/* CTF definition(s) of void. Only one definition of void should be generated.
> -   We should not encounter more than one definition of void, but use a vector
> -   to be safe.  */
> -static vec<ctf_id_t> voids;
> -
>   /* Functions in BTF have two separate type records - one for the prototype
>      (BTF_KIND_FUNC_PROTO), as well as a BTF_KIND_FUNC. CTF_K_FUNCTION types
>      map closely to BTF_KIND_FUNC_PROTO, but the BTF_KIND_FUNC records must be
>      created. This vector holds them.  */
>   static GTY (()) vec<ctf_dtdef_ref, va_gc> *funcs;
>   
> -/* The number of BTF variables added to the TU CTF container.  */
> -static unsigned int num_vars_added = 0;
> -
> -/* The number of BTF types added to the TU CTF container.  */
> -static unsigned int num_types_added = 0;
> +/* Maps BTF_KIND_FUNC_PROTO to the BTF_KIND_FUNC record for it.  Used when
> +   creating DATASEC entries.  */
> +static GTY (()) hash_map<ctf_dtdef_ref, ctf_dtdef_ref> *func_map;
>   
> -/* The number of types synthesized for BTF that do not correspond to
> -   CTF types.  */
> -static unsigned int num_types_created = 0;
> +/* Highest BTF ID assigned to any regular type translated from CTF.
> +   Does not include BTF_KIND_{VAR,FUNC,DATASEC} types.  */
> +static ctf_id_t max_translated_id = 0;
>   
>   /* Name strings for BTF kinds.
>      Note: the indices here must match the type defines in btf.h.  */
> @@ -160,6 +151,16 @@ get_btf_kind (uint32_t ctf_kind)
>     return BTF_KIND_UNKN;
>   }
>   
> +/* Convenience wrapper around get_btf_kind for the common case.  */
> +
> +static uint32_t
> +btf_dtd_kind (ctf_dtdef_ref dtd)
> +{
> +  if (!dtd)
> +    return BTF_KIND_UNKN;
> +  return get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
> +}
> +
>   /* Some BTF types, like BTF_KIND_FUNC_PROTO, are anonymous.  The machinery
>      in btfout to emit BTF, may reset dtd_data->ctti_name, but does not update
>      the name in the ctf_dtdef_ref type object (deliberate choice).  This
> @@ -173,101 +174,20 @@ get_btf_type_name (ctf_dtdef_ref dtd)
>     return (dtd->dtd_data.ctti_name) ? dtd->dtd_name : anon;
>   }
>   
> -/* Helper routines to map between 'relative' and 'absolute' IDs.
> -
> -   In BTF all records (including variables) are output in one long list, and all
> -   inter-type references are via index into that list.  But internally since we
> -   a) translate from CTF, which separates variable records from regular types
> -   and b) create some additional types after the fact, things like VAR and FUNC
> -   records are stored in separate vectors with their own indices.  These
> -   functions map between the 'relative' IDs (i.e.  indices in their respective
> -   containers) and 'absolute' IDs (i.e.  indices in the final contiguous
> -   output list), which goes in order:
> -     all normal type records translated from CTF
> -     all BTF_KIND_VAR records
> -     all BTF_KIND_FUNC records (synthesized split function records)
> -     all BTF_KIND_DATASEC records (synthesized)
> -
> -   The extra '+ 1's below are to account for the implicit "void" record, which
> -   has index 0 but isn't actually contained in the type list.  */
> -
> -/* Return the final BTF ID of the variable at relative index REL.  */
> -
> -static ctf_id_t
> -btf_absolute_var_id (ctf_id_t rel)
> -{
> -  return rel + (num_types_added + 1);
> -}
> -
> -/* Return the relative index of the variable with final BTF ID ABS.  */
> -
> -static ctf_id_t
> -btf_relative_var_id (ctf_id_t abs)
> -{
> -  return abs - (num_types_added + 1);
> -}
> -
> -/* Return the final BTF ID of the func record at relative index REL.  */
> -
> -static ctf_id_t
> -btf_absolute_func_id (ctf_id_t rel)
> -{
> -  return rel + (num_types_added + 1) + num_vars_added;
> -}
> -
> -/* Return the relative index of the func record with final BTF ID ABS.  */
> -
> -static ctf_id_t
> -btf_relative_func_id (ctf_id_t abs)
> -{
> -  return abs - ((num_types_added + 1) + num_vars_added);
> -}
> -
> -/* Return the final BTF ID of the datasec record at relative index REL.  */
> -
> -static ctf_id_t
> -btf_absolute_datasec_id (ctf_id_t rel)
> +static bool
> +btf_emit_type_p (ctf_dtdef_ref dtd)
>   {
> -  return rel + (num_types_added + 1) + num_vars_added + funcs->length ();
> -}
> -
> +  uint32_t kind = btf_dtd_kind (dtd);
>   
> -/* Allocate the btf_id_map, and initialize elements to BTF_INVALID_TYPEID.  */
> +  if (kind == BTF_KIND_UNKN)
> +    /* This type is not representable in BTF.  */
> +    return false;
>   
> -static void
> -init_btf_id_map (size_t len)
> -{
> -  btf_id_map = XNEWVEC (ctf_id_t, len);
> +  if (kind == BTF_KIND_INT && dtd->dtd_data.ctti_size == 0)
> +    /* This is a (redundant) definition of void.  */
> +    return false;
>   
> -  btf_id_map[0] = BTF_VOID_TYPEID;
> -  for (size_t i = 1; i < len; i++)
> -    btf_id_map[i] = BTF_INVALID_TYPEID;
> -}
> -
> -/* Return the BTF type ID of CTF type ID KEY, or BTF_INVALID_TYPEID if the CTF
> -   type with ID KEY does not map to a BTF type.  */
> -
> -ctf_id_t
> -get_btf_id (ctf_id_t key)
> -{
> -  return btf_id_map[key];
> -}
> -
> -/* Set the CTF type ID KEY to map to BTF type ID VAL.  */
> -
> -static inline void
> -set_btf_id (ctf_id_t key, ctf_id_t val)
> -{
> -  btf_id_map[key] = val;
> -}
> -
> -/* Return TRUE iff the given CTF type ID maps to a BTF type which will
> -   be emitted.  */
> -static inline bool
> -btf_emit_id_p (ctf_id_t id)
> -{
> -  return ((btf_id_map[id] != BTF_VOID_TYPEID)
> -	  && (btf_id_map[id] <= BTF_MAX_TYPE));
> +  return true;
>   }
>   
>   /* Return true if DTD is a forward-declared enum.  The BTF representation
> @@ -276,9 +196,8 @@ btf_emit_id_p (ctf_id_t id)
>   static bool
>   btf_fwd_to_enum_p (ctf_dtdef_ref dtd)
>   {
> -  uint32_t btf_kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
> -
> -  return (btf_kind == BTF_KIND_FWD && dtd->dtd_data.ctti_type == CTF_K_ENUM);
> +  uint32_t kind = btf_dtd_kind (dtd);
> +  return (kind == BTF_KIND_FWD && dtd->dtd_data.ctti_type == CTF_K_ENUM);
>   }
>   
>   /* Each BTF type can be followed additional, variable-length information
> @@ -290,7 +209,7 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
>   {
>     uint64_t vlen_bytes = 0;
>   
> -  uint32_t kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
> +  uint32_t kind = btf_dtd_kind (dtd);
>     uint32_t vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
>   
>     switch (kind)
> @@ -360,41 +279,6 @@ init_btf_sections (void)
>   			       BTF_INFO_SECTION_LABEL, btf_label_num++);
>   }
>   
> -/* Push a BTF datasec variable entry INFO into the datasec named SECNAME,
> -   creating the datasec if it does not already exist.  */
> -
> -static void
> -btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
> -			struct btf_var_secinfo info)
> -{
> -  if (secname == NULL)
> -    return;
> -
> -  for (size_t i = 0; i < datasecs.length (); i++)
> -    if (strcmp (datasecs[i].name, secname) == 0)
> -      {
> -	datasecs[i].entries.safe_push (info);
> -	return;
> -      }
> -
> -  /* If we don't already have a datasec record for secname, make one.  */
> -
> -  uint32_t str_off;
> -  ctf_add_string (ctfc, secname, &str_off, CTF_AUX_STRTAB);
> -  if (strcmp (secname, ""))
> -    ctfc->ctfc_aux_strlen += strlen (secname) + 1;
> -
> -  btf_datasec_t ds;
> -  ds.name = secname;
> -  ds.name_offset = str_off;
> -
> -  ds.entries.create (0);
> -  ds.entries.safe_push (info);
> -
> -  datasecs.safe_push (ds);
> -}
> -
> -
>   /* Return the section name, as of interest to btf_collect_datasec, for the
>      given symtab node.  Note that this deliberately returns NULL for objects
>      which do not go in a section btf_collect_datasec cares about.  */
> @@ -423,301 +307,15 @@ get_section_name (symtab_node *node)
>     return section_name;
>   }
>   
> -/* Construct all BTF_KIND_DATASEC records for CTFC. One such record is created
> -   for each non-empty data-containing section in the output. Each record is
> -   followed by a variable number of entries describing the variables stored
> -   in that section.  */
> -
> -static void
> -btf_collect_datasec (ctf_container_ref ctfc)
> -{
> -  cgraph_node *func;
> -  FOR_EACH_FUNCTION (func)
> -    {
> -      dw_die_ref die = lookup_decl_die (func->decl);
> -      if (die == NULL)
> -	continue;
> -
> -      ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
> -      if (dtd == NULL)
> -	continue;
> -
> -      if (DECL_EXTERNAL (func->decl)
> -	  && (lookup_attribute ("kernel_helper",
> -				DECL_ATTRIBUTES (func->decl))) != NULL_TREE)
> -	continue;
> -
> -      /* Functions actually get two types: a BTF_KIND_FUNC_PROTO, and
> -	 also a BTF_KIND_FUNC.  But the CTF container only allocates one
> -	 type per function, which matches closely with BTF_KIND_FUNC_PROTO.
> -	 For each such function, also allocate a BTF_KIND_FUNC entry.
> -	 These will be output later.  */
> -      ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
> -      func_dtd->dtd_data = dtd->dtd_data;
> -      func_dtd->dtd_data.ctti_type = dtd->dtd_type;
> -      func_dtd->linkage = dtd->linkage;
> -      func_dtd->dtd_name = dtd->dtd_name;
> -      /* +1 for the sentinel type not in the types map.  */
> -      func_dtd->dtd_type = num_types_added + num_types_created + 1;
> -
> -      /* Only the BTF_KIND_FUNC type actually references the name. The
> -	 BTF_KIND_FUNC_PROTO is always anonymous.  */
> -      dtd->dtd_data.ctti_name = 0;
> -
> -      vec_safe_push (funcs, func_dtd);
> -      num_types_created++;
> -
> -      /* Mark any 'extern' funcs and add DATASEC entries for them.  */
> -      if (DECL_EXTERNAL (func->decl))
> -	{
> -	  func_dtd->linkage = BTF_FUNC_EXTERN;
> -
> -	  const char *section_name = get_section_name (func);
> -	  /* Note: get_section_name () returns NULL for functions in text
> -	     section.  This is intentional, since we do not want to generate
> -	     DATASEC entries for them.  */
> -	  if (section_name == NULL)
> -	    continue;
> -
> -	  struct btf_var_secinfo info;
> -
> -	  info.type = func_dtd->dtd_type;
> -
> -	  /* Both zero at compile time.  */
> -	  info.size = 0;
> -	  info.offset = 0;
> -
> -	  btf_datasec_push_entry (ctfc, section_name, info);
> -	}
> -    }
> -
> -  varpool_node *node;
> -  FOR_EACH_VARIABLE (node)
> -    {
> -      dw_die_ref die = lookup_decl_die (node->decl);
> -      if (die == NULL)
> -	continue;
> -
> -      ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
> -      if (dvd == NULL)
> -	continue;
> -
> -      /* Mark extern variables.  */
> -      if (DECL_EXTERNAL (node->decl))
> -	{
> -	  dvd->dvd_visibility = BTF_VAR_GLOBAL_EXTERN;
> -
> -	  /* PR112849: avoid assuming a section for extern decls without
> -	     an explicit section, which would result in incorrectly
> -	     emitting a BTF_KIND_DATASEC entry for them.  */
> -	  if (node->get_section () == NULL)
> -	    continue;
> -	}
> -
> -      const char *section_name = get_section_name (node);
> -      if (section_name == NULL)
> -	continue;
> -
> -      struct btf_var_secinfo info;
> -
> -      info.type = 0;
> -      unsigned int *var_id = btf_var_ids->get (dvd);
> -      if (var_id)
> -	info.type = btf_absolute_var_id (*var_id);
> -      else
> -	continue;
> -
> -      info.size = 0;
> -      tree size = DECL_SIZE_UNIT (node->decl);
> -      if (tree_fits_uhwi_p (size))
> -	info.size = tree_to_uhwi (size);
> -      else if (VOID_TYPE_P (TREE_TYPE (node->decl)))
> -	info.size = 1;
> -
> -      /* Offset is left as 0 at compile time, to be filled in by loaders such
> -	 as libbpf.  */
> -      info.offset = 0;
> -
> -      btf_datasec_push_entry (ctfc, section_name, info);
> -    }
> -
> -  num_types_created += datasecs.length ();
> -}
> -
> -/* Return true if the type ID is that of a type which will not be emitted (for
> -   example, if it is not representable in BTF).  */
> -
> -static bool
> -btf_removed_type_p (ctf_id_t id)
> -{
> -  return holes.contains (id);
> -}
> -
> -/* Adjust the given type ID to account for holes and duplicate definitions of
> -   void.  */
> -
> -static ctf_id_t
> -btf_adjust_type_id (ctf_id_t id)
> -{
> -  size_t n;
> -  ctf_id_t i = 0;
> -
> -  /* Do not adjust invalid type markers.  */
> -  if (id == BTF_INVALID_TYPEID)
> -    return id;
> -
> -  for (n = 0; n < voids.length (); n++)
> -    if (id == voids[n])
> -      return BTF_VOID_TYPEID;
> -
> -  for (n = 0; n < holes.length (); n++)
> -    {
> -      if (holes[n] < id)
> -	i++;
> -      else if (holes[n] == id)
> -	return BTF_VOID_TYPEID;
> -    }
> -
> -  return id - i;
> -}
> -
> -/* Postprocessing callback routine for types.  */
> -
> -int
> -btf_dtd_postprocess_cb (ctf_dtdef_ref *slot, ctf_container_ref arg_ctfc)
> -{
> -  ctf_dtdef_ref ctftype = (ctf_dtdef_ref) * slot;
> -
> -  size_t index = ctftype->dtd_type;
> -  gcc_assert (index <= arg_ctfc->ctfc_types->elements ());
> -
> -  uint32_t ctf_kind, btf_kind;
> -
> -  ctf_kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
> -  btf_kind = get_btf_kind (ctf_kind);
> -
> -  if (btf_kind == BTF_KIND_UNKN)
> -    /* This type is not representable in BTF. Create a hole.  */
> -    holes.safe_push (ctftype->dtd_type);
> -
> -  else if (btf_kind == BTF_KIND_INT && ctftype->dtd_data.ctti_size == 0)
> -    {
> -      /* This is a (redundant) definition of void.  */
> -      voids.safe_push (ctftype->dtd_type);
> -      holes.safe_push (ctftype->dtd_type);
> -    }
> -
> -  arg_ctfc->ctfc_types_list[index] = ctftype;
> -
> -  return 1;
> -}
> -
> -/* Preprocessing callback routine for variables.  */
> -
> -int
> -btf_dvd_emit_preprocess_cb (ctf_dvdef_ref *slot, ctf_container_ref arg_ctfc)
> -{
> -  ctf_dvdef_ref var = (ctf_dvdef_ref) * slot;
> -
> -  /* If this is an extern variable declaration with a defining declaration
> -     later, skip it so that only the defining declaration is emitted.
> -     This is the same case, fix and reasoning as in CTF; see PR105089.  */
> -  if (ctf_dvd_ignore_lookup (arg_ctfc, var->dvd_key))
> -    return 1;
> -
> -  /* Do not add variables which refer to unsupported types.  */
> -  if (!voids.contains (var->dvd_type->dtd_type)
> -      && btf_removed_type_p (var->dvd_type->dtd_type))
> -    return 1;
> -
> -  arg_ctfc->ctfc_vars_list[num_vars_added] = var;
> -  btf_var_ids->put (var, num_vars_added);
> -
> -  num_vars_added++;
> -  num_types_created++;
> -
> -  return 1;
> -}
> -
> -/* Preprocessing callback routine for types.  */
> -
> -static void
> -btf_dtd_emit_preprocess_cb (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
> -{
> -  if (!btf_emit_id_p (dtd->dtd_type))
> -    return;
> -
> -  ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
> -}
> -
> -/* Preprocess the CTF information to prepare for BTF output.  BTF is almost a
> -   subset of CTF, with many small differences in encoding, and lacking support
> -   for some types (notably floating point formats).
> -
> -   During the preprocessing pass:
> -   - Ascertain that the sorted list of types has been prepared.  For the BTF
> -     generation process, this is taken care of by the btf_init_postprocess ().
> -
> -   - BTF_KIND_FUNC and BTF_KIND_DATASEC records are constructed. These types do
> -     not have analogues in CTF (the analogous type to CTF_K_FUNCTION is
> -     BTF_KIND_FUNC_PROTO), but can be relatively easily deduced from CTF
> -     information.
> -
> -   - Construct BTF_KIND_VAR records, representing variables.
> -
> -   - Calculate the total size in bytes of variable-length information following
> -     BTF type records. This is used for outputting the BTF header.
> -
> -   After preprocessing, all BTF information is ready to be output:
> -   - ctfc->ctfc_types_list holdstypes converted from CTF types. This does not
> -     include KIND_VAR, KIND_FUNC, nor KIND_DATASEC types. These types have been
> -     re-encoded to the appropriate representation in BTF.
> -   - ctfc->ctfc_vars_list holds all variables which should be output.
> -     Variables of unsupported types are not present in this list.
> -   - Vector 'funcs' holds all BTF_KIND_FUNC types, one to match each
> -     BTF_KIND_FUNC_PROTO.
> -   - Vector 'datasecs' holds all BTF_KIND_DATASEC types.  */
> -
> -static void
> -btf_emit_preprocess (ctf_container_ref ctfc)
> -{
> -  size_t num_ctf_types = ctfc->ctfc_types->elements ();
> -  size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
> -  size_t i;
> -
> -  if (num_ctf_types)
> -    {
> -      gcc_assert (ctfc->ctfc_types_list);
> -      /* Preprocess the types.  */
> -      for (i = 1; i <= num_ctf_types; i++)
> -	btf_dtd_emit_preprocess_cb (ctfc, ctfc->ctfc_types_list[i]);
> -    }
> -
> -  btf_var_ids = hash_map<ctf_dvdef_ref, unsigned int>::create_ggc (100);
> -
> -  if (num_ctf_vars)
> -    {
> -      /* Allocate and construct the list of variables. While BTF variables are
> -	 not distinct from types (in that variables are simply types with
> -	 BTF_KIND_VAR), it is simpler to maintain a separate list of variables
> -	 and append them to the types list during output.  */
> -      ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars);
> -      ctfc->ctfc_vars->traverse<ctf_container_ref, btf_dvd_emit_preprocess_cb>
> -	(ctfc);
> -
> -      ctfc->ctfc_num_vlen_bytes += (num_vars_added * sizeof (struct btf_var));
> -    }
> -
> -  btf_collect_datasec (ctfc);
> -}
> -
>   /* Return true iff DMD is a member description of a bit-field which can be
>      validly represented in BTF.  */
>   
>   static bool
> -btf_dmd_representable_bitfield_p (ctf_container_ref ctfc, ctf_dmdef_t *dmd)
> +btf_dmd_representable_bitfield_p (ctf_dmdef_t *dmd)
>   {
> -  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
> +  ctf_dtdef_ref ref_type = dmd->dmd_type;
> +  if (!ref_type)
> +    return false;
>   
>     if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
>       {
> @@ -739,76 +337,34 @@ btf_dmd_representable_bitfield_p (ctf_container_ref ctfc, ctf_dmdef_t *dmd)
>   /* Asm'out a reference to another BTF type.  */
>   
>   static void
> -btf_asm_type_ref (const char *prefix, ctf_container_ref ctfc, ctf_id_t ctf_id)
> +btf_asm_type_ref (const char *prefix, ctf_dtdef_ref dtd)
>   {
> -  ctf_id_t btf_id = get_btf_id (ctf_id);
> -  if (btf_id == BTF_VOID_TYPEID || btf_id == BTF_INVALID_TYPEID)
> -    {
> -      /* There is no explicit void type.
> -	 Also handle any invalid refs that made it this far, just in case.  */
> -      dw2_asm_output_data (4, btf_id, "%s: void", prefix);
> -    }
> +  if (!dtd || !btf_emit_type_p (dtd))
> +    dw2_asm_output_data (4, BTF_VOID_TYPEID, "%s: void", prefix);
>     else
>       {
> -      gcc_assert (btf_id <= num_types_added);
> -
> -      /* Ref to a standard type in the types list.  Note: take care that we
> -	 must index the type list by the original CTF id, not the BTF id.  */
> -      ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[ctf_id];
> -      uint32_t ref_kind
> -	= get_btf_kind (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info));
> -
> -      const char *kind_name = btf_fwd_to_enum_p (ref_type)
> -	? btf_kind_name (BTF_KIND_ENUM)
> -	: btf_kind_name (ref_kind);
> -
> -      dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_%s '%s')",
> -			   prefix, kind_name,
> -			   get_btf_type_name (ref_type));
> +      uint32_t kind = btf_dtd_kind (dtd);
> +      if (btf_fwd_to_enum_p (dtd))
> +	kind = BTF_KIND_ENUM;
> +      else if (kind == BTF_KIND_FUNC_PROTO && dtd->dtd_type > max_translated_id)
> +	kind = BTF_KIND_FUNC;
> +
> +      dw2_asm_output_data (4, dtd->dtd_type, "%s: (BTF_KIND_%s '%s')",
> +			   prefix, btf_kind_name (kind),
> +			   get_btf_type_name (dtd));
>       }
>   }
>   
> -/* Asm'out a reference to a BTF_KIND_VAR or BTF_KIND_FUNC type.  These type
> -   kinds are BTF-specific, and should only be referred to by entries in
> -   BTF_KIND_DATASEC records.  */
> -
> -static void
> -btf_asm_datasec_type_ref (const char *prefix, ctf_container_ref ctfc,
> -			  ctf_id_t btf_id)
> -{
> -  if (btf_id >= num_types_added + 1
> -      && btf_id < num_types_added + num_vars_added + 1)
> -    {
> -      /* Ref to a variable.  Should only appear in DATASEC entries.  */
> -      ctf_id_t var_id = btf_relative_var_id (btf_id);
> -      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[var_id];
> -      dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_VAR '%s')",
> -			   prefix, dvd->dvd_name);
> -
> -    }
> -  else if (btf_id >= num_types_added + num_vars_added + 1)
> -    {
> -      /* Ref to a FUNC record.  */
> -      size_t func_id = btf_relative_func_id (btf_id);
> -      ctf_dtdef_ref ref_type = (*funcs)[func_id];
> -      dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_FUNC '%s')",
> -			   prefix, get_btf_type_name (ref_type));
> -    }
> -  else
> -    /* The caller should not be calling this.  */
> -    gcc_unreachable ();
> -}
> -
>   /* Asm'out a BTF type. This routine is responsible for the bulk of the task
>      of converting CTF types to their BTF representation.  */
>   
>   static void
> -btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
> +btf_asm_type (ctf_dtdef_ref dtd)
>   {
>     uint32_t btf_kind, btf_kflag, btf_vlen, btf_size;
>     uint32_t ctf_info = dtd->dtd_data.ctti_info;
>   
> -  btf_kind = get_btf_kind (CTF_V2_INFO_KIND (ctf_info));
> +  btf_kind = btf_dtd_kind (dtd);
>     btf_size = dtd->dtd_data.ctti_size;
>     btf_vlen = CTF_V2_INFO_VLEN (ctf_info);
>   
> @@ -827,17 +383,17 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>   
>     if (btf_kind == BTF_KIND_STRUCT || btf_kind == BTF_KIND_UNION)
>       {
> -      /* If a struct/union has ANY bitfield members, set kflag=1.
> -	 Note that we must also change the encoding of every member to encode
> -	 both member bitfield size (stealing most-significant 8 bits) and bit
> -	 offset (LS 24 bits). This is done during preprocessing.  */
> +      /* If a struct/union has ANY bitfield members, set kflag=1.  */
>         ctf_dmdef_t *dmd;
>         for (dmd = dtd->dtd_u.dtu_members;
>   	   dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
>   	{
>   	  /* Set kflag if this member is a representable bitfield.  */
> -	  if (btf_dmd_representable_bitfield_p (ctfc, dmd))
> -	    btf_kflag = 1;
> +	  if (btf_dmd_representable_bitfield_p (dmd))
> +	    {
> +	      btf_kflag = 1;
> +	      break;
> +	    }
>   	}
>       }
>   
> @@ -871,7 +427,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>   		    : BTF_KF_ENUM_SIGNED;
>         if (dtd->dtd_data.ctti_size == 0x8)
>   	btf_kind = BTF_KIND_ENUM64;
> -   }
> +    }
>   
>     /* PR debug/112656.  BTF_KIND_FUNC_PROTO is always anonymous.  */
>     else if (btf_kind == BTF_KIND_FUNC_PROTO)
> @@ -879,7 +435,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>   
>     dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
>   		       "TYPE %" PRIu64 " BTF_KIND_%s '%s'",
> -		       get_btf_id (dtd->dtd_type), btf_kind_name (btf_kind),
> +		       dtd->dtd_type, btf_kind_name (btf_kind),
>   		       get_btf_type_name (dtd));
>     dw2_asm_output_data (4, BTF_TYPE_INFO (btf_kind, btf_kflag, btf_vlen),
>   		       "btt_info: kind=%u, kflag=%u, vlen=%u",
> @@ -905,30 +461,29 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>         break;
>       }
>   
> -  ctf_id_t ref_id = dtd->dtd_data.ctti_type;
> -  btf_asm_type_ref ("btt_type", ctfc, ref_id);
> +  btf_asm_type_ref ("btt_type", dtd->ref_type);
>   }
>   
>   /* Asm'out the variable information following a BTF_KIND_ARRAY.  */
>   
>   static void
> -btf_asm_array (ctf_container_ref ctfc, ctf_arinfo_t arr)
> +btf_asm_array (ctf_arinfo_t arr)
>   {
> -  btf_asm_type_ref ("bta_elem_type", ctfc, arr.ctr_contents->dtd_type);
> -  btf_asm_type_ref ("bta_index_type", ctfc, arr.ctr_index->dtd_type);
> +  btf_asm_type_ref ("bta_elem_type", arr.ctr_contents);
> +  btf_asm_type_ref ("bta_index_type", arr.ctr_index);
>     dw2_asm_output_data (4, arr.ctr_nelems, "bta_nelems");
>   }
>   
>   /* Asm'out a BTF_KIND_VAR.  */
>   
>   static void
> -btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
> +btf_asm_varent (ctf_dvdef_ref var)
>   {
> -  dw2_asm_output_data (4, var->dvd_name_offset, "TYPE %u BTF_KIND_VAR '%s'",
> -		       (*(btf_var_ids->get (var)) + num_types_added + 1),
> -		       var->dvd_name);
> +  dw2_asm_output_data (4, var->dvd_name_offset,
> +                       "TYPE %" PRIu64 " BTF_KIND_VAR '%s'",
> +                       var->dvd_id, var->dvd_name);
>     dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_VAR, 0, 0), "btv_info");
> -  btf_asm_type_ref ("btv_type", ctfc, var->dvd_type->dtd_type);
> +  btf_asm_type_ref ("btv_type", var->dvd_type);
>     dw2_asm_output_data (4, var->dvd_visibility, "btv_linkage");
>   }
>   
> @@ -936,23 +491,22 @@ btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
>      BTF_KIND_UNION.  */
>   
>   static void
> -btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
> +btf_asm_sou_member (ctf_dmdef_t * dmd, unsigned int idx)
>   {
> -  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
> -  ctf_id_t base_type = dmd->dmd_type->dtd_type;
> +  ctf_dtdef_ref base_type = dmd->dmd_type;
>     uint64_t sou_offset = dmd->dmd_offset;
>   
>     dw2_asm_output_data (4, dmd->dmd_name_offset,
>   		       "MEMBER '%s' idx=%u",
>   		       dmd->dmd_name, idx);
>   
> -  /* Re-encode bitfields to BTF representation.  */
> -  if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
> +  if (base_type
> +      && CTF_V2_INFO_KIND (base_type->dtd_data.ctti_info) == CTF_K_SLICE)
>       {
> -      if (btf_dmd_representable_bitfield_p (ctfc, dmd))
> +      if (btf_dmd_representable_bitfield_p (dmd))
>   	{
> -	  unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset;
> -	  unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits;
> +	  unsigned short word_offset = base_type->dtd_u.dtu_slice.cts_offset;
> +	  unsigned short bits = base_type->dtd_u.dtu_slice.cts_bits;
>   
>   	  /* Pack the bit offset and bitfield size together.  */
>   	  sou_offset += word_offset;
> @@ -960,17 +514,17 @@ btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
>   	  sou_offset |= ((bits & 0xff) << 24);
>   
>   	  /* Refer to the base type of the slice.  */
> -	  base_type = ref_type->dtd_u.dtu_slice.cts_type->dtd_type;
> +	  base_type = base_type->dtd_u.dtu_slice.cts_type;
>   	}
>         else
>   	{
>   	  /* Bitfield cannot be represented in BTF.  Emit the member as having
>   	     'void' type.  */
> -	  base_type = BTF_VOID_TYPEID;
> +	  base_type = NULL;
>   	}
>       }
>   
> -  btf_asm_type_ref ("btm_type", ctfc, base_type);
> +  btf_asm_type_ref ("btm_type", base_type);
>     dw2_asm_output_data (4, sou_offset, "btm_offset");
>   }
>   
> @@ -993,86 +547,68 @@ btf_asm_enum_const (unsigned int size, ctf_dmdef_t * dmd, unsigned int idx)
>   /* Asm'out a function parameter description following a BTF_KIND_FUNC_PROTO.  */
>   
>   static void
> -btf_asm_func_arg (ctf_container_ref ctfc, ctf_func_arg_t * farg,
> -		  size_t stroffset)
> +btf_asm_func_arg (ctf_func_arg_t * farg, size_t stroffset)
>   {
>     /* If the function arg does not have a name, refer to the null string at
>        the start of the string table. This ensures correct encoding for varargs
>        '...' arguments.  */
>     if ((farg->farg_name != NULL) && strcmp (farg->farg_name, ""))
> -    dw2_asm_output_data (4, farg->farg_name_offset + stroffset, "farg_name");
> +    dw2_asm_output_data (4, farg->farg_name_offset + stroffset,
> +			 "farg_name '%s'", farg->farg_name);
>     else
> -    dw2_asm_output_data (4, 0, "farg_name");
> -
> -  ctf_id_t ref_id = BTF_VOID_TYPEID;
> -  if (farg->farg_type && !btf_removed_type_p (farg->farg_type->dtd_type))
> -    ref_id = farg->farg_type->dtd_type;
> +    dw2_asm_output_data (4, 0, "farg_name ''");
>   
> -  btf_asm_type_ref ("farg_type", ctfc, ref_id);
> +  btf_asm_type_ref ("farg_type", farg->farg_type);
>   }
>   
>   /* Asm'out a BTF_KIND_FUNC type.  */
>   
>   static void
> -btf_asm_func_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd, ctf_id_t id)
> +btf_asm_func_type (ctf_dtdef_ref dtd)
>   {
> -  ctf_id_t ref_id = dtd->dtd_data.ctti_type;
>     dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
>   		       "TYPE %" PRIu64 " BTF_KIND_FUNC '%s'",
> -		       btf_absolute_func_id (id), get_btf_type_name (dtd));
> +		       dtd->dtd_type, get_btf_type_name (dtd));
>     dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_FUNC, 0, dtd->linkage),
>   		       "btt_info: kind=%u, kflag=%u, linkage=%u",
>   		       BTF_KIND_FUNC, 0, dtd->linkage);
> -  btf_asm_type_ref ("btt_type", ctfc, ref_id);
> +  btf_asm_type_ref ("btt_type", dtd->ref_type);
>   }
>   
> -/* Collect the name for the DATASEC reference required to be output as a
> -   symbol. */
> +/* Asm'out a variable entry following a BTF_KIND_DATASEC.  */
>   
> -static const char *
> -get_name_for_datasec_entry (ctf_container_ref ctfc, ctf_id_t ref_id)
> +static void
> +btf_asm_datasec_entry (struct btf_datasec_entry entry)
>   {
> -  if (ref_id >= num_types_added + 1
> -      && ref_id < num_types_added + num_vars_added + 1)
> +  const char *symbol_name = NULL;
> +  if (entry.is_var)
>       {
> -      /* Ref to a variable.  Should only appear in DATASEC entries.  */
> -      ctf_id_t var_id = btf_relative_var_id (ref_id);
> -      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[var_id];
> -      return dvd->dvd_name;
> +      symbol_name = entry.dvd->dvd_name;
> +      dw2_asm_output_data (4, entry.dvd->dvd_id,
> +			   "bts_type: (BTF_KIND_VAR '%s')", symbol_name);
>       }
> -  else if (ref_id >= num_types_added + num_vars_added + 1)
> +  else
>       {
> -      /* Ref to a FUNC record.  */
> -      size_t func_id = btf_relative_func_id (ref_id);
> -      ctf_dtdef_ref ref_type = (*funcs)[func_id];
> -      return get_btf_type_name (ref_type);
> +      symbol_name = entry.dtd->dtd_name;
> +      btf_asm_type_ref ("bts_type", entry.dtd);
>       }
> -  return NULL;
> -}
> -
> -/* Asm'out a variable entry following a BTF_KIND_DATASEC.  */
>   
> -static void
> -btf_asm_datasec_entry (ctf_container_ref ctfc, struct btf_var_secinfo info)
> -{
> -  const char *symbol_name = get_name_for_datasec_entry (ctfc, info.type);
> -  btf_asm_datasec_type_ref ("bts_type", ctfc, info.type);
>     if (!btf_with_core_debuginfo_p () || symbol_name == NULL)
> -    dw2_asm_output_data (4, info.offset, "bts_offset");
> +    dw2_asm_output_data (4, 0, "bts_offset");
>     else
>       dw2_asm_output_offset (4, symbol_name, NULL, "bts_offset");
> -  dw2_asm_output_data (4, info.size, "bts_size");
> +
> +  dw2_asm_output_data (4, entry.size, "bts_size");
>   }
>   
>   /* Asm'out a whole BTF_KIND_DATASEC, including its variable entries.  */
>   
>   static void
> -btf_asm_datasec_type (ctf_container_ref ctfc, btf_datasec_t ds, ctf_id_t id,
> -		      size_t stroffset)
> +btf_asm_datasec_type (btf_datasec_t ds)
>   {
> -  dw2_asm_output_data (4, ds.name_offset + stroffset,
> +  dw2_asm_output_data (4, ds.name_offset,
>   		       "TYPE %" PRIu64 " BTF_KIND_DATASEC '%s'",
> -		       btf_absolute_datasec_id (id), ds.name);
> +		       ds.id, ds.name);
>     dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_DATASEC, 0,
>   					 ds.entries.length ()),
>   		       "btt_info: n_entries=%u", ds.entries.length ());
> @@ -1080,7 +616,7 @@ btf_asm_datasec_type (ctf_container_ref ctfc, btf_datasec_t ds, ctf_id_t id,
>        loaders such as libbpf.  */
>     dw2_asm_output_data (4, 0, "btt_size");
>     for (size_t i = 0; i < ds.entries.length (); i++)
> -    btf_asm_datasec_entry (ctfc, ds.entries[i]);
> +    btf_asm_datasec_entry (ds.entries[i]);
>   }
>   
>   /* Compute and output the header information for a .BTF section.  */
> @@ -1099,20 +635,11 @@ output_btf_header (ctf_container_ref ctfc)
>   
>      uint32_t type_off = 0, type_len = 0;
>      uint32_t str_off = 0, str_len = 0;
> -   uint32_t datasec_vlen_bytes = 0;
>   
>      if (!ctfc_is_empty_container (ctfc))
>        {
> -       for (size_t i = 0; i < datasecs.length (); i++)
> -	 {
> -	   datasec_vlen_bytes += ((datasecs[i].entries.length ())
> -				  * sizeof (struct btf_var_secinfo));
> -	 }
> -
>          /* Total length (bytes) of the types section.  */
> -       type_len = (num_types_added * sizeof (struct btf_type))
> -	 + (num_types_created * sizeof (struct btf_type))
> -	 + datasec_vlen_bytes
> +       type_len = ctfc->ctfc_num_types * sizeof (struct btf_type)
>   	 + ctfc->ctfc_num_vlen_bytes;
>   
>          str_off = type_off + type_len;
> @@ -1124,7 +651,9 @@ output_btf_header (ctf_container_ref ctfc)
>      /* Offset of type section.  */
>      dw2_asm_output_data (4, type_off, "type_off");
>      /* Length of type section in bytes.  */
> -   dw2_asm_output_data (4, type_len, "type_len");
> +   dw2_asm_output_data (4, type_len, "type_len: ntypes=%u, vlen=%u",
> +			(uint32_t) ctfc->ctfc_num_types,
> +			(uint32_t) ctfc->ctfc_num_vlen_bytes);
>       /* Offset of string section.  */
>      dw2_asm_output_data (4, str_off, "str_off");
>       /* Length of string section in bytes.  */
> @@ -1137,11 +666,11 @@ static void
>   output_btf_vars (ctf_container_ref ctfc)
>   {
>     size_t i;
> -  size_t num_ctf_vars = num_vars_added;
> +  size_t num_ctf_vars = ctfc->ctfc_vars_list_count;
>     if (num_ctf_vars)
>       {
>         for (i = 0; i < num_ctf_vars; i++)
> -	btf_asm_varent (ctfc, ctfc->ctfc_vars_list[i]);
> +	btf_asm_varent (ctfc->ctfc_vars_list[i]);
>       }
>   }
>   
> @@ -1156,7 +685,8 @@ output_btf_strs (ctf_container_ref ctfc)
>   
>     while (ctf_string)
>       {
> -      dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_string, str_pos = 0x%x", str_pos);
> +      dw2_asm_output_nstring (ctf_string->cts_str, -1,
> +			      "btf_string, str_pos = 0x%x", str_pos);
>         str_pos += strlen(ctf_string->cts_str) + 1;
>         ctf_string = ctf_string->cts_next;
>       }
> @@ -1164,7 +694,8 @@ output_btf_strs (ctf_container_ref ctfc)
>     ctf_string = ctfc->ctfc_aux_strtable.ctstab_head;
>     while (ctf_string)
>       {
> -      dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_aux_string, str_pos = 0x%x", str_pos);
> +      dw2_asm_output_nstring (ctf_string->cts_str, -1,
> +			      "btf_aux_string, str_pos = 0x%x", str_pos);
>         str_pos += strlen(ctf_string->cts_str) + 1;
>         ctf_string = ctf_string->cts_next;
>       }
> @@ -1174,7 +705,7 @@ output_btf_strs (ctf_container_ref ctfc)
>      BTF_KIND_UNION type.  */
>   
>   static void
> -output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
> +output_asm_btf_sou_fields (ctf_dtdef_ref dtd)
>   {
>     ctf_dmdef_t * dmd;
>   
> @@ -1182,7 +713,7 @@ output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>     for (dmd = dtd->dtd_u.dtu_members;
>          dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
>       {
> -      btf_asm_sou_member (ctfc, dmd, idx);
> +      btf_asm_sou_member (dmd, idx);
>         idx++;
>       }
>   }
> @@ -1190,8 +721,7 @@ output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>   /* Output all enumerator constants following a BTF_KIND_ENUM{,64}.  */
>   
>   static void
> -output_asm_btf_enum_list (ctf_container_ref ARG_UNUSED (ctfc),
> -			  ctf_dtdef_ref dtd)
> +output_asm_btf_enum_list (ctf_dtdef_ref dtd)
>   {
>     ctf_dmdef_t * dmd;
>   
> @@ -1214,7 +744,7 @@ output_asm_btf_func_args_list (ctf_container_ref ctfc,
>     ctf_func_arg_t * farg;
>     for (farg = dtd->dtd_u.dtu_argv;
>          farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
> -    btf_asm_func_arg (ctfc, farg, farg_name_offset);
> +    btf_asm_func_arg (farg, farg_name_offset);
>   }
>   
>   /* Output the variable portion of a BTF type record. The information depends
> @@ -1225,7 +755,7 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>   {
>     uint32_t btf_kind, encoding;
>   
> -  btf_kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
> +  btf_kind = btf_dtd_kind (dtd);
>   
>     if (btf_kind == BTF_KIND_UNKN)
>       return;
> @@ -1238,8 +768,7 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>         if (dtd->dtd_data.ctti_size < 1)
>   	break;
>   
> -      /* In BTF the CHAR `encoding' seems to not be used, so clear it
> -         here.  */
> +      /* In BTF the CHAR `encoding' seems to not be used, so clear it here.  */
>         dtd->dtd_u.dtu_enc.cte_format &= ~BTF_INT_CHAR;
>   
>         encoding = BTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
> @@ -1250,16 +779,16 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>         break;
>   
>       case BTF_KIND_ARRAY:
> -      btf_asm_array (ctfc, dtd->dtd_u.dtu_arr);
> +      btf_asm_array (dtd->dtd_u.dtu_arr);
>         break;
>   
>       case BTF_KIND_STRUCT:
>       case BTF_KIND_UNION:
> -      output_asm_btf_sou_fields (ctfc, dtd);
> +      output_asm_btf_sou_fields (dtd);
>         break;
>   
>       case BTF_KIND_ENUM:
> -      output_asm_btf_enum_list (ctfc, dtd);
> +      output_asm_btf_enum_list (dtd);
>         break;
>   
>       case BTF_KIND_FUNC_PROTO:
> @@ -1289,9 +818,9 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>   static void
>   output_asm_btf_type (ctf_container_ref ctfc, ctf_dtdef_ref type)
>   {
> -  if (btf_emit_id_p (type->dtd_type))
> +  if (btf_emit_type_p (type))
>       {
> -      btf_asm_type (ctfc, type);
> +      btf_asm_type (type);
>         output_asm_btf_vlen_bytes (ctfc, type);
>       }
>   }
> @@ -1303,7 +832,9 @@ static void
>   output_btf_types (ctf_container_ref ctfc)
>   {
>     size_t i;
> -  size_t num_types = ctfc->ctfc_types->elements ();
> +  size_t num_types;
> +  num_types = ctfc->ctfc_types->elements ();
> +
>     if (num_types)
>       {
>         for (i = 1; i <= num_types; i++)
> @@ -1314,76 +845,45 @@ output_btf_types (ctf_container_ref ctfc)
>   /* Output all BTF_KIND_FUNC type records.  */
>   
>   static void
> -output_btf_func_types (ctf_container_ref ctfc)
> +output_btf_func_types (void)
>   {
>     ctf_dtdef_ref ref;
>     unsigned i;
>     FOR_EACH_VEC_ELT (*funcs, i, ref)
> -    btf_asm_func_type (ctfc, ref, i);
> +    btf_asm_func_type (ref);
>   }
>   
>   /* Output all BTF_KIND_DATASEC records.  */
>   
>   static void
> -output_btf_datasec_types (ctf_container_ref ctfc)
> +output_btf_datasec_types (void)
>   {
> -  size_t name_offset = ctfc_get_strtab_len (ctfc, CTF_STRTAB);
> -
> -  for (size_t i = 0; i < datasecs.length(); i++)
> -    btf_asm_datasec_type (ctfc, datasecs[i], i, name_offset);
> +  for (size_t i = 0; i < datasecs.length (); i++)
> +    btf_asm_datasec_type (datasecs[i]);
>   }
>   
> -/* Postprocess the CTF debug data post initialization.
> -
> -   During the postprocess pass:
> -
> -   - Prepare the sorted list of BTF types.
> -
> -     The sorted list of BTF types is, firstly, used for lookup (during the BTF
> -     generation process) of CTF/BTF types given a typeID.
> -
> -     Secondly, in the emitted BTF section, BTF Types need to be in the sorted
> -     order of their type IDs.  The BTF types section is viewed as an array,
> -     with type IDs used to index into that array.  It is essential that every
> -     type be placed at the exact index corresponding to its ID, or else
> -     references to that type from other types will no longer be correct.
> -
> -   - References to void types are converted to reference BTF_VOID_TYPEID. In
> -     CTF, a distinct type is used to encode void.
> -
> -   - Bitfield struct/union members are converted to BTF encoding. CTF uses
> -     slices to encode bitfields, but BTF does not have slices and encodes
> -     bitfield information directly in the variable-length btf_member
> -     descriptions following the struct or union type.
> -
> -   - Unrepresentable types are removed. We cannot have any invalid BTF types
> -     appearing in the output so they must be removed, and type ids of other
> -     types and references adjust accordingly. This also involves ensuring that
> -     BTF descriptions of struct members referring to unrepresentable types are
> -     not emitted, as they would be nonsensical.
> -
> -   - Adjust inner- and inter-type references-by-ID to account for removed
> -     types, and construct the types list.  */
> +/* Write out all BTF debug info.  */
>   
>   void
> -btf_init_postprocess (void)
> +btf_output (ctf_container_ref ctfc)
>   {
> -  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
> -
> -  holes.create (0);
> -  voids.create (0);
> +  output_btf_header (ctfc);
> +  output_btf_types (ctfc);
> +  output_btf_vars (ctfc);
> +  output_btf_func_types ();
> +  output_btf_datasec_types ();
> +  output_btf_strs (ctfc);
> +}
>   
> -  num_types_added = 0;
> -  num_types_created = 0;
> +/* Workaround for 'const void' variables.  These variables are sometimes used
> +   in eBPF programs to address kernel symbols.  DWARF does not generate const
> +   qualifier on void type, so we would incorrectly emit these variables
> +   without the const qualifier.  Find any such variables, and update them to
> +   refer to a new 'const' modifier type for void.  */
>   
> -  /* Workaround for 'const void' variables.  These variables are sometimes used
> -     in eBPF programs to address kernel symbols.  DWARF does not generate const
> -     qualifier on void type, so we would incorrectly emit these variables
> -     without the const qualifier.
> -     Unfortunately we need the TREE node to know it was const, and we need
> -     to create the const modifier type (if needed) now, before making the types
> -     list.  So we can't avoid iterating with FOR_EACH_VARIABLE here, and then
> -     again when creating the DATASEC entries.  */
> +static void
> +btf_early_add_const_void (ctf_container_ref ctfc)
> +{
>     ctf_dtdef_ref constvoid_dtd = NULL;
>     varpool_node *var;
>     FOR_EACH_VARIABLE (var)
> @@ -1398,120 +898,389 @@ btf_init_postprocess (void)
>   	  if (die == NULL)
>   	    continue;
>   
> -	  ctf_dvdef_ref dvd = ctf_dvd_lookup (tu_ctfc, die);
> +	  ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
>   	  if (dvd == NULL)
>   	    continue;
>   
>   	  /* Create the 'const' modifier type for void.  */
>   	  if (constvoid_dtd == NULL)
> -            constvoid_dtd = ctf_add_reftype (tu_ctfc, CTF_ADD_ROOT,
> -                                             dvd->dvd_type, CTF_K_CONST, NULL);
> +	    constvoid_dtd = ctf_add_reftype (ctfc, CTF_ADD_ROOT,
> +					     dvd->dvd_type, CTF_K_CONST, NULL);
>   	  dvd->dvd_type = constvoid_dtd;
>   	}
>       }
> +}
>   
> -  size_t i;
> -  size_t num_ctf_types = tu_ctfc->ctfc_types->elements ();
> +/* Functions actually get two type records: a BTF_KIND_FUNC_PROTO, and also a
> +   BTF_KIND_FUNC.  But the CTF container only allocates one type per function,
> +   which matches closely with BTF_KIND_FUNC_PROTO.  For each such function,
> +   construct a BTF_KIND_FUNC entry.  This is done early, because we want FUNC
> +   records even for functions which are later inlined by optimizations.  */
>   
> -  if (num_ctf_types)
> +static void
> +btf_early_add_func_records (ctf_container_ref ctfc)
> +{
> +  cgraph_node *func;
> +  FOR_EACH_FUNCTION (func)
>       {
> -      init_btf_id_map (num_ctf_types + 1);
> -
> -      /* Allocate the types list and traverse all types, placing each type
> -	 at the index according to its ID.  Add 1 because type ID 0 always
> -	 represents VOID.  */
> -      tu_ctfc->ctfc_types_list
> -	= ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1);
> -      tu_ctfc->ctfc_types->traverse<ctf_container_ref, btf_dtd_postprocess_cb>
> -	(tu_ctfc);
> -
> -      /* Build mapping of CTF type ID -> BTF type ID, and count total number
> -	 of valid BTF types added.  */
> -      for (i = 1; i <= num_ctf_types; i++)
> -	{
> -	  ctf_dtdef_ref dtd = tu_ctfc->ctfc_types_list[i];
> -	  ctf_id_t btfid = btf_adjust_type_id (dtd->dtd_type);
> -	  set_btf_id (dtd->dtd_type, btfid);
> -	  if (btfid < BTF_MAX_TYPE && (btfid != BTF_VOID_TYPEID))
> -	    num_types_added ++;
> -	}
> +      dw_die_ref die = lookup_decl_die (func->decl);
> +      if (die == NULL)
> +	continue;
> +
> +      ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
> +      if (dtd == NULL)
> +	continue;
> +
> +      /* Do not add FUNC records for kernel helpers.  */
> +      if (DECL_EXTERNAL (func->decl)
> +	  && (lookup_attribute ("kernel_helper",
> +				DECL_ATTRIBUTES (func->decl))) != NULL_TREE)
> +	continue;
> +
> +      ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
> +      func_dtd->dtd_data = dtd->dtd_data;
> +      func_dtd->dtd_data.ctti_type = dtd->dtd_type;
> +      func_dtd->ref_type = dtd;
> +      func_dtd->linkage = dtd->linkage;
> +      func_dtd->dtd_name = dtd->dtd_name;
> +      /* Type ID will be assigned just before output.  */
> +
> +      /* Only the BTF_KIND_FUNC type actually references the name. The
> +	 BTF_KIND_FUNC_PROTO is always anonymous.  */
> +      dtd->dtd_data.ctti_name = 0;
> +
> +      /* Mark 'extern' funcs.  */
> +      if (DECL_EXTERNAL (func->decl))
> +	func_dtd->linkage = BTF_FUNC_EXTERN;
> +
> +      /* Buffer newly created FUNC records.  We cannot simply insert them
> +	 into the types map, because types are keyed by their DWARF DIE,
> +	 and we have no unique DIE to use as a key since the FUNC_PROTOs
> +	 are already present in the map.  */
> +      vec_safe_push (funcs, func_dtd);
> +      func_map->put (dtd, func_dtd);
>       }
>   }
>   
> -/* Process and output all BTF data. Entry point of btfout.  */
> +/* Initial entry point of BTF generation, called at early_finish () after
> +   CTF information has possibly been output.  Translate all CTF information
> +   to BTF, and do any processing that must be done early, such as creating
> +   BTF_KIND_FUNC records.  */
>   
>   void
> -btf_output (const char * filename)
> +btf_early_finish (void)
>   {
>     ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
>   
> -  init_btf_sections ();
> -
> -  datasecs.create (0);
>     vec_alloc (funcs, 16);
> +  func_map = hash_map<ctf_dtdef_ref, ctf_dtdef_ref>::create_ggc (16);
> +
> +  btf_early_add_const_void (tu_ctfc);
> +  btf_early_add_func_records (tu_ctfc);
> +}
> +
> +/* Push a BTF datasec entry ENTRY into the datasec named SECNAME,
> +   creating the datasec record if it does not already exist.  */
> +
> +static void
> +btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
> +			struct btf_datasec_entry entry)
> +{
> +  if (secname == NULL)
> +    return;
> +
> +  /* If we already have a datasec record for the appropriate section,
> +     append the new entry to it.  */
> +  for (size_t i = 0; i < datasecs.length (); i++)
> +    if (strcmp (datasecs[i].name, secname) == 0)
> +      {
> +	datasecs[i].entries.safe_push (entry);
> +	return;
> +      }
> +
> +  /* If we don't already have a datasec record for secname, make one.  */
> +  uint32_t str_off;
> +  ctf_add_string (ctfc, secname, &str_off, CTF_AUX_STRTAB);
> +  if (strcmp (secname, ""))
> +    ctfc->ctfc_aux_strlen += strlen (secname) + 1;
>   
> -  ctf_add_cuname (tu_ctfc, filename);
> +  /* Note: ID will be assigned just before output.  */
> +  btf_datasec_t ds;
> +  ds.name = secname;
> +  ds.name_offset = str_off;
>   
> -  btf_emit_preprocess (tu_ctfc);
> +  /* Insert the entry into the new datasec record.  */
> +  ds.entries.create (1);
> +  ds.entries.quick_push (entry);
>   
> -  output_btf_header (tu_ctfc);
> -  output_btf_types (tu_ctfc);
> -  output_btf_vars (tu_ctfc);
> -  output_btf_func_types (tu_ctfc);
> -  output_btf_datasec_types (tu_ctfc);
> -  output_btf_strs (tu_ctfc);
> +  /* Insert the datasec record itself.  */
> +  datasecs.safe_push (ds);
>   }
>   
> -/* Reset all state for BTF generation so that we can rerun the compiler within
> -   the same process.  */
> +/* Create a datasec entry for a function, and insert it into the datasec
> +   record for the appropriate section.  Create the record if it does not
> +   yet exist.  */
>   
> -void
> -btf_finalize (void)
> +static void
> +btf_datasec_add_func (ctf_container_ref ctfc, cgraph_node *func,
> +		      ctf_dtdef_ref func_dtd)
>   {
> -  btf_info_section = NULL;
> +  const char *section_name = get_section_name (func);
>   
> -  /* Clear preprocessing state.  */
> -  num_vars_added = 0;
> -  num_types_added = 0;
> -  num_types_created = 0;
> +  /* Note: get_section_name () returns NULL for functions in text
> +     section.  This is intentional, since we do not want to generate
> +     DATASEC entries for them.  */
> +  if (section_name == NULL)
> +    return;
>   
> -  holes.release ();
> -  voids.release ();
> -  for (size_t i = 0; i < datasecs.length (); i++)
> -    datasecs[i].entries.release ();
> -  datasecs.release ();
> +  struct btf_datasec_entry entry;
> +  gcc_assert (func_dtd);
> +  entry.dtd = func_dtd;
> +  entry.is_var = false;
>   
> -  funcs = NULL;
> +  /* Size is left as zero at compile time, to be filled in by loaders
> +     such as libbpf.  */
> +  entry.size = 0;
>   
> -  btf_var_ids->empty ();
> -  btf_var_ids = NULL;
> +  btf_datasec_push_entry (ctfc, section_name, entry);
> +}
>   
> -  free (btf_id_map);
> -  btf_id_map = NULL;
> +/* Create a datasec entry for a variable, and insert it into the datasec
> +   record for the appropriate section.  Create the record if it does not
> +   yet exist.  */
>   
> -  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
> -  ctfc_delete_container (tu_ctfc);
> -  tu_ctfc = NULL;
> +static void
> +btf_datasec_add_var (ctf_container_ref ctfc, varpool_node *var,
> +		     ctf_dvdef_ref dvd)
> +{
> +  /* PR112849: avoid assuming a section for extern decls without
> +     an explicit section, which would result in incorrectly
> +     emitting a BTF_KIND_DATASEC entry for them.  */
> +  if (DECL_EXTERNAL (var->decl) && var->get_section () == NULL)
> +    return;
> +
> +  const char *section_name = get_section_name (var);
> +  if (section_name == NULL)
> +    return;
> +
> +  gcc_assert (dvd);
> +  struct btf_datasec_entry entry;
> +  entry.dvd = dvd;
> +  entry.is_var = true;
> +  entry.size = 0;
> +
> +  tree size = DECL_SIZE_UNIT (var->decl);
> +  if (tree_fits_uhwi_p (size))
> +    entry.size = tree_to_uhwi (size);
> +  else if (VOID_TYPE_P (TREE_TYPE (var->decl)))
> +    entry.size = 1;
> +
> +  btf_datasec_push_entry (ctfc, section_name, entry);
>   }
>   
> -/* Initial entry point of BTF generation, called at early_finish () after
> -   CTF information has possibly been output.  Translate all CTF information
> -   to BTF, and do any processing that must be done early, such as creating
> -   BTF_KIND_FUNC records.  */
> +/* Add datasec entries for functions to CTFC.  */
>   
> -void
> -btf_early_finish (void)
> +static void
> +btf_late_add_func_datasec_entries (ctf_container_ref ctfc)
> +{
> +  /* We need to create FUNC records at early_finish, so that we have them
> +     even for functions which are later inlined by optimization passes.
> +     But on the other hand, we do not want datasec entries for such functions,
> +     so only create the datasec entries for them late.  This loop will not
> +     hit functions which have already been inlined.  */
> +  cgraph_node *func;
> +  FOR_EACH_FUNCTION (func)
> +    {
> +      dw_die_ref die = lookup_decl_die (func->decl);
> +      if (die == NULL)
> +	continue;
> +
> +      ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
> +      if (dtd == NULL)
> +	continue;
> +
> +      ctf_dtdef_ref *pdtd = func_map->get (dtd);
> +      if (pdtd && DECL_EXTERNAL (func->decl))
> +	btf_datasec_add_func (ctfc, func, *pdtd);
> +    }
> +}
> +
> +/* Helper function used to determine whether or not a BTF_KIND_VAR record
> +   for the variable VAR shall be emitted.  */
> +
> +static bool
> +btf_emit_variable_p (ctf_container_ref ctfc, varpool_node *var,
> +		     ctf_dvdef_ref *pdvd)
> +{
> +  dw_die_ref die = lookup_decl_die (var->decl);
> +  if (die == NULL)
> +    return false;
> +
> +  ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
> +  if (dvd == NULL)
> +    return false;
> +
> +  /* If this is an extern variable declaration with a defining declaration
> +     later, skip it so that only the defining declaration is emitted.
> +     This is the same case, fix and reasoning as in CTF; see PR105089.  */
> +  if (ctf_dvd_ignore_lookup (ctfc, dvd->dvd_key))
> +    return false;
> +
> +  /* Skip variables with unrepresentable types.  */
> +  if (!btf_emit_type_p (dvd->dvd_type))
> +    return false;
> +
> +  *pdvd = dvd;
> +  return true;
> +}
> +
> +/* Add BTF_KIND_VAR records for variables.  */
> +
> +static void
> +btf_late_add_vars (ctf_container_ref ctfc)
> +{
> +  size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
> +
> +  ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars);
> +
> +  varpool_node *var;
> +  ctf_dvdef_ref dvd;
> +  FOR_EACH_VARIABLE (var)
> +    {
> +      if (!btf_emit_variable_p (ctfc, var, &dvd))
> +	continue;
> +
> +      /* Mark 'extern' variables.  */
> +      if (DECL_EXTERNAL (var->decl))
> +	dvd->dvd_visibility = BTF_VAR_GLOBAL_EXTERN;
> +
> +      /* Add the variable to the vars list.  */
> +      ctfc->ctfc_vars_list[ctfc->ctfc_vars_list_count++] = dvd;
> +
> +      /* Add a BTF_KIND_DATASEC entry for the variable.  */
> +      btf_datasec_add_var (ctfc, var, dvd);
> +    }
> +}
> +
> +/* Callback used by btf_late_assign_type_ids to insert types into their initial
> +   positions in the type list.  */
> +
> +static int
> +btf_type_list_cb (ctf_dtdef_ref *slot, ctf_container_ref ctfc)
> +{
> +  ctf_dtdef_ref dtd = *slot;
> +  ctfc->ctfc_types_list[dtd->dtd_type] = dtd;
> +  return 1;
> +}
> +
> +/* Construct the initial type list and assign BTF IDs for all types translated
> +   from CTF.  */
> +
> +static void
> +btf_late_collect_translated_types (ctf_container_ref ctfc)
> +{
> +  size_t num_ctf_types = ctfc->ctfc_types->elements ();
> +
> +  /* First, place each type at its CTF-assigned index in the list.
> +     The '+1' here and below is to account for the implicit void type with
> +     ID 0.  There is no real type at index 0 in the list.  */
> +  ctfc->ctfc_types_list = ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1);
> +  ctfc->ctfc_types->traverse<ctf_container_ref, btf_type_list_cb> (ctfc);
> +
> +  /* Now, pass through the list and adjust IDs to account for types which will
> +     not be emitted.  This results in each type that will be emitted in BTF
> +     being assigned an appropriate ID.  Note that types which will not be
> +     emitted remain in the list; they are skipped at output time.  */
> +  unsigned int skip = 0;
> +  for (size_t i = 1; i <= num_ctf_types; i++)
> +    {
> +      ctf_dtdef_ref dtd = ctfc->ctfc_types_list[i];
> +      if (!btf_emit_type_p (dtd))
> +	{
> +	  dtd->dtd_type = BTF_INVALID_TYPEID;
> +	  skip += 1;
> +	  continue;
> +	}
> +
> +      dtd->dtd_type -= skip;
> +      ctfc->ctfc_num_types++;
> +      ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
> +    }
> +
> +  max_translated_id = ctfc->ctfc_num_types;
> +  ctfc->ctfc_nextid = ctfc->ctfc_num_types + 1;
> +}
> +
> +/* Assign BTF IDs for FUNC records and account for their size.  */
> +
> +static void
> +btf_late_assign_func_ids (ctf_container_ref ctfc)
> +{
> +  ctf_dtdef_ref dtd;
> +  unsigned int i;
> +  FOR_EACH_VEC_ELT (*funcs, i, dtd)
> +    {
> +      dtd->dtd_type = ctfc->ctfc_nextid++;
> +      ctfc->ctfc_num_types++;
> +    }
> +}
> +
> +/* Assign BTF IDs for variables and account for their size.  */
> +
> +static void
> +btf_late_assign_var_ids (ctf_container_ref ctfc)
> +{
> +  for (size_t i = 0; i < ctfc->ctfc_vars_list_count; i++)
> +    {
> +      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
> +      ctf_id_t id = ctfc->ctfc_nextid++;
> +      gcc_assert (id <= BTF_MAX_TYPE);
> +      dvd->dvd_id = id;
> +
> +      ctfc->ctfc_num_types++;
> +      ctfc->ctfc_num_vlen_bytes += sizeof (struct btf_var);
> +    }
> +}
> +
> +/* Assign BTF IDs for datasec records and account for their size.  */
> +
> +static void
> +btf_late_assign_datasec_ids (ctf_container_ref ctfc)
>   {
> -  btf_init_postprocess ();
> +  for (size_t i = 0; i < datasecs.length (); i++)
> +    {
> +      datasecs[i].id = ctfc->ctfc_nextid++;
> +      datasecs[i].name_offset += ctfc_get_strtab_len (ctfc, CTF_STRTAB);
> +      ctfc->ctfc_num_types++;
> +      ctfc->ctfc_num_vlen_bytes += (datasecs[i].entries.length ()
> +				    * sizeof (struct btf_var_secinfo));
> +    }
>   }
>   
>   /* Late entry point for BTF generation, called from dwarf2out_finish ().
>      Complete and emit BTF information.  */
>   
>   void
> -btf_finish (const char * filename)
> +btf_finish (void)
>   {
> -  btf_output (filename);
> +  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
> +  init_btf_sections ();
> +
> +  datasecs.create (0);
> +
> +  tu_ctfc->ctfc_num_types = 0;
> +  tu_ctfc->ctfc_num_vlen_bytes = 0;
> +  tu_ctfc->ctfc_vars_list_count = 0;
> +
> +  btf_late_add_vars (tu_ctfc);
> +  btf_late_collect_translated_types (tu_ctfc);
> +  btf_late_add_func_datasec_entries (tu_ctfc);
> +  btf_late_assign_var_ids (tu_ctfc);
> +  btf_late_assign_func_ids (tu_ctfc);
> +  btf_late_assign_datasec_ids (tu_ctfc);
> +
> +  /* Finally, write out the complete .BTF section.  */
> +  btf_output (tu_ctfc);
>   
>     /* If compiling for BPF with CO-RE info, we cannot deallocate until after
>        CO-RE information is created, which happens very late in BPF backend.
> @@ -1521,6 +1290,27 @@ btf_finish (const char * filename)
>       btf_finalize ();
>   }
>   
> +/* Reset all state for BTF generation so that we can rerun the compiler within
> +   the same process.  */
> +
> +void
> +btf_finalize (void)
> +{
> +  btf_info_section = NULL;
> +  max_translated_id = 0;
> +
> +  for (size_t i = 0; i < datasecs.length (); i++)
> +    datasecs[i].entries.release ();
> +  datasecs.release ();
> +
> +  funcs = NULL;
> +  func_map->empty ();
> +  func_map = NULL;
> +
> +  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
> +  ctfc_delete_container (tu_ctfc);
> +  tu_ctfc = NULL;
> +}
>   
>   /* Traversal function for all BTF_KIND_FUNC type records.  */
>   
> diff --git a/gcc/ctfc.h b/gcc/ctfc.h
> index cfc805db7b5..90421c72c09 100644
> --- a/gcc/ctfc.h
> +++ b/gcc/ctfc.h
> @@ -162,10 +162,14 @@ struct GTY ((for_user)) ctf_dtdef
>     ctf_id_t dtd_type;	      /* Type identifier for this definition.  */
>     struct ctf_dtdef *ref_type; /* Type referred to by this type (if any).  */
>     ctf_itype_t dtd_data;	      /* Type node.  */
> -  bool from_global_func; /* Whether this type was added from a global
> -			    function.  */
>     uint32_t linkage;           /* Used in function types.  0=local, 1=global.  */
> -  bool dtd_enum_unsigned;     /* Enum signedness.  */
> +
> +  /* Whether this type was added from a global function.  */
> +  BOOL_BITFIELD from_global_func : 1;
> +  /* Enum signedness.  */
> +  BOOL_BITFIELD dtd_enum_unsigned : 1;
> +  /* Lots of spare bits.  */
> +
>     union GTY ((desc ("ctf_dtu_d_union_selector (&%1)")))
>     {
>       /* struct, union, or enum.  */
> @@ -192,6 +196,7 @@ struct GTY ((for_user)) ctf_dvdef
>     uint32_t dvd_name_offset;	/* Offset of the name in str table.  */
>     unsigned int dvd_visibility;	/* External visibility.  0=static,1=global.  */
>     struct ctf_dtdef * dvd_type;	/* Type of variable.  */
> +  ctf_id_t dvd_id;		/* ID of this variable.  Only used for BTF.  */
>   };
>   
>   typedef struct ctf_dvdef ctf_dvdef_t;
> @@ -388,7 +393,7 @@ extern void ctf_output (const char * filename);
>   extern void ctf_finalize (void);
>   
>   extern void btf_early_finish (void);
> -extern void btf_finish (const char * filename);
> +extern void btf_finish (void);
>   extern void btf_finalize (void);
>   
>   extern ctf_container_ref ctf_get_tu_ctfc (void);
> @@ -442,7 +447,9 @@ extern int ctf_add_variable (ctf_container_ref, const char *, ctf_dtdef_ref,
>   			     dw_die_ref, unsigned int, dw_die_ref);
>   
>   extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
> -extern ctf_id_t get_btf_id (ctf_id_t);
> +
> +/* Callback and traversal function for BTF_KIND_FUNC records.  Used by BPF
> +   target for BPF CO-RE implementation.  */
>   
>   typedef bool (*funcs_traverse_callback) (ctf_dtdef_ref, void *);
>   bool traverse_btf_func_types (funcs_traverse_callback, void *);
> diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
> index f16b5ceee74..ac195c1a862 100644
> --- a/gcc/dwarf2ctf.cc
> +++ b/gcc/dwarf2ctf.cc
> @@ -980,13 +980,13 @@ ctf_debug_early_finish (const char * filename)
>   /* Finish CTF/BTF debug info emission.  */
>   
>   void
> -ctf_debug_finish (const char * filename)
> +ctf_debug_finish ()
>   {
>     /* Emit BTF debug info here when CO-RE relocations need to be generated.
>        BTF with CO-RE relocations needs to be generated when CO-RE is in effect
>        for the BPF target.  */
>     if (btf_debuginfo_p ())
> -    btf_finish (filename);
> +    btf_finish ();
>   }
>   
>   #include "gt-dwarf2ctf.h"
> diff --git a/gcc/dwarf2ctf.h b/gcc/dwarf2ctf.h
> index 46184325bae..f8a181a9762 100644
> --- a/gcc/dwarf2ctf.h
> +++ b/gcc/dwarf2ctf.h
> @@ -32,7 +32,7 @@ extern void ctf_debug_init (void);
>   extern void ctf_debug_init_postprocess (bool);
>   extern bool ctf_do_die (dw_die_ref);
>   extern void ctf_debug_early_finish (const char *);
> -extern void ctf_debug_finish (const char *);
> +extern void ctf_debug_finish (void);
>   
>   /* Wrappers for CTF/BTF to fetch information from GCC DWARF DIE.  Used in
>      ctfc.cc.
> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
> index 1664934ccc3..794b94ca80b 100644
> --- a/gcc/dwarf2out.cc
> +++ b/gcc/dwarf2out.cc
> @@ -32276,7 +32276,7 @@ dwarf2out_finish (const char *filename)
>     /* Generate CTF/BTF debug info.  */
>     if ((ctf_debug_info_level > CTFINFO_LEVEL_NONE
>          || btf_debuginfo_p ()) && lang_GNU_C ())
> -    ctf_debug_finish (filename);
> +    ctf_debug_finish ();
>   
>     /* Skip emitting DWARF if not required.  */
>     if (!dwarf_debuginfo_p ())


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 5/6] btf: add -fprune-btf option
  2024-05-02 17:11 ` [PATCH v2 5/6] btf: add -fprune-btf option David Faust
@ 2024-05-03 21:08   ` Indu Bhagat
  0 siblings, 0 replies; 13+ messages in thread
From: Indu Bhagat @ 2024-05-03 21:08 UTC (permalink / raw)
  To: David Faust, gcc-patches; +Cc: jose.marchesi, cupertino.miranda

On 5/2/24 10:11, David Faust wrote:
> This patch adds a new option, -fprune-btf, to control BTF debug info
> generation.
> 
> As the name implies, this option enables a kind of "pruning" of the BTF
> information before it is emitted.  When enabled, rather than emitting
> all type information translated from DWARF, only information for types
> directly used in the source program is emitted.
> 
> The primary purpose of this pruning is to reduce the amount of
> unnecessary BTF information emitted, especially for BPF programs.  It is
> very common for BPF programs to incldue Linux kernel internal headers in
> order to have access to kernel data structures.  However, doing so often
> has the side effect of also adding type definitions for a large number
> of types which are not actually used by nor relevant to the program.
> In these cases, -fprune-btf commonly reduces the size of the resulting
> BTF information by approximately 10x.  This both slims down the size of
> the resulting object and reduces the time required by the BPF loader to
> verify the program and its BTF information.
> 

The 10x reduction is substantial.  Do you think its is worthwhile to 
mention alongside that this data is the average observed for the kernel 
self-tests (I assume it is) ? Just useful info when parsing the commit 
logs, especially when some data is specified...

> Note that the pruning implemented in this patch follows the same rules
> as the BTF pruning performed unconditionally by LLVM's BPF backend when
> generating BTF.  In particular, the main sources of pruning are:
> 
>    1) Only generate BTF for types used by variables and functions at
>       the file scope.
> 

I dont recollect anymore if BTF_KIND_VAR for unused static vars is also 
a correctness issue for BTF.  (With PR debug/113566, we know having 
BTF_KIND_DATASEC entries for optimized away vars is an issue).

It will be great to add some text here or elsewhere for posterity around 
this.

>    2) Avoid emitting full BTF for struct and union types which are only
>       pointed-to by members of other struct/union types.  In these cases,
>       the full BTF_KIND_STRUCT or BTF_KIND_UNION which would normally
>       be emitted is replaced with a BTF_KIND_FWD, as though the
>       underlying type was a forward-declared struct or union type.
> 
> gcc/
> 	* btfout.cc (btf_minimal_types): New hash set.
> 	(struct btf_fixup): New.
> 	(fixups, forwards): New vecs.
> 	(btf_output): Calculate num_types depending on flag_prune_btf.
> 	(btf_early_finsih): New initialization for flag_prune_btf.
> 	(btf_mark_full_type_used): Likewise.
> 	(btf_minimal_add_type): New function.
> 	(btf_minimal_type_list_cb): Likewise.
> 	(btf_late_collect_pruned_types): Likewise.
> 	(btf_late_add_vars): Handle special case for variables in ".maps"
> 	section when generating BTF for BPF CO-RE target.
> 	(btf_late_finish): Use btf_late_collect_pruned_types when
> 	flag_prune_btf in effect.  Move some initialization to btf_early_finish.
> 	(btf_finalize): Additional deallocation for flag_prune_btf.
> 	* common.opt (fprune-btf): New flag.
> 	* ctfc.cc (init_ctf_strtable): Make non-static.
> 	* ctfc.h (struct ctf_dtdef): Add visited_children_p boolean flag.
> 	(init_ctf_strtable, ctfc_delete_strtab): Make extern.
> 	* doc/invoke.texi (Debugging Options): Document -fprune-btf.
> 
> gcc/testsuite/
> 	* gcc.dg/debug/btf/btf-prune-1.c: New test.
> 	* gcc.dg/debug/btf/btf-prune-2.c: Likewise.
> 	* gcc.dg/debug/btf/btf-prune-3.c: Likewise.
> ---
>   gcc/btfout.cc                                | 394 ++++++++++++++++++-
>   gcc/common.opt                               |   4 +
>   gcc/ctfc.cc                                  |   2 +-
>   gcc/ctfc.h                                   |   5 +
>   gcc/doc/invoke.texi                          |  20 +
>   gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c |  25 ++
>   gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c |  33 ++
>   gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c |  35 ++
>   8 files changed, 511 insertions(+), 7 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c
>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c
>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c
> 
> diff --git a/gcc/btfout.cc b/gcc/btfout.cc
> index 0af0bd39fc7..93d56492bbe 100644
> --- a/gcc/btfout.cc
> +++ b/gcc/btfout.cc
> @@ -833,7 +833,10 @@ output_btf_types (ctf_container_ref ctfc)
>   {
>     size_t i;
>     size_t num_types;
> -  num_types = ctfc->ctfc_types->elements ();
> +  if (flag_prune_btf)
> +    num_types = max_translated_id;
> +  else
> +    num_types = ctfc->ctfc_types->elements ();
>   
>     if (num_types)
>       {
> @@ -962,6 +965,211 @@ btf_early_add_func_records (ctf_container_ref ctfc)
>       }
>   }
>   
> +/* The set of types used directly in the source program, and any types manually
> +   marked as used.  This is the set of types which will be emitted when
> +   pruning (-fprune-btf) is enabled.  */

Nit: emitted when flag_prune_btf is set ?

> +static GTY (()) hash_set<ctf_dtdef_ref> *btf_minimal_types;
> +

Curious to know if the choice of "btf_minimal_types" is deliberate over 
say "btf_used_types".  Either is fine, although I see that in the 
comments, we say "used types".  Its a nit really, so feel free to ignore.

> +/* Fixup used to avoid unnecessary pointer chasing for types.  A fixup is
> +   created when a structure or union member is a pointer to another struct
> +   or union type.  In such cases, avoid emitting full type information for
> +   the pointee struct or union type (which may be quite large), unless that
> +   type is used directly elsewhere.  */
> +struct btf_fixup
> +{
> +  ctf_dtdef_ref pointer_dtd; /* Type node to which the fixup is applied.  */
> +  ctf_dtdef_ref pointee_dtd; /* Original type node referred to by pointer_dtd.
> +				If this concrete type is not otherwise used,
> +				then a forward is created.  */
> +};
> +

Is it possible to  guard the creation and usage of fixups behind a 
variable/argument ?  The thinking is that there may be a future use case 
where a consumer wants only the unused types but no further 
"approximation" of converting sou to forwards. It may also be useful for 
debugging / testing for us.

It will be easy to organize the code in that way now, rather than later 
adapting the code.

While I have given the patch one quick look, I need more time to play 
around with this a bit. I am taking some time off next week, but I hope 
to come back to this after that.

> +/* Stores fixups while processing types.  */
> +static vec<struct btf_fixup> fixups;
> +
> +/* For fixups where the underlying type is not used in the end, a BTF_KIND_FWD
> +   is created and emitted.  This vector stores them.  */
> +static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
> +
> +/* Recursively add type DTD and any types it references to the used set.
> +   Return a type that should be used for references to DTD - usually DTD itself,
> +   but may be NULL if DTD corresponds to a type which will not be emitted.
> +   CHECK_PTR is true if one of the predecessors in recursive calls is a struct
> +   or union member.  SEEN_PTR is true if CHECK_PTR is true AND one of the
> +   predecessors was a pointer type.  These two flags are used to avoid chasing
> +   pointers to struct/union only used from pointer members.  For such types, we
> +   will emit a forward instead of the full type information.  */
> +
> +static ctf_dtdef_ref
> +btf_minimal_add_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
> +		      bool check_ptr, bool seen_ptr)
> +{
> +  if (dtd == NULL)
> +    return NULL;
> +
> +  uint32_t ctf_kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
> +  uint32_t kind = get_btf_kind (ctf_kind);
> +
> +  /* Check whether the type has already been added.  */
> +  if (btf_minimal_types->contains (dtd))
> +    {
> +      /* It's possible the type was already added as a fixup, but that we now
> +	 have a concrete use of it.  */
> +      switch (kind)
> +	{
> +	case BTF_KIND_PTR:
> +	case BTF_KIND_TYPEDEF:
> +	case BTF_KIND_CONST:
> +	case BTF_KIND_VOLATILE:
> +	case BTF_KIND_RESTRICT:
> +	  if (check_ptr)
> +	    /* Type was previously added as a fixup, and that's OK.  */
> +	    return dtd;
> +	  else
> +	    {
> +	      /* The type was previously added as a fixup, but now we have
> +		 a concrete use of it.  Remove the fixup.  */
> +	      for (size_t i = 0; i < fixups.length (); i++)
> +		if (fixups[i].pointer_dtd == dtd)
> +		  fixups.unordered_remove (i);
> +
> +	      /* Add the concrete base type.  */
> +	      dtd->ref_type = btf_minimal_add_type (ctfc, dtd->ref_type,
> +						    check_ptr, seen_ptr);
> +	      return dtd;
> +	    }
> +	default:
> +	  return dtd;
> +	}
> +    }
> +
> +  if (ctf_kind == CTF_K_SLICE)
> +    {
> +      /* Bitfield.  Add the underlying type to the used set, but leave
> +	 the reference to the bitfield.  The slice type won't be emitted,
> +	 but we need the information in it when writing out the bitfield
> +	 encoding.  */
> +      btf_minimal_add_type (ctfc, dtd->dtd_u.dtu_slice.cts_type,
> +			    check_ptr, seen_ptr);
> +      return dtd;
> +    }
> +
> +  /* Skip redundant definitions of void and types with no BTF encoding.  */
> +  if ((kind == BTF_KIND_INT && dtd->dtd_data.ctti_size == 0)
> +      || (kind == BTF_KIND_UNKN))
> +    return NULL;
> +
> +  /* Add the type itself, and assign its id.
> +     Do this before recursing to handle things like linked list structures.  */
> +  gcc_assert (ctfc->ctfc_nextid <= BTF_MAX_TYPE);
> +  dtd->dtd_type = ctfc->ctfc_nextid++;
> +  btf_minimal_types->add (dtd);
> +  ctf_add_string (ctfc, dtd->dtd_name, &(dtd->dtd_data.ctti_name), CTF_STRTAB);
> +  ctfc->ctfc_num_types++;
> +  ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
> +
> +  /* Recursively add types referenced by this type.  */
> +  switch (kind)
> +    {
> +    case BTF_KIND_INT:
> +    case BTF_KIND_FLOAT:
> +    case BTF_KIND_FWD:
> +      /* Leaf kinds which do not refer to any other types.  */
> +      break;
> +
> +    case BTF_KIND_FUNC:
> +    case BTF_KIND_VAR:
> +      /* Root kinds; no type we are visiting may refer to these.  */
> +      gcc_unreachable ();
> +
> +    case BTF_KIND_PTR:
> +    case BTF_KIND_TYPEDEF:
> +    case BTF_KIND_CONST:
> +    case BTF_KIND_VOLATILE:
> +    case BTF_KIND_RESTRICT:
> +      {
> +	/* These type kinds refer to exactly one other type.  */
> +	if (check_ptr && !seen_ptr)
> +	  seen_ptr = (kind == BTF_KIND_PTR);
> +
> +	/* Try to avoid chasing pointers to struct/union types if the
> +	   underlying type isn't used.  */
> +	if (check_ptr && seen_ptr)
> +	  {
> +	    ctf_dtdef_ref ref = dtd->ref_type;
> +	    uint32_t ref_kind = btf_dtd_kind (ref);
> +
> +	    if ((ref_kind == BTF_KIND_STRUCT || ref_kind == BTF_KIND_UNION)
> +		&& !btf_minimal_types->contains (ref))
> +	      {
> +		struct btf_fixup fixup;
> +		fixup.pointer_dtd = dtd;
> +		fixup.pointee_dtd = ref;
> +		fixups.safe_push (fixup);
> +		break;
> +	      }
> +	  }
> +
> +	/* Add the type to which this type refers.  */
> +	dtd->ref_type = btf_minimal_add_type (ctfc, dtd->ref_type,
> +					      check_ptr, seen_ptr);
> +	break;
> +      }
> +    case BTF_KIND_ARRAY:
> +      {
> +	/* Add element and index types.  */
> +	ctf_arinfo_t *arr = &(dtd->dtd_u.dtu_arr);
> +	arr->ctr_contents = btf_minimal_add_type (ctfc, arr->ctr_contents,
> +						  false, false);
> +	arr->ctr_index = btf_minimal_add_type (ctfc, arr->ctr_index,
> +					       false, false);
> +	break;
> +      }
> +    case BTF_KIND_STRUCT:
> +    case BTF_KIND_UNION:
> +    case BTF_KIND_ENUM:
> +    case BTF_KIND_ENUM64:
> +      {
> +	/* Add members.  */
> +	ctf_dmdef_t *dmd;
> +	for (dmd = dtd->dtd_u.dtu_members;
> +	     dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
> +	  {
> +	    /* Add member type for struct/union members.  For enums, only the
> +	       enumerator names are needed.  */
> +	    if (kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION)
> +	      dmd->dmd_type = btf_minimal_add_type (ctfc, dmd->dmd_type,
> +						    true, false);
> +	    ctf_add_string (ctfc, dmd->dmd_name, &(dmd->dmd_name_offset),
> +			    CTF_STRTAB);
> +	  }
> +	break;
> +      }
> +    case BTF_KIND_FUNC_PROTO:
> +      {
> +	/* Add return type.  */
> +	dtd->ref_type = btf_minimal_add_type (ctfc, dtd->ref_type,
> +					      false, false);
> +
> +	/* Add arg types.  */
> +	ctf_func_arg_t * farg;
> +	for (farg = dtd->dtd_u.dtu_argv;
> +	     farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
> +	  {
> +	    farg->farg_type = btf_minimal_add_type (ctfc, farg->farg_type,
> +						    false, false);
> +	    /* Note: argument names are stored in the auxilliary string table,
> +	       since CTF does not include arg names.  That table has not been
> +	       cleared, so no need to re-add argument names here.  */
> +	  }
> +	break;
> +      }
> +    default:
> +      return NULL;
> +    }
> +
> +  return dtd;
> +}
> +
>   /* Initial entry point of BTF generation, called at early_finish () after
>      CTF information has possibly been output.  Translate all CTF information
>      to BTF, and do any processing that must be done early, such as creating
> @@ -977,6 +1185,27 @@ btf_early_finish (void)
>   
>     btf_early_add_const_void (tu_ctfc);
>     btf_early_add_func_records (tu_ctfc);
> +
> +  /* Note: from here on, destructive changes are made to the TU CTFC to
> +     translate CTF to BTF.  These fields are reset to count BTF types etc.  */
> +  tu_ctfc->ctfc_num_types = 0;
> +  tu_ctfc->ctfc_num_vlen_bytes = 0;
> +  tu_ctfc->ctfc_vars_list_count = 0;
> +
> +  if (flag_prune_btf)
> +    {
> +      btf_minimal_types
> +	= hash_set<ctf_dtdef_ref>::create_ggc (tu_ctfc->ctfc_types->elements ());
> +      tu_ctfc->ctfc_nextid = 1;
> +      fixups.create (1);
> +
> +      /* Empty the string table, which was already populated with strings for
> +	 all types translated from DWARF.  We may only need a very small subset
> +	 of these strings; those will be re-added below.  */
> +      ctfc_delete_strtab (&tu_ctfc->ctfc_strtable);
> +      init_ctf_strtable (&tu_ctfc->ctfc_strtable);
> +      tu_ctfc->ctfc_strlen++;
> +    }
>   }
>   
>   /* Push a BTF datasec entry ENTRY into the datasec named SECNAME,
> @@ -1134,6 +1363,51 @@ btf_emit_variable_p (ctf_container_ref ctfc, varpool_node *var,
>     return true;
>   }
>   
> +
> +/* Recursively mark T and all children types as used to prevent them
> +   being pruned.  */
> +
> +static void
> +btf_mark_full_type_used (ctf_container_ref ctfc, tree t)
> +{
> +  ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, t);
> +  if (!dtd)
> +    return;
> +
> +  if (dtd->visited_children_p)
> +    return;
> +
> +  btf_minimal_add_type (ctfc, dtd, false, false);
> +  dtd->visited_children_p = true;
> +
> +  /* Note that it is only necessary here to visit descendents which may be
> +     pruned by replacing with a forward, i.e. pointed-to struct/union types.  */
> +  switch (TREE_CODE (t))
> +    {
> +    case POINTER_TYPE:
> +    case REFERENCE_TYPE:
> +      btf_mark_full_type_used (ctfc, TREE_TYPE (t));
> +      break;
> +
> +    case RECORD_TYPE:
> +    case UNION_TYPE:
> +      {
> +	tree member = TYPE_FIELDS (t);
> +	while (member != NULL_TREE)
> +	  {
> +	    if (DECL_ABSTRACT_ORIGIN (member))
> +	      continue;
> +
> +	    btf_mark_full_type_used (ctfc, TREE_TYPE (member));
> +	    member = DECL_CHAIN (member);
> +	  }
> +	break;
> +      }
> +    default:
> +      break;
> +    }
> +}
> +
>   /* Add BTF_KIND_VAR records for variables.  */
>   
>   static void
> @@ -1159,6 +1433,14 @@ btf_late_add_vars (ctf_container_ref ctfc)
>   
>         /* Add a BTF_KIND_DATASEC entry for the variable.  */
>         btf_datasec_add_var (ctfc, var, dvd);
> +
> +      /* Special case: for BPF CO-RE, the .maps section is special.
> +	 Full type info for anything in .maps is always required.  */
> +      const char *section = var->get_section ();
> +      if (section && (strcmp (section, ".maps") == 0)
> +	  && btf_with_core_debuginfo_p () && flag_prune_btf)
> +	btf_mark_full_type_used (ctfc, TREE_TYPE (var->decl));
> +
>       }
>   }
>   
> @@ -1257,6 +1539,88 @@ btf_late_assign_datasec_ids (ctf_container_ref ctfc)
>       }
>   }
>   
> +/* Callback used for assembling the only-used-types list.  Note that this is
> +   the same as btf_type_list_cb above, but the hash_set traverse requires a
> +   different function signature.  */
> +
> +static bool
> +btf_minimal_type_list_cb (const ctf_dtdef_ref& dtd, ctf_container_ref ctfc)
> +{
> +  ctfc->ctfc_types_list[dtd->dtd_type] = dtd;
> +  return true;
> +}
> +
> +/* Collect the set of types reachable from global variables and functions.
> +   This is the minimal set of types, used when generating pruned BTF.  */
> +
> +static void
> +btf_late_collect_pruned_types (ctf_container_ref ctfc)
> +{
> +  vec_alloc (forwards, 1);
> +
> +  /* Add types used from functions.  */
> +  ctf_dtdef_ref dtd;
> +  size_t i;
> +  FOR_EACH_VEC_ELT (*funcs, i, dtd)
> +    {
> +      btf_minimal_add_type (ctfc, dtd->ref_type, false, false);
> +      ctf_add_string (ctfc, dtd->dtd_name, &(dtd->dtd_data.ctti_name),
> +		      CTF_STRTAB);
> +    }
> +
> +  /* Add types used from global variables.  */
> +  for (i = 0; i < ctfc->ctfc_vars_list_count; i++)
> +    {
> +      ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
> +      btf_minimal_add_type (ctfc, dvd->dvd_type, false, false);
> +      ctf_add_string (ctfc, dvd->dvd_name, &(dvd->dvd_name_offset), CTF_STRTAB);
> +    }
> +
> +  /* Process fixups. If the base type was never added, create a forward for it
> +     and adjust the reference to point to that.  If it was added, then nothing
> +     needs to change.  */
> +  for (i = 0; i < fixups.length (); i++)
> +    {
> +      struct btf_fixup *fx = &fixups[i];
> +      if (!btf_minimal_types->contains (fx->pointee_dtd))
> +	{
> +	  /* The underlying type is not used.  Create a forward.  */
> +	  ctf_dtdef_ref fwd = ggc_cleared_alloc<ctf_dtdef_t> ();
> +	  ctf_id_t id = ctfc->ctfc_nextid++;
> +	  gcc_assert (id <= BTF_MAX_TYPE);
> +
> +	  bool union_p = (btf_dtd_kind (fx->pointee_dtd) == BTF_KIND_UNION);
> +
> +	  fwd->dtd_name = fx->pointee_dtd->dtd_name;
> +	  fwd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FORWARD, union_p, 0);
> +	  fwd->dtd_type = id;
> +	  ctfc->ctfc_num_types++;
> +	  ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (fwd);
> +	  ctf_add_string (ctfc, fwd->dtd_name, &(fwd->dtd_data.ctti_name),
> +			  CTF_STRTAB);
> +
> +	  /* Update the pointer to point to the forward.  */
> +	  fx->pointer_dtd->ref_type = fwd;
> +	  vec_safe_push (forwards, fwd);
> +	}
> +    }
> +
> +  /* Construct the resulting pruned type list.  */
> +  ctfc->ctfc_types_list
> +    = ggc_vec_alloc<ctf_dtdef_ref> (btf_minimal_types->elements () + 1
> +				    + vec_safe_length (forwards));
> +
> +  btf_minimal_types->traverse<ctf_container_ref, btf_minimal_type_list_cb>
> +    (ctfc);
> +
> +  /* Insert the newly created forwards into the regular types list too.  */
> +  FOR_EACH_VEC_ELT (*forwards, i, dtd)
> +    ctfc->ctfc_types_list[dtd->dtd_type] = dtd;
> +
> +  max_translated_id = btf_minimal_types->elements ()
> +    + vec_safe_length (forwards);
> +}
> +
>   /* Late entry point for BTF generation, called from dwarf2out_finish ().
>      Complete and emit BTF information.  */
>   
> @@ -1268,13 +1632,22 @@ btf_finish (void)
>   
>     datasecs.create (0);
>   
> -  tu_ctfc->ctfc_num_types = 0;
> -  tu_ctfc->ctfc_num_vlen_bytes = 0;
> -  tu_ctfc->ctfc_vars_list_count = 0;
> -
>     btf_late_add_vars (tu_ctfc);
> -  btf_late_collect_translated_types (tu_ctfc);
> +  if (flag_prune_btf)
> +    {
> +      /* Collect pruned set of BTF types and prepare for emission.
> +	 This includes only types directly used in file-scope variables and
> +	 function return/argument types.  */
> +      btf_late_collect_pruned_types (tu_ctfc);
> +    }
> +  else
> +    {
> +      /* Collect all BTF types and prepare for emission.
> +	 This includes all types translated from DWARF.  */
> +      btf_late_collect_translated_types (tu_ctfc);
> +    }
>     btf_late_add_func_datasec_entries (tu_ctfc);
> +
>     btf_late_assign_var_ids (tu_ctfc);
>     btf_late_assign_func_ids (tu_ctfc);
>     btf_late_assign_datasec_ids (tu_ctfc);
> @@ -1307,6 +1680,15 @@ btf_finalize (void)
>     func_map->empty ();
>     func_map = NULL;
>   
> +  if (flag_prune_btf)
> +    {
> +      btf_minimal_types->empty ();
> +      btf_minimal_types = NULL;
> +
> +      fixups.release ();
> +      forwards = NULL;
> +    }
> +
>     ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
>     ctfc_delete_container (tu_ctfc);
>     tu_ctfc = NULL;
> diff --git a/gcc/common.opt b/gcc/common.opt
> index ad348844775..c430cfd0428 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2578,6 +2578,10 @@ fpatchable-function-entry=
>   Common Var(flag_patchable_function_entry) Joined Optimization
>   Insert NOP instructions at each function entry.
>   
> +fprune-btf
> +Common Var(flag_prune_btf) Init(0)
> +Generate minimal BTF debug info.
> +
>   frandom-seed
>   Common Var(common_deferred_options) Defer
>   
> diff --git a/gcc/ctfc.cc b/gcc/ctfc.cc
> index d8f1037b4e0..7681af8542d 100644
> --- a/gcc/ctfc.cc
> +++ b/gcc/ctfc.cc
> @@ -913,7 +913,7 @@ ctfc_get_dvd_srcloc (ctf_dvdef_ref dvd, ctf_srcloc_ref loc)
>   /* Initialize the CTF string table.
>      The first entry in the CTF string table (empty string) is added.  */
>   
> -static void
> +void
>   init_ctf_strtable (ctf_strtable_t * strtab)
>   {
>     strtab->ctstab_head = NULL;
> diff --git a/gcc/ctfc.h b/gcc/ctfc.h
> index 90421c72c09..bd3d98ffed9 100644
> --- a/gcc/ctfc.h
> +++ b/gcc/ctfc.h
> @@ -168,6 +168,8 @@ struct GTY ((for_user)) ctf_dtdef
>     BOOL_BITFIELD from_global_func : 1;
>     /* Enum signedness.  */
>     BOOL_BITFIELD dtd_enum_unsigned : 1;
> +  /* Already visited children of this type, e.g. struct members.  */
> +  BOOL_BITFIELD visited_children_p : 1;
>     /* Lots of spare bits.  */
>   
>     union GTY ((desc ("ctf_dtu_d_union_selector (&%1)")))
> @@ -369,6 +371,9 @@ extern unsigned int ctfc_get_num_ctf_vars (ctf_container_ref);
>   
>   extern ctf_strtable_t * ctfc_get_strtab (ctf_container_ref, int);
>   
> +extern void init_ctf_strtable (ctf_strtable_t *);
> +extern void ctfc_delete_strtab (ctf_strtable_t *);
> +
>   /* Get the length of the specified string table in the CTF container.  */
>   
>   extern size_t ctfc_get_strtab_len (ctf_container_ref, int);
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 9456ced468a..2908afff7c6 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -533,6 +533,7 @@ Objective-C and Objective-C++ Dialects}.
>   -gvms -gz@r{[}=@var{type}@r{]}
>   -gsplit-dwarf  -gdescribe-dies  -gno-describe-dies
>   -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section
> +-fprune-btf -fno-prune-btf
>   -fno-eliminate-unused-debug-types
>   -femit-struct-debug-baseonly  -femit-struct-debug-reduced
>   -femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]}
> @@ -12234,6 +12235,25 @@ compressed debug sections, the option is rejected.  Otherwise, if the
>   assembler does not support them, @option{-gz} is silently ignored when
>   producing object files.
>   
> +@opindex fprune-btf
> +@opindex fno-prune-btf
> +@item -fprune-btf
> +@itemx -fno-prune-btf
> +Prune BTF information before emission.  When pruning, only type
> +information for types used by global variables and file-scope functions
> +will be emitted.  If compiling for the BPF target with BPF CO-RE
> +enabled, type information will also be emitted for types used in BPF
> +CO-RE relocations.  In addition, struct and union types which are only
> +referred to via pointers from members of other struct or union types
> +shall be pruned and replaced with BTF_KIND_FWD, as though those types
> +were only present in the input as forward declarations.
> +
> +This option substantially reduces the size of produced BTF information,
> +but at significant loss in the amount of detailed type information.
> +It is primarily useful when compiling for the BPF target, to minimize
> +the size of the resulting object, and to eliminate BTF information
> +which is not immediately relevant to the BPF program loading process.
> +
>   @opindex femit-struct-debug-baseonly
>   @item -femit-struct-debug-baseonly
>   Emit debug information for struct-like types
> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c
> new file mode 100644
> index 00000000000..3c9b59a07ec
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-1.c
> @@ -0,0 +1,25 @@
> +/* Simple test of -fprune-btf option operation.
> +   Since 'struct foo' is not used, no BTF shall be emitted for it.  */
> +
> +/* { dg-do compile } */
> +/* { dg-options "-gbtf -fprune-btf -dA" } */
> +
> +/* No BTF info for 'struct foo' nor types used only by it.  */
> +/* { dg-final { scan-assembler-not "BTF_KIND_STRUCT 'foo'" } } */
> +/* { dg-final { scan-assembler-not "BTF_KIND_INT 'char'" } } */
> +
> +/* We should get BTF info for 'struct bar' since it is used.  */
> +/* { dg-final { scan-assembler "BTF_KIND_STRUCT 'bar'"} } */
> +
> +struct foo {
> +  int a;
> +  char c;
> +};
> +
> +struct bar {
> +  int x;
> +  long z[4];
> +};
> +
> +struct bar a_bar;
> +
> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c
> new file mode 100644
> index 00000000000..20183dffcc7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-2.c
> @@ -0,0 +1,33 @@
> +/* Test that -fprune-btf does not chase pointer-to-struct members.  */
> +
> +/* { dg-do compile } */
> +/* { dg-options "-gbtf -fprune-btf -dA" } */
> +
> +/* Only use of B is via a pointer member of C.
> +   Full BTF for B is replaced with a forward.  */
> +/* { dg-final { scan-assembler-not "BTF_KIND_STRUCT 'B'" } } */
> +/* { dg-final { scan-assembler-times "TYPE \[0-9\]+ BTF_KIND_FWD 'B'" 1 } } */
> +
> +/* Detailed info for B is omitted, and A is otherwise unused.  */
> +/* { dg-final { scan-assembler-not "BTF_KIND_\[A-Z\]+ 'A'" } } */
> +
> +/* { dg-final { scan-assembler "BTF_KIND_STRUCT 'C'" } } */
> +
> +struct A;
> +
> +struct B {
> +  int x;
> +  int (*do_A_thing) (int, int);
> +  struct A *other;
> +};
> +
> +struct C {
> +  unsigned int x;
> +  struct B * a;
> +};
> +
> +int
> +foo (struct C *c)
> +{
> +  return c->x;
> +}
> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c
> new file mode 100644
> index 00000000000..57a079cf0b4
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-3.c
> @@ -0,0 +1,35 @@
> +/* Test that -fprune-btf */
> +
> +/* { dg-do compile } */
> +/* { dg-options "-gbtf -fprune-btf -dA" } */
> +
> +/* We expect full BTF information each struct.  */
> +/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_FWD 'file'" } } */
> +/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_STRUCT 'A'" } } */
> +/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_STRUCT 'B'" } } */
> +/* { dg-final { scan-assembler "TYPE \[0-9\]+ BTF_KIND_STRUCT 'C'" } } */
> +
> +struct file;
> +
> +struct A {
> +  void *private;
> +  long (*read)(struct file *, char *, unsigned long);
> +  long (*write)(struct file *, const char *, unsigned long);
> +};
> +
> +struct B {
> +  unsigned int x;
> +  struct A **as;
> +};
> +
> +struct C {
> +  struct A *arr_a[4];
> +  struct A *lone_a;
> +  unsigned int z;
> +};
> +
> +unsigned int
> +foo (struct B *b, struct C *c)
> +{
> +  return b->x + c->z;
> +}


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 6/6] bpf,btf: enable BTF pruning by default for BPF
  2024-05-02 17:11 ` [PATCH v2 6/6] bpf,btf: enable BTF pruning by default for BPF David Faust
@ 2024-05-03 21:12   ` Indu Bhagat
  0 siblings, 0 replies; 13+ messages in thread
From: Indu Bhagat @ 2024-05-03 21:12 UTC (permalink / raw)
  To: David Faust, gcc-patches; +Cc: jose.marchesi, cupertino.miranda

On 5/2/24 10:11, David Faust wrote:
> This patch enables -fprune-btf by default in the BPF backend when
> generating BTF information, and fixes BPF CO-RE generation when using
> -fprune-btf.
> 
> When generating BPF CO-RE information, we must ensure that types used
> in CO-RE relocations always have sufficient BTF information emited so
> that the CO-RE relocations can be processed by a BPF loader.  The BTF
> pruning algorithm on its own does not have sufficient information to
> determine which types are used in a BPF CO-RE relocation, so this
> information must be supplied by the BPF backend, using a new
> btf_mark_type_used function.
> 
> Co-authored-by: Cupertino Miranda <cupertino.miranda@oracle.com>
> 
> gcc/
> 	* btfout.cc (btf_mark_type_used): New.
> 	* ctfc.h (btf_mark_type_used): Declare it here.
> 	* config/bpf/bpf.cc (bpf_option_override): Enable -fprune-btf
> 	by default if -gbtf is enabled.
> 	* config/bpf/bcore-builtins.cc (extra_fn): New typedef.
> 	(compute_field_expr): Add callback parameter, and call it if supplied.
> 	Fix computation for MEM_REF.
> 	(mark_component_type_as_used): New.
> 	(bpf_mark_types_as_used): Likewise.
> 	(bpf_expand_core_builtin): Call here.
> 	* doc/invoke.texi (Debugging Options): Note that -fprune-btf is
> 	enabled by default for BPF target when generating BTF.
> 
> gcc/testsuite/
> 	* gcc.dg/debug/btf/btf-variables-5.c: Add -fno-prune-btf to dg-options.
> ---
>   gcc/btfout.cc                                 | 22 ++++++
>   gcc/config/bpf/bpf.cc                         |  5 ++
>   gcc/config/bpf/core-builtins.cc               | 70 +++++++++++++++++--
>   gcc/ctfc.h                                    |  1 +
>   gcc/doc/invoke.texi                           |  3 +
>   .../gcc.dg/debug/btf/btf-variables-5.c        |  2 +-
>   6 files changed, 96 insertions(+), 7 deletions(-)
> 
> diff --git a/gcc/btfout.cc b/gcc/btfout.cc
> index 93d56492bbe..da2c9d35be9 100644
> --- a/gcc/btfout.cc
> +++ b/gcc/btfout.cc
> @@ -1539,6 +1539,28 @@ btf_late_assign_datasec_ids (ctf_container_ref ctfc)
>       }
>   }
>   
> +
> +/* Manually mark that type T is used to ensure it will not be pruned.
> +   Used by the BPF backend when generating BPF CO-RE to mark types used
> +   in CO-RE relocations.  */
> +
> +void
> +btf_mark_type_used (tree t)
> +{
> +  /* If we are not going to prune anyway, this is a no-op.  */
> +  if (!flag_prune_btf)
> +    return;
> +
> +  gcc_assert (TYPE_P (t));
> +  ctf_container_ref ctfc = ctf_get_tu_ctfc ();
> +  ctf_dtdef_ref dtd = ctf_lookup_tree_type (ctfc, t);
> +
> +  if (!dtd)
> +    return;
> +
> +  btf_minimal_add_type (ctfc, dtd, false, false);
> +}
> +
>   /* Callback used for assembling the only-used-types list.  Note that this is
>      the same as btf_type_list_cb above, but the hash_set traverse requires a
>      different function signature.  */
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index e6ea211a2c6..75303ce8f46 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -221,6 +221,11 @@ bpf_option_override (void)
>         && !(target_flags_explicit & MASK_BPF_CORE))
>       target_flags |= MASK_BPF_CORE;
>   
> +  /* -gbtf implies -fprune-btf for BPF target.  */
> +  if (btf_debuginfo_p ())
> +    SET_OPTION_IF_UNSET (&global_options, &global_options_set,
> +			 flag_prune_btf, true);
> +
>     /* Determine available features from ISA setting (-mcpu=).  */
>     if (bpf_has_jmpext == -1)
>       bpf_has_jmpext = (bpf_isa >= ISA_V2);
> diff --git a/gcc/config/bpf/core-builtins.cc b/gcc/config/bpf/core-builtins.cc
> index d5a7de825ad..1b91b1c0d25 100644
> --- a/gcc/config/bpf/core-builtins.cc
> +++ b/gcc/config/bpf/core-builtins.cc
> @@ -624,13 +624,20 @@ bpf_core_get_index (const tree node, bool *valid)
>   
>      ALLOW_ENTRY_CAST is an input arguments and specifies if the function should
>      consider as valid expressions in which NODE entry is a cast expression (or
> -   tree code nop_expr).  */
> +   tree code nop_expr).
> +
> +   EXTRA_FN is a callback function to allow extra functionality with this
> +   function traversal. Currently used for marking used type during expand
> +   pass.  */
> +
> +typedef void (*extra_fn) (tree);
>   
>   static unsigned char
>   compute_field_expr (tree node, unsigned int *accessors,
>   		    bool *valid,
>   		    tree *access_node,
> -		    bool allow_entry_cast = true)
> +		    bool allow_entry_cast = true,
> +		    extra_fn callback = NULL)
>   {
>     unsigned char n = 0;
>     unsigned int fake_accessors[MAX_NR_ACCESSORS];
> @@ -647,6 +654,9 @@ compute_field_expr (tree node, unsigned int *accessors,
>   
>     *access_node = node;
>   
> +  if (callback != NULL)
> +    callback (node);
> +
>     switch (TREE_CODE (node))
>       {
>       case INDIRECT_REF:
> @@ -664,17 +674,19 @@ compute_field_expr (tree node, unsigned int *accessors,
>       case COMPONENT_REF:
>         n = compute_field_expr (TREE_OPERAND (node, 0), accessors,
>   			      valid,
> -			      access_node, false);
> +			      access_node, false, callback);
>         accessors[n] = bpf_core_get_index (TREE_OPERAND (node, 1), valid);
>         return n + 1;
>       case ARRAY_REF:
>       case ARRAY_RANGE_REF:
> -    case MEM_REF:
>         n = compute_field_expr (TREE_OPERAND (node, 0), accessors,
>   			      valid,
> -			      access_node, false);
> +			      access_node, false, callback);
>         accessors[n++] = bpf_core_get_index (node, valid);
>         return n;
> +    case MEM_REF:
> +      accessors[0] = bpf_core_get_index (node, valid);
> +      return 1;
>       case NOP_EXPR:
>         if (allow_entry_cast == true)
>   	{
> @@ -683,7 +695,7 @@ compute_field_expr (tree node, unsigned int *accessors,
>   	}
>         n = compute_field_expr (TREE_OPERAND (node, 0), accessors,
>   			      valid,
> -			      access_node, false);
> +			      access_node, false, callback);
>         return n;
>   
>       case ADDR_EXPR:
> @@ -1549,6 +1561,50 @@ bpf_resolve_overloaded_core_builtin (location_t loc, tree fndecl,
>     return construct_builtin_core_reloc (loc, fndecl, args, argsvec->length ());
>   }
>   
> +/* Callback function for bpf_mark_field_expr_types_as_used.  */
> +
> +static void
> +mark_component_type_as_used (tree node)
> +{
> +  if (TREE_CODE (node) == COMPONENT_REF)
> +    btf_mark_type_used (TREE_TYPE (TREE_OPERAND (node, 0)));
> +}
> +
> +/* Find and mark used struct/union types for BTF pruning.  */

How about something to the likes of:

/* Mark types in BPF relocations as used.  Doing so ensures these type 
do not get pruned.  */

> +
> +static void
> +bpf_mark_types_as_used (struct cr_builtins *data)
> +{
> +  tree expr = data->expr;
> +  switch (data->kind)
> +    {
> +    case BPF_RELO_FIELD_BYTE_OFFSET:
> +    case BPF_RELO_FIELD_BYTE_SIZE:
> +    case BPF_RELO_FIELD_EXISTS:
> +    case BPF_RELO_FIELD_SIGNED:
> +    case BPF_RELO_FIELD_LSHIFT_U64:
> +    case BPF_RELO_FIELD_RSHIFT_U64:
> +      if (TREE_CODE (expr) == ADDR_EXPR)
> +	expr = TREE_OPERAND (expr, 0);
> +
> +      expr = root_for_core_field_info (expr);
> +      compute_field_expr (data->expr, NULL, NULL, NULL, false,
> +			  mark_component_type_as_used);
> +      break;
> +    case BPF_RELO_TYPE_ID_LOCAL:
> +    case BPF_RELO_TYPE_ID_TARGET:
> +    case BPF_RELO_TYPE_EXISTS:
> +    case BPF_RELO_TYPE_SIZE:
> +    case BPF_RELO_ENUMVAL_EXISTS:
> +    case BPF_RELO_ENUMVAL_VALUE:
> +    case BPF_RELO_TYPE_MATCHES:
> +      btf_mark_type_used (data->type);
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +

I am wondering if there are tests for checking the BTF generated for BPF 
programs using co-re relocs.  Do you think we need to add more now that 
we have a specific method to keep it the expected behavior tested ?

>   /* Used in bpf_expand_builtin.  This function is called in RTL expand stage to
>      convert the internal __builtin_core_reloc in unspec:UNSPEC_CORE_RELOC RTL,
>      which will contain a third argument that is the index in the vec collected
> @@ -1567,6 +1623,8 @@ bpf_expand_core_builtin (tree exp, enum bpf_builtins code)
>   	tree index = CALL_EXPR_ARG (exp, 0);
>   	struct cr_builtins *data = get_builtin_data (TREE_INT_CST_LOW (index));
>   
> +	bpf_mark_types_as_used (data);
> +
>   	rtx v = expand_normal (data->default_value);
>   	rtx i = expand_normal (index);
>   	  return gen_rtx_UNSPEC (DImode,
> diff --git a/gcc/ctfc.h b/gcc/ctfc.h
> index bd3d98ffed9..99873a0b15c 100644
> --- a/gcc/ctfc.h
> +++ b/gcc/ctfc.h
> @@ -458,6 +458,7 @@ extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
>   
>   typedef bool (*funcs_traverse_callback) (ctf_dtdef_ref, void *);
>   bool traverse_btf_func_types (funcs_traverse_callback, void *);
> +extern void btf_mark_type_used (tree);
>   
>   /* CTF section does not emit location information; at this time, location
>      information is needed for BTF CO-RE use-cases.  */
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 2908afff7c6..f8778cdf7cc 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -12254,6 +12254,9 @@ It is primarily useful when compiling for the BPF target, to minimize
>   the size of the resulting object, and to eliminate BTF information
>   which is not immediately relevant to the BPF program loading process.
>   
> +This option is enabled by default for the BPF target when generating
> +BTF information.
> +
>   @opindex femit-struct-debug-baseonly
>   @item -femit-struct-debug-baseonly
>   Emit debug information for struct-like types
> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c b/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c
> index 8aae76cacab..c146b90abf9 100644
> --- a/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c
> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-variables-5.c
> @@ -5,7 +5,7 @@
>      with 'global' linkage. However two array types will be generated.  */
>   
>   /* { dg-do compile } */
> -/* { dg-options "-O0 -gbtf -dA" } */
> +/* { dg-options "-O0 -gbtf -dA -fno-prune-btf" } */
>   

But the test will pass on non-BPF targets without this additional option 
of -fno-prune-btf.

So is it more clear to rather add two different checks (which I think 
will be like):

/* { dg-final { scan-assembler-times "\[\t \]0\[\t 
\]+\[^\n\]*bta_nelems" 1 { target { ! bpf-*-* } } } } */
/* { dg-final { scan-assembler-times "\[\t \]0\[\t 
\]+\[^\n\]*bta_nelems" 0 { target { bpf-*-* } } } } */

What do you think ? If you end up picking this suggestion, a comment in 
the testcase around -fprune-btf being default for BPF will also be good 
to have.

>   /* Expect 1 variable with global (1) linkage.  */
>   /* { dg-final { scan-assembler-times "\[\t \]0xe000000\[\t \]+\[^\n\]*btv_info" 1 } } */


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission
  2024-05-03 21:02   ` Indu Bhagat
@ 2024-05-06 17:48     ` David Faust
  0 siblings, 0 replies; 13+ messages in thread
From: David Faust @ 2024-05-06 17:48 UTC (permalink / raw)
  To: Indu Bhagat; +Cc: gcc-patches, jose.marchesi, cupertino.miranda



On 5/3/24 2:02 PM, Indu Bhagat wrote:
> On 5/2/24 10:11, David Faust wrote:
>> This commit makes some structural changes to the CTF/BTF debug info
>> emission.  In particular:
>>
>>   a) CTF is new always fully generated and emitted before any
>>      BTF-related procedures are run.  This means that BTF-related
>>      functions can change, even irreversibly, the shared in-memory
>>      representation used by the two formats without issue.
>>
>>   b) BTF generation has fewer entry points, and is cleanly divided
>>      into early_finish and finish.
>>
>>   c) BTF is now always emitted at finish (called from dwarf2out_finish),
>>      rather than being emitted at early_finish for targets other than
>>      BPF CO-RE.  Note that this change alone does not alter the contents
>>      of BTF at all, regardless of whether it would have previously been
>>      emitted at early_finish or finish.
>>
> 
> This will necessitate that we disallow -gbtf with -flto for non-BPF 
> targets.  Emitting BTF always at dwarf2out_finish will not work with LTO.

Yes, you're right.  I was not thinking about LTO when I wrote this.

I suppose the obvious fix is to undo "c)" above.  That change is not
really strictly necessary for the rest of the refactor in this series,
though we would lose the fix for PR debug/113566 in patch 4, since
fixing that requires us to generate some of the BTF at late finish time.
 Then BTF emission would be the same as it is currently:

BTF for BPF target, non-LTO    -> (late) finish
BTF for BPF target, LTO        -> forbidden by BPF back-end
BTF for non-BPF target         -> early_finish

Alternatively, we could undo "c)" only for LTO builds, i.e.:

BTF for BPF target  non-LTO    -> (late) finish
BTF for BPF target, LTO        -> forbidden by BPF back-end
BTF for other targets, non-LTO -> (late) finish
BTF for other targets, LTO     -> early_finish

which would allow fixing debug/113566 for non-LTO builds.  Then the
differences in BTF related to debug/113566 should only appear between
LTO and non-LTO builds, rather than between BPF and non-BPF targets.

IMO the latter (move emission back to early_finish for LTO builds) is a
little better.

Either way, I think the majority of code related to BTF generation from
later in this series should not need to change much if at all - only
whether those routines end up called at early or late finish.

> 
>> The changes are transparent to both CTF and BTF emission.
>>
>> gcc/
>> 	* btfout.cc (btf_init_postprocess): Rename to...
>> 	(btf_early_finish): ...this.
>> 	(btf_output): Rename to...
>> 	(btf_finish): ...this.
>> 	* ctfc.h: Analogous changes.
>> 	* dwarf2ctf.cc (ctf_debug_early_finish): Conditionally call
>> 	btf_early_finish or ctf_finalize as appropriate.
>> 	(ctf_debug_finish): Always call btf_finish here if generating
>> 	BTF info.
>> 	(ctf_debug_finalize, ctf_debug_init_postprocess): Delete.
>> 	* dwarf2out.cc (dwarf2out_early_finish): Remove call to
>> 	ctf_debug_init_postprocess.
>> ---
>>   gcc/btfout.cc    | 28 +++++++++++++++++++++++++
>>   gcc/ctfc.h       |  4 ++--
>>   gcc/dwarf2ctf.cc | 54 +++++++++++-------------------------------------
>>   gcc/dwarf2out.cc |  2 --
>>   4 files changed, 42 insertions(+), 46 deletions(-)
>>
>> diff --git a/gcc/btfout.cc b/gcc/btfout.cc
>> index 07f066a4706..1b6a9ed811f 100644
>> --- a/gcc/btfout.cc
>> +++ b/gcc/btfout.cc
>> @@ -1491,6 +1491,34 @@ btf_finalize (void)
>>     tu_ctfc = NULL;
>>   }
>>   
>> +/* Initial entry point of BTF generation, called at early_finish () after
>> +   CTF information has possibly been output.  Translate all CTF information
>> +   to BTF, and do any processing that must be done early, such as creating
>> +   BTF_KIND_FUNC records.  */
>> +
>> +void
>> +btf_early_finish (void)
>> +{
>> +  btf_init_postprocess ();
>> +}
>> +
>> +/* Late entry point for BTF generation, called from dwarf2out_finish ().
>> +   Complete and emit BTF information.  */
>> +
>> +void
>> +btf_finish (const char * filename)
>> +{
>> +  btf_output (filename);
>> +
>> +  /* If compiling for BPF with CO-RE info, we cannot deallocate until after
>> +     CO-RE information is created, which happens very late in BPF backend.
>> +     Therefore, the deallocation (i.e. btf_finalize ()) is delayed until
>> +     TARGET_ASM_FILE_END for BPF CO-RE.  */
>> +  if (!btf_with_core_debuginfo_p ())
>> +    btf_finalize ();
>> +}
>> +
>> +
>>   /* Traversal function for all BTF_KIND_FUNC type records.  */
>>   
>>   bool
>> diff --git a/gcc/ctfc.h b/gcc/ctfc.h
>> index fa188bf2f5a..e7bd93901cf 100644
>> --- a/gcc/ctfc.h
>> +++ b/gcc/ctfc.h
>> @@ -384,8 +384,8 @@ extern void ctf_init (void);
>>   extern void ctf_output (const char * filename);
>>   extern void ctf_finalize (void);
>>   
>> -extern void btf_output (const char * filename);
>> -extern void btf_init_postprocess (void);
>> +extern void btf_early_finish (void);
>> +extern void btf_finish (const char * filename);
>>   extern void btf_finalize (void);
>>   
>>   extern ctf_container_ref ctf_get_tu_ctfc (void);
>> diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
>> index dc59569fe56..ec94982e4b1 100644
>> --- a/gcc/dwarf2ctf.cc
>> +++ b/gcc/dwarf2ctf.cc
>> @@ -933,30 +933,6 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
>>     return type_id;
>>   }
>>   
>> -/* Prepare for output and write out the CTF debug information.  */
>> -
>> -static void
>> -ctf_debug_finalize (const char *filename, bool btf)
>> -{
>> -  if (btf)
>> -    {
>> -      btf_output (filename);
>> -      /* btf_finalize when compiling BPF applciations gets deallocated by the
>> -	 BPF target in bpf_file_end.  */
>> -      if (btf_debuginfo_p () && !btf_with_core_debuginfo_p ())
>> -	btf_finalize ();
>> -    }
>> -
>> -  else
>> -    {
>> -      /* Emit the collected CTF information.  */
>> -      ctf_output (filename);
>> -
>> -      /* Reset the CTF state.  */
>> -      ctf_finalize ();
>> -    }
>> -}
>> -
>>   bool
>>   ctf_do_die (dw_die_ref die)
>>   {
>> @@ -996,27 +972,21 @@ ctf_debug_init (void)
>>     add_name_attribute (ctf_unknown_die, "unknown");
>>   }
>>   
>> -/* Preprocess the CTF debug information after initialization.  */
>> -
>> -void
>> -ctf_debug_init_postprocess (bool btf)
>> -{
>> -  /* Only BTF requires postprocessing right after init.  */
>> -  if (btf)
>> -    btf_init_postprocess ();
>> -}
>> -
>>   /* Early finish CTF/BTF debug info.  */
>>   
>>   void
>>   ctf_debug_early_finish (const char * filename)
>>   {
>> -  /* Emit CTF debug info early always.  */
>> -  if (ctf_debug_info_level > CTFINFO_LEVEL_NONE
>> -      /* Emit BTF debug info early if CO-RE relocations are not
>> -	 required.  */
>> -      || (btf_debuginfo_p () && !btf_with_core_debuginfo_p ()))
>> -    ctf_debug_finalize (filename, btf_debuginfo_p ());
>> +  /* Emit the collected CTF information.  */
>> +  if (ctf_debug_info_level > CTFINFO_LEVEL_NONE)
>> +    ctf_output (filename);
>> +
>> +  if (btf_debuginfo_p ())
>> +    /* If BTF will also be emitted, start translation to BTF.  */
>> +    btf_early_finish ();
>> +  else
>> +    /* Otherwise, done with the CTF container.  */
>> +    ctf_finalize ();
>>   }
>>   
>>   /* Finish CTF/BTF debug info emission.  */
>> @@ -1027,8 +997,8 @@ ctf_debug_finish (const char * filename)
>>     /* Emit BTF debug info here when CO-RE relocations need to be generated.
>>        BTF with CO-RE relocations needs to be generated when CO-RE is in effect
>>        for the BPF target.  */
>> -  if (btf_debuginfo_p () && btf_with_core_debuginfo_p ())
>> -    ctf_debug_finalize (filename, btf_debuginfo_p ());
>> +  if (btf_debuginfo_p ())
>> +    btf_finish (filename);
>>   }
>>   
>>   #include "gt-dwarf2ctf.h"
>> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
>> index 1b0e8b5a5b2..1664934ccc3 100644
>> --- a/gcc/dwarf2out.cc
>> +++ b/gcc/dwarf2out.cc
>> @@ -33168,8 +33168,6 @@ dwarf2out_early_finish (const char *filename)
>>         ctf_debug_do_cu (comp_unit_die ());
>>         for (limbo_die_node *node = limbo_die_list; node; node = node->next)
>>   	ctf_debug_do_cu (node->die);
>> -      /* Post process the debug data in the CTF container if necessary.  */
>> -      ctf_debug_init_postprocess (btf_debuginfo_p ());
>>   
>>         ctf_debug_early_finish (filename);
>>       }
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-05-06 17:45 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-02 17:11 [PATCH v2 0/6] btf: refactor and add pruning option David Faust
2024-05-02 17:11 ` [PATCH v2 1/6] ctf, btf: restructure CTF/BTF emission David Faust
2024-05-03 21:02   ` Indu Bhagat
2024-05-06 17:48     ` David Faust
2024-05-02 17:11 ` [PATCH v2 2/6] opts: allow any combination of DWARF, CTF, BTF David Faust
2024-05-02 17:11 ` [PATCH v2 3/6] ctf: use pointers instead of IDs internally David Faust
2024-05-03 21:04   ` Indu Bhagat
2024-05-02 17:11 ` [PATCH v2 4/6] btf: refactor and simplify implementation David Faust
2024-05-03 21:06   ` Indu Bhagat
2024-05-02 17:11 ` [PATCH v2 5/6] btf: add -fprune-btf option David Faust
2024-05-03 21:08   ` Indu Bhagat
2024-05-02 17:11 ` [PATCH v2 6/6] bpf,btf: enable BTF pruning by default for BPF David Faust
2024-05-03 21:12   ` Indu Bhagat

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).