Fix crashes due to python GIL released too early
[deliverable/binutils-gdb.git] / gdb / python / py-finishbreakpoint.c
index b67b1631528a2f459e173dc05f129fb0daefebcd..fc20575aea67863cc7e3ff96316aa58f23a31cd8 100644 (file)
@@ -1,6 +1,6 @@
 /* Python interface to finish breakpoints
 
-   Copyright (C) 2011-2012 Free Software Foundation, Inc.
+   Copyright (C) 2011-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 
 #include "defs.h"
-#include "exceptions.h"
 #include "python-internal.h"
 #include "breakpoint.h"
 #include "frame.h"
 #include "gdbthread.h"
 #include "arch-utils.h"
 #include "language.h"
-#include "observer.h"
+#include "observable.h"
 #include "inferior.h"
-
-static PyTypeObject finish_breakpoint_object_type;
+#include "block.h"
+#include "location.h"
 
 /* Function that is called when a Python finish bp is found out of scope.  */
-static char * const outofscope_func = "out_of_scope";
+static const char outofscope_func[] = "out_of_scope";
 
 /* struct implementing the gdb.FinishBreakpoint object by extending
    the gdb.Breakpoint class.  */
 struct finish_breakpoint_object
 {
   /* gdb.Breakpoint base class.  */
-  breakpoint_object py_bp;
+  gdbpy_breakpoint_object py_bp;
   /* gdb.Type object of the value return by the breakpointed function.
      May be NULL if no debug information was available or return type
      was VOID.  */
   PyObject *return_type;
-  /* gdb.Type object of the function finished by this breakpoint.  Will be
+  /* gdb.Value object of the function finished by this breakpoint.  Will be
      NULL if return_type is NULL.  */
-  PyObject *function_type;
+  PyObject *function_value;
   /* When stopped at this FinishBreakpoint, gdb.Value object returned by
      the function; Py_None if the value is not computable; NULL if GDB is
      not stopped at a FinishBreakpoint.  */
   PyObject *return_value;
 };
 
+extern PyTypeObject finish_breakpoint_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("finish_breakpoint_object");
+
 /* Python function to get the 'return_value' attribute of
    FinishBreakpoint.  */
 
@@ -78,9 +80,10 @@ bpfinishpy_dealloc (PyObject *self)
   struct finish_breakpoint_object *self_bpfinish =
         (struct finish_breakpoint_object *) self;
 
-  Py_XDECREF (self_bpfinish->function_type);
+  Py_XDECREF (self_bpfinish->function_value);
   Py_XDECREF (self_bpfinish->return_type);
   Py_XDECREF (self_bpfinish->return_value);
+  Py_TYPE (self)->tp_free (self);
 }
 
 /* Triggered when gdbpy_should_stop is about to execute the `stop' callback
@@ -88,11 +91,10 @@ bpfinishpy_dealloc (PyObject *self)
    `return_value', if possible.  */
 
 void
