CTF/BTF debug formats
authorIndu Bhagat <indu.bhagat@oracle.com>
Thu, 20 May 2021 18:15:52 +0000 (11:15 -0700)
committerJose E. Marchesi <jose.marchesi@oracle.com>
Mon, 28 Jun 2021 16:47:20 +0000 (18:47 +0200)
This commit introduces support for generating CTF debugging
information and BTF debugging information from GCC.

2021-06-28  Indu Bhagat  <indu.bhagat@oracle.com>
    David Faust  <david.faust@oracle.com>
    Jose E. Marchesi  <jose.marchesi@oracle.com>
    Weimin Pan  <weimin.pan@oracle.com>

gcc/

* Makefile.in: Add ctfc.*, ctfout.c and btfout.c files to
GTFILES.  Add new object files.
* common.opt: Add CTF and BTF debug info options.
* btfout.c: New file.
* ctfc.c: Likewise.
* ctfc.h: Likewise.
* ctfout.c: Likewise.
* dwarf2ctf.c: Likewise.
* dwarf2ctf.h: Likewise.
* dwarf2cfi.c (dwarf2out_do_frame): Acknowledge CTF_DEBUG and
BTF_DEBUG.
* dwarf2out.c (dwarf2out_source_line): Likewise.
(dwarf2out_finish): Skip emitting DWARF if CTF or BTF are to
be generated.
(debug_format_do_cu): New function.
(dwarf2out_early_finish): Traverse DIEs and emit CTF/BTF for
them if requested.
Include dwarf2ctf.c.
* final.c (dwarf2_debug_info_emitted_p): Acknowledge DWARF-based debug
formats.
* flag-types.h (enum debug_info_type): Add CTF_DEBUG and BTF_DEBUG.
(CTF_DEBUG): New bitmask.
(BTF_DEBUG): Likewise.
(enum ctf_debug_info_levels): New enum.
* gengtype.c (open_base_files): Handle ctfc.h.
(main): Handle uint32_t type.
* flags.h (btf_debuginfo_p): New definition.
(dwarf_based_debuginfo_p): Likewise.
* opts.c (debug_type_names): Add entries for CTF and BTF.
(btf_debuginfo_p): New function.
(dwarf_based_debuginfo_p): Likewise.
(common_handle_option): Handle -gctfN and -gbtf options.
(set_debug_level): Set CTF_DEBUG, BTF_DEBUG whenever appropriate.
* toplev.c (process_options): Inform the user and ignore -gctfLEVEL if
frontend is not C.

include/

* ctf.h: New file.
* btf.h: Likewise.

libiberty/

* simple-object.c (handle_lto_debug_sections): Copy over .ctf
sections.

19 files changed:
gcc/Makefile.in
gcc/btfout.c [new file with mode: 0644]
gcc/common.opt
gcc/ctfc.c [new file with mode: 0644]
gcc/ctfc.h [new file with mode: 0644]
gcc/ctfout.c [new file with mode: 0644]
gcc/dwarf2cfi.c
gcc/dwarf2ctf.c [new file with mode: 0644]
gcc/dwarf2ctf.h [new file with mode: 0644]
gcc/dwarf2out.c
gcc/final.c
gcc/flag-types.h
gcc/flags.h
gcc/gengtype.c
gcc/opts.c
gcc/toplev.c
include/btf.h [new file with mode: 0644]
include/ctf.h [new file with mode: 0644]
libiberty/simple-object.c

index 3d8c2b9..934b2a0 100644 (file)
@@ -1319,6 +1319,9 @@ OBJS = \
        cfgloopanal.o \
        cfgloopmanip.o \
        cfgrtl.o \
+       ctfc.o \
+       ctfout.o \
+       btfout.o \
        symtab.o \
        symtab-thunks.o \
        symtab-clones.o \
@@ -1359,6 +1362,7 @@ OBJS = \
        dumpfile.o \
        dwarf2asm.o \
        dwarf2cfi.o \
+       dwarf2ctf.o \
        dwarf2out.o \
        early-remat.o \
        emit-rtl.o \
@@ -2655,7 +2659,11 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/dwarf2out.h \
   $(srcdir)/dwarf2asm.c \
   $(srcdir)/dwarf2cfi.c \
+  $(srcdir)/dwarf2ctf.c \
   $(srcdir)/dwarf2out.c \
+  $(srcdir)/ctfc.h \
+  $(srcdir)/ctfout.c \
+  $(srcdir)/btfout.c \
   $(srcdir)/tree-vect-generic.c \
   $(srcdir)/gimple-isel.cc \
   $(srcdir)/dojump.c $(srcdir)/emit-rtl.h \
diff --git a/gcc/btfout.c b/gcc/btfout.c
new file mode 100644 (file)
index 0000000..45954b4
--- /dev/null
@@ -0,0 +1,1129 @@
+/* Output BTF format from GCC.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This file contains routines to output the BPF Type Format (BTF). The BTF
+   debug format is very similar to CTF; as a result, the structure of this file
+   closely resembles that of ctfout.c, and the same CTF container objects are
+   used.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "output.h"
+#include "dwarf2asm.h"
+#include "debug.h"
+#include "ctfc.h"
+#include "diagnostic-core.h"
+#include "cgraph.h"
+#include "varasm.h"
+#include "dwarf2out.h" /* For lookup_decl_die.  */
+
+static int btf_label_num;
+
+static GTY (()) section * btf_info_section;
+
+/* BTF debug info section.  */
+
+#ifndef BTF_INFO_SECTION_NAME
+#define BTF_INFO_SECTION_NAME  ".BTF"
+#endif
+
+#define BTF_INFO_SECTION_FLAGS (SECTION_DEBUG)
+
+/* Maximum size (in bytes) for an artifically generated BTF label.  */
+
+#define MAX_BTF_LABEL_BYTES 40
+
+static char btf_info_section_label[MAX_BTF_LABEL_BYTES];
+
+#ifndef BTF_INFO_SECTION_LABEL
+#define BTF_INFO_SECTION_LABEL  "Lbtf"
+#endif
+
+/* BTF encodes void as type id 0.  */
+
+#define BTF_VOID_TYPEID 0
+#define BTF_INIT_TYPEID 1
+
+#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 hash_map <ctf_dvdef_ref, unsigned int> *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.  */
+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.  */
+} 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;
+
+/* The number of types synthesized for BTF that do not correspond to
+   CTF types.  */
+static unsigned int num_types_created = 0;
+
+/* Map a CTF type kind to the corresponding BTF type kind.  */
+
+static uint32_t
+get_btf_kind (uint32_t ctf_kind)
+{
+  /* N.B. the values encoding kinds are not in general the same for the
+     same kind between CTF and BTF. e.g. CTF_K_CONST != BTF_KIND_CONST.  */
+  switch (ctf_kind)
+    {
+    case CTF_K_INTEGER:  return BTF_KIND_INT;
+    case CTF_K_POINTER:  return BTF_KIND_PTR;
+    case CTF_K_ARRAY:    return BTF_KIND_ARRAY;
+    case CTF_K_FUNCTION: return BTF_KIND_FUNC_PROTO;
+    case CTF_K_STRUCT:   return BTF_KIND_STRUCT;
+    case CTF_K_UNION:    return BTF_KIND_UNION;
+    case CTF_K_ENUM:     return BTF_KIND_ENUM;
+    case CTF_K_FORWARD:  return BTF_KIND_FWD;
+    case CTF_K_TYPEDEF:  return BTF_KIND_TYPEDEF;
+    case CTF_K_VOLATILE: return BTF_KIND_VOLATILE;
+    case CTF_K_CONST:    return BTF_KIND_CONST;
+    case CTF_K_RESTRICT: return BTF_KIND_RESTRICT;
+    default:;
+    }
+  return BTF_KIND_UNKN;
+}
+
+/* Allocate the btf_id_map, and initialize elements to BTF_INVALID_TYPEID.  */
+
+static void
+init_btf_id_map (size_t len)
+{
+  btf_id_map = XNEWVEC (ctf_id_t, len);
+
+  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.  */
+
+static inline 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));
+}
+
+/* Each BTF type can be followed additional, variable-length information
+   completing the description of the type. Calculate the number of bytes
+   of variable information required to encode a given type.  */
+
+static uint64_t
+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 vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
+
+  switch (kind)
+    {
+    case BTF_KIND_UNKN:
+    case BTF_KIND_PTR:
+    case BTF_KIND_FWD:
+    case BTF_KIND_TYPEDEF:
+    case BTF_KIND_VOLATILE:
+    case BTF_KIND_CONST:
+    case BTF_KIND_RESTRICT:
+    case BTF_KIND_FUNC:
+    /* These kinds have no vlen data.  */
+      break;
+
+    case BTF_KIND_INT:
+      /* Size 0 integers represent redundant definitions of void that will
+        not be emitted. Don't allocate space for them.  */
+      if (dtd->dtd_data.ctti_size == 0)
+       break;
+
+      vlen_bytes += sizeof (uint32_t);
+      break;
+
+    case BTF_KIND_ARRAY:
+      vlen_bytes += sizeof (struct btf_array);
+      break;
+
+    case BTF_KIND_STRUCT:
+    case BTF_KIND_UNION:
+      vlen_bytes += vlen * sizeof (struct btf_member);
+      break;
+
+    case BTF_KIND_ENUM:
+      vlen_bytes += vlen * sizeof (struct btf_enum);
+      break;
+
+    case BTF_KIND_FUNC_PROTO:
+      vlen_bytes += vlen * sizeof (struct btf_param);
+      break;
+
+    case BTF_KIND_VAR:
+      vlen_bytes += sizeof (struct btf_var);
+      break;
+
+    case BTF_KIND_DATASEC:
+      vlen_bytes += vlen * sizeof (struct btf_var_secinfo);
+      break;
+
+    default:
+      break;
+    }
+  return vlen_bytes;
+}
+
+/* Initialize BTF section (.BTF) for output.  */
+
+void
+init_btf_sections (void)
+{
+  btf_info_section = get_section (BTF_INFO_SECTION_NAME, BTF_INFO_SECTION_FLAGS,
+                                 NULL);
+
+  ASM_GENERATE_INTERNAL_LABEL (btf_info_section_label,
+                              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);
+  num_types_created++;
+}
+
+/* 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)
+{
+  /* See cgraph.h struct symtab_node, which varpool_node extends.  */
+  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;
+
+      const char *section_name = node->get_section ();
+
+      if (section_name == NULL)
+       {
+         switch (categorize_decl_for_section (node->decl, 0))
+           {
+           case SECCAT_BSS:
+             section_name = ".bss";
+             break;
+           case SECCAT_DATA:
+             section_name = ".data";
+             break;
+           case SECCAT_RODATA:
+             section_name = ".rodata";
+             break;
+           default:
+             continue;
+           }
+       }
+
+      struct btf_var_secinfo info;
+
+      info.type = 0;
+      unsigned int *var_id = btf_var_ids->get (dvd);
+      if (var_id)
+       /* +1 for the sentinel type not in the types map.  */
+       info.type = *var_id + num_types_added + 1;
+      else
+       continue;
+
+      info.size = 0;
+      tree size = DECL_SIZE_UNIT (node->decl);
+      if (tree_fits_uhwi_p (size))
+       info.size = tree_to_uhwi (size);
+
+      /* 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);
+    }
+}
+
+/* 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;
+
+  /* Do not add variables which refer to unsupported types.  */
+  if (btf_removed_type_p (var->dvd_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;
+
+  uint32_t btf_kind
+    = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
+
+  if (btf_kind == BTF_KIND_FUNC_PROTO)
+    {
+      /* 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;
+
+      vec_safe_push (funcs, func_dtd);
+      num_types_created++;
+
+      /* Only the BTF_KIND_FUNC type actually references the name. The
+        BTF_KIND_FUNC_PROTO is always anonymous.  */
+      dtd->dtd_data.ctti_name = 0;
+    }
+
+  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)
+{
+  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type];
+
+  if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
+    {
+      unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset;
+      unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits;
+      uint64_t sou_offset = dmd->dmd_offset;
+
+      if ((bits > 0xff) || ((sou_offset + word_offset) > 0xffffff))
+       return false;
+
+      return true;
+    }
+
+  return false;
+}
+
+/* BTF asm helper routines.  */
+
+/* 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)
+{
+  uint32_t btf_kind, btf_kflag, btf_vlen, btf_size_type;
+  uint32_t ctf_info = dtd->dtd_data.ctti_info;
+
+  btf_kind = get_btf_kind (CTF_V2_INFO_KIND (ctf_info));
+  btf_size_type = dtd->dtd_data.ctti_type;
+  btf_vlen = CTF_V2_INFO_VLEN (ctf_info);
+
+  /* By now any unrepresentable types have been removed.  */
+  gcc_assert (btf_kind != BTF_KIND_UNKN);
+
+  /* Size 0 integers are redundant definitions of void. None should remain
+     in the types list by this point.  */
+  gcc_assert (btf_kind != BTF_KIND_INT || btf_size_type >= 1);
+
+  /* Re-encode the ctti_info to BTF.  */
+  /* kflag is 1 for structs/unions with a bitfield member.
+     kflag is 1 for forwards to unions.
+     kflag is 0 in all other cases.  */
+  btf_kflag = 0;
+
+  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.  */
+      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;
+
+         /* Struct members that refer to unsupported types or bitfield formats
+            shall be skipped. These are marked during preprocessing.  */
+         else if (!btf_emit_id_p (dmd->dmd_type))
+           btf_vlen -= 1;
+       }
+    }
+
+  /* BTF forwards make use of KIND_FLAG to distinguish between forwards to
+     structs and forwards to unions. The dwarf2ctf conversion process stores
+     the kind of the forward in ctti_type, but for BTF this must be 0 for
+     forwards, with only the KIND_FLAG to distinguish.
+     At time of writing, BTF forwards to enums are unspecified.  */
+  if (btf_kind == BTF_KIND_FWD)
+    {
+      if (dtd->dtd_data.ctti_type == CTF_K_UNION)
+       btf_kflag = 1;
+
+      btf_size_type = 0;
+    }
+
+  dw2_asm_output_data (4, dtd->dtd_data.ctti_name, "btt_name");
+  dw2_asm_output_data (4, BTF_TYPE_INFO (btf_kind, btf_kflag, btf_vlen),
+                      "btt_info: kind=%u, kflag=%u, vlen=%u",
+                      btf_kind, btf_kflag, btf_vlen);
+  switch (btf_kind)
+    {
+    case BTF_KIND_INT:
+    case BTF_KIND_STRUCT:
+    case BTF_KIND_UNION:
+    case BTF_KIND_ENUM:
+    case BTF_KIND_DATASEC:
+      dw2_asm_output_data (4, dtd->dtd_data.ctti_size, "btt_size: %uB",
+                          dtd->dtd_data.ctti_size);
+      return;
+    default:
+      break;
+    }
+
+  dw2_asm_output_data (4, get_btf_id (dtd->dtd_data.ctti_type), "btt_type");
+}
+
+/* Asm'out the variable information following a BTF_KIND_ARRAY.  */
+
+static void
+btf_asm_array (ctf_dtdef_ref dtd)
+{
+  dw2_asm_output_data (4, get_btf_id (dtd->dtd_u.dtu_arr.ctr_contents),
+                      "bta_contents");
+  dw2_asm_output_data (4, get_btf_id (dtd->dtd_u.dtu_arr.ctr_index),
+                      "bta_index");
+  dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_nelems, "bta_nelems");
+}
+
+/* Asm'out a BTF_KIND_VAR.  */
+
+static void
+btf_asm_varent (ctf_dvdef_ref var)
+{
+  dw2_asm_output_data (4, var->dvd_name_offset, "btv_name");
+  dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_VAR, 0, 0), "btv_info");
+  dw2_asm_output_data (4, get_btf_id (var->dvd_type), "btv_type");
+  dw2_asm_output_data (4, (var->dvd_visibility ? 1 : 0), "btv_linkage");
+}
+
+/* Asm'out a member description following a BTF_KIND_STRUCT or
+   BTF_KIND_UNION.  */
+
+static void
+btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd)
+{
+  ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type];
+
+  /* Re-encode bitfields to BTF representation.  */
+  if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
+    {
+      ctf_id_t base_type = ref_type->dtd_u.dtu_slice.cts_type;
+      unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset;
+      unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits;
+      uint64_t sou_offset = dmd->dmd_offset;
+
+      /* Pack the bit offset and bitfield size together.  */
+      sou_offset += word_offset;
+
+      /* If this bitfield cannot be represented, do not output anything.
+        The parent struct/union 'vlen' field has already been updated.  */
+      if ((bits > 0xff) || (sou_offset > 0xffffff))
+       return;
+
+      sou_offset &= 0x00ffffff;
+      sou_offset |= ((bits & 0xff) << 24);
+
+      /* Refer to the base type of the slice.  */
+      dw2_asm_output_data (4, dmd->dmd_name_offset, "btm_name_off");
+      dw2_asm_output_data (4, get_btf_id (base_type), "btm_type");
+      dw2_asm_output_data (4, sou_offset, "btm_offset");
+    }
+  else
+    {
+      dw2_asm_output_data (4, dmd->dmd_name_offset, "btm_name_off");
+      dw2_asm_output_data (4, get_btf_id (dmd->dmd_type), "btm_type");
+      dw2_asm_output_data (4, dmd->dmd_offset, "btm_offset");
+    }
+}
+
+/* Asm'out an enum constant following a BTF_KIND_ENUM.  */
+
+static void
+btf_asm_enum_const (ctf_dmdef_t * dmd)
+{
+  dw2_asm_output_data (4, dmd->dmd_name_offset, "bte_name");
+  dw2_asm_output_data (4, dmd->dmd_value, "bte_value");
+}
+
+/* Asm'out a function parameter description following a BTF_KIND_FUNC_PROTO.  */
+
+static void
+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");
+  else
+    dw2_asm_output_data (4, 0, "farg_name");
+
+  dw2_asm_output_data (4, (btf_removed_type_p (farg->farg_type)
+                          ? BTF_VOID_TYPEID
+                          : get_btf_id (farg->farg_type)),
+                      "farg_type");
+}
+
+/* Asm'out a BTF_KIND_FUNC type.  */
+
+static void
+btf_asm_func_type (ctf_dtdef_ref dtd)
+{
+  dw2_asm_output_data (4, dtd->dtd_data.ctti_name, "btt_name");
+  dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_FUNC, 0, 0), "btt_info");
+  dw2_asm_output_data (4, get_btf_id (dtd->dtd_data.ctti_type), "btt_type");
+}
+
+/* Asm'out a variable entry following a BTF_KIND_DATASEC.  */
+
+static void
+btf_asm_datasec_entry (struct btf_var_secinfo info)
+{
+  dw2_asm_output_data (4, info.type, "bts_type");
+  dw2_asm_output_data (4, info.offset, "bts_offset");
+  dw2_asm_output_data (4, info.size, "bts_size");
+}
+
+/* Asm'out a whole BTF_KIND_DATASEC, including its variable entries.  */
+
+static void
+btf_asm_datasec_type (btf_datasec_t ds, size_t stroffset)
+{
+  dw2_asm_output_data (4, ds.name_offset + stroffset, "btt_name");
+  dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_DATASEC, 0,
+                                        ds.entries.length ()),
+                      "btt_info");
+  /* Note: the "total section size in bytes" is emitted as 0 and patched by
+     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 (ds.entries[i]);
+}
+
+/* Compute and output the header information for a .BTF section.  */
+
+static void
+output_btf_header (ctf_container_ref ctfc)
+{
+   switch_to_section (btf_info_section);
+   ASM_OUTPUT_LABEL (asm_out_file, btf_info_section_label);
+
+   /* BTF magic number, version, flags, and header length.  */
+   dw2_asm_output_data (2, BTF_MAGIC, "btf_magic");
+   dw2_asm_output_data (1, BTF_VERSION, "btf_version");
+   dw2_asm_output_data (1, 0, "btf_flags");
+   dw2_asm_output_data (4, sizeof (struct btf_header), "btf_hdr_len");
+
+   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
+        + ctfc->ctfc_num_vlen_bytes;
+
+       str_off = type_off + type_len;
+
+       str_len = ctfc->ctfc_strtable.ctstab_len
+        + ctfc->ctfc_aux_strtable.ctstab_len;
+     }
+
+   /* 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");
+    /* Offset of string section.  */
+   dw2_asm_output_data (4, str_off, "str_off");
+    /* Length of string section in bytes.  */
+   dw2_asm_output_data (4, str_len, "str_len");
+}
+
+/* Output all BTF_KIND_VARs in CTFC.  */
+
+static void
+output_btf_vars (ctf_container_ref ctfc)
+{
+  size_t i;
+  size_t num_ctf_vars = num_vars_added;
+  if (num_ctf_vars)
+    {
+      for (i = 0; i < num_ctf_vars; i++)
+       btf_asm_varent (ctfc->ctfc_vars_list[i]);
+    }
+}
+
+/* Output BTF string records. The BTF strings section is a concatenation
+   of the standard and auxilliary string tables in the ctf container.  */
+
+static void
+output_btf_strs (ctf_container_ref ctfc)
+{
+  ctf_string_t * ctf_string = ctfc->ctfc_strtable.ctstab_head;
+
+  while (ctf_string)
+    {
+      dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_string");
+      ctf_string = ctf_string->cts_next;
+    }
+
+  ctf_string = ctfc->ctfc_aux_strtable.ctstab_head;
+  while (ctf_string)
+    {
+      dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_aux_string");
+      ctf_string = ctf_string->cts_next;
+    }
+}
+
+/* Output all (representable) members of a BTF_KIND_STRUCT or
+   BTF_KIND_UNION type.  */
+
+static void
+output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+{
+  ctf_dmdef_t * dmd;
+
+  for (dmd = dtd->dtd_u.dtu_members;
+       dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
+      btf_asm_sou_member (ctfc, dmd);
+}
+
+/* Output all enumerator constants following a BTF_KIND_ENUM.  */
+
+static void
+output_asm_btf_enum_list (ctf_container_ref ARG_UNUSED (ctfc),
+                         ctf_dtdef_ref dtd)
+{
+  ctf_dmdef_t * dmd;
+
+  for (dmd = dtd->dtd_u.dtu_members;
+       dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
+    btf_asm_enum_const (dmd);
+}
+
+/* Output all function arguments following a BTF_KIND_FUNC_PROTO.  */
+
+static void
+output_asm_btf_func_args_list (ctf_container_ref ctfc,
+                              ctf_dtdef_ref dtd)
+{
+  size_t farg_name_offset = ctfc_get_strtab_len (ctfc, CTF_STRTAB);
+  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 (farg, farg_name_offset);
+}
+
+/* Output the variable portion of a BTF type record. The information depends
+   on the kind of the type.  */
+
+static void
+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));
+
+  if (btf_kind == BTF_KIND_UNKN)
+    return;
+
+  switch (btf_kind)
+    {
+    case BTF_KIND_INT:
+      /* Redundant definitions of void may still be hanging around in the type
+        list as size 0 integers. Skip emitting them.  */
+      if (dtd->dtd_data.ctti_size < 1)
+       break;
+
+      encoding = BTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
+                              dtd->dtd_u.dtu_enc.cte_offset,
+                              dtd->dtd_u.dtu_enc.cte_bits);
+
+      dw2_asm_output_data (4, encoding, "bti_encoding");
+      break;
+
+    case BTF_KIND_ARRAY:
+      btf_asm_array (dtd);
+      break;
+
+    case BTF_KIND_STRUCT:
+    case BTF_KIND_UNION:
+      output_asm_btf_sou_fields (ctfc, dtd);
+      break;
+
+    case BTF_KIND_ENUM:
+      output_asm_btf_enum_list (ctfc, dtd);
+      break;
+
+    case BTF_KIND_FUNC_PROTO:
+      output_asm_btf_func_args_list (ctfc, dtd);
+      break;
+
+    case BTF_KIND_VAR:
+      /* BTF Variables are handled by output_btf_vars and btf_asm_varent.
+        There should be no BTF_KIND_VAR types at this point.  */
+      gcc_unreachable ();
+
+    case BTF_KIND_DATASEC:
+      /* The BTF_KIND_DATASEC records are handled by output_btf_datasec_types
+        and btf_asm_datasec_type. There should be no BTF_KIND_DATASEC types
+        at this point.  */
+      gcc_unreachable ();
+
+    default:
+      /* All other BTF type kinds have no variable length data.  */
+      break;
+    }
+}
+
+/* Output a whole BTF type record for TYPE, including the fixed and variable
+   data portions.  */
+
+static void
+output_asm_btf_type (ctf_container_ref ctfc, ctf_dtdef_ref type)
+{
+  if (btf_emit_id_p (type->dtd_type))
+    {
+      btf_asm_type (ctfc, type);
+      output_asm_btf_vlen_bytes (ctfc, type);
+    }
+}
+
+/* Output all BTF types in the container. This does not include synthesized
+   types: BTF_KIND_VAR, BTF_KIND_FUNC, nor BTF_KIND_DATASEC.  */
+
+static void
+output_btf_types (ctf_container_ref ctfc)
+{
+  size_t i;
+  size_t num_types = ctfc->ctfc_types->elements ();
+  if (num_types)
+    {
+      for (i = 1; i <= num_types; i++)
+       output_asm_btf_type (ctfc, ctfc->ctfc_types_list[i]);
+    }
+}
+
+/* Output all BTF_KIND_FUNC type records.  */
+
+static void
+output_btf_func_types (void)
+{
+  for (size_t i = 0; i < vec_safe_length (funcs); i++)
+    btf_asm_func_type ((*funcs)[i]);
+}
+
+/* Output all BTF_KIND_DATASEC records.  */
+
+static void
+output_btf_datasec_types (ctf_container_ref ctfc)
+{
+  size_t name_offset = ctfc_get_strtab_len (ctfc, CTF_STRTAB);
+
+  for (size_t i = 0; i < datasecs.length(); i++)
+    btf_asm_datasec_type (datasecs[i], name_offset);
+}
+
+/* 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.  */
+
+void
+btf_init_postprocess (void)
+{
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+
+  size_t i;
+  size_t num_ctf_types = tu_ctfc->ctfc_types->elements ();
+
+  holes.create (0);
+  voids.create (0);
+
+  num_types_added = 0;
+  num_types_created = 0;
+
+  if (num_ctf_types)
+    {
+      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 ++;
+       }
+    }
+}
+
+/* Process and output all BTF data. Entry point of btfout.  */
+
+void
+btf_output (const char * filename)
+{
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+
+  init_btf_sections ();
+
+  datasecs.create (0);
+  vec_alloc (funcs, 16);
+
+  ctf_add_cuname (tu_ctfc, filename);
+
+  btf_emit_preprocess (tu_ctfc);
+
+  output_btf_header (tu_ctfc);
+  output_btf_types (tu_ctfc);
+  output_btf_vars (tu_ctfc);
+  output_btf_func_types ();
+  output_btf_datasec_types (tu_ctfc);
+  output_btf_strs (tu_ctfc);
+}
+
+/* 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;
+
+  /* Clear preprocessing state.  */
+  num_vars_added = 0;
+  num_types_added = 0;
+  num_types_created = 0;
+
+  holes.release ();
+  voids.release ();
+  for (size_t i = 0; i < datasecs.length (); i++)
+    datasecs[i].entries.release ();
+  datasecs.release ();
+
+  funcs = NULL;
+
+  free (btf_id_map);
+  btf_id_map = NULL;
+
+  ggc_free (btf_var_ids);
+  btf_var_ids = NULL;
+
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+  ctfc_delete_container (tu_ctfc);
+  tu_ctfc = NULL;
+}
+
+#include "gt-btfout.h"
index a1353e0..1dd4456 100644 (file)
@@ -122,6 +122,11 @@ enum debug_info_levels debug_info_level = DINFO_LEVEL_NONE
 Variable
 bool use_gnu_debug_info_extensions
 
+; Level of CTF debugging information we are producing.  See flag-types.h
+; for the definitions of the different possible levels.
+Variable
+enum ctf_debug_info_levels ctf_debug_info_level = CTFINFO_LEVEL_NONE
+
 ; Original value of maximum field alignment in bytes, specified via
 ; -fpack-struct=<value>.
 Variable
@@ -3183,6 +3188,16 @@ gcolumn-info
 Common Driver Var(debug_column_info,1) Init(1)
 Record DW_AT_decl_column and DW_AT_call_column in DWARF.
 
+; The CTF generation process feeds off DWARF dies.  This option implicitly
+; updates the debug_info_level to DINFO_LEVEL_NORMAL.
+gctf
+Common Driver RejectNegative JoinedOrMissing
+Generate CTF debug information at default level.
+
+gbtf
+Common Driver RejectNegative JoinedOrMissing
+Generate BTF debug information at default level.
+
 gdwarf
 Common Driver JoinedOrMissing Negative(gdwarf-)
 Generate debug information in default version of DWARF format.
diff --git a/gcc/ctfc.c b/gcc/ctfc.c
new file mode 100644 (file)
index 0000000..1a6ddb8
--- /dev/null
@@ -0,0 +1,969 @@
+/* Generate CTF.
+   Copyright (C) 2019,2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "toplev.h"
+#include "ctfc.h"
+#include "diagnostic-core.h"
+
+/* A CTF container object - one per translation unit.  */
+
+ctf_container_ref tu_ctfc;
+
+ctf_container_ref
+ctf_get_tu_ctfc (void)
+{
+  return tu_ctfc;
+}
+
+/* If the next ctf type id is still set to the init value, no ctf records to
+   report.  */
+bool
+ctfc_is_empty_container (ctf_container_ref ctfc)
+{
+  return ((ctfc)->ctfc_nextid == CTF_INIT_TYPEID);
+}
+
+/* Get the total number of CTF types in the container.  */
+
+unsigned int
+ctfc_get_num_ctf_types (ctf_container_ref ctfc)
+{
+  return ctfc->ctfc_types->elements ();
+}
+
+/* Get the total number of CTF variables in the container.  */
+
+unsigned int ctfc_get_num_ctf_vars (ctf_container_ref ctfc)
+{
+  return ctfc->ctfc_vars->elements ();
+}
+
+/* Get reference to the CTF string table or the CTF auxilliary
+   string table.  */
+
+ctf_strtable_t *
+ctfc_get_strtab (ctf_container_ref ctfc, int aux)
+{
+  return aux ? &(ctfc)->ctfc_aux_strtable : &(ctfc->ctfc_strtable);
+}
+
+/* Get the length of the specified string table of the CTF container.  */
+
+size_t
+ctfc_get_strtab_len (ctf_container_ref ctfc, int aux)
+{
+  ctf_strtable_t * strtab = ctfc_get_strtab (ctfc, aux);
+  return strtab->ctstab_len;
+}
+
+/* Get the number of bytes to represent the variable length portion of all CTF
+   types in the CTF container.  */
+
+size_t ctfc_get_num_vlen_bytes (ctf_container_ref ctfc)
+{
+  return ctfc->ctfc_num_vlen_bytes;
+}
+
+/* Return which member of the union is used in CTFTYPE.  Used for garbage
+   collection.  */
+
+enum ctf_dtu_d_union_enum
+ctf_dtu_d_union_selector (ctf_dtdef_ref ctftype)
+{
+  uint32_t kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
+  switch (kind)
+    {
+    case CTF_K_UNKNOWN:
+    case CTF_K_INTEGER:
+    case CTF_K_FLOAT:
+      return CTF_DTU_D_ENCODING;
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+    case CTF_K_ENUM:
+      return CTF_DTU_D_MEMBERS;
+    case CTF_K_ARRAY:
+      return CTF_DTU_D_ARRAY;
+    case CTF_K_FUNCTION:
+      return CTF_DTU_D_ARGUMENTS;
+    case CTF_K_SLICE:
+      return CTF_DTU_D_SLICE;
+    default:
+      /* The largest member as default.  */
+      return CTF_DTU_D_ARRAY;
+    }
+}
+
+/* Insert CTF type into the CTF container.  */
+
+static void
+ctf_dtd_insert (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+{
+  bool existed = false;
+  ctf_dtdef_ref entry = dtd;
+
+  ctf_dtdef_ref * item = ctfc->ctfc_types->find_slot (entry, INSERT);
+  if (*item == NULL)
+     *item = dtd;
+  else
+    existed = true;
+  /* Duplicate CTF type records not expected to be inserted.  */
+  gcc_assert (!existed);
+}
+
+/* Lookup CTF type given a DWARF die for the type.  */
+
+static ctf_dtdef_ref
+ctf_dtd_lookup (const ctf_container_ref ctfc, const dw_die_ref type)
+{
+  ctf_dtdef_t entry;
+  entry.dtd_key = type;
+
+  ctf_dtdef_ref * slot = ctfc->ctfc_types->find_slot (&entry, NO_INSERT);
+
+  if (slot)
+    return (ctf_dtdef_ref)*slot;
+
+  return NULL;
+}
+
+/* Insert CTF variable into the CTF container.  */
+
+static void
+ctf_dvd_insert (ctf_container_ref ctfc, ctf_dvdef_ref dvd)
+{
+  bool existed = false;
+  ctf_dvdef_ref entry = dvd;
+
+  ctf_dvdef_ref * item = ctfc->ctfc_vars->find_slot (entry, INSERT);
+  if (*item == NULL)
+     *item = dvd;
+  else
+    existed = true;
+  /* Duplicate variable records not expected to be inserted.  */
+  gcc_assert (!existed);
+}
+
+/* Lookup CTF variable given a DWARF die for the decl.  */
+
+ctf_dvdef_ref
+ctf_dvd_lookup (const ctf_container_ref ctfc, dw_die_ref die)
+{
+  ctf_dvdef_t entry;
+  entry.dvd_key = die;
+
+  ctf_dvdef_ref * slot = ctfc->ctfc_vars->find_slot (&entry, NO_INSERT);
+
+  if (slot)
+    return (ctf_dvdef_ref)*slot;
+
+  return NULL;
+}
+
+/* Append member definition to the list.  Member list is a singly-linked list
+   with list start pointing to the head.  */
+
+static void
+ctf_dmd_list_append (ctf_dmdef_t ** dmd, ctf_dmdef_t * elem)
+{
+  ctf_dmdef_t * tail = (dmd && *dmd) ? *dmd : NULL;
+  if (tail)
+    {
+      while (tail->dmd_next)
+       tail = tail->dmd_next;
+
+      tail->dmd_next = elem;
+    }
+  else
+    *dmd = elem;
+
+  elem->dmd_next = NULL;
+}
+
+/* Append function argument to the list.  Member list is a singly-linked list
+   with list start pointing to the head.  */
+
+static void
+ctf_farg_list_append (ctf_func_arg_t ** farg, ctf_func_arg_t * elem)
+{
+  ctf_func_arg_t * tail = (farg && *farg) ? *farg : NULL;
+  if (tail)
+    {
+      while (tail->farg_next)
+       tail = tail->farg_next;
+
+      tail->farg_next = elem;
+    }
+  else
+    *farg = elem;
+
+  elem->farg_next = NULL;
+}
+
+/* Append str to the CTF string table.  */
+
+static void
+ctfc_strtable_append_str (ctf_strtable_t * str_table, const char * str)
+{
+  ctf_string_t * ctf_string = ggc_cleared_alloc<ctf_string_t> ();
+  /* Keep a reference to the input STR.  */
+  ctf_string->cts_str = str;
+  ctf_string->cts_next = NULL;
+
+  if (!str_table->ctstab_head)
+    str_table->ctstab_head = ctf_string;
+
+  /* Append to the end of the list.  */
+  if (str_table->ctstab_tail)
+    str_table->ctstab_tail->cts_next = ctf_string;
+
+  str_table->ctstab_tail = ctf_string;
+}
+
+/* Wrapper function to add str to the CTF string table.  No de-duplication of
+   CTF strings is done by the compiler.  */
+
+static const char *
+ctfc_strtable_add_str (ctf_strtable_t * str_table, const char * name,
+                     uint32_t * name_offset)
+{
+  size_t len;
+  char * ctf_string;
+  /* Return value is the offset to the string in the string table.  */
+  uint32_t str_offset = str_table->ctstab_len;
+
+  /* Add empty string only once at the beginning of the string table.  Also, do
+     not add null strings, return the offset to the empty string for them.  */
+  if ((!name || (name != NULL && !strcmp (name, ""))) && str_offset)
+    {
+      ctf_string = CONST_CAST (char *, str_table->ctstab_estr);
+      str_offset = 0;
+    }
+  else
+    {
+      gcc_assert (name);
+      /* Add null-terminated strings to the string table.  */
+      len = strlen (name) + 1;
+      ctf_string = CONST_CAST (char *, ggc_strdup (name));
+
+      ctfc_strtable_append_str (str_table, ctf_string);
+      /* Add string to the string table.  Keep number of strings updated.  */
+      str_table->ctstab_num++;
+      /* Keep the number of bytes contained in the string table updated.  */
+      str_table->ctstab_len += len;
+    }
+
+  *name_offset = str_offset;
+
+  return (const char *) ctf_string;
+
+}
+
+/* Add string to the appropriate string table in the CTF container.  */
+
+const char *
+ctf_add_string (ctf_container_ref ctfc, const char * name,
+               uint32_t * name_offset, int aux_str = CTF_STRTAB)
+{
+  /* Get the CTF string table or the CTF auxilliary string table,
+     as applicable.  */
+  ctf_strtable_t *str_table = ctfc_get_strtab (ctfc, aux_str);
+  return ctfc_strtable_add_str (str_table, name, name_offset);
+}
+
+/* Add the compilation unit (CU) name string to the the CTF string table.  The
+   CU name has a prepended pwd string if it is a relative path.  Also set the
+   CU name offset in the CTF container.  */
+
+void
+ctf_add_cuname (ctf_container_ref ctfc, const char * filename)
+{
+  char * cuname = NULL;
+
+  /* (filename at this point of compilation cannot be null).  */
+
+  if (!IS_DIR_SEPARATOR (filename[0]))
+    {
+      /* Filename is a relative path.  */
+      const char * cu_pwd = get_src_pwd ();
+      const int cu_pwd_len = strlen (cu_pwd);
+
+      /* Add a DIR_SEPARATOR char before the filename.  */
+      const int len = cu_pwd_len + 2 + strlen (filename);
+
+      cuname = (char *) ggc_alloc_atomic (len);
+      memset (cuname, 0, len);
+
+      strcpy (cuname, cu_pwd);
+      cuname[cu_pwd_len] = DIR_SEPARATOR;
+      cuname[cu_pwd_len+1] = 0;
+      strcat (cuname, filename);
+    }
+  else
+    /* Filename is an absolute path.  */
+    cuname = CONST_CAST (char *, ggc_strdup (filename));
+
+  ctf_add_string (ctfc, cuname, &(ctfc->ctfc_cuname_offset));
+  /* Add 1 as CTF strings in the CTF string table are null-terminated
+     strings.  */
+  ctfc->ctfc_strlen += strlen (cuname) + 1;
+
+  /* Mark cuname for garbage collection.  */
+  cuname = NULL;
+}
+
+/* Functions to create CTF types.
+
+   These functions perform the task of adding CTF types to the CTF container.
+   No de-duplication is done by them; the onus is on the calling function to do
+   so.  The caller must first do a lookup via ctf_dtd_lookup or
+   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
+ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name,
+                ctf_dtdef_ref * rp, dw_die_ref die)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+
+  gcc_assert (flag == CTF_ADD_NONROOT || flag == CTF_ADD_ROOT);
+
+  dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
+
+  type = ctfc->ctfc_nextid++;
+  gcc_assert (type < CTF_MAX_TYPE); /* CTF type ID overflow.  */
+
+  /* Buffer the strings in the CTF string table.  */
+  dtd->dtd_name = ctf_add_string (ctfc, name, &(dtd->dtd_data.ctti_name));
+  dtd->dtd_type = type;
+  dtd->dtd_key = die;
+
+  if ((name != NULL) && strcmp (name, ""))
+    ctfc->ctfc_strlen += strlen (name) + 1;
+
+  ctf_dtd_insert (ctfc, dtd);
+
+  *rp = dtd;
+  return type;
+}
+
+static ctf_id_t
+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->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
+
+  uint32_t roundup_nbytes = (ROUND_UP (ep->cte_bits, BITS_PER_UNIT)
+                                   / BITS_PER_UNIT);
+
+  /* FIXME, stay close to what libctf does.  But by getting next power of two,
+     aren't we conveying less precise information.  E.g. floating point mode
+     XF has a size of 12 bytes.  */
+  dtd->dtd_data.ctti_size = roundup_nbytes ? (1 << ceil_log2 (roundup_nbytes))
+                          : roundup_nbytes;
+  dtd->dtd_u.dtu_enc = *ep;
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+                uint32_t kind, dw_die_ref die)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+
+  gcc_assert (ref <= CTF_MAX_TYPE);
+
+  type = ctf_add_generic (ctfc, flag, NULL, &dtd, 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;
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+ctf_id_t
+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->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
+  dtd->dtd_data.ctti_type = kind;
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_typedef (ctf_container_ref ctfc, uint32_t flag, const char * name,
+                ctf_id_t ref, dw_die_ref die)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+
+  gcc_assert (ref <= CTF_MAX_TYPE);
+  /* Nameless Typedefs are not expected.  */
+  gcc_assert ((name != NULL) && strcmp (name, ""));
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, 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;
+
+  gcc_assert (dtd->dtd_type != dtd->dtd_data.ctti_type);
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_id_t 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);
+
+  type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
+
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
+
+  roundup_nbytes = (ROUND_UP (bit_size, BITS_PER_UNIT) / BITS_PER_UNIT);
+  /* FIXME, stay close to what libctf does.  But by getting next power of two,
+     aren't we conveying less precise information, especially for bitfields.
+     For example, cte_bits = 33, roundup_nbytes = 5, ctti_size = 8 in the
+     implementation below.  */
+  dtd->dtd_data.ctti_size = roundup_nbytes ? (1 << ceil_log2 (roundup_nbytes))
+                                          : 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_u.dtu_slice.cts_type = (uint32_t) 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;
+}
+
+ctf_id_t
+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_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_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,
+                dw_die_ref die)
+{
+  return (ctf_add_reftype (ctfc, flag, ref, CTF_K_POINTER, die));
+}
+
+ctf_id_t
+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);
+
+  /* Caller of this API must make sure CTF type for arp->ctr_contents and
+     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->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
+  dtd->dtd_data.ctti_size = 0;
+  dtd->dtd_u.dtu_arr = *arp;
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
+             HOST_WIDE_INT size, 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.  */
+
+  /* The compiler does, however, update any previously existing forward types
+     to non-root.  CTF does not allow existence of two root types with the same
+     name.  */
+  ctf_dtdef_ref enum_fwd_type = ctf_dtd_lookup (ctfc, die);
+  if (enum_fwd_type)
+    {
+      enum_fwd_type->dtd_data.ctti_info
+       = CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
+    }
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
+
+  /* Size in bytes should always fit, of course.
+     TBD WARN - warn instead?  */
+  gcc_assert (size <= CTF_MAX_SIZE);
+
+  dtd->dtd_data.ctti_size = size;
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+int
+ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
+                   HOST_WIDE_INT value, dw_die_ref die)
+{
+  ctf_dmdef_t * dmd;
+  uint32_t kind, vlen, root;
+
+  /* Callers of this API must make sure that CTF_K_ENUM with enid has been
+     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 (name);
+
+  kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
+  root = CTF_V2_INFO_ISROOT (dtd->dtd_data.ctti_info);
+  vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
+
+  gcc_assert (kind == CTF_K_ENUM && vlen < CTF_MAX_VLEN);
+
+  /* Enum value is of type HOST_WIDE_INT in the compiler, dmd_value is int32_t
+     on the other hand.  Check bounds and skip adding this enum value if out of
+     bounds.  */
+  if ((value > INT_MAX) || (value < INT_MIN))
+    {
+      /* FIXME - Note this TBD_CTF_REPRESENTATION_LIMIT.  */
+      return (1);
+    }
+
+  dmd = ggc_cleared_alloc<ctf_dmdef_t> ();
+
+  /* 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_offset = 0;
+
+  dmd->dmd_value = value;
+
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, root, vlen + 1);
+  ctf_dmd_list_append (&dtd->dtd_u.dtu_members, dmd);
+
+  if ((name != NULL) && strcmp (name, ""))
+    ctfc->ctfc_strlen += strlen (name) + 1;
+
+  return (0);
+}
+
+int
+ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou,
+                      const char * name, ctf_id_t type,
+                      uint64_t bit_offset)
+{
+  ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, sou);
+  ctf_dmdef_t * dmd;
+
+  uint32_t kind, vlen, root;
+
+  /* The type of the member being added must already exist.  */
+  gcc_assert (dtd);
+
+  kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
+  root = CTF_V2_INFO_ISROOT (dtd->dtd_data.ctti_info);
+  vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
+
+  gcc_assert (kind == CTF_K_STRUCT || kind == CTF_K_UNION);
+  gcc_assert (vlen < CTF_MAX_VLEN);
+
+  dmd = ggc_cleared_alloc<ctf_dmdef_t> ();
+
+  /* Buffer the strings in the CTF string table.  */
+  dmd->dmd_name = ctf_add_string (ctfc, name, &(dmd->dmd_name_offset));
+  dmd->dmd_type = type;
+  dmd->dmd_value = -1;
+
+  if (kind == CTF_K_STRUCT && vlen != 0)
+    dmd->dmd_offset = bit_offset;
+  else
+    dmd->dmd_offset = 0;
+
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, root, vlen + 1);
+  ctf_dmd_list_append (&dtd->dtd_u.dtu_members, dmd);
+
+  if ((name != NULL) && strcmp (name, ""))
+    ctfc->ctfc_strlen += strlen (name) + 1;
+
+  return 0;
+}
+
+int
+ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref,
+                 dw_die_ref die, unsigned int external_vis)
+{
+  ctf_dvdef_ref dvd;
+
+  gcc_assert (name);
+
+  if (name != NULL)
+    {
+      dvd = ggc_cleared_alloc<ctf_dvdef_t> ();
+      dvd->dvd_key = die;
+      /* Buffer the strings in the CTF string table.  */
+      dvd->dvd_name = ctf_add_string (ctfc, name, &(dvd->dvd_name_offset));
+      dvd->dvd_visibility = external_vis;
+      dvd->dvd_type = ref;
+      ctf_dvd_insert (ctfc, dvd);
+
+      if (strcmp (name, ""))
+       ctfc->ctfc_strlen += strlen (name) + 1;
+    }
+
+  return 0;
+}
+
+int
+ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
+                     const char * name, ctf_id_t type)
+{
+  ctf_dtdef_ref 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);
+  /* The number of args must have been non-zero.  */
+  vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
+  gcc_assert (vlen);
+
+  farg = ggc_cleared_alloc<ctf_func_arg_t> ();
+
+  /* Buffer the strings in the auxilliary string table.  CTF V3 format does not
+     require function argument names.  Use auxilliary string table to keep
+     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;
+
+  ctf_farg_list_append (&dtd->dtd_u.dtu_argv, farg);
+
+  /* For aux_str, keep ctfc_aux_strlen updated for debugging.  */
+  if ((name != NULL) && strcmp (name, ""))
+    ctfc->ctfc_aux_strlen += strlen (name) + 1;
+
+  return 0;
+}
+
+ctf_id_t
+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)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+  uint32_t vlen;
+
+  gcc_assert (ctc);
+
+  vlen = ctc->ctc_argc;
+  gcc_assert (vlen <= CTF_MAX_VLEN);
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+
+  dtd->from_global_func = from_global_func;
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
+  /* Caller must make sure CTF types for ctc->ctc_return are already added.  */
+  dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return;
+  /* Caller must make sure CTF types for function arguments are already added
+     via ctf_add_function_arg () API.  */
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+ctf_id_t
+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));
+
+  /* In the compiler, no need to handle the case of promoting forwards to
+     structs.  This comment is simply to note a divergence from libctf.  */
+
+  /* The compiler does, however, update any previously existing forward types
+     to non-root.  CTF does not allow existence of two root types with the same
+     name.  */
+  ctf_dtdef_ref sou_fwd_type = ctf_dtd_lookup (ctfc, die);
+  if (sou_fwd_type)
+    {
+      sou_fwd_type->dtd_data.ctti_info
+       = CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
+    }
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, die);
+
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
+
+  if (size > CTF_MAX_SIZE)
+    {
+      dtd->dtd_data.ctti_size = CTF_LSIZE_SENT;
+      dtd->dtd_data.ctti_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
+      dtd->dtd_data.ctti_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
+      ctfc->ctfc_num_types++;
+    }
+  else
+    {
+      dtd->dtd_data.ctti_size = (uint32_t) size;
+      ctfc->ctfc_num_stypes++;
+    }
+
+  return type;
+}
+
+/* Check if CTF for TYPE has already been generated.  Mainstay for
+   de-duplication.  If CTF type already exists, returns TRUE and updates
+   the TYPE_ID for the caller.  */
+
+bool
+ctf_type_exists (ctf_container_ref ctfc, dw_die_ref type,
+                ctf_id_t * type_id)
+{
+  bool exists = false;
+  ctf_dtdef_ref ctf_type_seen = ctf_dtd_lookup (ctfc, type);
+
+  if (ctf_type_seen)
+    {
+      exists = true;
+      /* CTF type for this type exists.  */
+      *type_id = ctf_type_seen->dtd_type;
+    }
+
+  return exists;
+}
+
+/* Location information for CTF Types and CTF Variables.  CTF section does not
+   emit location information; at this time, location information is needed for
+   BTF CO-RE use-cases.  */
+
+int
+ctfc_get_dtd_srcloc (ctf_dtdef_ref dtd, ctf_srcloc_ref loc)
+{
+  loc->ctsloc_file = ctf_get_die_loc_file (dtd->dtd_key);
+  loc->ctsloc_line = ctf_get_die_loc_line (dtd->dtd_key);
+  loc->ctsloc_col = ctf_get_die_loc_col (dtd->dtd_key);
+
+  if (loc->ctsloc_file == NULL)
+    return 1;
+
+  return 0;
+}
+
+int
+ctfc_get_dvd_srcloc (ctf_dvdef_ref dvd, ctf_srcloc_ref loc)
+{
+  loc->ctsloc_file = ctf_get_die_loc_file (dvd->dvd_key);
+  loc->ctsloc_line = ctf_get_die_loc_line (dvd->dvd_key);
+  loc->ctsloc_col = ctf_get_die_loc_col (dvd->dvd_key);
+
+  if (loc->ctsloc_file == NULL)
+    return 1;
+
+  return 0;
+}
+
+/* CTF container setup and teardown routines.  */
+
+/* Initialize the CTF string table.
+   The first entry in the CTF string table (empty string) is added.  */
+
+static void
+init_ctf_strtable (ctf_strtable_t * strtab)
+{
+  strtab->ctstab_head = NULL;
+  strtab->ctstab_tail = NULL;
+  strtab->ctstab_num = 0;
+  strtab->ctstab_len = 0;
+
+  /* The first entry in the CTF string table is an empty string.  E.g., CTF
+     type records with no name (like CTF_K_CONST, CTF_K_VOLATILE etc) point to
+     this string.  */
+  uint32_t estr_offset = 0;
+  strtab->ctstab_estr = ctfc_strtable_add_str (strtab, "", &estr_offset);
+}
+
+/* Initialize the string tables in the CTF container.  */
+
+static void
+init_ctf_string_table (ctf_container_ref ctfc)
+{
+  init_ctf_strtable (&ctfc->ctfc_strtable);
+  ctfc->ctfc_strlen++;
+
+  init_ctf_strtable (&ctfc->ctfc_aux_strtable);
+  ctfc->ctfc_aux_strlen++;
+}
+
+/* Allocate a new CTF container with the desired flags.  */
+
+static inline ctf_container_ref
+new_ctf_container (void)
+{
+  tu_ctfc = ggc_cleared_alloc<ctf_container_t> ();
+  tu_ctfc->ctfc_types
+    = hash_table<ctfc_dtd_hasher>::create_ggc (100);
+  tu_ctfc->ctfc_vars
+    = hash_table<ctfc_dvd_hasher>::create_ggc (100);
+
+  return tu_ctfc;
+}
+
+/* Initialize a CTF container per translation unit.  */
+
+static void
+init_ctf_container (void)
+{
+  tu_ctfc = new_ctf_container ();
+
+  tu_ctfc->ctfc_magic = CTF_MAGIC;
+  tu_ctfc->ctfc_version = CTF_VERSION;
+  tu_ctfc->ctfc_flags = CTF_F_NEWFUNCINFO;
+  tu_ctfc->ctfc_nextid = CTF_INIT_TYPEID;
+
+  init_ctf_string_table (tu_ctfc);
+}
+
+void
+ctfc_delete_strtab (ctf_strtable_t * strtab)
+{
+  ctf_string_t * str = NULL;
+  ctf_string_t * next_str = NULL;
+
+  str = strtab->ctstab_head;
+  next_str = str;
+  while (next_str != NULL)
+    {
+      next_str = str->cts_next;
+      ggc_free (str);
+      str = next_str;
+    }
+
+  strtab->ctstab_head = NULL;
+  strtab->ctstab_tail = NULL;
+  strtab->ctstab_estr = NULL;
+}
+
+/* Delete the CTF container's resources.  */
+
+void
+ctfc_delete_container (ctf_container_ref ctfc)
+{
+  /* FIXME - CTF container can be cleaned up now.
+     Will the ggc machinery take care of cleaning up the container structure
+     including the hash_map members etc. ?  */
+  if (ctfc)
+    {
+      ctfc_delete_strtab (&ctfc->ctfc_strtable);
+      ctfc_delete_strtab (&ctfc->ctfc_aux_strtable);
+      if (ctfc->ctfc_vars_list)
+       {
+         ggc_free (ctfc->ctfc_vars_list);
+         ctfc->ctfc_vars_list = NULL;
+       }
+      if (ctfc->ctfc_types_list)
+       {
+         ggc_free (ctfc->ctfc_types_list);
+         ctfc->ctfc_types_list = NULL;
+       }
+      if (ctfc->ctfc_gfuncs_list)
+       {
+         ggc_free (ctfc->ctfc_gfuncs_list);
+         ctfc->ctfc_gfuncs_list = NULL;
+       }
+      if (ctfc->ctfc_gobjts_list)
+       {
+         ggc_free (ctfc->ctfc_gobjts_list);
+         ctfc->ctfc_gobjts_list = NULL;
+       }
+
+      ctfc= NULL;
+    }
+}
+
+/* CTF routines interfacing to the compiler.  */
+
+void
+ctf_init (void)
+{
+  init_ctf_container ();
+}
diff --git a/gcc/ctfc.h b/gcc/ctfc.h
new file mode 100644 (file)
index 0000000..39c5270
--- /dev/null
@@ -0,0 +1,436 @@
+/* ctfc.h - Declarations and definitions related to the CTF container.
+   Copyright (C) 2019,2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This file defines the data structures and functions used by the compiler
+   to generate the CTF debug info.  The definitions below are compiler internal
+   representations and closely reflect the CTF format requirements in <ctf.h>.
+
+   The contents of the CTF container are used eventually for emission of both
+   CTF (ctfout.c) and BTF debug info (btfout.c), as the two type debug formats
+   are close cousins.  */
+
+#ifndef GCC_CTFC_H
+#define GCC_CTFC_H 1
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "dwarf2ctf.h"
+#include "ctf.h"
+#include "btf.h"
+
+/* Invalid CTF type ID definition.  */
+
+#define CTF_NULL_TYPEID 0
+
+/* Value to start generating the CTF type ID from.  */
+
+#define CTF_INIT_TYPEID 1
+
+/* CTF type ID.  */
+
+typedef uint64_t ctf_id_t;
+
+/* CTF string table element (list node).  */
+
+typedef struct GTY ((chain_next ("%h.cts_next"))) ctf_string
+{
+  const char * cts_str;                  /* CTF string.  */
+  struct ctf_string * cts_next;   /* A list node.  */
+} ctf_string_t;
+
+/* Internal representation of CTF string table.  */
+
+typedef struct GTY (()) ctf_strtable
+{
+  ctf_string_t * ctstab_head;      /* Head str ptr.  */
+  ctf_string_t * ctstab_tail;      /* Tail.  new str appended to tail.  */
+  int ctstab_num;                  /* Number of strings in the table.  */
+  size_t ctstab_len;               /* Size of string table in bytes.  */
+  const char * ctstab_estr;        /* Empty string "".  */
+} ctf_strtable_t;
+
+/* Encoding information for integers, floating-point values etc.  The flags
+   field will contain values appropriate for the type defined in <ctf.h>.  */
+
+typedef struct GTY (()) ctf_encoding
+{
+  unsigned int cte_format;  /* Data format (CTF_INT_* or CTF_FP_* flags).  */
+  unsigned int cte_offset;  /* Offset of value in bits.  */
+  unsigned int cte_bits;    /* Size of storage in bits.  */
+} ctf_encoding_t;
+
+/* Array information for CTF generation.  */
+
+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.  */
+} 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).  */
+} ctf_funcinfo_t;
+
+typedef struct GTY (()) ctf_sliceinfo
+{
+  unsigned int 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;
+
+/* CTF type representation internal to the compiler.  It closely reflects the
+   ctf_type_t type node in <ctf.h> except the GTY (()) tags.  */
+
+typedef struct GTY (()) ctf_itype
+{
+  uint32_t ctti_name;          /* Reference to name in string table.  */
+  uint32_t ctti_info;          /* Encoded kind, variant length (see below).  */
+  union GTY ((desc ("0")))
+  {
+    uint32_t GTY ((tag ("0"))) _size;/* Size of entire type in bytes.  */
+    uint32_t GTY ((tag ("1"))) _type;/* Reference to another type.  */
+  } _u;
+  uint32_t ctti_lsizehi;       /* High 32 bits of type size in bytes.  */
+  uint32_t ctti_lsizelo;       /* Low 32 bits of type size in bytes.  */
+} ctf_itype_t;
+
+#define ctti_size _u._size
+#define ctti_type _u._type
+
+/* Function arguments end with varargs.  */
+
+#define CTF_FUNC_VARARG 0x1
+
+/* Struct/union/enum member definition for CTF generation.  */
+
+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).  */
+  uint32_t dmd_name_offset;    /* Offset of the name in str table.  */
+  uint64_t dmd_offset;         /* Offset of this member in bits (for sou).  */
+  int dmd_value;               /* Value of this member (for enum).  */
+  struct ctf_dmdef * dmd_next; /* A list node.  */
+} ctf_dmdef_t;
+
+#define ctf_dmd_list_next(elem) ((ctf_dmdef_t *)((elem)->dmd_next))
+
+/* Function Argument.  */
+
+typedef struct GTY (()) ctf_func_arg
+{
+  ctf_id_t farg_type;            /* Type identifier of the argument.  */
+  const char * farg_name;        /* Name of the the argument.  */
+  uint32_t farg_name_offset;     /* Offset of the name in str table.  */
+  struct ctf_func_arg * farg_next;/* A list node.  */
+} ctf_func_arg_t;
+
+#define ctf_farg_list_next(elem) ((ctf_func_arg_t *)((elem)->farg_next))
+
+/* Type definition for CTF generation.  */
+
+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.  */
+  ctf_itype_t dtd_data;              /* Type node.  */
+  bool from_global_func; /* Whether this type was added from a global
+                           function.  */
+  union GTY ((desc ("ctf_dtu_d_union_selector (&%1)")))
+  {
+    /* struct, union, or enum.  */
+    ctf_dmdef_t * GTY ((tag ("CTF_DTU_D_MEMBERS"))) dtu_members;
+    /* array.  */
+    ctf_arinfo_t GTY ((tag ("CTF_DTU_D_ARRAY"))) dtu_arr;
+    /* integer or float.  */
+    ctf_encoding_t GTY ((tag ("CTF_DTU_D_ENCODING"))) dtu_enc;
+    /* function.  */
+    ctf_func_arg_t * GTY ((tag ("CTF_DTU_D_ARGUMENTS"))) dtu_argv;
+    /* slice.  */
+    ctf_sliceinfo_t GTY ((tag ("CTF_DTU_D_SLICE"))) dtu_slice;
+  } dtd_u;
+};
+
+typedef struct ctf_dtdef ctf_dtdef_t;
+
+/* Variable definition for CTF generation.  */
+
+struct GTY ((for_user)) ctf_dvdef
+{
+  dw_die_ref dvd_key;          /* DWARF DIE corresponding to the variable.  */
+  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.  */
+};
+
+typedef struct ctf_dvdef ctf_dvdef_t;
+
+typedef ctf_dvdef_t * ctf_dvdef_ref;
+typedef ctf_dtdef_t * ctf_dtdef_ref;
+
+/* Location information for CTF Types and CTF Variables.  */
+
+typedef struct GTY (()) ctf_srcloc
+{
+  const char * ctsloc_file;
+  unsigned int ctsloc_line;
+  unsigned int ctsloc_col;
+} ctf_srcloc_t;
+
+typedef ctf_srcloc_t * ctf_srcloc_ref;
+
+/* Helper enum and api for the GTY machinery to work on union dtu_d.  */
+
+enum ctf_dtu_d_union_enum {
+  CTF_DTU_D_MEMBERS,
+  CTF_DTU_D_ARRAY,
+  CTF_DTU_D_ENCODING,
+  CTF_DTU_D_ARGUMENTS,
+  CTF_DTU_D_SLICE,
+};
+
+enum ctf_dtu_d_union_enum
+ctf_dtu_d_union_selector (ctf_dtdef_ref);
+
+struct ctfc_dtd_hasher : ggc_ptr_hash <ctf_dtdef_t>
+{
+  typedef ctf_dtdef_ref compare_type;
+
+  static hashval_t hash (ctf_dtdef_ref);
+  static bool equal (ctf_dtdef_ref, ctf_dtdef_ref);
+};
+
+inline hashval_t
+ctfc_dtd_hasher::hash (ctf_dtdef_ref dtd)
+{
+  return htab_hash_pointer (dtd->dtd_key);
+}
+
+inline bool
+ctfc_dtd_hasher::equal (ctf_dtdef_ref dtd, ctf_dtdef_ref dtd2)
+{
+  return (dtd->dtd_key == dtd2->dtd_key);
+}
+
+struct ctfc_dvd_hasher : ggc_ptr_hash <ctf_dvdef_t>
+{
+  typedef ctf_dvdef_ref compare_type;
+
+  static hashval_t hash (ctf_dvdef_ref);
+  static bool equal (ctf_dvdef_ref, ctf_dvdef_ref);
+};
+
+inline hashval_t
+ctfc_dvd_hasher::hash (ctf_dvdef_ref dvd)
+{
+  return htab_hash_pointer (dvd->dvd_key);
+}
+
+inline bool
+ctfc_dvd_hasher::equal (ctf_dvdef_ref dvd, ctf_dvdef_ref dvd2)
+{
+  return (dvd->dvd_key == dvd2->dvd_key);
+}
+
+/* CTF container structure.
+   It is the context passed around when generating ctf debug info.  There is
+   one container per translation unit.  */
+
+typedef struct GTY (()) ctf_container
+{
+  /* CTF Preamble.  */
+  unsigned short ctfc_magic;
+  unsigned char ctfc_version;
+  unsigned char ctfc_flags;
+  uint32_t ctfc_cuname_offset;
+
+  /* CTF types.  */
+  hash_table <ctfc_dtd_hasher> * GTY (()) ctfc_types;
+  /* CTF variables.  */
+  hash_table <ctfc_dvd_hasher> * GTY (()) ctfc_vars;
+
+  /* CTF string table.  */
+  ctf_strtable_t ctfc_strtable;
+  /* Auxilliary string table.  At this time, used for keeping func arg names
+     for BTF.  */
+  ctf_strtable_t ctfc_aux_strtable;
+
+  uint64_t ctfc_num_types;
+  uint64_t ctfc_num_stypes;
+  uint64_t ctfc_num_global_funcs;
+  uint64_t ctfc_num_global_objts;
+
+  /* Number of vlen bytes - the variable length portion after ctf_type_t and
+     ctf_stype_t in the CTF section.  This is used to calculate the offsets in
+     the CTF header.  */
+  uint64_t ctfc_num_vlen_bytes;
+
+  /* Next CTF type id to assign.  */
+  ctf_id_t ctfc_nextid;
+
+  /* Specify an explicit length of 0 so that the GC marking routines steer
+     clear of marking the CTF vars and CTF types twice. These lists below do
+     not own the pointed to objects, they simply hold references to them.  */
+
+  /* List of pre-processed CTF Variables.  CTF requires that the variables
+     appear in the sorted order of their names.  */
+  ctf_dvdef_t ** GTY ((length ("0"))) ctfc_vars_list;
+  /* List of pre-processed CTF types.  CTF requires that a shared type must
+     appear before the type that uses it.  For the compiler, this means types
+     are emitted in sorted order of their type IDs.  */
+  ctf_dtdef_t ** GTY ((length ("0"))) ctfc_types_list;
+  /* List of CTF function types for global functions.  The order of global
+     function entries in the CTF funcinfo section is undefined by the
+     compiler.  */
+  ctf_dtdef_t ** GTY ((length ("0"))) ctfc_gfuncs_list;
+  /* List of CTF variables at global scope.  The order of global object entries
+     in the CTF objinfo section is undefined by the  compiler.  */
+  ctf_dvdef_t ** GTY ((length ("0"))) ctfc_gobjts_list;
+
+  /* Following members are for debugging only.  They do not add functional
+     value to the task of CTF creation.  These can be cleaned up once CTF
+     generation stabilizes.  */
+
+  /* Keep a count of the number of bytes dumped in asm for debugging
+     purposes.  */
+  uint64_t ctfc_numbytes_asm;
+   /* Total length of all strings in CTF.  */
+  size_t ctfc_strlen;
+  /* Total length of all strings in aux string table.  */
+  size_t ctfc_aux_strlen;
+
+} ctf_container_t;
+
+/* Markers for which string table from the CTF container to use.  */
+
+#define CTF_STRTAB 0       /* CTF string table.  */
+#define CTF_AUX_STRTAB 1    /* CTF auxilliary string table.  */
+
+typedef ctf_container_t * ctf_container_ref;
+
+extern GTY (()) ctf_container_ref tu_ctfc;
+
+extern void ctfc_delete_container (ctf_container_ref);
+
+/* If the next ctf type id is still set to the init value, no ctf records to
+   report.  */
+extern bool ctfc_is_empty_container (ctf_container_ref);
+
+/* Get the total number of CTF types in the container.  */
+
+extern unsigned int ctfc_get_num_ctf_types (ctf_container_ref);
+
+/* Get the total number of CTF variables in the container.  */
+
+extern unsigned int ctfc_get_num_ctf_vars (ctf_container_ref);
+
+/* Get reference to the CTF string table or the CTF auxilliary
+   string table.  */
+
+extern ctf_strtable_t * ctfc_get_strtab (ctf_container_ref, int);
+
+/* Get the length of the specified string table in the CTF container.  */
+
+extern size_t ctfc_get_strtab_len (ctf_container_ref, int);
+
+/* Get the number of bytes to represent the variable length portion of all CTF
+   types in the CTF container.  */
+
+extern size_t ctfc_get_num_vlen_bytes (ctf_container_ref);
+
+/* The compiler demarcates whether types are visible at top-level scope or not.
+   The only example so far of a type not visible at top-level scope is slices.
+   CTF_ADD_NONROOT is used to indicate the latter.  */
+#define        CTF_ADD_NONROOT 0       /* CTF type only visible in nested scope.  */
+#define        CTF_ADD_ROOT    1       /* CTF type visible at top-level scope.  */
+
+/* These APIs allow to initialize and finalize the CTF machinery and
+   to add types to the CTF container associated to the current
+   translation unit.  Used in dwarf2ctf.c.  */
+
+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_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 void ctf_add_cuname (ctf_container_ref, const char *);
+
+extern ctf_dvdef_ref ctf_dvd_lookup (const ctf_container_ref, dw_die_ref);
+
+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,
+                                uint32_t, dw_die_ref);
+extern ctf_id_t ctf_add_enum (ctf_container_ref, uint32_t, const char *,
+                             HOST_WIDE_INT, dw_die_ref);
+extern ctf_id_t ctf_add_slice (ctf_container_ref, uint32_t, ctf_id_t,
+                              uint32_t, uint32_t, dw_die_ref);
+extern ctf_id_t 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 *,
+                                const ctf_encoding_t *, dw_die_ref);
+extern ctf_id_t 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,
+                                dw_die_ref);
+extern ctf_id_t 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 *,
+                                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 *,
+                                 const ctf_funcinfo_t *, dw_die_ref, bool);
+extern ctf_id_t 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 *,
+                              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);
+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,
+                            dw_die_ref, unsigned int);
+
+/* CTF section does not emit location information; at this time, location
+   information is needed for BTF CO-RE use-cases.  */
+
+extern int ctfc_get_dtd_srcloc (ctf_dtdef_ref, ctf_srcloc_ref);
+extern int ctfc_get_dvd_srcloc (ctf_dvdef_ref, ctf_srcloc_ref);
+
+#endif /* GCC_CTFC_H */
diff --git a/gcc/ctfout.c b/gcc/ctfout.c
new file mode 100644 (file)
index 0000000..c264fd6
--- /dev/null
@@ -0,0 +1,830 @@
+/* Output CTF format from GCC.
+   Copyright (C) 2019,2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "output.h"
+#include "dwarf2asm.h"
+#include "debug.h"
+#include "ctfc.h"
+#include "diagnostic-core.h"
+
+static int ctf_label_num;
+
+/* Pointers to various CTF sections.  */
+
+static GTY (()) section * ctf_info_section;
+
+/* Section names used to hold CTF debugging information.  */
+
+/* CTF debug info section.  */
+
+#ifndef CTF_INFO_SECTION_NAME
+#define CTF_INFO_SECTION_NAME  ".ctf"
+#endif
+
+/* Section flags for the CTF debug info section.  */
+
+#define CTF_INFO_SECTION_FLAGS (SECTION_DEBUG)
+
+/* Maximum size (in bytes) of an artificially generated CTF label.  */
+
+#define MAX_CTF_LABEL_BYTES 40
+
+static char ctf_info_section_label[MAX_CTF_LABEL_BYTES];
+
+#ifndef CTF_INFO_SECTION_LABEL
+#define CTF_INFO_SECTION_LABEL                 "Lctf"
+#endif
+
+/* CTF preprocess callback arguments.  */
+
+typedef struct ctf_dtd_preprocess_arg
+{
+  uint64_t dtd_global_func_idx;
+  ctf_container_ref dtd_arg_ctfc;
+} ctf_dtd_preprocess_arg_t;
+
+typedef struct ctf_dvd_preprocess_arg
+{
+  uint64_t dvd_global_obj_idx;
+  ctf_container_ref dvd_arg_ctfc;
+} ctf_dvd_preprocess_arg_t;
+
+/* Compare two CTF variable definition entries.  Currently used for sorting
+   by name.  */
+
+static int
+ctf_varent_compare (const void * entry1, const void * entry2)
+{
+  int result;
+  const ctf_dvdef_t * e1 = *(const ctf_dvdef_t * const*) entry1;
+  const ctf_dvdef_t * e2 = *(const ctf_dvdef_t * const*) entry2;
+
+  result = strcmp (e1->dvd_name, e2->dvd_name);
+
+  return result;
+}
+
+/* A CTF type record may be followed by variable-length of bytes to encode the
+   CTF type completely.  This routine calculates the number of bytes, in the
+   final binary CTF format, which are used to encode information about the type
+   completely.
+
+   This function must always be in sync with the CTF header.  */
+
+static uint64_t
+ctf_calc_num_vbytes (ctf_dtdef_ref ctftype)
+{
+  uint32_t size;
+  uint64_t vlen_bytes = 0;
+
+  uint32_t kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
+  uint32_t vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info);
+
+  ctf_dmdef_t * dmd;
+  ctf_func_arg_t * farg;
+  uint32_t size_per_member = 0;
+  unsigned int num_members = 0;
+  unsigned int num_fargs = 0;
+
+  switch (kind)
+    {
+      case CTF_K_FORWARD:
+      case CTF_K_UNKNOWN:
+      case CTF_K_POINTER:
+      case CTF_K_TYPEDEF:
+      case CTF_K_VOLATILE:
+      case CTF_K_CONST:
+      case CTF_K_RESTRICT:
+       /* These types have no vlen data.  */
+       break;
+
+      case CTF_K_INTEGER:
+      case CTF_K_FLOAT:
+       /* 4 bytes to represent encoding CTF_INT_DATA, CTF_FP_DATA.  */
+       vlen_bytes += sizeof (uint32_t);
+       break;
+      case CTF_K_FUNCTION:
+       /* Sanity check - number of function args must be the same as
+          vlen.  */
+       for (farg = ctftype->dtd_u.dtu_argv;
+            farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
+         num_fargs++;
+       gcc_assert (vlen == num_fargs);
+
+       /* FIXME - CTF_PADDING_FOR_ALIGNMENT.  */
+       vlen_bytes += (vlen + (vlen & 1)) * sizeof (uint32_t);
+       break;
+      case CTF_K_ARRAY:
+       /* This has a single ctf_array_t.  */
+       vlen_bytes += sizeof (ctf_array_t);
+       break;
+      case CTF_K_SLICE:
+       vlen_bytes += sizeof (ctf_slice_t);
+       break;
+      case CTF_K_STRUCT:
+      case CTF_K_UNION:
+       /* Count the number and type of members.  */
+       size = ctftype->dtd_data.ctti_size;
+       size_per_member = size >= CTF_LSTRUCT_THRESH
+                         ? sizeof (ctf_lmember_t) : sizeof (ctf_member_t);
+
+       /* Sanity check - number of members of struct must be the same as
+          vlen.  */
+       for (dmd = ctftype->dtd_u.dtu_members;
+            dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
+         num_members++;
+       gcc_assert (vlen == num_members);
+
+       vlen_bytes += (num_members * size_per_member);
+       break;
+      case CTF_K_ENUM:
+       vlen_bytes += vlen * sizeof (ctf_enum_t);
+       break;
+      default :
+       break;
+    }
+  return vlen_bytes;
+}
+
+/* Add a CTF variable to the end of the list.  */
+
+static void
+ctf_list_add_ctf_vars (ctf_container_ref ctfc, ctf_dvdef_ref var)
+{
+  /* FIXME - static may not fly with multiple CUs.  */
+  static int num_vars_added = 0;
+  ctfc->ctfc_vars_list[num_vars_added++] = var;
+}
+
+/* Initialize the various sections and labels for CTF output.  */
+
+void
+init_ctf_sections (void)
+{
+  /* Note : Even in case of LTO, the compiler continues to generate a single
+     CTF section for each compilation unit "early".  Unlike other debug
+     sections, CTF sections are non-LTO sections, and do not take the
+     .gnu.debuglto_ prefix.  The linker will de-duplicate the types in the CTF
+     sections, in case of LTO or  otherwise.  */
+  ctf_info_section = get_section (CTF_INFO_SECTION_NAME, CTF_INFO_SECTION_FLAGS,
+                                 NULL);
+
+  ASM_GENERATE_INTERNAL_LABEL (ctf_info_section_label,
+                              CTF_INFO_SECTION_LABEL, ctf_label_num++);
+}
+
+/* Routines for CTF pre-processing.  */
+
+static void
+ctf_preprocess_var (ctf_container_ref ctfc, ctf_dvdef_ref var)
+{
+  /* Add it to the list of types.  This array of types will be sorted before
+     assembling into output.  */
+  ctf_list_add_ctf_vars (ctfc, var);
+}
+
+/* CTF preprocess callback routine for CTF variables.  */
+
+int
+ctf_dvd_preprocess_cb (ctf_dvdef_ref * slot, void * arg)
+{
+  ctf_dvd_preprocess_arg_t * dvd_arg =  (ctf_dvd_preprocess_arg_t *)arg;
+  ctf_dvdef_ref var = (ctf_dvdef_ref) *slot;
+  ctf_container_ref arg_ctfc = dvd_arg->dvd_arg_ctfc;
+
+  ctf_preprocess_var (arg_ctfc, var);
+
+  /* Keep track of global objts.  */
+  arg_ctfc->ctfc_gobjts_list[dvd_arg->dvd_global_obj_idx] = var;
+  dvd_arg->dvd_global_obj_idx++;
+
+  return 1;
+}
+
+/* CTF preprocess callback routine for CTF types.  */
+
+int
+ctf_dtd_preprocess_cb (ctf_dtdef_ref * slot, void * arg)
+{
+  uint32_t kind;
+
+  ctf_dtdef_ref ctftype = (ctf_dtdef_ref) *slot;
+  ctf_dtd_preprocess_arg_t * dtd_arg = (ctf_dtd_preprocess_arg_t *)arg;
+  ctf_container_ref arg_ctfc = dtd_arg->dtd_arg_ctfc;
+
+  size_t index = ctftype->dtd_type;
+  gcc_assert (index <= arg_ctfc->ctfc_types->elements ());
+
+  /* CTF types need to be output in the order of their type IDs.  In other
+     words, if type A is used to define type B, type ID of type A must
+     appear before type ID of type B.  */
+  arg_ctfc->ctfc_types_list[index] = ctftype;
+
+  /* Keep track of the CTF type if it's a function type and the type
+     was generated from a function object.  */
+  kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
+  if (kind == CTF_K_FUNCTION && ctftype->from_global_func)
+    {
+      arg_ctfc->ctfc_gfuncs_list[dtd_arg->dtd_global_func_idx] = ctftype;
+      dtd_arg->dtd_global_func_idx++;
+    }
+
+  /* Calculate the vlen bytes.  */
+  arg_ctfc->ctfc_num_vlen_bytes += ctf_calc_num_vbytes (ctftype);
+
+  return 1;
+}
+
+/* CTF preprocessing.
+   After the CTF types for the compilation unit have been generated fully, the
+   compiler writes out the asm for the CTF types.
+
+   CTF writeout in the compiler requires two passes over the CTF types.  In the
+   first pass, the CTF preprocess pass:
+     1.  CTF types are sorted in the order of their type IDs.
+     2.  The variable number of bytes after each CTF type record are calculated.
+        This is used to calculate the offsets in the ctf_header_t.
+     3.  If the CTF type is of CTF_K_FUNCTION, the number of bytes in the
+        funcinfo sub-section are calculated.  This is used to calculate the
+        offsets in the ctf_header_t.
+     4.  Keep the list of CTF variables in ASCIIbetical order of their names.
+
+   In the second pass, the CTF writeout pass, asm tags are written out using
+   the compiler's afore-generated internal pre-processed CTF types.  */
+
+static void
+ctf_preprocess (ctf_container_ref ctfc)
+{
+  size_t num_ctf_types = ctfc->ctfc_types->elements ();
+
+  /* Initialize an array to keep track of the CTF variables at global
+     scope.  */
+  size_t num_global_objts = ctfc->ctfc_num_global_objts;
+  if (num_global_objts)
+    {
+      ctfc->ctfc_gobjts_list = ggc_vec_alloc<ctf_dvdef_t*>(num_global_objts);
+    }
+
+  size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
+  if (num_ctf_vars)
+    {
+      ctf_dvd_preprocess_arg_t dvd_arg;
+      dvd_arg.dvd_global_obj_idx = 0;
+      dvd_arg.dvd_arg_ctfc = ctfc;
+
+      /* Allocate CTF var list.  */
+      ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars);
+      /* Variables appear in the sort ASCIIbetical order of their names.  This
+        permits binary searching in the CTF reader.  Add the variables to a
+        list for sorting.  */
+      ctfc->ctfc_vars->traverse<void *, ctf_dvd_preprocess_cb> (&dvd_arg);
+      /* Sort the list.  */
+      qsort (ctfc->ctfc_vars_list, num_ctf_vars, sizeof (ctf_dvdef_ref),
+            ctf_varent_compare);
+    }
+
+  /* Initialize an array to keep track of the CTF functions types for global
+     functions in the CTF data section.  */
+  size_t num_global_funcs = ctfc->ctfc_num_global_funcs;
+  if (num_global_funcs)
+    {
+      ctfc->ctfc_gfuncs_list = ggc_vec_alloc<ctf_dtdef_t*>(num_global_funcs);
+      gcc_assert (num_ctf_types);
+    }
+
+  if (num_ctf_types)
+    {
+      ctf_dtd_preprocess_arg_t dtd_arg;
+      dtd_arg.dtd_global_func_idx = 0;
+      dtd_arg.dtd_arg_ctfc = ctfc;
+      /* Allocate the CTF types list.  Add 1 because type ID 0 is never a valid
+        CTF type ID.  No CTF type record should appear at that offset, this
+        eases debugging and readability.  */
+      ctfc->ctfc_types_list = ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1);
+      /* Pre-process CTF types.  */
+      ctfc->ctfc_types->traverse<void *, ctf_dtd_preprocess_cb> (&dtd_arg);
+
+      gcc_assert (dtd_arg.dtd_global_func_idx == num_global_funcs);
+    }
+}
+
+/* CTF asm helper routines.  */
+
+/* Asm'out the CTF preamble.  */
+
+static void
+ctf_asm_preamble (ctf_container_ref ctfc)
+{
+  dw2_asm_output_data (2, ctfc->ctfc_magic,
+                      "CTF preamble magic number");
+  dw2_asm_output_data (1, ctfc->ctfc_version, "CTF preamble version");
+  dw2_asm_output_data (1, ctfc->ctfc_flags, "CTF preamble flags");
+}
+
+/* Asm'out a CTF type which is represented by ctf_stype_t.  */
+
+static void
+ctf_asm_stype (ctf_dtdef_ref type)
+{
+  dw2_asm_output_data (4, type->dtd_data.ctti_name, "ctt_name");
+  dw2_asm_output_data (4, type->dtd_data.ctti_info, "ctt_info");
+  /* union.  */
+  dw2_asm_output_data (4, type->dtd_data.ctti_size, "ctt_size or ctt_type");
+}
+
+/* Asm'out a CTF type which is represented by ctf_type_t.  */
+
+static void
+ctf_asm_type (ctf_dtdef_ref type)
+{
+  dw2_asm_output_data (4, type->dtd_data.ctti_name, "ctt_name");
+  dw2_asm_output_data (4, type->dtd_data.ctti_info, "ctt_info");
+  /* union.  */
+  dw2_asm_output_data (4, type->dtd_data.ctti_size, "ctt_size");
+  dw2_asm_output_data (4, type->dtd_data.ctti_lsizehi, "ctt_lsizehi");
+  dw2_asm_output_data (4, type->dtd_data.ctti_lsizelo, "ctt_lsizelo");
+}
+
+/* Asm'out a CTF type of kind CTF_K_SLICE.  */
+
+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 (2, type->dtd_u.dtu_slice.cts_offset, "cts_offset");
+  dw2_asm_output_data (2, type->dtd_u.dtu_slice.cts_bits, "cts_bits");
+}
+
+/* Asm'out a CTF type of kind CTF_K_ARRAY.  */
+
+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, dtd->dtd_u.dtu_arr.ctr_nelems, "cta_nelems");
+}
+
+/* Asm'out a CTF variable.  */
+
+static void
+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");
+}
+
+/* Asm'out a member of CTF struct or union, represented by ctf_lmember_t.  */
+
+static void
+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, CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset),
+                      "ctlm_offsetlo");
+}
+
+/* Asm'out a member of a CTF sruct or union, represented by ctf_member_t.  */
+
+static void
+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");
+}
+
+/* Asm'out an enumerator constant.  */
+
+static void
+ctf_asm_enum_const (ctf_dmdef_t * dmd)
+{
+  dw2_asm_output_data (4, dmd->dmd_name_offset, "cte_name");
+  dw2_asm_output_data (4, dmd->dmd_value, "cte_value");
+}
+
+/* Asm'out a function argument.  */
+
+static void
+ctf_asm_func_arg (ctf_func_arg_t * farg)
+{
+  dw2_asm_output_data (4, farg->farg_type, "dtu_argv");
+}
+
+/* CTF writeout to asm file.  */
+
+static void
+output_ctf_header (ctf_container_ref ctfc)
+{
+  switch_to_section (ctf_info_section);
+  ASM_OUTPUT_LABEL (asm_out_file, ctf_info_section_label);
+
+  ctf_asm_preamble (ctfc);
+
+  /* For a single compilation unit, the parent container's name and label are
+     NULL.  */
+  dw2_asm_output_data (4, 0, "cth_parlabel");
+  dw2_asm_output_data (4, 0, "cth_parname");
+  dw2_asm_output_data (4, ctfc->ctfc_cuname_offset, "cth_cuname");
+
+  int typeslen = 0;
+  /* Initialize the offsets.  The offsets are from after the CTF header.  */
+  uint32_t lbloff = 0;
+  uint32_t objtoff = 0;
+  uint32_t funcoff = 0;
+  uint32_t objtidxoff = 0;
+  uint32_t funcidxoff = 0;
+  uint32_t varoff = 0;
+  uint32_t typeoff = 0;
+  uint32_t stroff = 0;
+
+  if (!ctfc_is_empty_container (ctfc))
+    {
+      gcc_assert (ctfc_get_num_ctf_types (ctfc)
+                 == (ctfc->ctfc_num_types + ctfc->ctfc_num_stypes));
+
+      funcoff = objtoff + ctfc->ctfc_num_global_objts * sizeof (uint32_t);
+      /* Object index appears after function info.  */
+      objtidxoff = funcoff + ctfc->ctfc_num_global_funcs * sizeof (uint32_t);
+      /* Funxtion index goes next.  */
+      funcidxoff = objtidxoff + ctfc->ctfc_num_global_objts * sizeof (uint32_t);
+      /* Vars appear after function index.  */
+      varoff = funcidxoff + ctfc->ctfc_num_global_funcs * sizeof (uint32_t);
+      /* CTF types appear after vars.  */
+      typeoff = varoff + ctfc_get_num_ctf_vars (ctfc) * sizeof (ctf_varent_t);
+      /* The total number of bytes for CTF types is the sum of the number of
+        times struct ctf_type_t, struct ctf_stype_t are written, plus the
+        amount of variable length data after each one of these.  */
+      typeslen = ctfc->ctfc_num_types * sizeof (ctf_type_t)
+               + ctfc->ctfc_num_stypes * (sizeof (ctf_stype_t))
+               + ctfc_get_num_vlen_bytes (ctfc);
+
+      /* Strings appear after types.  */
+      stroff = typeoff + typeslen;
+    }
+
+    /* Offset of label section.  */
+    dw2_asm_output_data (4, lbloff, "cth_lbloff");
+    /* Offset of object section.  */
+    dw2_asm_output_data (4, objtoff, "cth_objtoff");
+    /* Offset of function section.  */
+    dw2_asm_output_data (4, funcoff, "cth_funcoff");
+    /* Offset of object index section.  */
+    dw2_asm_output_data (4, objtidxoff, "cth_objtidxoff");
+    /* Offset of function index section.  */
+    dw2_asm_output_data (4, funcidxoff, "cth_funcidxoff");
+
+    /* Offset of variable section.  */
+    dw2_asm_output_data (4, varoff, "cth_varoff");
+    /* Offset of type section.  */
+    dw2_asm_output_data (4, typeoff, "cth_typeoff");
+    /* Offset of string section.  */
+    dw2_asm_output_data (4, stroff, "cth_stroff");
+    /* Length of string section in bytes.  */
+    dw2_asm_output_data (4, ctfc->ctfc_strlen, "cth_strlen");
+}
+
+/* Output the CTF object info section.  */
+
+static void
+output_ctf_obj_info (ctf_container_ref ctfc)
+{
+  uint64_t i;
+  ctf_dvdef_ref var;
+
+  if (!ctfc->ctfc_num_global_objts) return;
+
+  /* Compiler spits out the objts (at global scope) in the CTF obj info section.
+     In no specific order.  In an object file, the CTF object index section is
+     used to associate the objts to their corresponding names.  */
+  for (i = 0; i < ctfc->ctfc_num_global_objts; i++)
+    {
+      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");
+    }
+
+}
+
+/* Output the CTF function info section.  */
+
+static void
+output_ctf_func_info (ctf_container_ref ctfc)
+{
+  uint64_t i;
+  ctf_dtdef_ref ctftype;
+
+  if (!ctfc->ctfc_num_global_funcs) return;
+
+  /* The CTF funcinfo section is simply an array of CTF_K_FUNCTION type IDs in
+     the type section.  In an object file, the CTF function index section is
+     used to associate functions to their corresponding names.  */
+  for (i = 0; i < ctfc->ctfc_num_global_funcs; i++)
+    {
+      ctftype = ctfc->ctfc_gfuncs_list[i];
+      dw2_asm_output_data (4, ctftype->dtd_type, "funcinfo_func_type");
+    }
+}
+
+/* Output the CTF object index section.  */
+
+static void
+output_ctf_objtidx (ctf_container_ref ctfc)
+{
+  uint64_t i;
+  ctf_dvdef_ref var;
+
+  if (!ctfc->ctfc_num_global_objts) return;
+
+  for (i = 0; i < ctfc->ctfc_num_global_objts; i++)
+    {
+      var = ctfc->ctfc_gobjts_list[i];
+      /* Offset to the name in CTF string table.  */
+      dw2_asm_output_data (4, var->dvd_name_offset, "objtinfo_name");
+    }
+}
+
+/* Output the CTF function index section.  */
+
+static void
+output_ctf_funcidx (ctf_container_ref ctfc)
+{
+  uint64_t i;
+  ctf_dtdef_ref ctftype;
+
+  if (!ctfc->ctfc_num_global_funcs) return;
+
+  for (i = 0; i < ctfc->ctfc_num_global_funcs; i++)
+    {
+      ctftype = ctfc->ctfc_gfuncs_list[i];
+      /* Offset to the name in CTF string table.  */
+      dw2_asm_output_data (4, ctftype->dtd_data.ctti_name, "funcinfo_name");
+    }
+}
+
+/* Output the CTF variables.  Variables appear in the sorted ASCIIbetical
+   order of their names.  This permits binary searching in the CTF reader.  */
+
+static void
+output_ctf_vars (ctf_container_ref ctfc)
+{
+  size_t i;
+  size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
+  if (num_ctf_vars)
+    {
+      /* Iterate over the list of sorted vars and output the asm.  */
+      for (i = 0; i < num_ctf_vars; i++)
+       {
+         ctf_asm_varent (ctfc->ctfc_vars_list[i]);
+         /* The type of variable must be a valid one.  */
+         gcc_assert (ctfc->ctfc_vars_list[i]->dvd_type != CTF_NULL_TYPEID);
+       }
+    }
+}
+
+/* Output the CTF string records.  */
+
+static void
+output_ctf_strs (ctf_container_ref ctfc)
+{
+  ctf_string_t * ctf_string = ctfc->ctfc_strtable.ctstab_head;
+
+  while (ctf_string)
+    {
+      dw2_asm_output_nstring (ctf_string->cts_str, -1, "ctf_string");
+      ctf_string = ctf_string->cts_next;
+    }
+}
+
+/* Output the members of the CTF struct or union.  */
+
+static void
+output_asm_ctf_sou_fields (ctf_container_ref ARG_UNUSED (ctfc),
+                          ctf_dtdef_ref dtd)
+{
+  ctf_dmdef_t * dmd;
+
+  /* Function pointer to dump struct/union members.  */
+  void (*ctf_asm_sou_field_func) (ctf_dmdef_t *);
+
+  uint32_t size = dtd->dtd_data.ctti_size;
+
+  /* The variable length data struct/union CTF types is an array of
+     ctf_member or ctf_lmember, depending on size of the member.  */
+  if (size >= CTF_LSTRUCT_THRESH)
+    ctf_asm_sou_field_func = ctf_asm_sou_lmember;
+  else
+    ctf_asm_sou_field_func = ctf_asm_sou_member;
+
+  for (dmd = dtd->dtd_u.dtu_members;
+       dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
+    {
+      ctf_asm_sou_field_func (dmd);
+      /* Sanity Check - Unrepresented types appear as explicit types.  */
+      gcc_assert (dmd->dmd_type != CTF_NULL_TYPEID);
+    }
+}
+
+/* Output the list of enumerator constants of the CTF enum type.  */
+
+static void
+output_asm_ctf_enum_list (ctf_container_ref ARG_UNUSED (ctfc),
+                         ctf_dtdef_ref dtd)
+{
+  ctf_dmdef_t * dmd;
+
+  for (dmd = dtd->dtd_u.dtu_members;
+       dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
+    ctf_asm_enum_const (dmd);
+}
+
+/* Output the list of function arguments of the CTF function type.  */
+
+static void
+output_asm_func_args_list (ctf_container_ref ARG_UNUSED (ctfc),
+                         ctf_dtdef_ref dtd)
+{
+  ctf_func_arg_t * farg;
+
+  for (farg = dtd->dtd_u.dtu_argv;
+       farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
+    ctf_asm_func_arg (farg);
+}
+
+/* Output the variable length portion of the CTF type record.  */
+
+static void
+output_asm_ctf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref ctftype)
+{
+  uint32_t encoding;
+  uint32_t kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
+  uint32_t vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info);
+
+  switch (kind)
+    {
+      case CTF_K_INTEGER:
+      case CTF_K_FLOAT:
+       if (kind == CTF_K_INTEGER)
+         {
+           encoding = CTF_INT_DATA (ctftype->dtd_u.dtu_enc.cte_format,
+                                    ctftype->dtd_u.dtu_enc.cte_offset,
+                                    ctftype->dtd_u.dtu_enc.cte_bits);
+         }
+       else
+         {
+           encoding = CTF_FP_DATA (ctftype->dtd_u.dtu_enc.cte_format,
+                                   ctftype->dtd_u.dtu_enc.cte_offset,
+                                   ctftype->dtd_u.dtu_enc.cte_bits);
+         }
+       dw2_asm_output_data (4, encoding, "ctf_encoding_data");
+       break;
+      case CTF_K_FUNCTION:
+         {
+           output_asm_func_args_list (ctfc, ctftype);
+           /* FIXME - CTF_PADDING_FOR_ALIGNMENT.
+              libctf expects this padding for alignment reasons.  Expected to
+              be redundant in CTF_VERSION_4.  */
+           if (vlen & 1)
+             dw2_asm_output_data (4, 0, "dtu_argv_padding");
+
+           break;
+         }
+      case CTF_K_ARRAY:
+       ctf_asm_array (ctftype);
+       break;
+      case CTF_K_SLICE:
+         {
+           ctf_asm_slice (ctftype);
+           /* Type of the slice must be a valid CTF type.  */
+           gcc_assert (ctftype->dtd_u.dtu_slice.cts_type != CTF_NULL_TYPEID);
+           break;
+         }
+      case CTF_K_STRUCT:
+      case CTF_K_UNION:
+       output_asm_ctf_sou_fields (ctfc, ctftype);
+       break;
+      case CTF_K_ENUM:
+       output_asm_ctf_enum_list (ctfc, ctftype);
+       break;
+
+      default:
+       /* CTF types of kind CTF_K_VOLATILE, CTF_K_CONST, CTF_K_RESTRICT,
+          etc have no vlen data to write.  */
+       break;
+    }
+}
+
+/* Output a CTF Type.  */
+
+static void
+output_asm_ctf_type (ctf_container_ref ctfc, ctf_dtdef_ref type)
+{
+  if (type->dtd_data.ctti_size <= CTF_MAX_SIZE)
+    ctf_asm_stype (type);
+  else
+    ctf_asm_type (type);
+  /* Now comes the variable-length portion for defining types completely.
+     E.g., encoding follows CTF_INT_DATA, CTF_FP_DATA types,
+     struct ctf_array_t follows CTF_K_ARRAY types, or a bunch of
+     struct ctf_member / ctf_lmember ctf_enum sit in there for CTF_K_STRUCT or
+     CTF_K_UNION.  */
+  output_asm_ctf_vlen_bytes (ctfc, type);
+
+  uint32_t kind = CTF_V2_INFO_KIND (type->dtd_data.ctti_info);
+  /* The underlying type must be a valid CTF type.  */
+  if (kind == CTF_K_POINTER || kind == CTF_K_TYPEDEF
+      || kind == CTF_K_VOLATILE || kind == CTF_K_CONST
+      || kind == CTF_K_RESTRICT)
+    gcc_assert (type->dtd_data.ctti_type != CTF_NULL_TYPEID);
+}
+
+/* Output all CTF type records.  */
+
+static void
+output_ctf_types (ctf_container_ref ctfc)
+{
+  size_t i;
+  size_t num_ctf_types = ctfc->ctfc_types->elements ();
+  if (num_ctf_types)
+    {
+      /* Type ID = 0 is used as sentinel value; not a valid type.  */
+      for (i = 1; i <= num_ctf_types; i++)
+       output_asm_ctf_type (ctfc, ctfc->ctfc_types_list[i]);
+    }
+}
+
+/* CTF routines interfacing to the compiler.  */
+
+/* Prepare and output the CTF section.  */
+
+void
+ctf_output (const char * filename)
+{
+  if (ctf_debug_info_level == CTFINFO_LEVEL_NONE)
+    return;
+
+  /* Get the CTF container for the current translation unit.  */
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+
+  init_ctf_sections ();
+
+  ctf_add_cuname (tu_ctfc, filename);
+
+  /* Pre-process CTF before generating assembly.  */
+  ctf_preprocess (tu_ctfc);
+  output_ctf_header (tu_ctfc);
+  output_ctf_obj_info (tu_ctfc);
+  output_ctf_func_info (tu_ctfc);
+  output_ctf_objtidx (tu_ctfc);
+  output_ctf_funcidx (tu_ctfc);
+  output_ctf_vars (tu_ctfc);
+  output_ctf_types (tu_ctfc);
+  output_ctf_strs (tu_ctfc);
+
+  /* The total number of string bytes must be equal to those processed out to
+     the str subsection.  */
+  gcc_assert (tu_ctfc->ctfc_strlen
+             == ctfc_get_strtab_len (tu_ctfc, CTF_STRTAB));
+
+}
+
+/* Reset all state for CTF generation so that we can rerun the compiler within
+   the same process.  */
+
+void
+ctf_finalize (void)
+{
+  ctf_info_section = NULL;
+
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+  ctfc_delete_container (tu_ctfc);
+  tu_ctfc = NULL;
+}
+
+#include "gt-ctfout.h"
index c27ac19..df9b625 100644 (file)
@@ -3558,7 +3558,7 @@ dwarf2out_do_frame (void)
   /* We want to emit correct CFA location expressions or lists, so we
      have to return true if we're going to generate debug info, even if
      we're not going to output frame or unwind info.  */
-  if (dwarf_debuginfo_p ())
+  if (dwarf_debuginfo_p () || dwarf_based_debuginfo_p ())
     return true;
 
   if (saved_do_cfi_asm > 0)
diff --git a/gcc/dwarf2ctf.c b/gcc/dwarf2ctf.c
new file mode 100644 (file)
index 0000000..08e1252
--- /dev/null
@@ -0,0 +1,990 @@
+/* Generate CTF types and objects from the GCC DWARF.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "dwarf2out.h"
+#include "dwarf2out.h"
+
+#include "dwarf2ctf.h"
+#include "ctfc.h"
+
+/* Forward declarations for some routines defined in this file.  */
+
+static ctf_id_t
+gen_ctf_type (ctf_container_ref, dw_die_ref);
+
+/* All the DIE structures we handle come from the DWARF information
+   generated by GCC.  However, there are two situations where we need
+   to create our own created DIE structures because GCC doesn't
+   provide them.
+
+   The DWARF spec suggests using a DIE with DW_TAG_unspecified_type
+   and name "void" in order to denote the void type.  But GCC doesn't
+   follow this advice.  Still we need a DIE to act as a key for void
+   types, we use ctf_void_die.
+
+   Also, if a subrange type corresponding to an array index does not
+   specify a type then we assume it is `int'.
+
+   Finally, for types unrepresentable in CTF, we need a DIE to anchor
+   them to a CTF type of kind unknown.
+
+   The variables below are initialized in ctf_debug_init and hold
+   references to the proper DIEs.  */
+
+static GTY (()) dw_die_ref ctf_void_die;
+static GTY (()) dw_die_ref ctf_array_index_die;
+static GTY (()) dw_die_ref ctf_unknown_die;
+
+/* Some DIEs have a type description attribute, stored in a DW_AT_type
+   attribute.  However, GCC generates no attribute to signify a `void'
+   type.
+
+   This can happen in many contexts (return type of a function,
+   pointed or qualified type, etc) so we use the `ctf_get_AT_type'
+   function below abstracts this.  */
+
+static dw_die_ref
+ctf_get_AT_type (dw_die_ref die)
+{
+  dw_die_ref type_die = get_AT_ref (die, DW_AT_type);
+  return (type_die ? type_die : ctf_void_die);
+}
+
+/* Some data member DIEs have location specified as a DWARF expression
+   (specifically in DWARF2).  Luckily, the expression is a simple
+   DW_OP_plus_uconst with one operand set to zero.
+
+   Sometimes the data member location may also be negative.  In yet some other
+   cases (specifically union data members), the data member location is
+   non-existent.  Handle all these scenarios here to abstract this.  */
+
+static HOST_WIDE_INT
+ctf_get_AT_data_member_location (dw_die_ref die)
+{
+  HOST_WIDE_INT field_location = 0;
+  dw_attr_node * attr;
+
+  /* The field location (in bits) can be determined from
+     either a DW_AT_data_member_location attribute or a
+     DW_AT_data_bit_offset attribute.  */
+  if (get_AT (die, DW_AT_data_bit_offset))
+    field_location = get_AT_unsigned (die, DW_AT_data_bit_offset);
+  else
+    {
+      attr = get_AT (die, DW_AT_data_member_location);
+      if (attr && AT_class (attr) == dw_val_class_loc)
+       {
+         dw_loc_descr_ref descr = AT_loc (attr);
+         /* Operand 2 must be zero; the structure is assumed to be on the
+            stack in DWARF2.  */
+         gcc_assert (!descr->dw_loc_oprnd2.v.val_unsigned);
+         gcc_assert (descr->dw_loc_oprnd2.val_class
+                     == dw_val_class_unsigned_const);
+         field_location = descr->dw_loc_oprnd1.v.val_unsigned;
+       }
+      else
+       {
+         attr = get_AT (die, DW_AT_data_member_location);
+         if (attr && AT_class (attr) == dw_val_class_const)
+           field_location = AT_int (attr);
+         else
+           field_location = (get_AT_unsigned (die,
+                                          DW_AT_data_member_location)
+                             * 8);
+       }
+    }
+
+  return field_location;
+}
+
+/* CTF Types' and CTF Variables' Location Information.  CTF section does not
+   emit location information, this is provided for BTF CO-RE use-cases.  These
+   functions fetch information from DWARF Die directly, as such the location
+   information is not buffered in the CTF container.  */
+
+const char *
+ctf_get_die_loc_file (dw_die_ref die)
+{
+  if (!die)
+    return NULL;
+
+  struct dwarf_file_data * file;
+  file = get_AT_file (die, DW_AT_decl_file);
+  if (!file)
+    return NULL;
+
+  return file->filename;
+}
+
+unsigned int
+ctf_get_die_loc_line (dw_die_ref die)
+{
+  if (!die)
+    return 0;
+
+  return get_AT_unsigned (die, DW_AT_decl_line);
+}
+
+unsigned int
+ctf_get_die_loc_col (dw_die_ref die)
+{
+  if (!die)
+    return 0;
+
+  return get_AT_unsigned (die, DW_AT_decl_column);
+}
+
+/* Generate CTF for the void type.  */
+
+static ctf_id_t
+gen_ctf_void_type (ctf_container_ref ctfc)
+{
+  ctf_encoding_t ctf_encoding = {0, 0, 0};
+
+  /* In CTF the void type is encoded as a 0-byte signed integer
+     type.  */
+
+  ctf_encoding.cte_bits = 0;
+  ctf_encoding.cte_format = CTF_INT_SIGNED;
+
+  gcc_assert (ctf_void_die != NULL);
+  return ctf_add_integer (ctfc, CTF_ADD_ROOT, "void",
+                         &ctf_encoding, ctf_void_die);
+}
+
+/* Generate CTF type of unknown kind.  */
+
+static ctf_id_t
+gen_ctf_unknown_type (ctf_container_ref ctfc)
+{
+  ctf_id_t unknown_type_id;
+
+  /* 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
+     ctf_add_encoded interface; the CTF encoding object is not 'used' any more
+     than just the generation of size from.  */
+  ctf_encoding_t ctf_encoding = {0, 0, 0};
+
+  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);
+
+  return unknown_type_id;
+}
+
+/* Sizes of entities can be given in bytes or bits.  This function
+   abstracts this by returning the size in bits of the given entity.
+   If no DW_AT_byte_size nor DW_AT_bit_size are defined, this function
+   returns 0.  */
+
+static uint32_t
+ctf_die_bitsize (dw_die_ref die)
+{
+  dw_attr_node *attr_byte_size = get_AT (die, DW_AT_byte_size);
+  dw_attr_node *attr_bit_size = get_AT (die, DW_AT_bit_size);
+
+  if (attr_bit_size)
+    return AT_unsigned (attr_bit_size);
+  else if (attr_byte_size)
+    return (AT_unsigned (attr_byte_size) * 8);
+  else
+    return 0;
+}
+
+/* Generate CTF for base type (integer, boolean, real, fixed point and complex).
+   Important: the caller of this API must make sure that duplicate types are
+   not added.  */
+
+static ctf_id_t
+gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
+{
+  ctf_id_t type_id = CTF_NULL_TYPEID;
+
+  ctf_encoding_t ctf_encoding = {0, 0, 0};
+
+  unsigned int encoding = get_AT_unsigned (type, DW_AT_encoding);
+  unsigned int bit_size = ctf_die_bitsize (type);
+  const char * name_string = get_AT_string (type, DW_AT_name);
+
+  switch (encoding)
+    {
+    case DW_ATE_void:
+
+      ctf_encoding.cte_format = CTF_INT_SIGNED;
+      ctf_encoding.cte_bits = 0;
+
+      gcc_assert (name_string);
+      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+                                &ctf_encoding, type);
+
+      break;
+    case DW_ATE_boolean:
+
+      ctf_encoding.cte_format = CTF_INT_BOOL;
+      ctf_encoding.cte_bits = bit_size;
+
+      gcc_assert (name_string);
+      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+                                &ctf_encoding, type);
+      break;
+    case DW_ATE_float:
+      {
+       unsigned int float_bit_size
+         = tree_to_uhwi (TYPE_SIZE (float_type_node));
+       unsigned int double_bit_size
+         = tree_to_uhwi (TYPE_SIZE (double_type_node));
+       unsigned int long_double_bit_size
+         = tree_to_uhwi (TYPE_SIZE (long_double_type_node));
+
+       if (bit_size == float_bit_size)
+         ctf_encoding.cte_format = CTF_FP_SINGLE;
+       else if (bit_size == double_bit_size)
+         ctf_encoding.cte_format = CTF_FP_DOUBLE;
+       else if (bit_size == long_double_bit_size)
+         ctf_encoding.cte_format = CTF_FP_LDOUBLE;
+       else
+         /* CTF does not have representation for other types.  Skip them.  */
+         break;
+
+       ctf_encoding.cte_bits = bit_size;
+       type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+                                &ctf_encoding, type);
+
+       break;
+      }
+    case DW_ATE_signed_char:
+      /* FALLTHROUGH */
+    case DW_ATE_unsigned_char:
+      /* FALLTHROUGH */
+    case DW_ATE_signed:
+      /* FALLTHROUGH */
+    case DW_ATE_unsigned:
+
+      if (encoding == DW_ATE_signed_char
+         || encoding == DW_ATE_unsigned_char)
+       ctf_encoding.cte_format |= CTF_INT_CHAR;
+
+      if (encoding == DW_ATE_signed
+         || encoding == DW_ATE_signed_char)
+       ctf_encoding.cte_format |= CTF_INT_SIGNED;
+
+      ctf_encoding.cte_bits = bit_size;
+      type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+                                &ctf_encoding, type);
+      break;
+
+    case DW_ATE_complex_float:
+      {
+       unsigned int float_bit_size
+         = tree_to_uhwi (TYPE_SIZE (float_type_node));
+       unsigned int double_bit_size
+         = tree_to_uhwi (TYPE_SIZE (double_type_node));
+       unsigned int long_double_bit_size
+         = tree_to_uhwi (TYPE_SIZE (long_double_type_node));
+
+       if (bit_size == float_bit_size * 2)
+         ctf_encoding.cte_format = CTF_FP_CPLX;
+       else if (bit_size == double_bit_size * 2)
+         ctf_encoding.cte_format = CTF_FP_DCPLX;
+       else if (bit_size == long_double_bit_size * 2)
+           ctf_encoding.cte_format = CTF_FP_LDCPLX;
+       else
+         /* CTF does not have representation for other types.  Skip them.  */
+         break;
+
+       ctf_encoding.cte_bits = bit_size;
+       type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+                                &ctf_encoding, type);
+       break;
+      }
+    default:
+      /* Ignore.  */
+      break;
+    }
+
+  return type_id;
+}
+
+/* Generate CTF for a pointer type.  */
+
+static ctf_id_t
+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;
+  dw_die_ref pointed_type_die = ctf_get_AT_type (ptr_type);
+
+  type_id = 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;
+
+  ptr_type_id = ctf_add_pointer (ctfc, CTF_ADD_ROOT, type_id, ptr_type);
+  return ptr_type_id;
+}
+
+/* Generate CTF for an array type.  */
+
+static ctf_id_t
+gen_ctf_array_type (ctf_container_ref ctfc, dw_die_ref array_type)
+{
+  dw_die_ref c;
+  ctf_id_t array_elems_type_id = CTF_NULL_TYPEID;
+
+  int vector_type_p = get_AT_flag (array_type, DW_AT_GNU_vector);
+  if (vector_type_p)
+    return array_elems_type_id;
+
+  dw_die_ref 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);
+
+  /* DWARF array types pretend C supports multi-dimensional arrays.
+     So for the type int[N][M], the array type DIE contains two
+     subrange_type children, the first iwth upper bound N-1 and the
+     second with upper bound M-1.
+
+     CTF, on the other hand, just encodes each array type in its own
+     array type CTF struct.  Therefore we have to iterate on the
+     children and create all the needed types.  */
+
+  c = dw_get_die_child (array_type);
+  gcc_assert (c);
+  do
+    {
+      ctf_arinfo_t arinfo;
+      dw_die_ref array_index_type;
+      uint32_t array_num_elements;
+
+      c = dw_get_die_sib (c);
+
+      if (dw_get_die_tag (c) == DW_TAG_subrange_type)
+       {
+         dw_attr_node *upper_bound_at;
+
+         array_index_type = ctf_get_AT_type (c);
+
+         /* When DW_AT_upper_bound is used to specify the size of an
+            array in DWARF, it is usually an unsigned constant
+            specifying the upper bound index of the array.  However,
+            for unsized arrays, such as foo[] or bar[0],
+            DW_AT_upper_bound is a signed integer constant
+            instead.  */
+
+         upper_bound_at = get_AT (c, DW_AT_upper_bound);
+         if (upper_bound_at
+             && AT_class (upper_bound_at) == dw_val_class_unsigned_const)
+           /* This is the upper bound index.  */
+           array_num_elements = get_AT_unsigned (c, DW_AT_upper_bound) + 1;
+         else if (get_AT (c, DW_AT_count))
+           array_num_elements = get_AT_unsigned (c, DW_AT_count);
+         else
+           {
+             /* This is a VLA of some kind.  */
+             array_num_elements = 0;
+           }
+       }
+      else if (dw_get_die_tag (c) == DW_TAG_enumeration_type)
+       {
+         array_index_type = 0;
+         array_num_elements = 0;
+         /* XXX writeme. */
+         gcc_assert (1);
+       }
+      else
+       gcc_unreachable ();
+
+      /* Ok, mount and register the array type.  Note how the array
+        type we register here is the type of the elements in
+        subsequent "dimensions", if there are any.  */
+
+      arinfo.ctr_nelems = array_num_elements;
+      if (array_index_type)
+       arinfo.ctr_index = gen_ctf_type (ctfc, array_index_type);
+      else
+       arinfo.ctr_index = gen_ctf_type (ctfc, ctf_array_index_die);
+
+      arinfo.ctr_contents = array_elems_type_id;
+      if (!ctf_type_exists (ctfc, c, &array_elems_type_id))
+       array_elems_type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo,
+                                            c);
+    }
+  while (c != dw_get_die_child (array_type));
+
+#if 0
+  /* Type de-duplication.
+     Consult the ctfc_types hash again before adding the CTF array type because
+     there can be cases where an array_type type may have been added by the
+     gen_ctf_type call above.  */
+  if (!ctf_type_exists (ctfc, array_type, &type_id))
+    type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, array_type);
+#endif
+
+  return array_elems_type_id;
+}
+
+/* Generate CTF for a typedef.  */
+
+static ctf_id_t
+gen_ctf_typedef (ctf_container_ref ctfc, dw_die_ref tdef)
+{
+  ctf_id_t tdef_type_id, tid;
+  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);
+
+  /* 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;
+}
+
+/* Generate CTF for a type modifier.
+
+   If the given DIE contains a valid C modifier (like _Atomic), which is not
+   supported by CTF, then this function skips the modifier die and continues
+   with the underlying type.
+
+   For all other cases, this function returns a CTF_NULL_TYPEID;
+*/
+
+static ctf_id_t
+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;
+  dw_die_ref qual_type = ctf_get_AT_type (modifier);
+
+  switch (dw_get_die_tag (modifier))
+    {
+    case DW_TAG_const_type: kind = CTF_K_CONST; break;
+    case DW_TAG_volatile_type: kind = CTF_K_VOLATILE; break;
+    case DW_TAG_restrict_type: kind = CTF_K_RESTRICT; break;
+    case DW_TAG_atomic_type: break;
+    default:
+      return CTF_NULL_TYPEID;
+    }
+
+  /* Register the type for which this modifier applies.  */
+  qual_type_id = 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;
+
+  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);
+
+  return modifier_type_id;
+}
+
+/* Generate CTF for a struct type.  */
+
+static ctf_id_t
+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;
+
+  /* An incomplete structure or union type is represented in DWARF by
+     a structure or union DIE that does not have a size attribute and
+     that has a DW_AT_declaration attribute.  This corresponds to a
+     CTF forward type with kind CTF_K_STRUCT.  */
+  if (bit_size == 0 && declaration_p)
+    return ctf_add_forward (ctfc, CTF_ADD_ROOT,
+                           sou_name, kind, sou);
+
+  /* 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);
+
+  /* Now process the struct members.  */
+  {
+    dw_die_ref c;
+
+    c = dw_get_die_child (sou);
+    if (c)
+      do
+       {
+         const char *field_name;
+         dw_die_ref field_type;
+         HOST_WIDE_INT field_location;
+         ctf_id_t field_type_id;
+
+         c = dw_get_die_sib (c);
+
+         field_name = get_AT_string (c, DW_AT_name);
+         field_type = ctf_get_AT_type (c);
+         field_location = ctf_get_AT_data_member_location (c);
+
+         /* Generate the field type.  */
+         field_type_id = gen_ctf_type (ctfc, field_type);
+
+         /* If this is a bit-field, then wrap the field type
+            generated above with a CTF slice.  */
+         if (get_AT (c, DW_AT_bit_offset)
+             || get_AT (c, DW_AT_data_bit_offset))
+           {
+             dw_attr_node *attr;
+             HOST_WIDE_INT bitpos = 0;
+             HOST_WIDE_INT bitsize = ctf_die_bitsize (c);
+             HOST_WIDE_INT bit_offset;
+
+             /* The bit offset is given in bits and it may be
+                negative.  */
+             attr = get_AT (c, DW_AT_bit_offset);
+             if (attr)
+               {
+                 if (AT_class (attr) == dw_val_class_unsigned_const)
+                   bit_offset = AT_unsigned (attr);
+                 else
+                   bit_offset = AT_int (attr);
+
+                 if (BYTES_BIG_ENDIAN)
+                   bitpos = field_location + bit_offset;
+                 else
+                   {
+                     HOST_WIDE_INT bit_size;
+
+                     attr = get_AT (c, DW_AT_byte_size);
+                     if (attr)
+                       /* Explicit size given in bytes.  */
+                       bit_size = AT_unsigned (attr) * 8;
+                     else
+                       /* Infer the size from the member type.  */
+                       bit_size = ctf_die_bitsize (field_type);
+
+                     bitpos = (field_location
+                               + bit_size
+                               - bit_offset
+                               - bitsize);
+                   }
+               }
+
+             /* In DWARF5 a data_bit_offset attribute is given with
+                the offset of the data from the beginning of the
+                struct.  Acknowledge it if present.  */
+             attr = get_AT (c, DW_AT_data_bit_offset);
+             if (attr)
+               bitpos += AT_unsigned (attr);
+
+             field_type_id = ctf_add_slice (ctfc, CTF_ADD_NONROOT,
+                                            field_type_id,
+                                            bitpos - field_location,
+                                            bitsize,
+                                            c);
+           }
+
+         /* Add the field type to the struct or union type.  */
+         ctf_add_member_offset (ctfc, sou,
+                                field_name,
+                                field_type_id,
+                                field_location);
+       }
+      while (c != dw_get_die_child (sou));
+  }
+
+  return sou_type_id;
+}
+
+/* Generate CTF for a function type.  */
+
+static ctf_id_t
+gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
+                      bool from_global_func)
+{
+  const char *function_name = get_AT_string (function, DW_AT_name);
+  dw_die_ref return_type = ctf_get_AT_type (function);
+
+  ctf_funcinfo_t func_info;
+  uint32_t num_args = 0;
+
+  ctf_id_t return_type_id;
+  ctf_id_t function_type_id;
+
+  /* First, add the return type.  */
+  return_type_id = gen_ctf_type (ctfc, return_type);
+  func_info.ctc_return = return_type_id;
+
+  /* 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;
+
+  /* Do a first pass on the formals to determine the number of
+     arguments, and whether the function type gets a varargs.  */
+  {
+    dw_die_ref c;
+
+    c = dw_get_die_child (function);
+    if (c)
+      do
+       {
+         c = dw_get_die_sib (c);
+
+         if (dw_get_die_tag (c) == DW_TAG_formal_parameter)
+           num_args += 1;
+         else if (dw_get_die_tag (c) == DW_TAG_unspecified_parameters)
+           {
+             func_info.ctc_flags |= CTF_FUNC_VARARG;
+             num_args += 1;
+           }
+       }
+      while (c != dw_get_die_child (function));
+  }
+
+  /* Note the number of typed arguments _includes_ the vararg.  */
+  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);
+
+  /* Second pass on formals: generate the CTF types corresponding to
+     them and add them as CTF function args.  */
+  {
+    dw_die_ref c;
+    unsigned int i = 0;
+    const char *arg_name;
+    ctf_id_t arg_type;
+
+    c = dw_get_die_child (function);
+    if (c)
+      do
+       {
+         c = dw_get_die_sib (c);
+
+         if (dw_get_die_tag (c) == DW_TAG_unspecified_parameters)
+           {
+             gcc_assert (i == num_args - 1);
+             /* Add an argument with type 0 and no name.  */
+             ctf_add_function_arg (ctfc, function, "", 0);
+           }
+         else if (dw_get_die_tag (c) == DW_TAG_formal_parameter)
+           {
+             i++;
+             arg_name = get_AT_string (c, DW_AT_name);
+             arg_type = gen_ctf_type (ctfc, ctf_get_AT_type (c));
+             /* Add the argument to the existing CTF function type.  */
+             ctf_add_function_arg (ctfc, function, arg_name, arg_type);
+           }
+         else
+           /* This is a local variable.  Ignore.  */
+           continue;
+       }
+      while (c != dw_get_die_child (function));
+  }
+
+  return function_type_id;
+}
+
+/* Generate CTF for an enumeration type.  */
+
+static ctf_id_t
+gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
+{
+  const char *enum_name = get_AT_string (enumeration, DW_AT_name);
+  unsigned int bit_size = ctf_die_bitsize (enumeration);
+  int declaration_p = get_AT_flag (enumeration, DW_AT_declaration);
+
+  ctf_id_t enumeration_type_id;
+
+  /* If this is an incomplete enum, generate a CTF forward for it and
+     be done.  */
+  if (declaration_p)
+    {
+      gcc_assert (enum_name);
+      return ctf_add_forward (ctfc, CTF_ADD_ROOT, enum_name,
+                             CTF_K_ENUM, enumeration);
+    }
+
+  /* If the size the enumerators is not specified then use the size of
+     the underlying type, which must be a base type.  */
+  if (bit_size == 0)
+    {
+      dw_die_ref type = ctf_get_AT_type (enumeration);
+      bit_size = ctf_die_bitsize (type);
+    }
+
+  /* Generate a CTF type for the enumeration.  */
+  enumeration_type_id = ctf_add_enum (ctfc, CTF_ADD_ROOT,
+                                     enum_name, bit_size / 8, enumeration);
+
+  /* Process the enumerators.  */
+  {
+    dw_die_ref c;
+
+    c = dw_get_die_child (enumeration);
+    if (c)
+      do
+       {
+         const char *enumerator_name;
+         dw_attr_node *enumerator_value;
+         HOST_WIDE_INT value_wide_int;
+
+         c = dw_get_die_sib (c);
+
+         enumerator_name = get_AT_string (c, DW_AT_name);
+         enumerator_value = get_AT (c, DW_AT_const_value);
+
+         /* enumerator_value can be either a signed or an unsigned
+            constant value.  */
+         if (AT_class (enumerator_value) == dw_val_class_unsigned_const
+             || (AT_class (enumerator_value)
+                 == dw_val_class_unsigned_const_implicit))
+           value_wide_int = AT_unsigned (enumerator_value);
+         else
+           value_wide_int = AT_int (enumerator_value);
+
+         ctf_add_enumerator (ctfc, enumeration_type_id,
+                             enumerator_name, value_wide_int, enumeration);
+       }
+      while (c != dw_get_die_child (enumeration));
+  }
+
+  return enumeration_type_id;
+}
+
+/* Add a CTF variable record for the given input DWARF DIE.  */
+
+static void
+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;
+
+  /* Avoid duplicates.  */
+  if (ctf_dvd_lookup (ctfc, die))
+    return;
+
+  /* Add the type of the variable.  */
+  var_type_id = 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);
+  ctfc->ctfc_num_global_objts += 1;
+}
+
+/* Add a CTF function record for the given input DWARF DIE.  */
+
+static void
+gen_ctf_function (ctf_container_ref ctfc, dw_die_ref die)
+{
+  ctf_id_t function_type_id;
+  /* Type de-duplication.
+     Consult the ctfc_types hash before adding the CTF function type.  */
+  if (ctf_type_exists (ctfc, die, &function_type_id))
+    return;
+
+  /* Add the type of the function and update the global functions
+     counter.  Note that DWARF encodes function types in both
+     DW_TAG_subroutine_type and DW_TAG_subprogram in exactly the same
+     way.  */
+  (void) gen_ctf_function_type (ctfc, die, true /* from_global_func */);
+  ctfc->ctfc_num_global_funcs += 1;
+}
+
+/* Add CTF type record(s) for the given input DWARF DIE and return its type id.
+
+   If there is already a CTF type corresponding to the given DIE, then
+   this function returns the type id of the existing type.
+
+   If the given DIE is not recognized as a type, then this function
+   returns CTF_NULL_TYPEID.  */
+
+static ctf_id_t
+gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
+{
+  ctf_id_t type_id;
+  int unrecog_die = false;
+
+  if (ctf_type_exists (ctfc, die, &type_id))
+    return type_id;
+
+  switch (dw_get_die_tag (die))
+    {
+    case DW_TAG_base_type:
+      type_id = gen_ctf_base_type (ctfc, die);
+      break;
+    case DW_TAG_pointer_type:
+      type_id = gen_ctf_pointer_type (ctfc, die);
+      break;
+    case DW_TAG_typedef:
+      type_id = gen_ctf_typedef (ctfc, die);
+      break;
+    case DW_TAG_array_type:
+      type_id = gen_ctf_array_type (ctfc, die);
+      break;
+    case DW_TAG_structure_type:
+      type_id = 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);
+      break;
+    case DW_TAG_subroutine_type:
+      type_id = gen_ctf_function_type (ctfc, die,
+                                      false /* from_global_func */);
+      break;
+    case DW_TAG_enumeration_type:
+      type_id = gen_ctf_enumeration_type (ctfc, die);
+      break;
+    case DW_TAG_atomic_type:
+      /* FALLTHROUGH */
+    case DW_TAG_const_type:
+      /* FALLTHROUGH */
+    case DW_TAG_restrict_type:
+      /* FALLTHROUGH */
+    case DW_TAG_volatile_type:
+      type_id = 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);
+       else
+         type_id = CTF_NULL_TYPEID;
+
+       break;
+      }
+    case DW_TAG_reference_type:
+      type_id = CTF_NULL_TYPEID;
+      break;
+    default:
+      /* Unrecognized DIE.  */
+      unrecog_die = true;
+      type_id = CTF_NULL_TYPEID;
+      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);
+
+  return type_id;
+}
+
+bool
+ctf_do_die (dw_die_ref die)
+{
+  ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+
+  /* Note how we tell the caller to continue traversing children DIEs
+     if this DIE didn't result in CTF records being added.  */
+  if (dw_get_die_tag (die) == DW_TAG_variable)
+    {
+      gen_ctf_variable (tu_ctfc, die);
+      return false;
+    }
+  else if (dw_get_die_tag (die) == DW_TAG_subprogram)
+    {
+      gen_ctf_function (tu_ctfc, die);
+      return false;
+    }
+  else
+    return gen_ctf_type (tu_ctfc, die) == CTF_NULL_TYPEID;
+}
+
+/* Initialize CTF subsystem for CTF debug info generation.  */
+
+void
+ctf_debug_init (void)
+{
+  /* First, initialize the CTF subsystem.  */
+  ctf_init ();
+
+  /* Create a couple of DIE structures that we may need.  */
+  ctf_void_die = new_die_raw (DW_TAG_unspecified_type);
+  add_name_attribute (ctf_void_die, "void");
+  ctf_array_index_die
+    = base_type_die (integer_type_node, 0 /* reverse */);
+  add_name_attribute (ctf_array_index_die, "int");
+  ctf_unknown_die = new_die_raw (DW_TAG_unspecified_type);
+  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 ();
+}
+
+/* Prepare for output and write out the CTF debug information.  */
+
+void
+ctf_debug_finalize (const char *filename, bool btf)
+{
+  if (btf)
+    {
+      btf_output (filename);
+      btf_finalize ();
+    }
+
+  else
+    {
+      /* Emit the collected CTF information.  */
+      ctf_output (filename);
+
+      /* Reset the CTF state.  */
+      ctf_finalize ();
+    }
+}
+
+#include "gt-dwarf2ctf.h"
diff --git a/gcc/dwarf2ctf.h b/gcc/dwarf2ctf.h
new file mode 100644 (file)
index 0000000..a3cf567
--- /dev/null
@@ -0,0 +1,53 @@
+/* dwarf2ctf.h - DWARF interface for CTF/BTF generation.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This file contains declarations and prototypes to define an interface
+   between DWARF and CTF/BTF generation.  */
+
+#ifndef GCC_DWARF2CTF_H
+#define GCC_DWARF2CTF_H 1
+
+#include "dwarf2out.h"
+
+/* Debug Format Interface.  Used in dwarf2out.c.  */
+
+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_finalize (const char *, bool);
+
+/* Wrappers for CTF/BTF to fetch information from GCC DWARF DIE.  Used in
+   ctfc.c.
+
+   A CTF container does not store all debug information internally.  Some of
+   the info is fetched indirectly via the DIE reference available in each CTF
+   container entry.
+
+   These functions will be used by the CTF container to give access to its
+   consumers (CTF/BTF) to various debug information available in DWARF DIE.
+   Direct access to debug information in GCC dwarf structures by the consumers
+   of CTF/BTF information is not ideal.  */
+
+/* Source location information.  */
+
+extern const char * ctf_get_die_loc_file (dw_die_ref);
+extern unsigned int ctf_get_die_loc_line (dw_die_ref);
+extern unsigned int ctf_get_die_loc_col (dw_die_ref);
+
+#endif /* GCC_DWARF2CTF_H */
index e10006c..13998b2 100644 (file)
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "expr.h"
 #include "dwarf2out.h"
+#include "dwarf2ctf.h"
 #include "dwarf2asm.h"
 #include "toplev.h"
 #include "md5.h"
@@ -28332,7 +28333,10 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
   dw_line_info_table *table;
   static var_loc_view lvugid;
 
-  if (debug_info_level < DINFO_LEVEL_TERSE)
+  /* 'line_info_table' information gathering is not needed when the debug
+     info level is set to the lowest value.  Also, the current DWARF-based
+     debug formats do not use this info.  */
+  if (debug_info_level < DINFO_LEVEL_TERSE || !dwarf_debuginfo_p ())
     return;
 
   table = cur_line_info_table;
@@ -31876,6 +31880,10 @@ dwarf2out_finish (const char *filename)
   unsigned char checksum[16];
   char dl_section_ref[MAX_ARTIFICIAL_LABEL_BYTES];
 
+  /* Skip emitting DWARF if not required.  */
+  if (!dwarf_debuginfo_p ())
+    return;
+
   /* Flush out any latecomers to the limbo party.  */
   flush_limbo_die_list ();
 
@@ -32631,6 +32639,19 @@ note_variable_value (dw_die_ref die)
   FOR_EACH_CHILD (die, c, note_variable_value (c));
 }
 
+/* Process DWARF dies for CTF generation.  */
+
+static void
+ctf_debug_do_cu (dw_die_ref die)
+{
+  dw_die_ref c;
+
+  if (!ctf_do_die (die))
+    return;
+
+  FOR_EACH_CHILD (die, c, ctf_do_die (c));
+}
+
 /* Perform any cleanups needed after the early debug generation pass
    has run.  */
 
