This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Hello, thanks for you comments, I replied inline: > Kevin> -static void > Kevin> +void > Kevin> ?create_breakpoint_sal (struct gdbarch *gdbarch, > Kevin> ? ? ? ? ? ? ? ? ? ? ? ? struct symtabs_and_lines sals, char *addr_string, > Kevin> ? ? ? ? ? ? ? ? ? ? ? ? char *cond_string, > > What is the rationale for using this function in particular? > > It seems to me that it would probably be better to make an explicit_pc=1 > SAL using the unwound PC. ?Then there would be no reason to avoid the > currently exported API. There isn't. I just followed the "finish" command implementation and understood that this function looked like what I was looking for! I re-wrote this part of the code to use the existing API > Kevin> - ?if (inferior_thread ()->control.proceed_to_finish) > Kevin> + ?if (gdbpy_is_stopped_at_finish_bp (inferior_thread ()->control.stop_bpstat) > Kevin> + ? ? ?|| inferior_thread ()->control.proceed_to_finish) > > gdbpy_is_stopped_at_finish_bp is not safe to call here -- it assumes the > GIL has been acquired, which it has not. ?I would rather it not be changed > to acquire the GIL, however. ?I think one of two other approaches would > be preferable. > > One way you could handle this is to add a new constant to enum bptype. > This is likely to be pretty invasive. > > Another way would be to add a flag to the struct breakpoint itself. > > Yet another way would be a new breakpoint_ops method. you're right; I chose the second way, breakpoint.h: enum py_bp_type { py_bp_none, /* No Python object. */ py_bp_standard, /* Ordinary breakpoint object. */ py_bp_finish /* FinishBreakpoint object. */ }; /* Type of the Python Breakpoint object stored in `py_bp_object'. */ enum py_bp_type py_bp_type; py-breakpoint.c: gdbpy_is_stopped_at_bp_type (bpstat stop_bpstat, enum py_bp_type type) so that it doesn't require GIL state handling > This is related, in a way, to the out-of-scope handling. ?Right now the > patch tries to reimplement the existing breakpoint re-setting logic in > py-finishbreakpoint.c, via observers. ?I think it would be better to > have this be done automatically by the existing code in breakpoint.c, > perhaps adding some additional python-visible notification step. I'm not sure what you're talking about; I re-explain and document this aspect at the bottom of the mail, you'll tell me if this is still relevant > Kevin> +static char * const outofscope_func = "out_of_scope"; > > "const char *". I copied it from py-breakpoint.c: > static char * const stop_func = "stop"; and I think thank we can't change it, otherwise it conflicts with > PyObject* PyObject_CallMethod(PyObject *o, char *method, char *format, ...) and creates a compiler warning > Kevin> + ?/* The function finished by this breakpoint. ?*/ > Kevin> + ?struct symbol *function; > > If you want to store a pointer to a symbol, then you have to account for > the case where the objfile is destroyed. ?Otherwise you can end up with > a dangling pointer. > > Alternatively, perhaps you could have this refer to a Symbol object; but > then you have to be careful to check it for validity before using it. > > Actually, it seems that the symbol is only used to get the function's > return type. ?You might as well just compute that up front and store a > Type. > Kevin> +/* Python function to get the 'return_value' attribute of > Kevin> + FinishBreakpoint. */ > Kevin> + > Kevin> +static PyObject * > Kevin> +bpfinishpy_get_returnvalue (PyObject *self, void *closure) > Kevin> +{ > Kevin> + struct finish_breakpoint_object *self_finishbp = > Kevin> + (struct finish_breakpoint_object *) self; > Kevin> + > Kevin> + BPPY_REQUIRE_VALID (&self_finishbp->py_bp); > Kevin> + > Kevin> + if (self_finishbp->function == NULL) > Kevin> + goto return_none; > Kevin> + > Kevin> + /* Ensure that GDB is stopped at this FinishBreakpoint. */ > Kevin> + if (inferior_thread ()->control.stop_bpstat != NULL) > Kevin> + { > Kevin> + bpstat bs; > Kevin> + > Kevin> + for(bs = inferior_thread ()->control.stop_bpstat; > Kevin> + bs; bs = bs->next) > > I am not an expert here, but I think it is probably no good to rely on > this state remaining live. > > I think it would be better to simply have a stop at one of these > breakpoints compute and cache the Value object immediately. as per your two comments, I now only store the `struct type' of the function and the return value, and cache the `gdb.Value' object when GDB stops at a FinishBreakpoint. `FinishBreakpoint.return_value' may have to populate the cache when it's accessed from Breakpoint.stop() because there is no guarantee the FinishBreakpoint observer will be notified first. > Kevin> +static void > Kevin> +gdbpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj) > Kevin> +{ > Kevin> + ?breakpoint_object *bp_obj = (breakpoint_object *) bpfinish_obj; > Kevin> + ?PyObject *py_obj = (PyObject *) bp_obj ; > Kevin> + > Kevin> + ?bpfinish_obj->out_of_scope_notif = 0; > Kevin> + > Kevin> + ?if (PyObject_HasAttrString (py_obj, outofscope_func)) > Kevin> + ? ?{ > Kevin> + ? ? ?struct gdbarch *garch = ?bp_obj->bp->gdbarch ? > Kevin> + ? ? ? ? ?bp_obj->bp->gdbarch : get_current_arch (); > Kevin> + ? ? ?struct cleanup *cleanup = ensure_python_env (garch, current_language); > > You can't call any Python functions without the GIL. > This applies to PyObject_HasAttrString here. > > In this case, though, gdbpy_out_of_scope is called by one function that > already has the GIL. ?So, I think the acquisition should be pushed into > its other caller. fixed > Kevin> + ?pc = get_frame_pc (prev_frame); > > This can throw an exception. ?So, it needs to be wrapped in a TRY_CATCH. > This may apply to some other GDB functions called by the "Python-facing" > code, I did not check them all. fixed > Kevin> diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp > > Funny file name. funny but correct, or too funny? ;) > Kevin> +gdb_test "python ExceptionBreakpoint()" "ExceptionBreakpoint init" "set BP before throwing the exception" > Kevin> +gdb_test "python print len(gdb.breakpoints())" "4" "check number of BPs" > Kevin> +gdb_test "continue" ".*stopped at ExceptionFinishBreakpoint.*" "check FinishBreakpoint in catch()" > Kevin> +gdb_test "python print len(gdb.breakpoints())" "4" "check finish BP removal" > > I don't think this tests the most important case -- where an exception > is thrown, invalidating the return breakpoint. > > That is, put a breakpoint in throw_exception_1, continue to there, then > set the breakpoint, then continue again. > > I didn't examine the longjmp test but the same idea applies there. > > Other cases to consider are - > > * inferior exec > * inferior exit > * explicit inferior function call > * "return" command I'll work on the tests for the next version of the patch ("return" should already be covered) -- so, about the `out_of_scope' stuffs, > Kevin> +/* Python function to set the 'out_of_scope_notif' attribute of > Kevin> + FinishBreakpoint. */ > Kevin> + > Kevin> +static int > Kevin> +bpfinishpy_set_outofscope_notif (PyObject *self, PyObject *newvalue, > Kevin> + void *closure) > > I don't understand the point of this function. > > I think documentation would help. here is a bit of documentation about this class: @subsubsection Finish Breakpoints @cindex python finish breakpoints @tindex gdb.FinishBreakpoint A @fdb{finish breakpoint} is a breakpoint set at the return address of a frame, based on the "finish command. @code{gdb.FinishBreakpoint} extends @code{gdb.Breakpoint} @defmethod FinishBreakpoint __init__ frame @r{[}internal@r{]} Create a FinishBreakpoint at the return of the @code{gdb.Frame} object @var{frame}. The optional @var{internal} argument allows the breakpoint to become invisible to the user. @xref{Breakpoints In Python}, for further details about this argument. @end defmethod @defop Operation {gdb.Breakpoint} out_of_scope (self) In some circonstances (eg, @code{longjmp}, C++ exceptions, @value{GDBN} @code{return} command, ...), a function may not properly terminate, and thus never hit a @{code} FinishBreakpoint. When @value{GDBN} notices such a situation, the @code{out_of_scope} function will be triggered. This method will only be called if the @code{out_of_scope_notif} attribute is @code{True}. Deleting (@code{gdb.Breakpoint.delete()}) the @code{FinishBreakpoint} is allowed in this function. You may want to sub-class the @code{gdb.FinishBreakpoint} and implement the @code{out_of_scope} method: @smallexample class MyFinishBreakpoint (gdb.FinishBreakpoint) def stop (self): print "normal finish" return True def out_of_scope(): print "abnormal finish" @end smallexample @end defop @defmethod FinishBreakpoint check_scope Because @value{GDBN} currently only checks if @code{FinishBreakpoint}s ran out of scope at normal stops, this method allows to force the verification and trigger the @code{out_of_scope} method if necessary. It will return @code{True} if @code{out_of_scope()} was triggered, @code{False} otherwise. @end defmethod @defivar FinishBreakpoint out_of_scope_notif This attribute will be @code{True} until the @code{out_of_scope} method has been called and @code{False} afterwards. This attribute is writeable, so out of scope notifications can be re-enabled. @end defivar @defivar FinishBreakpoint return_value When @value{GDBN} is stopped at a @code{FinishBreakpoint}, and the frame used to build the @code{FinishBreakpoint} had debug symbols, this attribute will contain a @code{gdb.Value} object corresponding to the return value of the function. The value will be @code{None} if the value was not computable. This attribute is not writable. @end defivar > Kevin> +static PyMethodDef finish_breakpoint_object_methods[] = { > Kevin> + { "check_scope", bpfinishpy_check_scope, METH_NOARGS, > Kevin> + "check_scope () -> Boolean.\n\ > Kevin> +Return true if out_of_scope() has been triggered, false if not." }, > > How is this useful? > And, why a method instead of an attribute? as described, this is useful especially in the case of a GDB-forced "return": normal_stop observers are not notified, so `out_of_scope()' is not triggered. `check_scope()' allows Python scripts to force this verification when they need. The reason why it's a method is that it may execute `out_of_scope()', which was, from my point of view, inconsistent with the concept of attribute. > Kevin> +static PyGetSetDef finish_breakpoint_object_getset[] = { > Kevin> + { "out_of_scope_notif", bpfinishpy_get_outofscope_notif, bpfinishpy_set_outofscope_notif, > > I don't like the name "out_of_scope_notif", particularly if this is an > apt description of its meaning: > Kevin> + "Boolean telling whether the breakpoint is still within the scope \ > Kevin> +of the current callstack.", NULL }, I've got some difficulties to find a correct name for this attribute, which is used for two purposes: - avoid calling `out_of_scope' every normal_stop when the breakpoint is not anymore in the callstack - allow the script to re-activate notification when it wants to 're-use' the FinishBreakpoint (instead of deleting it / creating a new one) cordially, Kevin
Attachment:
finish_bp.txt
Description: Text document
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |