diff options
Diffstat (limited to 'gcc/ctfc.c')
-rw-r--r-- | gcc/ctfc.c | 969 |
1 files changed, 969 insertions, 0 deletions
diff --git a/gcc/ctfc.c b/gcc/ctfc.c new file mode 100644 index 0000000..1a6ddb8 --- /dev/null +++ b/gcc/ctfc.c @@ -0,0 +1,969 @@ +/* Generate CTF. + Copyright (C) 2019,2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "toplev.h" +#include "ctfc.h" +#include "diagnostic-core.h" + +/* A CTF container object - one per translation unit. */ + +ctf_container_ref tu_ctfc; + +ctf_container_ref +ctf_get_tu_ctfc (void) +{ + return tu_ctfc; +} + +/* If the next ctf type id is still set to the init value, no ctf records to + report. */ +bool +ctfc_is_empty_container (ctf_container_ref ctfc) +{ + return ((ctfc)->ctfc_nextid == CTF_INIT_TYPEID); +} + +/* Get the total number of CTF types in the container. */ + +unsigned int +ctfc_get_num_ctf_types (ctf_container_ref ctfc) +{ + return ctfc->ctfc_types->elements (); +} + +/* Get the total number of CTF variables in the container. */ + +unsigned int ctfc_get_num_ctf_vars (ctf_container_ref ctfc) +{ + return ctfc->ctfc_vars->elements (); +} + +/* Get reference to the CTF string table or the CTF auxilliary + string table. */ + +ctf_strtable_t * +ctfc_get_strtab (ctf_container_ref ctfc, int aux) +{ + return aux ? &(ctfc)->ctfc_aux_strtable : &(ctfc->ctfc_strtable); +} + +/* Get the length of the specified string table of the CTF container. */ + +size_t +ctfc_get_strtab_len (ctf_container_ref ctfc, int aux) +{ + ctf_strtable_t * strtab = ctfc_get_strtab (ctfc, aux); + return strtab->ctstab_len; +} + +/* Get the number of bytes to represent the variable length portion of all CTF + types in the CTF container. */ + +size_t ctfc_get_num_vlen_bytes (ctf_container_ref ctfc) +{ + return ctfc->ctfc_num_vlen_bytes; +} + +/* Return which member of the union is used in CTFTYPE. Used for garbage + collection. */ + +enum ctf_dtu_d_union_enum +ctf_dtu_d_union_selector (ctf_dtdef_ref ctftype) +{ + uint32_t kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info); + switch (kind) + { + case CTF_K_UNKNOWN: + case CTF_K_INTEGER: + case CTF_K_FLOAT: + return CTF_DTU_D_ENCODING; + case CTF_K_STRUCT: + case CTF_K_UNION: + case CTF_K_ENUM: + return CTF_DTU_D_MEMBERS; + case CTF_K_ARRAY: + return CTF_DTU_D_ARRAY; + case CTF_K_FUNCTION: + return CTF_DTU_D_ARGUMENTS; + case CTF_K_SLICE: + return CTF_DTU_D_SLICE; + default: + /* The largest member as default. */ + return CTF_DTU_D_ARRAY; + } +} + +/* Insert CTF type into the CTF container. */ + +static void +ctf_dtd_insert (ctf_container_ref ctfc, ctf_dtdef_ref dtd) +{ + bool existed = false; + ctf_dtdef_ref entry = dtd; + + ctf_dtdef_ref * item = ctfc->ctfc_types->find_slot (entry, INSERT); + if (*item == NULL) + *item = dtd; + else + existed = true; + /* Duplicate CTF type records not expected to be inserted. */ + gcc_assert (!existed); +} + +/* Lookup CTF type given a DWARF die for the type. */ + +static ctf_dtdef_ref +ctf_dtd_lookup (const ctf_container_ref ctfc, const dw_die_ref type) +{ + ctf_dtdef_t entry; + entry.dtd_key = type; + + ctf_dtdef_ref * slot = ctfc->ctfc_types->find_slot (&entry, NO_INSERT); + + if (slot) + return (ctf_dtdef_ref)*slot; + + return NULL; +} + +/* Insert CTF variable into the CTF container. */ + +static void +ctf_dvd_insert (ctf_container_ref ctfc, ctf_dvdef_ref dvd) +{ + bool existed = false; + ctf_dvdef_ref entry = dvd; + + ctf_dvdef_ref * item = ctfc->ctfc_vars->find_slot (entry, INSERT); + if (*item == NULL) + *item = dvd; + else + existed = true; + /* Duplicate variable records not expected to be inserted. */ + gcc_assert (!existed); +} + +/* Lookup CTF variable given a DWARF die for the decl. */ + +ctf_dvdef_ref +ctf_dvd_lookup (const ctf_container_ref ctfc, dw_die_ref die) +{ + ctf_dvdef_t entry; + entry.dvd_key = die; + + ctf_dvdef_ref * slot = ctfc->ctfc_vars->find_slot (&entry, NO_INSERT); + + if (slot) + return (ctf_dvdef_ref)*slot; + + return NULL; +} + +/* Append member definition to the list. Member list is a singly-linked list + with list start pointing to the head. */ + +static void +ctf_dmd_list_append (ctf_dmdef_t ** dmd, ctf_dmdef_t * elem) +{ + ctf_dmdef_t * tail = (dmd && *dmd) ? *dmd : NULL; + if (tail) + { + while (tail->dmd_next) + tail = tail->dmd_next; + + tail->dmd_next = elem; + } + else + *dmd = elem; + + elem->dmd_next = NULL; +} + +/* Append function argument to the list. Member list is a singly-linked list + with list start pointing to the head. */ + +static void +ctf_farg_list_append (ctf_func_arg_t ** farg, ctf_func_arg_t * elem) +{ + ctf_func_arg_t * tail = (farg && *farg) ? *farg : NULL; + if (tail) + { + while (tail->farg_next) + tail = tail->farg_next; + + tail->farg_next = elem; + } + else + *farg = elem; + + elem->farg_next = NULL; +} + +/* Append str to the CTF string table. */ + +static void +ctfc_strtable_append_str (ctf_strtable_t * str_table, const char * str) +{ + ctf_string_t * ctf_string = ggc_cleared_alloc<ctf_string_t> (); + /* Keep a reference to the input STR. */ + ctf_string->cts_str = str; + ctf_string->cts_next = NULL; + + if (!str_table->ctstab_head) + str_table->ctstab_head = ctf_string; + + /* Append to the end of the list. */ + if (str_table->ctstab_tail) + str_table->ctstab_tail->cts_next = ctf_string; + + str_table->ctstab_tail = ctf_string; +} + +/* Wrapper function to add str to the CTF string table. No de-duplication of + CTF strings is done by the compiler. */ + +static const char * +ctfc_strtable_add_str (ctf_strtable_t * str_table, const char * name, + uint32_t * name_offset) +{ + size_t len; + char * ctf_string; + /* Return value is the offset to the string in the string table. */ + uint32_t str_offset = str_table->ctstab_len; + + /* Add empty string only once at the beginning of the string table. Also, do + not add null strings, return the offset to the empty string for them. */ + if ((!name || (name != NULL && !strcmp (name, ""))) && str_offset) + { + ctf_string = CONST_CAST (char *, str_table->ctstab_estr); + str_offset = 0; + } + else + { + gcc_assert (name); + /* Add null-terminated strings to the string table. */ + len = strlen (name) + 1; + ctf_string = CONST_CAST (char *, ggc_strdup (name)); + + ctfc_strtable_append_str (str_table, ctf_string); + /* Add string to the string table. Keep number of strings updated. */ + str_table->ctstab_num++; + /* Keep the number of bytes contained in the string table updated. */ + str_table->ctstab_len += len; + } + + *name_offset = str_offset; + + return (const char *) ctf_string; + +} + +/* Add string to the appropriate string table in the CTF container. */ + +const char * +ctf_add_string (ctf_container_ref ctfc, const char * name, + uint32_t * name_offset, int aux_str = CTF_STRTAB) +{ + /* Get the CTF string table or the CTF auxilliary string table, + as applicable. */ + ctf_strtable_t *str_table = ctfc_get_strtab (ctfc, aux_str); + return ctfc_strtable_add_str (str_table, name, name_offset); +} + +/* Add the compilation unit (CU) name string to the the CTF string table. The + CU name has a prepended pwd string if it is a relative path. Also set the + CU name offset in the CTF container. */ + +void +ctf_add_cuname (ctf_container_ref ctfc, const char * filename) +{ + char * cuname = NULL; + + /* (filename at this point of compilation cannot be null). */ + + if (!IS_DIR_SEPARATOR (filename[0])) + { + /* Filename is a relative path. */ + const char * cu_pwd = get_src_pwd (); + const int cu_pwd_len = strlen (cu_pwd); + + /* Add a DIR_SEPARATOR char before the filename. */ + const int len = cu_pwd_len + 2 + strlen (filename); + + cuname = (char *) ggc_alloc_atomic (len); + memset (cuname, 0, len); + + strcpy (cuname, cu_pwd); + cuname[cu_pwd_len] = DIR_SEPARATOR; + cuname[cu_pwd_len+1] = 0; + strcat (cuname, filename); + } + else + /* Filename is an absolute path. */ + cuname = CONST_CAST (char *, ggc_strdup (filename)); + + ctf_add_string (ctfc, cuname, &(ctfc->ctfc_cuname_offset)); + /* Add 1 as CTF strings in the CTF string table are null-terminated + strings. */ + ctfc->ctfc_strlen += strlen (cuname) + 1; + + /* Mark cuname for garbage collection. */ + cuname = NULL; +} + +/* Functions to create CTF types. + + These functions perform the task of adding CTF types to the CTF container. + No de-duplication is done by them; the onus is on the calling function to do + so. The caller must first do a lookup via ctf_dtd_lookup or + ctf_dvd_lookup, as applicable, to ascertain that the CTF type or the CTF + variable respectively does not already exist, and then add it. */ + +static ctf_id_t +ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name, + ctf_dtdef_ref * rp, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + gcc_assert (flag == CTF_ADD_NONROOT || flag == CTF_ADD_ROOT); + + dtd = ggc_cleared_alloc<ctf_dtdef_t> (); + + type = ctfc->ctfc_nextid++; + gcc_assert (type < CTF_MAX_TYPE); /* CTF type ID overflow. */ + + /* Buffer the strings in the CTF string table. */ + dtd->dtd_name = ctf_add_string (ctfc, name, &(dtd->dtd_data.ctti_name)); + dtd->dtd_type = type; + dtd->dtd_key = die; + + if ((name != NULL) && strcmp (name, "")) + ctfc->ctfc_strlen += strlen (name) + 1; + + ctf_dtd_insert (ctfc, dtd); + + *rp = dtd; + return type; +} + +static ctf_id_t +ctf_add_encoded (ctf_container_ref ctfc, uint32_t flag, const char * name, + const ctf_encoding_t * ep, uint32_t kind, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + type = ctf_add_generic (ctfc, flag, name, &dtd, die); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0); + + uint32_t roundup_nbytes = (ROUND_UP (ep->cte_bits, BITS_PER_UNIT) + / BITS_PER_UNIT); + + /* FIXME, stay close to what libctf does. But by getting next power of two, + aren't we conveying less precise information. E.g. floating point mode + XF has a size of 12 bytes. */ + dtd->dtd_data.ctti_size = roundup_nbytes ? (1 << ceil_log2 (roundup_nbytes)) + : roundup_nbytes; + dtd->dtd_u.dtu_enc = *ep; + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + uint32_t kind, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + gcc_assert (ref <= CTF_MAX_TYPE); + + type = ctf_add_generic (ctfc, flag, NULL, &dtd, die); + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0); + /* Caller of this API must guarantee that a CTF type with id = ref already + exists. This will also be validated for us at link-time. */ + dtd->dtd_data.ctti_type = (uint32_t) ref; + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_forward (ctf_container_ref ctfc, uint32_t flag, const char * name, + uint32_t kind, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type = 0; + + type = ctf_add_generic (ctfc, flag, name, &dtd, die); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0); + dtd->dtd_data.ctti_type = kind; + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_typedef (ctf_container_ref ctfc, uint32_t flag, const char * name, + ctf_id_t ref, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + gcc_assert (ref <= CTF_MAX_TYPE); + /* Nameless Typedefs are not expected. */ + gcc_assert ((name != NULL) && strcmp (name, "")); + + type = ctf_add_generic (ctfc, flag, name, &dtd, die); + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_TYPEDEF, flag, 0); + /* Caller of this API must guarantee that a CTF type with id = ref already + exists. This will also be validated for us at link-time. */ + dtd->dtd_data.ctti_type = (uint32_t) ref; + + gcc_assert (dtd->dtd_type != dtd->dtd_data.ctti_type); + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + uint32_t bit_offset, uint32_t bit_size, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + uint32_t roundup_nbytes; + + gcc_assert ((bit_size <= 255) && (bit_offset <= 255)); + + gcc_assert (ref <= CTF_MAX_TYPE); + + type = ctf_add_generic (ctfc, flag, NULL, &dtd, die); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0); + + roundup_nbytes = (ROUND_UP (bit_size, BITS_PER_UNIT) / BITS_PER_UNIT); + /* FIXME, stay close to what libctf does. But by getting next power of two, + aren't we conveying less precise information, especially for bitfields. + For example, cte_bits = 33, roundup_nbytes = 5, ctti_size = 8 in the + implementation below. */ + dtd->dtd_data.ctti_size = roundup_nbytes ? (1 << ceil_log2 (roundup_nbytes)) + : 0; + + /* Caller of this API must guarantee that a CTF type with id = ref already + exists. This will also be validated for us at link-time. */ + dtd->dtd_u.dtu_slice.cts_type = (uint32_t) ref; + dtd->dtd_u.dtu_slice.cts_bits = bit_size; + dtd->dtd_u.dtu_slice.cts_offset = bit_offset; + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_float (ctf_container_ref ctfc, uint32_t flag, + const char * name, const ctf_encoding_t * ep, dw_die_ref die) +{ + return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_FLOAT, die)); +} + +ctf_id_t +ctf_add_integer (ctf_container_ref ctfc, uint32_t flag, + const char * name, const ctf_encoding_t * ep, dw_die_ref die) +{ + return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_INTEGER, die)); +} + +ctf_id_t +ctf_add_unknown (ctf_container_ref ctfc, uint32_t flag, + const char * name, const ctf_encoding_t * ep, dw_die_ref die) +{ + return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_UNKNOWN, die)); +} + +ctf_id_t +ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + dw_die_ref die) +{ + return (ctf_add_reftype (ctfc, flag, ref, CTF_K_POINTER, die)); +} + +ctf_id_t +ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp, + dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + gcc_assert (arp); + + /* Caller of this API must make sure CTF type for arp->ctr_contents and + arp->ctr_index are already added. This will also be validated for us at + link-time. */ + + type = ctf_add_generic (ctfc, flag, NULL, &dtd, die); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0); + dtd->dtd_data.ctti_size = 0; + dtd->dtd_u.dtu_arr = *arp; + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name, + HOST_WIDE_INT size, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + /* In the compiler, no need to handle the case of promoting forwards to + enums. This comment is simply to note a divergence from libctf. */ + + /* The compiler does, however, update any previously existing forward types + to non-root. CTF does not allow existence of two root types with the same + name. */ + ctf_dtdef_ref enum_fwd_type = ctf_dtd_lookup (ctfc, die); + if (enum_fwd_type) + { + enum_fwd_type->dtd_data.ctti_info + = CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0); + } + + type = ctf_add_generic (ctfc, flag, name, &dtd, die); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0); + + /* Size in bytes should always fit, of course. + TBD WARN - warn instead? */ + gcc_assert (size <= CTF_MAX_SIZE); + + dtd->dtd_data.ctti_size = size; + + ctfc->ctfc_num_stypes++; + + return type; +} + +int +ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name, + HOST_WIDE_INT value, dw_die_ref die) +{ + ctf_dmdef_t * dmd; + uint32_t kind, vlen, root; + + /* Callers of this API must make sure that CTF_K_ENUM with enid has been + addded. This will also be validated for us at link-time. */ + ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die); + gcc_assert (dtd); + gcc_assert (dtd->dtd_type == enid); + gcc_assert (name); + + kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info); + root = CTF_V2_INFO_ISROOT (dtd->dtd_data.ctti_info); + vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info); + + gcc_assert (kind == CTF_K_ENUM && vlen < CTF_MAX_VLEN); + + /* Enum value is of type HOST_WIDE_INT in the compiler, dmd_value is int32_t + on the other hand. Check bounds and skip adding this enum value if out of + bounds. */ + if ((value > INT_MAX) || (value < INT_MIN)) + { + /* FIXME - Note this TBD_CTF_REPRESENTATION_LIMIT. */ + return (1); + } + + dmd = ggc_cleared_alloc<ctf_dmdef_t> (); + + /* Buffer the strings in the CTF string table. */ + dmd->dmd_name = ctf_add_string (ctfc, name, &(dmd->dmd_name_offset)); + dmd->dmd_type = CTF_NULL_TYPEID; + dmd->dmd_offset = 0; + + dmd->dmd_value = value; + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, root, vlen + 1); + ctf_dmd_list_append (&dtd->dtd_u.dtu_members, dmd); + + if ((name != NULL) && strcmp (name, "")) + ctfc->ctfc_strlen += strlen (name) + 1; + + return (0); +} + +int +ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou, + const char * name, ctf_id_t type, + uint64_t bit_offset) +{ + ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, sou); + ctf_dmdef_t * dmd; + + uint32_t kind, vlen, root; + + /* The type of the member being added must already exist. */ + gcc_assert (dtd); + + kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info); + root = CTF_V2_INFO_ISROOT (dtd->dtd_data.ctti_info); + vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info); + + gcc_assert (kind == CTF_K_STRUCT || kind == CTF_K_UNION); + gcc_assert (vlen < CTF_MAX_VLEN); + + dmd = ggc_cleared_alloc<ctf_dmdef_t> (); + + /* Buffer the strings in the CTF string table. */ + dmd->dmd_name = ctf_add_string (ctfc, name, &(dmd->dmd_name_offset)); + dmd->dmd_type = type; + dmd->dmd_value = -1; + + if (kind == CTF_K_STRUCT && vlen != 0) + dmd->dmd_offset = bit_offset; + else + dmd->dmd_offset = 0; + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, root, vlen + 1); + ctf_dmd_list_append (&dtd->dtd_u.dtu_members, dmd); + + if ((name != NULL) && strcmp (name, "")) + ctfc->ctfc_strlen += strlen (name) + 1; + + return 0; +} + +int +ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref, + dw_die_ref die, unsigned int external_vis) +{ + ctf_dvdef_ref dvd; + + gcc_assert (name); + + if (name != NULL) + { + dvd = ggc_cleared_alloc<ctf_dvdef_t> (); + dvd->dvd_key = die; + /* Buffer the strings in the CTF string table. */ + dvd->dvd_name = ctf_add_string (ctfc, name, &(dvd->dvd_name_offset)); + dvd->dvd_visibility = external_vis; + dvd->dvd_type = ref; + ctf_dvd_insert (ctfc, dvd); + + if (strcmp (name, "")) + ctfc->ctfc_strlen += strlen (name) + 1; + } + + return 0; +} + +int +ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func, + const char * name, ctf_id_t type) +{ + ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, func); + ctf_func_arg_t * farg; + uint32_t vlen; + + /* The function to which argument is being added must already exist. */ + gcc_assert (dtd); + /* The number of args must have been non-zero. */ + vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info); + gcc_assert (vlen); + + farg = ggc_cleared_alloc<ctf_func_arg_t> (); + + /* Buffer the strings in the auxilliary string table. CTF V3 format does not + require function argument names. Use auxilliary string table to keep + these strings to avoid unnecessary bloat in CTF section in CTF V3. */ + farg->farg_name = ctf_add_string (ctfc, name, &(farg->farg_name_offset), + CTF_AUX_STRTAB); + farg->farg_type = type; + + ctf_farg_list_append (&dtd->dtd_u.dtu_argv, farg); + + /* For aux_str, keep ctfc_aux_strlen updated for debugging. */ + if ((name != NULL) && strcmp (name, "")) + ctfc->ctfc_aux_strlen += strlen (name) + 1; + + return 0; +} + +ctf_id_t +ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name, + const ctf_funcinfo_t * ctc, dw_die_ref die, + bool from_global_func) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + uint32_t vlen; + + gcc_assert (ctc); + + vlen = ctc->ctc_argc; + gcc_assert (vlen <= CTF_MAX_VLEN); + + type = ctf_add_generic (ctfc, flag, name, &dtd, die); + + dtd->from_global_func = from_global_func; + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen); + /* Caller must make sure CTF types for ctc->ctc_return are already added. */ + dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return; + /* Caller must make sure CTF types for function arguments are already added + via ctf_add_function_arg () API. */ + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name, + uint32_t kind, size_t size, dw_die_ref die) +{ + ctf_dtdef_ref dtd; + ctf_id_t type = 0; + + gcc_assert ((kind == CTF_K_STRUCT) || (kind == CTF_K_UNION)); + + /* In the compiler, no need to handle the case of promoting forwards to + structs. This comment is simply to note a divergence from libctf. */ + + /* The compiler does, however, update any previously existing forward types + to non-root. CTF does not allow existence of two root types with the same + name. */ + ctf_dtdef_ref sou_fwd_type = ctf_dtd_lookup (ctfc, die); + if (sou_fwd_type) + { + sou_fwd_type->dtd_data.ctti_info + = CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0); + } + + type = ctf_add_generic (ctfc, flag, name, &dtd, die); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0); + + if (size > CTF_MAX_SIZE) + { + dtd->dtd_data.ctti_size = CTF_LSIZE_SENT; + dtd->dtd_data.ctti_lsizehi = CTF_SIZE_TO_LSIZE_HI (size); + dtd->dtd_data.ctti_lsizelo = CTF_SIZE_TO_LSIZE_LO (size); + ctfc->ctfc_num_types++; + } + else + { + dtd->dtd_data.ctti_size = (uint32_t) size; + ctfc->ctfc_num_stypes++; + } + + return type; +} + +/* Check if CTF for TYPE has already been generated. Mainstay for + de-duplication. If CTF type already exists, returns TRUE and updates + the TYPE_ID for the caller. */ + +bool +ctf_type_exists (ctf_container_ref ctfc, dw_die_ref type, + ctf_id_t * type_id) +{ + bool exists = false; + ctf_dtdef_ref ctf_type_seen = ctf_dtd_lookup (ctfc, type); + + if (ctf_type_seen) + { + exists = true; + /* CTF type for this type exists. */ + *type_id = ctf_type_seen->dtd_type; + } + + return exists; +} + +/* Location information for CTF Types and CTF Variables. CTF section does not + emit location information; at this time, location information is needed for + BTF CO-RE use-cases. */ + +int +ctfc_get_dtd_srcloc (ctf_dtdef_ref dtd, ctf_srcloc_ref loc) +{ + loc->ctsloc_file = ctf_get_die_loc_file (dtd->dtd_key); + loc->ctsloc_line = ctf_get_die_loc_line (dtd->dtd_key); + loc->ctsloc_col = ctf_get_die_loc_col (dtd->dtd_key); + + if (loc->ctsloc_file == NULL) + return 1; + + return 0; +} + +int +ctfc_get_dvd_srcloc (ctf_dvdef_ref dvd, ctf_srcloc_ref loc) +{ + loc->ctsloc_file = ctf_get_die_loc_file (dvd->dvd_key); + loc->ctsloc_line = ctf_get_die_loc_line (dvd->dvd_key); + loc->ctsloc_col = ctf_get_die_loc_col (dvd->dvd_key); + + if (loc->ctsloc_file == NULL) + return 1; + + return 0; +} + +/* CTF container setup and teardown routines. */ + +/* Initialize the CTF string table. + The first entry in the CTF string table (empty string) is added. */ + +static void +init_ctf_strtable (ctf_strtable_t * strtab) +{ + strtab->ctstab_head = NULL; + strtab->ctstab_tail = NULL; + strtab->ctstab_num = 0; + strtab->ctstab_len = 0; + + /* The first entry in the CTF string table is an empty string. E.g., CTF + type records with no name (like CTF_K_CONST, CTF_K_VOLATILE etc) point to + this string. */ + uint32_t estr_offset = 0; + strtab->ctstab_estr = ctfc_strtable_add_str (strtab, "", &estr_offset); +} + +/* Initialize the string tables in the CTF container. */ + +static void +init_ctf_string_table (ctf_container_ref ctfc) +{ + init_ctf_strtable (&ctfc->ctfc_strtable); + ctfc->ctfc_strlen++; + + init_ctf_strtable (&ctfc->ctfc_aux_strtable); + ctfc->ctfc_aux_strlen++; +} + +/* Allocate a new CTF container with the desired flags. */ + +static inline ctf_container_ref +new_ctf_container (void) +{ + tu_ctfc = ggc_cleared_alloc<ctf_container_t> (); + tu_ctfc->ctfc_types + = hash_table<ctfc_dtd_hasher>::create_ggc (100); + tu_ctfc->ctfc_vars + = hash_table<ctfc_dvd_hasher>::create_ggc (100); + + return tu_ctfc; +} + +/* Initialize a CTF container per translation unit. */ + +static void +init_ctf_container (void) +{ + tu_ctfc = new_ctf_container (); + + tu_ctfc->ctfc_magic = CTF_MAGIC; + tu_ctfc->ctfc_version = CTF_VERSION; + tu_ctfc->ctfc_flags = CTF_F_NEWFUNCINFO; + tu_ctfc->ctfc_nextid = CTF_INIT_TYPEID; + + init_ctf_string_table (tu_ctfc); +} + +void +ctfc_delete_strtab (ctf_strtable_t * strtab) +{ + ctf_string_t * str = NULL; + ctf_string_t * next_str = NULL; + + str = strtab->ctstab_head; + next_str = str; + while (next_str != NULL) + { + next_str = str->cts_next; + ggc_free (str); + str = next_str; + } + + strtab->ctstab_head = NULL; + strtab->ctstab_tail = NULL; + strtab->ctstab_estr = NULL; +} + +/* Delete the CTF container's resources. */ + +void +ctfc_delete_container (ctf_container_ref ctfc) +{ + /* FIXME - CTF container can be cleaned up now. + Will the ggc machinery take care of cleaning up the container structure + including the hash_map members etc. ? */ + if (ctfc) + { + ctfc_delete_strtab (&ctfc->ctfc_strtable); + ctfc_delete_strtab (&ctfc->ctfc_aux_strtable); + if (ctfc->ctfc_vars_list) + { + ggc_free (ctfc->ctfc_vars_list); + ctfc->ctfc_vars_list = NULL; + } + if (ctfc->ctfc_types_list) + { + ggc_free (ctfc->ctfc_types_list); + ctfc->ctfc_types_list = NULL; + } + if (ctfc->ctfc_gfuncs_list) + { + ggc_free (ctfc->ctfc_gfuncs_list); + ctfc->ctfc_gfuncs_list = NULL; + } + if (ctfc->ctfc_gobjts_list) + { + ggc_free (ctfc->ctfc_gobjts_list); + ctfc->ctfc_gobjts_list = NULL; + } + + ctfc= NULL; + } +} + +/* CTF routines interfacing to the compiler. */ + +void +ctf_init (void) +{ + init_ctf_container (); +} |