-bpfinishpy_pre_stop_hook (struct breakpoint_object *bp_obj)
+bpfinishpy_pre_stop_hook (struct gdbpy_breakpoint_object *bp_obj)
 {
   struct finish_breakpoint_object *self_finishbp =
         (struct finish_breakpoint_object *) bp_obj;
-  volatile struct gdb_exception except;
 
   /* Can compute return_value only once.  */
   gdb_assert (!self_finishbp->return_value);
@@ -100,11 +102,13 @@ bpfinishpy_pre_stop_hook (struct breakpoint_object *bp_obj)
   if (!self_finishbp->return_type)
     return;
 
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  try
     {
-      struct value *ret =
-          get_return_value (type_object_to_type (self_finishbp->function_type),
-                            type_object_to_type (self_finishbp->return_type));
+      struct value *function =
+        value_object_to_value (self_finishbp->function_value);
+      struct type *value_type =
+        type_object_to_type (self_finishbp->return_type);
+      struct value *ret = get_return_value (function, value_type);
 
       if (ret)
         {
@@ -118,7 +122,7 @@ bpfinishpy_pre_stop_hook (struct breakpoint_object *bp_obj)
           self_finishbp->return_value = Py_None;
         }
     }
-  if (except.reason < 0)
+  catch (const gdb_exception &except)
     {
       gdbpy_convert_exception (except);
       gdbpy_print_stack ();
@@ -129,17 +133,16 @@ bpfinishpy_pre_stop_hook (struct breakpoint_object *bp_obj)
    of the gdb.FinishBreakpoint object BP_OBJ.  */
 
 void
-bpfinishpy_post_stop_hook (struct breakpoint_object *bp_obj)
+bpfinishpy_post_stop_hook (struct gdbpy_breakpoint_object *bp_obj)
 {
-  volatile struct gdb_exception except;
 
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  try
     {
       /* Can't delete it here, but it will be removed at the next stop.  */
       disable_breakpoint (bp_obj->bp);
       gdb_assert (bp_obj->bp->disposition == disp_del);
     }
-  if (except.reason < 0)
+  catch (const gdb_exception &except)
     {
       gdbpy_convert_exception (except);
       gdbpy_print_stack ();
@@ -151,81 +154,85 @@ bpfinishpy_post_stop_hook (struct breakpoint_object *bp_obj)
 static int
 bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 {
-  static char *keywords[] = { "frame", "internal", NULL };
+  static const char *keywords[] = { "frame", "internal", NULL };
   struct finish_breakpoint_object *self_bpfinish =
       (struct finish_breakpoint_object *) self;
-  int type = bp_breakpoint;
   PyObject *frame_obj = NULL;
   int thread;
-  struct frame_info *frame, *prev_frame = NULL;
+  struct frame_info *frame = NULL; /* init for gcc -Wall */
+  struct frame_info *prev_frame = NULL;
   struct frame_id frame_id;
   PyObject *internal = NULL;
   int internal_bp = 0;
-  CORE_ADDR finish_pc, pc;
-  volatile struct gdb_exception except;
-  char *addr_str, small_buf[100];
+  CORE_ADDR pc;
   struct symbol *function;
 
-  if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
-                                    &frame_obj, &internal))
+  if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
+                                       &frame_obj, &internal))
     return -1;
 
-  /* Default frame to gdb.newest_frame if necessary.  */
-  if (!frame_obj)
-    frame_obj = gdbpy_newest_frame (NULL, NULL);
-  else
-    Py_INCREF (frame_obj);
-
-  frame = frame_object_to_frame_info (frame_obj);
-  Py_DECREF (frame_obj);
-
-  if (frame == NULL)
-    goto invalid_frame;
-  
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  try
     {
-      prev_frame = get_prev_frame (frame);
-      if (prev_frame == 0)
-        {
-          PyErr_SetString (PyExc_ValueError, _("\"FinishBreakpoint\" not "   \
-                                               "meaningful in the outermost "\
-                                               "frame."));
-        }
-      else if (get_frame_type (prev_frame) == DUMMY_FRAME)
-        {
-          PyErr_SetString (PyExc_ValueError, _("\"FinishBreakpoint\" cannot "\
-                                               "be set on a dummy frame."));
-        }
+      /* Default frame to newest frame if necessary.  */
+      if (frame_obj == NULL)
+       frame = get_current_frame ();
       else
-        {
-          frame_id = get_frame_id (prev_frame);
-          if (frame_id_eq (frame_id, null_frame_id))
-            PyErr_SetString (PyExc_ValueError,
-                             _("Invalid ID for the `frame' object."));
-        }
+       frame = frame_object_to_frame_info (frame_obj);
+
+      if (frame == NULL)
+       {
+         PyErr_SetString (PyExc_ValueError,
+                          _("Invalid ID for the `frame' object."));
+       }
+      else
+       {
+         prev_frame = get_prev_frame (frame);
+         if (prev_frame == 0)
+           {
+             PyErr_SetString (PyExc_ValueError,
+                              _("\"FinishBreakpoint\" not "
+                                "meaningful in the outermost "
+                                "frame."));
+           }
+         else if (get_frame_type (prev_frame) == DUMMY_FRAME)
+           {
+             PyErr_SetString (PyExc_ValueError,
+                              _("\"FinishBreakpoint\" cannot "
+                                "be set on a dummy frame."));
+           }
+         else
+           {
+             frame_id = get_frame_id (prev_frame);
+             if (frame_id_eq (frame_id, null_frame_id))
+               PyErr_SetString (PyExc_ValueError,
+                                _("Invalid ID for the `frame' object."));
+           }
+       }
     }
-  if (except.reason < 0)
+  catch (const gdb_exception &except)
     {
       gdbpy_convert_exception (except);
       return -1;
     }
-  else if (PyErr_Occurred ())
+
+  if (PyErr_Occurred ())
     return -1;
 
-  thread = pid_to_thread_id (inferior_ptid);
-  if (thread == 0)
+  if (inferior_ptid == null_ptid)
     {
       PyErr_SetString (PyExc_ValueError,
                        _("No thread currently selected."));
       return -1;
     }
 
+  thread = inferior_thread ()->global_num;
+
   if (internal)
     {
       internal_bp = PyObject_IsTrue (internal);
-      if (internal_bp == -1) 
+      if (internal_bp == -1)
         {
-          PyErr_SetString (PyExc_ValueError, 
+          PyErr_SetString (PyExc_ValueError,
                            _("The value of `internal' must be a boolean."));
           return -1;
         }
@@ -233,9 +240,9 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 
   /* Find the function we will return from.  */
   self_bpfinish->return_type = NULL;
-  self_bpfinish->function_type = NULL;
+  self_bpfinish->function_value = NULL;
 
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  try
     {
       if (get_frame_pc_if_available (frame, &pc))
         {
@@ -243,45 +250,51 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
           if (function != NULL)
             {
               struct type *ret_type =
-                  TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
+               check_typedef (TYPE_TARGET_TYPE (SYMBOL_TYPE (function)));
 
               /* Remember only non-void return types.  */
               if (TYPE_CODE (ret_type) != TYPE_CODE_VOID)
                 {
+                  struct value *func_value;
+
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  self_bpfinish->function_type =
-                      type_to_type_object (SYMBOL_TYPE (function));
+                  func_value = read_var_value (function, NULL, frame);
+                  self_bpfinish->function_value =
+                      value_to_value_object (func_value);
                   PyErr_Clear ();
                 }
             }
         }
     }
-  if (except.reason < 0
-      || !self_bpfinish->return_type || !self_bpfinish->function_type)
+  catch (const gdb_exception &except)
+    {
+      /* Just swallow.  Either the return type or the function value
+        remain NULL.  */
+    }
+
+  if (self_bpfinish->return_type == NULL || self_bpfinish->function_value == NULL)
     {
       /* Won't be able to compute return value.  */
       Py_XDECREF (self_bpfinish->return_type);
-      Py_XDECREF (self_bpfinish->function_type);
+      Py_XDECREF (self_bpfinish->function_value);
 
       self_bpfinish->return_type = NULL;
-      self_bpfinish->function_type = NULL;
+      self_bpfinish->function_value = NULL;
     }
 
   bppy_pending_object = &self_bpfinish->py_bp;
   bppy_pending_object->number = -1;
   bppy_pending_object->bp = NULL;
 
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  try
     {
       /* Set a breakpoint on the return address.  */
-      finish_pc = get_frame_pc (prev_frame);
-      xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (finish_pc));
-      addr_str = small_buf;
-
+      event_location_up location
+       = new_address_location (get_frame_pc (prev_frame), NULL, 0);
       create_breakpoint (python_gdbarch,
-                         addr_str, NULL, thread,
+                         location.get (), NULL, thread, NULL,
                          0,
                          1 /*temp_flag*/,
                          bp_breakpoint,
@@ -290,20 +303,18 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                          &bkpt_breakpoint_ops,
                          0, 1, internal_bp, 0);
     }
-  GDB_PY_SET_HANDLE_EXCEPTION (except);
-  
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_SET_HANDLE_EXCEPTION (except);
+    }
+
   self_bpfinish->py_bp.bp->frame_id = frame_id;
   self_bpfinish->py_bp.is_finish_bp = 1;
-  
+
   /* Bind the breakpoint with the current program space.  */
   self_bpfinish->py_bp.bp->pspace = current_program_space;
 
   return 0;
-  
- invalid_frame:
-  PyErr_SetString (PyExc_ValueError, 
-                   _("Invalid ID for the `frame' object."));
-  return -1;
 }
 
 /* Called when GDB notices that the finish breakpoint BP_OBJ is out of
@@ -313,15 +324,16 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 static void
 bpfinishpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj)
 {
-  volatile struct gdb_exception except;
-  breakpoint_object *bp_obj = (breakpoint_object *) bpfinish_obj;
+  gdbpy_breakpoint_object *bp_obj = (gdbpy_breakpoint_object *) bpfinish_obj;
   PyObject *py_obj = (PyObject *) bp_obj;
 
   if (bpfinish_obj->py_bp.bp->enable_state == bp_enabled
       && PyObject_HasAttrString (py_obj, outofscope_func))
     {
-      if (!PyObject_CallMethod (py_obj, outofscope_func, NULL))
-          gdbpy_print_stack ();
+      gdbpy_ref<> meth_result (PyObject_CallMethod (py_obj, outofscope_func,
+                                                   NULL));
+      if (meth_result == NULL)
+       gdbpy_print_stack ();
     }
 
   delete_breakpoint (bpfinish_obj->py_bp.bp);
@@ -330,14 +342,12 @@ bpfinishpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj)
 /* Callback for `bpfinishpy_detect_out_scope'.  Triggers Python's
    `B->out_of_scope' function if B is a FinishBreakpoint out of its scope.  */
 
