@@ -63,53 +63,44 @@ static char btf_info_section_label[MAX_BTF_LABEL_BYTES];
#define BTF_INVALID_TYPEID 0xFFFFFFFF
-/* Mapping of CTF variables to the IDs they will be assigned when they are
- converted to BTF_KIND_VAR type records. Strictly accounts for the index
- from the start of the variable type entries, does not include the number
- of types emitted prior to the variable records. */
-static GTY (()) hash_map <ctf_dvdef_ref, unsigned> *btf_var_ids;
-
-/* Mapping of type IDs from original CTF ID to BTF ID. Types do not map
- 1-to-1 from CTF to BTF. To avoid polluting the CTF container when updating
- type references-by-ID, we use this map instead. */
-static ctf_id_t * btf_id_map = NULL;
-
-/* Information for creating the BTF_KIND_DATASEC records. */
+/* Internal representation of an entry in a BTF_KIND_DATASEC record. */
+struct btf_datasec_entry
+{
+ union {
+ ctf_dvdef_ref dvd; /* Reference to the underlying variable represented. */
+ ctf_dtdef_ref dtd; /* Reference to the underlying type represented. */
+ };
+ bool is_var; /* True iff this entry represents a variable. */
+ uint32_t size; /* Size of variable or function, in bytes.
+ For functions, always zero at compile time. */
+};
+
+/* Internal representation of a BTF_KIND_DATASEC record. */
typedef struct btf_datasec
{
- const char *name; /* Section name, e.g. ".bss". */
- uint32_t name_offset; /* Offset to name in string table. */
- vec<struct btf_var_secinfo> entries; /* Variable entries in this section. */
+ ctf_id_t id; /* BTF type ID of this record. */
+ const char *name; /* Section name, e.g. ".bss". */
+ uint32_t name_offset; /* Offset to name in string table. */
+ vec<struct btf_datasec_entry> entries; /* Entries in this section. */
} btf_datasec_t;
/* One BTF_KIND_DATASEC record is created for each output data section which
will hold at least one variable. */
static vec<btf_datasec_t> datasecs;
-/* Holes occur for types which are present in the CTF container, but are either
- non-representable or redundant in BTF. */
-static vec<ctf_id_t> holes;
-
-/* CTF definition(s) of void. Only one definition of void should be generated.
- We should not encounter more than one definition of void, but use a vector
- to be safe. */
-static vec<ctf_id_t> voids;
-
/* Functions in BTF have two separate type records - one for the prototype
(BTF_KIND_FUNC_PROTO), as well as a BTF_KIND_FUNC. CTF_K_FUNCTION types
map closely to BTF_KIND_FUNC_PROTO, but the BTF_KIND_FUNC records must be
created. This vector holds them. */
static GTY (()) vec<ctf_dtdef_ref, va_gc> *funcs;
-/* The number of BTF variables added to the TU CTF container. */
-static unsigned int num_vars_added = 0;
-
-/* The number of BTF types added to the TU CTF container. */
-static unsigned int num_types_added = 0;
+/* Maps BTF_KIND_FUNC_PROTO to the BTF_KIND_FUNC record for it. Used when
+ creating DATASEC entries. */
+static GTY (()) hash_map<ctf_dtdef_ref, ctf_dtdef_ref> *func_map;
-/* The number of types synthesized for BTF that do not correspond to
- CTF types. */
-static unsigned int num_types_created = 0;
+/* Highest BTF ID assigned to any regular type translated from CTF.
+ Does not include BTF_KIND_{VAR,FUNC,DATASEC} types. */
+static ctf_id_t max_translated_id = 0;
/* Name strings for BTF kinds.
Note: the indices here must match the type defines in btf.h. */
@@ -155,6 +146,16 @@ get_btf_kind (uint32_t ctf_kind)
return BTF_KIND_UNKN;
}
+/* Convenience wrapper around get_btf_kind for the common case. */
+
+static uint32_t
+btf_dtd_kind (ctf_dtdef_ref dtd)
+{
+ if (!dtd)
+ return BTF_KIND_UNKN;
+ return get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
+}
+
/* Some BTF types, like BTF_KIND_FUNC_PROTO, are anonymous. The machinery
in btfout to emit BTF, may reset dtd_data->ctti_name, but does not update
the name in the ctf_dtdef_ref type object (deliberate choice). This
@@ -168,101 +169,20 @@ get_btf_type_name (ctf_dtdef_ref dtd)
return (dtd->dtd_data.ctti_name) ? dtd->dtd_name : anon;
}
-/* Helper routines to map between 'relative' and 'absolute' IDs.
-
- In BTF all records (including variables) are output in one long list, and all
- inter-type references are via index into that list. But internally since we
- a) translate from CTF, which separates variable records from regular types
- and b) create some additional types after the fact, things like VAR and FUNC
- records are stored in separate vectors with their own indices. These
- functions map between the 'relative' IDs (i.e. indices in their respective
- containers) and 'absolute' IDs (i.e. indices in the final contiguous
- output list), which goes in order:
- all normal type records translated from CTF
- all BTF_KIND_VAR records
- all BTF_KIND_FUNC records (synthesized split function records)
- all BTF_KIND_DATASEC records (synthesized)
-
- The extra '+ 1's below are to account for the implicit "void" record, which
- has index 0 but isn't actually contained in the type list. */
-
-/* Return the final BTF ID of the variable at relative index REL. */
-
-static ctf_id_t
-btf_absolute_var_id (ctf_id_t rel)
-{
- return rel + (num_types_added + 1);
-}
-
-/* Return the relative index of the variable with final BTF ID ABS. */
-
-static ctf_id_t
-btf_relative_var_id (ctf_id_t abs)
-{
- return abs - (num_types_added + 1);
-}
-
-/* Return the final BTF ID of the func record at relative index REL. */
-
-static ctf_id_t
-btf_absolute_func_id (ctf_id_t rel)
-{
- return rel + (num_types_added + 1) + num_vars_added;
-}
-
-/* Return the relative index of the func record with final BTF ID ABS. */
-
-static ctf_id_t
-btf_relative_func_id (ctf_id_t abs)
-{
- return abs - ((num_types_added + 1) + num_vars_added);
-}
-
-/* Return the final BTF ID of the datasec record at relative index REL. */
-
-static ctf_id_t
-btf_absolute_datasec_id (ctf_id_t rel)
-{
- return rel + (num_types_added + 1) + num_vars_added + funcs->length ();
-}
-
-
-/* Allocate the btf_id_map, and initialize elements to BTF_INVALID_TYPEID. */
-
-static void
-init_btf_id_map (size_t len)
+static bool
+btf_emit_type_p (ctf_dtdef_ref dtd)
{
- btf_id_map = XNEWVEC (ctf_id_t, len);
+ uint32_t kind = btf_dtd_kind (dtd);
- btf_id_map[0] = BTF_VOID_TYPEID;
- for (size_t i = 1; i < len; i++)
- btf_id_map[i] = BTF_INVALID_TYPEID;
-}
+ if (kind == BTF_KIND_UNKN)
+ /* This type is not representable in BTF. */
+ return false;
-/* Return the BTF type ID of CTF type ID KEY, or BTF_INVALID_TYPEID if the CTF
- type with ID KEY does not map to a BTF type. */
+ if (kind == BTF_KIND_INT && dtd->dtd_data.ctti_size == 0)
+ /* This is a (redundant) definition of void. */
+ return false;
-ctf_id_t
-get_btf_id (ctf_id_t key)
-{
- return btf_id_map[key];
-}
-
-/* Set the CTF type ID KEY to map to BTF type ID VAL. */
-
-static inline void
-set_btf_id (ctf_id_t key, ctf_id_t val)
-{
- btf_id_map[key] = val;
-}
-
-/* Return TRUE iff the given CTF type ID maps to a BTF type which will
- be emitted. */
-static inline bool
-btf_emit_id_p (ctf_id_t id)
-{
- return ((btf_id_map[id] != BTF_VOID_TYPEID)
- && (btf_id_map[id] <= BTF_MAX_TYPE));
+ return true;
}
/* Return true if DTD is a forward-declared enum. The BTF representation
@@ -271,9 +191,8 @@ btf_emit_id_p (ctf_id_t id)
static bool
btf_fwd_to_enum_p (ctf_dtdef_ref dtd)
{
- uint32_t btf_kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
-
- return (btf_kind == BTF_KIND_FWD && dtd->dtd_data.ctti_type == CTF_K_ENUM);
+ uint32_t kind = btf_dtd_kind (dtd);
+ return (kind == BTF_KIND_FWD && dtd->dtd_data.ctti_type == CTF_K_ENUM);
}
/* Each BTF type can be followed additional, variable-length information
@@ -285,7 +204,7 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
{
uint64_t vlen_bytes = 0;
- uint32_t kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
+ uint32_t kind = btf_dtd_kind (dtd);
uint32_t vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
switch (kind)
@@ -355,41 +274,6 @@ init_btf_sections (void)
BTF_INFO_SECTION_LABEL, btf_label_num++);
}
-/* Push a BTF datasec variable entry INFO into the datasec named SECNAME,
- creating the datasec if it does not already exist. */
-
-static void
-btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
- struct btf_var_secinfo info)
-{
- if (secname == NULL)
- return;
-
- for (size_t i = 0; i < datasecs.length (); i++)
- if (strcmp (datasecs[i].name, secname) == 0)
- {
- datasecs[i].entries.safe_push (info);
- return;
- }
-
- /* If we don't already have a datasec record for secname, make one. */
-
- uint32_t str_off;
- ctf_add_string (ctfc, secname, &str_off, CTF_AUX_STRTAB);
- if (strcmp (secname, ""))
- ctfc->ctfc_aux_strlen += strlen (secname) + 1;
-
- btf_datasec_t ds;
- ds.name = secname;
- ds.name_offset = str_off;
-
- ds.entries.create (0);
- ds.entries.safe_push (info);
-
- datasecs.safe_push (ds);
-}
-
-
/* Return the section name, as of interest to btf_collect_datasec, for the
given symtab node. Note that this deliberately returns NULL for objects
which do not go in a section btf_collect_datasec cares about. */
@@ -418,301 +302,15 @@ get_section_name (symtab_node *node)
return section_name;
}
-/* Construct all BTF_KIND_DATASEC records for CTFC. One such record is created
- for each non-empty data-containing section in the output. Each record is
- followed by a variable number of entries describing the variables stored
- in that section. */
-
-static void
-btf_collect_datasec (ctf_container_ref ctfc)
-{
- cgraph_node *func;
- FOR_EACH_FUNCTION (func)
- {
- dw_die_ref die = lookup_decl_die (func->decl);
- if (die == NULL)
- continue;
-
- ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
- if (dtd == NULL)
- continue;
-
- if (DECL_EXTERNAL (func->decl)
- && (lookup_attribute ("kernel_helper",
- DECL_ATTRIBUTES (func->decl))) != NULL_TREE)
- continue;
-
- /* Functions actually get two types: a BTF_KIND_FUNC_PROTO, and
- also a BTF_KIND_FUNC. But the CTF container only allocates one
- type per function, which matches closely with BTF_KIND_FUNC_PROTO.
- For each such function, also allocate a BTF_KIND_FUNC entry.
- These will be output later. */
- ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
- func_dtd->dtd_data = dtd->dtd_data;
- func_dtd->dtd_data.ctti_type = dtd->dtd_type;
- func_dtd->linkage = dtd->linkage;
- func_dtd->dtd_name = dtd->dtd_name;
- /* +1 for the sentinel type not in the types map. */
- func_dtd->dtd_type = num_types_added + num_types_created + 1;
-
- /* Only the BTF_KIND_FUNC type actually references the name. The
- BTF_KIND_FUNC_PROTO is always anonymous. */
- dtd->dtd_data.ctti_name = 0;
-
- vec_safe_push (funcs, func_dtd);
- num_types_created++;
-
- /* Mark any 'extern' funcs and add DATASEC entries for them. */
- if (DECL_EXTERNAL (func->decl))
- {
- func_dtd->linkage = BTF_FUNC_EXTERN;
-
- const char *section_name = get_section_name (func);
- /* Note: get_section_name () returns NULL for functions in text
- section. This is intentional, since we do not want to generate
- DATASEC entries for them. */
- if (section_name == NULL)
- continue;
-
- struct btf_var_secinfo info;
-
- info.type = func_dtd->dtd_type;
-
- /* Both zero at compile time. */
- info.size = 0;
- info.offset = 0;
-
- btf_datasec_push_entry (ctfc, section_name, info);
- }
- }
-
- varpool_node *node;
- FOR_EACH_VARIABLE (node)
- {
- dw_die_ref die = lookup_decl_die (node->decl);
- if (die == NULL)
- continue;
-
- ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
- if (dvd == NULL)
- continue;
-
- /* Mark extern variables. */
- if (DECL_EXTERNAL (node->decl))
- {
- dvd->dvd_visibility = BTF_VAR_GLOBAL_EXTERN;
-
- /* PR112849: avoid assuming a section for extern decls without
- an explicit section, which would result in incorrectly
- emitting a BTF_KIND_DATASEC entry for them. */
- if (node->get_section () == NULL)
- continue;
- }
-
- const char *section_name = get_section_name (node);
- if (section_name == NULL)
- continue;
-
- struct btf_var_secinfo info;
-
- info.type = 0;
- unsigned int *var_id = btf_var_ids->get (dvd);
- if (var_id)
- info.type = btf_absolute_var_id (*var_id);
- else
- continue;
-
- info.size = 0;
- tree size = DECL_SIZE_UNIT (node->decl);
- if (tree_fits_uhwi_p (size))
- info.size = tree_to_uhwi (size);
- else if (VOID_TYPE_P (TREE_TYPE (node->decl)))
- info.size = 1;
-
- /* Offset is left as 0 at compile time, to be filled in by loaders such
- as libbpf. */
- info.offset = 0;
-
- btf_datasec_push_entry (ctfc, section_name, info);
- }
-
- num_types_created += datasecs.length ();
-}
-
-/* Return true if the type ID is that of a type which will not be emitted (for
- example, if it is not representable in BTF). */
-
-static bool
-btf_removed_type_p (ctf_id_t id)
-{
- return holes.contains (id);
-}
-
-/* Adjust the given type ID to account for holes and duplicate definitions of
- void. */
-
-static ctf_id_t
-btf_adjust_type_id (ctf_id_t id)
-{
- size_t n;
- ctf_id_t i = 0;
-
- /* Do not adjust invalid type markers. */
- if (id == BTF_INVALID_TYPEID)
- return id;
-
- for (n = 0; n < voids.length (); n++)
- if (id == voids[n])
- return BTF_VOID_TYPEID;
-
- for (n = 0; n < holes.length (); n++)
- {
- if (holes[n] < id)
- i++;
- else if (holes[n] == id)
- return BTF_VOID_TYPEID;
- }
-
- return id - i;
-}
-
-/* Postprocessing callback routine for types. */
-
-int
-btf_dtd_postprocess_cb (ctf_dtdef_ref *slot, ctf_container_ref arg_ctfc)
-{
- ctf_dtdef_ref ctftype = (ctf_dtdef_ref) * slot;
-
- size_t index = ctftype->dtd_type;
- gcc_assert (index <= arg_ctfc->ctfc_types->elements ());
-
- uint32_t ctf_kind, btf_kind;
-
- ctf_kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
- btf_kind = get_btf_kind (ctf_kind);
-
- if (btf_kind == BTF_KIND_UNKN)
- /* This type is not representable in BTF. Create a hole. */
- holes.safe_push (ctftype->dtd_type);
-
- else if (btf_kind == BTF_KIND_INT && ctftype->dtd_data.ctti_size == 0)
- {
- /* This is a (redundant) definition of void. */
- voids.safe_push (ctftype->dtd_type);
- holes.safe_push (ctftype->dtd_type);
- }
-
- arg_ctfc->ctfc_types_list[index] = ctftype;
-
- return 1;
-}
-
-/* Preprocessing callback routine for variables. */
-
-int
-btf_dvd_emit_preprocess_cb (ctf_dvdef_ref *slot, ctf_container_ref arg_ctfc)
-{
- ctf_dvdef_ref var = (ctf_dvdef_ref) * slot;
-
- /* If this is an extern variable declaration with a defining declaration
- later, skip it so that only the defining declaration is emitted.
- This is the same case, fix and reasoning as in CTF; see PR105089. */
- if (ctf_dvd_ignore_lookup (arg_ctfc, var->dvd_key))
- return 1;
-
- /* Do not add variables which refer to unsupported types. */
- if (!voids.contains (var->dvd_type->dtd_type)
- && btf_removed_type_p (var->dvd_type->dtd_type))
- return 1;
-
- arg_ctfc->ctfc_vars_list[num_vars_added] = var;
- btf_var_ids->put (var, num_vars_added);
-
- num_vars_added++;
- num_types_created++;
-
- return 1;
-}
-
-/* Preprocessing callback routine for types. */
-
-static void
-btf_dtd_emit_preprocess_cb (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
-{
- if (!btf_emit_id_p (dtd->dtd_type))
- return;
-
- ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
-}
-
-/* Preprocess the CTF information to prepare for BTF output. BTF is almost a
- subset of CTF, with many small differences in encoding, and lacking support
- for some types (notably floating point formats).
-
- During the preprocessing pass:
- - Ascertain that the sorted list of types has been prepared. For the BTF
- generation process, this is taken care of by the btf_init_postprocess ().
-
- - BTF_KIND_FUNC and BTF_KIND_DATASEC records are constructed. These types do
- not have analogues in CTF (the analogous type to CTF_K_FUNCTION is
- BTF_KIND_FUNC_PROTO), but can be relatively easily deduced from CTF
- information.
-
- - Construct BTF_KIND_VAR records, representing variables.
-
- - Calculate the total size in bytes of variable-length information following
- BTF type records. This is used for outputting the BTF header.
-
- After preprocessing, all BTF information is ready to be output:
- - ctfc->ctfc_types_list holdstypes converted from CTF types. This does not
- include KIND_VAR, KIND_FUNC, nor KIND_DATASEC types. These types have been
- re-encoded to the appropriate representation in BTF.
- - ctfc->ctfc_vars_list holds all variables which should be output.
- Variables of unsupported types are not present in this list.
- - Vector 'funcs' holds all BTF_KIND_FUNC types, one to match each
- BTF_KIND_FUNC_PROTO.
- - Vector 'datasecs' holds all BTF_KIND_DATASEC types. */
-
-static void
-btf_emit_preprocess (ctf_container_ref ctfc)
-{
- size_t num_ctf_types = ctfc->ctfc_types->elements ();
- size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
- size_t i;
-
- if (num_ctf_types)
- {
- gcc_assert (ctfc->ctfc_types_list);
- /* Preprocess the types. */
- for (i = 1; i <= num_ctf_types; i++)
- btf_dtd_emit_preprocess_cb (ctfc, ctfc->ctfc_types_list[i]);
- }
-
- btf_var_ids = hash_map<ctf_dvdef_ref, unsigned int>::create_ggc (100);
-
- if (num_ctf_vars)
- {
- /* Allocate and construct the list of variables. While BTF variables are
- not distinct from types (in that variables are simply types with
- BTF_KIND_VAR), it is simpler to maintain a separate list of variables
- and append them to the types list during output. */
- ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars);
- ctfc->ctfc_vars->traverse<ctf_container_ref, btf_dvd_emit_preprocess_cb>
- (ctfc);
-
- ctfc->ctfc_num_vlen_bytes += (num_vars_added * sizeof (struct btf_var));
- }
-
- btf_collect_datasec (ctfc);
-}
-
/* Return true iff DMD is a member description of a bit-field which can be
validly represented in BTF. */
static bool
-btf_dmd_representable_bitfield_p (ctf_container_ref ctfc, ctf_dmdef_t *dmd)
+btf_dmd_representable_bitfield_p (ctf_dmdef_t *dmd)
{
- ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
+ ctf_dtdef_ref ref_type = dmd->dmd_type;
+ if (!ref_type)
+ return false;
if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
{
@@ -734,76 +332,34 @@ btf_dmd_representable_bitfield_p (ctf_container_ref ctfc, ctf_dmdef_t *dmd)
/* Asm'out a reference to another BTF type. */
static void
-btf_asm_type_ref (const char *prefix, ctf_container_ref ctfc, ctf_id_t ctf_id)
+btf_asm_type_ref (const char *prefix, ctf_dtdef_ref dtd)
{
- ctf_id_t btf_id = get_btf_id (ctf_id);
- if (btf_id == BTF_VOID_TYPEID || btf_id == BTF_INVALID_TYPEID)
- {
- /* There is no explicit void type.
- Also handle any invalid refs that made it this far, just in case. */
- dw2_asm_output_data (4, btf_id, "%s: void", prefix);
- }
+ if (!dtd || !btf_emit_type_p (dtd))
+ dw2_asm_output_data (4, BTF_VOID_TYPEID, "%s: void", prefix);
else
{
- gcc_assert (btf_id <= num_types_added);
-
- /* Ref to a standard type in the types list. Note: take care that we
- must index the type list by the original CTF id, not the BTF id. */
- ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[ctf_id];
- uint32_t ref_kind
- = get_btf_kind (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info));
-
- const char *kind_name = btf_fwd_to_enum_p (ref_type)
- ? btf_kind_name (BTF_KIND_ENUM)
- : btf_kind_name (ref_kind);
-
- dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_%s '%s')",
- prefix, kind_name,
- get_btf_type_name (ref_type));
- }
-}
-
-/* Asm'out a reference to a BTF_KIND_VAR or BTF_KIND_FUNC type. These type
- kinds are BTF-specific, and should only be referred to by entries in
- BTF_KIND_DATASEC records. */
-
-static void
-btf_asm_datasec_type_ref (const char *prefix, ctf_container_ref ctfc,
- ctf_id_t btf_id)
-{
- if (btf_id >= num_types_added + 1
- && btf_id < num_types_added + num_vars_added + 1)
- {
- /* Ref to a variable. Should only appear in DATASEC entries. */
- ctf_id_t var_id = btf_relative_var_id (btf_id);
- ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[var_id];
- dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_VAR '%s')",
- prefix, dvd->dvd_name);
-
- }
- else if (btf_id >= num_types_added + num_vars_added + 1)
- {
- /* Ref to a FUNC record. */
- size_t func_id = btf_relative_func_id (btf_id);
- ctf_dtdef_ref ref_type = (*funcs)[func_id];
- dw2_asm_output_data (4, btf_id, "%s: (BTF_KIND_FUNC '%s')",
- prefix, get_btf_type_name (ref_type));
+ uint32_t kind = btf_dtd_kind (dtd);
+ if (btf_fwd_to_enum_p (dtd))
+ kind = BTF_KIND_ENUM;
+ else if (kind == BTF_KIND_FUNC_PROTO && dtd->dtd_type > max_translated_id)
+ kind = BTF_KIND_FUNC;
+
+ dw2_asm_output_data (4, dtd->dtd_type, "%s: (BTF_KIND_%s '%s')",
+ prefix, btf_kind_name (kind),
+ get_btf_type_name (dtd));
}
- else
- /* The caller should not be calling this. */
- gcc_unreachable ();
}
/* Asm'out a BTF type. This routine is responsible for the bulk of the task
of converting CTF types to their BTF representation. */
static void
-btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+btf_asm_type (ctf_dtdef_ref dtd)
{
uint32_t btf_kind, btf_kflag, btf_vlen, btf_size;
uint32_t ctf_info = dtd->dtd_data.ctti_info;
- btf_kind = get_btf_kind (CTF_V2_INFO_KIND (ctf_info));
+ btf_kind = btf_dtd_kind (dtd);
btf_size = dtd->dtd_data.ctti_size;
btf_vlen = CTF_V2_INFO_VLEN (ctf_info);
@@ -822,17 +378,17 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
if (btf_kind == BTF_KIND_STRUCT || btf_kind == BTF_KIND_UNION)
{
- /* If a struct/union has ANY bitfield members, set kflag=1.
- Note that we must also change the encoding of every member to encode
- both member bitfield size (stealing most-significant 8 bits) and bit
- offset (LS 24 bits). This is done during preprocessing. */
+ /* If a struct/union has ANY bitfield members, set kflag=1. */
ctf_dmdef_t *dmd;
for (dmd = dtd->dtd_u.dtu_members;
dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
{
/* Set kflag if this member is a representable bitfield. */
- if (btf_dmd_representable_bitfield_p (ctfc, dmd))
- btf_kflag = 1;
+ if (btf_dmd_representable_bitfield_p (dmd))
+ {
+ btf_kflag = 1;
+ break;
+ }
}
}
@@ -866,7 +422,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
: BTF_KF_ENUM_SIGNED;
if (dtd->dtd_data.ctti_size == 0x8)
btf_kind = BTF_KIND_ENUM64;
- }
+ }
/* PR debug/112656. BTF_KIND_FUNC_PROTO is always anonymous. */
else if (btf_kind == BTF_KIND_FUNC_PROTO)
@@ -874,7 +430,7 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
"TYPE %" PRIu64 " BTF_KIND_%s '%s'",
- get_btf_id (dtd->dtd_type), btf_kind_name (btf_kind),
+ dtd->dtd_type, btf_kind_name (btf_kind),
get_btf_type_name (dtd));
dw2_asm_output_data (4, BTF_TYPE_INFO (btf_kind, btf_kflag, btf_vlen),
"btt_info: kind=%u, kflag=%u, vlen=%u",
@@ -900,30 +456,29 @@ btf_asm_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
break;
}
- ctf_id_t ref_id = dtd->dtd_data.ctti_type;
- btf_asm_type_ref ("btt_type", ctfc, ref_id);
+ btf_asm_type_ref ("btt_type", dtd->ref_type);
}
/* Asm'out the variable information following a BTF_KIND_ARRAY. */
static void
-btf_asm_array (ctf_container_ref ctfc, ctf_arinfo_t arr)
+btf_asm_array (ctf_arinfo_t arr)
{
- btf_asm_type_ref ("bta_elem_type", ctfc, arr.ctr_contents->dtd_type);
- btf_asm_type_ref ("bta_index_type", ctfc, arr.ctr_index->dtd_type);
+ btf_asm_type_ref ("bta_elem_type", arr.ctr_contents);
+ btf_asm_type_ref ("bta_index_type", arr.ctr_index);
dw2_asm_output_data (4, arr.ctr_nelems, "bta_nelems");
}
/* Asm'out a BTF_KIND_VAR. */
static void
-btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
+btf_asm_varent (ctf_dvdef_ref var)
{
- dw2_asm_output_data (4, var->dvd_name_offset, "TYPE %u BTF_KIND_VAR '%s'",
- (*(btf_var_ids->get (var)) + num_types_added + 1),
- var->dvd_name);
+ dw2_asm_output_data (4, var->dvd_name_offset,
+ "TYPE %" PRIu64 " BTF_KIND_VAR '%s'",
+ var->dvd_id, var->dvd_name);
dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_VAR, 0, 0), "btv_info");
- btf_asm_type_ref ("btv_type", ctfc, var->dvd_type->dtd_type);
+ btf_asm_type_ref ("btv_type", var->dvd_type);
dw2_asm_output_data (4, var->dvd_visibility, "btv_linkage");
}
@@ -931,23 +486,22 @@ btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
BTF_KIND_UNION. */
static void
-btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
+btf_asm_sou_member (ctf_dmdef_t * dmd, unsigned int idx)
{
- ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type->dtd_type];
- ctf_id_t base_type = dmd->dmd_type->dtd_type;
+ ctf_dtdef_ref base_type = dmd->dmd_type;
uint64_t sou_offset = dmd->dmd_offset;
dw2_asm_output_data (4, dmd->dmd_name_offset,
"MEMBER '%s' idx=%u",
dmd->dmd_name, idx);
- /* Re-encode bitfields to BTF representation. */
- if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
+ if (base_type
+ && CTF_V2_INFO_KIND (base_type->dtd_data.ctti_info) == CTF_K_SLICE)
{
- if (btf_dmd_representable_bitfield_p (ctfc, dmd))
+ if (btf_dmd_representable_bitfield_p (dmd))
{
- unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset;
- unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits;
+ unsigned short word_offset = base_type->dtd_u.dtu_slice.cts_offset;
+ unsigned short bits = base_type->dtd_u.dtu_slice.cts_bits;
/* Pack the bit offset and bitfield size together. */
sou_offset += word_offset;
@@ -955,17 +509,17 @@ btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
sou_offset |= ((bits & 0xff) << 24);
/* Refer to the base type of the slice. */
- base_type = ref_type->dtd_u.dtu_slice.cts_type->dtd_type;
+ base_type = base_type->dtd_u.dtu_slice.cts_type;
}
else
{
/* Bitfield cannot be represented in BTF. Emit the member as having
'void' type. */
- base_type = BTF_VOID_TYPEID;
+ base_type = NULL;
}
}
- btf_asm_type_ref ("btm_type", ctfc, base_type);
+ btf_asm_type_ref ("btm_type", base_type);
dw2_asm_output_data (4, sou_offset, "btm_offset");
}
@@ -988,86 +542,68 @@ btf_asm_enum_const (unsigned int size, ctf_dmdef_t * dmd, unsigned int idx)
/* Asm'out a function parameter description following a BTF_KIND_FUNC_PROTO. */
static void
-btf_asm_func_arg (ctf_container_ref ctfc, ctf_func_arg_t * farg,
- size_t stroffset)
+btf_asm_func_arg (ctf_func_arg_t * farg, size_t stroffset)
{
/* If the function arg does not have a name, refer to the null string at
the start of the string table. This ensures correct encoding for varargs
'...' arguments. */
if ((farg->farg_name != NULL) && strcmp (farg->farg_name, ""))
- dw2_asm_output_data (4, farg->farg_name_offset + stroffset, "farg_name");
+ dw2_asm_output_data (4, farg->farg_name_offset + stroffset,
+ "farg_name '%s'", farg->farg_name);
else
- dw2_asm_output_data (4, 0, "farg_name");
-
- ctf_id_t ref_id = BTF_VOID_TYPEID;
- if (farg->farg_type && !btf_removed_type_p (farg->farg_type->dtd_type))
- ref_id = farg->farg_type->dtd_type;
+ dw2_asm_output_data (4, 0, "farg_name ''");
- btf_asm_type_ref ("farg_type", ctfc, ref_id);
+ btf_asm_type_ref ("farg_type", farg->farg_type);
}
/* Asm'out a BTF_KIND_FUNC type. */
static void
-btf_asm_func_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd, ctf_id_t id)
+btf_asm_func_type (ctf_dtdef_ref dtd)
{
- ctf_id_t ref_id = dtd->dtd_data.ctti_type;
dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
"TYPE %" PRIu64 " BTF_KIND_FUNC '%s'",
- btf_absolute_func_id (id), get_btf_type_name (dtd));
+ dtd->dtd_type, get_btf_type_name (dtd));
dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_FUNC, 0, dtd->linkage),
"btt_info: kind=%u, kflag=%u, linkage=%u",
BTF_KIND_FUNC, 0, dtd->linkage);
- btf_asm_type_ref ("btt_type", ctfc, ref_id);
+ btf_asm_type_ref ("btt_type", dtd->ref_type);
}
-/* Collect the name for the DATASEC reference required to be output as a
- symbol. */
+/* Asm'out a variable entry following a BTF_KIND_DATASEC. */
-static const char *
-get_name_for_datasec_entry (ctf_container_ref ctfc, ctf_id_t ref_id)
+static void
+btf_asm_datasec_entry (struct btf_datasec_entry entry)
{
- if (ref_id >= num_types_added + 1
- && ref_id < num_types_added + num_vars_added + 1)
+ const char *symbol_name = NULL;
+ if (entry.is_var)
{
- /* Ref to a variable. Should only appear in DATASEC entries. */
- ctf_id_t var_id = btf_relative_var_id (ref_id);
- ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[var_id];
- return dvd->dvd_name;
+ symbol_name = entry.dvd->dvd_name;
+ dw2_asm_output_data (4, entry.dvd->dvd_id,
+ "bts_type: (BTF_KIND_VAR '%s')", symbol_name);
}
- else if (ref_id >= num_types_added + num_vars_added + 1)
+ else
{
- /* Ref to a FUNC record. */
- size_t func_id = btf_relative_func_id (ref_id);
- ctf_dtdef_ref ref_type = (*funcs)[func_id];
- return get_btf_type_name (ref_type);
+ symbol_name = entry.dtd->dtd_name;
+ btf_asm_type_ref ("bts_type", entry.dtd);
}
- return NULL;
-}
-
-/* Asm'out a variable entry following a BTF_KIND_DATASEC. */
-static void
-btf_asm_datasec_entry (ctf_container_ref ctfc, struct btf_var_secinfo info)
-{
- const char *symbol_name = get_name_for_datasec_entry (ctfc, info.type);
- btf_asm_datasec_type_ref ("bts_type", ctfc, info.type);
if (!btf_with_core_debuginfo_p () || symbol_name == NULL)
- dw2_asm_output_data (4, info.offset, "bts_offset");
+ dw2_asm_output_data (4, 0, "bts_offset");
else
dw2_asm_output_offset (4, symbol_name, NULL, "bts_offset");
- dw2_asm_output_data (4, info.size, "bts_size");
+
+ dw2_asm_output_data (4, entry.size, "bts_size");
}
/* Asm'out a whole BTF_KIND_DATASEC, including its variable entries. */
static void
-btf_asm_datasec_type (ctf_container_ref ctfc, btf_datasec_t ds, ctf_id_t id,
- size_t stroffset)
+btf_asm_datasec_type (btf_datasec_t ds)
{
- dw2_asm_output_data (4, ds.name_offset + stroffset,
+ dw2_asm_output_data (4, ds.name_offset,
"TYPE %" PRIu64 " BTF_KIND_DATASEC '%s'",
- btf_absolute_datasec_id (id), ds.name);
+ ds.id, ds.name);
dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_DATASEC, 0,
ds.entries.length ()),
"btt_info: n_entries=%u", ds.entries.length ());
@@ -1075,7 +611,7 @@ btf_asm_datasec_type (ctf_container_ref ctfc, btf_datasec_t ds, ctf_id_t id,
loaders such as libbpf. */
dw2_asm_output_data (4, 0, "btt_size");
for (size_t i = 0; i < ds.entries.length (); i++)
- btf_asm_datasec_entry (ctfc, ds.entries[i]);
+ btf_asm_datasec_entry (ds.entries[i]);
}
/* Compute and output the header information for a .BTF section. */
@@ -1094,20 +630,11 @@ output_btf_header (ctf_container_ref ctfc)
uint32_t type_off = 0, type_len = 0;
uint32_t str_off = 0, str_len = 0;
- uint32_t datasec_vlen_bytes = 0;
if (!ctfc_is_empty_container (ctfc))
{
- for (size_t i = 0; i < datasecs.length (); i++)
- {
- datasec_vlen_bytes += ((datasecs[i].entries.length ())
- * sizeof (struct btf_var_secinfo));
- }
-
/* Total length (bytes) of the types section. */
- type_len = (num_types_added * sizeof (struct btf_type))
- + (num_types_created * sizeof (struct btf_type))
- + datasec_vlen_bytes
+ type_len = ctfc->ctfc_num_types * sizeof (struct btf_type)
+ ctfc->ctfc_num_vlen_bytes;
str_off = type_off + type_len;
@@ -1119,7 +646,9 @@ output_btf_header (ctf_container_ref ctfc)
/* Offset of type section. */
dw2_asm_output_data (4, type_off, "type_off");
/* Length of type section in bytes. */
- dw2_asm_output_data (4, type_len, "type_len");
+ dw2_asm_output_data (4, type_len, "type_len: ntypes=%u, vlen=%u",
+ (uint32_t) ctfc->ctfc_num_types,
+ (uint32_t) ctfc->ctfc_num_vlen_bytes);
/* Offset of string section. */
dw2_asm_output_data (4, str_off, "str_off");
/* Length of string section in bytes. */
@@ -1132,11 +661,11 @@ static void
output_btf_vars (ctf_container_ref ctfc)
{
size_t i;
- size_t num_ctf_vars = num_vars_added;
+ size_t num_ctf_vars = ctfc->ctfc_vars_list_count;
if (num_ctf_vars)
{
for (i = 0; i < num_ctf_vars; i++)
- btf_asm_varent (ctfc, ctfc->ctfc_vars_list[i]);
+ btf_asm_varent (ctfc->ctfc_vars_list[i]);
}
}
@@ -1151,7 +680,8 @@ output_btf_strs (ctf_container_ref ctfc)
while (ctf_string)
{
- dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_string, str_pos = 0x%x", str_pos);
+ dw2_asm_output_nstring (ctf_string->cts_str, -1,
+ "btf_string, str_pos = 0x%x", str_pos);
str_pos += strlen(ctf_string->cts_str) + 1;
ctf_string = ctf_string->cts_next;
}
@@ -1159,7 +689,8 @@ output_btf_strs (ctf_container_ref ctfc)
ctf_string = ctfc->ctfc_aux_strtable.ctstab_head;
while (ctf_string)
{
- dw2_asm_output_nstring (ctf_string->cts_str, -1, "btf_aux_string, str_pos = 0x%x", str_pos);
+ dw2_asm_output_nstring (ctf_string->cts_str, -1,
+ "btf_aux_string, str_pos = 0x%x", str_pos);
str_pos += strlen(ctf_string->cts_str) + 1;
ctf_string = ctf_string->cts_next;
}
@@ -1169,7 +700,7 @@ output_btf_strs (ctf_container_ref ctfc)
BTF_KIND_UNION type. */
static void
-output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+output_asm_btf_sou_fields (ctf_dtdef_ref dtd)
{
ctf_dmdef_t * dmd;
@@ -1177,7 +708,7 @@ output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
for (dmd = dtd->dtd_u.dtu_members;
dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
{
- btf_asm_sou_member (ctfc, dmd, idx);
+ btf_asm_sou_member (dmd, idx);
idx++;
}
}
@@ -1185,8 +716,7 @@ output_asm_btf_sou_fields (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
/* Output all enumerator constants following a BTF_KIND_ENUM{,64}. */
static void
-output_asm_btf_enum_list (ctf_container_ref ARG_UNUSED (ctfc),
- ctf_dtdef_ref dtd)
+output_asm_btf_enum_list (ctf_dtdef_ref dtd)
{
ctf_dmdef_t * dmd;
@@ -1209,7 +739,7 @@ output_asm_btf_func_args_list (ctf_container_ref ctfc,
ctf_func_arg_t * farg;
for (farg = dtd->dtd_u.dtu_argv;
farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
- btf_asm_func_arg (ctfc, farg, farg_name_offset);
+ btf_asm_func_arg (farg, farg_name_offset);
}
/* Output the variable portion of a BTF type record. The information depends
@@ -1220,7 +750,7 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
{
uint32_t btf_kind, encoding;
- btf_kind = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
+ btf_kind = btf_dtd_kind (dtd);
if (btf_kind == BTF_KIND_UNKN)
return;
@@ -1233,8 +763,7 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
if (dtd->dtd_data.ctti_size < 1)
break;
- /* In BTF the CHAR `encoding' seems to not be used, so clear it
- here. */
+ /* In BTF the CHAR `encoding' seems to not be used, so clear it here. */
dtd->dtd_u.dtu_enc.cte_format &= ~BTF_INT_CHAR;
encoding = BTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
@@ -1245,16 +774,16 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
break;
case BTF_KIND_ARRAY:
- btf_asm_array (ctfc, dtd->dtd_u.dtu_arr);
+ btf_asm_array (dtd->dtd_u.dtu_arr);
break;
case BTF_KIND_STRUCT:
case BTF_KIND_UNION:
- output_asm_btf_sou_fields (ctfc, dtd);
+ output_asm_btf_sou_fields (dtd);
break;
case BTF_KIND_ENUM:
- output_asm_btf_enum_list (ctfc, dtd);
+ output_asm_btf_enum_list (dtd);
break;
case BTF_KIND_FUNC_PROTO:
@@ -1284,9 +813,9 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
static void
output_asm_btf_type (ctf_container_ref ctfc, ctf_dtdef_ref type)
{
- if (btf_emit_id_p (type->dtd_type))
+ if (btf_emit_type_p (type))
{
- btf_asm_type (ctfc, type);
+ btf_asm_type (type);
output_asm_btf_vlen_bytes (ctfc, type);
}
}
@@ -1298,7 +827,9 @@ static void
output_btf_types (ctf_container_ref ctfc)
{
size_t i;
- size_t num_types = ctfc->ctfc_types->elements ();
+ size_t num_types;
+ num_types = ctfc->ctfc_types->elements ();
+
if (num_types)
{
for (i = 1; i <= num_types; i++)
@@ -1309,76 +840,45 @@ output_btf_types (ctf_container_ref ctfc)
/* Output all BTF_KIND_FUNC type records. */
static void
-output_btf_func_types (ctf_container_ref ctfc)
+output_btf_func_types (void)
{
ctf_dtdef_ref ref;
unsigned i;
FOR_EACH_VEC_ELT (*funcs, i, ref)
- btf_asm_func_type (ctfc, ref, i);
+ btf_asm_func_type (ref);
}
/* Output all BTF_KIND_DATASEC records. */
static void
-output_btf_datasec_types (ctf_container_ref ctfc)
+output_btf_datasec_types (void)
{
- size_t name_offset = ctfc_get_strtab_len (ctfc, CTF_STRTAB);
-
- for (size_t i = 0; i < datasecs.length(); i++)
- btf_asm_datasec_type (ctfc, datasecs[i], i, name_offset);
+ for (size_t i = 0; i < datasecs.length (); i++)
+ btf_asm_datasec_type (datasecs[i]);
}
-/* Postprocess the CTF debug data post initialization.
-
- During the postprocess pass:
-
- - Prepare the sorted list of BTF types.
-
- The sorted list of BTF types is, firstly, used for lookup (during the BTF
- generation process) of CTF/BTF types given a typeID.
-
- Secondly, in the emitted BTF section, BTF Types need to be in the sorted
- order of their type IDs. The BTF types section is viewed as an array,
- with type IDs used to index into that array. It is essential that every
- type be placed at the exact index corresponding to its ID, or else
- references to that type from other types will no longer be correct.
-
- - References to void types are converted to reference BTF_VOID_TYPEID. In
- CTF, a distinct type is used to encode void.
-
- - Bitfield struct/union members are converted to BTF encoding. CTF uses
- slices to encode bitfields, but BTF does not have slices and encodes
- bitfield information directly in the variable-length btf_member
- descriptions following the struct or union type.
-
- - Unrepresentable types are removed. We cannot have any invalid BTF types
- appearing in the output so they must be removed, and type ids of other
- types and references adjust accordingly. This also involves ensuring that
- BTF descriptions of struct members referring to unrepresentable types are
- not emitted, as they would be nonsensical.
-
- - Adjust inner- and inter-type references-by-ID to account for removed
- types, and construct the types list. */
+/* Write out all BTF debug info. */
void
-btf_init_postprocess (void)
+btf_output (ctf_container_ref ctfc)
{
- ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
-
- holes.create (0);
- voids.create (0);
+ output_btf_header (ctfc);
+ output_btf_types (ctfc);
+ output_btf_vars (ctfc);
+ output_btf_func_types ();
+ output_btf_datasec_types ();
+ output_btf_strs (ctfc);
+}
- num_types_added = 0;
- num_types_created = 0;
+/* Workaround for 'const void' variables. These variables are sometimes used
+ in eBPF programs to address kernel symbols. DWARF does not generate const
+ qualifier on void type, so we would incorrectly emit these variables
+ without the const qualifier. Find any such variables, and update them to
+ refer to a new 'const' modifier type for void. */
- /* Workaround for 'const void' variables. These variables are sometimes used
- in eBPF programs to address kernel symbols. DWARF does not generate const
- qualifier on void type, so we would incorrectly emit these variables
- without the const qualifier.
- Unfortunately we need the TREE node to know it was const, and we need
- to create the const modifier type (if needed) now, before making the types
- list. So we can't avoid iterating with FOR_EACH_VARIABLE here, and then
- again when creating the DATASEC entries. */
+static void
+btf_add_const_void (ctf_container_ref ctfc)
+{
ctf_dtdef_ref constvoid_dtd = NULL;
varpool_node *var;
FOR_EACH_VARIABLE (var)
@@ -1393,120 +893,392 @@ btf_init_postprocess (void)
if (die == NULL)
continue;
- ctf_dvdef_ref dvd = ctf_dvd_lookup (tu_ctfc, die);
+ ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
if (dvd == NULL)
continue;
/* Create the 'const' modifier type for void. */
if (constvoid_dtd == NULL)
- constvoid_dtd = ctf_add_reftype (tu_ctfc, CTF_ADD_ROOT,
+ constvoid_dtd = ctf_add_reftype (ctfc, CTF_ADD_ROOT,
dvd->dvd_type, CTF_K_CONST, NULL);
dvd->dvd_type = constvoid_dtd;
}
}
+}
- size_t i;
- size_t num_ctf_types = tu_ctfc->ctfc_types->elements ();
+/* Functions actually get two type records: a BTF_KIND_FUNC_PROTO, and also a
+ BTF_KIND_FUNC. But the CTF container only allocates one type per function,
+ which matches closely with BTF_KIND_FUNC_PROTO. For each such function,
+ construct a BTF_KIND_FUNC entry. This is done early, because we want FUNC
+ records even for functions which are later inlined by optimizations. */
- if (num_ctf_types)
+static void
+btf_add_func_records (ctf_container_ref ctfc)
+{
+ cgraph_node *func;
+ FOR_EACH_FUNCTION (func)
{
- init_btf_id_map (num_ctf_types + 1);
-
- /* Allocate the types list and traverse all types, placing each type
- at the index according to its ID. Add 1 because type ID 0 always
- represents VOID. */
- tu_ctfc->ctfc_types_list
- = ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1);
- tu_ctfc->ctfc_types->traverse<ctf_container_ref, btf_dtd_postprocess_cb>
- (tu_ctfc);
-
- /* Build mapping of CTF type ID -> BTF type ID, and count total number
- of valid BTF types added. */
- for (i = 1; i <= num_ctf_types; i++)
- {
- ctf_dtdef_ref dtd = tu_ctfc->ctfc_types_list[i];
- ctf_id_t btfid = btf_adjust_type_id (dtd->dtd_type);
- set_btf_id (dtd->dtd_type, btfid);
- if (btfid < BTF_MAX_TYPE && (btfid != BTF_VOID_TYPEID))
- num_types_added ++;
- }
+ dw_die_ref die = lookup_decl_die (func->decl);
+ if (die == NULL)
+ continue;
+
+ ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
+ if (dtd == NULL)
+ continue;
+
+ /* Do not add FUNC records for kernel helpers. */
+ if (DECL_EXTERNAL (func->decl)
+ && (lookup_attribute ("kernel_helper",
+ DECL_ATTRIBUTES (func->decl))) != NULL_TREE)
+ continue;
+
+ ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
+ func_dtd->dtd_data = dtd->dtd_data;
+ func_dtd->dtd_data.ctti_type = dtd->dtd_type;
+ func_dtd->ref_type = dtd;
+ func_dtd->linkage = dtd->linkage;
+ func_dtd->dtd_name = dtd->dtd_name;
+ /* Type ID will be assigned just before output. */
+
+ /* Only the BTF_KIND_FUNC type actually references the name.
+ The BTF_KIND_FUNC_PROTO is always anonymous. */
+ dtd->dtd_data.ctti_name = 0;
+
+ /* Mark 'extern' funcs. */
+ if (DECL_EXTERNAL (func->decl))
+ func_dtd->linkage = BTF_FUNC_EXTERN;
+
+ /* Buffer newly created FUNC records. We cannot simply insert them
+ into the types map, because types are keyed by their DWARF DIE,
+ and we have no unique DIE to use as a key since the FUNC_PROTOs
+ are already present in the map. */
+ vec_safe_push (funcs, func_dtd);
+ func_map->put (dtd, func_dtd);
}
}
-/* Process and output all BTF data. Entry point of btfout. */
+/* Initial entry point of BTF generation, called at early_finish () after
+ CTF information has possibly been output. Translate all CTF information
+ to BTF, and do any processing that must be done early, such as creating
+ BTF_KIND_FUNC records. */
void
-btf_output (const char * filename)
+btf_early_finish (void)
{
ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
- init_btf_sections ();
-
- datasecs.create (0);
vec_alloc (funcs, 16);
+ func_map = hash_map<ctf_dtdef_ref, ctf_dtdef_ref>::create_ggc (16);
- ctf_add_cuname (tu_ctfc, filename);
+ /* Note: from this point on, destructive changes are made to the TU CTFC to
+ translate CTF to BTF. If CTF debug info has also been requested, it must
+ be emitted before starting the translation to BTF. */
+ btf_add_const_void (tu_ctfc);
+ btf_add_func_records (tu_ctfc);
+}
- btf_emit_preprocess (tu_ctfc);
+/* Push a BTF datasec entry ENTRY into the datasec named SECNAME,
+ creating the datasec record if it does not already exist. */
- output_btf_header (tu_ctfc);
- output_btf_types (tu_ctfc);
- output_btf_vars (tu_ctfc);
- output_btf_func_types (tu_ctfc);
- output_btf_datasec_types (tu_ctfc);
- output_btf_strs (tu_ctfc);
+static void
+btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
+ struct btf_datasec_entry entry)
+{
+ if (secname == NULL)
+ return;
+
+ /* If we already have a datasec record for the appropriate section,
+ append the new entry to it. */
+ for (size_t i = 0; i < datasecs.length (); i++)
+ if (strcmp (datasecs[i].name, secname) == 0)
+ {
+ datasecs[i].entries.safe_push (entry);
+ return;
+ }
+
+ /* If we don't already have a datasec record for secname, make one. */
+ uint32_t str_off;
+ ctf_add_string (ctfc, secname, &str_off, CTF_AUX_STRTAB);
+ if (strcmp (secname, ""))
+ ctfc->ctfc_aux_strlen += strlen (secname) + 1;
+
+ /* Note: ID will be assigned just before output. */
+ btf_datasec_t ds;
+ ds.name = secname;
+ ds.name_offset = str_off;
+
+ /* Insert the entry into the new datasec record. */
+ ds.entries.create (1);
+ ds.entries.quick_push (entry);
+
+ /* Insert the datasec record itself. */
+ datasecs.safe_push (ds);
}
-/* Reset all state for BTF generation so that we can rerun the compiler within
- the same process. */
+/* Create a datasec entry for a function, and insert it into the datasec
+ record for the appropriate section. Create the record if it does not
+ yet exist. */
-void
-btf_finalize (void)
+static void
+btf_datasec_add_func (ctf_container_ref ctfc, cgraph_node *func,
+ ctf_dtdef_ref func_dtd)
{
- btf_info_section = NULL;
+ const char *section_name = get_section_name (func);
- /* Clear preprocessing state. */
- num_vars_added = 0;
- num_types_added = 0;
- num_types_created = 0;
+ /* Note: get_section_name () returns NULL for functions in text
+ section. This is intentional, since we do not want to generate
+ DATASEC entries for them. */
+ if (section_name == NULL)
+ return;
- holes.release ();
- voids.release ();
- for (size_t i = 0; i < datasecs.length (); i++)
- datasecs[i].entries.release ();
- datasecs.release ();
+ struct btf_datasec_entry entry;
+ gcc_assert (func_dtd);
+ entry.dtd = func_dtd;
+ entry.is_var = false;
- funcs = NULL;
+ /* Size is left as zero at compile time, to be filled in by loaders
+ such as libbpf. */
+ entry.size = 0;
- btf_var_ids->empty ();
- btf_var_ids = NULL;
+ btf_datasec_push_entry (ctfc, section_name, entry);
+}
- free (btf_id_map);
- btf_id_map = NULL;
+/* Create a datasec entry for a variable, and insert it into the datasec
+ record for the appropriate section. Create the record if it does not
+ yet exist. */
- ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
- ctfc_delete_container (tu_ctfc);
- tu_ctfc = NULL;
+static void
+btf_datasec_add_var (ctf_container_ref ctfc, varpool_node *var,
+ ctf_dvdef_ref dvd)
+{
+ /* PR112849: avoid assuming a section for extern decls without
+ an explicit section, which would result in incorrectly
+ emitting a BTF_KIND_DATASEC entry for them. */
+ if (DECL_EXTERNAL (var->decl) && var->get_section () == NULL)
+ return;
+
+ const char *section_name = get_section_name (var);
+ if (section_name == NULL)
+ return;
+
+ gcc_assert (dvd);
+ struct btf_datasec_entry entry;
+ entry.dvd = dvd;
+ entry.is_var = true;
+ entry.size = 0;
+
+ tree size = DECL_SIZE_UNIT (var->decl);
+ if (tree_fits_uhwi_p (size))
+ entry.size = tree_to_uhwi (size);
+ else if (VOID_TYPE_P (TREE_TYPE (var->decl)))
+ entry.size = 1;
+
+ btf_datasec_push_entry (ctfc, section_name, entry);
}
-/* Initial entry point of BTF generation, called at early_finish () after
- CTF information has possibly been output. Translate all CTF information
- to BTF, and do any processing that must be done early, such as creating
- BTF_KIND_FUNC records. */
+/* Add datasec entries for functions to CTFC. */
-void
-btf_early_finish (void)
+static void
+btf_add_func_datasec_entries (ctf_container_ref ctfc)
+{
+ /* We need to create FUNC records at early_finish, so that we have them
+ even for functions which are later inlined by optimization passes.
+ But on the other hand, we do not want datasec entries for such functions,
+ so only create the datasec entries for them late. This loop will not
+ hit functions which have already been inlined. */
+ cgraph_node *func;
+ FOR_EACH_FUNCTION (func)
+ {
+ dw_die_ref die = lookup_decl_die (func->decl);
+ if (die == NULL)
+ continue;
+
+ ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
+ if (dtd == NULL)
+ continue;
+
+ ctf_dtdef_ref *pdtd = func_map->get (dtd);
+ if (pdtd && DECL_EXTERNAL (func->decl))
+ btf_datasec_add_func (ctfc, func, *pdtd);
+ }
+}
+
+/* Helper function used to determine whether or not a BTF_KIND_VAR record
+ for the variable VAR shall be emitted. */
+
+static bool
+btf_emit_variable_p (ctf_container_ref ctfc, varpool_node *var,
+ ctf_dvdef_ref *pdvd)
+{
+ dw_die_ref die = lookup_decl_die (var->decl);
+ if (die == NULL)
+ return false;
+
+ ctf_dvdef_ref dvd = ctf_dvd_lookup (ctfc, die);
+ if (dvd == NULL)
+ return false;
+
+ /* If this is an extern variable declaration with a defining declaration
+ later, skip it so that only the defining declaration is emitted.
+ This is the same case, fix and reasoning as in CTF; see PR105089. */
+ if (ctf_dvd_ignore_lookup (ctfc, dvd->dvd_key))
+ return false;
+
+ /* Skip variables with unrepresentable types. */
+ if (!btf_emit_type_p (dvd->dvd_type))
+ return false;
+
+ *pdvd = dvd;
+ return true;
+}
+
+/* Add BTF_KIND_VAR records for variables. */
+
+static void
+btf_add_vars (ctf_container_ref ctfc)
{
- btf_init_postprocess ();
+ size_t num_ctf_vars = ctfc->ctfc_vars->elements ();
+
+ ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars);
+
+ varpool_node *var;
+ ctf_dvdef_ref dvd;
+ FOR_EACH_VARIABLE (var)
+ {
+ if (!btf_emit_variable_p (ctfc, var, &dvd))
+ continue;
+
+ /* Mark 'extern' variables. */
+ if (DECL_EXTERNAL (var->decl))
+ dvd->dvd_visibility = BTF_VAR_GLOBAL_EXTERN;
+
+ /* Add the variable to the vars list. */
+ ctfc->ctfc_vars_list[ctfc->ctfc_vars_list_count++] = dvd;
+
+ /* Add a BTF_KIND_DATASEC entry for the variable. */
+ btf_datasec_add_var (ctfc, var, dvd);
+ }
+}
+
+/* Callback used by btf_assign_type_ids to insert types into their initial
+ positions in the type list. */
+
+static int
+btf_type_list_cb (ctf_dtdef_ref *slot, ctf_container_ref ctfc)
+{
+ ctf_dtdef_ref dtd = *slot;
+ ctfc->ctfc_types_list[dtd->dtd_type] = dtd;
+ return 1;
+}
+
+/* Construct the initial type list and assign BTF IDs for all types translated
+ from CTF. */
+
+static void
+btf_collect_translated_types (ctf_container_ref ctfc)
+{
+ size_t num_ctf_types = ctfc->ctfc_types->elements ();
+
+ /* First, place each type at its CTF-assigned index in the list.
+ The '+1' here and below is to account for the implicit void type with
+ ID 0. There is no real type at index 0 in the list. */
+ ctfc->ctfc_types_list = ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1);
+ ctfc->ctfc_types->traverse<ctf_container_ref, btf_type_list_cb> (ctfc);
+
+ /* Now, pass through the list and adjust IDs to account for types which will
+ not be emitted. This results in each type that will be emitted in BTF
+ being assigned an appropriate ID. Note that types which will not be
+ emitted remain in the list; they are skipped at output time. */
+ unsigned int skip = 0;
+ for (size_t i = 1; i <= num_ctf_types; i++)
+ {
+ ctf_dtdef_ref dtd = ctfc->ctfc_types_list[i];
+ if (!btf_emit_type_p (dtd))
+ {
+ dtd->dtd_type = BTF_INVALID_TYPEID;
+ skip += 1;
+ continue;
+ }
+
+ dtd->dtd_type -= skip;
+ ctfc->ctfc_num_types++;
+ ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
+ }
+
+ max_translated_id = ctfc->ctfc_num_types;
+ ctfc->ctfc_nextid = ctfc->ctfc_num_types + 1;
+}
+
+/* Assign BTF IDs for FUNC records and account for their size. */
+
+static void
+btf_assign_func_ids (ctf_container_ref ctfc)
+{
+ ctf_dtdef_ref dtd;
+ unsigned int i;
+ FOR_EACH_VEC_ELT (*funcs, i, dtd)
+ {
+ dtd->dtd_type = ctfc->ctfc_nextid++;
+ ctfc->ctfc_num_types++;
+ }
+}
+
+/* Assign BTF IDs for variables and account for their size. */
+
+static void
+btf_assign_var_ids (ctf_container_ref ctfc)
+{
+ for (size_t i = 0; i < ctfc->ctfc_vars_list_count; i++)
+ {
+ ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
+ ctf_id_t id = ctfc->ctfc_nextid++;
+ gcc_assert (id <= BTF_MAX_TYPE);
+ dvd->dvd_id = id;
+
+ ctfc->ctfc_num_types++;
+ ctfc->ctfc_num_vlen_bytes += sizeof (struct btf_var);
+ }
+}
+
+/* Assign BTF IDs for datasec records and account for their size. */
+
+static void
+btf_assign_datasec_ids (ctf_container_ref ctfc)
+{
+ for (size_t i = 0; i < datasecs.length (); i++)
+ {
+ datasecs[i].id = ctfc->ctfc_nextid++;
+ datasecs[i].name_offset += ctfc_get_strtab_len (ctfc, CTF_STRTAB);
+ ctfc->ctfc_num_types++;
+ ctfc->ctfc_num_vlen_bytes += (datasecs[i].entries.length ()
+ * sizeof (struct btf_var_secinfo));
+ }
}
/* Late entry point for BTF generation, called from dwarf2out_finish ().
Complete and emit BTF information. */
void
-btf_finish (const char * filename)
+btf_finish (void)
{
- btf_output (filename);
+ ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+ init_btf_sections ();
+
+ datasecs.create (0);
+
+ tu_ctfc->ctfc_num_types = 0;
+ tu_ctfc->ctfc_num_vlen_bytes = 0;
+ tu_ctfc->ctfc_vars_list_count = 0;
+
+ btf_add_vars (tu_ctfc);
+ btf_collect_translated_types (tu_ctfc);
+ btf_add_func_datasec_entries (tu_ctfc);
+ btf_assign_var_ids (tu_ctfc);
+ btf_assign_func_ids (tu_ctfc);
+ btf_assign_datasec_ids (tu_ctfc);
+
+ /* Finally, write out the complete .BTF section. */
+ btf_output (tu_ctfc);
/* If compiling for BPF with CO-RE info, we cannot deallocate until after the
contents of the .BTF.ext section are finalized, which happens very late in
@@ -1516,6 +1288,27 @@ btf_finish (const char * filename)
btf_finalize ();
}
+/* Reset all state for BTF generation so that we can rerun the compiler within
+ the same process. */
+
+void
+btf_finalize (void)
+{
+ btf_info_section = NULL;
+ max_translated_id = 0;
+
+ for (size_t i = 0; i < datasecs.length (); i++)
+ datasecs[i].entries.release ();
+ datasecs.release ();
+
+ funcs = NULL;
+ func_map->empty ();
+ func_map = NULL;
+
+ ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
+ ctfc_delete_container (tu_ctfc);
+ tu_ctfc = NULL;
+}
/* Traversal function for all BTF_KIND_FUNC type records. */
@@ -164,10 +164,14 @@ struct GTY ((for_user)) ctf_dtdef
ctf_id_t dtd_type; /* Type identifier for this definition. */
ctf_dtdef_ref ref_type; /* Type referred to by this type (if any). */
ctf_itype_t dtd_data; /* Type node. */
- bool from_global_func; /* Whether this type was added from a global
- function. */
uint32_t linkage; /* Used in function types. 0=local, 1=global. */
- bool dtd_enum_unsigned; /* Enum signedness. */
+
+ /* Whether this type was added from a global function. */
+ BOOL_BITFIELD from_global_func : 1;
+ /* Enum signedness. */
+ BOOL_BITFIELD dtd_enum_unsigned : 1;
+ /* Lots of spare bits. */
+
union GTY ((desc ("ctf_dtu_d_union_selector (&%1)")))
{
/* struct, union, or enum. */
@@ -194,6 +198,7 @@ struct GTY ((for_user)) ctf_dvdef
uint32_t dvd_name_offset; /* Offset of the name in str table. */
unsigned int dvd_visibility; /* External visibility. 0=static,1=global. */
ctf_dtdef_ref dvd_type; /* Type of variable. */
+ ctf_id_t dvd_id; /* ID of this variable. Only used for BTF. */
};
typedef struct ctf_dvdef ctf_dvdef_t;
@@ -388,7 +393,7 @@ extern void ctf_output (const char * filename);
extern void ctf_finalize (void);
extern void btf_early_finish (void);
-extern void btf_finish (const char * filename);
+extern void btf_finish (void);
extern void btf_finalize (void);
extern ctf_container_ref ctf_get_tu_ctfc (void);
@@ -443,7 +448,9 @@ extern int ctf_add_variable (ctf_container_ref, const char *, ctf_dtdef_ref,
dw_die_ref, unsigned int, dw_die_ref);
extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
-extern ctf_id_t get_btf_id (ctf_id_t);
+
+/* Callback and traversal function for BTF_KIND_FUNC records. Used by BPF
+ target for BPF CO-RE implementation. */
typedef bool (*funcs_traverse_callback) (ctf_dtdef_ref, void *);
bool traverse_btf_func_types (funcs_traverse_callback, void *);
@@ -979,7 +979,7 @@ ctf_debug_early_finish (const char * filename)
/* For LTO builds, also emit BTF now. */
if (flag_lto && !in_lto_p)
- btf_finish (filename);
+ btf_finish ();
}
else
/* Otherwise, done with the CTF container. */
@@ -989,12 +989,12 @@ ctf_debug_early_finish (const char * filename)
/* Finish CTF/BTF debug info emission. */
void
-ctf_debug_finish (const char * filename)
+ctf_debug_finish ()
{
/* Emit BTF late, unless this is an LTO build in which case it was
already done early. */
if (btf_debuginfo_p () && !flag_lto)
- btf_finish (filename);
+ btf_finish ();
}
#include "gt-dwarf2ctf.h"
@@ -32,7 +32,7 @@ extern void ctf_debug_init (void);
extern void ctf_debug_init_postprocess (bool);
extern bool ctf_do_die (dw_die_ref);
extern void ctf_debug_early_finish (const char *);
-extern void ctf_debug_finish (const char *);
+extern void ctf_debug_finish (void);
/* Wrappers for CTF/BTF to fetch information from GCC DWARF DIE. Used in
ctfc.cc.
@@ -32345,7 +32345,7 @@ dwarf2out_finish (const char *filename)
/* Generate CTF/BTF debug info. */
if ((ctf_debug_info_level > CTFINFO_LEVEL_NONE
|| btf_debuginfo_p ()) && lang_GNU_C ())
- ctf_debug_finish (filename);
+ ctf_debug_finish ();
#ifdef CODEVIEW_DEBUGGING_INFO
if (codeview_debuginfo_p ())