libctf, types: enhance ctf_type_aname to print function arg types

Somehow this never got implemented, which makes debugging any kind of
bug that has to do with argument types fantastically confusing, because
it *looks* like the func type takes no arguments though in fact it does.

This also lets us simplify the dumper slightly (and introduces our first
uses of ctf_assert and ctf_err_warn: there will be many more).

ctf_type_aname dumps function types without including the function
pointer name itself: ctf_dump search-and-replaces it in.  This seems to
give the nicest-looking results for existing users of both, even if it
is a bit fiddly.

libctf/
	* ctf-types.c (ctf_type_aname): Print arg types here...
	* ctf-dump.c (ctf_dump_funcs): ... not here: but do substitute
	in the type name here.
This commit is contained in:
Nick Alcock 2020-06-04 15:25:32 +01:00
parent 8b37e7b63e
commit c6e9a1e576
3 changed files with 94 additions and 55 deletions

View file

@ -1,3 +1,9 @@
2020-07-22 Nick Alcock <nick.alcock@oracle.com>
* ctf-types.c (ctf_type_aname): Print arg types here...
* ctf-dump.c (ctf_dump_funcs): ... not here: but do substitute
in the type name here.
2020-07-22 Nick Alcock <nick.alcock@oracle.com> 2020-07-22 Nick Alcock <nick.alcock@oracle.com>
* ctf-impl.h (ctf_assert): New. * ctf-impl.h (ctf_assert): New.

View file

@ -397,13 +397,11 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
for (i = 0; i < fp->ctf_nsyms; i++) for (i = 0; i < fp->ctf_nsyms; i++)
{ {
char *str; char *str;
char *bit; char *bit = NULL;
const char *err; const char *err;
const char *sym_name; const char *sym_name;
ctf_funcinfo_t fi; ctf_funcinfo_t fi;
ctf_id_t type; ctf_id_t type;
size_t j;
ctf_id_t *args;
if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR) if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR)
switch (ctf_errno (state->cds_fp)) switch (ctf_errno (state->cds_fp))
@ -418,74 +416,65 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
case ECTF_NOFUNCDAT: case ECTF_NOFUNCDAT:
continue; continue;
} }
if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
return (ctf_set_errno (fp, ENOMEM));
/* Return type. */ /* Return type and all args. */
if ((str = ctf_type_aname (state->cds_fp, type)) == NULL) if ((bit = ctf_type_aname (state->cds_fp, type)) == NULL)
{ {
err = "look up return type"; err = "look up return type";
goto err; goto err;
} }
str = str_append (str, " "); /* Replace in the returned string, dropping in the function name. */
/* Function name. */
sym_name = ctf_lookup_symbol_name (fp, i); sym_name = ctf_lookup_symbol_name (fp, i);
if (sym_name[0] == '\0') if (sym_name[0] != '\0')
{ {
if (asprintf (&bit, "0x%lx ", (unsigned long) i) < 0) char *retstar;
char *new_bit;
char *walk;
new_bit = malloc (strlen (bit) + 1 + strlen (sym_name));
if (!new_bit)
goto oom; goto oom;
/* See ctf_type_aname. */
retstar = strstr (bit, "(*) (");
if (!ctf_assert (fp, retstar))
goto assert_err;
retstar += 2; /* After the '*' */
/* C is not good at search-and-replace. */
walk = new_bit;
memcpy (walk, bit, retstar - bit);
walk += (retstar - bit);
strcpy (walk, sym_name);
walk += strlen (sym_name);
strcpy (walk, retstar);
free (bit);
bit = new_bit;
} }
else
{ if (asprintf (&str, "Symbol 0x%lx: %s", (unsigned long) i, bit) < 0)
if (asprintf (&bit, "%s (0x%lx) ", sym_name, (unsigned long) i) < 0)
goto oom; goto oom;
}
str = str_append (str, bit);
str = str_append (str, " (");
free (bit); free (bit);
/* Function arguments. */
if (ctf_func_args (state->cds_fp, i, fi.ctc_argc, args) < 0)
{
err = "look up argument type";
goto err;
}
for (j = 0; j < fi.ctc_argc; j++)
{
if ((bit = ctf_type_aname (state->cds_fp, args[j])) == NULL)
{
err = "look up argument type name";
goto err;
}
str = str_append (str, bit);
if ((j < fi.ctc_argc - 1) || (fi.ctc_flags & CTF_FUNC_VARARG))
str = str_append (str, ", ");
free (bit);
}
if (fi.ctc_flags & CTF_FUNC_VARARG)
str = str_append (str, "...");
str = str_append (str, ")");
free (args);
ctf_dump_append (state, str); ctf_dump_append (state, str);
continue; continue;
oom:
free (args);
free (str);
return (ctf_set_errno (fp, errno));
err: err:
ctf_dprintf ("Cannot %s dumping function type for symbol 0x%li: %s\n", ctf_err_warn (fp, 1, "Cannot %s dumping function type for "
err, (unsigned long) i, "symbol 0x%li: %s", err, (unsigned long) i,
ctf_errmsg (ctf_errno (state->cds_fp))); ctf_errmsg (ctf_errno (state->cds_fp)));
free (args); free (bit);
free (str); return -1; /* errno is set for us. */
oom:
free (bit);
return (ctf_set_errno (fp, errno));
assert_err:
free (bit);
return -1; /* errno is set for us. */ return -1; /* errno is set for us. */
} }
return 0; return 0;

View file

@ -745,7 +745,51 @@ ctf_type_aname (ctf_file_t *fp, ctf_id_t type)
ctf_decl_sprintf (&cd, "[%u]", cdp->cd_n); ctf_decl_sprintf (&cd, "[%u]", cdp->cd_n);
break; break;
case CTF_K_FUNCTION: case CTF_K_FUNCTION:
ctf_decl_sprintf (&cd, "()"); {
size_t i;
ctf_funcinfo_t fi;
ctf_id_t *argv = NULL;
if (ctf_func_type_info (rfp, cdp->cd_type, &fi) < 0)
goto err; /* errno is set for us. */
if ((argv = calloc (fi.ctc_argc, sizeof (ctf_id_t *))) == 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. */
ctf_decl_sprintf (&cd, "(*) (");
for (i = 0; i < fi.ctc_argc; i++)
{
char *arg = ctf_type_aname (rfp, argv[i]);
if (arg == NULL)
goto err; /* errno is set for us. */
ctf_decl_sprintf (&cd, "%s", arg);
free (arg);
if ((i < fi.ctc_argc - 1)
|| (fi.ctc_flags & CTF_FUNC_VARARG))
ctf_decl_sprintf (&cd, ", ");
}
if (fi.ctc_flags & CTF_FUNC_VARARG)
ctf_decl_sprintf (&cd, "...");
ctf_decl_sprintf (&cd, ")");
free (argv);
break;
err:
free (argv);
ctf_decl_fini (&cd);
return NULL;
}
break; break;
case CTF_K_STRUCT: case CTF_K_STRUCT:
case CTF_K_FORWARD: case CTF_K_FORWARD: