typedef struct ctf_funcinfo
{
ctf_id_t ctc_return; /* Function return type. */
- uint32_t ctc_argc; /* Number of typed arguments to function. */
+ size_t ctc_argc; /* Number of typed arguments to function. */
uint32_t ctc_flags; /* Function attributes (see below). */
} ctf_funcinfo_t;
_CTF_ITEM (ECTF_NOTBITSOU, "Type is not a bitfield-capable struct or union.") \
_CTF_ITEM (ECTF_DESCENDING, "Structure offsets may not descend.") \
_CTF_ITEM (ECTF_LINKAGE, "Invalid linkage.") \
+ _CTF_ITEM (ECTF_LINKKIND, "Only functions and variables have linkage.") \
_CTF_ITEM (ECTF_NOTDATASEC, "This function requires a datasec.") \
_CTF_ITEM (ECTF_NOTVAR, "This function requires a variable.") \
_CTF_ITEM (ECTF_NODATASEC, "Variable not found in datasec.") \
extern int ctf_version (int);
/* Given a symbol table index corresponding to a function symbol, return info on
- the type of a given function's arguments or return value. Vararg functions
- have a final arg with CTF_FUNC_VARARG on in ctc_flags. */
+ the type of a given function's arguments or return value, or its parameter
+ names. Vararg functions have a final arg with CTF_FUNC_VARARG on in
+ ctc_flags. */
extern int ctf_func_info (ctf_dict_t *, unsigned long, ctf_funcinfo_t *);
extern int ctf_func_args (ctf_dict_t *, unsigned long, uint32_t, ctf_id_t *);
+extern int ctf_func_arg_names (ctf_dict_t *, unsigned long, uint32_t, const char **);
-/* As above, but for CTF_K_FUNCTION types in CTF dicts. */
+/* As above, but for CTF_K_FUNCTION or CTF_K_FUNC_LINKAGE types in CTF dicts. */
extern int ctf_func_type_info (ctf_dict_t *, ctf_id_t, ctf_funcinfo_t *);
extern int ctf_func_type_args (ctf_dict_t *, ctf_id_t, uint32_t, ctf_id_t *);
+extern int ctf_func_type_arg_names (ctf_dict_t *, ctf_id_t, uint32_t,
+ const char **);
+
+/* Get the linkage of a CTF_K_FUNC_LINKAGE or variable. */
+
+extern int ctf_type_linkage (ctf_dict_t *, ctf_id_t);
/* Look up function or data symbols by name and return their CTF type ID,
if any. (For both function symbols and data symbols that are function
const char *, const ctf_encoding_t *);
extern ctf_id_t ctf_add_forward (ctf_dict_t *, uint32_t, const char *,
uint32_t);
-extern ctf_id_t ctf_add_function (ctf_dict_t *, uint32_t,
- const ctf_funcinfo_t *, const ctf_id_t *);
extern ctf_id_t ctf_add_integer (ctf_dict_t *, uint32_t, const char *,
const ctf_encoding_t *);
+/* ctf_add_function adds an unnamed function with a bundle of arguments and a
+ return type. ctf_add_function_linkage provides a function with a name
+ and linkage, which is one of the CTF_FUNC_LINKAGE_* constants. */
+extern ctf_id_t ctf_add_function (ctf_dict_t *, uint32_t,
+ const ctf_funcinfo_t *, const ctf_id_t *,
+ const char **arg_names);
+extern ctf_id_t ctf_add_function_linkage (ctf_dict_t *, uint32_t,
+ ctf_id_t, const char *, int linkage);
+
/* Add a "slice", which wraps some integral type and changes its encoding
(useful for bitfields, etc). In most respects slices are treated the same
kind as the type they wrap: only ctf_type_reference can see the difference,
ctf_id_t
ctf_add_function (ctf_dict_t *fp, uint32_t flag,
- const ctf_funcinfo_t *ctc, const ctf_id_t *argv)
+ const ctf_funcinfo_t *ctc, const ctf_id_t *argv,
+ const char **arg_names)
{
ctf_dtdef_t *dtd;
- ctf_id_t type;
uint32_t vlen;
- uint32_t *vdat;
+ ctf_param_t *vdat;
ctf_dict_t *tmp = fp;
- size_t initial_vbytes;
size_t i;
if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
return (ctf_set_typed_errno (fp, EINVAL));
vlen = ctc->ctc_argc;
+
+ /* UPTODO: CTF_K_BIG prefix for big functions? */
+ if (vlen > 0xffff)
+ return (ctf_set_typed_errno (fp, EOVERFLOW));
+
if (ctc->ctc_flags & CTF_FUNC_VARARG)
vlen++; /* Add trailing zero to indicate varargs (see below). */
if (ctc->ctc_return != 0
- && ctf_lookup_by_id (&tmp, ctc->ctc_return) == NULL)
+ && ctf_lookup_by_id (&tmp, ctc->ctc_return, NULL) == NULL)
return CTF_ERR; /* errno is set for us. */
+ for (i = 0; i < ctc->ctc_argc; i++)
+ {
+ tmp = fp;
+ if (argv[i] != 0 && ctf_lookup_by_id (&tmp, argv[i], NULL) == NULL)
+ return CTF_ERR; /* errno is set for us. */
+ }
+
if (vlen > CTF_MAX_VLEN)
return (ctf_set_typed_errno (fp, EOVERFLOW));
- /* One word extra allocated for padding for 4-byte alignment if need be.
- Not reflected in vlen: we don't want to copy anything into it, and
- it's in addition to (e.g.) the trailing 0 indicating varargs. */
-
- initial_vbytes = (sizeof (uint32_t) * (vlen + (vlen & 1)));
- if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION,
- initial_vbytes, &dtd)) == CTF_ERR)
+ if ((dtd = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION, 0,
+ sizeof (ctf_param_t) * vlen, 0, NULL)) == NULL)
return CTF_ERR; /* errno is set for us. */
- vdat = (uint32_t *) dtd->dtd_vlen;
+ vdat = (ctf_param_t *) dtd->dtd_vlen;
for (i = 0; i < ctc->ctc_argc; i++)
{
- tmp = fp;
- if (argv[i] != 0 && ctf_lookup_by_id (&tmp, argv[i]) == NULL)
- return CTF_ERR; /* errno is set for us. */
- vdat[i] = (uint32_t) argv[i];
+ vdat[i].cfp_name = ctf_str_add (fp, arg_names[i]);
+ vdat[i].cfp_type = (uint32_t) argv[i];
}
- dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
- dtd->dtd_data.ctt_type = (uint32_t) ctc->ctc_return;
+ dtd->dtd_data->ctt_info = CTF_TYPE_INFO (CTF_K_FUNCTION, 0, vlen);
+ dtd->dtd_data->ctt_type = (uint32_t) ctc->ctc_return;
if (ctc->ctc_flags & CTF_FUNC_VARARG)
- vdat[vlen - 1] = 0; /* Add trailing zero to indicate varargs. */
+ {
+ vdat[vlen - 1].cfp_type = 0; /* Add trailing zero to indicate varargs. */
+ vdat[vlen - 1].cfp_name = 0;
+ }
+
+ return dtd->dtd_type;
+}
+
+ctf_id_t
+ctf_add_function_linkage (ctf_dict_t *fp, uint32_t flag,
+ ctf_id_t ref, const char *name, int linkage)
+{
+ ctf_dtdef_t *dtd;
+ ctf_dict_t *tmp = fp;
+
+ if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
+ return (ctf_set_typed_errno (fp, EINVAL));
+
+ if (linkage < 0 || linkage > 2)
+ return (ctf_set_typed_errno (fp, ECTF_LINKAGE));
+
+ if (ref != 0 && ctf_lookup_by_id (&tmp, ref, NULL) == NULL)
+ return CTF_ERR; /* errno is set for us. */
+
+ if (ctf_type_kind (fp, ref) != CTF_K_FUNCTION)
+ return (ctf_set_typed_errno (fp, ECTF_NOTFUNC));
+
+ if ((dtd = ctf_add_generic (fp, flag, name, CTF_K_FUNC_LINKAGE, 0,
+ 0, 0, NULL)) == NULL)
+ return CTF_ERR; /* errno is set for us. */
+
+ dtd->dtd_data->ctt_info = CTF_TYPE_INFO (CTF_K_FUNC_LINKAGE, 0, linkage);
+ dtd->dtd_data->ctt_type = (uint32_t) ref;
return dtd->dtd_type;
}
if (fp->ctf_flags & LCTF_NO_TYPE)
return (ctf_set_errno (fp, ECTF_NOTSERIALIZED));
- if (ctf_lookup_by_id (&tmp, id) == NULL)
+ if (ctf_lookup_by_id (&tmp, id, NULL) == NULL)
return -1; /* errno is set for us. */
if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
ctf_encoding_t src_en, dst_en;
ctf_arinfo_t src_ar, dst_ar;
- ctf_funcinfo_t ctc;
-
ctf_id_t orig_src_type = src_type;
if ((src_prefix = ctf_lookup_by_id (&src_fp, src_type, &src_tp)) == NULL)
dst_type = ctf_add_array (dst_fp, flag, &src_ar);
break;
+ /* UPTODO: FUNC_LINKAGE, DATASEC, VAR, *TAG */
case CTF_K_FUNCTION:
- ctc.ctc_return = ctf_add_type_internal (dst_fp, src_fp,
- src_tp->ctt_type,
- proc_tracking_fp);
- ctc.ctc_argc = 0;
- ctc.ctc_flags = 0;
+ {
+ ctf_funcinfo_t fi;
+ ctf_id_t *argv;
+ const char **arg_names;
+ size_t i;
- if (ctc.ctc_return == CTF_ERR)
- return CTF_ERR; /* errno is set for us. */
+ if (ctf_func_type_info (src_fp, src_type, &fi) < 0)
+ return CTF_ERR; /* errno is set for us. */
- dst_type = ctf_add_function (dst_fp, flag, &ctc, NULL);
- break;
+ fi.ctc_return = ctf_add_type_internal (dst_fp, src_fp,
+ src_tp->ctt_type,
+ proc_tracking_fp);
+
+ if (fi.ctc_return == CTF_ERR)
+ return CTF_ERR; /* errno is set for us. */
+
+ if ((argv = calloc (fi.ctc_argc, sizeof (ctf_id_t *))) == NULL)
+ {
+ ctf_set_errno (src_fp, errno);
+ return CTF_ERR;
+ }
+
+ if (ctf_func_type_args (src_fp, src_type, fi.ctc_argc, argv) < 0)
+ {
+ free (argv);
+ return CTF_ERR; /* errno is set for us. */
+ }
+
+ for (i = 0; i < fi.ctc_argc; i++)
+ {
+ argv[i] = ctf_add_type_internal (dst_fp, src_fp,
+ argv[i],
+ proc_tracking_fp);
+ if (argv[i] == CTF_ERR)
+ {
+ free (argv);
+ return CTF_ERR; /* errno is set for us. */
+ }
+ }
+
+ if ((arg_names = calloc (fi.ctc_argc, sizeof (const char **))) == NULL)
+ {
+ free (argv);
+ free (arg_names);
+ return CTF_ERR; /* errno is set for us. */
+ }
+
+ if (ctf_func_type_arg_names (src_fp, src_type, fi.ctc_argc,
+ arg_names) < 0)
+ {
+ free (argv);
+ free (arg_names);
+ return CTF_ERR; /* errno is set for us. */
+ }
+
+ dst_type = ctf_add_function (dst_fp, flag, &fi, argv, arg_names);
+ free (argv);
+ free (arg_names);
+ break;
+ }
case CTF_K_STRUCT:
case CTF_K_UNION:
prec = CTF_PREC_BASE;
break;
+ case CTF_K_FUNC_LINKAGE:
+ ctf_decl_push (cd, fp, suffix->ctt_type);
+ prec = CTF_PREC_FUNCTION;
+ break;
+
case CTF_K_FUNCTION:
ctf_decl_push (cd, fp, suffix->ctt_type);
prec = CTF_PREC_FUNCTION;
return ctf_func_type_args (fp, type, argc, argv);
}
+
+/* Given a symbol table index, return the argument names for the function
+ described by the corresponding entry in the symbol table. */
+
+int
+ctf_func_arg_names (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
+ const char **arg_names)
+{
+ ctf_id_t type;
+
+ if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
+ return -1; /* errno is set for us. */
+
+ if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
+ return (ctf_set_errno (fp, ECTF_NOTFUNC));
+
+ return ctf_func_type_arg_names (fp, type, argc, arg_names);
+}
size_t i;
ctf_funcinfo_t fi;
ctf_id_t *argv = NULL;
+ const char **arg_names = NULL;
if (ctf_func_type_info (rfp, cdp->cd_type, &fi) < 0)
goto err; /* errno is set for us. */
goto err;
}
+ if ((arg_names = calloc (fi.ctc_argc, sizeof (const char *))) == NULL)
+ {
+ ctf_set_errno (rfp, errno);
+ goto err;
+ }
+
if (ctf_func_type_args (rfp, cdp->cd_type,
fi.ctc_argc, argv) < 0)
goto err; /* errno is set for us. */
+ if (ctf_func_type_arg_names (rfp, cdp->cd_type,
+ fi.ctc_argc, arg_names) < 0)
+ goto err; /* errno is set for us. */
+
ctf_decl_sprintf (&cd, "(*) (");
for (i = 0; i < fi.ctc_argc; i++)
{
if (arg == NULL)
goto err; /* errno is set for us. */
- ctf_decl_sprintf (&cd, "%s", arg);
+ ctf_decl_sprintf (&cd, "%s%s%s", arg, arg_names[i] != 0 ?
+ " ":"", arg_names[i] != 0
+ ? arg_names[i] : "");
free (arg);
if ((i < fi.ctc_argc - 1)
err:
ctf_set_errno (fp, ctf_errno (rfp));
free (argv);
+ free (arg_names);
ctf_decl_fini (&cd);
return NULL;
}
case CTF_K_ENUM64:
ctf_decl_sprintf (&cd, "enum %s", name);
break;
+ case CTF_K_FUNC_LINKAGE:
+ case CTF_K_VAR:
+ {
+ int linkage;
+ if ((linkage = ctf_type_linkage (fp, cdp->cd_type)) < 0)
+ {
+ ctf_set_errno (fp, ECTF_CORRUPT);
+ ctf_decl_fini (&cd);
+ return NULL;
+ }
+
+ ctf_decl_sprintf (&cd, "%s%s", linkage == 0 ? "static "
+ : (linkage == 2 ? "extern " :
+ (linkage == 1 ? "" : "(invalid linkage) ")),
+ name);
+ break;
+ }
case CTF_K_FORWARD:
{
switch (ctf_type_kind_forwarded (fp, cdp->cd_type))
if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
return -1; /* errno is set for us. */
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+ if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
return -1; /* errno is set for us. */
- switch (LCTF_INFO_KIND (fp, tp->ctt_info))
+ switch (LCTF_KIND (fp, tp))
{
case CTF_K_POINTER:
return fp->ctf_dmodel->ctd_pointer;
case CTF_K_FUNCTION:
- return 0; /* Function size is only known by symtab. */
-
+ case CTF_K_FUNC_LINKAGE:
+ return 0; /* Function size is only known by symtab. */
case CTF_K_ARRAY:
/* ctf_add_array() does not directly encode the element size, but
if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
return -1; /* errno is set for us. */
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+ if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
return -1; /* errno is set for us. */
- kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+ kind = LCTF_KIND (fp, tp);
switch (kind)
{
case CTF_K_POINTER:
case CTF_K_FUNCTION:
+ case CTF_K_FUNC_LINKAGE:
return fp->ctf_dmodel->ctd_pointer;
case CTF_K_ARRAY:
ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
{
ctf_dict_t *ofp = fp;
- const ctf_type_t *tp;
+ const ctf_type_t *tp, *suffix;
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+ if ((tp = ctf_lookup_by_id (&fp, type, &suffix)) == NULL)
return CTF_ERR; /* errno is set for us. */
- switch (LCTF_INFO_KIND (fp, tp->ctt_info))
+ switch (LCTF_KIND (fp, tp))
{
case CTF_K_POINTER:
case CTF_K_TYPEDEF:
case CTF_K_VOLATILE:
case CTF_K_CONST:
case CTF_K_RESTRICT:
- return tp->ctt_type;
+ case CTF_K_FUNCTION:
+ case CTF_K_FUNC_LINKAGE:
+ case CTF_K_VAR:
+ return suffix->ctt_type;
/* Slices store their type in an unusual place. */
case CTF_K_SLICE:
{
ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
{
ctf_dict_t *ofp = fp;
- const ctf_type_t *tp;
+ const ctf_type_t *tp, *suffix;
uint32_t kind;
- const uint32_t *args;
- const ctf_dtdef_t *dtd;
- ssize_t size, increment;
+ unsigned char *vlen;
+ const ctf_param_t *args;
if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
return -1; /* errno is set for us. */
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
- return -1; /* errno is set for us. */
+ if (ctf_type_kind (fp, type) == CTF_K_FUNC_LINKAGE)
+ type = ctf_type_reference (fp, type);
- (void) ctf_get_ctt_size (fp, tp, &size, &increment);
- kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+ if ((tp = ctf_lookup_by_id (&fp, type, &suffix)) == NULL)
+ return -1; /* errno is set for us. */
+ kind = LCTF_KIND (fp, tp);
if (kind != CTF_K_FUNCTION)
return (ctf_set_errno (ofp, ECTF_NOTFUNC));
- fip->ctc_return = tp->ctt_type;
+ fip->ctc_return = suffix->ctt_type;
fip->ctc_flags = 0;
- fip->ctc_argc = LCTF_INFO_VLEN (fp, tp->ctt_info);
- if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
- args = (uint32_t *) ((uintptr_t) tp + increment);
- else
- args = (uint32_t *) dtd->dtd_vlen;
+ vlen = ctf_vlen (fp, type, tp, &fip->ctc_argc);
+ args = (const ctf_param_t *) vlen;
- if (fip->ctc_argc != 0 && args[fip->ctc_argc - 1] == 0)
+ if (fip->ctc_argc != 0 && args[fip->ctc_argc - 1].cfp_type == 0)
{
fip->ctc_flags |= CTF_FUNC_VARARG;
fip->ctc_argc--;
ctf_func_type_args (ctf_dict_t *fp, ctf_id_t type, uint32_t argc, ctf_id_t *argv)
{
const ctf_type_t *tp;
- const uint32_t *args;
- const ctf_dtdef_t *dtd;
- ssize_t size, increment;
+ const ctf_param_t *args;
+ unsigned char *vlen;
ctf_funcinfo_t f;
+ if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+ return -1; /* errno is set for us. */
+
+ if (ctf_type_kind (fp, type) == CTF_K_FUNC_LINKAGE)
+ type = ctf_type_reference (fp, type);
+
if (ctf_func_type_info (fp, type, &f) < 0)
return -1; /* errno is set for us. */
+ if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
+ return -1; /* errno is set for us. */
+
+ vlen = ctf_vlen (fp, type, tp, NULL);
+ args = (const ctf_param_t *) vlen;
+
+ for (argc = MIN (argc, f.ctc_argc); argc != 0; argc--)
+ *argv++ = (args++)->cfp_type;
+
+ return 0;
+}
+
+/* Given a type ID relating to a function type, return the argument names for
+ the function. */
+
+int
+ctf_func_type_arg_names (ctf_dict_t *fp, ctf_id_t type, uint32_t argc,
+ const char **arg_names)
+{
+ const ctf_type_t *tp;
+ const ctf_param_t *args;
+ unsigned char *vlen;
+ ctf_funcinfo_t f;
+
if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
return -1; /* errno is set for us. */
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+ if (ctf_type_kind (fp, type) == CTF_K_FUNC_LINKAGE)
+ type = ctf_type_reference (fp, type);
+
+ if (ctf_func_type_info (fp, type, &f) < 0)
return -1; /* errno is set for us. */
- (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+ if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
+ return -1; /* errno is set for us. */
- if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
- args = (uint32_t *) ((uintptr_t) tp + increment);
- else
- args = (uint32_t *) dtd->dtd_vlen;
+ vlen = ctf_vlen (fp, type, tp, NULL);
+ args = (const ctf_param_t *) vlen;
for (argc = MIN (argc, f.ctc_argc); argc != 0; argc--)
- *argv++ = *args++;
+ *arg_names++ = ctf_strptr (fp, (args++)->cfp_name);
return 0;
}
+/* Get the linkage of a CTF_K_FUNC_LINKAGE or variable. */
+
+int
+ctf_type_linkage (ctf_dict_t *fp, ctf_id_t type)
+{
+ const ctf_type_t *tp;
+ const ctf_type_t *suffix;
+ unsigned char *vlen;
+ ctf_linkage_t *l;
+
+ int kind;
+
+ if ((tp = ctf_lookup_by_id (&fp, type, &suffix)) == NULL)
+ return -1; /* errno is set for us. */
+
+ kind = ctf_type_kind_unsliced (fp, type);
+ if (kind != CTF_K_FUNC_LINKAGE && kind != CTF_K_VAR)
+ return ctf_set_errno (fp, ECTF_LINKKIND);
+
+ if (kind == CTF_K_VAR)
+ {
+ vlen = ctf_vlen (fp, type, tp, NULL);
+ l = (ctf_linkage_t *) vlen;
+
+ return l->ctl_linkage;
+ }
+
+ /* CTF_K_FUNC_LINKAGE. */
+ return CTF_INFO_VLEN (suffix->ctt_info);
+}
+
/* bsearch_r comparison function for datasec searches. */
static int
search_datasec_by_offset (const void *key_, const void *arr_)
ctf_func_info;
ctf_func_args;
+ ctf_func_arg_names;
ctf_func_type_info;
ctf_func_type_args;
+ ctf_func_type_arg_names;
ctf_lookup_by_name;
ctf_lookup_by_symbol;
ctf_type_kind;
ctf_type_kind_forwarded;
ctf_type_reference;
+ ctf_type_linkage;
ctf_type_pointer;
ctf_type_encoding;
ctf_type_visit;
ctf_add_btf_float;
ctf_add_forward;
ctf_add_function;
+ ctf_add_function_linkage;
ctf_add_integer;
ctf_add_pointer;
ctf_add_type;