diff --git a/gcc/ctfc.cc b/gcc/ctfc.cc index 6fe44d2e8d4..f24e7bff948 100644 --- a/gcc/ctfc.cc +++ b/gcc/ctfc.cc @@ -179,6 +179,40 @@ ctf_dvd_lookup (const ctf_container_ref ctfc, dw_die_ref die) return NULL; } +/* Insert a dummy CTF variable into the list of variables to be ignored. */ + +static void +ctf_dvd_ignore_insert (ctf_container_ref ctfc, ctf_dvdef_ref dvd) +{ + bool existed = false; + ctf_dvdef_ref entry = dvd; + + ctf_dvdef_ref * item = ctfc->ctfc_ignore_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 the dummy CTF variable given the DWARF die for the non-defining + decl to be ignored. */ + +bool +ctf_dvd_ignore_lookup (const ctf_container_ref ctfc, dw_die_ref die) +{ + ctf_dvdef_t entry; + entry.dvd_key = die; + + ctf_dvdef_ref * slot = ctfc->ctfc_ignore_vars->find_slot (&entry, NO_INSERT); + + if (slot) + return true; + + return false; +} + /* Append member definition to the list. Member list is a singly-linked list with list start pointing to the head. */ @@ -666,9 +700,10 @@ ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou, int ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref, - dw_die_ref die, unsigned int external_vis) + dw_die_ref die, unsigned int external_vis, + dw_die_ref die_var_decl) { - ctf_dvdef_ref dvd; + ctf_dvdef_ref dvd, dvd_ignore; gcc_assert (name); @@ -680,6 +715,24 @@ ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref, dvd->dvd_name = ctf_add_string (ctfc, name, &(dvd->dvd_name_offset)); dvd->dvd_visibility = external_vis; dvd->dvd_type = ref; + + /* If DW_AT_specification attribute exists, keep track of it as this is + the non-defining declaration corresponding to the variable. We will + skip emitting CTF variable for such incomplete, non-defining + declarations. + There could be some non-defining declarations, however, for which a + defining declaration does not show up in the same CU. For such + cases, the compiler continues to emit CTF variable record as + usual. */ + if (die_var_decl) + { + dvd_ignore = ggc_cleared_alloc (); + dvd_ignore->dvd_key = die_var_decl; + /* It's alright to leave other fields as zero. No valid CTF + variable will be added for these DW_TAG_variable DIEs. */ + ctf_dvd_ignore_insert (ctfc, dvd_ignore); + } + ctf_dvd_insert (ctfc, dvd); if (strcmp (name, "")) @@ -900,6 +953,8 @@ new_ctf_container (void) = hash_table::create_ggc (100); tu_ctfc->ctfc_vars = hash_table::create_ggc (100); + tu_ctfc->ctfc_ignore_vars + = hash_table::create_ggc (10); return tu_ctfc; } @@ -952,6 +1007,9 @@ ctfc_delete_container (ctf_container_ref ctfc) ctfc->ctfc_vars->empty (); ctfc->ctfc_types = NULL; + ctfc->ctfc_ignore_vars->empty (); + ctfc->ctfc_ignore_vars = NULL; + ctfc_delete_strtab (&ctfc->ctfc_strtable); ctfc_delete_strtab (&ctfc->ctfc_aux_strtable); if (ctfc->ctfc_vars_list) diff --git a/gcc/ctfc.h b/gcc/ctfc.h index 4ce756c728a..001e544ef08 100644 --- a/gcc/ctfc.h +++ b/gcc/ctfc.h @@ -274,6 +274,8 @@ typedef struct GTY (()) ctf_container hash_table * GTY (()) ctfc_types; /* CTF variables. */ hash_table * GTY (()) ctfc_vars; + /* CTF variables to be ignored. */ + hash_table * GTY (()) ctfc_ignore_vars; /* CTF string table. */ ctf_strtable_t ctfc_strtable; @@ -394,6 +396,8 @@ extern ctf_dtdef_ref ctf_dtd_lookup (const ctf_container_ref ctfc, dw_die_ref die); extern ctf_dvdef_ref ctf_dvd_lookup (const ctf_container_ref ctfc, dw_die_ref die); +extern bool ctf_dvd_ignore_lookup (const ctf_container_ref ctfc, + dw_die_ref die); extern const char * ctf_add_string (ctf_container_ref, const char *, uint32_t *, int); @@ -430,7 +434,7 @@ extern int ctf_add_member_offset (ctf_container_ref, dw_die_ref, const char *, extern int ctf_add_function_arg (ctf_container_ref, dw_die_ref, const char *, ctf_id_t); extern int ctf_add_variable (ctf_container_ref, const char *, ctf_id_t, - dw_die_ref, unsigned int); + dw_die_ref, unsigned int, dw_die_ref); extern ctf_id_t ctf_lookup_tree_type (ctf_container_ref, const tree); extern ctf_id_t get_btf_id (ctf_id_t); diff --git a/gcc/ctfout.cc b/gcc/ctfout.cc index 28a873b2027..3cf89b94f99 100644 --- a/gcc/ctfout.cc +++ b/gcc/ctfout.cc @@ -212,6 +212,13 @@ ctf_dvd_preprocess_cb (ctf_dvdef_ref * slot, void * arg) ctf_dvdef_ref var = (ctf_dvdef_ref) *slot; ctf_container_ref arg_ctfc = dvd_arg->dvd_arg_ctfc; + /* If the CTF variable corresponds to an extern variable declaration with + a defining declaration later on, skip it. Only CTF variable + corresponding to the defining declaration for the extern variable is + desirable. */ + if (ctf_dvd_ignore_lookup (arg_ctfc, var->dvd_key)) + return 1; + ctf_preprocess_var (arg_ctfc, var); /* Keep track of global objts. */ @@ -276,16 +283,16 @@ static void ctf_preprocess (ctf_container_ref ctfc) { size_t num_ctf_types = ctfc->ctfc_types->elements (); + size_t num_ctf_vars = ctfc_get_num_ctf_vars (ctfc); /* Initialize an array to keep track of the CTF variables at global - scope. */ - size_t num_global_objts = ctfc->ctfc_num_global_objts; + scope. At this time, size it conservatively. */ + size_t num_global_objts = num_ctf_vars; if (num_global_objts) { ctfc->ctfc_gobjts_list = ggc_vec_alloc(num_global_objts); } - size_t num_ctf_vars = ctfc_get_num_ctf_vars (ctfc); if (num_ctf_vars) { ctf_dvd_preprocess_arg_t dvd_arg; @@ -299,8 +306,11 @@ ctf_preprocess (ctf_container_ref ctfc) list for sorting. */ ctfc->ctfc_vars->traverse (&dvd_arg); /* Sort the list. */ - qsort (ctfc->ctfc_vars_list, num_ctf_vars, sizeof (ctf_dvdef_ref), - ctf_varent_compare); + qsort (ctfc->ctfc_vars_list, ctfc->ctfc_vars_list_count, + sizeof (ctf_dvdef_ref), ctf_varent_compare); + /* Update the actual number of the generated CTF variables at global + scope. */ + ctfc->ctfc_num_global_objts = dvd_arg.dvd_global_obj_idx; } /* Initialize an array to keep track of the CTF functions types for global @@ -476,7 +486,7 @@ output_ctf_header (ctf_container_ref ctfc) /* Vars appear after function index. */ varoff = funcidxoff + ctfc->ctfc_num_global_funcs * sizeof (uint32_t); /* CTF types appear after vars. */ - typeoff = varoff + ctfc_get_num_ctf_vars (ctfc) * sizeof (ctf_varent_t); + typeoff = varoff + (ctfc->ctfc_vars_list_count) * 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. */ @@ -595,7 +605,7 @@ static void output_ctf_vars (ctf_container_ref ctfc) { size_t i; - size_t num_ctf_vars = ctfc_get_num_ctf_vars (ctfc); + unsigned int num_ctf_vars = ctfc->ctfc_vars_list_count; if (num_ctf_vars) { /* Iterate over the list of sorted vars and output the asm. */ diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc index 747b2f66107..a6329ab6ee4 100644 --- a/gcc/dwarf2ctf.cc +++ b/gcc/dwarf2ctf.cc @@ -808,12 +808,26 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die) if (ctf_dvd_lookup (ctfc, die)) return; + /* Do not generate CTF variable records for non-defining incomplete + declarations. Such declarations can be known via the DWARF + DW_AT_specification attribute. */ + if (ctf_dvd_ignore_lookup (ctfc, die)) + return; + + /* The value of the DW_AT_specification attribute, if present, is a + reference to the debugging information entry representing the + non-defining declaration. */ + dw_die_ref decl = get_AT_ref (die, DW_AT_specification); + /* Add the type of the variable. */ var_type_id = gen_ctf_type (ctfc, var_type); /* Generate the new CTF variable and update global counter. */ - (void) ctf_add_variable (ctfc, var_name, var_type_id, die, external_vis); - ctfc->ctfc_num_global_objts += 1; + (void) ctf_add_variable (ctfc, var_name, var_type_id, die, external_vis, + decl); + /* Skip updating the number of global objects at this time. This is updated + later after pre-processing as some CTF variable records although + generated now, will not be emitted later. [PR105089]. */ } /* Add a CTF function record for the given input DWARF DIE. */