From c6e9a1e576ce4d948393b29e77b37e4ad934ee8f Mon Sep 17 00:00:00 2001 From: Nick Alcock Date: Thu, 4 Jun 2020 15:25:32 +0100 Subject: [PATCH] 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. --- libctf/ChangeLog | 6 ++++ libctf/ctf-dump.c | 87 ++++++++++++++++++++-------------------------- libctf/ctf-types.c | 46 +++++++++++++++++++++++- 3 files changed, 89 insertions(+), 50 deletions(-) diff --git a/libctf/ChangeLog b/libctf/ChangeLog index 114d4e6c9a0..288ad6e554d 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,3 +1,9 @@ +2020-07-22 Nick Alcock + + * 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 * ctf-impl.h (ctf_assert): New. diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c index b8a81bc1ccf..08d79f36d83 100644 --- a/libctf/ctf-dump.c +++ b/libctf/ctf-dump.c @@ -397,13 +397,11 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state) for (i = 0; i < fp->ctf_nsyms; i++) { char *str; - char *bit; + char *bit = NULL; const char *err; const char *sym_name; ctf_funcinfo_t fi; ctf_id_t type; - size_t j; - ctf_id_t *args; if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR) 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: continue; } - if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL) - return (ctf_set_errno (fp, ENOMEM)); - /* Return type. */ - if ((str = ctf_type_aname (state->cds_fp, type)) == NULL) + /* Return type and all args. */ + if ((bit = ctf_type_aname (state->cds_fp, type)) == NULL) { err = "look up return type"; goto err; } - str = str_append (str, " "); - - /* Function name. */ + /* Replace in the returned string, dropping in the function name. */ 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) - goto oom; - } - else - { - if (asprintf (&bit, "%s (0x%lx) ", sym_name, (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; - } - str = str_append (str, bit); - str = str_append (str, " ("); - free (bit); - /* Function arguments. */ + /* See ctf_type_aname. */ + retstar = strstr (bit, "(*) ("); + if (!ctf_assert (fp, retstar)) + goto assert_err; + retstar += 2; /* After the '*' */ - if (ctf_func_args (state->cds_fp, i, fi.ctc_argc, args) < 0) - { - err = "look up argument type"; - goto err; - } + /* 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); - 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); + bit = new_bit; } - if (fi.ctc_flags & CTF_FUNC_VARARG) - str = str_append (str, "..."); - str = str_append (str, ")"); + if (asprintf (&str, "Symbol 0x%lx: %s", (unsigned long) i, bit) < 0) + goto oom; + free (bit); - free (args); ctf_dump_append (state, str); continue; + err: + ctf_err_warn (fp, 1, "Cannot %s dumping function type for " + "symbol 0x%li: %s", err, (unsigned long) i, + ctf_errmsg (ctf_errno (state->cds_fp))); + free (bit); + return -1; /* errno is set for us. */ + oom: - free (args); - free (str); + free (bit); return (ctf_set_errno (fp, errno)); - err: - ctf_dprintf ("Cannot %s dumping function type for symbol 0x%li: %s\n", - err, (unsigned long) i, - ctf_errmsg (ctf_errno (state->cds_fp))); - free (args); - free (str); + + assert_err: + free (bit); return -1; /* errno is set for us. */ } return 0; diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c index 550068250fd..ddcca66a282 100644 --- a/libctf/ctf-types.c +++ b/libctf/ctf-types.c @@ -745,7 +745,51 @@ ctf_type_aname (ctf_file_t *fp, ctf_id_t type) ctf_decl_sprintf (&cd, "[%u]", cdp->cd_n); break; 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; case CTF_K_STRUCT: case CTF_K_FORWARD: -- 2.30.2