libbacktrace: use ELF symbol table if no debug info available
authorIan Lance Taylor <iant@golang.org>
Thu, 17 Sep 2020 00:03:52 +0000 (17:03 -0700)
committerIan Lance Taylor <iant@golang.org>
Thu, 17 Sep 2020 00:04:43 +0000 (17:04 -0700)
PR libbacktrace/97080
* fileline.c (backtrace_syminfo_to_full_callback): New function.
(backtrace_syminfo_to_full_error_callback): New function.
* elf.c (elf_nodebug): Call syminfo_fn if possible.
* internal.h (struct backtrace_call_full): Define.
(backtrace_syminfo_to_full_callback): Declare.
(backtrace_syminfo_to_full_error_callback): Declare.
* mtest.c (f3): Only check all[i] if data.index permits.

libbacktrace/elf.c
libbacktrace/fileline.c
libbacktrace/internal.h
libbacktrace/mtest.c

index dd00470824687774e4118e4c0d08e279682c7357..941f820d944c76ec349a597ce32bf7fa7acb4693 100644 (file)
@@ -547,18 +547,6 @@ elf_crc32_file (struct backtrace_state *state, int descriptor,
   return ret;
 }
 
-/* A dummy callback function used when we can't find any debug info.  */
-
-static int
-elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
-            uintptr_t pc ATTRIBUTE_UNUSED,
-            backtrace_full_callback callback ATTRIBUTE_UNUSED,
-            backtrace_error_callback error_callback, void *data)
-{
-  error_callback (data, "no debug info in ELF executable", -1);
-  return 0;
-}
-
 /* A dummy callback function used when we can't find a symbol
    table.  */
 
@@ -571,6 +559,33 @@ elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
   error_callback (data, "no symbol table in ELF executable", -1);
 }
 
+/* A callback function used when we can't find any debug info.  */
+
+static int
+elf_nodebug (struct backtrace_state *state, uintptr_t pc,
+            backtrace_full_callback callback,
+            backtrace_error_callback error_callback, void *data)
+{
+  if (state->syminfo_fn != NULL && state->syminfo_fn != elf_nosyms)
+    {
+      struct backtrace_call_full bdata;
+
+      /* Fetch symbol information so that we can least get the
+        function name.  */
+
+      bdata.full_callback = callback;
+      bdata.full_error_callback = error_callback;
+      bdata.full_data = data;
+      bdata.ret = 0;
+      state->syminfo_fn (state, pc, backtrace_syminfo_to_full_callback,
+                        backtrace_syminfo_to_full_error_callback, &bdata);
+      return bdata.ret;
+    }
+
+  error_callback (data, "no debug info in ELF executable", -1);
+  return 0;
+}
+
 /* Compare struct elf_symbol for qsort.  */
 
 static int
index be62b9899c5a7e8a889c781ecbd7e1680f44034d..cd1e10dd58cca26c0b2a1dc4b7e3986559e1a8df 100644 (file)
@@ -317,3 +317,30 @@ backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
   state->syminfo_fn (state, pc, callback, error_callback, data);
   return 1;
 }
+
+/* A backtrace_syminfo_callback that can call into a
+   backtrace_full_callback, used when we have a symbol table but no
+   debug info.  */
+
+void
+backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
+                                   const char *symname,
+                                   uintptr_t symval ATTRIBUTE_UNUSED,
+                                   uintptr_t symsize ATTRIBUTE_UNUSED)
+{
+  struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
+
+  bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, symname);
+}
+
+/* An error callback that corresponds to
+   backtrace_syminfo_to_full_callback.  */
+
+void
+backtrace_syminfo_to_full_error_callback (void *data, const char *msg,
+                                         int errnum)
+{
+  struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
+
+  bdata->full_error_callback (bdata->full_data, msg, errnum);
+}
index 098623374560458475c57efe00799ebdf0d85508..047a700c0ce469ad241d321864a80b95e5793769 100644 (file)
@@ -326,6 +326,31 @@ extern int backtrace_dwarf_add (struct backtrace_state *state,
                                void *data, fileline *fileline_fn,
                                struct dwarf_data **fileline_entry);
 
+/* A data structure to pass to backtrace_syminfo_to_full.  */
+
+struct backtrace_call_full
+{
+  backtrace_full_callback full_callback;
+  backtrace_error_callback full_error_callback;
+  void *full_data;
+  int ret;
+};
+
+/* A backtrace_syminfo_callback that can call into a
+   backtrace_full_callback, used when we have a symbol table but no
+   debug info.  */
+
+extern void backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
+                                               const char *symname,
+                                               uintptr_t symval,
+                                               uintptr_t symsize);
+
+/* An error callback that corresponds to
+   backtrace_syminfo_to_full_callback.  */
+
+extern void backtrace_syminfo_to_full_error_callback (void *, const char *,
+                                                     int);
+
 /* A test-only hook for elf_uncompress_zdebug.  */
 
 extern int backtrace_uncompress_zdebug (struct backtrace_state *,
index d90fd1e33cc36ba64c5885c262263fb41f16eea3..d73c98d44f8ea4e314405edc1853160e3b00e0cb 100644 (file)
@@ -156,40 +156,49 @@ f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
        }
     }
 
-  if (all[0].function == NULL)
+  if (data.index > 0)
     {
-      fprintf (stderr, "test1: [0]: missing function name\n");
-      data.failed = 1;
-    }
-  else if (strcmp (all[0].function, "f3") != 0)
-    {
-      fprintf (stderr, "test1: [0]: got %s expected %s\n",
-              all[0].function, "f3");
-      data.failed = 1;
+      if (all[0].function == NULL)
+       {
+         fprintf (stderr, "test1: [0]: missing function name\n");
+         data.failed = 1;
+       }
+      else if (strcmp (all[0].function, "f3") != 0)
+       {
+         fprintf (stderr, "test1: [0]: got %s expected %s\n",
+                  all[0].function, "f3");
+         data.failed = 1;
+       }
     }
 
-  if (all[1].function == NULL)
-    {
-      fprintf (stderr, "test1: [1]: missing function name\n");
-      data.failed = 1;
-    }
-  else if (strcmp (all[1].function, "f2") != 0)
+  if (data.index > 1)
     {
-      fprintf (stderr, "test1: [1]: got %s expected %s\n",
-              all[0].function, "f2");
-      data.failed = 1;
+      if (all[1].function == NULL)
+       {
+         fprintf (stderr, "test1: [1]: missing function name\n");
+         data.failed = 1;
+       }
+      else if (strcmp (all[1].function, "f2") != 0)
+       {
+         fprintf (stderr, "test1: [1]: got %s expected %s\n",
+                  all[0].function, "f2");
+         data.failed = 1;
+       }
     }
 
-  if (all[2].function == NULL)
-    {
-      fprintf (stderr, "test1: [2]: missing function name\n");
-      data.failed = 1;
-    }
-  else if (strcmp (all[2].function, "test1") != 0)
+  if (data.index > 2)
     {
-      fprintf (stderr, "test1: [2]: got %s expected %s\n",
-              all[0].function, "test1");
-      data.failed = 1;
+      if (all[2].function == NULL)
+       {
+         fprintf (stderr, "test1: [2]: missing function name\n");
+         data.failed = 1;
+       }
+      else if (strcmp (all[2].function, "test1") != 0)
+       {
+         fprintf (stderr, "test1: [2]: got %s expected %s\n",
+                  all[0].function, "test1");
+         data.failed = 1;
+       }
     }
 
   printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");