[PATCH,RFC,V4 4/5] CTF generation for a single compilation unit

Indu Bhagat indu.bhagat@oracle.com
Thu Jul 18 00:02:00 GMT 2019


For each translation unit, a CTF container (ctf_container_t) is used to
keep the CTF debug info.

- ctfout.c hosts the compiler facing routines for CTF generation and emission.
- ctfcreate.c contains the CTF format specific CTF creation routines.
- ctfutils.c contains helper routines for CTF creation.

[Changes from V3]
   - Bugfixes
   - Implementation for CTF function and object index sub-sections.
   - Skip types when CTF lacks representation for them.
   - CTF Compilation Unit name support (CU name).


gcc/ChangeLog:

	* Makefile.in: Add new object files.
	* ctfcreate.c: New file.
	* ctfout.c (ctf_dtu_d_union_selector): New helper function for garbage
	collection of dtd_u union in ctf_dtdef_t.
	(ctfc_add_cuname): New function to add compilation unit name to CTF
	container.
	(ctf_dtdef_hash::hash): New function to generate hashkey for a CTF type
	record.
	(hash_dtd_tree_decl): New function.
	(ctf_dtdef_hash::equal): Likewise.
	(is_ctf_base_type): Likewise.
	(get_cvr_quals_for_type): Likewise.
	(get_type_name_string): Likewise.
	(get_decl_name_string): Likewise.
	(ctf_type_exists): Likewise.
	(init_ctf_string_table): Likewise.
	(new_ctf_container): Allocate contents of CTF container.
	(delete_ctf_container): Cleanup contents of CTF container.
	(init_ctf_sections): Update code comments regarding LTO.
	(gen_ctf_base_type): New function.
	(gen_ctf_pointer_type): Likewise.
	(gen_ctf_array_type): Likewise.
	(gen_ctf_forward_type): Likewise.
	(gen_ctf_enum_const_list): Likewise.
	(gen_ctf_enum_type): Likewise.
	(gen_ctf_function_type): Likewise.
	(gen_ctf_cvrquals): Likewise.
	(gen_ctf_sou_type): Likewise.
	(gen_ctf_typedef): Likewise.
	(gen_ctf_variable): Likewise.
	(gen_ctf_function): Likewise.
	(gen_ctf_type): Likewise.
	(gen_ctf_bitfield_type_for_decl): Likewise.
	(gen_ctf_type_for_decl): Likewise.
	(ctf_preprocess_var): Likewise.
	(ctf_dvd_preprocess_cb): Likewise.
	(ctf_dtd_preprocess_cb): Likewise.
	(ctf_preprocess): Likewise.
	(ctf_asm_preamble): Likewise.
	(ctf_asm_stype): Likewise.
	(ctf_asm_type): Likewise.
	(ctf_asm_slice): Likewise.
	(ctf_asm_array): Likewise.
	(ctf_asm_varent): Likewise.
	(ctf_asm_sou_lmember): Likewise.
	(ctf_asm_sou_member): Likewise.
	(ctf_asm_enum_const): Likewise.
	(output_ctf_header): Output the CTF section if the CTF container is not
	empty.
	(output_ctf_obj_info): New function.
	(output_ctf_func_info): Likewise.
	(output_ctf_objtidx): Likewise.
	(output_ctf_funcidx): Likewise.
	(output_ctf_vars): Likewise.
	(output_ctf_strs): Likewise.
	(output_asm_ctf_sou_fields): Likewise.
	(output_asm_ctf_enum_list): Likewise.
	(output_asm_ctf_vlen_bytes): Likewise.
	(output_asm_ctf_type): Likewise.
	(output_ctf_types): Likewise.
	(ctf_decl): Likewise.
	(ctf_early_finish): Trigger CTF emission.
	(ctf_early_global_decl): Invoke CTF generation function.
	(ctfout_c_finalize): Add cleanup of CTF container.
	* ctfout.h (typedef struct GTY): New data structures.
	(struct ctf_dtdef_hash): CTF type structure hasher.
	* ctfutils.c: New file.

include/ChangeLog:
 
	* ctf.h: Sync with binutils.  Keep ctf_slice_t aligned.  Add CTF obj
	index and func index section.

---
 gcc/ChangeLog     |   70 +++
 gcc/Makefile.in   |    2 +
 gcc/ctfcreate.c   |  531 ++++++++++++++++
 gcc/ctfout.c      | 1811 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/ctfout.h      |  317 +++++++++-
 gcc/ctfutils.c    |  198 ++++++
 include/ChangeLog |    5 +
 include/ctf.h     |   58 +-
 8 files changed, 2942 insertions(+), 50 deletions(-)
 create mode 100644 gcc/ctfcreate.c
 create mode 100644 gcc/ctfutils.c

diff --git a/gcc/ctfcreate.c b/gcc/ctfcreate.c
new file mode 100644
index 0000000..f14ee69
--- /dev/null
+++ b/gcc/ctfcreate.c
@@ -0,0 +1,531 @@
+/* Functions to create and update CTF from GCC.
+   Copyright (C) 2019 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/>.  */
+
+/* Create CTF types.  The code is mostly adapted from libctf.
+
+   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.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "ctfout.h"
+
+void
+ctf_dtd_insert (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+{
+  ctf_dtdef_ref entry = dtd;
+  bool existed = ctfc->ctfc_types->put (entry, dtd);
+  /* Duplicate CTF type records not expected to be inserted.  And dtd_decl
+     cannot be NULL.  */
+  gcc_assert (dtd->dtd_decl != NULL && !existed);
+}
+
+/* Lookup CTF type given a tree type or decl node.  dtd_key_flags are not
+   necessary for lookup in most cases, because they are needed only for CTF
+   types with no corresponding tree type or decl to begin with.  */
+
+ctf_dtdef_ref
+ctf_dtd_lookup (const ctf_container_ref ctfc, const tree type)
+{
+  return ctf_dtd_lookup_with_flags (ctfc, type, 0);
+}
+
+/* Lookup CTF type given a tree type or decl node and key_flags.  */
+
+ctf_dtdef_ref
+ctf_dtd_lookup_with_flags (const ctf_container_ref ctfc, const tree type,
+			   const unsigned int key_flags)
+{
+  ctf_dtdef_ref * slot;
+
+  ctf_dtdef_t entry;
+  entry.dtd_key.dtdk_key_decl = type;
+  entry.dtd_key.dtdk_key_flags = key_flags;
+
+  slot = ctfc->ctfc_types->get (&entry);
+
+  if (slot)
+    return (ctf_dtdef_ref) (*slot);
+
+  return NULL;
+}
+
+void
+ctf_dvd_insert (ctf_container_ref ctfc, ctf_dvdef_ref dvd)
+{
+  bool existed = ctfc->ctfc_vars->put (dvd->dvd_decl, dvd);
+  /* Duplicate variable records not expected to be inserted.  And dvd_decl
+     cannot be NULL.  */
+  gcc_assert (dvd->dvd_decl != NULL && !existed);
+}
+
+/* Lookup CTF variable given a decl node.  */
+
+ctf_dvdef_ref
+ctf_dvd_lookup (const ctf_container_ref ctfc, const tree decl)
+{
+  ctf_dvdef_ref * slot;
+
+  slot = ctfc->ctfc_vars->get (decl);
+
+  if (slot)
+    return (ctf_dvdef_ref) (*slot);
+
+  return NULL;
+}
+
+static ctf_id_t
+ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name,
+		 ctf_dtdef_ref * rp, tree treetype, uint32_t key_flags)
+{
+  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.dtdk_key_decl = treetype;
+  dtd->dtd_key.dtdk_key_flags = key_flags;
+
+  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, tree treetype)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0);
+
+  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;
+}
+
+static ctf_id_t
+ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+		 uint32_t kind, tree treetype, uint32_t cvrint)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+  uint32_t key_flags = 0;
+
+  /* dtd_key_flags are set only for const, volatile and restrict.  */
+  if (cvrint && (kind == CTF_K_VOLATILE || kind == CTF_K_CONST
+		  || kind == CTF_K_RESTRICT))
+    key_flags = kind;
+
+  gcc_assert (ref <= CTF_MAX_TYPE);
+
+  type = ctf_add_generic (ctfc, flag, NULL, &dtd, treetype, key_flags);
+  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, tree treetype)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type = 0;
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0);
+
+  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, tree treetype)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+
+  gcc_assert (ref <= CTF_MAX_TYPE);
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0);
+  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,
+	       const ctf_encoding_t * ep, tree treetype)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+  uint32_t roundup_nbytes;
+
+  gcc_assert ((ep->cte_bits <= 255) && (ep->cte_offset <= 255));
+
+  gcc_assert (ref <= CTF_MAX_TYPE);
+
+  type = ctf_add_generic (ctfc, flag, NULL, &dtd, treetype, 0);
+
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
+
+  roundup_nbytes = (ROUND_UP (ep->cte_bits, BITS_PER_UNIT) / BITS_PER_UNIT);
+  gcc_assert (roundup_nbytes);
+  /* 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 = (1 << ceil_log2 (roundup_nbytes));
+
+  /* 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 = ep->cte_bits;
+  dtd->dtd_u.dtu_slice.cts_offset = ep->cte_offset;
+
+  ctfc->ctfc_num_stypes++;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_volatile (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+		  tree type, uint32_t cvrint)
+{
+  return (ctf_add_reftype (ctfc, flag, ref, CTF_K_VOLATILE, type, cvrint));
+}
+
+ctf_id_t
+ctf_add_const (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+	       tree type, uint32_t cvrint)
+{
+  return (ctf_add_reftype (ctfc, flag, ref, CTF_K_CONST, type, cvrint));
+}
+
+ctf_id_t
+ctf_add_restrict (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+		  tree type, uint32_t cvrint)
+{
+  return (ctf_add_reftype (ctfc, flag, ref, CTF_K_RESTRICT, type, cvrint));
+}
+
+ctf_id_t
+ctf_add_float (ctf_container_ref ctfc, uint32_t flag,
+	       const char * name, const ctf_encoding_t * ep, tree type)
+{
+  return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_FLOAT, type));
+}
+
+ctf_id_t
+ctf_add_integer (ctf_container_ref ctfc, uint32_t flag,
+		 const char * name, const ctf_encoding_t * ep, tree type)
+{
+  return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_INTEGER, type));
+}
+
+ctf_id_t
+ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
+		 tree type)
+{
+  return (ctf_add_reftype (ctfc, flag, ref, CTF_K_POINTER, type, 0));
+}
+
+ctf_id_t
+ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
+	       tree treetype)
+{
+  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, treetype, 0);
+
+  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, tree enum_type)
+{
+  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.  */
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, enum_type, 0);
+
+  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, tree enum_type)
+{
+  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, enum_type);
+  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, tree sou, const char * name,
+		       ctf_id_t type, unsigned long 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);
+
+#if 0
+  /* Check duplicate members with the same name.  May be a useful check if
+     members of anonymous truct or union are folded into the parent struct (if
+     exists); See a pending TBD in gen_ctf_sou_type for more info.  */
+  if (name != NULL)
+    {
+      for (dmd = dtd->dtd_u.dtu_members;
+	   dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
+	{
+	  if (dmd->dmd_name != NULL)
+	    gcc_assert (strcmp (dmd->dmd_name, name) != 0);
+	}
+    }
+#endif
+
+  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,
+		  tree decl)
+{
+  ctf_dvdef_ref dvd;
+
+  gcc_assert (name);
+
+  if (name != NULL)
+    {
+      dvd = ggc_cleared_alloc<ctf_dvdef_t> ();
+      /* Buffer the strings in the CTF string table.  */
+      dvd->dvd_name = ctf_add_string (ctfc, name, &(dvd->dvd_name_offset));
+      dvd->dvd_type = ref;
+      dvd->dvd_decl = decl;
+      ctf_dvd_insert (ctfc, dvd);
+
+      if (strcmp (name, ""))
+	ctfc->ctfc_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, ctf_func_arg_t * argv,
+		  tree func_decl_or_type)
+{
+  ctf_dtdef_ref dtd;
+  ctf_id_t type;
+  uint32_t vlen;
+
+  gcc_assert (ctc);
+  if (ctc->ctc_argc)
+    gcc_assert (argv);
+
+  vlen = ctc->ctc_argc;
+
+  /* Caller must make sure CTF types for ctc->ctc_return and function
+     arguements are already added.  */
+
+  gcc_assert (vlen <= CTF_MAX_VLEN);
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, func_decl_or_type, 0);
+
+  dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
+  dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return;
+
+  dtd->dtd_u.dtu_argv = argv;
+
+  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, tree treetype)
+{
+  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.  */
+
+  type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0);
+
+  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;
+}
diff --git a/gcc/ctfout.c b/gcc/ctfout.c
index 471cf80..47b1f73 100644
--- a/gcc/ctfout.c
+++ b/gcc/ctfout.c
@@ -25,11 +25,13 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "memmodel.h"
 #include "tm_p.h"
