@@ -1255,6 +1255,8 @@ OBJS = \
cfgloopmanip.o \
cfgrtl.o \
ctfout.o \
+ ctfutils.o \
+ ctfcreate.o \
symtab.o \
cgraph.o \
cgraphbuild.o \
new file mode 100644
@@ -0,0 +1,526 @@
+/* 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);
+
+ /* A void type has a size of zero. A power of 2 is expected otherwise. */
+ gcc_assert (!roundup_nbytes
+ || (exact_log2 (roundup_nbytes) != -1));
+ 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 > 0 && 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 > 0 && 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 > 0 && 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)
+{
+ /* 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);
+
+ ctf_dmdef_t * dmd;
+
+ uint32_t kind, vlen, root;
+
+ 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);
+
+ 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;
+ /* Variable value is of type HOST_WIDE_INT, dmd_value is int32_t on the other
+ hand. Check bounds. TBD WARN - warn instead or skip type ? */
+ gcc_assert ((value <= INT_MAX) && (value >= INT_MIN));
+ 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;
+}
@@ -46,12 +46,16 @@ static GTY (()) section * ctf_info_section;
#ifndef CTF_INFO_SECTION_NAME
#define CTF_INFO_SECTION_NAME ".ctf"
#endif
+#ifndef CTF_LTO_INFO_SECTION_NAME
+#define CTF_LTO_INFO_SECTION_NAME ".gnu.debuglto_.ctf"
+#endif
/* Section flags for .ctf section. */
/* CTF debug info section. */
#define CTF_INFO_SECTION_FLAGS (SECTION_DEBUG)
+#define CTF_LTO_INFO_SECTION_FLAGS (SECTION_DEBUG | SECTION_EXCLUDE)
/* Maximum size (in bytes) of an artificially generated CTF label. */
@@ -63,8 +67,297 @@ 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
+{
+ 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;
+ }
+}
+
+/* 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 +368,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,22 +399,920 @@ 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;
+ }
+
+ ctfc= NULL;
}
}
/* Initialize the various sections and labels for CTF output. */
void
-init_ctf_sections (void)
+init_ctf_sections (bool early_lto_debug)
{
- ctf_info_section = get_section (CTF_INFO_SECTION_NAME,
- CTF_INFO_SECTION_FLAGS,
- NULL);
+ // TBD - If the producer is LTO, there can be multiple translation units
+
+ if (early_lto_debug)
+ {
+ ctf_info_section = get_section (CTF_LTO_INFO_SECTION_NAME,
+ CTF_LTO_INFO_SECTION_FLAGS,
+ NULL);
+ }
+ else
+ {
+ 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++);
}
+/* 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). */
+
+/* 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)
+{
+ 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. */
+ 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 * 8;
+
+ 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 * 8;
+
+ type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
+ &ctf_encoding, type);
+ break;
+
+ case REAL_TYPE:
+ if (size == sizeof (float))
+ encoding = CTF_FP_SINGLE;
+ else if (size == sizeof (double))
+ encoding = CTF_FP_DOUBLE;
+ else if (size == sizeof (long double))
+ 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 * 8;
+
+ type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+ &ctf_encoding, type);
+ break;
+
+ /* FIXME - We do not have a fixed point type in CTF yet. */
+ case FIXED_POINT_TYPE:
+ /* TBD WARN - warn instead or skip type ? */
+ gcc_assert (false);
+ break;
+
+ case COMPLEX_TYPE:
+ encoding = 0;
+
+ if (size == sizeof (float))
+ encoding = CTF_FP_CPLX;
+ else if (size == sizeof (double))
+ encoding = CTF_FP_DCPLX;
+ else if (size == sizeof (long double))
+ 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 * 8;
+
+ type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
+ &ctf_encoding, type);
+ break;
+
+ case VOID_TYPE:
+ encoding = CTF_INT_SIGNED;
+ ctf_encoding.cte_format = encoding;
+ ctf_encoding.cte_bits = 0;
+
+ 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 - confirm this behaviour. */
+ 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;
+ 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 != 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;
+}
+
+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
+gen_ctf_enum_const_list (ctf_container_ref ctfc, const tree enum_type,
+ const ctf_id_t enum_type_id)
+{
+ tree link;
+ tree enum_value;
+ HOST_WIDE_INT value;
+ /* Append the enum values to the CTF_K_ENUM record. */
+ for (link = TYPE_VALUES (enum_type); link != NULL; link = TREE_CHAIN (link))
+ {
+ 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));
+
+ value = TREE_INT_CST_LOW (enum_value);
+ const char * enum_valname = IDENTIFIER_POINTER (TREE_PURPOSE (link));
+ gcc_assert (enum_valname);
+
+ ctf_add_enumerator (ctfc, enum_type_id, enum_valname, value, enum_type);
+ }
+}
+
+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;
+
+ 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)
+{
+ 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;
+}
+
+/* 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)
+{
+ tree qualified_type;
+ int flags;
+ uint32_t cvrint = 0;
+ int quals_index = 0;
+
+ ctf_id_t qual_type_id = type_id;
+ int cvr_quals = get_cvr_quals_for_type (type);
+
+ 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;
+}
+
+static ctf_id_t
+gen_ctf_sou_type (ctf_container_ref ctfc, tree sou_type)
+{
+ 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);
+ }
+ 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
+ /* No other type is expected for C frontend. */
+ gcc_unreachable ();
+ }
+
+ /* Add qualifiers if any. */
+ if (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)
+{
+ ctf_dvd_preprocess_arg_t * dvd_arg = (ctf_dvd_preprocess_arg_t *)arg;
+
+ ctf_container_ref arg_ctfc = dvd_arg->dvd_arg_ctfc;
+ ctf_dvdef_ref var = (ctf_dvdef_ref) *slot;
+
+ ctf_preprocess_var (arg_ctfc, var);
+
+ 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_vars = ctfc->ctfc_vars->elements ();
+ if (num_ctf_vars)
+ {
+ ctf_dvd_preprocess_arg_t dvd_arg;
+ 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);
+ }
+
+ size_t num_ctf_types = ctfc->ctfc_types->elements ();
+
+ /* Initialize an array to keep track of the CTF functions types for global
+ functions in the 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
@@ -124,7 +1324,78 @@ ctf_asm_preamble (ctf_container_ref ctfc)
dw2_asm_output_data (1, ctfc->ctfc_flags, "CTF preamble flags");
}
-/* Output the CTF header. */
+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)
@@ -133,6 +1404,282 @@ output_ctf_header (ctf_container_ref ctfc)
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");
+
+ 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 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));
+
+ /* Vars appear after function info. */
+ varoff = funcoff + get_ctfc_num_funcinfo_bytes (ctfc);
+ /* 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 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_func_info (ctf_container_ref ctfc)
+{
+ unsigned long i, j;
+ ctf_dtdef_ref ctftype;
+ uint32_t vlen;
+
+ /* Compiler spits out the function type, return type, and args of each global
+ function in the CTF funcinfo section. In no specific order.
+ TBD - An index needs to be added to associate these with the 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");
+ }
+}
+
+/* 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. */
@@ -149,16 +1696,32 @@ ctf_early_finish (const char * ARG_UNUSED (filename))
if (ctf_debug_info_level == CTFINFO_LEVEL_NONE)
return;
- init_ctf_sections ();
+ init_ctf_sections (false);
+
+ /* Pre-process CTF before generating assembly. */
+ ctf_preprocess (tu_ctfc);
output_ctf_header (tu_ctfc);
+ output_ctf_func_info (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 ARG_UNUSED (decl))
+ctf_early_global_decl (tree decl)
{
/* Generate CTF type information if appropriate debug level is set
- (ctf_debug_info_level == CTFINFO_LEVEL_NORMAL). */
+ 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 +1733,7 @@ ctfout_c_finalize (void)
ctf_info_section = NULL;
delete_ctf_container (tu_ctfc);
+ tu_ctfc = NULL;
}
#include "gt-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,63 @@ 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;
+
+ /* 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_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;
+
+ /* 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 +280,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 */
new file mode 100644
@@ -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;
+}
@@ -378,13 +378,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