@@ -32753,6 +32774,20 @@ dwarf2out_early_finish (const char *filename)
       print_die (comp_unit_die (), dump_file);
     }
 
+  /* Generate CTF/BTF debug info.  */
+  if ((ctf_debug_info_level > CTFINFO_LEVEL_NONE
+       || btf_debuginfo_p ()) && lang_GNU_C ())
+    {
+      ctf_debug_init ();
+      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 ());
+      /* Emit CTF/BTF debug info.  */
+      ctf_debug_finalize (filename, btf_debuginfo_p ());
+    }
+
   /* Do not generate DWARF assembler now when not producing LTO bytecode.  */
   if ((!flag_generate_lto && !flag_generate_offload)
       /* FIXME: Disable debug info generation for (PE-)COFF targets since the
index dba0b0a..ac6892d 100644 (file)
@@ -1429,7 +1429,7 @@ static bool
 dwarf2_debug_info_emitted_p (tree decl)
 {
   /* When DWARF2 debug info is not generated internally.  */
-  if (!dwarf_debuginfo_p ())
+  if (!dwarf_debuginfo_p () && !dwarf_based_debuginfo_p ())
     return false;
 
   if (DECL_IGNORED_P (decl))
index 375448e..e43d1de 100644 (file)
@@ -29,7 +29,9 @@ enum debug_info_type
   DINFO_TYPE_DWARF2 = 2,         /* Dwarf v2 debug info.  */
   DINFO_TYPE_XCOFF = 3,                  /* IBM/Xcoff debug info.  */
   DINFO_TYPE_VMS = 4,            /* VMS debug info.  */
-  DINFO_TYPE_MAX = DINFO_TYPE_VMS /* Marker only.  */
+  DINFO_TYPE_CTF = 5,            /* CTF debug info.  */
+  DINFO_TYPE_BTF = 6,            /* BTF debug info.  */
+  DINFO_TYPE_MAX = DINFO_TYPE_BTF /* Marker only.  */
 };
 
 #define NO_DEBUG      (0U)
@@ -41,6 +43,10 @@ enum debug_info_type
 #define XCOFF_DEBUG   (1U << DINFO_TYPE_XCOFF)
 /* Write VMS debug info (using vmsdbgout.c).  */
 #define VMS_DEBUG     (1U << DINFO_TYPE_VMS)
+/* Write CTF debug info (using ctfout.c).  */
+#define CTF_DEBUG     (1U << DINFO_TYPE_CTF)
+/* Write BTF debug info (using btfout.c).  */
+#define BTF_DEBUG     (1U << DINFO_TYPE_BTF)
 /* Note: Adding new definitions to handle -combination- of debug formats,
    like VMS_AND_DWARF2_DEBUG is not recommended.  This definition remains
    here for historical reasons.  */
@@ -56,6 +62,19 @@ enum debug_info_levels
   DINFO_LEVEL_VERBOSE  /* Write normal info plus #define/#undef info.  */
 };
 
+/* CTF debug info levels.
+   CTF debug info levels are untied with DWARF debug info levels because CTF
+   may co-exist with DWARF.  */
+enum ctf_debug_info_levels
+{
+  CTFINFO_LEVEL_NONE = 0,     /* Write no CTF debug info.  */
+  CTFINFO_LEVEL_TERSE = 1,    /* Write CTF information to support tracebacks
+                                only.  Not Implemented.  */
+  CTFINFO_LEVEL_NORMAL = 2    /* Write CTF type information for all entities
+                                (functions, data objects, variables etc.)
+                                at file-scope or global-scope only.  */
+};
+
 /* A major contribution to object and executable size is debug
    information size.  A major contribution to debug information
    size is struct descriptions replicated in several object files.
index cc7b79b..85fd228 100644 (file)
@@ -40,10 +40,19 @@ unsigned int debug_set_count (uint32_t w_symbols);
 
 const char * debug_set_names (uint32_t w_symbols);
 
+/* Return true iff BTF debug info is enabled.  */
+
+extern bool btf_debuginfo_p ();
+
 /* Return true iff DWARF2 debug info is enabled.  */
 
 extern bool dwarf_debuginfo_p ();
 
+/* Return true iff the debug info format is to be generated based on DWARF
+   DIEs (like CTF and BTF debug info formats).  */
+
+extern bool dwarf_based_debuginfo_p ();
+
 extern void strip_off_ending (char *, int);
 extern int base_of_path (const char *path, const char **base_out);
 
index c1fa6d3..d105c9b 100644 (file)
@@ -1727,7 +1727,7 @@ open_base_files (void)
       "target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h",
       "ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h", "omp-general.h",
       "omp-offload.h", "ipa-modref-tree.h", "ipa-modref.h", "symtab-thunks.h",
-      "symtab-clones.h", "diagnostic-spec.h",
+      "symtab-clones.h", "diagnostic-spec.h", "ctfc.h",
       NULL
     };
     const char *const *ifp;
@@ -5202,6 +5202,7 @@ main (int argc, char **argv)
       POS_HERE (do_scalar_typedef ("poly_int64", &pos));
       POS_HERE (do_scalar_typedef ("poly_uint64", &pos));
       POS_HERE (do_scalar_typedef ("uint64_t", &pos));
+      POS_HERE (do_scalar_typedef ("uint32_t", &pos));
       POS_HERE (do_scalar_typedef ("uint8", &pos));
       POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
       POS_HERE (do_scalar_typedef ("jword", &pos));
index 52e9e3a..66262c5 100644 (file)
@@ -42,7 +42,7 @@ static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
 const char *const debug_type_names[] =
 {
-  "none", "stabs", "dwarf-2", "xcoff", "vms"
+  "none", "stabs", "dwarf-2", "xcoff", "vms", "ctf", "btf"
 };
 
 /* Bitmasks of fundamental debug info formats indexed by enum
@@ -50,13 +50,14 @@ const char *const debug_type_names[] =
 
 static uint32_t debug_type_masks[] =
 {
-  NO_DEBUG, DBX_DEBUG, DWARF2_DEBUG, XCOFF_DEBUG, VMS_DEBUG
+  NO_DEBUG, DBX_DEBUG, DWARF2_DEBUG, XCOFF_DEBUG, VMS_DEBUG,
+  CTF_DEBUG, BTF_DEBUG
 };
 
 /* Names of the set of debug formats requested by user.  Updated and accessed
    via debug_set_names.  */
 
-static char df_set_names[sizeof "none stabs dwarf-2 xcoff vms"];
+static char df_set_names[sizeof "none stabs dwarf-2 xcoff vms ctf btf"];
 
 /* Get enum debug_info_type of the specified debug format, for error messages.
    Can be used only for individual debug format types.  */
@@ -126,6 +127,14 @@ debug_set_names (uint32_t w_symbols)
   return df_set_names;
 }
 
+/* Return TRUE iff BTF debug info is enabled.  */
+
+bool
+btf_debuginfo_p ()
+{
+  return (write_symbols & BTF_DEBUG);
+}
+
 /* Return TRUE iff dwarf2 debug info is enabled.  */
 
 bool
@@ -134,6 +143,15 @@ dwarf_debuginfo_p ()
   return (write_symbols & DWARF2_DEBUG);
 }
 
+/* Return true iff the debug info format is to be generated based on DWARF
+   DIEs (like CTF and BTF debug info formats).  */
+
+bool dwarf_based_debuginfo_p ()
+{
+  return ((write_symbols & CTF_DEBUG)
+         || (write_symbols & BTF_DEBUG));
+}
+
 /* Parse the -femit-struct-debug-detailed option value
    and set the flag variables. */
 
@@ -2868,6 +2886,24 @@ common_handle_option (struct gcc_options *opts,
                        loc);
       break;
 
+    case OPT_gbtf:
+      set_debug_level (BTF_DEBUG, false, arg, opts, opts_set, loc);
+      /* set the debug level to level 2, but if already at level 3,
+        don't lower it.  */
+      if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL)
+       opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
+      break;
+
+    case OPT_gctf:
+      set_debug_level (CTF_DEBUG, false, arg, opts, opts_set, loc);
+      /* CTF generation feeds off DWARF dies.  For optimal CTF, switch debug
+        info level to 2.  If off or at level 1, set it to level 2, but if
+        already at level 3, don't lower it.  */
+      if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL
+         && opts->x_ctf_debug_info_level > CTFINFO_LEVEL_NONE)
+       opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
+      break;
+
     case OPT_gdwarf:
       if (arg && strlen (arg) != 0)
         {
@@ -3116,7 +3152,10 @@ set_debug_level (uint32_t dinfo, int extended, const char *arg,
          if (extended == 2)
            {
 #if defined DWARF2_DEBUGGING_INFO || defined DWARF2_LINENO_DEBUGGING_INFO
-             opts->x_write_symbols = DWARF2_DEBUG;
+             if (opts->x_write_symbols & CTF_DEBUG)
+               opts->x_write_symbols |= DWARF2_DEBUG;
+             else
+               opts->x_write_symbols = DWARF2_DEBUG;
 #elif defined DBX_DEBUGGING_INFO
              opts->x_write_symbols = DBX_DEBUG;
 #endif
@@ -3125,41 +3164,81 @@ set_debug_level (uint32_t dinfo, int extended, const char *arg,
          if (opts->x_write_symbols == NO_DEBUG)
            warning_at (loc, 0, "target system does not support debug output");
        }
+      else if ((opts->x_write_symbols & CTF_DEBUG)
+              || (opts->x_write_symbols & BTF_DEBUG))
+       {
+         opts->x_write_symbols |= DWARF2_DEBUG;
+         opts_set->x_write_symbols |= DWARF2_DEBUG;
+       }
     }
   else
     {
-      /* Does it conflict with an already selected debug format?  */
-      if (opts_set->x_write_symbols != NO_DEBUG
-         && opts->x_write_symbols != NO_DEBUG
-         && dinfo != opts->x_write_symbols)
+      /* Make and retain the choice if both CTF and DWARF debug info are to
+        be generated.  */
+      if (((dinfo == DWARF2_DEBUG) || (dinfo == CTF_DEBUG))
+         && ((opts->x_write_symbols == (DWARF2_DEBUG|CTF_DEBUG))
+             || (opts->x_write_symbols == DWARF2_DEBUG)
+             || (opts->x_write_symbols == CTF_DEBUG)))
        {
-         gcc_assert (debug_set_count (dinfo) <= 1);
-         error_at (loc, "debug format %qs conflicts with prior selection",
-                   debug_type_names[debug_set_to_format (dinfo)]);
+         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 |= dinfo;
+         opts_set->x_write_symbols |= dinfo;
+       }
+      else
+       {
+         /* Does it conflict with an already selected debug format?  */
+         if (opts_set->x_write_symbols != NO_DEBUG
+             && opts->x_write_symbols != NO_DEBUG
+             && dinfo != opts->x_write_symbols)
+           {
+             gcc_assert (debug_set_count (dinfo) <= 1);
+             error_at (loc, "debug format %qs conflicts with prior selection",
+                       debug_type_names[debug_set_to_format (dinfo)]);
+           }
+         opts->x_write_symbols = dinfo;
+         opts_set->x_write_symbols = dinfo;
        }
-
-      opts->x_write_symbols = dinfo;
-      opts_set->x_write_symbols = dinfo;
     }
 
-  /* A debug flag without a level defaults to level 2.
-     If off or at level 1, set it to level 2, but if already
-     at level 3, don't lower it.  */ 
-  if (*arg == '\0')
-    {
-      if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL)
-       opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
-    }
-  else
+  if (dinfo != BTF_DEBUG)
     {
-      int argval = integral_argument (arg);
-      if (argval == -1)
-       error_at (loc, "unrecognized debug output level %qs", arg);
-      else if (argval > 3)
-       error_at (loc, "debug output level %qs is too high", arg);
+      /* A debug flag without a level defaults to level 2.
+        If off or at level 1, set it to level 2, but if already
+        at level 3, don't lower it.  */
+      if (*arg == '\0')
+       {
+         if (dinfo == CTF_DEBUG)
+           opts->x_ctf_debug_info_level = CTFINFO_LEVEL_NORMAL;
+         else if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL)
+           opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
+       }
       else
-       opts->x_debug_info_level = (enum debug_info_levels) argval;
+       {
+         int argval = integral_argument (arg);
+         if (argval == -1)
+           error_at (loc, "unrecognized debug output level %qs", arg);
+         else if (argval > 3)
+           error_at (loc, "debug output level %qs is too high", arg);
+         else
+           {
+             if (dinfo == CTF_DEBUG)
+               opts->x_ctf_debug_info_level
+                 = (enum ctf_debug_info_levels) argval;
+             else
+               opts->x_debug_info_level = (enum debug_info_levels) argval;
+           }
+       }
     }
+  else if (*arg != '\0')
+    error_at (loc, "unrecognized btf debug output level %qs", arg);
 }
 
 /* Arrange to dump core on error for diagnostic context DC.  (The
index a785522..43f1f7d 100644 (file)
@@ -1232,6 +1232,7 @@ parse_alignment_opts (void)
 static void
 process_options (void)
 {
+  const char *language_string = lang_hooks.name;
   /* Just in case lang_hooks.post_options ends up calling a debug_hook.
      This can happen with incorrect pre-processed input. */
   debug_hooks = &do_nothing_debug_hooks;
@@ -1415,6 +1416,17 @@ process_options (void)
        debug_info_level = DINFO_LEVEL_NONE;
     }
 