+#include "toplev.h"
 #include "varasm.h"
 #include "output.h"
 #include "dwarf2asm.h"
 #include "debug.h"
 #include "ctfout.h"
+#include "diagnostic-core.h"
 
 /* A CTF container object - one per translation unit.  */
 
@@ -43,14 +45,14 @@ 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.  */
 
-/* CTF debug info section.  */
-
 #define CTF_INFO_SECTION_FLAGS (SECTION_DEBUG)
 
 /* Maximum size (in bytes) of an artificially generated CTF label.  */
@@ -63,8 +65,338 @@ static char ctf_info_section_label[MAX_CTF_LABEL_BYTES];
 #define CTF_INFO_SECTION_LABEL			"Lctf"
 #endif
 
+/* Forward declarations for some routines defined in this file.  */
+
+/* Generate CTF type for the given type.  Types already added are skipped.  */
+
+static ctf_id_t gen_ctf_type (ctf_container_ref, tree);
+
+/* Generate CTF type for the given decl.  Types already added are skipped.  */
+
+static ctf_id_t gen_ctf_type_for_decl (ctf_container_ref, tree);
+
+/* CTF preprocess callback arguments.  */
+
+typedef struct ctf_dtd_preprocess_arg
+{
+  unsigned long dtd_global_func_idx;
+  ctf_container_ref dtd_arg_ctfc;
+} ctf_dtd_preprocess_arg_t;
+
+typedef struct ctf_dvd_preprocess_arg
+{
+  unsigned long dvd_global_obj_idx;
+  ctf_container_ref dvd_arg_ctfc;
+} ctf_dvd_preprocess_arg_t;
+
+/* CTF cvr qualifier mask.  */
+
+const int ctf_cvr_qual_mask = (TYPE_QUAL_CONST
+			      | TYPE_QUAL_VOLATILE
+			      | TYPE_QUAL_RESTRICT);
+
+/* 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)
+{
+  unsigned int kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
+  switch (kind)
+    {
+    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;
+    }
+}
+
+/* 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.  */
+
+static void
+ctfc_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 + 1 + strlen (filename);
+
+      cuname = (char *) ggc_alloc_atomic (len);
+      memset (cuname, 0, len);
+
+      strcpy (cuname, cu_pwd);
+      cuname[cu_pwd_len] = DIR_SEPARATOR;
+      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;
+}
+
+/* Returns a hash code for CTF type records.  */
+
+hashval_t
+ctf_dtdef_hash::hash (ctf_dtdef_ref e1)
+{
+  ctf_dtdef_ref e = e1;
+  tree e_decl = e->dtd_decl;
+  uint32_t key_flags = e->dtd_key_flags;
+
+  hashval_t key = hash_dtd_tree_decl (e_decl, key_flags);
+
+  return key;
+}
+
+hashval_t
+hash_dtd_tree_decl (tree e_decl, uint32_t key_flags)
+{
+  hashval_t key;
+  tree type = NULL;
+
+  if ((TREE_CODE (e_decl) == FIELD_DECL)
+      || (TREE_CODE (e_decl) == TYPE_DECL))
+    type = TREE_TYPE (e_decl);
+  else
+    type = e_decl; /* TREE_TYPE was used as dtd_key otherwise.  */
+
+  if (TREE_CODE (e_decl) == TYPE_DECL
+      || TREE_CODE (e_decl) == FUNCTION_DECL
+      /* No CTF type de-duplication for slices.  See note in
+	 gen_ctf_bitfield_type_for_decl.  */
+      || ((TREE_CODE (e_decl) == FIELD_DECL) && DECL_BIT_FIELD_TYPE (e_decl)))
+    {
+      key = (hashval_t) htab_hash_pointer (e_decl);
+    }
+  else
+    {
+      gcc_assert (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type);
+      key = (hashval_t) TYPE_UID (type);
+    }
+
+  if (key_flags)
+    key = iterative_hash (&key_flags, sizeof (key_flags), key);
+
+  return key;
+}
+
+/* Returns nonzero if entry1 and entry2 are the same CTF types.  */
+
+bool
+ctf_dtdef_hash::equal (ctf_dtdef_ref entry1, ctf_dtdef_ref entry2)
+{
+  bool eq = 0;
+  tree e1_type, e2_type;
+  int e1_cvr_quals = 0, e2_cvr_quals = 0;
+
+  ctf_dtdef_ref e1 = entry1;
+  ctf_dtdef_ref e2 = entry2;
+
+  tree e1_decl = e1->dtd_decl;
+  tree e2_decl = e2->dtd_decl;
+
+  gcc_assert (e1_decl);
+  gcc_assert (e2_decl);
+  /* This pre-check is useful because dtd_decl can be either type or decl tree
+     references.  */
+  eq = (TREE_CODE (e1_decl) == TREE_CODE (e2_decl));
+  if (eq)
+    {
+      if ((TREE_CODE (e1_decl) == FIELD_DECL)
+	  || (TREE_CODE (e1_decl) == TYPE_DECL))
+	{
+	  e1_type = TREE_TYPE (e1_decl);
+	  e2_type = TREE_TYPE (e2_decl);
+	}
+      else
+	{
+	  /* TREE_TYPE was used as dtd_key otherwise.  */
+	  e1_type = e1_decl;
+	  e2_type = e2_decl;
+	}
+
+      if (TREE_CODE (e1_decl) == TYPE_DECL
+	  || TREE_CODE (e1_decl) == FUNCTION_DECL
+	  /* No CTF type de-duplication for slices.  See note in
+	     gen_ctf_bitfield_type_for_decl.  */
+	  || ((TREE_CODE (e1_decl) == FIELD_DECL)
+	      && DECL_BIT_FIELD_TYPE (e1_decl)))
+
+	{
+	  eq = (htab_hash_pointer (e1_decl) ==  htab_hash_pointer (e2_decl));
+	}
+      else
+	{
+	  gcc_assert (TREE_CODE_CLASS (TREE_CODE (e1_type)) == tcc_type);
+	  gcc_assert (TREE_CODE_CLASS (TREE_CODE (e2_type)) == tcc_type);
+
+	  eq = (TYPE_UID (e1_type) == TYPE_UID (e2_type));
+
+	  /* Always compare cvr_quals when available.  */
+	  e1_cvr_quals = (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (e1_type)
+			  & ctf_cvr_qual_mask);
+	  e2_cvr_quals = (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (e2_type)
+			  & ctf_cvr_qual_mask);
+
+	  if (eq && e1_cvr_quals)
+	    {
+	      e2_cvr_quals = (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (e2_type)
+			      & ctf_cvr_qual_mask);
+	      eq = (e1_cvr_quals == e2_cvr_quals);
+	    }
+	}
+
+      if (eq)
+	{
+	  /* dtd_key_flags are set only for CTF type records which have no
+	     direct corresponding tree type or decl.  They will be 0
+	     otherwise.  */
+	  eq = (e1->dtd_key_flags == e2->dtd_key_flags);
+	}
+    }
+
+  return eq;
+}
+
+static inline int
+is_ctf_base_type (tree type)
+{
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case FIXED_POINT_TYPE:
+    case COMPLEX_TYPE:
+    case BOOLEAN_TYPE:
+    case VOID_TYPE:
+      return 1;
+
+    case ARRAY_TYPE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+    case ENUMERAL_TYPE:
+    case FUNCTION_TYPE:
+    case METHOD_TYPE:
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+    case NULLPTR_TYPE:
+    case OFFSET_TYPE:
+    case LANG_TYPE:
+    case VECTOR_TYPE:
+      return 0;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return 0;
+}
+
+static inline int
+get_cvr_quals_for_type (tree type)
+{
+  int cvr_quals = 0;
+
+  if (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type)
+    cvr_quals = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (type);
+
+  return cvr_quals;
+}
+
+static const char *
+get_type_name_string (tree type)
+{
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type);
+
+  tree type_name = TYPE_IDENTIFIER (type);
+  const char * name_string = type_name ? IDENTIFIER_POINTER (type_name) : NULL;
+
+  return name_string;
+}
+
+static const char *
+get_decl_name_string (tree decl)
+{
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == tcc_declaration);
+
+  tree decl_name = DECL_NAME (decl);
+  const char * name_string = decl_name ? IDENTIFIER_POINTER (decl_name) : NULL;
+
+  return name_string;
+}
+
+/* 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.  */
+
+static bool
+ctf_type_exists (ctf_container_ref ctfc, tree 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;
+}
+
 /* 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_string_table (ctf_container_ref ctfc)
+{
+  ctfc->ctfc_strtable.ctstab_head = NULL;
+  ctfc->ctfc_strtable.ctstab_tail = NULL;
+  ctfc->ctfc_strtable.ctstab_num = 0;
+  ctfc->ctfc_strtable.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;
+  ctfc->ctfc_strtable.ctstab_estr = ctf_add_string (ctfc, "", &estr_offset);
+  ctfc->ctfc_strlen++;
+}
+
 /* Allocate a new CTF container with the desired flags.  */
 
 static inline ctf_container_ref
@@ -75,6 +407,15 @@ new_ctf_container (unsigned char ctp_flags)
   tu_ctfc->ctfc_magic = CTF_MAGIC;
   tu_ctfc->ctfc_version = CTF_VERSION;
   tu_ctfc->ctfc_flags = ctp_flags;
+  tu_ctfc->ctfc_nextid = CTF_INIT_TYPEID;
+
+  tu_ctfc->ctfc_types
+    = hash_map<ctf_dtdef_hash, ctf_dtdef_ref>::create_ggc (100);
+
+  tu_ctfc->ctfc_vars
+    = hash_map<tree_decl_hash, ctf_dvdef_ref>::create_ggc (100);
+
+  init_ctf_string_table (tu_ctfc);
 
   return tu_ctfc;
 }
@@ -97,7 +438,28 @@ delete_ctf_container (ctf_container_ref ctfc)
      including the hash_map members etc. ?  */
   if (ctfc)
     {
-      ctfc = NULL;
+      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;
     }
 }
 
@@ -106,59 +468,1445 @@ delete_ctf_container (ctf_container_ref ctfc)
 void
 init_ctf_sections (void)
 {
-  ctf_info_section = get_section (CTF_INFO_SECTION_NAME,
-				  CTF_INFO_SECTION_FLAGS,
+  /* 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++);
 }
 
-/* Asm'out the CTF preamble.  */
+/* Leaf routines for CTF type generation.
+   Called via the gen_ctf_type (), these APIs update the CTF container with new
+   CTF records.  CTF type de-duplication must be done by the caller API
+   (See "Parent routines for CTF generation below).  */
 
-static void
-ctf_asm_preamble (ctf_container_ref ctfc)
+/* 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, tree type)
 {
-  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");
+  ctf_id_t type_id = CTF_NULL_TYPEID;
+
+  ctf_encoding_t ctf_encoding = {0, 0, 0};
+  HOST_WIDE_INT size = int_size_in_bytes (type);
+
+  uint32_t encoding = 0;
+
+  const char * name_string = get_type_name_string (type);
+  /* Base TYPE node must have had a TYPE_IDENTIFIER node, else retrieval of
+     name string of the base type will need to be adjusted.  */
+  /* This assert here fails for "complex char a".  CTF skips these types.  But
+     need to debug why the TYPE_NAME is null.  FIXME - moved the asserts into
+     each respective block below meanwhile.  */
+  // gcc_assert (name_string);
+
+  /* Add the type of variable.  */
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+      {
+	/* Note - CTF_INT_VARARGS is unused in CTF.  */
+
+	/* Update size and encoding.  */
+	if (TYPE_STRING_FLAG (type))
+	  {
+	    if (TYPE_UNSIGNED (type))
+	      encoding = CTF_INT_CHAR;
+	    else
+	      encoding = CTF_INT_CHAR | CTF_INT_SIGNED;
+	  }
+	else if (!TYPE_UNSIGNED (type))
+	  encoding = CTF_INT_SIGNED;
+
+	ctf_encoding.cte_format = encoding;
+	ctf_encoding.cte_bits = size * BITS_PER_UNIT;
+
+	gcc_assert (name_string);
+	type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+				   &ctf_encoding, type);
+
+	break;
+      }
+
+  case BOOLEAN_TYPE:
+    encoding = CTF_INT_BOOL;
+
+    ctf_encoding.cte_format = encoding;
+    ctf_encoding.cte_bits = size * BITS_PER_UNIT;
+
+    gcc_assert (name_string);
+    type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+			       &ctf_encoding, type);
+    break;
+
+  case REAL_TYPE:
+    if (FLOAT_MODE_P (TYPE_MODE (type)))
+      {
+	if (size == int_size_in_bytes (float_type_node))
+	  encoding = CTF_FP_SINGLE;
+	else if (size == int_size_in_bytes (double_type_node))
+	  encoding = CTF_FP_DOUBLE;
+	else if ((size == int_size_in_bytes (long_double_type_node))
+		  || (size == int_size_in_bytes (float128_type_node)))
+	  encoding = CTF_FP_LDOUBLE;
+	/* Encoding must be appropriately initialized by now.  */
+	gcc_assert (encoding && encoding <= CTF_FP_MAX);
+
+	ctf_encoding.cte_format = encoding;
+	ctf_encoding.cte_bits = size * BITS_PER_UNIT;
+
+	gcc_assert (name_string);
+	type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+			       &ctf_encoding, type);
+      }
+    else
+      {
+	/* CTF does not have representation for non IEEE float encoding.  Skip
+	   this type.  FIXME - Note this TBD_CTF_REPRESENTATION_LIMIT.  */
+	inform (input_location,
+		"Skipping non IEEE fp type as not represented in CTF");
+      }
+    break;
+
+  case FIXED_POINT_TYPE:
+    /* CTF does not have representation for fixed point type.  Skip this type.
+       FIXME - Note this TBD_CTF_REPRESENTATION_LIMIT.  */
+    inform (input_location,
+	    "Skipping fixed point type as not represented in CTF");
+    break;
+
+  case COMPLEX_TYPE:
+    encoding = 0;
+    if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+      {
+	tree component_type = TREE_TYPE (type);
+	size = int_size_in_bytes (component_type);
+
+	if (size == int_size_in_bytes (float_type_node))
+	  encoding = CTF_FP_CPLX;
+	else if (size == int_size_in_bytes (double_type_node))
+	  encoding = CTF_FP_DCPLX;
+	else if ((size == int_size_in_bytes (long_double_type_node))
+		 || (size == int_size_in_bytes (float128_type_node)))
+	  encoding = CTF_FP_LDCPLX;
+
+	/* Encoding must be appropriately initialized by now.  */
+	gcc_assert (encoding && encoding != CTF_FP_MAX);
+
+	ctf_encoding.cte_format = encoding;
+	ctf_encoding.cte_bits = size * BITS_PER_UNIT;
+
+	gcc_assert (name_string);
+	type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+				 &ctf_encoding, type);
+      }
+    else
+      {
+	/* CTF does not have representation for complex integer type.  Skip this
+	   type.  FIXME - Note this TBD_CTF_REPRESENTATION_LIMIT.  */
+	inform (input_location,
+		"Skipping complex integer type as not represented in CTF");
+      }
+    break;
+
+  case VOID_TYPE:
+    encoding = CTF_INT_SIGNED;
+    ctf_encoding.cte_format = encoding;
+    ctf_encoding.cte_bits = 0;
+
+    gcc_assert (name_string);
+    type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+			       &ctf_encoding, type);
+
+    break;
+
+  default:
+    /* No other TREE_CODEs are expected as CTF base types.  */
+    gcc_unreachable () ;
+  }
+
+  return type_id;
+}
+
+static ctf_id_t
+gen_ctf_pointer_type (ctf_container_ref ctfc, tree ptr_type)
+{
+  ctf_id_t type_id = CTF_NULL_TYPEID;
+  ctf_id_t pointer_to_type_id = CTF_NULL_TYPEID;
+
+  tree pointertotype = TREE_TYPE (ptr_type);
+
+  type_id = gen_ctf_type (ctfc, pointertotype);
+
+  /* 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.  For example, a struct have a member of type
+     pointer to the struct, e.g.,
+     struct link { struct link * next; } * slink;  */
+  if (ctf_type_exists (ctfc, ptr_type, &pointer_to_type_id))
+    return pointer_to_type_id;
+
+  pointer_to_type_id = ctf_add_pointer (ctfc, CTF_ADD_ROOT, type_id,
+					  ptr_type);
+
+  return pointer_to_type_id;
+}
+
+static ctf_id_t
+gen_ctf_array_type (ctf_container_ref ctfc, tree array_type)
+{
+  ctf_id_t type_id = CTF_NULL_TYPEID;
+  tree lower, upper;
+  ctf_arinfo_t arinfo;
+  HOST_WIDE_INT min_index = 0, max_index = 0;
+  uint32_t num_elements = 0;
+  ctf_id_t ctf_contents_type_id = CTF_NULL_TYPEID;
+  ctf_id_t ctf_index_type_id = CTF_NULL_TYPEID;
+
+  tree type_of_array_element = TREE_TYPE (array_type);
+  tree type_of_index = TYPE_DOMAIN (array_type);
+
+  /* type_of_index may be NULL in some cases, e.g., when we parse
+     extern const char _var_example[];
+     In this case of unsized uninitialized array declaration, CTF encodes an
+     explicit zero for the number of elements.  This is quite distinct from
+     DWARF which encodes no bound information in such a case.
+     TBD_CTF_FORMAT_OPEN_ISSUES (1) - see testcase ctf-array-2.c.  */
+  if (type_of_index)
+    {
+      lower = TYPE_MIN_VALUE (type_of_index);
+      upper = TYPE_MAX_VALUE (type_of_index);
+      min_index = tree_to_shwi (lower);
+      /* TYPE_MAX_VALUE of index may be null for variable-length arrays.  */
+      max_index = upper ? tree_to_shwi (upper) : 0;
+      if (max_index > 0) gcc_assert (max_index >= min_index);
+      /* If max_index == min_index, both the values must be zero; num_elements
+	 set to zero in that case.  */
+      num_elements = (max_index > 0 && max_index > min_index)
+		      ? max_index - min_index + 1 : 0;
+      gcc_assert (num_elements <= CTF_MAX_SIZE);
+    }
+
+  arinfo.ctr_nelems = num_elements;
+
+  /* Overwrite the type_of_index with integer_type_node.
+     TYPE_DOMAIN of ARRAY_TYPE have code INTEGER_TYPE, but have no
+     IDENTIFIER_NODES.  This causes issues in retrieving the name string of
+     the index type (See gen_ctf_base_type) becuase the TYPE_IDENTIFIER is NULL
+     in those cases.
+     Use integer_type_node instead.  This also helps gen_ctf_base_type to not
+     generate crooked (and duplicate) int records with wierd "integer" size for
+     arrays.  */
+  type_of_index = integer_type_node;
+
+  ctf_index_type_id = gen_ctf_type (ctfc, type_of_index);
+  arinfo.ctr_index = ctf_index_type_id;
+
+  ctf_contents_type_id = gen_ctf_type (ctfc, type_of_array_element);
+  arinfo.ctr_contents = ctf_contents_type_id;
+
+  type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, array_type);
+
+  return type_id;
 }
 
-/* Output the CTF header.  */
+static ctf_id_t
+gen_ctf_forward_type (ctf_container_ref ctfc, tree fwd_type, uint32_t kind)
+{
+  ctf_id_t fwd_type_id = 0;
+
+  const char * fwd_name = get_type_name_string (fwd_type);
+  /* Type de-duplication is already done by now.  See gen_ctf_type ().
+     Simple add the forward type.  */
+  fwd_type_id = ctf_add_forward (ctfc, CTF_ADD_ROOT, fwd_name, kind, fwd_type);
+
+  return fwd_type_id;
+}
 
 static void
-output_ctf_header (ctf_container_ref ctfc)
+gen_ctf_enum_const_list (ctf_container_ref ctfc, const tree enum_type,
+			 const ctf_id_t enum_type_id)
 {
-  switch_to_section (ctf_info_section);
-  ASM_OUTPUT_LABEL (asm_out_file, ctf_info_section_label);
+  tree link;
+  tree enum_value;
+  HOST_WIDE_INT value;
+  bool skipped = 0;
+  /* Append the enum values to the CTF_K_ENUM record.  */
+  for (link = TYPE_VALUES (enum_type); link != NULL; link = TREE_CHAIN (link))
+    {
+      skipped = 0;
+      enum_value = TREE_VALUE (link);
+      /* For now, handle enumeration constants not wider than
+	 HOST_WIDE_INT.  TBD handle this.  */
+      gcc_assert (int_size_in_bytes (TREE_TYPE (enum_value))*HOST_BITS_PER_CHAR
+		  <= HOST_BITS_PER_WIDE_INT || tree_fits_shwi_p (enum_value));
 
-  ctf_asm_preamble (ctfc);
+      value = TREE_INT_CST_LOW (enum_value);
+      const char * enum_valname = IDENTIFIER_POINTER (TREE_PURPOSE (link));
+      gcc_assert (enum_valname);
+
+      skipped = ctf_add_enumerator (ctfc, enum_type_id, enum_valname, value,
+				    enum_type);
+
+      /* Addition of the enumeration constant is skipped if not representable
+	 in CTF (int32_t).
+	 FIXME - Note this TBD_CTF_REPRESENTATION_LIMIT.  */
+      if (skipped)
+	inform (input_location,
+		"Skipping enumerator constant as not represented in CTF");
+    }
 }
 
-/* CTF routines interfacing to the compiler.  */
+static ctf_id_t
+gen_ctf_enum_type (ctf_container_ref ctfc, tree enum_type)
+{
+  ctf_id_t enum_type_id = CTF_NULL_TYPEID;
+  HOST_WIDE_INT size;
 
-void
-ctf_debug_init (void)
+  gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
+
+  if (!TYPE_SIZE (enum_type))
+    {
+      /* Add CTF forward type of enum kind.  */
+      uint32_t kind = CTF_K_ENUM;
+      enum_type_id = gen_ctf_forward_type (ctfc, enum_type, kind);
+      return enum_type_id;
+    }
+
+  const char * enum_name = get_type_name_string (enum_type);
+  size = int_size_in_bytes (enum_type);
+
+  /* Add CTF enum type.  */
+  enum_type_id = ctf_add_enum (ctfc, CTF_ADD_ROOT, enum_name, size, enum_type);
+  /* Add CTF records for enum const values.  */
+  gen_ctf_enum_const_list (ctfc, enum_type, enum_type_id);
+
+  return enum_type_id;
+}
+
+static ctf_id_t
+gen_ctf_function_type (ctf_container_ref ctfc, tree func_decl_or_type,
+		       const char * func_name)
 {
-  init_ctf_containers ();
+  ctf_id_t type_id = CTF_NULL_TYPEID, return_type_id = CTF_NULL_TYPEID;
+  tree func_type;
+  tree link;
+  tree first_param_type;
+  tree formal_type = NULL;
+  tree return_type = NULL;
+  tree param_type;
+  uint32_t num_args = 0;
+  ctf_func_arg_t * argv_ids;
+  ctf_funcinfo_t func_info;
+
+  if (TREE_CODE (func_decl_or_type) == FUNCTION_TYPE)
+    func_type = func_decl_or_type;
+  else
+    func_type = TREE_TYPE (func_decl_or_type);
+
+  return_type = TREE_TYPE (func_type);
+  first_param_type = TYPE_ARG_TYPES (func_type);
+
+  /* Add CTF record for function return type.  */
+  return_type_id = gen_ctf_type (ctfc, return_type);
+  func_info.ctc_return = return_type_id;
+
+  /* Make our first pass over the list of formal parameter types and count
+     them.  */
+  for (link = first_param_type; link;)
+    {
+      formal_type = TREE_VALUE (link);
+      if (formal_type == void_type_node)
+	break;
+
+      num_args++;
+
+      link = TREE_CHAIN (link);
+    }
+
+  /* Check if this function type has an ellipsis.  */
+  if (formal_type != void_type_node)
+    {
+      func_info.ctc_flags |= CTF_FUNC_VARARG;
+      /* Increment the number of args.  This is the number of args we write
+	 after the CTF_K_FUNCTION CTF record.  */
+      num_args++;
+    }
+
+  /* The number of typed arguments should include the ellipsis.  */
+  func_info.ctc_argc = num_args;
+
+  /* Create an array of ctf_id_t to hold CTF types for args (including the
+     ellipsis).  */
+  argv_ids = ggc_vec_alloc<ctf_func_arg_t>(num_args);
+
+  /* Make a pass over the list of formal parameter types and generate CTF for
+     each.  */
+  unsigned int i = 0;
+  for (link = TYPE_ARG_TYPES (func_type);
+       link && TREE_VALUE (link);
+       link = TREE_CHAIN (link))
+    {
+      param_type = TREE_VALUE (link);
+
+      if (param_type == void_type_node)
+	break;
+
+      argv_ids[i++].farg_type = gen_ctf_type (ctfc, param_type);
+    }
+
+  if (formal_type != void_type_node)
+    {
+      /* Add trailing zero to indicate varargs.  */
+      argv_ids[i].farg_type = 0;
+      gcc_assert (i == num_args - 1);
+    }
+
+  type_id = ctf_add_function (ctfc, CTF_ADD_ROOT, func_name,
+			      (const ctf_funcinfo_t *)&func_info, argv_ids,
+			      func_decl_or_type);
+
+  return type_id;
 }
 
-void
-ctf_early_finish (const char * ARG_UNUSED (filename))
+/* Add CTF qualifier record.
+
+   If there are multiple qualifiers, the recommended ordering for CTF qualifier
+   records is const, volatile, restrict (from top-most to bottom-most).  */
+
+static ctf_id_t
+gen_ctf_cvrquals (ctf_container_ref ctfc, tree type, ctf_id_t type_id)
 {
-  if (ctf_debug_info_level == CTFINFO_LEVEL_NONE)
-    return;
+  tree qualified_type;
+  int flags;
+  uint32_t cvrint = 0;
+  int quals_index = 0;
 
-  init_ctf_sections ();
+  ctf_id_t qual_type_id = type_id;
+  int cvr_quals = get_cvr_quals_for_type (type);
 
-  output_ctf_header (tu_ctfc);
+  int quals_order[3] = { TYPE_QUAL_RESTRICT,
+			 TYPE_QUAL_VOLATILE,
+			 TYPE_QUAL_CONST };
+  ctf_id_t (*func_ptrs[3]) (ctf_container_ref, uint32_t, ctf_id_t, tree,
+			    uint32_t) = { ctf_add_restrict,
+					  ctf_add_volatile,
+					  ctf_add_const };
+  unsigned int key_flags[3] = { CTF_K_RESTRICT, CTF_K_VOLATILE, CTF_K_CONST };
+  ctf_id_t (*ctf_add_qual_func) (ctf_container_ref, uint32_t, ctf_id_t, tree,
+				 uint32_t);
+
+  qualified_type = get_qualified_type (type, cvr_quals);
+
+  /* Type de-duplication for cvr records.
+     Do not add CTF types for the same type with the matching cvr qual
+     if already present.  */
+  if (qualified_type)
+    {
+      if (ctf_type_exists (ctfc, qualified_type, &qual_type_id))
+	return qual_type_id;
+    }
+  else
+    /* If the qualified_type is NULL, use TREE_TYPE of the decl to add
+       the CTF record.  CTF for unqualified type must have been added by
+       now.  */
+    gcc_assert (ctf_type_exists (ctfc, type, &qual_type_id));
+
+  /* CTF represents distinct type records for each qualifier (CTF_K_RESTRICT,
+     CTF_K_VOLATILE, CTF_K_CONST). The records can be shared between types.
+     Here we try to de-duplicate these records as well.  */
+  while (cvr_quals)
+    {
+      flags = cvr_quals & quals_order[quals_index];
+      ctf_add_qual_func = func_ptrs[quals_index];
+      if (flags)
+	{
+	  /* Reset the corresponding cvr_qual flag so that it is not processed
+	     again.  */
+	  cvr_quals &= ~quals_order[quals_index];
+	  cvrint = (cvr_quals != 0);
+
+	 /* The dtd_decl of the all CTF type records should be non-null for
+	    de-duplication to work.  CTF records for CVR quals of a type will
+	    have the same dtd_decl in this case.  So, to prevent collisions, we
+	    use dtd_decl and dtd_key_flags for creating the hashkey.  */
+	  ctf_dtdef_ref qual_type_exists
+	    = ctf_dtd_lookup_with_flags (ctfc, type, key_flags[quals_index]);
+	  if (qual_type_exists)
+	    qual_type_id = qual_type_exists->dtd_type;
+	  else
+	    qual_type_id = ctf_add_qual_func (ctfc, CTF_ADD_ROOT, qual_type_id,
+					      type, cvrint);
+	}
+      quals_index++;
+    }
+
+  /* At least one CTF record must have been added or found to be duplicate
+     by now.  */
+  gcc_assert (qual_type_id != type_id);
+
+  return qual_type_id;
 }
 
