CTF types. */
static unsigned int num_types_created = 0;
+/* Name strings for BTF kinds.
+ Note: the indices here must match the type defines in btf.h. */
+static const char *const btf_kind_names[] =
+ {
+ "UNKN", "INT", "PTR", "ARRAY", "STRUCT", "UNION", "ENUM", "FWD",
+ "TYPEDEF", "VOLATILE", "CONST", "RESTRICT", "FUNC", "FUNC_PROTO",
+ "VAR", "DATASEC", "FLOAT", "DECL_TAG", "TYPE_TAG", "ENUM64"
+ };
+
+/* Return a name string for the given BTF_KIND. */
+
+static const char *
+btf_kind_name (uint32_t btf_kind)
+{
+ return btf_kind_names[btf_kind];
+}
+
/* Map a CTF type kind to the corresponding BTF type kind. */
static uint32_t
return BTF_KIND_UNKN;
}
+/* 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 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
info.type = 0;
unsigned int *var_id = btf_var_ids->get (dvd);
if (var_id)
- /* +1 for the sentinel type not in the types map. */
- info.type = *var_id + num_types_added + 1;
+ info.type = btf_absolute_var_id (*var_id);
else
continue;
/* BTF asm helper routines. */
+/* Asm'out a reference to another BTF type. */
+
+static void
+btf_asm_type_ref (const char *prefix, ctf_container_ref ctfc, ctf_id_t ref_id)
+{
+ if (ref_id == BTF_VOID_TYPEID || ref_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, ref_id, "%s: void", prefix);
+ }
+ else if (ref_id >= num_types_added + 1
+ && ref_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 (ref_id);
+ ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[var_id];
+ dw2_asm_output_data (4, ref_id, "%s: (BTF_KIND_VAR '%s')",
+ prefix, dvd->dvd_name);
+
+ }
+ else if (ref_id >= num_types_added + num_vars_added + 1)
+ {
+ /* Ref to a FUNC record. */
+ size_t func_id = btf_relative_func_id (ref_id);
+ ctf_dtdef_ref ref_type = (*funcs)[func_id];
+ dw2_asm_output_data (4, ref_id, "%s: (BTF_KIND_FUNC '%s')",
+ prefix, ref_type->dtd_name);
+ }
+ else
+ {
+ /* Ref to a standard type in the types list. */
+ ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[ref_id];
+ uint32_t ref_kind
+ = get_btf_kind (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info));
+
+ dw2_asm_output_data (4, ref_id, "%s: (BTF_KIND_%s '%s')",
+ prefix, btf_kind_name (ref_kind),
+ ref_type->dtd_name);
+ }
+}
+
/* Asm'out a BTF type. This routine is responsible for the bulk of the task
of converting CTF types to their BTF representation. */
btf_kind = BTF_KIND_ENUM64;
}
- dw2_asm_output_data (4, dtd->dtd_data.ctti_name, "btt_name");
+ dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
+ "TYPE %lu BTF_KIND_%s '%s'",
+ get_btf_id (dtd->dtd_type), btf_kind_name (btf_kind),
+ dtd->dtd_name);
dw2_asm_output_data (4, BTF_TYPE_INFO (btf_kind, btf_kflag, btf_vlen),
"btt_info: kind=%u, kflag=%u, vlen=%u",
btf_kind, btf_kflag, btf_vlen);
break;
}
- dw2_asm_output_data (4, get_btf_id (dtd->dtd_data.ctti_type), "btt_type");
+ ctf_id_t ref_id = get_btf_id (dtd->dtd_data.ctti_type);
+ btf_asm_type_ref ("btt_type", ctfc, ref_id);
}
/* Asm'out the variable information following a BTF_KIND_ARRAY. */
static void
-btf_asm_array (ctf_dtdef_ref dtd)
+btf_asm_array (ctf_container_ref ctfc, ctf_arinfo_t arr)
{
- dw2_asm_output_data (4, get_btf_id (dtd->dtd_u.dtu_arr.ctr_contents),
- "bta_contents");
- dw2_asm_output_data (4, get_btf_id (dtd->dtd_u.dtu_arr.ctr_index),
- "bta_index");
- dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_nelems, "bta_nelems");
+ btf_asm_type_ref ("bta_elem_type", ctfc, get_btf_id (arr.ctr_contents));
+ btf_asm_type_ref ("bta_index_type", ctfc, get_btf_id (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_dvdef_ref var)
+btf_asm_varent (ctf_container_ref ctfc, ctf_dvdef_ref var)
{
- dw2_asm_output_data (4, var->dvd_name_offset, "btv_name");
+ ctf_id_t ref_id = get_btf_id (var->dvd_type);
+ 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, BTF_TYPE_INFO (BTF_KIND_VAR, 0, 0), "btv_info");
- dw2_asm_output_data (4, get_btf_id (var->dvd_type), "btv_type");
+ btf_asm_type_ref ("btv_type", ctfc, ref_id);
dw2_asm_output_data (4, var->dvd_visibility, "btv_linkage");
}
BTF_KIND_UNION. */
static void
-btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd)
+btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned int idx)
{
ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type];
sou_offset &= 0x00ffffff;
sou_offset |= ((bits & 0xff) << 24);
+ dw2_asm_output_data (4, dmd->dmd_name_offset,
+ "MEMBER '%s' idx=%u",
+ dmd->dmd_name, idx);
/* Refer to the base type of the slice. */
- dw2_asm_output_data (4, dmd->dmd_name_offset, "btm_name_off");
- dw2_asm_output_data (4, get_btf_id (base_type), "btm_type");
+ btf_asm_type_ref ("btm_type", ctfc, get_btf_id (base_type));
dw2_asm_output_data (4, sou_offset, "btm_offset");
}
else
{
- dw2_asm_output_data (4, dmd->dmd_name_offset, "btm_name_off");
- dw2_asm_output_data (4, get_btf_id (dmd->dmd_type), "btm_type");
+ dw2_asm_output_data (4, dmd->dmd_name_offset,
+ "MEMBER '%s' idx=%u",
+ dmd->dmd_name, idx);
+ btf_asm_type_ref ("btm_type", ctfc, get_btf_id (dmd->dmd_type));
dw2_asm_output_data (4, dmd->dmd_offset, "btm_offset");
}
}
/* Asm'out an enum constant following a BTF_KIND_ENUM{,64}. */
static void
-btf_asm_enum_const (unsigned int size, ctf_dmdef_t * dmd)
+btf_asm_enum_const (unsigned int size, ctf_dmdef_t * dmd, unsigned int idx)
{
- dw2_asm_output_data (4, dmd->dmd_name_offset, "bte_name");
+ dw2_asm_output_data (4, dmd->dmd_name_offset, "ENUM_CONST '%s' idx=%u",
+ dmd->dmd_name, idx);
if (size == 4)
dw2_asm_output_data (size, dmd->dmd_value, "bte_value");
else
/* Asm'out a function parameter description following a BTF_KIND_FUNC_PROTO. */
static void
-btf_asm_func_arg (ctf_func_arg_t * farg, size_t stroffset)
+btf_asm_func_arg (ctf_container_ref ctfc, 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
else
dw2_asm_output_data (4, 0, "farg_name");
- dw2_asm_output_data (4, (btf_removed_type_p (farg->farg_type)
- ? BTF_VOID_TYPEID
- : get_btf_id (farg->farg_type)),
- "farg_type");
+ btf_asm_type_ref ("farg_type", ctfc, (btf_removed_type_p (farg->farg_type)
+ ? BTF_VOID_TYPEID
+ : get_btf_id (farg->farg_type)));
}
/* Asm'out a BTF_KIND_FUNC type. */
static void
-btf_asm_func_type (ctf_dtdef_ref dtd)
+btf_asm_func_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd, size_t i)
{
- dw2_asm_output_data (4, dtd->dtd_data.ctti_name, "btt_name");
- 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);
- dw2_asm_output_data (4, get_btf_id (dtd->dtd_data.ctti_type), "btt_type");
+ ctf_id_t ref_id = dtd->dtd_data.ctti_type;
+ dw2_asm_output_data (4, dtd->dtd_data.ctti_name,
+ "TYPE %lu BTF_KIND_FUNC '%s'",
+ num_types_added + num_vars_added + 1 + i,
+ dtd->dtd_name);
+ 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, get_btf_id (ref_id));
}
/* Asm'out a variable entry following a BTF_KIND_DATASEC. */
static void
-btf_asm_datasec_entry (struct btf_var_secinfo info)
+btf_asm_datasec_entry (ctf_container_ref ctfc, struct btf_var_secinfo info)
{
- dw2_asm_output_data (4, info.type, "bts_type");
+ btf_asm_type_ref ("bts_type", ctfc, info.type);
dw2_asm_output_data (4, info.offset, "bts_offset");
dw2_asm_output_data (4, info.size, "bts_size");
}
/* Asm'out a whole BTF_KIND_DATASEC, including its variable entries. */
static void
-btf_asm_datasec_type (btf_datasec_t ds, size_t stroffset)
+btf_asm_datasec_type (ctf_container_ref ctfc, btf_datasec_t ds, ctf_id_t id,
+ size_t stroffset)
{
- dw2_asm_output_data (4, ds.name_offset + stroffset, "btt_name");
+ dw2_asm_output_data (4, ds.name_offset + stroffset,
+ "TYPE %lu BTF_KIND_DATASEC '%s'",
+ btf_absolute_datasec_id (id), ds.name);
dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_DATASEC, 0,
ds.entries.length ()),
- "btt_info");
+ "btt_info: n_entries=%u", ds.entries.length ());
/* Note: the "total section size in bytes" is emitted as 0 and patched by
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 (ds.entries[i]);
+ btf_asm_datasec_entry (ctfc, ds.entries[i]);
}
/* Compute and output the header information for a .BTF section. */
if (num_ctf_vars)
{
for (i = 0; i < num_ctf_vars; i++)
- btf_asm_varent (ctfc->ctfc_vars_list[i]);
+ btf_asm_varent (ctfc, ctfc->ctfc_vars_list[i]);
}
}
{
ctf_dmdef_t * dmd;
+ unsigned idx = 0;
for (dmd = dtd->dtd_u.dtu_members;
dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
- btf_asm_sou_member (ctfc, dmd);
+ {
+ btf_asm_sou_member (ctfc, dmd, idx);
+ idx++;
+ }
}
/* Output all enumerator constants following a BTF_KIND_ENUM{,64}. */
{
ctf_dmdef_t * dmd;
+ unsigned idx = 0;
for (dmd = dtd->dtd_u.dtu_members;
dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
- btf_asm_enum_const (dtd->dtd_data.ctti_size, dmd);
+ {
+ btf_asm_enum_const (dtd->dtd_data.ctti_size, dmd, idx);
+ idx++;
+ }
}
/* Output all function arguments following a BTF_KIND_FUNC_PROTO. */
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 (farg, farg_name_offset);
+ btf_asm_func_arg (ctfc, farg, farg_name_offset);
}
/* Output the variable portion of a BTF type record. The information depends
break;
case BTF_KIND_ARRAY:
- btf_asm_array (dtd);
+ btf_asm_array (ctfc, dtd->dtd_u.dtu_arr);
break;
case BTF_KIND_STRUCT:
/* Output all BTF_KIND_FUNC type records. */
static void
-output_btf_func_types (void)
+output_btf_func_types (ctf_container_ref ctfc)
{
for (size_t i = 0; i < vec_safe_length (funcs); i++)
- btf_asm_func_type ((*funcs)[i]);
+ btf_asm_func_type (ctfc, (*funcs)[i], i);
}
/* Output all BTF_KIND_DATASEC records. */
size_t name_offset = ctfc_get_strtab_len (ctfc, CTF_STRTAB);
for (size_t i = 0; i < datasecs.length(); i++)
- btf_asm_datasec_type (datasecs[i], name_offset);
+ btf_asm_datasec_type (ctfc, datasecs[i], i, name_offset);
}
/* Postprocess the CTF debug data post initialization.
output_btf_header (tu_ctfc);
output_btf_types (tu_ctfc);
output_btf_vars (tu_ctfc);
- output_btf_func_types ();
+ output_btf_func_types (tu_ctfc);
output_btf_datasec_types (tu_ctfc);
output_btf_strs (tu_ctfc);
}