libctf: create, types: variables and datasecs (REVIEW NEEDED)

This is an area of significant difference from CTFv3.  The API changes
significantly, with quite a few additions to allow creation and querying of
these new datasec entities:

-typedef int ctf_variable_f (const char *name, ctf_id_t type, void *arg);
+typedef int ctf_variable_f (ctf_dict_t *, const char *name, ctf_id_t type,
+			    void *arg);
+typedef int ctf_datasec_var_f (ctf_dict_t *fp, ctf_id_t type, size_t offset,
+			       size_t datasec_size, void *arg);

+/* Search a datasec for a variable covering a given offset.
+
+   Errors with ECTF_NODATASEC if not found.  */
+
+ctf_id_t ctf_datasec_var_offset (ctf_dict_t *fp, ctf_id_t datasec,
+				 uint32_t offset);
+
+/* Return the datasec that a given variable appears in, or ECTF_NODATASEC if
+   none.  */
+
+ctf_id_t ctf_variable_datasec (ctf_dict_t *fp, ctf_id_t var);

+int ctf_datasec_var_iter (ctf_dict_t *, ctf_id_t, ctf_datasec_var_f *,
+			  void *);
+ctf_id_t ctf_datasec_var_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
+			       size_t *size, size_t *offset);

-int ctf_add_variable (ctf_dict_t *, const char *, ctf_id_t);
+/* ctf_add_variable adds variables to no datasec at all;
+   ctf_add_section_variable adds them to the given datasec, or to no datasec at
+   all if the datasec is NULL.  */
+
+ctf_id_t ctf_add_variable (ctf_dict_t *, const char *, int linkage, ctf_id_t);
+ctf_id_t ctf_add_section_variable (ctf_dict_t *, uint32_t,
+				   const char *datasec, const char *name,
+				   int linkage, ctf_id_t type,
+				   size_t size, size_t offset);

We tie datasecs quite closely to variables at addition (and, as should
become clear later, dedup) time: you never create datasecs, you only create
variables *in* datasecs, and the datasec springs into existence when you do
so: datasecs are always found in the same dict as the variables they contain
(the variables are never in the parent if the datasec is in a child or
anything).  We keep track of the variable->datasec mapping in
ctf_var_datasecs (populating it at addition and open time), to allow
ctf_variable_datasec to work at reasonable speed.  (But, as yet, there are
no tests of this function at all.)

The datasecs are created unsorted (to avoid variable addition becoming
O(n^2)) and sorted at serialization time, and when ctf_datasec_var_offset is
invoked.

We reuse the natural-alignment code from struct addition to get a plausible
offset in datasecs if an alignment of -1 is specified: maybe this is
unnecessary now (it was originally added when ctf_add_variable added
variables to a "default datasec", while now it just leaves them out of
all datasecs, like externs are).

One constraint of this is that we currently prohibit the addition of
nonrepresentable-typed variables, because we can't tell what their natural
alignment is: if we dropped the whole "align" and just required everyone
adding a variable to a datasec to specify an offset, we could drop that
restriction. WDYT?

One additional caveat: right now, ctf_lookup_variable() looks up the type of
a variable (because when it was invented, variables were not entities in
themselves that you could look up).  This name is confusing as hell as a
result.  It might be less confusing to make it return the CTF_K_VAR, but
that would be awful to adapt callers to, since both are represented with
ctf_id_t's, so the compiler wouldn't warn about the needed change at all...
I've vacillated on this three or four times now.
This commit is contained in:
Nick Alcock
2025-04-24 17:42:16 +01:00
parent 097ff012e4
commit ea21a1b2ae
7 changed files with 488 additions and 65 deletions

View File

@@ -176,6 +176,8 @@ typedef struct ctf_decl
int cd_enomem; /* Nonzero if OOM during printing. */
} ctf_decl_t;
#define DTD_F_UNSORTED 0x0001 /* set on a datasec if it needs sorting. */
typedef struct ctf_dtdef
{
ctf_list_t dtd_list; /* List forward/back pointers. */
@@ -431,8 +433,6 @@ struct ctf_dict
ctf_link_sym_t **ctf_dynsymidx; /* Indexes ctf_dynsyms by symidx. */
uint32_t ctf_dynsymmax; /* Maximum ctf_dynsym index. */
ctf_list_t ctf_in_flight_dynsyms; /* Dynsyms during accumulation. */
struct ctf_varent *ctf_vars; /* Sorted variable->type mapping. */
unsigned long ctf_nvars; /* Number of variables in ctf_vars. */
uint32_t ctf_typemax; /* Maximum valid type index. */
uint32_t ctf_idmax; /* Maximum valid non-provisional type ID. */
uint32_t ctf_stypes; /* Number of static (non-dynamic) types. */
@@ -630,7 +630,6 @@ extern ctf_id_t ctf_index_to_type (const ctf_dict_t *, uint32_t);
#define LCTF_PRESERIALIZED 0x0020 /* Already serialized all but the strtab. */
extern ctf_dynhash_t *ctf_name_table (ctf_dict_t *, int);
extern ctf_id_t ctf_lookup_variable_here (ctf_dict_t *fp, const char *name);
extern const ctf_type_t *ctf_lookup_by_id (ctf_dict_t **, ctf_id_t,
const ctf_type_t **suffix);
extern const ctf_type_t *ctf_find_prefix (ctf_dict_t *, const ctf_type_t *,
@@ -743,7 +742,6 @@ extern ctf_id_t ctf_add_encoded (ctf_dict_t *, uint32_t, const char *,
const ctf_encoding_t *, uint32_t kind);
extern ctf_id_t ctf_add_reftype (ctf_dict_t *, uint32_t, ctf_id_t,
uint32_t kind);
extern int ctf_add_variable_forced (ctf_dict_t *, const char *, ctf_id_t);
extern int ctf_add_funcobjt_sym_forced (ctf_dict_t *, int is_function,
const char *, ctf_id_t);
@@ -815,6 +813,9 @@ extern ctf_id_t ctf_type_resolve_nonrepresentable (ctf_dict_t *, ctf_id_t, int a
extern int ctf_type_kind_unsliced (ctf_dict_t *, ctf_id_t);
extern ssize_t ctf_type_align_natural (ctf_dict_t *fp, ctf_id_t prev_type,
ctf_id_t type, ssize_t bit_offset);
extern ctf_var_secinfo_t *ctf_datasec_entry (ctf_dict_t *, ctf_id_t,
int component_idx);
extern void ctf_datasec_sort (ctf_dict_t *, ctf_dtdef_t *);
_libctf_printflike_ (1, 2)
extern void ctf_dprintf (const char *, ...);