+  /* CTF is supported for only C at this time.
+     Compiling with -flto results in frontend language of GNU GIMPLE.  */
+  if (!lang_GNU_C ()
+      && ctf_debug_info_level > CTFINFO_LEVEL_NONE)
+    {
+      inform (UNKNOWN_LOCATION,
+             "CTF debug info requested, but not supported for %qs frontend",
+             language_string);
+      ctf_debug_info_level = CTFINFO_LEVEL_NONE;
+    }
+
   if (flag_dump_final_insns && !flag_syntax_only && !no_backend)
     {
       FILE *final_output = fopen (flag_dump_final_insns, "w");
@@ -1436,7 +1448,8 @@ process_options (void)
 
   /* A lot of code assumes write_symbols == NO_DEBUG if the debugging
      level is 0.  */
-  if (debug_info_level == DINFO_LEVEL_NONE)
+  if (debug_info_level == DINFO_LEVEL_NONE
+      && ctf_debug_info_level == CTFINFO_LEVEL_NONE)
     write_symbols = NO_DEBUG;
 
   if (write_symbols == NO_DEBUG)
@@ -1450,7 +1463,8 @@ process_options (void)
     debug_hooks = &xcoff_debug_hooks;
 #endif
 #ifdef DWARF2_DEBUGGING_INFO
-  else if (write_symbols == DWARF2_DEBUG)
+  else if (dwarf_debuginfo_p ()
+          || dwarf_based_debuginfo_p ())
     debug_hooks = &dwarf2_debug_hooks;
 #endif
 #ifdef VMS_DEBUGGING_INFO
@@ -1472,6 +1486,7 @@ process_options (void)
   /* We know which debug output will be used so we can set flag_var_tracking
      and flag_var_tracking_uninit if the user has not specified them.  */
   if (debug_info_level < DINFO_LEVEL_NORMAL
+      || !dwarf_debuginfo_p ()
       || debug_hooks->var_location == do_nothing_debug_hooks.var_location)
     {
       if (flag_var_tracking == 1
diff --git a/include/btf.h b/include/btf.h
new file mode 100644 (file)
index 0000000..3b1a4c3
--- /dev/null
@@ -0,0 +1,196 @@
+/* Declarations and definitions relating to the BPF Type Format (BTF).
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file is derived from the BTF specification described in the
+   Linux kernel source tree (linux/Documentation/bpf/btf.rst).  */
+
+#ifndef _BTF_H_
+#define _BTF_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* BTF magic number to identify header, endianness.  */
+#define BTF_MAGIC      0xeb9f
+/* Data format version number.  */
+#define BTF_VERSION    1
+
+struct btf_header
+{
+  uint16_t magic;      /* Magic number (BTF_MAGIC).  */
+  uint8_t  version;    /* Data format version (BTF_VERSION).  */
+  uint8_t  flags;      /* Flags. Currently unused.  */
+  uint32_t hdr_len;    /* Length of this header (sizeof (struct btf_header)).  */
+
+  /* Following offsets are relative to the end of this header.  */
+  uint32_t type_off;   /* Offset of type section, in bytes.  */
+  uint32_t type_len;   /* Length of type section, in bytes.  */
+  uint32_t str_off;    /* Offset of string section, in bytes.  */
+  uint32_t str_len;    /* Length of string section, in bytes.  */
+};
+
+/* Maximum type identifier.  */
+#define BTF_MAX_TYPE   0x000fffff
+/* Maximum offset into the string section.  */
+#define BTF_MAX_NAME_OFFSET    0x00ffffff
+/* Maximum number of struct, union, enum members or func args.  */
+#define BTF_MAX_VLEN   0xffff
+
+struct btf_type
+{
+  uint32_t name_off;   /* Offset in string section of type name.  */
+  uint32_t info;       /* Encoded kind, variant length, kind flag:
+                          - bits  0-15: vlen
+                          - bits 16-23: unused
+                          - bits 24-27: kind
+                          - bits 28-30: unused
+                          - bit     31: kind_flag
+                          See accessor macros below.  */
+
+  /* SIZE is used by INT, ENUM, STRUCT, UNION, DATASEC kinds.
+     TYPE is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, FUNC,
+     FUNC_PROTO and VAR kinds.  */
+  union
+  {
+    uint32_t size;     /* Size of the entire type, in bytes.  */
+    uint32_t type;     /* A type_id referring to another type.  */
+  };
+};
+
+/* The folloing macros access the information encoded in btf_type.info.  */
+/* Type kind. See below.  */
+#define BTF_INFO_KIND(info)    (((info) >> 24) & 0x0f)
+/* Number of entries of variable length data following certain type kinds.
+   For example, number of structure members, number of function parameters.  */
+#define BTF_INFO_VLEN(info)    ((info) & 0xffff)
+/* For BTF_KIND_FWD, 1 if forward to union, 0 if forward to struct.
+   For BTF_KIND_STRUCT and BTF_KIND_UNION, 1 if the struct/union contains
+   a bitfield.  */
+#define BTF_INFO_KFLAG(info)   ((info) >> 31)
+
+/* Encoding for struct btf_type.info.  */
+#define BTF_TYPE_INFO(kind, kflag, vlen) \
+  ((((kflag) ? 1 : 0 ) << 31) | ((kind) << 24) | ((vlen) & 0xffff))
+
+#define BTF_KIND_UNKN          0       /* Unknown or invalid.  */
+#define BTF_KIND_INT           1       /* Integer.  */
+#define BTF_KIND_PTR           2       /* Pointer.  */
+#define BTF_KIND_ARRAY         3       /* Array.  */
+#define BTF_KIND_STRUCT                4       /* Struct.  */
+#define BTF_KIND_UNION         5       /* Union.  */
+#define BTF_KIND_ENUM          6       /* Enumeration.  */
+#define BTF_KIND_FWD           7       /* Forward.  */
+#define BTF_KIND_TYPEDEF       8       /* Typedef.  */
+#define BTF_KIND_VOLATILE      9       /* Referenced type is volatile.  */
+#define BTF_KIND_CONST         10      /* Referenced type is const.  */
+#define BTF_KIND_RESTRICT      11      /* Restrict.  */
+#define BTF_KIND_FUNC          12      /* Subprogram.  */
+#define BTF_KIND_FUNC_PROTO    13      /* Function Prototype.  */
+#define BTF_KIND_VAR           14      /* Variable.  */
+#define BTF_KIND_DATASEC       15      /* Section such as .bss or .data.  */
+#define BTF_KIND_MAX           BTF_KIND_DATASEC
+#define NR_BTF_KINDS           (BTF_KIND_MAX + 1)
+
+/* For some BTF_KINDs, struct btf_type is immediately followed by
+   additional data describing the type.  */
+
+/* BTF_KIND_INT is followed by a 32-bit word, with the following
+   bit arrangement.  */
+#define BTF_INT_ENCODING(VAL)  (((VAL) & 0x0f000000) >> 24)
+#define BTF_INT_OFFSET(VAL)    (((VAL) & 0x00ff0000) >> 16)
+#define BTF_INT_BITS(VAL)      ((VAL)  & 0x000000ff)
+
+#define BTF_INT_DATA(encoding, offset, bits) \
+  ((((encoding) & 0x0f) << 24) | (((offset) & 0xff) << 16) | ((bits) & 0xff))
+
+/* BTF_INT_ENCODING holds the following attribute flags.  */
+#define BTF_INT_SIGNED         (1 << 0)
+#define BTF_INT_CHAR   (1 << 1)
+#define BTF_INT_BOOL   (1 << 2)
+
+/* BTF_KIND_ENUM is followed by VLEN struct btf_enum entries,
+   which describe the enumerators. Note that BTF currently only
+   supports signed 32-bit enumerator values.  */
+struct btf_enum
+{
+  uint32_t name_off;   /* Offset in string section of enumerator name.  */
+  int32_t  val;                /* Enumerator value.  */
+};
+
+/* BTF_KIND_ARRAY is followed by a single struct btf_array.  */
+struct btf_array
+{
+  uint32_t type;       /* Type of array elements.  */
+  uint32_t index_type; /* Type of array index.  */
+  uint32_t nelems;     /* Number of elements. 0 for unsized/variable length.  */
+};
+
+/* BTF_KIND_STRUCT and BTF_KIND_UNION are followed by VLEN
+   struct btf_member.  */
+struct btf_member
+{
+  uint32_t name_off;   /* Offset in string section of member name.  */
+  uint32_t type;       /* Type of member.  */
+  uint32_t offset;     /* If the type info kind_flag is set, this contains
+                          both the member bitfield size and bit offset,
+                          according to the macros below. If kind_flag is not
+                          set, offset contains only the bit offset (from the
+                          beginning of the struct).  */
+};
+
+/* If struct or union type info kind_flag is set, used to access member
+   bitfield size from btf_member.offset.  */
+#define BTF_MEMBER_BITFIELD_SIZE (val)         ((val) >> 24)
+/* If struct or union type info kind_flag is set, used to access member
+   bit offset from btf_member.offset.  */
+#define BTF_MEMBER_BIT_OFFSET (val)    ((val) & 0x00ffffff)
+
+/* BTF_KIND_FUNC_PROTO is followed by VLEN struct btf_param entries, which
+   describe the types of the function parameters.  */
+struct btf_param
+{
+  uint32_t name_off;   /* Offset in string section of parameter name.  */
+  uint32_t type;       /* Type of parameter.  */
+};
+
+/* BTF_KIND_VAR is followed by a single struct btf_var, which describes
+   information about the variable.  */
+struct btf_var
+{
+  uint32_t linkage;    /* Currently only 0=static or 1=global.  */
+};
+
+/* BTF_KIND_DATASEC is followed by VLEN struct btf_var_secinfo entries,
+   which describe all BTF_KIND_VAR types contained in the section.  */
+struct btf_var_secinfo
+{
+  uint32_t type;       /* Type of variable.  */
+  uint32_t offset;     /* In-section offset of variable (in bytes).  */
+  uint32_t size;       /* Size (in bytes) of variable.  */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BTF_H_ */
diff --git a/include/ctf.h b/include/ctf.h
new file mode 100644 (file)
index 0000000..91b03f7
--- /dev/null
@@ -0,0 +1,520 @@
+/* CTF format description.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef        _CTF_H
+#define        _CTF_H
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* CTF - Compact ANSI-C Type Format
+
+   This file format can be used to compactly represent the information needed
+   by a debugger to interpret the ANSI-C types used by a given program.
+   Traditionally, this kind of information is generated by the compiler when
+   invoked with the -g flag and is stored in "stabs" strings or in the more
+   modern DWARF format.  CTF provides a representation of only the information
+   that is relevant to debugging a complex, optimized C program such as the
+   operating system kernel in a form that is significantly more compact than
+   the equivalent stabs or DWARF representation.  The format is data-model
+   independent, so consumers do not need different code depending on whether
+   they are 32-bit or 64-bit programs; libctf automatically compensates for
+   endianness variations.  CTF assumes that a standard ELF symbol table is
+   available for use in the debugger, and uses the structure and data of the
+   symbol table to avoid storing redundant information.  The CTF data may be
+   compressed on disk or in memory, indicated by a bit in the header.  CTF may
+   be interpreted in a raw disk file, or it may be stored in an ELF section,
+   typically named .ctf.  Data structures are aligned so that a raw CTF file or
+   CTF ELF section may be manipulated using mmap(2).
+
+   The CTF file or section itself has the following structure:
+
+   +--------+--------+---------+----------+--------+----------+...
+   |  file  |  type  |  data   | function | object | function |...
+   | header | labels | objects |   info   | index  |  index   |...
+   +--------+--------+---------+----------+--------+----------+...
+
+   ...+----------+-------+--------+
+   ...| variable | data  | string |
+   ...|   info   | types | table  |
+      +----------+-------+--------+
+
+   The file header stores a magic number and version information, encoding
+   flags, and the byte offset of each of the sections relative to the end of the
+   header itself.  If the CTF data has been uniquified against another set of
+   CTF data, a reference to that data also appears in the the header.  This
+   reference is the name of the label corresponding to the types uniquified
+   against.
+
+   Following the header is a list of labels, used to group the types included in
+   the data types section.  Each label is accompanied by a type ID i.  A given
+   label refers to the group of types whose IDs are in the range [0, i].
+
+   Data object and function records (collectively, "symtypetabs") are stored in
+   the same order as they appear in the corresponding symbol table, except that
+   symbols marked SHN_UNDEF are not stored and symbols that have no type data
+   are padded out with zeroes.  For each entry in these tables, the type ID (a
+   small integer) is recorded.  (Functions get CTF_K_FUNCTION types, just like
+   data objects that are function pointers.)
+
+   For situations in which the order of the symbols in the symtab is not known,
+   or most symbols have no type in this dict and most entries would be
+   zero-pads, a pair of optional indexes follow the data object and function
+   info sections: each of these is an array of strtab indexes, mapped 1:1 to the
+   corresponding data object / function info section, giving each entry in those
+   sections a name so that the linker can correlate them with final symtab
+   entries and reorder them accordingly (dropping the indexes in the process).
+
+   Variable records (as distinct from data objects) provide a modicum of support
+   for non-ELF systems, mapping a variable name to a CTF type ID.  The variable
+   names are sorted into ASCIIbetical order, permitting binary searching.  We do
+   not define how the consumer maps these variable names to addresses or
+   anything else, or indeed what these names represent: they might be names
+   looked up at runtime via dlsym() or names extracted at runtime by a debugger
+   or anything else the consumer likes.  Variable records with identically-
+   named entries in the data object section are removed.
+
+   The data types section is a list of variable size records that represent each
+   type, in order by their ID.  The types themselves form a directed graph,
+   where each node may contain one or more outgoing edges to other type nodes,
+   denoted by their ID.  Most type nodes are standalone or point backwards to
+   earlier nodes, but this is not required: nodes can point to later nodes,
+   particularly structure and union members.
+
+   Strings are recorded as a string table ID (0 or 1) and a byte offset into the
+   string table.  String table 0 is the internal CTF string table.  String table
+   1 is the external string table, which is the string table associated with the
+   ELF dynamic symbol table for this object.  CTF does not record any strings
+   that are already in the symbol table, and the CTF string table does not
+   contain any duplicated strings.
+
+   If the CTF data has been merged with another parent CTF object, some outgoing
+   edges may refer to type nodes that exist in another CTF object.  The debugger
+   and libctf library are responsible for connecting the appropriate objects
+   together so that the full set of types can be explored and manipulated.
+
+   This connection is done purely using the ctf_import() function.  The
+   ctf_archive machinery (and thus ctf_open et al) automatically imports archive
+   members named ".ctf" into child dicts if available in the same archive, to
+   match the relationship set up by the linker, but callers can call ctf_import
+   themselves as well if need be, if they know a different relationship is in
+   force.  */
+
+#define CTF_MAX_TYPE   0xfffffffe      /* Max type identifier value.  */
+#define CTF_MAX_PTYPE  0x7fffffff      /* Max parent type identifier value.  */
+#define CTF_MAX_NAME 0x7fffffff                /* Max offset into a string table.  */
+#define CTF_MAX_VLEN   0xffffff /* Max struct, union, enum members or args.  */
+
+/* See ctf_type_t */
+#define CTF_MAX_SIZE   0xfffffffe      /* Max size of a v2 type in bytes. */
+#define CTF_LSIZE_SENT 0xffffffff      /* Sentinel for v2 ctt_size.  */
+
+  /* Start of actual data structure definitions.
+
+     Every field in these structures must have corresponding code in the
+     endianness-swapping machinery in libctf/ctf-open.c.  */
+
+typedef struct ctf_preamble
+{
+  unsigned short ctp_magic;    /* Magic number (CTF_MAGIC).  */
+  unsigned char ctp_version;   /* Data format version number (CTF_VERSION).  */
+  unsigned char ctp_flags;     /* Flags (see below).  */
+} ctf_preamble_t;
+
+typedef struct ctf_header
+{
+  ctf_preamble_t cth_preamble;
+  uint32_t cth_parlabel;       /* Ref to name of parent lbl uniq'd against.  */
+  uint32_t cth_parname;                /* Ref to basename of parent.  */
+  uint32_t cth_cuname;         /* Ref to CU name (may be 0).  */
+  uint32_t cth_lbloff;         /* Offset of label section.  */
+  uint32_t cth_objtoff;                /* Offset of object section.  */
+  uint32_t cth_funcoff;                /* Offset of function section.  */
+  uint32_t cth_objtidxoff;     /* Offset of object index section.  */
+  uint32_t cth_funcidxoff;     /* Offset of function index section.  */
+  uint32_t cth_varoff;         /* Offset of variable section.  */
+  uint32_t cth_typeoff;                /* Offset of type section.  */
+  uint32_t cth_stroff;         /* Offset of string section.  */
+  uint32_t cth_strlen;         /* Length of string section in bytes.  */
+} ctf_header_t;
+
+#define cth_magic   cth_preamble.ctp_magic
+#define cth_version cth_preamble.ctp_version
+#define cth_flags   cth_preamble.ctp_flags
+
+#define CTF_MAGIC      0xdff2  /* Magic number identifying header.  */
+
+/* Data format version number.  */
+
+/* v1 upgraded to a later version is not quite the same as the native form,
+   because the boundary between parent and child types is different but not
+   recorded anywhere, and you can write it out again via ctf_compress_write(),
+   so we must track whether the thing was originally v1 or not.  If we were
+   writing the header from scratch, we would add a *pair* of version number
+   fields to allow for this, but this will do for now.  (A flag will not do,
+   because we need to encode both the version we came from and the version we
+   went to, not just "we were upgraded".) */
+
+# define CTF_VERSION_1 1
+# define CTF_VERSION_1_UPGRADED_3 2
+# define CTF_VERSION_2 3
+
+/* Note: some flags may be valid only in particular format versions.  */
+
+#define CTF_VERSION_3 4
+#define CTF_VERSION CTF_VERSION_3 /* Current version.  */
+
+#define CTF_F_COMPRESS 0x1     /* Data buffer is compressed by libctf.  */
+#define CTF_F_NEWFUNCINFO 0x2  /* New v3 func info section format.  */
+
+typedef struct ctf_lblent
+{
+  uint32_t ctl_label;          /* Ref to name of label.  */
+  uint32_t ctl_type;           /* Last type associated with this label.  */
+} ctf_lblent_t;
+
+typedef struct ctf_varent
+{
+  uint32_t ctv_name;           /* Reference to name in string table.  */
+  uint32_t ctv_type;           /* Index of type of this variable.  */
+} ctf_varent_t;
+
+/* In format v2, type sizes, measured in bytes, come in two flavours.  Nearly
+   all of them fit into a (UINT_MAX - 1), and thus can be stored in the ctt_size
+   member of a ctf_stype_t.  The maximum value for these sizes is CTF_MAX_SIZE.
+   Types larger than this must be stored in the ctf_lsize member of a
+   ctf_type_t.  Use of this member is indicated by the presence of
+   CTF_LSIZE_SENT in ctt_size.  */
+
+typedef struct ctf_stype
+{
+  uint32_t ctt_name;           /* Reference to name in string table.  */
+  uint32_t ctt_info;           /* Encoded kind, variant length (see below).  */
+#ifndef __GNUC__
+  union
+  {
+    uint32_t _size;            /* Size of entire type in bytes.  */
+    uint32_t _type;            /* Reference to another type.  */
+  } _u;
+#else
+  __extension__
+  union
+  {
+    uint32_t ctt_size;         /* Size of entire type in bytes.  */
+    uint32_t ctt_type;         /* Reference to another type.  */
+  };
+#endif
+} ctf_stype_t;
+
+typedef struct ctf_type
+{
+  uint32_t ctt_name;           /* Reference to name in string table.  */
+  uint32_t ctt_info;           /* Encoded kind, variant length (see below).  */
+#ifndef __GNUC__
+union
+  {
+    uint32_t _size;            /* Always CTF_LSIZE_SENT.  */
+    uint32_t _type;            /* Do not use.  */
+  } _u;
+#else
+  __extension__
+  union
+  {
+    uint32_t ctt_size;         /* Always CTF_LSIZE_SENT.  */
+    uint32_t ctt_type;         /* Do not use.  */
+  };
+#endif
+  uint32_t ctt_lsizehi;                /* High 32 bits of type size in bytes.  */
+  uint32_t ctt_lsizelo;                /* Low 32 bits of type size in bytes.  */
+} ctf_type_t;
+
+#ifndef __GNUC__
+#define ctt_size _u._size      /* For fundamental types that have a size.  */
+#define ctt_type _u._type      /* For types that reference another type.  */
+#endif
+
+/* The following macros and inline functions compose and decompose values for
+   ctt_info and ctt_name, as well as other structures that contain name
+   references.  Use outside libdtrace-ctf itself is explicitly for access to CTF
+   files directly: types returned from the library will always appear to be
+   CTF_V2.
+
+   v1: (transparently upgraded to v2 at open time: may be compiled out of the
+   library)
+               ------------------------
+   ctt_info:   | kind | isroot | vlen |
+               ------------------------
+               15   11    10    9     0
+
+   v2:
+               ------------------------
+   ctt_info:   | kind | isroot | vlen |
+               ------------------------
+               31    26    25  24     0
+
+   CTF_V1 and V2 _INFO_VLEN have the same interface:
+
+   kind = CTF_*_INFO_KIND(c.ctt_info);     <-- CTF_K_* value (see below)
+   vlen = CTF_*_INFO_VLEN(fp, c.ctt_info); <-- length of variable data list
+
+   stid = CTF_NAME_STID(c.ctt_name);     <-- string table id number (0 or 1)
+   offset = CTF_NAME_OFFSET(c.ctt_name); <-- string table byte offset
+
+   c.ctt_info = CTF_TYPE_INFO(kind, vlen);
+   c.ctt_name = CTF_TYPE_NAME(stid, offset);  */
+
+#define CTF_V1_INFO_KIND(info)         (((info) & 0xf800) >> 11)
+#define CTF_V1_INFO_ISROOT(info)       (((info) & 0x0400) >> 10)
+#define CTF_V1_INFO_VLEN(info)         (((info) & CTF_MAX_VLEN_V1))
+
+#define CTF_V2_INFO_KIND(info)         (((info) & 0xfc000000) >> 26)
+#define CTF_V2_INFO_ISROOT(info)       (((info) & 0x2000000) >> 25)
+#define CTF_V2_INFO_VLEN(info)         (((info) & CTF_MAX_VLEN))
+
+#define CTF_NAME_STID(name)            ((name) >> 31)
+#define CTF_NAME_OFFSET(name)          ((name) & CTF_MAX_NAME)
+#define CTF_SET_STID(name, stid)       ((name) | ((unsigned int) stid) << 31)
+
+/* V2 only. */
+#define CTF_TYPE_INFO(kind, isroot, vlen) \
+       (((kind) << 26) | (((isroot) ? 1 : 0) << 25) | ((vlen) & CTF_MAX_VLEN))
+
+#define CTF_TYPE_NAME(stid, offset) \
+       (((stid) << 31) | ((offset) & CTF_MAX_NAME))
+
+/* The next set of macros are for public consumption only.  Not used internally,
+   since the relevant type boundary is dependent upon the version of the file at
+   *opening* time, not the version after transparent upgrade.  Use
+   ctf_type_isparent() / ctf_type_ischild() for that.  */
+
+#define CTF_V2_TYPE_ISPARENT(fp, id)   ((id) <= CTF_MAX_PTYPE)
+#define CTF_V2_TYPE_ISCHILD(fp, id)    ((id) > CTF_MAX_PTYPE)
+#define CTF_V2_TYPE_TO_INDEX(id)       ((id) & CTF_MAX_PTYPE)
+#define CTF_V2_INDEX_TO_TYPE(id, child) ((child) ? ((id) | (CTF_MAX_PTYPE+1)) : (id))
+
+#define CTF_V1_TYPE_ISPARENT(fp, id)   ((id) <= CTF_MAX_PTYPE_V1)
+#define CTF_V1_TYPE_ISCHILD(fp, id)    ((id) > CTF_MAX_PTYPE_V1)
+#define CTF_V1_TYPE_TO_INDEX(id)       ((id) & CTF_MAX_PTYPE_V1)
+#define CTF_V1_INDEX_TO_TYPE(id, child) ((child) ? ((id) | (CTF_MAX_PTYPE_V1+1)) : (id))
+
+/* Valid for both V1 and V2. */
+#define CTF_TYPE_LSIZE(cttp) \
+       (((uint64_t)(cttp)->ctt_lsizehi) << 32 | (cttp)->ctt_lsizelo)
+#define CTF_SIZE_TO_LSIZE_HI(size)     ((uint32_t)((uint64_t)(size) >> 32))
+#define CTF_SIZE_TO_LSIZE_LO(size)     ((uint32_t)(size))
+
+#define CTF_STRTAB_0   0       /* String table id 0 (in-CTF).  */
+#define CTF_STRTAB_1   1       /* String table id 1 (ELF strtab).  */
+
+/* Values for CTF_TYPE_KIND().  If the kind has an associated data list,
+   CTF_INFO_VLEN() will extract the number of elements in the list, and
+   the type of each element is shown in the comments below. */
+
+#define CTF_K_UNKNOWN  0       /* Unknown type (used for padding and
+                                  unrepresentable types).  */
+#define CTF_K_INTEGER  1       /* Variant data is CTF_INT_DATA (see below).  */
+#define CTF_K_FLOAT    2       /* Variant data is CTF_FP_DATA (see below).  */
+#define CTF_K_POINTER  3       /* ctt_type is referenced type.  */
+#define CTF_K_ARRAY    4       /* Variant data is single ctf_array_t.  */
+#define CTF_K_FUNCTION 5       /* ctt_type is return type, variant data is
+                                  list of argument types (unsigned short's for v1,
+                                  uint32_t's for v2).  */
+#define CTF_K_STRUCT   6       /* Variant data is list of ctf_member_t's.  */
+#define CTF_K_UNION    7       /* Variant data is list of ctf_member_t's.  */
+#define CTF_K_ENUM     8       /* Variant data is list of ctf_enum_t's.  */
+#define CTF_K_FORWARD  9       /* No additional data; ctt_name is tag.  */
+#define CTF_K_TYPEDEF  10      /* ctt_type is referenced type.  */
+#define CTF_K_VOLATILE 11      /* ctt_type is base type.  */
+#define CTF_K_CONST    12      /* ctt_type is base type.  */
+#define CTF_K_RESTRICT 13      /* ctt_type is base type.  */
+#define CTF_K_SLICE    14      /* Variant data is a ctf_slice_t.  */
+
+#define CTF_K_MAX      63      /* Maximum possible (V2) CTF_K_* value.  */
+
+/* Values for ctt_type when kind is CTF_K_INTEGER.  The flags, offset in bits,
+   and size in bits are encoded as a single word using the following macros.
+   (However, you can also encode the offset and bitness in a slice.)  */
+
+#define CTF_INT_ENCODING(data) (((data) & 0xff000000) >> 24)
+#define CTF_INT_OFFSET(data)   (((data) & 0x00ff0000) >> 16)
+#define CTF_INT_BITS(data)     (((data) & 0x0000ffff))
+
+#define CTF_INT_DATA(encoding, offset, bits) \
+       (((encoding) << 24) | ((offset) << 16) | (bits))
+
+#define CTF_INT_SIGNED 0x01    /* Integer is signed (otherwise unsigned).  */
+#define CTF_INT_CHAR   0x02    /* Character display format.  */
+#define CTF_INT_BOOL   0x04    /* Boolean display format.  */
+#define CTF_INT_VARARGS        0x08    /* Varargs display format.  */
+
+/* Use CTF_CHAR to produce a char that agrees with the system's native
+   char signedness.  */
+#if CHAR_MIN == 0
+# define CTF_CHAR (CTF_INT_CHAR)
+#else
+# define CTF_CHAR (CTF_INT_CHAR | CTF_INT_SIGNED)
+#endif
+
+/* Values for ctt_type when kind is CTF_K_FLOAT.  The encoding, offset in bits,
+   and size in bits are encoded as a single word using the following macros.
+   (However, you can also encode the offset and bitness in a slice.)  */
+
+#define CTF_FP_ENCODING(data)  (((data) & 0xff000000) >> 24)
+#define CTF_FP_OFFSET(data)    (((data) & 0x00ff0000) >> 16)
+#define CTF_FP_BITS(data)      (((data) & 0x0000ffff))
+
+#define CTF_FP_DATA(encoding, offset, bits) \
+       (((encoding) << 24) | ((offset) << 16) | (bits))
+
+/* Variant data when kind is CTF_K_FLOAT is an encoding in the top eight bits.  */
+#define CTF_FP_ENCODING(data)  (((data) & 0xff000000) >> 24)
+
+#define CTF_FP_SINGLE  1       /* IEEE 32-bit float encoding.  */
+#define CTF_FP_DOUBLE  2       /* IEEE 64-bit float encoding.  */
+#define CTF_FP_CPLX    3       /* Complex encoding.  */
+#define CTF_FP_DCPLX   4       /* Double complex encoding.  */
+#define CTF_FP_LDCPLX  5       /* Long double complex encoding.  */
+#define CTF_FP_LDOUBLE 6       /* Long double encoding.  */
+#define CTF_FP_INTRVL  7       /* Interval (2x32-bit) encoding.  */
+#define CTF_FP_DINTRVL 8       /* Double interval (2x64-bit) encoding.  */
+#define CTF_FP_LDINTRVL        9       /* Long double interval (2x128-bit) encoding.  */
+#define CTF_FP_IMAGRY  10      /* Imaginary (32-bit) encoding.  */
+#define CTF_FP_DIMAGRY 11      /* Long imaginary (64-bit) encoding.  */
+#define CTF_FP_LDIMAGRY        12      /* Long double imaginary (128-bit) encoding.  */
+
+#define CTF_FP_MAX     12      /* Maximum possible CTF_FP_* value */
+
+/* A slice increases the offset and reduces the bitness of the referenced
+   ctt_type, which must be a type which has an encoding (fp, int, or enum).  We
+   also store the referenced type in here, because it is easier to keep the
+   ctt_size correct for the slice than to shuffle the size into here and keep
+   the ctt_type where it is for other types.
+
+   In a future version, where we loosen requirements on alignment in the CTF
+   file, the cts_offset and cts_bits will be chars: but for now they must be
+   shorts or everything after a slice will become unaligned.  */
+
+typedef struct ctf_slice
+{
+  uint32_t cts_type;
+  unsigned short cts_offset;
+  unsigned short cts_bits;
+} ctf_slice_t;
+
+typedef struct ctf_array
+{
+  uint32_t cta_contents;       /* Reference to type of array contents.  */
+  uint32_t cta_index;          /* Reference to type of array index.  */
+  uint32_t cta_nelems;         /* Number of elements.  */
+} ctf_array_t;
+
+/* Most structure members have bit offsets that can be expressed using a short.
+   Some don't.  ctf_member_t is used for structs which cannot contain any of
+   these large offsets, whereas ctf_lmember_t is used in the latter case.  If
+   any member of a given struct has an offset that cannot be expressed using a
+   uint32_t, all members will be stored as type ctf_lmember_t.  This is expected
+   to be very rare (but nonetheless possible).  */
+
+#define CTF_LSTRUCT_THRESH     536870912
+
+typedef struct ctf_member_v2
+{
+  uint32_t ctm_name;           /* Reference to name in string table.  */
+  uint32_t ctm_offset;         /* Offset of this member in bits.  */
+  uint32_t ctm_type;           /* Reference to type of member.  */
+} ctf_member_t;
+
+typedef struct ctf_lmember_v2
+{
+  uint32_t ctlm_name;          /* Reference to name in string table.  */
+  uint32_t ctlm_offsethi;      /* High 32 bits of member offset in bits.  */
+  uint32_t ctlm_type;          /* Reference to type of member.  */
+  uint32_t ctlm_offsetlo;      /* Low 32 bits of member offset in bits.  */
+} ctf_lmember_t;
+
+#define        CTF_LMEM_OFFSET(ctlmp) \
+       (((uint64_t)(ctlmp)->ctlm_offsethi) << 32 | (ctlmp)->ctlm_offsetlo)
+#define        CTF_OFFSET_TO_LMEMHI(offset)    ((uint32_t)((uint64_t)(offset) >> 32))
+#define        CTF_OFFSET_TO_LMEMLO(offset)    ((uint32_t)(offset))
+
+typedef struct ctf_enum
+{
+  uint32_t cte_name;           /* Reference to name in string table.  */
+  int32_t cte_value;           /* Value associated with this name.  */
+} ctf_enum_t;
+
+/* The ctf_archive is a collection of ctf_dict_t's stored together. The format
+   is suitable for mmap()ing: this control structure merely describes the
+   mmap()ed archive (and overlaps the first few bytes of it), hence the
+   greater care taken with integral types.  All CTF files in an archive
+   must have the same data model.  (This is not validated.)
+
+   All integers in this structure are stored in little-endian byte order.
+
+   The code relies on the fact that everything in this header is a uint64_t
+   and thus the header needs no padding (in particular, that no padding is
+   needed between ctfa_ctfs and the unnamed ctfa_archive_modent array
+   that follows it).
+
+   This is *not* the same as the data structure returned by the ctf_arc_*()
+   functions:  this is the low-level on-disk representation.  */
+
+#define CTFA_MAGIC 0x8b47f2a4d7623eeb  /* Random.  */
+struct ctf_archive
+{
+  /* Magic number.  (In loaded files, overwritten with the file size
+     so ctf_arc_close() knows how much to munmap()).  */
+  uint64_t ctfa_magic;
+
+  /* CTF data model.  */
+  uint64_t ctfa_model;
+
+  /* Number of CTF dicts in the archive.  */
+  uint64_t ctfa_ndicts;
+
+  /* Offset of the name table.  */
+  uint64_t ctfa_names;
+
+  /* Offset of the CTF table.  Each element starts with a size (a uint64_t
+     in network byte order) then a ctf_dict_t of that size.  */
+  uint64_t ctfa_ctfs;
+};
+
+/* An array of ctfa_nnamed of this structure lies at
+   ctf_archive[ctf_archive->ctfa_modents] and gives the ctfa_ctfs or
+   ctfa_names-relative offsets of each name or ctf_dict_t.  */
+
+typedef struct ctf_archive_modent
+{
+  uint64_t name_offset;
+  uint64_t ctf_offset;
+} ctf_archive_modent_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                         /* _CTF_H */
index 6d70b95..909995d 100644 (file)
@@ -304,6 +304,9 @@ handle_lto_debug_sections (const char *name, int rename)
   /* Copy over .GCC.command.line section under the same name if present.  */
   else if (strcmp (name, ".GCC.command.line") == 0)
     return strcpy (newname, name);
+  /* Copy over .ctf section under the same name if present.  */
+  else if (strcmp (name, ".ctf") == 0)
+    return strcpy (newname, name);
   free (newname);
   return NULL;
 }