-void
-ctf_early_global_decl (tree ARG_UNUSED (decl))
+static ctf_id_t
+gen_ctf_sou_type (ctf_container_ref ctfc, tree sou_type)
 {
-  /* Generate CTF type information if appropriate debug level is set
-     (ctf_debug_info_level == CTFINFO_LEVEL_NORMAL).  */
+  HOST_WIDE_INT sou_size;
+
+  ctf_id_t sou_type_id = CTF_NULL_TYPEID;
+  ctf_id_t field_type_id = CTF_NULL_TYPEID;
+
+  tree field;
+  HOST_WIDE_INT bit_offset = 0;
+
+  gcc_assert (RECORD_OR_UNION_TYPE_P (sou_type));
+
+  /* Handle anonymous record or union.  */
+#if 0
+  if (TYPE_NAME (sou_type) == NULL)
+    {
+      /* TBD - confirm this behaviour.
+	 The compiler will not flatten an anonymous struct or union into its
+	 parent if one exists.  Members of anonymous struct or union continue
+	 to be wrappped by the respective anonymous record.  */
+    }
+#endif
+  uint32_t kind = (TREE_CODE (sou_type) == RECORD_TYPE)
+		  ? CTF_K_STRUCT : CTF_K_UNION;
+
+  if (!TYPE_SIZE (sou_type))
+    {
+      /* Add CTF forward type of struct or union kind.  */
+      sou_type_id = gen_ctf_forward_type (ctfc, sou_type, kind);
+      return sou_type_id;
+    }
+
+    const char * sou_name = get_type_name_string (sou_type);
+    sou_size = int_size_in_bytes (sou_type);
+
+    /* Add CTF struct/union type.  */
+    if ((TREE_CODE (sou_type) == RECORD_TYPE)
+	|| (TREE_CODE (sou_type) == UNION_TYPE))
+      sou_type_id = ctf_add_sou (ctfc, CTF_ADD_ROOT, sou_name, kind, sou_size,
+				 sou_type);
+    /* QUAL_UNION_TYPE not expected in C.  */
+    else
+      gcc_unreachable ();
+
+    /* Add members of the struct.  */
+    for (field = TYPE_FIELDS (sou_type); field != NULL_TREE;
+	 field = TREE_CHAIN (field))
+      {
+	/* Enum members have DECL_NAME (field) as NULL.  */
+	const char * field_name = get_decl_name_string (field);
+
+	/* variable bit offsets are not handled at the moment.  */
+	gcc_assert (TREE_CODE (DECL_FIELD_BIT_OFFSET (field)) == INTEGER_CST);
+
+	bit_offset = int_bit_position (field);
+	/* Add the CTF type record for the field, followed by the field
+	   itself.  */
+	field_type_id = gen_ctf_type_for_decl (ctfc, field);
+	ctf_add_member_offset (ctfc, sou_type, field_name, field_type_id,
+			       bit_offset);
+      }
+
+  return sou_type_id;
+}
+
+/* Parent routines for CTF generation.
+   These routines are entry points for CTF generation.  Given a type or decl,
+   these routines perform de-duplication before invoking the Leaf CTF
+   generation routines for adding types.  */
+
+/* Generate CTF typedef records for a given declaration.  Performs
+   de-duplication before adding typedef.  */
+
+static ctf_id_t
+gen_ctf_typedef (ctf_container_ref ctfc, tree decl)
+{
+  ctf_id_t type_id = CTF_NULL_TYPEID, typedef_type_id = CTF_NULL_TYPEID;
+
+  tree type = TREE_TYPE (decl);
+  const char * decl_name_string = get_type_name_string (type);
+
+  /* CTF type de-duplication in the compiler.
+     Do not add duplicate typedef.  */
+  if (ctf_type_exists (ctfc, decl, &type_id))
+    return type_id;
+
+  /* Generate the type if not already done.  */
+  type_id = gen_ctf_type_for_decl (ctfc, decl);
+
+  /* Add typedef.  dtd_decl points to the typedef tree node.  */
+  typedef_type_id = ctf_add_typedef (ctfc, CTF_ADD_ROOT, decl_name_string,
+				     type_id, decl);
+  type_id = typedef_type_id;
+
+  return type_id;
+}
+
+/* Generate CTF variable records for a given declaration.  Performs
+   de-duplication before adding variable.  */
+
+static ctf_id_t
+gen_ctf_variable (ctf_container_ref ctfc, tree decl)
+{
+  ctf_id_t type_id = CTF_NULL_TYPEID, var_type_id = CTF_NULL_TYPEID;
+
+  const char* name = get_decl_name_string (decl);
+
+  ctf_dvdef_ref var_type_seen = ctf_dvd_lookup (tu_ctfc, decl);
+  /* Avoid duplicates.  A VAR_DECL is duplicate if it is the same decl node.
+     See hash_dvd_tree_decl.  */
+  if (!var_type_seen)
+    {
+      type_id = gen_ctf_type_for_decl (ctfc, decl);
+      /* Now add the variable.  */
+      var_type_id = ctf_add_variable (tu_ctfc, name, type_id, decl);
+
+      /* Update global objects count.  */
+      if (TREE_PUBLIC (decl))
+	ctfc->ctfc_num_global_objts++;
+    }
+  else
+    var_type_id = var_type_seen->dvd_type;
+
+  return var_type_id;
+}
+
+/* Generate CTF function records for a given declaration.  */
+
+static ctf_id_t
+gen_ctf_function (ctf_container_ref ctfc, tree func_decl)
+{
+  gcc_assert (TREE_CODE (func_decl) == FUNCTION_DECL);
+
+  ctf_id_t type_id = CTF_NULL_TYPEID;
+
+  const char * func_name = get_decl_name_string (func_decl);
+
+  /* Duplicate function types are expected to be seen as functions with same
+     signature will show the same function type.  For each distinct function
+     declaration, however, CTF function type records must be added anew.
+     Duplicate function *declarations* must, however be avoided.  This is
+     expected to happen if the gen_ctf_function API is called multiple times
+     for the same func_decl.  */
+
+  bool exists = ctf_type_exists (ctfc, func_decl, &type_id);
+  gcc_assert (!exists);
+
+  /* Add CTF Function type.  */
+  type_id = gen_ctf_function_type (ctfc, func_decl, func_name);
+
+  /* Update global functions count.  */
+  if (TREE_PUBLIC (func_decl))
+    ctfc->ctfc_num_global_funcs++;
+
+  return type_id;
+}
+
+/* Add CTF type record(s) for the given input type.  */
+static ctf_id_t
+gen_ctf_type (ctf_container_ref ctfc, tree type)
+{
+  ctf_id_t type_id = CTF_NULL_TYPEID;
+
+  /* This API expects to handle tcc_type nodes only.
+     ctf_add_int/float etc  == type ==  INTEGER_TYPE, REAL_TYPE etc
+     ctf_add_pointer	    == type ==  POINTER_TYPE
+     ctf_add_array	    == type ==  ARRAY_TYPE
+     ctf_add_sou	    == type ==  RECORD_TYPE, UNION_TYPE.  */
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type);
+
+  int cvr_quals = get_cvr_quals_for_type (type);
+
+  /* For a type of ARRAY_TYPE, type qualifiers (if any) are with
+     TREE_TYPE (type).  TYPE_MAIN_VARIANT (type) however will not contain
+     these quals.  Need to pass the former to gen_ctf_array_type.  */
+  tree gen_type = (TREE_CODE (type) == ARRAY_TYPE)
+		  ? type : TYPE_MAIN_VARIANT (type);
+
+  /* CTF type de-duplication in the compiler.  */
+  if (!ctf_type_exists (ctfc, gen_type, &type_id))
+    {
+      /* Encountering a CTF type for the first time.  Add the CTF type.  */
+
+      if (is_ctf_base_type (gen_type))
+	type_id = gen_ctf_base_type (ctfc, gen_type);
+
+      else if (RECORD_OR_UNION_TYPE_P (gen_type))
+	type_id = gen_ctf_sou_type (ctfc, gen_type);
+
+      else if (TREE_CODE (gen_type) == ARRAY_TYPE)
+	type_id = gen_ctf_array_type (tu_ctfc, gen_type);
+
+      else if (TREE_CODE (gen_type) == ENUMERAL_TYPE)
+	type_id = gen_ctf_enum_type (tu_ctfc, gen_type);
+
+      else if (POINTER_TYPE_P (gen_type))
+	type_id = gen_ctf_pointer_type (tu_ctfc, gen_type);
+
+      else if (TREE_CODE (gen_type) == FUNCTION_TYPE)
+	/* Function pointers.  */
+	type_id = gen_ctf_function_type (tu_ctfc, gen_type, NULL);
+
+      else if (TREE_CODE (gen_type) == VECTOR_TYPE)
+	/* CTF does not have representation for vector types.  Skip this type.
+	   FIXME- Note this TBD_CTF_REPRESENTATION_LIMIT.  */
+	inform (input_location,
+		"Skipping vector type as not represented in CTF");
+
+      else
+	/* No other type is expected for C frontend.  */
+	gcc_unreachable ();
+    }
+
+  /* Add qualifiers if any.  */
+  if ((type_id != CTF_NULL_TYPEID) && (cvr_quals & ctf_cvr_qual_mask))
+    type_id = gen_ctf_cvrquals (ctfc, type, type_id);
+
+  return type_id;
+}
+
+/* Generate CTF records for bitfield declarations.  */
+
+static ctf_id_t
+gen_ctf_bitfield_type_for_decl (ctf_container_ref ctfc, const tree field,
+				const ctf_id_t type_id)
+{
+  ctf_id_t bitfield_type_id = CTF_NULL_TYPEID;
+
+  gcc_assert (TREE_CODE (field) == FIELD_DECL);
+
+  gcc_assert (ctfc);
+  HOST_WIDE_INT size_in_bits = tree_to_shwi (DECL_SIZE (field));
+
+  ctf_encoding_t ep = {0,0,0};
+  /* Assume default encoding as unsigned.  */
+  uint32_t encoding = 0;
+  tree type = TREE_TYPE (field);
+
+  /* The type of a bit field can only be integral.  */
+  if (TREE_CODE (type) != INTEGER_TYPE)
+    gcc_unreachable ();
+
+  /* Handle both enum bitfields and integer bitfields.  */
+  if (TYPE_STRING_FLAG (type))
+    {
+      if (TYPE_UNSIGNED (type))
+	encoding = CTF_INT_CHAR;
+      else
+	encoding = CTF_INT_CHAR | CTF_INT_SIGNED;
+    }
+  else if (!TYPE_UNSIGNED (type))
+    encoding = CTF_INT_SIGNED;
+
+  ep.cte_format = encoding;
+  /* The offset of the slice is the offset into a machine word.
+     TBD Handle big-endian - should the offset be byte-order dependent ?  */
+  ep.cte_offset = int_bit_position (field) % BITS_PER_WORD;
+  ep.cte_bits = size_in_bits;
+
+  /* No type de-duplication for slices.
+     (Probe the CTF container with field_decl)
+     There is no way to de-duplicate two bitfields using just type or decl
+     references as dtd_key_decl.  Two field declarations may share the
+     same TREE_TYPE and DECL_BIT_FIELD_TYPE references, but may have different
+     offset and num bits.  */
+
+  bitfield_type_id = ctf_add_slice (ctfc, CTF_ADD_NONROOT, type_id, &ep,
+				    field);
+
+  return bitfield_type_id;
+}
+
+static ctf_id_t
+gen_ctf_type_for_decl (ctf_container_ref ctfc, tree decl)
+{
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == tcc_declaration);
+
+  ctf_id_t type_id = CTF_NULL_TYPEID;
+  tree type;
+  tree bitfield_type = NULL;
+
+  type = TREE_TYPE (decl);
+
+  /* In a FIELD_DECL, this indicates whether the field was a bitfield.  */
+  if (TREE_CODE (decl) == FIELD_DECL)
+    bitfield_type = DECL_BIT_FIELD_TYPE (decl);
+
+  /* Create CTF for the unqualified type, if it not done already.  If it's a
+     bitfield type, use that to generate the CTF type record.  */
+  if (bitfield_type)
+    type = bitfield_type;
+
+  /* CTF type de-duplication in the compiler.
+     Lookup if CTF for unqualified type has already been added.  CTF slices are
+     not shared across declarations.  */
+  if (ctf_type_exists (ctfc, type, &type_id))
+    {
+      if (!bitfield_type)
+	return type_id;
+    }
+  else
+    type_id = gen_ctf_type (ctfc, type);
+
+  /* Now, create CTF slice if it is a bitfield.  */
+  if (bitfield_type)
+    type_id = gen_ctf_bitfield_type_for_decl (ctfc, decl, type_id);
+
+  return type_id;
+}
+
+/* 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.  */
+  list_add_ctf_vars (ctfc, var);
+}
+
+/* CTF preprocess callback routine for CTF variables.  */
+
+bool
+ctf_dvd_preprocess_cb (tree const & ARG_UNUSED (key), ctf_dvdef_ref * slot,
+		       void * arg)
+{
+  tree var_decl;
+
+  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.  */
+  var_decl = var->dvd_decl;
+  if ((TREE_CODE_CLASS (TREE_CODE (var_decl)) == tcc_declaration)
+      && TREE_PUBLIC (var_decl))
+    {
+      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.  */
+
+bool
+ctf_dtd_preprocess_cb (ctf_dtdef_ref const & ARG_UNUSED (key),
+		       ctf_dtdef_ref * slot, void * arg)
+{
+  uint32_t kind, vlen;
+  tree func_decl;
+
+  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.  */
+  kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
+  if (kind == CTF_K_FUNCTION)
+    {
+      func_decl = ctftype->dtd_decl;
+      if ((TREE_CODE_CLASS (TREE_CODE (func_decl)) == tcc_declaration)
+	  && TREE_PUBLIC (func_decl))
+	{
+	  arg_ctfc->ctfc_gfuncs_list[dtd_arg->dtd_global_func_idx] = ctftype;
+	  dtd_arg->dtd_global_func_idx++;
+	  vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info);
+	  /* Update the function info section size in bytes.  Avoid using
+	     ctf_calc_num_vbytes API, the latter is only meant to convey
+	     the vlen bytes after CTF types in the CTF data types section.  */
+	  arg_ctfc->ctfc_num_funcinfo_bytes += (vlen + 2) * sizeof (uint32_t);
+	}
+    }
+
+  /* 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);
+      gcc_assert (num_ctf_types);
+    }
+
+  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 = tu_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");
+}
+
+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");
+}
+
+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");
+}
+
+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");
+}
+
+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");
+}
+
+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");
+}
+
+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");
+}
+
+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");
+}
+
+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");
+}
+
+/* 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 (! is_empty_container (ctfc))
+    {
+      gcc_assert (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 + get_ctfc_num_funcinfo_bytes (ctfc);
+      /* 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 + 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))
+		+ get_ctfc_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");
+}
+
+static void
+output_ctf_obj_info (ctf_container_ref ctfc)
+{
+  unsigned long 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");
+    }
+
+}
+
+static void
+output_ctf_func_info (ctf_container_ref ctfc)
+{
+  unsigned long i, j;
+  ctf_dtdef_ref ctftype;
+  uint32_t vlen;
+
+  if (!ctfc->ctfc_num_global_funcs) return;
+
+  /* Compiler spits out the function type, return type, and args of each global
+     function in the CTF funcinfo section.  In no specific order.
+     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];
+      vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info);
+
+      /* function type.  */
+      dw2_asm_output_data (4, ctftype->dtd_type, "funcinfo_func_type");
+
+      /* return type.  */
+      dw2_asm_output_data (4, ctftype->dtd_data.ctti_type,
+			   "funcinfo_func_return_type");
+
+      /* function args types.  */
+      for (j = 0; j < vlen; j++)
+	dw2_asm_output_data (4, ctftype->dtd_u.dtu_argv[j].farg_type,
+			     "funcinfo_func_args");
+    }
+}
+
+static void
+output_ctf_objtidx (ctf_container_ref ctfc)
+{
+  unsigned long 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");
+    }
+}
+
+static void
+output_ctf_funcidx (ctf_container_ref ctfc)
+{
+  unsigned long 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 sort 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]);
+    }
+}
+
+/* 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;
+    }
+}
+
+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);
+}
+
+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);
+}
+
+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);
+  uint32_t i;
+
+  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:
+	  {
+	    for (i = 0; i < vlen; i++)
+	      dw2_asm_output_data (4, ctftype->dtd_u.dtu_argv[i].farg_type,
+				   "dtu_argv");
+	    /* 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);
+	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;
+    }
+}
+
+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);
+}
+
+/* Output the 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]);
+    }
+}
+
+static void
+ctf_decl (tree decl)
+{
+  switch (TREE_CODE (decl))
+    {
+    case ERROR_MARK:
+      return;
+
+    case FUNCTION_DECL:
+      gen_ctf_function (tu_ctfc, decl);
+      break;
+
+    case VAR_DECL:
+      gen_ctf_variable (tu_ctfc, decl);
+      break;
+
+    case TYPE_DECL:
+      /* Stay aligned to what DWARF does.
+	 DWARF has this check so as to not emit stubs for types unless they are
+	 needed by other DIEs.  */
+      if (TYPE_DECL_SUPPRESS_DEBUG (decl))
+	return;
+
+      if (DECL_IS_BUILTIN (decl))
+	return;
+
+      /* If we are in terse mode, don't generate any CTF for types.  */
+      if (ctf_debug_info_level <= CTFINFO_LEVEL_TERSE)
+	return;
+      /* If function-scope tag, do not generate CTF type info for it.  */
+      if (decl_function_context (decl))
+	return;
+
+      gen_ctf_typedef (tu_ctfc, decl);
+
+      break;
+
+    default:
+      /* No other TREE_CODE is expected at this time.  */
+      gcc_unreachable ();
+    }
+}
+
+/* CTF routines interfacing to the compiler.  */
+
+void
+ctf_debug_init (void)
+{
+  init_ctf_containers ();
+}
+
+void
+ctf_early_finish (const char * filename)
+{
+  if (ctf_debug_info_level == CTFINFO_LEVEL_NONE)
+    return;
+
+  init_ctf_sections ();
+
+  ctfc_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 == get_cur_ctf_str_len (tu_ctfc));
+
+  delete_ctf_container (tu_ctfc);
+}
+
+void
+ctf_early_global_decl (tree decl)
+{
+  /* Generate CTF type information if appropriate debug level is set
+     to CTFINFO_LEVEL_NORMAL.  */
+
+  if (ctf_debug_info_level == CTFINFO_LEVEL_NORMAL)
+    ctf_decl (decl);
 }
 
 /* Reset all state within ctfout.c so that we can rerun the compiler
@@ -170,6 +1918,7 @@ ctfout_c_finalize (void)
   ctf_info_section = NULL;
 
   delete_ctf_container (tu_ctfc);
+  tu_ctfc = NULL;
 }
 
 #include "gt-ctfout.h"
diff --git a/gcc/ctfout.h b/gcc/ctfout.h
index f281aaf..6a01f82 100644
--- a/gcc/ctfout.h
+++ b/gcc/ctfout.h
@@ -24,10 +24,189 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_CTFOUT_H
 #define GCC_CTFOUT_H 1
 
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "tree-hash-traits.h"
 #include "ctf.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 unsigned long 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
+{
+  unsigned int ctti_name;	/* Reference to name in string table.  */
+  unsigned int ctti_info;	/* Encoded kind, variant length (see below).  */
+  union GTY ((desc ("0")))
+  {
+    unsigned int GTY ((tag ("0"))) _size;/* Size of entire type in bytes.  */
+    unsigned int GTY ((tag ("1"))) _type;/* Reference to another type.  */
+  } _u;
+  unsigned int ctti_lsizehi;	/* High 32 bits of type size in bytes.  */
+  unsigned int 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).  */
+  unsigned int dmd_name_offset;	/* Offset of the name in str table.  */
+  unsigned long 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;
+
+/* Function Argument.  (Encapsulated because GTY machinery does not like
+   non struct/union members.  See usage in ctf_dtdef_t.)  */
+
+typedef struct GTY (()) ctf_func_arg
+{
+  ctf_id_t farg_type;		/* Type identifier of the argument.  */
+} ctf_func_arg_t;
+
+typedef struct GTY (()) ctf_dtdef_key
+{
+  tree dtdk_key_decl;		/* Tree decl corresponding to the type.  */
+  unsigned int dtdk_key_flags;  /* Extra flags for hashing the type.  */
+} ctf_dtdef_key_t;
+
+/* Type definition for CTF generation.  */
+
+typedef struct GTY (()) ctf_dtdef
+{
+  ctf_dtdef_key_t 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.  */
+  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;
+} ctf_dtdef_t;
+
+#define dtd_decl dtd_key.dtdk_key_decl
+#define dtd_key_flags dtd_key.dtdk_key_flags
+
+/* Variable definition for CTF generation.  */
+
+typedef struct GTY (()) ctf_dvdef
+{
+  tree dvd_decl;		/* Tree decl corresponding to the variable.  */
+  const char * dvd_name;	/* Name associated with variable.  */
+  unsigned int dvd_name_offset;	/* Offset of the name in str table.  */
+  ctf_id_t dvd_type;		/* Type of variable.  */
+} ctf_dvdef_t;
+
+typedef ctf_dvdef_t * ctf_dvdef_ref;
+typedef ctf_dtdef_t * ctf_dtdef_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 ctf_dtdef_hash : 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);
+};
+
 /* CTF container structure.
-   It is the context passed around when generating CTF debug info.  There is
+   It is the context passed around when generating ctf debug info.  There is
    one container per translation unit.  */
 
 typedef struct GTY (()) ctf_container
@@ -36,12 +215,68 @@ typedef struct GTY (()) ctf_container
   unsigned short ctfc_magic;
   unsigned char ctfc_version;
   unsigned char ctfc_flags;
-  /* CTF Types.  */
-  // hash_map <ctf_dtdef_hash, ctf_dtdefp_t> * GTY (()) ctfc_types;
+  unsigned int ctfc_cuname_offset;
+
+  /* CTF types.  */
+  hash_map <ctf_dtdef_hash, ctf_dtdef_ref> * GTY (()) ctfc_types;
+  /* CTF variables.  */
+  hash_map <tree_decl_hash, ctf_dvdef_ref> * GTY (()) ctfc_vars;
+  /* CTF string table.  */
+  ctf_strtable_t ctfc_strtable;
+
+  unsigned long ctfc_num_types;
+  unsigned long ctfc_num_stypes;
+  unsigned long ctfc_num_global_funcs;
+  unsigned long ctfc_num_global_objts;
+
+  unsigned long ctfc_num_funcinfo_bytes;
+  /* 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.  */
+  unsigned long ctfc_num_vlen_bytes;
+
+  /* Next CTF type id to assign.  */
+  ctf_id_t ctfc_nextid;
+  /* List of pre-processed CTF Variables.  CTF requires that the variables
+     appear in the sorted order of their names.  */
+  ctf_dvdef_t ** GTY ((length ("%h.ctfc_vars ? %h.ctfc_vars->elements () : 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 ("%h.ctfc_types ? %h.ctfc_types->elements () : 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 ("%h.ctfc_num_global_funcs"))) 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 ("%h.ctfc_num_global_objts"))) 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.  */
+  unsigned long ctfc_numbytes_asm;
+   /* Total length of all strings in CTF.  */
+  size_t ctfc_strlen;
+
 } ctf_container_t;
 
 typedef ctf_container_t * ctf_container_ref;
 
+/* If the next ctf type id is still set to the init value, no ctf records to
+   report.  */
+#define is_empty_container(ctfc) (((ctfc)->ctfc_nextid == CTF_INIT_TYPEID))
+#define get_num_ctf_vars(ctfc)   (ctfc->ctfc_vars->elements ())
+#define get_num_ctf_types(ctfc)  (ctfc->ctfc_types->elements ())
+
+#define get_cur_ctf_str_len(ctfc)      ((ctfc)->ctfc_strtable.ctstab_len)
+
+#define get_ctfc_num_vlen_bytes(ctfc)	((ctfc)->ctfc_num_vlen_bytes)
+#define get_ctfc_num_funcinfo_bytes(ctfc) ((ctfc)->ctfc_num_funcinfo_bytes)
+
 void ctf_debug_init (void);
 
 void ctf_early_global_decl (tree decl);
@@ -50,4 +285,80 @@ void ctf_early_finish (const char * filename);
 
 void ctfout_c_finalize (void);
 
+/* 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.  */
+
+/* Interface from ctfcreate.c to ctfout.c.
+   These APIs create CTF types and add them to the CTF container associated
+   with the translation unit.  The return value is the typeID of the CTF type
+   added to the container.  */
+extern ctf_id_t ctf_add_volatile (ctf_container_ref, uint32_t, ctf_id_t, tree,
+				  uint32_t);
+extern ctf_id_t ctf_add_const (ctf_container_ref, uint32_t, ctf_id_t, tree,
+			       uint32_t);
+extern ctf_id_t ctf_add_restrict (ctf_container_ref, uint32_t, ctf_id_t, tree,
+				  uint32_t);
+extern ctf_id_t ctf_add_enum (ctf_container_ref, uint32_t, const char *,
+			      HOST_WIDE_INT, tree);
+extern ctf_id_t ctf_add_slice (ctf_container_ref, uint32_t, ctf_id_t,
+			       const ctf_encoding_t *, tree);
+extern ctf_id_t ctf_add_float (ctf_container_ref, uint32_t, const char *,
+			       const ctf_encoding_t *, tree);
+extern ctf_id_t ctf_add_integer (ctf_container_ref, uint32_t, const char *,
+				 const ctf_encoding_t *, tree);
+extern ctf_id_t ctf_add_pointer (ctf_container_ref, uint32_t flag, ctf_id_t,
+				 tree);
+extern ctf_id_t ctf_add_array (ctf_container_ref, uint32_t,
+			       const ctf_arinfo_t *, tree);
+extern ctf_id_t ctf_add_forward (ctf_container_ref, uint32_t, const char *,
+				 uint32_t, tree);
+extern ctf_id_t ctf_add_typedef (ctf_container_ref, uint32_t, const char *,
+				 ctf_id_t, tree);
+extern ctf_id_t ctf_add_function (ctf_container_ref, uint32_t, const char *,
+				  const ctf_funcinfo_t *, ctf_func_arg_t *,
+				  tree);
+extern ctf_id_t ctf_add_sou (ctf_container_ref, uint32_t, const char *,
+			     uint32_t, size_t, tree);
+
+extern int ctf_add_enumerator (ctf_container_ref, ctf_id_t, const char *,
+			       HOST_WIDE_INT, tree);
+extern int ctf_add_member_offset (ctf_container_ref, tree, const char *,
+				  ctf_id_t, unsigned long);
+extern int ctf_add_variable (ctf_container_ref, const char *, ctf_id_t, tree);
+
+/* Interface from ctfutils.c.
+   Utility functions for CTF generation.  */
+
+#define ctf_dmd_list_next(elem)		((ctf_dmdef_t *)((elem)->dmd_next))
+
+extern void ctf_dmd_list_append (ctf_dmdef_t **, ctf_dmdef_t *);
+
+extern void ctf_dtd_insert (ctf_container_ref, ctf_dtdef_ref);
+extern void ctf_dtd_delete (ctf_container_ref, ctf_dtdef_ref);
+extern ctf_dtdef_ref ctf_dtd_lookup (const ctf_container_ref, const tree);
+extern ctf_dtdef_ref ctf_dtd_lookup_with_flags (const ctf_container_ref,
+						const tree,
+						const unsigned int);
+
+extern void ctf_dvd_insert (ctf_container_ref, ctf_dvdef_ref);
+extern void ctf_dvd_delete (ctf_container_ref, ctf_dvdef_ref);
+extern ctf_dvdef_ref ctf_dvd_lookup (const ctf_container_ref, const tree);
+
+extern int ctf_varent_compare (const void *, const void *);
+extern unsigned long ctf_calc_num_vbytes (ctf_dtdef_ref);
+
+/* Add a str to the CTF string table.  */
+extern const char * ctf_add_string (ctf_container_ref, const char *,
+				    uint32_t *);
+
+extern void list_add_ctf_vars (ctf_container_ref, ctf_dvdef_ref);
+
+/* Interface from ctfout.c to ctfutils.c.  */
+
+extern hashval_t hash_dtd_tree_decl (tree, uint32_t);
+extern hashval_t hash_dvd_tree_decl (tree);
+
 #endif /* GCC_CTFOUT_H */
diff --git a/gcc/ctfutils.c b/gcc/ctfutils.c
new file mode 100644
index 0000000..805c91f
--- /dev/null
+++ b/gcc/ctfutils.c
@@ -0,0 +1,198 @@
+/* Functions to create and update CTF from GCC.
+   Copyright (C) 2019 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 implementation of various utility functions to collect
+   and keep CTF information.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "ctfout.h"
+
+/* Append member definition to the list.  Member list is a singly-linked list
+   with list start pointing to the head.  */
+
+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;
+}
+
+/* Compare two CTF variable definition entries.  Currently used for sorting
+   by name.  */
+
+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;
+}
+
+/* Add str to CTF string table.  No de-duplication of CTF strings is done by
+   the compiler.  */
+
+static void
+ctfc_strtable_add_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;
+}
+
+const char *
+ctf_add_string (ctf_container_ref ctfc, 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 = get_cur_ctf_str_len (ctfc);
+
+  /* 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 *, ctfc->ctfc_strtable.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_add_str (&(ctfc->ctfc_strtable), ctf_string);
+      /* Add string to the string table.  Keep number of strings updated.  */
+      ctfc->ctfc_strtable.ctstab_num++;
+      /* Keep the number of bytes contained in the CTF string table updated.  */
+      (ctfc)->ctfc_strtable.ctstab_len += len;
+    }
+
+  *name_offset = str_offset;
+
+  return (const char *) ctf_string;
+}
+
+/* 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.  */
+
+unsigned long
+ctf_calc_num_vbytes (ctf_dtdef_ref ctftype)
+{
+  uint32_t size;
+  unsigned long 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;
+  uint32_t size_per_member = 0;
+  unsigned int num_members = 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:
+	/* 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;
+}
+
+void
+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;
+}
diff --git a/include/ctf.h b/include/ctf.h
index 3a6f266..b75eba2 100644
--- a/include/ctf.h
+++ b/include/ctf.h
@@ -52,10 +52,15 @@ extern "C"
 
    The CTF file or section itself has the following structure:
 
-   +--------+--------+---------+----------+----------+-------+--------+
-   |  file  |  type  |  data   | function | variable | data  | string |
-   | header | labels | objects |   info   |   info   | types | table  |
-   +--------+--------+---------+----------+----------+-------+--------+
+   +--------+--------+---------+----------+--------+----------+...
+   |  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
@@ -74,14 +79,27 @@ extern "C"
    For each data object, the type ID (a small integer) is recorded.  For each
    function, the type ID of the return type and argument types is recorded.
 
+   For situations in which the order of the symbols in the symtab is not known,
+   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.
+   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.
 
    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.
+   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
@@ -125,9 +143,12 @@ 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.  */
@@ -142,13 +163,14 @@ typedef struct ctf_header
 
 /* Data format version number.  */
 
-/* v1 upgraded to v2 is not quite the same as native v2 (the boundary between
-   parent and child types is different), 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".) */
+/* 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
@@ -378,13 +400,17 @@ union
    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.  */
+   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 char cts_offset;
-  unsigned char cts_bits;
+  unsigned short cts_offset;
+  unsigned short cts_bits;
 } ctf_slice_t;
 
 typedef struct ctf_array
-- 
1.8.3.1



More information about the Gcc-patches mailing list