Message ID | 1563408480-4665-5-git-send-email-indu.bhagat@oracle.com |
---|---|
State | New |
Headers | show |
Series | Support for CTF in GCC | expand |
This patch was missing a stub from Makefile.in diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 5487377..0994f3b 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1257,6 +1257,8 @@ OBJS = \ cfgloopmanip.o \ cfgrtl.o \ ctfout.o \ + ctfutils.o \ + ctfcreate.o \ symtab.o \ cgraph.o \ cgraphbuild.o \ Sorry for inconvenience, Indu On Wed, Jul 17, 2019 at 4:58 PM Indu Bhagat <indu.bhagat@oracle.com> wrote: > > 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 >
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