-static int
-bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args)
+static bool
+bpfinishpy_detect_out_scope_cb (struct breakpoint *b,
+                               struct breakpoint *bp_stopped)
 {
-  volatile struct gdb_exception except;
-  struct breakpoint *bp_stopped = (struct breakpoint *) args;
   PyObject *py_bp = (PyObject *) b->py_bp_object;
-  struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch ();
-  
+
   /* Trigger out_of_scope if this is a FinishBreakpoint and its frame is
      not anymore in the current callstack.  */
   if (py_bp != NULL && b->py_bp_object->is_finish_bp)
@@ -348,14 +358,14 @@ bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args)
       /* Check scope if not currently stopped at the FinishBreakpoint.  */
       if (b != bp_stopped)
         {
-          TRY_CATCH (except, RETURN_MASK_ALL)
+          try
             {
               if (b->pspace == current_inferior ()->pspace
                   && (!target_has_registers
                       || frame_find_by_id (b->frame_id) == NULL))
                 bpfinishpy_out_of_scope (finish_bp);
             }
-          if (except.reason < 0)
+          catch (const gdb_exception &except)
             {
               gdbpy_convert_exception (except);
               gdbpy_print_stack ();
@@ -372,13 +382,13 @@ bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args)
 static void
 bpfinishpy_handle_stop (struct bpstats *bs, int print_frame)
 {
-  struct cleanup *cleanup = ensure_python_env (get_current_arch (),
-                                               current_language);
+  gdbpy_enter enter_py (get_current_arch (), current_language);
 
-  iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb,
-                            bs == NULL ? NULL : bs->breakpoint_at);
-
-  do_cleanups (cleanup);
+  iterate_over_breakpoints ([&] (breakpoint *bp)
+    {
+      return bpfinishpy_detect_out_scope_cb
+       (bp, bs == NULL ? NULL : bs->breakpoint_at);
+    });
 }
 
 /* Attached to `exit' notifications, triggers all the necessary out of
@@ -387,41 +397,42 @@ bpfinishpy_handle_stop (struct bpstats *bs, int print_frame)
 static void
 bpfinishpy_handle_exit (struct inferior *inf)
 {
-  struct cleanup *cleanup = ensure_python_env (target_gdbarch,
-                                               current_language);
+  gdbpy_enter enter_py (target_gdbarch (), current_language);
 
-  iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, NULL);
-
-  do_cleanups (cleanup);
+  iterate_over_breakpoints ([&] (breakpoint *bp)
+    {
+      return bpfinishpy_detect_out_scope_cb (bp, nullptr);
+    });
 }
 
 /* Initialize the Python finish breakpoint code.  */
 
-void
+int
 gdbpy_initialize_finishbreakpoints (void)
 {
   if (PyType_Ready (&finish_breakpoint_object_type) < 0)
-      return;
-  
-  Py_INCREF (&finish_breakpoint_object_type);
-  PyModule_AddObject (gdb_module, "FinishBreakpoint",
-                      (PyObject *) &finish_breakpoint_object_type);
-    
-  observer_attach_normal_stop (bpfinishpy_handle_stop);
-  observer_attach_inferior_exit (bpfinishpy_handle_exit);
+    return -1;
+
+  if (gdb_pymodule_addobject (gdb_module, "FinishBreakpoint",
+                             (PyObject *) &finish_breakpoint_object_type) < 0)
+    return -1;
+
+  gdb::observers::normal_stop.attach (bpfinishpy_handle_stop);
+  gdb::observers::inferior_exit.attach (bpfinishpy_handle_exit);
+
+  return 0;
 }
 
-static PyGetSetDef finish_breakpoint_object_getset[] = {
+static gdb_PyGetSetDef finish_breakpoint_object_getset[] = {
   { "return_value", bpfinishpy_get_returnvalue, NULL,
   "gdb.Value object representing the return value, if any. \
 None otherwise.", NULL },
     { NULL }  /* Sentinel.  */
 };
 
-static PyTypeObject finish_breakpoint_object_type =
+PyTypeObject finish_breakpoint_object_type =
 {
-  PyObject_HEAD_INIT (NULL)
-  0,                              /*ob_size*/
+  PyVarObject_HEAD_INIT (NULL, 0)
   "gdb.FinishBreakpoint",         /*tp_name*/
   sizeof (struct finish_breakpoint_object),  /*tp_basicsize*/
   0,                              /*tp_itemsize*/
This page took 0.036906 seconds and 4 git commands to generate.