From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13628 invoked by alias); 30 Sep 2010 14:02:29 -0000 Received: (qmail 13604 invoked by uid 22791); 30 Sep 2010 14:02:26 -0000 X-SWARE-Spam-Status: No, hits=-5.5 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_BP,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 30 Sep 2010 14:02:19 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o8UE2Ift005482 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 30 Sep 2010 10:02:18 -0400 Received: from localhost.localdomain.redhat.com (ovpn-113-74.phx2.redhat.com [10.3.113.74]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o8UE2FvP015188 for ; Thu, 30 Sep 2010 10:02:16 -0400 From: Phil Muldoon To: gdb-patches@sourceware.org Subject: [patch] Add visible flag to breakpoints. Reply-to: pmuldoon@redhat.com X-URL: http://www.redhat.com Date: Thu, 30 Sep 2010 16:28:00 -0000 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-09/txt/msg00510.txt.bz2 This patch allows breakpoints to be become invisible to the user. This is part of a larger effort to improve the Python breakpoint support within GDB. One of the use-cases we have in Python is for a command to set (maybe a large) number of breakpoints to catch predefined behavior. However we do not want this to impact the usability or readability of the existing 'info breakpoints' output. This patch fixes that by allowing breakpoints to become invisible to the user. One of the initial approaches we took was to create our own kind of Python breakpoint. This would be much like all of the special case internal breakpoints that currently exist within GDB. But these are too special purpose -- we lose all the general accessibility and edge-cases behavior within general purpose breakpoints. And, ultimately we would have to put all of that code back in, causing code duplication. So we decided to add a visible flag. Currently this visibility flag is only accessible through the Python breakpoint code. If the visible keyword is set when the breakpoint is created, it will not be mentioned (only the new breakpoint observer will be called), and the breakpoint will not be enumerated via 'info breakpoints'. The visibility of a breakpoint can subsequently be altered via the 'visible' attribute of the Python object which will flip the visible flag in the breakpoint struct. Subsequent calls to 'info breakpoints' will then show the breakpoint. There are several assumptions I have made in this patch. If when the breakpoint it created, the visible flag is set to False: -- GDB will not mention the breakpoint creation, but will notify any observers. -- The breakpoint will not be enumerated in the 'info breakpoint' list. -- The breakpoint whether invisible or not, will always be enumerated in 'maint info breakpoints' -- The internalvar bpnum is always set to the breakpoint just created, regardless of whether the visibility flag is set. I think these are sane defaults, but I'm open to changing them as we need too. What do you think? Cheers, Phil -- 2010-09-30 Phil Muldoon * python/py-breakpoint.c (bppy_get_visibility): New function. (bppy_set_visibility): Ditto. (bppy_new): Add visible keyword and pass it as a parameter to create_new_breakpoint. * breakpoint.h (struct breakpoint): Add visible flag. (create_new_breakpoint): Declare. * breakpoint.c (breakpoint_visible): New function. (breakpoint_1): Check if breakpoint is visible. (set_raw_breakpoint_without_location): Set visible to 1. (create_breakpoint_sal): Add visible parameter and set visibility. Only call mention if breakpoint is visible, else just notify the observer. (create_breakpoint_sals): Ditto. (create_new_breakpoint): Renamed from create_new_breakpoint. Add visible parameter. (create_breakpoint): Wrap create_new_breakpoint with default visibility set to on. 2010-09-30 Phil Muldoon * gdb.texinfo (Breakpoints In Python): Document optional visible flag. Document visible attribute. 2010-09-30 Phil Muldoon * gdb.python/py-breakpoint.exp: Add breakpoint visibility tests. -- diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index b4502e7..26cab2c 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -4907,6 +4907,14 @@ user_settable_breakpoint (const struct breakpoint *b) || is_tracepoint (b) || is_watchpoint (b)); } + +/* Return non-zero if B is visible to the user. */ + +static int +breakpoint_visible (const struct breakpoint *b) +{ + return b->visible; +} /* Print information on user settable breakpoint (watchpoint, etc) number BNUM. If BNUM is -1 print all user-settable breakpoints. @@ -4939,7 +4947,8 @@ breakpoint_1 (int bnum, int allflag, int (*filter) (const struct breakpoint *)) if (filter && !filter (b)) continue; - if (allflag || user_settable_breakpoint (b)) + if (allflag || (user_settable_breakpoint (b) + && breakpoint_visible (b))) { int addr_bit, type_len; @@ -5007,7 +5016,8 @@ breakpoint_1 (int bnum, int allflag, int (*filter) (const struct breakpoint *)) /* We only print out user settable breakpoints unless the allflag is set. */ - if (allflag || user_settable_breakpoint (b)) + if (allflag || (user_settable_breakpoint (b) + && breakpoint_visible (b))) print_one_breakpoint (b, &last_loc, print_address_bits, allflag); } } @@ -5456,6 +5466,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch, b->syscalls_to_be_caught = NULL; b->ops = NULL; b->condition_not_parsed = 0; + b->visible = 1; /* Add this breakpoint to the end of the chain so that a list of breakpoints will come out in order @@ -6914,7 +6925,8 @@ create_breakpoint_sal (struct gdbarch *gdbarch, char *cond_string, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, - struct breakpoint_ops *ops, int from_tty, int enabled) + struct breakpoint_ops *ops, int from_tty, + int enabled, int visible) { struct breakpoint *b = NULL; int i; @@ -6961,6 +6973,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch, b->enable_state = enabled ? bp_enabled : bp_disabled; b->disposition = disposition; b->pspace = sals.sals[0].pspace; + b->visible = visible; if (type == bp_static_tracepoint) { @@ -7034,7 +7047,12 @@ Couldn't determine the static tracepoint marker to probe")); = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address)); b->ops = ops; - mention (b); + if (visible) + mention (b); + else + /* Just notify observers without printing. */ + observer_notify_breakpoint_created (b->number); + } /* Remove element at INDEX_TO_REMOVE from SAL, shifting other @@ -7190,7 +7208,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, struct breakpoint_ops *ops, int from_tty, - int enabled) + int enabled, int visible) { int i; @@ -7201,7 +7219,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch, create_breakpoint_sal (gdbarch, expanded, addr_string[i], cond_string, type, disposition, - thread, task, ignore_count, ops, from_tty, enabled); + thread, task, ignore_count, ops, + from_tty, enabled, visible); } } @@ -7474,15 +7493,16 @@ decode_static_tracepoint_spec (char **arg_p) was created; false otherwise. */ int -create_breakpoint (struct gdbarch *gdbarch, - char *arg, char *cond_string, int thread, - int parse_condition_and_thread, - int tempflag, enum bptype type_wanted, - int ignore_count, - enum auto_boolean pending_break_support, - struct breakpoint_ops *ops, - int from_tty, - int enabled) +create_new_breakpoint (struct gdbarch *gdbarch, + char *arg, char *cond_string, int thread, + int parse_condition_and_thread, + int tempflag, enum bptype type_wanted, + int ignore_count, + enum auto_boolean pending_break_support, + struct breakpoint_ops *ops, + int from_tty, + int enabled, + int visible) { struct gdb_exception e; struct symtabs_and_lines sals; @@ -7658,7 +7678,7 @@ create_breakpoint (struct gdbarch *gdbarch, cond_string, type_wanted, tempflag ? disp_del : disp_donttouch, thread, task, ignore_count, ops, - from_tty, enabled); + from_tty, enabled, visible); do_cleanups (old_chain); @@ -7679,7 +7699,7 @@ create_breakpoint (struct gdbarch *gdbarch, create_breakpoints_sal (gdbarch, sals, addr_string, cond_string, type_wanted, tempflag ? disp_del : disp_donttouch, thread, task, ignore_count, ops, from_tty, - enabled); + enabled, visible); } else { @@ -7699,13 +7719,18 @@ create_breakpoint (struct gdbarch *gdbarch, b->ops = ops; b->enable_state = enabled ? bp_enabled : bp_disabled; b->pspace = current_program_space; + b->visible = visible; if (enabled && b->pspace->executing_startup && (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint)) b->enable_state = bp_startup_disabled; - mention (b); + if (visible) + mention (b); + else + /* Just notify observers without printing. */ + observer_notify_breakpoint_created (b->number); } if (sals.nelts > 1) @@ -7727,6 +7752,34 @@ create_breakpoint (struct gdbarch *gdbarch, return 1; } + +/* Set a breakpoint. This function is shared between CLI and MI + functions for setting a breakpoint. This function has two major + modes of operations, selected by the PARSE_CONDITION_AND_THREAD + parameter. If non-zero, the function will parse arg, extracting + breakpoint location, address and thread. Otherwise, ARG is just the + location of breakpoint, with condition and thread specified by the + COND_STRING and THREAD parameters. Returns true if any breakpoint + was created; false otherwise. */ + +int +create_breakpoint (struct gdbarch *gdbarch, + char *arg, char *cond_string, int thread, + int parse_condition_and_thread, + int tempflag, enum bptype type_wanted, + int ignore_count, + enum auto_boolean pending_break_support, + struct breakpoint_ops *ops, + int from_tty, + int enabled) +{ + return create_new_breakpoint (gdbarch, arg, cond_string, thread, + parse_condition_and_thread, tempflag, + type_wanted, ignore_count, + pending_break_support, + ops, from_tty, enabled, 1); +} + /* Set a breakpoint. ARG is a string describing breakpoint address, condition, and thread. diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 9f7600a..3c3b5d0 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -557,6 +557,13 @@ struct breakpoint breakpoints, we will use this index to try to find the same marker again. */ int static_trace_marker_id_idx; + + /* Python breakpoints are allowed to specify whether the + breakpoint will be visible to the user via 'info breakpoints'. + This is to enable Python scripts to set many breakpoints in + commands/functions without impacting the readability of the + 'info breakpoints' command. */ + int visible; }; typedef struct breakpoint *breakpoint_p; @@ -870,6 +877,18 @@ extern int create_breakpoint (struct gdbarch *gdbarch, char *arg, int from_tty, int enabled); +extern int create_new_breakpoint (struct gdbarch *gdbarch, char *arg, + char *cond_string, int thread, + int parse_condition_and_thread, + int tempflag, + enum bptype type_wanted, + int ignore_count, + enum auto_boolean pending_break_support, + struct breakpoint_ops *ops, + int from_tty, + int enabled, + int visible); + extern void insert_breakpoints (void); extern int remove_breakpoints (void); diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0b24718..1fa6faa 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -22552,7 +22552,7 @@ Return the symbol table's source absolute file name. Python code can manipulate breakpoints via the @code{gdb.Breakpoint} class. -@defmethod Breakpoint __init__ spec @r{[}type@r{]} @r{[}wp_class@r{]} +@defmethod Breakpoint __init__ spec @r{[}type@r{]} @r{[}wp_class@r{]} @r{[}visible@r{]} Create a new breakpoint. @var{spec} is a string naming the location of the breakpoint, or an expression that defines a watchpoint. The contents can be any location recognized by the @@ -22560,7 +22560,12 @@ watchpoint. The contents can be any location recognized by the command. The optional @var{type} denotes the breakpoint to create from the types defined later in this chapter. This argument can be either: @code{BP_BREAKPOINT} or @code{BP_WATCHPOINT}. @var{type} -defaults to @code{BP_BREAKPOINT}. The optional @var{wp_class} +defaults to @code{BP_BREAKPOINT}. The optional @var{visible} argument +allows the breakpoint to become invisible to the user. The breakpoint +will neither be reported when created, or will it be enumerated in the +output from @samp{info breakpoints} (but will be enumerated with the +@samp{maint info breakpoints} command). The @var{visible} argument +has no effect with watchpoints. The optional @var{wp_class} argument defines the class of watchpoint to create, if @var{type} is defined as @code{BP_WATCHPOINT}. If a watchpoint class is not provided, it is assumed to be a @var{WP_WRITE} class. @@ -22638,6 +22643,12 @@ determine the actual breakpoint type or use-case. This attribute is not writable. @end defivar +@defivar Breakpoint visible +This attribute holds the breakpoint's visibility flag --- the identifier used to +determine whether the breakpoint is visible to the user when set, or +when the @samp{info breakpoints} command is run. This attribute is writable. +@end defivar + The available types are represented by constants defined in the @code{gdb} module: diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 0c70cbf..acbaab2 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -500,6 +500,40 @@ bppy_get_type (PyObject *self, void *closure) return PyInt_FromLong (self_bp->bp->type); } +/* Python function to get the visibility state of the breakpoint. */ +static PyObject * +bppy_get_visibility (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + return PyInt_FromLong (self_bp->bp->visible); +} + +/* Python function to set the visibility state of a breakpoint. */ +static int +bppy_set_visibility (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL || ! PyBool_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + _("Value must be True or False.")); + return -1; + } + + if (newvalue == Py_True) + self_bp->bp->visible = 1; + else + self_bp->bp->visible = 0; + + return 0; +} + /* Python function to get the breakpoint's number. */ static PyObject * bppy_get_number (PyObject *self, void *closure) @@ -566,14 +600,15 @@ static PyObject * bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { PyObject *result; - static char *keywords[] = { "spec", "type", "wp_class", NULL }; + static char *keywords[] = { "spec", "type", "wp_class", "visible", NULL }; char *spec; int type = bp_breakpoint; int access_type = hw_write; + int visible = 1; volatile struct gdb_exception except; - if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|ii", keywords, - &spec, &type, &access_type)) + if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iii", keywords, + &spec, &type, &access_type, &visible)) return NULL; result = subtype->tp_alloc (subtype, 0); @@ -589,13 +624,13 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { case bp_breakpoint: { - create_breakpoint (python_gdbarch, - spec, NULL, -1, - 0, - 0, bp_breakpoint, - 0, - AUTO_BOOLEAN_TRUE, - NULL, 0, 1); + create_new_breakpoint (python_gdbarch, + spec, NULL, -1, + 0, + 0, bp_breakpoint, + 0, + AUTO_BOOLEAN_TRUE, + NULL, 0, 1, visible); break; } case bp_watchpoint: @@ -816,6 +851,9 @@ or None if no condition set."}, "Commands of the breakpoint, as specified by the user."}, { "type", bppy_get_type, NULL, "Type of breakpoint."}, + { "visible", bppy_get_visibility, bppy_set_visibility, + "Whether the breakpoint is visible to the user."}, + { NULL } /* Sentinel. */ }; diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index 07a7362..dc78a92 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -126,6 +126,30 @@ gdb_test "end" gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0 gdb_test "python print blist\[len(blist)-1\].commands" "print \"Command for breakpoint has been executed.\".*print result" +# Start with a fresh gdb. +clean_restart ${testfile} + +if ![runto_main] then { + fail "Cannot run to main." + return 0 +} + +# Test invisible breakpooints. +delete_breakpoints +set ibp_location [gdb_get_line_number "Break at multiply."] +gdb_py_test_silent_cmd "python ibp = gdb.Breakpoint(\"$ibp_location\", visible=False)" "Set invisible breakpoint" 0 +gdb_py_test_silent_cmd "python ilist = gdb.breakpoints()" "Get Breakpoint List" 0 +gdb_test "python print ilist\[0\]" "" "Check invisible bp obj exists" +gdb_test "python print ilist\[0\].location" "py-breakpoint\.c:$ibp_location*" "Check breakpoint location" +gdb_test "python print ilist\[0\].visible" "0" "Check breakpoint visibility" +gdb_test "python print ilist\[0\].number == gdb.parse_and_eval(\"\$bpnum\")" "True" "Check that bpnum has been updated" +gdb_test "info breakpoints" "No breakpoints or watchpoints.*" "Check info breakpoints does not show invisible breakpoints" +gdb_test "maint info breakpoints" "py-breakpoint\.c:$ibp_location.*" "Check maint info breakpoints shows invisible breakpoints" +gdb_py_test_silent_cmd "python ilist\[0\].visible = True" "Set visibility to True" 0 +gdb_test "info breakpoints" "py-breakpoint\.c:$ibp_location.*" "Check info breakpoints shows visible breakpoints" +gdb_py_test_silent_cmd "python ilist\[0\].visible = False" "Set visibility to True" 0 +gdb_test "info breakpoints" "No breakpoints or watchpoints.*" "Check info breakpoints does not show invisible breakpoints" + # Watchpoints # Start with a fresh gdb. clean_restart ${testfile}