GDB (xrefs)
Loading...
Searching...
No Matches
py-finishbreakpoint.c
Go to the documentation of this file.
1/* Python interface to finish breakpoints
2
3 Copyright (C) 2011-2023 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20
21
22#include "defs.h"
23#include "top.h"
24#include "python-internal.h"
25#include "breakpoint.h"
26#include "frame.h"
27#include "gdbthread.h"
28#include "arch-utils.h"
29#include "language.h"
30#include "observable.h"
31#include "inferior.h"
32#include "block.h"
33#include "location.h"
34
35/* Function that is called when a Python finish bp is found out of scope. */
36static const char outofscope_func[] = "out_of_scope";
37
38/* struct implementing the gdb.FinishBreakpoint object by extending
39 the gdb.Breakpoint class. */
41{
42 /* gdb.Breakpoint base class. */
44
45 /* gdb.Symbol object of the function finished by this breakpoint.
46
47 nullptr if no debug information was available or return type was VOID. */
49
50 /* gdb.Value object of the function finished by this breakpoint.
51
52 nullptr if no debug information was available or return type was VOID. */
54
55 /* When stopped at this FinishBreakpoint, gdb.Value object returned by
56 the function; Py_None if the value is not computable; NULL if GDB is
57 not stopped at a FinishBreakpoint. */
59
60 /* The initiating frame for this operation, used to decide when we have
61 left this frame. */
63};
64
65extern PyTypeObject finish_breakpoint_object_type
66 CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("finish_breakpoint_object");
67
68/* Python function to get the 'return_value' attribute of
69 FinishBreakpoint. */
70
71static PyObject *
73{
74 struct finish_breakpoint_object *self_finishbp =
75 (struct finish_breakpoint_object *) self;
76
77 if (!self_finishbp->return_value)
78 Py_RETURN_NONE;
79
80 Py_INCREF (self_finishbp->return_value);
81 return self_finishbp->return_value;
82}
83
84/* Deallocate FinishBreakpoint object. */
85
86static void
88{
89 struct finish_breakpoint_object *self_bpfinish =
90 (struct finish_breakpoint_object *) self;
91
92 Py_XDECREF (self_bpfinish->func_symbol);
93 Py_XDECREF (self_bpfinish->function_value);
94 Py_XDECREF (self_bpfinish->return_value);
95 Py_TYPE (self)->tp_free (self);
96}
97
98/* Triggered when gdbpy_breakpoint_cond_says_stop is about to execute the `stop'
99 callback of the gdb.FinishBreakpoint object BP_OBJ. Will compute and cache
100 the `return_value', if possible. */
101
102void
104{
105 struct finish_breakpoint_object *self_finishbp =
106 (struct finish_breakpoint_object *) bp_obj;
107
108 /* Can compute return_value only once. */
109 gdb_assert (!self_finishbp->return_value);
110
111 if (self_finishbp->func_symbol == nullptr)
112 return;
113
114 try
115 {
116 scoped_value_mark free_values;
117
118 struct symbol *func_symbol =
119 symbol_object_to_symbol (self_finishbp->func_symbol);
120 struct value *function =
121 value_object_to_value (self_finishbp->function_value);
122 struct value *ret =
123 get_return_value (func_symbol, function);
124
125 if (ret)
126 {
127 self_finishbp->return_value = value_to_value_object (ret);
128 if (!self_finishbp->return_value)
130 }
131 else
132 {
133 Py_INCREF (Py_None);
134 self_finishbp->return_value = Py_None;
135 }
136 }
137 catch (const gdb_exception &except)
138 {
141 }
142}
143
144/* Triggered when gdbpy_breakpoint_cond_says_stop has triggered the `stop'
145 callback of the gdb.FinishBreakpoint object BP_OBJ. */
146
147void
149{
150
151 try
152 {
153 /* Can't delete it here, but it will be removed at the next stop. */
154 disable_breakpoint (bp_obj->bp);
156 }
157 catch (const gdb_exception &except)
158 {
161 }
162}
163
164/* Python function to create a new breakpoint. */
165
166static int
168{
169 static const char *keywords[] = { "frame", "internal", NULL };
170 struct finish_breakpoint_object *self_bpfinish =
171 (struct finish_breakpoint_object *) self;
172 PyObject *frame_obj = NULL;
173 int thread;
174 frame_info_ptr frame = NULL; /* init for gcc -Wall */
175 frame_info_ptr prev_frame = NULL;
176 struct frame_id frame_id;
177 PyObject *internal = NULL;
178 int internal_bp = 0;
179 CORE_ADDR pc;
180
181 if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
182 &frame_obj, &internal))
183 return -1;
184
185 try
186 {
187 /* Default frame to newest frame if necessary. */
188 if (frame_obj == NULL)
189 frame = get_current_frame ();
190 else
191 frame = frame_object_to_frame_info (frame_obj);
192
193 if (frame == NULL)
194 {
195 PyErr_SetString (PyExc_ValueError,
196 _("Invalid ID for the `frame' object."));
197 }
198 else
199 {
200 prev_frame = get_prev_frame (frame);
201 if (prev_frame == 0)
202 {
203 PyErr_SetString (PyExc_ValueError,
204 _("\"FinishBreakpoint\" not "
205 "meaningful in the outermost "
206 "frame."));
207 }
208 else if (get_frame_type (prev_frame) == DUMMY_FRAME)
209 {
210 PyErr_SetString (PyExc_ValueError,
211 _("\"FinishBreakpoint\" cannot "
212 "be set on a dummy frame."));
213 }
214 else
215 frame_id = get_frame_id (prev_frame);
216 }
217 }
218 catch (const gdb_exception &except)
219 {
221 return -1;
222 }
223
224 if (PyErr_Occurred ())
225 return -1;
226
227 if (inferior_ptid == null_ptid)
228 {
229 PyErr_SetString (PyExc_ValueError,
230 _("No thread currently selected."));
231 return -1;
232 }
233
234 thread = inferior_thread ()->global_num;
235
236 if (internal)
237 {
238 internal_bp = PyObject_IsTrue (internal);
239 if (internal_bp == -1)
240 {
241 PyErr_SetString (PyExc_ValueError,
242 _("The value of `internal' must be a boolean."));
243 return -1;
244 }
245 }
246
247 /* Find the function we will return from. */
248 self_bpfinish->func_symbol = nullptr;
249 self_bpfinish->function_value = nullptr;
250
251 try
252 {
253 if (get_frame_pc_if_available (frame, &pc))
254 {
255 struct symbol *function = find_pc_function (pc);
256 if (function != nullptr)
257 {
258 struct type *ret_type =
259 check_typedef (function->type ()->target_type ());
260
261 /* Remember only non-void return types. */
262 if (ret_type->code () != TYPE_CODE_VOID)
263 {
264 scoped_value_mark free_values;
265
266 /* Ignore Python errors at this stage. */
267 value *func_value = read_var_value (function, NULL, frame);
268 self_bpfinish->function_value
269 = value_to_value_object (func_value);
270 PyErr_Clear ();
271
272 self_bpfinish->func_symbol
273 = symbol_to_symbol_object (function);
274 PyErr_Clear ();
275 }
276 }
277 }
278 }
279 catch (const gdb_exception_forced_quit &except)
280 {
281 quit_force (NULL, 0);
282 }
283 catch (const gdb_exception &except)
284 {
285 /* Just swallow. Either the return type or the function value
286 remain NULL. */
287 }
288
289 if (self_bpfinish->func_symbol == nullptr
290 || self_bpfinish->function_value == nullptr)
291 {
292 /* Won't be able to compute return value. */
293 Py_XDECREF (self_bpfinish->func_symbol);
294 Py_XDECREF (self_bpfinish->function_value);
295
296 self_bpfinish->func_symbol = nullptr;
297 self_bpfinish->function_value = nullptr;
298 }
299
300 bppy_pending_object = &self_bpfinish->py_bp;
302 bppy_pending_object->bp = NULL;
303
304 try
305 {
306 /* Set a breakpoint on the return address. */
307 location_spec_up locspec
308 = new_address_location_spec (get_frame_pc (prev_frame), NULL, 0);
310 locspec.get (), NULL, thread, -1, NULL, false,
311 0,
312 1 /*temp_flag*/,
314 0,
317 0, 1, internal_bp, 0);
318 }
319 catch (const gdb_exception &except)
320 {
322 }
323
324 self_bpfinish->py_bp.bp->frame_id = frame_id;
325 self_bpfinish->py_bp.is_finish_bp = 1;
326 self_bpfinish->initiating_frame = get_frame_id (frame);
327
328 /* Bind the breakpoint with the current program space. */
329 self_bpfinish->py_bp.bp->pspace = current_program_space;
330
331 return 0;
332}
333
334/* Called when GDB notices that the finish breakpoint BP_OBJ is out of
335 the current callstack. Triggers the method OUT_OF_SCOPE if implemented,
336 then delete the breakpoint. */
337
338static void
340{
341 gdbpy_breakpoint_object *bp_obj = (gdbpy_breakpoint_object *) bpfinish_obj;
342 PyObject *py_obj = (PyObject *) bp_obj;
343
344 if (bpfinish_obj->py_bp.bp->enable_state == bp_enabled
345 && PyObject_HasAttrString (py_obj, outofscope_func))
346 {
347 gdbpy_ref<> meth_result (PyObject_CallMethod (py_obj, outofscope_func,
348 NULL));
349 if (meth_result == NULL)
351 }
352}
353
354/* Callback for `bpfinishpy_detect_out_scope'. Triggers Python's
355 `B->out_of_scope' function if B is a FinishBreakpoint out of its scope.
356
357 When DELETE_BP is true then breakpoint B will be deleted if B is a
358 FinishBreakpoint and it is out of scope, otherwise B will not be
359 deleted. */
360
361static void
363 struct breakpoint *bp_stopped,
364 bool delete_bp)
365{
366 PyObject *py_bp = (PyObject *) b->py_bp_object;
367
368 /* Trigger out_of_scope if this is a FinishBreakpoint and its frame is
369 not anymore in the current callstack. */
370 if (py_bp != NULL && b->py_bp_object->is_finish_bp)
371 {
372 struct finish_breakpoint_object *finish_bp =
374
375 /* Check scope if not currently stopped at the FinishBreakpoint. */
376 if (b != bp_stopped)
377 {
378 try
379 {
380 struct frame_id initiating_frame = finish_bp->initiating_frame;
381
382 if (b->pspace == current_inferior ()->pspace
384 || frame_find_by_id (initiating_frame) == NULL))
385 {
386 bpfinishpy_out_of_scope (finish_bp);
387 if (delete_bp)
388 delete_breakpoint (finish_bp->py_bp.bp);
389 }
390 }
391 catch (const gdb_exception &except)
392 {
395 }
396 }
397 }
398}
399
400/* Called when gdbpy_breakpoint_deleted is about to delete a breakpoint. A
401 chance to trigger the out_of_scope callback (if appropriate) for the
402 associated Python object. */
403
404void
406{
407 breakpoint *bp = bp_obj->bp;
408 bpfinishpy_detect_out_scope_cb (bp, nullptr, false);
409}
410
411/* Attached to `stop' notifications, check if the execution has run
412 out of the scope of any FinishBreakpoint before it has been hit. */
413
414static void
416{
417 gdbpy_enter enter_py;
418
421 (&bp, bs == NULL ? NULL : bs->breakpoint_at, true);
422}
423
424/* Attached to `exit' notifications, triggers all the necessary out of
425 scope notifications. */
426
427static void
429{
430 gdbpy_enter enter_py (target_gdbarch ());
431
433 bpfinishpy_detect_out_scope_cb (&bp, nullptr, true);
434}
435
436/* Initialize the Python finish breakpoint code. */
437
440{
442 return -1;
443
444 if (PyType_Ready (&finish_breakpoint_object_type) < 0)
445 return -1;
446
447 if (gdb_pymodule_addobject (gdb_module, "FinishBreakpoint",
449 return -1;
450
452 "py-finishbreakpoint");
454 "py-finishbreakpoint");
455
456 return 0;
457}
458
460
461
462
464 { "return_value", bpfinishpy_get_returnvalue, NULL,
465 "gdb.Value object representing the return value, if any. \
466None otherwise.", NULL },
467 { NULL } /* Sentinel. */
468};
469
471{
472 PyVarObject_HEAD_INIT (NULL, 0)
473 "gdb.FinishBreakpoint", /*tp_name*/
474 sizeof (struct finish_breakpoint_object), /*tp_basicsize*/
475 0, /*tp_itemsize*/
476 bpfinishpy_dealloc, /*tp_dealloc*/
477 0, /*tp_print*/
478 0, /*tp_getattr*/
479 0, /*tp_setattr*/
480 0, /*tp_compare*/
481 0, /*tp_repr*/
482 0, /*tp_as_number*/
483 0, /*tp_as_sequence*/
484 0, /*tp_as_mapping*/
485 0, /*tp_hash */
486 0, /*tp_call*/
487 0, /*tp_str*/
488 0, /*tp_getattro*/
489 0, /*tp_setattro */
490 0, /*tp_as_buffer*/
491 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
492 "GDB finish breakpoint object", /* tp_doc */
493 0, /* tp_traverse */
494 0, /* tp_clear */
495 0, /* tp_richcompare */
496 0, /* tp_weaklistoffset */
497 0, /* tp_iter */
498 0, /* tp_iternext */
499 0, /* tp_methods */
500 0, /* tp_members */
501 finish_breakpoint_object_getset,/* tp_getset */
502 &breakpoint_object_type, /* tp_base */
503 0, /* tp_dict */
504 0, /* tp_descr_get */
505 0, /* tp_descr_set */
506 0, /* tp_dictoffset */
507 bpfinishpy_init, /* tp_init */
508 0, /* tp_alloc */
509 0 /* tp_new */
510};
struct gdbarch * target_gdbarch(void)
struct symbol * find_pc_function(CORE_ADDR pc)
Definition blockframe.c:150
void delete_breakpoint(struct breakpoint *bpt)
int create_breakpoint(struct gdbarch *gdbarch, location_spec *locspec, const char *cond_string, int thread, int inferior, const char *extra_string, bool force_condition, int parse_extra, int tempflag, enum bptype type_wanted, int ignore_count, enum auto_boolean pending_break_support, const struct breakpoint_ops *ops, int from_tty, int enabled, int internal, unsigned flags)
const struct breakpoint_ops code_breakpoint_ops
Definition breakpoint.c:290
void disable_breakpoint(struct breakpoint *bpt)
breakpoint_safe_range all_breakpoints_safe()
Definition breakpoint.c:712
@ disp_del_at_next_stop
Definition breakpoint.h:238
@ bp_breakpoint
Definition breakpoint.h:86
@ bp_enabled
Definition breakpoint.h:220
static struct gdbarch * get_gdbarch()
struct program_space * pspace
Definition inferior.h:582
@ AUTO_BOOLEAN_TRUE
Definition defs.h:248
struct value * read_var_value(struct symbol *var, const struct block *var_block, frame_info_ptr frame)
Definition findvar.c:739
CORE_ADDR get_frame_pc(frame_info_ptr frame)
Definition frame.c:2712
enum frame_type get_frame_type(frame_info_ptr frame)
Definition frame.c:2955
bool get_frame_pc_if_available(frame_info_ptr frame, CORE_ADDR *pc)
Definition frame.c:2719
frame_info_ptr frame_find_by_id(struct frame_id id)
Definition frame.c:916
frame_info_ptr get_current_frame(void)
Definition frame.c:1670
struct frame_id get_frame_id(frame_info_ptr fi)
Definition frame.c:631
frame_info_ptr get_prev_frame(frame_info_ptr this_frame)
Definition frame.c:2614
@ DUMMY_FRAME
Definition frame.h:190
struct thread_info * inferior_thread(void)
Definition thread.c:85
struct type * check_typedef(struct type *type)
Definition gdbtypes.c:2966
ptid_t inferior_ptid
Definition infcmd.c:74
struct value * get_return_value(struct symbol *func_symbol, struct value *function)
Definition infcmd.c:1467
struct inferior * current_inferior(void)
Definition inferior.c:55
location_spec_up new_address_location_spec(CORE_ADDR addr, const char *addr_string, int addr_string_len)
Definition location.c:230
std::unique_ptr< location_spec > location_spec_up
Definition location.h:71
observable< struct inferior * > inferior_exit
observable< struct bpstat *, int > normal_stop
struct program_space * current_program_space
Definition progspace.c:40
bool gdbpy_breakpoint_init_breakpoint_type()
PyTypeObject breakpoint_object_type
gdbpy_breakpoint_object * bppy_pending_object
PyTypeObject finish_breakpoint_object_type
static int bpfinishpy_init(PyObject *self, PyObject *args, PyObject *kwargs)
void bpfinishpy_post_stop_hook(struct gdbpy_breakpoint_object *bp_obj)
static void bpfinishpy_handle_stop(struct bpstat *bs, int print_frame)
void bpfinishpy_pre_delete_hook(struct gdbpy_breakpoint_object *bp_obj)
static const char outofscope_func[]
static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION gdbpy_initialize_finishbreakpoints(void)
static void bpfinishpy_handle_exit(struct inferior *inf)
static void bpfinishpy_out_of_scope(struct finish_breakpoint_object *bpfinish_obj)
static void bpfinishpy_dealloc(PyObject *self)
static PyObject * bpfinishpy_get_returnvalue(PyObject *self, void *closure)
void bpfinishpy_pre_stop_hook(struct gdbpy_breakpoint_object *bp_obj)
static gdb_PyGetSetDef finish_breakpoint_object_getset[]
static void bpfinishpy_detect_out_scope_cb(struct breakpoint *b, struct breakpoint *bp_stopped, bool delete_bp)
frame_info_ptr frame_object_to_frame_info(PyObject *obj)
Definition py-frame.c:62
gdb::ref_ptr< T, gdbpy_ref_policy< T > > gdbpy_ref
Definition py-ref.h:42
struct symbol * symbol_object_to_symbol(PyObject *obj)
Definition py-symbol.c:357
PyObject * symbol_to_symbol_object(struct symbol *sym)
Definition py-symbol.c:344
void gdbpy_convert_exception(const struct gdb_exception &exception)
Definition py-utils.c:217
int gdb_pymodule_addobject(PyObject *module, const char *name, PyObject *object)
Definition py-utils.c:334
PyObject * value_to_value_object(struct value *val)
Definition py-value.c:1854
struct value * value_object_to_value(PyObject *self)
Definition py-value.c:1877
void gdbpy_print_stack(void)
#define PyObject_CallMethod
PyObject * gdb_module
#define CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF(ARG)
#define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
#define GDBPY_INITIALIZE_FILE(INIT,...)
#define GDB_PY_SET_HANDLE_EXCEPTION(Exception)
static int gdb_PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, const char **keywords,...)
static void print_frame(const frame_print_options &opts, frame_info_ptr frame, int print_level, enum print_what print_what, int print_args, struct symtab_and_line sal)
struct breakpoint * breakpoint_at
gdbpy_breakpoint_object * py_bp_object
Definition breakpoint.h:890
program_space * pspace
Definition breakpoint.h:829
enum enable_state enable_state
Definition breakpoint.h:800
bpdisp disposition
Definition breakpoint.h:802
struct frame_id frame_id
Definition breakpoint.h:824
gdbpy_breakpoint_object py_bp
struct breakpoint * bp
PyObject_HEAD int number
Definition gnu-nat.c:153
struct type * type() const
Definition symtab.h:1331
struct type * target_type() const
Definition gdbtypes.h:1037
type_code code() const
Definition gdbtypes.h:956
Definition value.h:130
int target_has_registers()
Definition target.c:189
void quit_force(int *exit_arg, int from_tty)
Definition top.c:1732
int PyObject
Definition varobj.c:41