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 "python-internal.h"
24#include "breakpoint.h"
25#include "frame.h"
26#include "gdbthread.h"
27#include "arch-utils.h"
28#include "language.h"
29#include "observable.h"
30#include "inferior.h"
31#include "block.h"
32#include "location.h"
33
34/* Function that is called when a Python finish bp is found out of scope. */
35static const char outofscope_func[] = "out_of_scope";
36
37/* struct implementing the gdb.FinishBreakpoint object by extending
38 the gdb.Breakpoint class. */
40{
41 /* gdb.Breakpoint base class. */
43
44 /* gdb.Symbol object of the function finished by this breakpoint.
45
46 nullptr if no debug information was available or return type was VOID. */
48
49 /* gdb.Value object of the function finished by this breakpoint.
50
51 nullptr if no debug information was available or return type was VOID. */
53
54 /* When stopped at this FinishBreakpoint, gdb.Value object returned by
55 the function; Py_None if the value is not computable; NULL if GDB is
56 not stopped at a FinishBreakpoint. */
58};
59
60extern PyTypeObject finish_breakpoint_object_type
61 CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("finish_breakpoint_object");
62
63/* Python function to get the 'return_value' attribute of
64 FinishBreakpoint. */
65
66static PyObject *
68{
69 struct finish_breakpoint_object *self_finishbp =
70 (struct finish_breakpoint_object *) self;
71
72 if (!self_finishbp->return_value)
73 Py_RETURN_NONE;
74
75 Py_INCREF (self_finishbp->return_value);
76 return self_finishbp->return_value;
77}
78
79/* Deallocate FinishBreakpoint object. */
80
81static void
83{
84 struct finish_breakpoint_object *self_bpfinish =
85 (struct finish_breakpoint_object *) self;
86
87 Py_XDECREF (self_bpfinish->func_symbol);
88 Py_XDECREF (self_bpfinish->function_value);
89 Py_XDECREF (self_bpfinish->return_value);
90 Py_TYPE (self)->tp_free (self);
91}
92
93/* Triggered when gdbpy_breakpoint_cond_says_stop is about to execute the `stop'
94 callback of the gdb.FinishBreakpoint object BP_OBJ. Will compute and cache
95 the `return_value', if possible. */
96
97void
99{
100 struct finish_breakpoint_object *self_finishbp =
101 (struct finish_breakpoint_object *) bp_obj;
102
103 /* Can compute return_value only once. */
104 gdb_assert (!self_finishbp->return_value);
105
106 if (self_finishbp->func_symbol == nullptr)
107 return;
108
109 try
110 {
111 struct symbol *func_symbol =
112 symbol_object_to_symbol (self_finishbp->func_symbol);
113 struct value *function =
114 value_object_to_value (self_finishbp->function_value);
115 struct value *ret =
116 get_return_value (func_symbol, function);
117
118 if (ret)
119 {
120 self_finishbp->return_value = value_to_value_object (ret);
121 if (!self_finishbp->return_value)
123 }
124 else
125 {
126 Py_INCREF (Py_None);
127 self_finishbp->return_value = Py_None;
128 }
129 }
130 catch (const gdb_exception &except)
131 {
134 }
135}
136
137/* Triggered when gdbpy_breakpoint_cond_says_stop has triggered the `stop'
138 callback of the gdb.FinishBreakpoint object BP_OBJ. */
139
140void
142{
143
144 try
145 {
146 /* Can't delete it here, but it will be removed at the next stop. */
147 disable_breakpoint (bp_obj->bp);
149 }
150 catch (const gdb_exception &except)
151 {
154 }
155}
156
157/* Python function to create a new breakpoint. */
158
159static int
161{
162 static const char *keywords[] = { "frame", "internal", NULL };
163 struct finish_breakpoint_object *self_bpfinish =
164 (struct finish_breakpoint_object *) self;
165 PyObject *frame_obj = NULL;
166 int thread;
167 frame_info_ptr frame = NULL; /* init for gcc -Wall */
168 frame_info_ptr prev_frame = NULL;
169 struct frame_id frame_id;
170 PyObject *internal = NULL;
171 int internal_bp = 0;
172 CORE_ADDR pc;
173
174 if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
175 &frame_obj, &internal))
176 return -1;
177
178 try
179 {
180 /* Default frame to newest frame if necessary. */
181 if (frame_obj == NULL)
182 frame = get_current_frame ();
183 else
184 frame = frame_object_to_frame_info (frame_obj);
185
186 if (frame == NULL)
187 {
188 PyErr_SetString (PyExc_ValueError,
189 _("Invalid ID for the `frame' object."));
190 }
191 else
192 {
193 prev_frame = get_prev_frame (frame);
194 if (prev_frame == 0)
195 {
196 PyErr_SetString (PyExc_ValueError,
197 _("\"FinishBreakpoint\" not "
198 "meaningful in the outermost "
199 "frame."));
200 }
201 else if (get_frame_type (prev_frame) == DUMMY_FRAME)
202 {
203 PyErr_SetString (PyExc_ValueError,
204 _("\"FinishBreakpoint\" cannot "
205 "be set on a dummy frame."));
206 }
207 else
208 frame_id = get_frame_id (prev_frame);
209 }
210 }
211 catch (const gdb_exception &except)
212 {
214 return -1;
215 }
216
217 if (PyErr_Occurred ())
218 return -1;
219
220 if (inferior_ptid == null_ptid)
221 {
222 PyErr_SetString (PyExc_ValueError,
223 _("No thread currently selected."));
224 return -1;
225 }
226
227 thread = inferior_thread ()->global_num;
228
229 if (internal)
230 {
231 internal_bp = PyObject_IsTrue (internal);
232 if (internal_bp == -1)
233 {
234 PyErr_SetString (PyExc_ValueError,
235 _("The value of `internal' must be a boolean."));
236 return -1;
237 }
238 }
239
240 /* Find the function we will return from. */
241 self_bpfinish->func_symbol = nullptr;
242 self_bpfinish->function_value = nullptr;
243
244 try
245 {
246 if (get_frame_pc_if_available (frame, &pc))
247 {
248 struct symbol *function = find_pc_function (pc);
249 if (function != nullptr)
250 {
251 struct type *ret_type =
252 check_typedef (function->type ()->target_type ());
253
254 /* Remember only non-void return types. */
255 if (ret_type->code () != TYPE_CODE_VOID)
256 {
257 /* Ignore Python errors at this stage. */
258 value *func_value = read_var_value (function, NULL, frame);
259 self_bpfinish->function_value
260 = value_to_value_object (func_value);
261 PyErr_Clear ();
262
263 self_bpfinish->func_symbol
264 = symbol_to_symbol_object (function);
265 PyErr_Clear ();
266 }
267 }
268 }
269 }
270 catch (const gdb_exception &except)
271 {
272 /* Just swallow. Either the return type or the function value
273 remain NULL. */
274 }
275
276 if (self_bpfinish->func_symbol == nullptr
277 || self_bpfinish->function_value == nullptr)
278 {
279 /* Won't be able to compute return value. */
280 Py_XDECREF (self_bpfinish->func_symbol);
281 Py_XDECREF (self_bpfinish->function_value);
282
283 self_bpfinish->func_symbol = nullptr;
284 self_bpfinish->function_value = nullptr;
285 }
286
287 bppy_pending_object = &self_bpfinish->py_bp;
289 bppy_pending_object->bp = NULL;
290
291 try
292 {
293 /* Set a breakpoint on the return address. */
294 location_spec_up locspec
295 = new_address_location_spec (get_frame_pc (prev_frame), NULL, 0);
297 locspec.get (), NULL, thread, NULL, false,
298 0,
299 1 /*temp_flag*/,
301 0,
304 0, 1, internal_bp, 0);
305 }
306 catch (const gdb_exception &except)
307 {
309 }
310
311 self_bpfinish->py_bp.bp->frame_id = frame_id;
312 self_bpfinish->py_bp.is_finish_bp = 1;
313
314 /* Bind the breakpoint with the current program space. */
315 self_bpfinish->py_bp.bp->pspace = current_program_space;
316
317 return 0;
318}
319
320/* Called when GDB notices that the finish breakpoint BP_OBJ is out of
321 the current callstack. Triggers the method OUT_OF_SCOPE if implemented,
322 then delete the breakpoint. */
323
324static void
326{
327 gdbpy_breakpoint_object *bp_obj = (gdbpy_breakpoint_object *) bpfinish_obj;
328 PyObject *py_obj = (PyObject *) bp_obj;
329
330 if (bpfinish_obj->py_bp.bp->enable_state == bp_enabled
331 && PyObject_HasAttrString (py_obj, outofscope_func))
332 {
333 gdbpy_ref<> meth_result (PyObject_CallMethod (py_obj, outofscope_func,
334 NULL));
335 if (meth_result == NULL)
337 }
338
339 delete_breakpoint (bpfinish_obj->py_bp.bp);
340}
341
342/* Callback for `bpfinishpy_detect_out_scope'. Triggers Python's
343 `B->out_of_scope' function if B is a FinishBreakpoint out of its scope. */
344
345static void
347 struct breakpoint *bp_stopped)
348{
349 PyObject *py_bp = (PyObject *) b->py_bp_object;
350
351 /* Trigger out_of_scope if this is a FinishBreakpoint and its frame is
352 not anymore in the current callstack. */
353 if (py_bp != NULL && b->py_bp_object->is_finish_bp)
354 {
355 struct finish_breakpoint_object *finish_bp =
357
358 /* Check scope if not currently stopped at the FinishBreakpoint. */
359 if (b != bp_stopped)
360 {
361 try
362 {
363 if (b->pspace == current_inferior ()->pspace
365 || frame_find_by_id (b->frame_id) == NULL))
366 bpfinishpy_out_of_scope (finish_bp);
367 }
368 catch (const gdb_exception &except)
369 {
372 }
373 }
374 }
375}
376
377/* Attached to `stop' notifications, check if the execution has run
378 out of the scope of any FinishBreakpoint before it has been hit. */
379
380static void
382{
383 gdbpy_enter enter_py;
384
386 bpfinishpy_detect_out_scope_cb (bp, bs == NULL ? NULL : bs->breakpoint_at);
387}
388
389/* Attached to `exit' notifications, triggers all the necessary out of
390 scope notifications. */
391
392static void
394{
395 gdbpy_enter enter_py (target_gdbarch ());
396
399}
400
401/* Initialize the Python finish breakpoint code. */
402
403int
405{
407 return -1;
408
409 if (PyType_Ready (&finish_breakpoint_object_type) < 0)
410 return -1;
411
412 if (gdb_pymodule_addobject (gdb_module, "FinishBreakpoint",
414 return -1;
415
417 "py-finishbreakpoint");
419 "py-finishbreakpoint");
420
421 return 0;
422}
423
425 { "return_value", bpfinishpy_get_returnvalue, NULL,
426 "gdb.Value object representing the return value, if any. \
427None otherwise.", NULL },
428 { NULL } /* Sentinel. */
429};
430
432{
433 PyVarObject_HEAD_INIT (NULL, 0)
434 "gdb.FinishBreakpoint", /*tp_name*/
435 sizeof (struct finish_breakpoint_object), /*tp_basicsize*/
436 0, /*tp_itemsize*/
437 bpfinishpy_dealloc, /*tp_dealloc*/
438 0, /*tp_print*/
439 0, /*tp_getattr*/
440 0, /*tp_setattr*/
441 0, /*tp_compare*/
442 0, /*tp_repr*/
443 0, /*tp_as_number*/
444 0, /*tp_as_sequence*/
445 0, /*tp_as_mapping*/
446 0, /*tp_hash */
447 0, /*tp_call*/
448 0, /*tp_str*/
449 0, /*tp_getattro*/
450 0, /*tp_setattro */
451 0, /*tp_as_buffer*/
452 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
453 "GDB finish breakpoint object", /* tp_doc */
454 0, /* tp_traverse */
455 0, /* tp_clear */
456 0, /* tp_richcompare */
457 0, /* tp_weaklistoffset */
458 0, /* tp_iter */
459 0, /* tp_iternext */
460 0, /* tp_methods */
461 0, /* tp_members */
462 finish_breakpoint_object_getset,/* tp_getset */
463 &breakpoint_object_type, /* tp_base */
464 0, /* tp_dict */
465 0, /* tp_descr_get */
466 0, /* tp_descr_set */
467 0, /* tp_dictoffset */
468 bpfinishpy_init, /* tp_init */
469 0, /* tp_alloc */
470 0 /* tp_new */
471};
struct gdbarch * target_gdbarch(void)
struct symbol * find_pc_function(CORE_ADDR pc)
Definition blockframe.c:150
void delete_breakpoint(struct breakpoint *bpt)
const struct breakpoint_ops code_breakpoint_ops
Definition breakpoint.c:225
int create_breakpoint(struct gdbarch *gdbarch, location_spec *locspec, const char *cond_string, int thread, 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)
void disable_breakpoint(struct breakpoint *bpt)
breakpoint_safe_range all_breakpoints_safe()
Definition breakpoint.c:637
@ 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:547
@ AUTO_BOOLEAN_TRUE
Definition defs.h:249
struct value * read_var_value(struct symbol *var, const struct block *var_block, frame_info_ptr frame)
Definition findvar.c:787
CORE_ADDR get_frame_pc(frame_info_ptr frame)
Definition frame.c:2592
enum frame_type get_frame_type(frame_info_ptr frame)
Definition frame.c:2835
bool get_frame_pc_if_available(frame_info_ptr frame, CORE_ADDR *pc)
Definition frame.c:2599
frame_info_ptr frame_find_by_id(struct frame_id id)
Definition frame.c:868
frame_info_ptr get_current_frame(void)
Definition frame.c:1615
struct frame_id get_frame_id(frame_info_ptr fi)
Definition frame.c:607
frame_info_ptr get_prev_frame(frame_info_ptr this_frame)
Definition frame.c:2494
@ DUMMY_FRAME
Definition frame.h:182
struct thread_info * inferior_thread(void)
Definition thread.c:83
struct type * check_typedef(struct type *type)
Definition gdbtypes.c:3010
ptid_t inferior_ptid
Definition infcmd.c:91
struct value * get_return_value(struct symbol *func_symbol, struct value *function)
Definition infcmd.c:1474
struct inferior * current_inferior(void)
Definition inferior.c:54
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:39
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)
static void bpfinishpy_detect_out_scope_cb(struct breakpoint *b, struct breakpoint *bp_stopped)
void bpfinishpy_post_stop_hook(struct gdbpy_breakpoint_object *bp_obj)
static void bpfinishpy_handle_stop(struct bpstat *bs, int print_frame)
static const char outofscope_func[]
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[]
int gdbpy_initialize_finishbreakpoints(void)
frame_info_ptr frame_object_to_frame_info(PyObject *obj)
Definition py-frame.c:61
gdb::ref_ptr< T, gdbpy_ref_policy< T > > gdbpy_ref
Definition py-ref.h:43
struct symbol * symbol_object_to_symbol(PyObject *obj)
Definition py-symbol.c:354
PyObject * symbol_to_symbol_object(struct symbol *sym)
Definition py-symbol.c:341
void gdbpy_convert_exception(const struct gdb_exception &exception)
Definition py-utils.c:216
int gdb_pymodule_addobject(PyObject *module, const char *name, PyObject *object)
Definition py-utils.c:331
PyObject * value_to_value_object(struct value *val)
Definition py-value.c:1778
struct value * value_object_to_value(PyObject *self)
Definition py-value.c:1823
void gdbpy_print_stack(void)
#define PyObject_CallMethod
PyObject * gdb_module
#define CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF(ARG)
#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:824
program_space * pspace
Definition breakpoint.h:767
enum enable_state enable_state
Definition breakpoint.h:735
bpdisp disposition
Definition breakpoint.h:737
struct frame_id frame_id
Definition breakpoint.h:762
gdbpy_breakpoint_object py_bp
struct breakpoint * bp
PyObject_HEAD int number
Definition gnu-nat.c:154
struct type * type() const
Definition symtab.h:1285
struct type * target_type() const
Definition gdbtypes.h:1000
type_code code() const
Definition gdbtypes.h:927
Definition value.c:181
int target_has_registers()
Definition target.c:190
int PyObject
Definition varobj.c:41