gdb/python: print name of unwinder that claimed frame in debug message
authorSimon Marchi <simon.marchi@polymtl.ca>
Tue, 22 Jun 2021 18:16:01 +0000 (14:16 -0400)
committerSimon Marchi <simon.marchi@polymtl.ca>
Tue, 22 Jun 2021 18:47:10 +0000 (14:47 -0400)
If we have multiple registered unwinders, this will helps identify which
unwinder was chosen and make it easier to track down potential problems.
Unwinders have a mandatory name argument, which we can use in the
message.

First, make gdb._execute_unwinders return a tuple containing the name,
in addition to the UnwindInfo.  Then, make pyuw_sniffer include the name
in the debug message.

I moved the debug message earlier.  I think it's good to print it as
early as possible, so that we see it in case an assert is hit in the
loop below, for example.

gdb/ChangeLog:

* python/lib/gdb/__init__.py (_execute_unwinders): Return tuple
with name of chosen unwinder.
* python/py-unwind.c (pyuw_sniffer): Print name of chosen
unwinder in debug message.

Change-Id: Id603545b44a97df2a39dd1872fe1f38ad5059f03

gdb/ChangeLog
gdb/python/lib/gdb/__init__.py
gdb/python/py-unwind.c

index d9e0a3a4f4da860f61529c2572e34eeb8e003db3..995c8a1a3756aedc5cd55e83d78dbafc34cb43ea 100644 (file)
@@ -1,3 +1,10 @@
+2021-06-22  Simon Marchi  <simon.marchi@polymtl.ca>
+
+       * python/lib/gdb/__init__.py (_execute_unwinders): Return tuple
+       with name of chosen unwinder.
+       * python/py-unwind.c (pyuw_sniffer): Print name of chosen
+       unwinder in debug message.
+
 2021-06-22  Andreas Schwab  <schwab@suse.de>
 
        PR symtab/27999
index d748b3a5827e7842e970afe6c730c781b633a76e..f2f38b32af9604886919d9943fc0d3c389e3a0c0 100644 (file)
@@ -90,27 +90,33 @@ def _execute_unwinders(pending_frame):
 
     Arguments:
         pending_frame: gdb.PendingFrame instance.
+
     Returns:
-        gdb.UnwindInfo instance or None.
+        Tuple with:
+
+         [0] gdb.UnwindInfo instance
+         [1] Name of unwinder that claimed the frame (type `str`)
+
+       or None, if no unwinder has claimed the frame.
     """
     for objfile in objfiles():
         for unwinder in objfile.frame_unwinders:
             if unwinder.enabled:
                 unwind_info = unwinder(pending_frame)
                 if unwind_info is not None:
-                    return unwind_info
+                    return (unwind_info, unwinder.name)
 
     for unwinder in current_progspace().frame_unwinders:
         if unwinder.enabled:
             unwind_info = unwinder(pending_frame)
             if unwind_info is not None:
-                return unwind_info
+                return (unwind_info, unwinder.name)
 
     for unwinder in frame_unwinders:
         if unwinder.enabled:
             unwind_info = unwinder(pending_frame)
             if unwind_info is not None:
-                return unwind_info
+                return (unwind_info, unwinder.name)
 
     return None
 
index d3ef1911ab8204d74e180e889590706a10696e62..18ea2434f87e63e495f7a403800c8e6346f06d8e 100644 (file)
@@ -556,33 +556,56 @@ pyuw_sniffer (const struct frame_unwind *self, struct frame_info *this_frame,
     }
   gdbpy_ref<> pyo_execute (PyObject_GetAttrString (gdb_python_module,
                                                   "_execute_unwinders"));
-  if (pyo_execute == NULL)
+  if (pyo_execute == nullptr)
     {
       gdbpy_print_stack ();
       return 0;
     }
 
-  gdbpy_ref<> pyo_unwind_info
+  /* A (gdb.UnwindInfo, str) tuple, or None.  */
+  gdbpy_ref<> pyo_execute_ret
     (PyObject_CallFunctionObjArgs (pyo_execute.get (),
                                   pyo_pending_frame.get (), NULL));
-  if (pyo_unwind_info == NULL)
+  if (pyo_execute_ret == nullptr)
     {
       /* If the unwinder is cancelled due to a Ctrl-C, then propagate
         the Ctrl-C as a GDB exception instead of swallowing it.  */
       gdbpy_print_stack_or_quit ();
       return 0;
     }
-  if (pyo_unwind_info == Py_None)
+  if (pyo_execute_ret == Py_None)
     return 0;
 
+  /* Verify the return value of _execute_unwinders is a tuple of size 2.  */
+  gdb_assert (PyTuple_Check (pyo_execute_ret.get ()));
+  gdb_assert (PyTuple_GET_SIZE (pyo_execute_ret.get ()) == 2);
+
+  if (pyuw_debug)
+    {
+      PyObject *pyo_unwinder_name = PyTuple_GET_ITEM (pyo_execute_ret.get (), 1);
+      gdb::unique_xmalloc_ptr<char> name
+       = python_string_to_host_string (pyo_unwinder_name);
+
+      /* This could happen if the user passed something else than a string
+        as the unwinder's name.  */
+      if (name == nullptr)
+       {
+         gdbpy_print_stack ();
+         name = make_unique_xstrdup ("<failed to get unwinder name>");
+       }
+
+      pyuw_debug_printf ("frame claimed by unwinder %s", name.get ());
+    }
+
   /* Received UnwindInfo, cache data.  */
-  if (PyObject_IsInstance (pyo_unwind_info.get (),
+  PyObject *pyo_unwind_info = PyTuple_GET_ITEM (pyo_execute_ret.get (), 0);
+  if (PyObject_IsInstance (pyo_unwind_info,
                           (PyObject *) &unwind_info_object_type) <= 0)
     error (_("A Unwinder should return gdb.UnwindInfo instance."));
 
   {
     unwind_info_object *unwind_info =
-      (unwind_info_object *) pyo_unwind_info.get ();
+      (unwind_info_object *) pyo_unwind_info;
     int reg_count = unwind_info->saved_regs->size ();
 
     cached_frame
@@ -613,7 +636,6 @@ pyuw_sniffer (const struct frame_unwind *self, struct frame_info *this_frame,
   }
 
   *cache_ptr = cached_frame;
-  pyuw_debug_printf ("frame claimed");
   return 1;
 }