[33/59] libctf, types: enhance ctf_type_aname to print function arg types

Message ID 20200630233146.338613-34-nick.alcock@oracle.com
State New
Headers show
Series
  • Deduplicating CTF linker
Related show

Commit Message

H.J. Lu via Binutils June 30, 2020, 11:31 p.m.
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/ctf-dump.c  | 87 ++++++++++++++++++++--------------------------
 libctf/ctf-types.c | 46 +++++++++++++++++++++++-
 2 files changed, 83 insertions(+), 50 deletions(-)

-- 
2.27.0.247.g3dff7de930

Patch

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: