* [patch] [python] Expose some breakpoint operations to Python
@ 2011-06-23 12:35 Phil Muldoon
2011-06-23 13:19 ` Eli Zaretskii
2011-06-23 14:07 ` Pedro Alves
0 siblings, 2 replies; 12+ messages in thread
From: Phil Muldoon @ 2011-06-23 12:35 UTC (permalink / raw)
To: gdb-patches
This patch exposes to the Python API some breakpoint operations. The
operations exported are:
print_it
print_one
print_one_detail
print_mention
One of the changes made in this patch is to bind the Python breakpoint
and the GDB breakpoint much earlier if the breakpoint is created from
the Python API. This change was needed as some breakpoint operations
are called before the observers are notified. Previously we bound the
Python object and the breakpoint when the observer was notified. In the
case where a breakpoint is not created from the Python API this is still
the case. In any case, the ordering of breakpoint operations and
breakpoint observers means we have to bind some breakpoints at
creation. This has meant we have had to alter some of the breakpoint
APIs to carry the breakpoint object in the parameter list at creation.
I've included both MI and CLI tests. These are very similar. The MI
tests are needed to prove that the exported Python APIs work
seamlessly with MI notifications.
Tested on X8664 Fedora 15 with no regressions.
What do you think?
Cheers,
Phil
--
2011-06-23 Phil Muldoon <pmuldoon@redhat.com>
* python/python.h (gdbpy_bind_breakpoint): Export.
* python/python.c (gdbpy_bind_breakpoint): New function.
* python/python-internal.h (breakpoint_object): Moved from
py-breakpoint.c
* python/py-breakpoint.c (breakpoint_object): Move to
python-internal.h
(py_breakpoint_ops): Define.
(pybp_print_stop_actions): Define.
(find_python_obj): New function.
(pybp_print_one): Ditto.
(pybp_print_one_detail): Ditto.
(pybp_print_mention): Ditto.
(pybp_print_it): Ditto.
(bppy_init): Call bppy_build_ops. Pass bppy_pending_object to
create_breakpoint, watch_command_wrapper, awatch_command_wrapper
and rwatch_command_wrapper.
(gdbpy_breakpoint_created): Check for early binding of breakpoints.
Add initialization to newpb breakpoint. Conditionalize later
binding if an early binding has already occurred.
(gdbpy_initialize_breakpoints): Build pybp_print_stop_action
constants.
* mi/mi-cmd-break.c (mi_cmd_break_insert): Update create_breakpoint
call.
(mi_cmd_break_watch): Update watch_command_wrapper,
rwatch_command_wrapper and awatch_command_wrapper calls.
* breakpoint.h: Update create_breakpoint, watch_command_wrapper,
rwatch_command_wrapper and awatch_command_wrapper definitions.
* breakpoint.c (create_breakpoint_sal): Add Python breakpoint_struct
parameter. Call gdbpy_bind_breakpoint.
(watch_command_1): Ditto.
(create_breakpoints_sal): Add Python breakpoint_struct parameter.
Pass to called functions.
(watch_command_wrapper): Ditto.
(create_breakpoint): Add Python breakpoint_struct parameter. Pass
to called function. Call gdbpy_bind_breakpoint.
(break_command_1): Update create_breakpoint call with
breakpoint_object parameter.
(handle_gnu_v3_exceptions): Ditto
(trace_command): Ditto.
(ftrace_command): Ditto.
(strace_command): Ditto.
(create_tracepoint_from_upload): Ditto.
(watch_maybe_just_location): Update watch_command_1 call with
breakpoint_struct parameter.
(rwatch_command_wrapper): Ditto.
(awatch_command_wrapper): Ditto.
(handle_gnu_v3_exceptions):
2011-06-23 Phil Muldoon <pmuldoon@redhat.com>
* gdb.python/py-breakpoint.exp: Add breakpoint operation tests.
* gdb.python/py-mi.exp: Ditto.
* gdb.python/py-mi-bp.py: New file.
2011-06-23 pmuldoon <pmuldoon@redhat.com>
* gdb.texinfo (Breakpoints In Python): Document breakpoint
operation APIs.
--
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 935cd03..3e2c42c 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7500,7 +7500,8 @@ bp_loc_is_permanent (struct bp_location *loc)
/* Create a breakpoint with SAL as location. Use ADDR_STRING
as textual description of the location, and COND_STRING
- as condition expression. */
+ as condition expression. PY_OBJ is the Python object previously
+ created to be attached to the breakpoint; this can be NULL. */
static void
create_breakpoint_sal (struct gdbarch *gdbarch,
@@ -7509,7 +7510,8 @@ create_breakpoint_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 internal, int display_canonical)
+ int enabled, int internal, int display_canonical,
+ struct breakpoint_object *py_obj)
{
struct breakpoint *b = NULL;
int i;
@@ -7628,6 +7630,11 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
b->ops = ops;
+
+ /* Now that the breakpoint is created, bind the breakpoint with the
+ Python breakpoint object. */
+ gdbpy_bind_breakpoint (py_obj, b);
+
/* Do not mention breakpoints with a negative number, but do
notify observers. */
if (!internal)
@@ -7774,7 +7781,9 @@ expand_line_sal_maybe (struct symtab_and_line sal)
SALS.nelts is not 1 is when we set a breakpoint on an overloaded
function. In that case, it's still not possible to specify
separate conditions for different overloaded functions, so
- we take just a single condition string.
+ we take just a single condition string. PY_OBJ is the Python object
+ previously created to be attached to the breakpoint; this can be
+ NULL.
NOTE: If the function succeeds, the caller is expected to cleanup
the arrays ADDR_STRING, COND_STRING, and SALS (but not the
@@ -7790,7 +7799,8 @@ 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 internal)
+ int enabled, int internal,
+ struct breakpoint_object *py_obj)
{
int i;
@@ -7803,7 +7813,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
cond_string, type, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal,
- canonical->special_display);
+ canonical->special_display, py_obj);
}
}
@@ -8059,8 +8069,9 @@ decode_static_tracepoint_spec (char **arg_p)
the location of breakpoint, with condition and thread specified by
the COND_STRING and THREAD parameters. If INTERNAL is non-zero,
the breakpoint number will be allocated from the internal
- breakpoint count. Returns true if any breakpoint was created;
- false otherwise. */
+ breakpoint count. PY_OBJ is the Python object previously created
+ to be attached to the breakpoint; this can be NULL. Returns true
+ if any breakpoint was created; false otherwise. */
int
create_breakpoint (struct gdbarch *gdbarch,
@@ -8070,7 +8081,8 @@ create_breakpoint (struct gdbarch *gdbarch,
int ignore_count,
enum auto_boolean pending_break_support,
struct breakpoint_ops *ops,
- int from_tty, int enabled, int internal)
+ int from_tty, int enabled, int internal,
+ struct breakpoint_object *py_obj)
{
volatile struct gdb_exception e;
struct symtabs_and_lines sals;
@@ -8244,7 +8256,7 @@ create_breakpoint (struct gdbarch *gdbarch,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
from_tty, enabled, internal,
- canonical.special_display);
+ canonical.special_display, py_obj);
do_cleanups (old_chain);
@@ -8269,7 +8281,7 @@ create_breakpoint (struct gdbarch *gdbarch,
type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
- enabled, internal);
+ enabled, internal, py_obj);
}
else
{
@@ -8288,7 +8300,10 @@ create_breakpoint (struct gdbarch *gdbarch,
b->ops = ops;
b->enable_state = enabled ? bp_enabled : bp_disabled;
b->pspace = current_program_space;
- b->py_bp_object = NULL;
+
+ /* Now that the breakpoint is created, bind the breakpoint with
+ the Python breakpoint object. */
+ gdbpy_bind_breakpoint (py_obj, b);
if (enabled && b->pspace->executing_startup
&& (b->type == bp_breakpoint
@@ -8345,7 +8360,8 @@ break_command_1 (char *arg, int flag, int from_tty)
NULL /* breakpoint_ops */,
from_tty,
1 /* enabled */,
- 0 /* internal */);
+ 0 /* internal */,
+ NULL /* Python breakpoint object */);
}
@@ -9178,7 +9194,8 @@ is_masked_watchpoint (const struct breakpoint *b)
hw_access: watch access (read or write) */
static void
watch_command_1 (char *arg, int accessflag, int from_tty,
- int just_location, int internal)
+ int just_location, int internal,
+ struct breakpoint_object *py_obj)
{
volatile struct gdb_exception e;
struct breakpoint *b, *scope_breakpoint = NULL;
@@ -9400,6 +9417,11 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
b->exp = exp;
b->exp_valid_block = exp_valid_block;
b->cond_exp_valid_block = cond_exp_valid_block;
+
+ /* Now that the breakpoint is created, bind the breakpoint with the
+ Python breakpoint object. */
+ gdbpy_bind_breakpoint (py_obj, b);
+
if (just_location)
{
struct type *t = value_type (val);
@@ -9569,9 +9591,10 @@ can_use_hardware_watchpoint (struct value *v)
}
void
-watch_command_wrapper (char *arg, int from_tty, int internal)
+watch_command_wrapper (char *arg, int from_tty, int internal,
+ struct breakpoint_object *py_obj)
{
- watch_command_1 (arg, hw_write, from_tty, 0, internal);
+ watch_command_1 (arg, hw_write, from_tty, 0, internal, py_obj);
}
/* A helper function that looks for an argument at the start of a
@@ -9607,7 +9630,7 @@ watch_maybe_just_location (char *arg, int accessflag, int from_tty)
just_location = 1;
}
- watch_command_1 (arg, accessflag, from_tty, just_location, 0);
+ watch_command_1 (arg, accessflag, from_tty, just_location, 0, NULL);
}
static void
@@ -9617,9 +9640,10 @@ watch_command (char *arg, int from_tty)
}
void
-rwatch_command_wrapper (char *arg, int from_tty, int internal)
+rwatch_command_wrapper (char *arg, int from_tty, int internal,
+ struct breakpoint_object *py_obj)
{
- watch_command_1 (arg, hw_read, from_tty, 0, internal);
+ watch_command_1 (arg, hw_read, from_tty, 0, internal, py_obj);
}
static void
@@ -9629,9 +9653,10 @@ rwatch_command (char *arg, int from_tty)
}
void
-awatch_command_wrapper (char *arg, int from_tty, int internal)
+awatch_command_wrapper (char *arg, int from_tty, int internal,
+ struct breakpoint_object *py_obj)
{
- watch_command_1 (arg, hw_access, from_tty, 0, internal);
+ watch_command_1 (arg, hw_access, from_tty, 0, internal, py_obj);
}
static void
@@ -10003,7 +10028,8 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_string,
AUTO_BOOLEAN_TRUE /* pending */,
&gnu_v3_exception_catchpoint_ops, from_tty,
1 /* enabled */,
- 0 /* internal */);
+ 0 /* internal */,
+ NULL /* Python breakpoint object */);
return 1;
}
@@ -12350,7 +12376,8 @@ trace_command (char *arg, int from_tty)
NULL,
from_tty,
1 /* enabled */,
- 0 /* internal */))
+ 0 /* internal */,
+ NULL /* Python breakpoint object */))
set_tracepoint_count (breakpoint_count);
}
@@ -12367,7 +12394,8 @@ ftrace_command (char *arg, int from_tty)
NULL,
from_tty,
1 /* enabled */,
- 0 /* internal */))
+ 0 /* internal */,
+ NULL /* Python breakpoint object */))
set_tracepoint_count (breakpoint_count);
}
@@ -12386,7 +12414,8 @@ strace_command (char *arg, int from_tty)
NULL,
from_tty,
1 /* enabled */,
- 0 /* internal */))
+ 0 /* internal */,
+ NULL /* Python breakpoint object */))
set_tracepoint_count (breakpoint_count);
}
@@ -12451,7 +12480,8 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
NULL,
0 /* from_tty */,
utp->enabled /* enabled */,
- 0 /* internal */))
+ 0 /* internal */,
+ NULL /* Python breakpoint object */))
return NULL;
set_tracepoint_count (breakpoint_count);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 6fca479..9cb175d 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1020,9 +1020,12 @@ extern void break_command (char *, int);
extern void hbreak_command_wrapper (char *, int);
extern void thbreak_command_wrapper (char *, int);
extern void rbreak_command_wrapper (char *, int);
-extern void watch_command_wrapper (char *, int, int);
-extern void awatch_command_wrapper (char *, int, int);
-extern void rwatch_command_wrapper (char *, int, int);
+extern void watch_command_wrapper (char *, int, int,
+ struct breakpoint_object *);
+extern void awatch_command_wrapper (char *, int, int,
+ struct breakpoint_object *);
+extern void rwatch_command_wrapper (char *, int, int,
+ struct breakpoint_object *);
extern void tbreak_command (char *, int);
/* Arguments to pass as context to some catch command handlers. */
@@ -1067,7 +1070,8 @@ extern int create_breakpoint (struct gdbarch *gdbarch, char *arg,
struct breakpoint_ops *ops,
int from_tty,
int enabled,
- int internal);
+ int internal,
+ struct breakpoint_object *py_obj);
extern void insert_breakpoints (void);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3a705c2..7931bad 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -23341,14 +23341,18 @@ argument defines the class of watchpoint to create, if @var{type} is
assumed to be a @var{WP_WRITE} class.
@end defmethod
-@defop Operation {gdb.Breakpoint} stop (self)
The @code{gdb.Breakpoint} class can be sub-classed and, in
-particular, you may choose to implement the @code{stop} method.
-If this method is defined as a sub-class of @code{gdb.Breakpoint},
-it will be called when the inferior reaches any location of a
-breakpoint which instantiates that sub-class. If the method returns
-@code{True}, the inferior will be stopped at the location of the
-breakpoint, otherwise the inferior will continue.
+particular, you may choose to implement several different methods
+detailed below. These methods influence how GDB operates with certain
+breakpoint operations.
+
+@defop Operation {gdb.Breakpoint} stop (self)
+The @code{stop} method may be implemented as part of a
+@code{gdb.Breakpoint}. This method will be called when the inferior
+reaches any location of a breakpoint which instantiates that
+sub-class. If the method returns @code{True}, the inferior will be
+stopped at the location of the breakpoint, otherwise the inferior will
+continue.
If there are multiple breakpoints at the same location with a
@code{stop} method, each one will be called regardless of the
@@ -23369,6 +23373,144 @@ class MyBreakpoint (gdb.Breakpoint):
@end smallexample
@end defop
+@defop Operation {gdb.Breakpoint} print_mention (self)
+
+The @code{print_mention} method may be implemented as part of a
+@code{gdb.Breakpoint}. This method will be called when a breakpoint is
+created which instantiates that sub-class. This method allows
+customization of the message that @value{GDBN} prints when a
+breakpoint is created. This method must return a string.
+
+Example @code{print_mention} implementation:
+
+@smallexample
+class MyBreakpoint (gdb.Breakpoint):
+
+ def print_mention (self):
+ return "Our Breakpoint " + str(self.number) + " at " + str(self.location)
+@end smallexample
+
+When a user creates a breakpoint using this class, @value{GDBN} will
+print:
+
+@smallexample
+Our Breakpoint 2 at somewhere/some-file.c:10
+@end smallexample
+@end defop
+
+@defop Operation {gdb.Breakpoint} print_stop_action (self)
+
+The @code{print_stop_action} method may be implemented as part of a
+@code{gdb.Breakpoint}. This method will be called when the inferior
+stops at a breakpoint that is instantiated by that sub-class. This
+method allows customization of the message that @value{GDBN} prints
+when the inferior stops at that breakpoint. This method must return a
+Python @code{Tuple}. The first element of the tuple should be a
+string that defines the breakpoint prelude. The prelude is printed
+before the breakpoint location information is printed. If a prelude
+is not needed, Python @code{None} can be returned instead. The second
+element should be one of the following constants defined in the
+@code{gdb} module:
+
+@table @code
+@findex PRINT_SRC_AND_LOC
+@findex gdb.PRINT_SRC_AND_LOC
+@item PRINT_SRC_AND_LOC
+Print the source line number and location information associated with
+this breakpoint.
+@findex PRINT_SRC_ONLY
+@findex gdb.PRINT_SRC_ONLY
+@item PRINT_SRC_ONLY
+Print the source line number information only.
+@findex PRINT_NOTHING
+@findex gdb.PRINT_NOTHING
+@item PRINT_NOTHING
+Do not print any breakpoint information.
+@end table
+
+Example @code{print_stop_action} implementation:
+
+@smallexample
+class MyBreakpoint (gdb.Breakpoint):
+
+ def print_stop_action (self):
+ return ("Our Breakpoint, ", gdb.PRINT_SRC_AND_LOC)
+@end smallexample
+
+When @value{GDBN} stops the inferior at a breakpoint defined by
+this class, @value{GDBN} will print:
+
+@smallexample
+Our Breakpoint, foofunc (argc=1, argv=0xff) somewhere/some-file.c:10
+@end smallexample
+@end defop
+
+@defop Operation {gdb.Breakpoint} print_one (self, address)
+@anchor{print_one}
+
+The @code{print_one} method may be implemented as part of a
+@code{gdb.Breakpoint}. This method will be called when information is
+requested on a breakpoint (such as the @value {GDBN} command,
+@samp{info breakpoints}). This method allows customization of the
+information that @value{GDBN} prints. The @code{address} parameter
+contains the address where @value{GDBN} stopped the inferior. This
+method must return a Python @code{Tuple}. The first element of the
+tuple should be a Python @code{Long} that contains the address that is
+to be printed in the informational output, or @code{None}. If
+@code{None} is returned, address information will not be printed. The
+second element should be a Python string giving a very brief
+description of the breakpoint, or Python @code{None} if you do not
+want to print anything for that field.
+
+Example @code{print_one} implementation:
+
+@smallexample
+class MyBreakpoint (gdb.Breakpoint):
+
+ def print_one (self, address):
+ return (address,"Our Breakpoint")
+@end smallexample
+
+The output from @samp{info breakpoints} from the above example:
+
+@smallexample
+Num Type Disp Enb Address What
+1 breakpoint keep y 0x0000000000400532 Our Breakpoint
+@end smallexample
+@end defop
+
+@defop Operation {gdb.Breakpoint} print_one (self, address)
+
+The @code{print_one_detail} method may be implemented as part of a
+@code{gdb.Breakpoint}. This method is a companion method to
+@samp{print_one} (@pxref{print_one}). This method will be called when
+information is requested on a breakpoint (such as the @value {GDBN}
+command, @samp{info breakpoints}), and allows extra details to be
+printed about that breakpoint. This method must return a Python
+string containing brief supplemental information on that breakpoint.
+
+Example @code{print_one_detail} implementation:
+
+@smallexample
+class MyBreakpoint (gdb.Breakpoint):
+
+ def print_one (self, address):
+ return (address,"Our Breakpoint")
+
+ def print_one_detail (self):
+ return "Our Breakpoint at " + str (self.location) + "\n"
+
+@end smallexample
+
+The output from @samp{info breakpoints} from the above example:
+
+@smallexample
+Num Type Disp Enb Address What
+1 breakpoint keep y 0x0000000000400532 Our Breakpoint
+Our Breakpoint at somwhere/somefile.c:10
+@end smallexample
+@end defop
+
The available watchpoint types represented by constants are defined in the
@code{gdb} module:
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index d68a033..4e84e73 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -169,7 +169,7 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
temp_p, type_wanted,
ignore_count,
pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
- NULL, 0, enabled, 0);
+ NULL, 0, enabled, 0, NULL);
do_cleanups (back_to);
}
@@ -259,13 +259,13 @@ mi_cmd_break_watch (char *command, char **argv, int argc)
switch (type)
{
case REG_WP:
- watch_command_wrapper (expr, FROM_TTY, 0);
+ watch_command_wrapper (expr, FROM_TTY, 0, NULL);
break;
case READ_WP:
- rwatch_command_wrapper (expr, FROM_TTY, 0);
+ rwatch_command_wrapper (expr, FROM_TTY, 0, NULL);
break;
case ACCESS_WP:
- awatch_command_wrapper (expr, FROM_TTY, 0);
+ awatch_command_wrapper (expr, FROM_TTY, 0, NULL);
break;
default:
error (_("-break-watch: Unknown watchpoint type."));
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 9c33848..1536223 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -30,6 +30,9 @@
#include "ada-lang.h"
#include "arch-utils.h"
#include "language.h"
+#include "valprint.h"
+#include "annotate.h"
+#include "mi/mi-common.h"
static PyTypeObject breakpoint_object_type;
@@ -43,16 +46,21 @@ static breakpoint_object *bppy_pending_object;
/* Function that is called when a Python condition is evaluated. */
static char * const stop_func = "stop";
-struct breakpoint_object
-{
- PyObject_HEAD
-
- /* The breakpoint number according to gdb. */
- int number;
-
- /* The gdb breakpoint object, or NULL if the breakpoint has been
- deleted. */
- struct breakpoint *bp;
+/* The Python breakpoint_ops structure. This structure is dynamically
+ built when bppy_init inspects the functions that have been defined
+ in the Python breakpoint object. */
+static struct breakpoint_ops py_breakpoint_ops =
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
};
/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
@@ -107,6 +115,16 @@ static struct pybp_code pybp_watch_types[] =
{NULL} /* Sentinel. */
};
+/* Entries related to the type of print action when a breakpoint is
+ hit. */
+static struct pybp_code pybp_print_stop_actions[] =
+{
+ {"PRINT_SRC_AND_LOC", PRINT_SRC_AND_LOC},
+ {"PRINT_SRC_ONLY", PRINT_SRC_ONLY},
+ {"PRINT_NOTHING", PRINT_NOTHING},
+ {NULL} /* Sentinel. */
+};
+
/* Python function which checks the validity of a breakpoint object. */
static PyObject *
bppy_is_valid (PyObject *self, PyObject *args)
@@ -594,6 +612,354 @@ bppy_get_ignore_count (PyObject *self, void *closure)
return PyInt_FromLong (self_bp->bp->ignore_count);
}
+/* Convenience function that given a breakpoint B, return (and cast
+ to PyObject) the corresponding Python object. This function should
+ never be called on an breakpoint that you do not expect to have a
+ Python object. */
+static PyObject *
+find_python_obj (const struct breakpoint *b)
+{
+ if (! b->py_bp_object)
+ internal_error (__FILE__, __LINE__,
+ _("Cannot reference Python object in breakpoint."));
+
+ return (PyObject *) b->py_bp_object;
+}
+
+/* Implement the breakpoint_ops "print_one" function. This function
+ calls the corresponding Python function and expects a Tuple in
+ return. This Tuple must have two elements: a Long or None
+ representing the breakpoint address, and a String representing the
+ data printed in the "What" field of the breakpoint information
+ output. */
+static void pybp_print_one (struct breakpoint *b,
+ struct bp_location **bp_loc)
+{
+ PyObject *self;
+ PyObject *result = NULL;
+ PyObject *address;
+ PyObject *method = PyString_FromString ("print_one");
+ struct cleanup *cleanup;
+ struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch ();
+ struct value_print_options opts;
+ PyObject *what_obj;
+ CORE_ADDR bp_addr;
+
+ self = find_python_obj (b);
+ cleanup = ensure_python_env (garch, current_language);
+ make_cleanup_py_decref (method);
+
+ /* Sometimes the bp_location is NULL. Similar to
+ print_one_breakpoint_location if we cannot find a location here,
+ we access it from the breakpoint. */
+ if (*bp_loc != NULL)
+ bp_addr = (*bp_loc)->address;
+ else
+ bp_addr = b->loc->address;
+
+ address = PyLong_FromUnsignedLong (bp_addr);
+
+ if (! address)
+ goto python_error;
+
+ result = PyObject_CallMethodObjArgs (self, method, address, NULL);
+ if (result)
+ {
+ if (! PyTuple_Check (result) || PyTuple_Size (result) != 2)
+ goto type_error;
+ }
+ else
+ goto python_error;
+
+ get_user_print_options (&opts);
+
+ /* Field 4, the address. */
+ if (opts.addressprint)
+ {
+ PyObject *addr_field = PyTuple_GetItem (result, 0);
+
+ if (! addr_field)
+ goto python_error;
+
+ if (addr_field == Py_None)
+ ui_out_field_skip (uiout, "addr");
+ else
+ {
+ CORE_ADDR addr_value;
+
+ if (! PyLong_Check (addr_field))
+ goto type_error;
+
+ addr_value = PyLong_AsUnsignedLong (addr_field);
+
+ /* Check for overflows. */
+ if (PyErr_Occurred ())
+ goto python_error;
+
+ annotate_field (4);
+ ui_out_field_core_addr (uiout, "addr",
+ garch, addr_value);
+ }
+ }
+
+ /* Field 5, 'What' output. */
+ what_obj = PyTuple_GetItem (result, 1);
+ if (! what_obj)
+ goto python_error;
+
+ if (what_obj == Py_None)
+ ui_out_field_skip (uiout, "what");
+ else
+ {
+ char *what_string = NULL;
+
+ if (! gdbpy_is_string (what_obj))
+ goto type_error;
+
+ what_string = gdbpy_obj_to_string (what_obj);
+ if (! what_string)
+ goto python_error;
+
+ annotate_field (5);
+ ui_out_field_string (uiout, "what", what_string);
+ xfree (what_string);
+ }
+
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+
+ type_error:
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Invalid information returned from Python " \
+ "'print_one' function"));
+ gdbpy_print_stack ();
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+
+ python_error:
+ gdbpy_print_stack ();
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+}
+
+/* Implement the breakpoint_ops "print_one_detail" function. This
+ function calls the corresponding Python function and expects a
+ String in return. The returned string will be printed when
+ information on this breakpoint is requested, and the requesting
+ function prints the extra detail line (see info breakpoints). */
+static void
+pybp_print_one_detail (const struct breakpoint *b,
+ struct ui_out *uiout)
+{
+ PyObject *self;
+ PyObject *result = NULL;
+ struct cleanup *cleanup;
+ struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch ();
+ char *detail_str = NULL;
+
+ self = find_python_obj (b);
+ cleanup = ensure_python_env (garch, current_language);
+ result = PyObject_CallMethod (self, "print_one_detail", NULL);
+
+ if (! result)
+ goto python_error;
+
+ if (! gdbpy_is_string (result))
+ goto type_error;
+
+ detail_str = gdbpy_obj_to_string (result);
+ if (! detail_str)
+ goto python_error;
+
+ ui_out_text (uiout, detail_str);
+ xfree (detail_str);
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+
+ type_error:
+ PyErr_SetString (PyExc_RuntimeError,
+ _("The Python function 'print_one_detail' must return " \
+ "a string."));
+ gdbpy_print_stack ();
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+
+ python_error:
+ gdbpy_print_stack ();
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+}
+
+/* Implement the breakpoint_ops "print_mention" function. This function
+ calls the corresponding Python function and expects a String in
+ return. The returned string will be printed when the breakpoint is
+ created. */
+static void
+pybp_print_mention (struct breakpoint *b)
+{
+ PyObject *self;
+ PyObject *result = NULL;
+ struct cleanup *cleanup;
+ struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch ();
+ char *mention_str = NULL;
+
+ self = find_python_obj (b);
+ cleanup = ensure_python_env (garch, current_language);
+ result = PyObject_CallMethod (self, "print_mention", NULL);
+
+ if (! result)
+ goto python_error;
+
+ if (! gdbpy_is_string (result))
+ goto type_error;
+
+ mention_str = gdbpy_obj_to_string (result);
+ if (! mention_str)
+ goto python_error;
+
+ ui_out_text (uiout, mention_str);
+ xfree (mention_str);
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+
+ type_error:
+ PyErr_SetString (PyExc_RuntimeError,
+ _("The Python function 'print_mention' must return " \
+ "a string."));
+ gdbpy_print_stack ();
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+
+ python_error:
+ gdbpy_print_stack ();
+ Py_XDECREF (result);
+ do_cleanups (cleanup);
+ return;
+}
+
+/* Implement the breakpoint_ops "print_it" function. This function
+ calls the corresponding Python function and expects a Tuple in
+ return. This Tuple must have two elements: a String or None
+ representing the breakpoint prelude, and an enum from
+ pybp_print_stop_actions representing the print action of the
+ breakpoint. */
+static enum print_stop_action
+pybp_print_it (struct breakpoint *b)
+{
+ PyObject *self;
+ PyObject *result = NULL;
+ PyObject *py_str = NULL;
+ PyObject *code;
+ struct cleanup *cleanup;
+ struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch ();
+ long action_code = 0;
+ char *desc = NULL;
+ int print_prelude = 1;
+
+ self = find_python_obj (b);
+ cleanup = ensure_python_env (garch, current_language);
+ result = PyObject_CallMethod (self, "print_stop_action", NULL);
+
+ if (result)
+ {
+ make_cleanup_py_decref (result);
+ if (! PyTuple_Check (result) || PyTuple_Size (result) != 2)
+ goto type_error;
+ }
+ else
+ goto python_error;
+
+ py_str = PyTuple_GetItem (result, 0);
+
+ if (! py_str)
+ goto python_error;
+
+ if (py_str == Py_None)
+ print_prelude = 0;
+ else
+ {
+ if (gdbpy_is_string (py_str))
+ {
+ desc = gdbpy_obj_to_string (py_str);
+ if (! desc)
+ goto python_error;
+ make_cleanup (xfree, desc);
+ }
+ else
+ goto type_error;
+ }
+
+ code = PyTuple_GetItem (result, 1);
+ if (! code)
+ goto python_error;
+
+ if (! PyInt_Check (code))
+ goto type_error;
+
+ action_code = PyInt_AsLong (code);
+
+ /* The action_code might just be -1 'as normal' without a
+ Python error, so we have to check both. */
+ if ((action_code == -1) && (PyErr_Occurred ()))
+ goto python_error;
+
+ if ((action_code != PRINT_SRC_AND_LOC)
+ && (action_code != PRINT_SRC_ONLY)
+ && (action_code != PRINT_NOTHING))
+ goto type_error;
+
+ if (print_prelude)
+ ui_out_text (uiout, desc);
+
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_string (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+ ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+ }
+
+ do_cleanups (cleanup);
+
+ return action_code;
+
+ type_error:
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Function print_stop_action has to return " \
+ "a tuple with two elements."));
+ gdbpy_print_stack ();
+ do_cleanups (cleanup);
+ return PRINT_UNKNOWN;
+
+ python_error:
+ gdbpy_print_stack ();
+ do_cleanups (cleanup);
+ return PRINT_UNKNOWN;
+}
+
+/* Build the breakpoint_ops structure. Examine the contents of the
+ Python object and only add the specific functions that have been
+ implemented. */
+static void
+bppy_build_ops (PyObject *self)
+{
+ if (PyObject_HasAttrString (self, "print_stop_action"))
+ py_breakpoint_ops.print_it = pybp_print_it;
+ if (PyObject_HasAttrString (self, "print_mention"))
+ py_breakpoint_ops.print_mention = pybp_print_mention;
+ if (PyObject_HasAttrString (self, "print_one"))
+ py_breakpoint_ops.print_one = pybp_print_one;
+ if (PyObject_HasAttrString (self, "print_one_detail"))
+ py_breakpoint_ops.print_one_detail = pybp_print_one_detail;
+}
+
/* Python function to create a new breakpoint. */
static int
bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
@@ -610,6 +976,7 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
&spec, &type, &access_type, &internal))
return -1;
+ bppy_build_ops (self);
if (internal)
{
internal_bp = PyObject_IsTrue (internal);
@@ -633,17 +1000,23 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
0, bp_breakpoint,
0,
AUTO_BOOLEAN_TRUE,
- NULL, 0, 1, internal_bp);
+ &py_breakpoint_ops,
+ 0, 1, internal_bp,
+ bppy_pending_object);
+
break;
}
case bp_watchpoint:
{
if (access_type == hw_write)
- watch_command_wrapper (spec, 0, internal_bp);
+ watch_command_wrapper (spec, 0, internal_bp,
+ bppy_pending_object);
else if (access_type == hw_access)
- awatch_command_wrapper (spec, 0, internal_bp);
+ awatch_command_wrapper (spec, 0, internal_bp,
+ bppy_pending_object);
else if (access_type == hw_read)
- rwatch_command_wrapper (spec, 0, internal_bp);
+ rwatch_command_wrapper (spec, 0, internal_bp,
+ bppy_pending_object);
else
error(_("Cannot understand watchpoint access type."));
break;
@@ -784,7 +1157,7 @@ gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj)
static void
gdbpy_breakpoint_created (struct breakpoint *bp)
{
- breakpoint_object *newbp;
+ breakpoint_object *newbp = NULL;
PyGILState_STATE state;
if (bp->number < 0 && bppy_pending_object == NULL)
@@ -805,12 +1178,25 @@ gdbpy_breakpoint_created (struct breakpoint *bp)
bppy_pending_object = NULL;
}
else
- newbp = PyObject_New (breakpoint_object, &breakpoint_object_type);
+ {
+ /* This breakpoint was not created by a Python API so create a
+ new object, and initialize the other storage elements. */
+ newbp = PyObject_New (breakpoint_object,
+ &breakpoint_object_type);
+ newbp->number = -1;
+ newbp->bp = NULL;
+ }
if (newbp)
{
newbp->number = bp->number;
- newbp->bp = bp;
- newbp->bp->py_bp_object = newbp;
+
+ /* Sometimes the bindings between breakpoint, and breakpoint
+ object are created early in create_breakpoint. If this is
+ the case do not overwrite. */
+ if (! newbp->bp)
+ newbp->bp = bp;
+ if (! newbp->bp->py_bp_object)
+ newbp->bp->py_bp_object = newbp;
Py_INCREF (newbp);
++bppy_live;
}
@@ -887,6 +1273,15 @@ gdbpy_initialize_breakpoints (void)
return;
}
+ /* Add print stop types constants. */
+ for (i = 0; pybp_print_stop_actions[i].name; ++i)
+ {
+ if (PyModule_AddIntConstant (gdb_module,
+ /* Cast needed for Python 2.4. */
+ (char *) pybp_print_stop_actions[i].name,
+ pybp_print_stop_actions[i].code) < 0)
+ return;
+ }
}
\f
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index b65109d..ccfd796 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -130,6 +130,18 @@ typedef struct
PyObject *inf_obj;
} thread_object;
+struct breakpoint_object
+{
+ PyObject_HEAD
+
+ /* The breakpoint number according to gdb. */
+ int number;
+
+ /* The gdb breakpoint object, or NULL if the breakpoint has been
+ deleted. */
+ struct breakpoint *bp;
+};
+
extern struct cmd_list_element *set_python_list;
extern struct cmd_list_element *show_python_list;
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 8a7bc66..bea34aa 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -190,6 +190,20 @@ eval_python_from_control_command (struct command_line *cmd)
do_cleanups (cleanup);
}
+/* Bind a breakpoint to a breakpoint object. */
+
+void
+gdbpy_bind_breakpoint (struct breakpoint_object *obj,
+ struct breakpoint *b)
+{
+ if (obj && b)
+ {
+ obj->bp = b;
+ obj->number = b->number;
+ b->py_bp_object = obj;
+ }
+}
+
/* Implementation of the gdb "python" command. */
static void
diff --git a/gdb/python/python.h b/gdb/python/python.h
index ce0eb35..a51b592 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -32,6 +32,9 @@ void eval_python_from_control_command (struct command_line *);
void source_python_script (FILE *stream, const char *file);
+void gdbpy_bind_breakpoint (struct breakpoint_object *obj,
+ struct breakpoint *b);
+
int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp
index f0a83f1..945cfee 100644
--- a/gdb/testsuite/gdb.python/py-breakpoint.exp
+++ b/gdb/testsuite/gdb.python/py-breakpoint.exp
@@ -293,3 +293,72 @@ gdb_py_test_silent_cmd "python wp1 = wp_eval (\"result\", type=gdb.BP_WATCHPOIN
gdb_test "continue" ".*\[Ww\]atchpoint.*result.*Old value =.*New value = 788.*" "Test watchpoint write"
gdb_test "python print never_eval_bp1.count" "0" \
"Check that this unrelated breakpoints eval function was never called."
+
+# Breakpoint operations.
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+if ![runto_main] then {
+ fail "Cannot run to main."
+ return 0
+}
+delete_breakpoints
+
+set bp_location [gdb_get_line_number "Break at multiply."]
+set bp_location2 [gdb_get_line_number "Break at add."]
+set bp_location3 [gdb_get_line_number "Break at end."]
+
+gdb_py_test_multiple "Breakpoint with operations" \
+ "python" "" \
+ "class bp_oper (gdb.Breakpoint):" "" \
+ " def print_mention (self):" "" \
+ " return \"Special Breakpoint \"+str(self.number)+\" at \"+str(self.location)" "" \
+ " def print_stop_action (self):" "" \
+ " return (\"Testcase Breakpoint, \",gdb.PRINT_SRC_AND_LOC)" "" \
+ " def print_one (self, address):" "" \
+ " return (address,\"Test-case breakpoint\")" "" \
+ " def print_one_detail (self):" "" \
+ " return \"TS breakpoint at \"+str(self.location)+\"\\n\"" "" \
+ "end" ""
+
+gdb_py_test_multiple "Breakpoint with operations" \
+ "python" "" \
+ "class bp_oper_source (bp_oper):" "" \
+ " def print_stop_action (self):" "" \
+ " return (\"Testcase Breakpoint, \",gdb.PRINT_SRC_ONLY)" "" \
+ " return gdb.PRINT_SRC_ONLY" "" \
+ "end" ""
+
+gdb_py_test_multiple "Breakpoint with operations" \
+ "python" "" \
+ "class bp_oper_nothing (bp_oper):" "" \
+ " def print_stop_action (self):" "" \
+ " return (\"Print Nothing\\n\", gdb.PRINT_NOTHING)" "" \
+ "end" ""
+
+gdb_test "python foo = bp_oper(\"$bp_location\")" \
+ "Special Breakpoint.*at.*py-breakpoint\.c:41" \
+ "Test breakpoint ops mention"
+
+gdb_test "continue" ".*Testcase Breakpoint.*$srcfile:$bp_location.*" \
+ "Test PRINT_SRC_AND_LOC with preamble"
+delete_breakpoints
+
+gdb_test "python foo = bp_oper_source(\"$bp_location2\")" \
+ "Special Breakpoint.*at.*py-breakpoint\.c:42" \
+ "Test breakpoint ops mention"
+
+gdb_test "continue" ".*Testcase Breakpoint.*$bp_location2.*" \
+ "Test PRINT_SRC_ONLY with preamble"
+delete_breakpoints
+
+gdb_test "python nothing = bp_oper_nothing(\"$bp_location3\")" \
+ "Special Breakpoint.*at.*py-breakpoint\.c:45" \
+ "Test breakpoint ops mention"
+
+gdb_test "continue" ".*Print Nothing.*" \
+ "Test PRINT_NOTHING with preamble"
+
+gdb_test "info breakpoints" \
+ "breakpoint.*keep.*y.*$hex.*Test-case breakpoint.*TS breakpoint.*at.*py-breakpoint.*" \
+ "Check info breakpoints shows breakpoint op breakpoints"
diff --git a/gdb/testsuite/gdb.python/py-mi-bp.py b/gdb/testsuite/gdb.python/py-mi-bp.py
index e69de29..99c12cd 100644
--- a/gdb/testsuite/gdb.python/py-mi-bp.py
+++ b/gdb/testsuite/gdb.python/py-mi-bp.py
@@ -0,0 +1,32 @@
+# Copyright (C) 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests python pretty
+# printers.
+
+class mi_bp (gdb.Breakpoint):
+
+ def print_mention (self):
+ return "MI Testcase Breakpoint " + str (self.number) + " at " + str (self.location)
+
+ def print_stop_action (self):
+ return ("MI Testcase Breakpoint, ", gdb.PRINT_SRC_AND_LOC)
+
+ def print_one (self, address):
+ return (address,"MI Testcase Breakpoint")
+
+ def print_one_detail (self):
+ return "MI Testcase Breakpoint at " + str (self.location) + "\n"
+
diff --git a/gdb/testsuite/gdb.python/py-mi.exp b/gdb/testsuite/gdb.python/py-mi.exp
index 2e4d12b..0f1da26 100644
--- a/gdb/testsuite/gdb.python/py-mi.exp
+++ b/gdb/testsuite/gdb.python/py-mi.exp
@@ -17,6 +17,8 @@
# pretty-printing for MI.
load_lib mi-support.exp
+load_lib gdb-python.exp
+
set MIFLAGS "-i=mi2"
gdb_exit
@@ -28,6 +30,8 @@ set testfile "py-mi"
set srcfile py-prettyprint.c
set binfile ${objdir}/${subdir}/${testfile}
set pyfile py-prettyprint.py
+set py_bpfile py-mi-bp.py
+
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } {
untested ${testfile}.exp
return -1
@@ -284,6 +288,32 @@ mi_list_varobj_children nstype2 {
{ {nstype2.<error at 0>} {<error at 0>} 6 {char \[6\]} }
} "list children after setting exception flag"
+# Test breakpoint ops
+gdb_exit
+if [mi_gdb_start] {
+ continue
+}
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+mi_runto main
+set bp_location [gdb_get_line_number {MI breakpoint here} ${srcfile}]
+set remote_python_bp_file [remote_download host ${srcdir}/${subdir}/${py_bpfile}]
+mi_gdb_test "python execfile ('${remote_python_bp_file}')" ""
+
+mi_gdb_test "python mi_bp_i = mi_bp(\"$bp_location\")" \
+ ".*\"MI Testcase Breakpoint.*=breakpoint-created,bkpt=\{number=\".*\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\".*\",what=\"MI Testcase Breakpoint\",times=\"0\",original-location=\".*\"\}.*" \
+ "Test breakpoint ops mention"
+
+mi_gdb_test "continue" \
+ ".*breakpoint-modified,bkpt={number=\".*\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\".*\",what=\"MI Testcase Breakpoint\",times=\"1\",original-location=\".*py-prettyprint.c.*\".*MI Testcase Breakpoint, main.*at.*py-prettyprint.c.*" \
+ "Test print_one"
+
+mi_gdb_test "-break-list" \
+ ".*BreakpointTable=\{nr_rows=\"1\",nr_cols=\"6\",hdr=\\\[\{width=\"7\",alignment=\"-1\",col_name=\"number\",colhdr=\"Num\"\},\{width=\"14\",alignment=\"-1\",col_name=\"type\",colhdr=\"Type\"\},\{width=\"4\",alignment=\"-1\",col_name=\"disp\",colhdr=\"Disp\"\},\{width=\"3\",alignment=\"-1\",col_name=\"enabled\",colhdr=\"Enb\"\},\{width=\"18\",alignment=\"-1\",col_name=\"addr\",colhdr=\"Address\"\},\{width=\"40\",alignment=\"2\",col_name=\"what\",colhdr=\"What\"\}\\\],body=\\\[bkpt=\{number=\"2\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\".*\",what=\"MI Testcase Breakpoint\",times=\"1\",original-location=\".*py-prettyprint.c.*\"\}\\\]\}" \
+ "list of breakpoints"
+
# C++ MI tests
gdb_exit
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [patch] [python] Expose some breakpoint operations to Python 2011-06-23 12:35 [patch] [python] Expose some breakpoint operations to Python Phil Muldoon @ 2011-06-23 13:19 ` Eli Zaretskii 2011-06-23 14:07 ` Pedro Alves 1 sibling, 0 replies; 12+ messages in thread From: Eli Zaretskii @ 2011-06-23 13:19 UTC (permalink / raw) To: pmuldoon; +Cc: gdb-patches > From: Phil Muldoon <pmuldoon@redhat.com> > Date: Thu, 23 Jun 2011 13:35:02 +0100 > > 2011-06-23 pmuldoon <pmuldoon@redhat.com> > > * gdb.texinfo (Breakpoints In Python): Document breakpoint > operation APIs. Thanks. > +detailed below. These methods influence how GDB operates with certain ^^^ "@value{GDBN}" > +@defop Operation {gdb.Breakpoint} stop (self) > +The @code{stop} method may be implemented as part of a > +@code{gdb.Breakpoint}. I'm not sure we need this sentence. You already say above that these methods can be part of sub-classing the gdb.Breakpoint class. And we certainly don't need to repeat this sentence for each method. > +@smallexample > +class MyBreakpoint (gdb.Breakpoint): > + > + def print_mention (self): > + return "Our Breakpoint " + str(self.number) + " at " + str(self.location) > +@end smallexample The line that begins with "return" is too long, please break it in two. > +Python @code{Tuple}. The first element of the tuple should be a > +string that defines the breakpoint prelude. The prelude is printed > +before the breakpoint location information is printed. If a prelude > +is not needed, Python @code{None} can be returned instead. The last sentence could use some improvement. First, "can be" is not really right: using None is a must in this case, AFAICT. And second, "returned" is not right either. How about this variant: If no prelude should be printed, the first element should be @code{None}. > +@item PRINT_SRC_AND_LOC > +Print the source line number and location information associated with > +this breakpoint. What is "location" in this context? This should be clearly documented, because the example you show is ambiguous. > +@item PRINT_NOTHING > +Do not print any breakpoint information. Would it be a good idea to tell under which circumstances would this option be useful? > +The @code{print_one} method may be implemented as part of a > +@code{gdb.Breakpoint}. This method will be called when information is > +requested on a breakpoint (such as the @value {GDBN} command, > +@samp{info breakpoints}). ^ That comma should be removed. > The @code{address} parameter Parameters should have the @var markup, not @code. > +contains the address where @value{GDBN} stopped the inferior. This > +method must return a Python @code{Tuple}. The first element of the > +tuple should be a Python @code{Long} that contains the address that is > +to be printed in the informational output, or @code{None}. If > +@code{None} is returned, address information will not be printed. The > +second element should be a Python string giving a very brief > +description of the breakpoint, or Python @code{None} if you do not > +want to print anything for that field. I think this description should clearly indicate the fields of the normal output of "info breakpoints" which can be customized by implementing this method. Also, what does None mean in terms of formatting: is the value get replaced by blanks, or do the next fields get shifted to the left (and thus their formatting gets messed up)? Or maybe the "Address" column be removed from the display entirely? The example you show does not answer these questions, because it shows a more-or-less default display of a breakpoint. Btw, what's the point of passing the address to this method, if it should return it? Is there any reason that users will want to return some value other than the address itself or None? > +@defop Operation {gdb.Breakpoint} print_one (self, address) ^^^^^^^^^ Cut/paste error: this should be print_one_detail. > +The @code{print_one_detail} method may be implemented as part of a > +@code{gdb.Breakpoint}. This method is a companion method to > +@samp{print_one} (@pxref{print_one}). This method will be called when > +information is requested on a breakpoint (such as the @value {GDBN} > +command, @samp{info breakpoints}), and allows extra details to be ^ A redundant comma. > +printed about that breakpoint. This method must return a Python > +string containing brief supplemental information on that breakpoint. I wonder why we pass the address here. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch] [python] Expose some breakpoint operations to Python 2011-06-23 12:35 [patch] [python] Expose some breakpoint operations to Python Phil Muldoon 2011-06-23 13:19 ` Eli Zaretskii @ 2011-06-23 14:07 ` Pedro Alves 2011-06-23 14:46 ` Phil Muldoon 1 sibling, 1 reply; 12+ messages in thread From: Pedro Alves @ 2011-06-23 14:07 UTC (permalink / raw) To: gdb-patches, pmuldoon On Thursday 23 June 2011 13:35:02, Phil Muldoon wrote: > This patch exposes to the Python API some breakpoint operations. The > operations exported are: > > print_it > print_one > print_one_detail > print_mention > > One of the changes made in this patch is to bind the Python breakpoint > and the GDB breakpoint much earlier if the breakpoint is created from > the Python API. This change was needed as some breakpoint operations > are called before the observers are notified. Previously we bound the > Python object and the breakpoint when the observer was notified. In the > case where a breakpoint is not created from the Python API this is still > the case. In any case, the ordering of breakpoint operations and > breakpoint observers means we have to bind some breakpoints at > creation. This has meant we have had to alter some of the breakpoint > APIs to carry the breakpoint object in the parameter list at creation. > > I've included both MI and CLI tests. These are very similar. The MI > tests are needed to prove that the exported Python APIs work > seamlessly with MI notifications. > > Tested on X8664 Fedora 15 with no regressions. > > What do you think? Well, here's my kneee jerk reaction. Last night I started converting all breakpoints to use breakpoint_ops, and I immediately stumbled on the fact that the print_one method doesn't appear to work as is. I don't like the idea of exposing the API as is and getting stuck with it when we haven't even made sure it's a good fit for gdb's own regular breakpoints. :-( -- Pedro Alves ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch] [python] Expose some breakpoint operations to Python 2011-06-23 14:07 ` Pedro Alves @ 2011-06-23 14:46 ` Phil Muldoon 2011-06-23 15:30 ` Pedro Alves 0 siblings, 1 reply; 12+ messages in thread From: Phil Muldoon @ 2011-06-23 14:46 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Pedro Alves <pedro@codesourcery.com> writes: >> What do you think? > > Well, here's my kneee jerk reaction. Last night I started converting > all breakpoints to use breakpoint_ops, and I immediately stumbled on > the fact that the print_one method doesn't appear to work as is. I > don't like the idea of exposing the API as is and getting stuck > with it when we haven't even made sure it's a good fit for > gdb's own regular breakpoints. :-( I'm curious to know what is wrong with it. print_one just passes the breakpoint and the address to the consumer, and the consumer then just prints to the "Addr" and "What" fields. In the strict context of the API, it works in the Python tests. Can you expand on that instance? OTOH, in a larger sense, I agree with your internal API statement. If it is not suitable yet, we should not expose it yet. For example the "print_it" enum 'SRC_ONLY' just prints a source-line number (without a file). I cannot fathom how it would be useful. Then again, there is lots that I do not consider useful, but it is in some other GDB context. If you have a plan for the API, could your write it up? I am ready and willing to help out wherever and whenever needed. Cheers Phil -- Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham (USA), Brendan Lane (Ireland), Matt Parson (USA), Charlie Peters (USA) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch] [python] Expose some breakpoint operations to Python 2011-06-23 14:46 ` Phil Muldoon @ 2011-06-23 15:30 ` Pedro Alves 2011-06-23 15:57 ` Phil Muldoon 0 siblings, 1 reply; 12+ messages in thread From: Pedro Alves @ 2011-06-23 15:30 UTC (permalink / raw) To: gdb-patches, pmuldoon On Thursday 23 June 2011 15:46:14, Phil Muldoon wrote: > Pedro Alves <pedro@codesourcery.com> writes: > > >> What do you think? > > > > Well, here's my kneee jerk reaction. Last night I started converting > > all breakpoints to use breakpoint_ops, and I immediately stumbled on > > the fact that the print_one method doesn't appear to work as is. I > > don't like the idea of exposing the API as is and getting stuck > > with it when we haven't even made sure it's a good fit for > > gdb's own regular breakpoints. :-( > > I'm curious to know what is wrong with it. print_one just passes the > breakpoint and the address to the consumer, and the consumer then just > prints to the "Addr" and "What" fields. In the strict context of the > API, it works in the Python tests. > > Can you expand on that instance? ... > > If you have a plan for the API, could your write it up? I am ready and > willing to help out wherever and whenever needed. No plan yet. I just started out by adding a single breakpoint_ops instance that handles all breakpoint types that currently aren't using breakpoint_ops, and moving all default actions to the corresponding callback. This would be straightforward if the API is a good fit. But take a look at the fallback code in print_one_breakpoint_location, and print_one_breakpoint. Breakpoints with multiple locations are handled a bit differently than just a fallbach, with multiple calls to print_one_breakpoint. Maybe we could move all that !print_one code inside the new print_one callback? Not sure. Also, maybe we should split printing the "what" from the "address"? Not sure either, but it looks bizarre to me that current print_one implementations need to know to call annotate_field. Then there are implementations that print free form text surrounding those values, e.g., see print_one_catch_vfork. These issues certainly inpact the python api. (You'll also note that the ->insert_location and ->remove_location call sites reveal that something isn't fully abstracted, since failing to insert different kinds of breakpoints leads to different reactions in the code). Note, the doesn't even compile. Something else that's obviously missing with exposing breakpoint_ops to python as is (yes I know you haven't exported all of it), is that most certainly users will want to be able to call the "super" method. That is, say, e.g, override, the ->check_status method, and still call the default method, whatever it was. > OTOH, in a larger sense, I agree with your internal API statement. If > it is not suitable yet, we should not expose it yet. For example the > "print_it" enum 'SRC_ONLY' just prints a source-line number (without a > file). I cannot fathom how it would be useful. Well, what does grep tell us? breakpoint.c: PRINT_SRC_ONLY: Means we printed something, and we do *not* desire breakpoint.c: PRINT_SRC_ONLY: Means we printed something, but there is no need breakpoint.c: if (val == PRINT_SRC_ONLY breakpoint.h: PRINT_SRC_ONLY, infrun.c: case PRINT_SRC_ONLY: Looks like it's never used? Maybe gdbtk uses it, haven't checked. Certainly a good example of that cleaning up the house a little before exposing the API is a good idea. > Then again, there is > lots that I do not consider useful, but it is in some other GDB context. -- Pedro Alves --- gdb/breakpoint.c | 1539 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 802 insertions(+), 737 deletions(-) Index: src/gdb/breakpoint.c =================================================================== --- src.orig/gdb/breakpoint.c 2011-06-23 01:25:32.000000000 +0100 +++ src/gdb/breakpoint.c 2011-06-23 15:59:56.489910546 +0100 @@ -104,9 +104,7 @@ static void break_command_1 (char *, int static void mention (struct breakpoint *); -/* This function is used in gdbtk sources and thus can not be made - static. */ -struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch, +static struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line, enum bptype); @@ -1436,10 +1434,7 @@ update_watchpoint (struct breakpoint *b, (b->type, i, other_type_used); if (target_resources_ok <= 0) { - /* If there's no works_in_software_mode method, we - assume that the watchpoint works in software mode. */ - int sw_mode = (!b->ops || !b->ops->works_in_software_mode - || b->ops->works_in_software_mode (b)); + int sw_mode = b->ops->works_in_software_mode (b); if (target_resources_ok == 0 && !sw_mode) error (_("Target does not support this type of " @@ -1451,8 +1446,7 @@ update_watchpoint (struct breakpoint *b, b->type = bp_watchpoint; } } - else if (b->ops && b->ops->works_in_software_mode - && !b->ops->works_in_software_mode (b)) + else if (!b->ops->works_in_software_mode (b)) error (_("Expression cannot be implemented with " "read/access watchpoint.")); else @@ -1555,127 +1549,11 @@ insert_bp_location (struct bp_location * bl->target_info.placed_address_space = bl->pspace->aspace; bl->target_info.length = bl->length; + val = bl->owner->ops->insert_location (bl); + if (bl->loc_type == bp_loc_software_breakpoint || bl->loc_type == bp_loc_hardware_breakpoint) { - if (bl->owner->type != bp_hardware_breakpoint) - { - /* If the explicitly specified breakpoint type - is not hardware breakpoint, check the memory map to see - if the breakpoint address is in read only memory or not. - - Two important cases are: - - location type is not hardware breakpoint, memory - is readonly. We change the type of the location to - hardware breakpoint. - - location type is hardware breakpoint, memory is - read-write. This means we've previously made the - location hardware one, but then the memory map changed, - so we undo. - - When breakpoints are removed, remove_breakpoints will use - location types we've just set here, the only possible - problem is that memory map has changed during running - program, but it's not going to work anyway with current - gdb. */ - struct mem_region *mr - = lookup_mem_region (bl->target_info.placed_address); - - if (mr) - { - if (automatic_hardware_breakpoints) - { - enum bp_loc_type new_type; - - if (mr->attrib.mode != MEM_RW) - new_type = bp_loc_hardware_breakpoint; - else - new_type = bp_loc_software_breakpoint; - - if (new_type != bl->loc_type) - { - static int said = 0; - - bl->loc_type = new_type; - if (!said) - { - fprintf_filtered (gdb_stdout, - _("Note: automatically using " - "hardware breakpoints for " - "read-only addresses.\n")); - said = 1; - } - } - } - else if (bl->loc_type == bp_loc_software_breakpoint - && mr->attrib.mode != MEM_RW) - warning (_("cannot set software breakpoint " - "at readonly address %s"), - paddress (bl->gdbarch, bl->address)); - } - } - - /* First check to see if we have to handle an overlay. */ - if (overlay_debugging == ovly_off - || bl->section == NULL - || !(section_is_overlay (bl->section))) - { - /* No overlay handling: just set the breakpoint. */ - - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_insert_hw_breakpoint (bl->gdbarch, - &bl->target_info); - else - val = target_insert_breakpoint (bl->gdbarch, - &bl->target_info); - } - else - { - /* This breakpoint is in an overlay section. - Shall we set a breakpoint at the LMA? */ - if (!overlay_events_enabled) - { - /* Yes -- overlay event support is not active, - so we must try to set a breakpoint at the LMA. - This will not work for a hardware breakpoint. */ - if (bl->loc_type == bp_loc_hardware_breakpoint) - warning (_("hardware breakpoint %d not supported in overlay!"), - bl->owner->number); - else - { - CORE_ADDR addr = overlay_unmapped_address (bl->address, - bl->section); - /* Set a software (trap) breakpoint at the LMA. */ - bl->overlay_target_info = bl->target_info; - bl->overlay_target_info.placed_address = addr; - val = target_insert_breakpoint (bl->gdbarch, - &bl->overlay_target_info); - if (val != 0) - fprintf_unfiltered (tmp_error_stream, - "Overlay breakpoint %d " - "failed: in ROM?\n", - bl->owner->number); - } - } - /* Shall we set a breakpoint at the VMA? */ - if (section_is_mapped (bl->section)) - { - /* Yes. This overlay section is mapped into memory. */ - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_insert_hw_breakpoint (bl->gdbarch, - &bl->target_info); - else - val = target_insert_breakpoint (bl->gdbarch, - &bl->target_info); - } - else - { - /* No. This breakpoint will not be inserted. - No error, but do not mark the bp as 'inserted'. */ - return 0; - } - } - if (val) { /* Can't set the breakpoint. */ @@ -1734,11 +1612,6 @@ insert_bp_location (struct bp_location * watchpoints. It's not clear that it's necessary... */ && bl->owner->disposition != disp_del_at_next_stop) { - gdb_assert (bl->owner->ops != NULL - && bl->owner->ops->insert_location != NULL); - - val = bl->owner->ops->insert_location (bl); - /* If trying to set a read-watchpoint, and it turns out it's not supported, try emulating one with an access watchpoint. */ if (val == 1 && bl->watchpoint_type == hw_read) @@ -1777,10 +1650,6 @@ insert_bp_location (struct bp_location * else if (bl->owner->type == bp_catchpoint) { - gdb_assert (bl->owner->ops != NULL - && bl->owner->ops->insert_location != NULL); - - val = bl->owner->ops->insert_location (bl); if (val) { bl->owner->enable_state = bp_disabled; @@ -2537,74 +2406,7 @@ remove_breakpoint_1 (struct bp_location if (bl->loc_type == bp_loc_software_breakpoint || bl->loc_type == bp_loc_hardware_breakpoint) { - /* "Normal" instruction breakpoint: either the standard - trap-instruction bp (bp_breakpoint), or a - bp_hardware_breakpoint. */ - - /* First check to see if we have to handle an overlay. */ - if (overlay_debugging == ovly_off - || bl->section == NULL - || !(section_is_overlay (bl->section))) - { - /* No overlay handling: just remove the breakpoint. */ - - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info); - else - val = target_remove_breakpoint (bl->gdbarch, &bl->target_info); - } - else - { - /* This breakpoint is in an overlay section. - Did we set a breakpoint at the LMA? */ - if (!overlay_events_enabled) - { - /* Yes -- overlay event support is not active, so we - should have set a breakpoint at the LMA. Remove it. - */ - /* Ignore any failures: if the LMA is in ROM, we will - have already warned when we failed to insert it. */ - if (bl->loc_type == bp_loc_hardware_breakpoint) - target_remove_hw_breakpoint (bl->gdbarch, - &bl->overlay_target_info); - else - target_remove_breakpoint (bl->gdbarch, - &bl->overlay_target_info); - } - /* Did we set a breakpoint at the VMA? - If so, we will have marked the breakpoint 'inserted'. */ - if (bl->inserted) - { - /* Yes -- remove it. Previously we did not bother to - remove the breakpoint if the section had been - unmapped, but let's not rely on that being safe. We - don't know what the overlay manager might do. */ - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_remove_hw_breakpoint (bl->gdbarch, - &bl->target_info); - - /* However, we should remove *software* breakpoints only - if the section is still mapped, or else we overwrite - wrong code with the saved shadow contents. */ - else if (section_is_mapped (bl->section)) - val = target_remove_breakpoint (bl->gdbarch, - &bl->target_info); - else - val = 0; - } - else - { - /* No -- not inserted, so no need to remove. No error. */ - val = 0; - } - } - - /* In some cases, we might not be able to remove a breakpoint - in a shared library that has already been removed, but we - have not yet processed the shlib unload event. */ - if (val && solib_name_from_address (bl->pspace, bl->address)) - val = 0; - + val = bl->owner->ops->remove_location (bl); if (val) return val; bl->inserted = (is == mark_inserted); @@ -2626,9 +2428,6 @@ remove_breakpoint_1 (struct bp_location && breakpoint_enabled (bl->owner) && !bl->duplicate) { - gdb_assert (bl->owner->ops != NULL - && bl->owner->ops->remove_location != NULL); - val = bl->owner->ops->remove_location (bl); if (val) return val; @@ -3549,12 +3348,8 @@ print_bp_stop_message (bpstat bs) if (b == NULL) return PRINT_UNKNOWN; - /* Normal case. Call the breakpoint's print_it method, or - print_it_typical. */ - if (b->ops != NULL && b->ops->print_it != NULL) - return b->ops->print_it (b); - else - return print_it_typical (bs); + /* Normal case. Call the breakpoint's print_it method. */ + return b->ops->print_it (b); } break; @@ -3873,60 +3668,19 @@ which its expression is valid.\n"); } /* Return true if it looks like target has stopped due to hitting - breakpoint location BL. This function does not check if we - should stop, only if BL explains the stop. */ + breakpoint location BL. This function does not check if we should + stop, only if BL explains the stop. */ + static int bpstat_check_location (const struct bp_location *bl, struct address_space *aspace, CORE_ADDR bp_addr) { struct breakpoint *b = bl->owner; - /* BL is from existing struct breakpoint. */ + /* BL is from an existing breakpoint. */ gdb_assert (b != NULL); - if (b->ops && b->ops->breakpoint_hit) - return b->ops->breakpoint_hit (bl, aspace, bp_addr); - - /* By definition, the inferior does not report stops at - tracepoints. */ - if (is_tracepoint (b)) - return 0; - - if (!is_watchpoint (b) - && b->type != bp_hardware_breakpoint - && b->type != bp_catchpoint) /* a non-watchpoint bp */ - { - if (!breakpoint_address_match (bl->pspace->aspace, bl->address, - aspace, bp_addr)) - return 0; - if (overlay_debugging /* unmapped overlay section */ - && section_is_overlay (bl->section) - && !section_is_mapped (bl->section)) - return 0; - } - - /* Continuable hardware watchpoints are treated as non-existent if the - reason we stopped wasn't a hardware watchpoint (we didn't stop on - some data address). Otherwise gdb won't stop on a break instruction - in the code (not from a breakpoint) when a hardware watchpoint has - been defined. Also skip watchpoints which we know did not trigger - (did not match the data address). */ - - if (is_hardware_watchpoint (b) - && b->watchpoint_triggered == watch_triggered_no) - return 0; - - if (b->type == bp_hardware_breakpoint) - { - if (bl->address != bp_addr) - return 0; - if (overlay_debugging /* unmapped overlay section */ - && section_is_overlay (bl->section) - && !section_is_mapped (bl->section)) - return 0; - } - - return 1; + return b->ops->breakpoint_hit (bl, aspace, bp_addr); } /* If BS refers to a watchpoint, determine if the watched values @@ -4307,27 +4061,11 @@ bpstat_stop_status (struct address_space if (!bs->stop) continue; - bpstat_check_watchpoint (bs); - if (!bs->stop) - continue; - b = bs->breakpoint_at; - - if (b->ops != NULL && b->ops->check_status != NULL) + b->ops->check_status (bs); + if (bs->stop) { - b->ops->check_status (bs); - if (!bs->stop) - continue; - } - - if (b->type == bp_thread_event || b->type == bp_overlay_event - || b->type == bp_longjmp_master - || b->type == bp_std_terminate_master - || b->type == bp_exception_master) - /* We do not stop for these. */ - bs->stop = 0; - else - bpstat_check_breakpoint_conditions (bs, ptid); + bpstat_check_breakpoint_conditions (bs, ptid); if (bs->stop) { @@ -4360,6 +4098,7 @@ bpstat_stop_status (struct address_space /* Print nothing for this entry if we dont stop or dont print. */ if (bs->stop == 0 || bs->print == 0) bs->print_it = print_it_noop; + } } /* If we aren't stopping, the value of some hardware watchpoint may @@ -4992,20 +4731,10 @@ print_one_breakpoint_location (struct br ui_out_text (uiout, "\n"); - if (!part_of_multiple && b->ops && b->ops->print_one_detail) + if (!part_of_multiple) b->ops->print_one_detail (b, uiout); - if (!part_of_multiple && b->static_trace_marker_id) - { - gdb_assert (b->type == bp_static_tracepoint); - - ui_out_text (uiout, "\tmarker id is "); - ui_out_field_string (uiout, "static-tracepoint-marker-string-id", - b->static_trace_marker_id); - ui_out_text (uiout, "\n"); - } - - if (part_of_multiple && frame_id_p (b->frame_id)) + if (part_of_multiple && frame_id_p (b->frame_id)) { annotate_field (6); ui_out_text (uiout, "\tstop only in stack frame at "); @@ -5753,28 +5482,13 @@ init_bp_location (struct bp_location *lo static struct bp_location * allocate_bp_location (struct breakpoint *bpt) { - struct bp_location *loc; - - if (bpt->ops && bpt->ops->allocate_location) - return bpt->ops->allocate_location (bpt); - - loc = xmalloc (sizeof (struct bp_location)); - init_bp_location (loc, NULL, bpt); - return loc; + return bpt->ops->allocate_location (bpt); } static void free_bp_location (struct bp_location *loc) { - if (loc->ops && loc->ops->dtor) - loc->ops->dtor (loc); - - if (loc->cond) - xfree (loc->cond); - - if (loc->function_name) - xfree (loc->function_name); - + loc->ops->dtor (loc); xfree (loc); } @@ -5992,13 +5706,13 @@ init_raw_breakpoint (struct breakpoint * prior to completing the initialization of the breakpoint. If this should happen, a bogus breakpoint will be left on the chain. */ -struct breakpoint * +static struct breakpoint * set_raw_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal, enum bptype bptype) { struct breakpoint *b = XNEW (struct breakpoint); - init_raw_breakpoint (b, gdbarch, sal, bptype, NULL); + init_raw_breakpoint (b, gdbarch, sal, bptype, &bkpt_ops); add_to_breakpoint_chain (b); return b; } @@ -7054,10 +6768,7 @@ hw_breakpoint_used_count (void) { /* Special types of hardware breakpoints may use more than one register. */ - if (b->ops && b->ops->resources_needed) - i += b->ops->resources_needed (bl); - else - i++; + i += b->ops->resources_needed (bl); } } @@ -7082,10 +6793,7 @@ hw_watchpoint_used_count (enum bptype ty { /* Special types of hardware watchpoints may use more than one register. */ - if (b->ops && b->ops->resources_needed) - i += b->ops->resources_needed (bl); - else - i++; + i += b->ops->resources_needed (bl); } else if (is_hardware_watchpoint (b)) *other_type_used = 1; @@ -7267,162 +6975,7 @@ set_momentary_breakpoint_at_pc (struct g static void mention (struct breakpoint *b) { - int say_where = 0; - struct cleanup *ui_out_chain; - struct value_print_options opts; - - get_user_print_options (&opts); - - if (b->ops != NULL && b->ops->print_mention != NULL) - b->ops->print_mention (b); - else - switch (b->type) - { - case bp_none: - printf_filtered (_("(apparently deleted?) Eventpoint %d: "), - b->number); - break; - case bp_watchpoint: - ui_out_text (uiout, "Watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_hardware_watchpoint: - ui_out_text (uiout, "Hardware watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_read_watchpoint: - ui_out_text (uiout, "Hardware read watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_access_watchpoint: - ui_out_text (uiout, "Hardware access (read/write) watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_breakpoint: - case bp_gnu_ifunc_resolver: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - if (b->disposition == disp_del) - printf_filtered (_("Temporary breakpoint")); - else - printf_filtered (_("Breakpoint")); - printf_filtered (_(" %d"), b->number); - if (b->type == bp_gnu_ifunc_resolver) - printf_filtered (_(" at gnu-indirect-function resolver")); - say_where = 1; - break; - case bp_hardware_breakpoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Hardware assisted breakpoint %d"), b->number); - say_where = 1; - break; - case bp_tracepoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Tracepoint")); - printf_filtered (_(" %d"), b->number); - say_where = 1; - break; - case bp_fast_tracepoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Fast tracepoint")); - printf_filtered (_(" %d"), b->number); - say_where = 1; - break; - case bp_static_tracepoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Static tracepoint")); - printf_filtered (_(" %d"), b->number); - say_where = 1; - break; - - case bp_until: - case bp_finish: - case bp_longjmp: - case bp_longjmp_resume: - case bp_exception: - case bp_exception_resume: - case bp_step_resume: - case bp_hp_step_resume: - case bp_call_dummy: - case bp_std_terminate: - case bp_watchpoint_scope: - case bp_shlib_event: - case bp_thread_event: - case bp_overlay_event: - case bp_jit_event: - case bp_longjmp_master: - case bp_std_terminate_master: - case bp_exception_master: - case bp_gnu_ifunc_resolver_return: - break; - } - - if (say_where) - { - /* i18n: cagney/2005-02-11: Below needs to be merged into a - single string. */ - if (b->loc == NULL) - { - printf_filtered (_(" (%s) pending."), b->addr_string); - } - else - { - if (opts.addressprint || b->source_file == NULL) - { - printf_filtered (" at "); - fputs_filtered (paddress (b->loc->gdbarch, b->loc->address), - gdb_stdout); - } - if (b->source_file) - printf_filtered (": file %s, line %d.", - b->source_file, b->line_number); - - if (b->loc->next) - { - struct bp_location *loc = b->loc; - int n = 0; - for (; loc; loc = loc->next) - ++n; - printf_filtered (" (%d locations)", n); - } - - } - } + b->ops->print_mention (b); if (ui_out_is_mi_like_p (uiout)) return; printf_filtered ("\n"); @@ -7496,8 +7049,6 @@ bp_loc_is_permanent (struct bp_location return retval; } - - /* Create a breakpoint with SAL as location. Use ADDR_STRING as textual description of the location, and COND_STRING as condition expression. */ @@ -10799,127 +10350,801 @@ bpstat_remove_breakpoint_callback (struc return 0; } -/* Delete a breakpoint and clean up all traces of it in the data - structures. */ +/* Default breakpoint_ops methods. */ -void -delete_breakpoint (struct breakpoint *bpt) +static void +bkpt_dtor (struct breakpoint *self) { - struct breakpoint *b; - - gdb_assert (bpt != NULL); + decref_counted_command_line (&self->commands); + xfree (self->cond_string); + xfree (self->cond_exp); + xfree (self->addr_string); + xfree (self->addr_string_range_end); + xfree (self->exp); + xfree (self->exp_string); + xfree (self->exp_string_reparse); + value_free (self->val); + xfree (self->source_file); +} - /* Has this bp already been deleted? This can happen because - multiple lists can hold pointers to bp's. bpstat lists are - especial culprits. +static struct bp_location * +bkpt_allocate_location (struct breakpoint *self) +{ + struct bp_location *loc; - One example of this happening is a watchpoint's scope bp. When - the scope bp triggers, we notice that the watchpoint is out of - scope, and delete it. We also delete its scope bp. But the - scope bp is marked "auto-deleting", and is already on a bpstat. - That bpstat is then checked for auto-deleting bp's, which are - deleted. + loc = XNEW (struct bp_location); + init_bp_location (loc, NULL, bpt); + return loc; +} - A real solution to this problem might involve reference counts in - bp's, and/or giving them pointers back to their referencing - bpstat's, and teaching delete_breakpoint to only free a bp's - storage when no more references were extent. A cheaper bandaid - was chosen. */ - if (bpt->type == bp_none) - return; +static enum print_stop_action +bkpt_print_it (bpstat bs) +{ + return print_it_typical (bs); +} - /* At least avoid this stale reference until the reference counting - of breakpoints gets resolved. */ - if (bpt->related_breakpoint != bpt) - { - struct breakpoint *related; +static int +bkpt_breakpoint_hit (const struct bp_location *bl, + struct address_space *aspace, CORE_ADDR bp_addr) +{ + struct breakpoint *b = bl->owner; - if (bpt->type == bp_watchpoint_scope) - watchpoint_del_at_next_stop (bpt->related_breakpoint); - else if (bpt->related_breakpoint->type == bp_watchpoint_scope) - watchpoint_del_at_next_stop (bpt); + /* By definition, the inferior does not report stops at + tracepoints. */ + if (is_tracepoint (b)) + return 0; - /* Unlink bpt from the bpt->related_breakpoint ring. */ - for (related = bpt; related->related_breakpoint != bpt; - related = related->related_breakpoint); - related->related_breakpoint = bpt->related_breakpoint; - bpt->related_breakpoint = bpt; + if (!is_watchpoint (b) + && b->type != bp_hardware_breakpoint + && b->type != bp_catchpoint) /* a non-watchpoint bp */ + { + if (!breakpoint_address_match (bl->pspace->aspace, bl->address, + aspace, bp_addr)) + return 0; + if (overlay_debugging /* unmapped overlay section */ + && section_is_overlay (bl->section) + && !section_is_mapped (bl->section)) + return 0; } - /* watch_command_1 creates a watchpoint but only sets its number if - update_watchpoint succeeds in creating its bp_locations. If there's - a problem in that process, we'll be asked to delete the half-created - watchpoint. In that case, don't announce the deletion. */ - if (bpt->number) - observer_notify_breakpoint_deleted (bpt); + /* Continuable hardware watchpoints are treated as non-existent if the + reason we stopped wasn't a hardware watchpoint (we didn't stop on + some data address). Otherwise gdb won't stop on a break instruction + in the code (not from a breakpoint) when a hardware watchpoint has + been defined. Also skip watchpoints which we know did not trigger + (did not match the data address). */ - if (breakpoint_chain == bpt) - breakpoint_chain = bpt->next; + if (is_hardware_watchpoint (b) + && b->watchpoint_triggered == watch_triggered_no) + return 0; - ALL_BREAKPOINTS (b) - if (b->next == bpt) + if (b->type == bp_hardware_breakpoint) { - b->next = bpt->next; - break; + if (bl->address != bp_addr) + return 0; + if (overlay_debugging /* unmapped overlay section */ + && section_is_overlay (bl->section) + && !section_is_mapped (bl->section)) + return 0; } - if (bpt->ops != NULL && bpt->ops->dtor != NULL) - bpt->ops->dtor (bpt); - - decref_counted_command_line (&bpt->commands); - xfree (bpt->cond_string); - xfree (bpt->cond_exp); - xfree (bpt->addr_string); - xfree (bpt->addr_string_range_end); - xfree (bpt->exp); - xfree (bpt->exp_string); - xfree (bpt->exp_string_reparse); - value_free (bpt->val); - xfree (bpt->source_file); - - - /* Be sure no bpstat's are pointing at the breakpoint after it's - been freed. */ - /* FIXME, how can we find all bpstat's? We just check stop_bpstat - in all threeds for now. Note that we cannot just remove bpstats - pointing at bpt from the stop_bpstat list entirely, as breakpoint - commands are associated with the bpstat; if we remove it here, - then the later call to bpstat_do_actions (&stop_bpstat); in - event-top.c won't do anything, and temporary breakpoints with - commands won't work. */ - - iterate_over_threads (bpstat_remove_breakpoint_callback, bpt); - - /* Now that breakpoint is removed from breakpoint list, update the - global location list. This will remove locations that used to - belong to this breakpoint. Do this before freeing the breakpoint - itself, since remove_breakpoint looks at location's owner. It - might be better design to have location completely - self-contained, but it's not the case now. */ - update_global_location_list (0); - + return 1; +} - /* On the chance that someone will soon try again to delete this - same bp, we mark it as deleted before freeing its storage. */ - bpt->type = bp_none; +static int +bkpt_check_status (bpstat bs) +{ + struct breakpoint *b = bs->breakpoint_at; - xfree (bpt); + if (is_watchpoint (b)) + bpstat_check_watchpoint (bs); + else if (b->type == bp_thread_event + || b->type == bp_overlay_event + || b->type == bp_longjmp_master + || b->type == bp_std_terminate_master + || b->type == bp_exception_master) + /* We do not stop for these. */ + bs->stop = 0; } static void -do_delete_breakpoint_cleanup (void *b) +bkpt_print_one (struct breakpoint *self, + struct bp_location *loc, + int header_of_multiple, + int part_of_multiple, + struct bp_location **last_loc) { - delete_breakpoint (b); -} + struct value_print_options opts; -struct cleanup * -make_cleanup_delete_breakpoint (struct breakpoint *b) -{ - return make_cleanup (do_delete_breakpoint_cleanup, b); + get_user_print_options (&opts); } -/* Iterator function to call a user-provided callback function once - for each of B and its related breakpoints. */ +/* Implement the "print_one_detail" breakpoint_ops method for regular + breakpoints. */ + +static void +bkpt_print_one_detail (const struct breakpoint *self, + struct ui_out *uiout) +{ + if (self->static_trace_marker_id) + { + gdb_assert (self->type == bp_static_tracepoint); + + ui_out_text (uiout, "\tmarker id is "); + ui_out_field_string (uiout, "static-tracepoint-marker-string-id", + self->static_trace_marker_id); + ui_out_text (uiout, "\n"); + } +} + +static int +bkpt_resources_needed (struct bp_location *bl) +{ + gdb_assert (bl->owner->type == bp_hardware_breakpoint + || is_hardware_watchpoint (bl->owner)); + + return 1; +} + +static int +bkpt_print_mention (struct breakpoint *b) +{ + struct cleanup *ui_out_chain; + struct value_print_options opts; + int say_where = 0; + + get_user_print_options (&opts); + + switch (b->type) + { + case bp_none: + printf_filtered (_("(apparently deleted?) Eventpoint %d: "), + b->number); + break; + case bp_watchpoint: + ui_out_text (uiout, "Watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); + ui_out_field_int (uiout, "number", b->number); + ui_out_text (uiout, ": "); + ui_out_field_string (uiout, "exp", b->exp_string); + do_cleanups (ui_out_chain); + break; + case bp_hardware_watchpoint: + ui_out_text (uiout, "Hardware watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); + ui_out_field_int (uiout, "number", b->number); + ui_out_text (uiout, ": "); + ui_out_field_string (uiout, "exp", b->exp_string); + do_cleanups (ui_out_chain); + break; + case bp_read_watchpoint: + ui_out_text (uiout, "Hardware read watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt"); + ui_out_field_int (uiout, "number", b->number); + ui_out_text (uiout, ": "); + ui_out_field_string (uiout, "exp", b->exp_string); + do_cleanups (ui_out_chain); + break; + case bp_access_watchpoint: + ui_out_text (uiout, "Hardware access (read/write) watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt"); + ui_out_field_int (uiout, "number", b->number); + ui_out_text (uiout, ": "); + ui_out_field_string (uiout, "exp", b->exp_string); + do_cleanups (ui_out_chain); + break; + case bp_breakpoint: + case bp_gnu_ifunc_resolver: + if (ui_out_is_mi_like_p (uiout)) + { + say_where = 0; + break; + } + if (b->disposition == disp_del) + printf_filtered (_("Temporary breakpoint")); + else + printf_filtered (_("Breakpoint")); + printf_filtered (_(" %d"), b->number); + if (b->type == bp_gnu_ifunc_resolver) + printf_filtered (_(" at gnu-indirect-function resolver")); + say_where = 1; + break; + case bp_hardware_breakpoint: + if (ui_out_is_mi_like_p (uiout)) + { + say_where = 0; + break; + } + printf_filtered (_("Hardware assisted breakpoint %d"), b->number); + say_where = 1; + break; + case bp_tracepoint: + if (ui_out_is_mi_like_p (uiout)) + { + say_where = 0; + break; + } + printf_filtered (_("Tracepoint")); + printf_filtered (_(" %d"), b->number); + say_where = 1; + break; + case bp_fast_tracepoint: + if (ui_out_is_mi_like_p (uiout)) + { + say_where = 0; + break; + } + printf_filtered (_("Fast tracepoint")); + printf_filtered (_(" %d"), b->number); + say_where = 1; + break; + case bp_static_tracepoint: + if (ui_out_is_mi_like_p (uiout)) + { + say_where = 0; + break; + } + printf_filtered (_("Static tracepoint")); + printf_filtered (_(" %d"), b->number); + say_where = 1; + break; + + case bp_until: + case bp_finish: + case bp_longjmp: + case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: + case bp_step_resume: + case bp_hp_step_resume: + case bp_call_dummy: + case bp_std_terminate: + case bp_watchpoint_scope: + case bp_shlib_event: + case bp_thread_event: + case bp_overlay_event: + case bp_jit_event: + case bp_longjmp_master: + case bp_std_terminate_master: + case bp_exception_master: + case bp_gnu_ifunc_resolver_return: + break; + } + + if (say_where) + { + /* i18n: cagney/2005-02-11: Below needs to be merged into a + single string. */ + if (b->loc == NULL) + { + printf_filtered (_(" (%s) pending."), b->addr_string); + } + else + { + if (opts.addressprint || b->source_file == NULL) + { + printf_filtered (" at "); + fputs_filtered (paddress (b->loc->gdbarch, b->loc->address), + gdb_stdout); + } + if (b->source_file) + printf_filtered (": file %s, line %d.", + b->source_file, b->line_number); + + if (b->loc->next) + { + struct bp_location *loc = b->loc; + int n = 0; + for (; loc; loc = loc->next) + ++n; + printf_filtered (" (%d locations)", n); + } + + } + } +} + +static int +bkpt_re_set (struct breakpoint *b) +{ + switch (b->type) + { + case bp_none: + warning (_("attempted to reset apparently deleted breakpoint #%d?"), + b->number); + return 0; + case bp_breakpoint: + case bp_hardware_breakpoint: + case bp_tracepoint: + case bp_fast_tracepoint: + case bp_static_tracepoint: + case bp_gnu_ifunc_resolver: + /* Do not attempt to re-set breakpoints disabled during startup. */ + if (b->enable_state == bp_startup_disabled) + return 0; + + if (b->addr_string == NULL) + { + /* Anything without a string can't be re-set. */ + delete_breakpoint (b); + return 0; + } + + breakpoint_re_set_default (b); + } + break; + + case bp_watchpoint: + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_access_watchpoint: + /* Watchpoint can be either on expression using entirely global + variables, or it can be on local variables. + + Watchpoints of the first kind are never auto-deleted, and + even persist across program restarts. Since they can use + variables from shared libraries, we need to reparse + expression as libraries are loaded and unloaded. + + Watchpoints on local variables can also change meaning as + result of solib event. For example, if a watchpoint uses + both a local and a global variables in expression, it's a + local watchpoint, but unloading of a shared library will make + the expression invalid. This is not a very common use case, + but we still re-evaluate expression, to avoid surprises to + the user. + + Note that for local watchpoints, we re-evaluate it only if + watchpoints frame id is still valid. If it's not, it means + the watchpoint is out of scope and will be deleted soon. In + fact, I'm not sure we'll ever be called in this case. + + If a local watchpoint's frame id is still valid, then + b->exp_valid_block is likewise valid, and we can safely use it. + + Don't do anything about disabled watchpoints, since they will + be reevaluated again when enabled. */ + update_watchpoint (b, 1 /* reparse */); + break; + /* We needn't really do anything to reset these, since the mask + that requests them is unaffected by e.g., new libraries being + loaded. */ + case bp_catchpoint: + break; + + default: + printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type); + /* fall through */ + /* Delete overlay event and longjmp master breakpoints; they will be + reset later by breakpoint_re_set. */ + case bp_overlay_event: + case bp_longjmp_master: + case bp_std_terminate_master: + case bp_exception_master: + delete_breakpoint (b); + break; + + /* This breakpoint is special, it's set up when the inferior + starts and we really don't want to touch it. */ + case bp_shlib_event: + + /* Like bp_shlib_event, this breakpoint type is special. + Once it is set up, we do not want to touch it. */ + case bp_thread_event: + + /* Keep temporary breakpoints, which can be encountered when we + step over a dlopen call and SOLIB_ADD is resetting the + breakpoints. Otherwise these should have been blown away via + the cleanup chain or by breakpoint_init_inferior when we + rerun the executable. */ + case bp_until: + case bp_finish: + case bp_watchpoint_scope: + case bp_call_dummy: + case bp_std_terminate: + case bp_step_resume: + case bp_hp_step_resume: + case bp_longjmp: + case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: + case bp_jit_event: + case bp_gnu_ifunc_resolver_return: + break; + } +} + +static void +bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp) +{ + if (tp->type == bp_fast_tracepoint) + fprintf_unfiltered (fp, "ftrace"); + if (tp->type == bp_static_tracepoint) + fprintf_unfiltered (fp, "strace"); + else if (tp->type == bp_tracepoint) + fprintf_unfiltered (fp, "trace"); + else if (tp->type == bp_breakpoint && tp->disposition == disp_del) + fprintf_unfiltered (fp, "tbreak"); + else if (tp->type == bp_breakpoint) + fprintf_unfiltered (fp, "break"); + else if (tp->type == bp_hardware_breakpoint + && tp->disposition == disp_del) + fprintf_unfiltered (fp, "thbreak"); + else if (tp->type == bp_hardware_breakpoint) + fprintf_unfiltered (fp, "hbreak"); + else if (tp->type == bp_watchpoint) + fprintf_unfiltered (fp, "watch"); + else if (tp->type == bp_hardware_watchpoint) + fprintf_unfiltered (fp, "watch"); + else if (tp->type == bp_read_watchpoint) + fprintf_unfiltered (fp, "rwatch"); + else if (tp->type == bp_access_watchpoint) + fprintf_unfiltered (fp, "awatch"); + else + internal_error (__FILE__, __LINE__, + _("unhandled breakpoint type %d"), (int) tp->type); + + if (tp->exp_string) + fprintf_unfiltered (fp, " %s", tp->exp_string); + else if (tp->addr_string) + fprintf_unfiltered (fp, " %s", tp->addr_string); + else + { + char tmp[40]; + + sprintf_vma (tmp, tp->loc->address); + fprintf_unfiltered (fp, " *0x%s", tmp); + } +} + +static int +bkpt_works_in_software_mode (const struct breakpoint *b) +{ + gdb_assert_unreachable (""); +} + +static int +bkpt_insert_location (struct bp_location *bl) +{ + if (bl->loc_type == bp_loc_software_breakpoint + || bl->loc_type == bp_loc_hardware_breakpoint) + { + if (bl->owner->type != bp_hardware_breakpoint) + { + /* If the explicitly specified breakpoint type + is not hardware breakpoint, check the memory map to see + if the breakpoint address is in read only memory or not. + + Two important cases are: + - location type is not hardware breakpoint, memory + is readonly. We change the type of the location to + hardware breakpoint. + - location type is hardware breakpoint, memory is + read-write. This means we've previously made the + location hardware one, but then the memory map changed, + so we undo. + + When breakpoints are removed, remove_breakpoints will use + location types we've just set here, the only possible + problem is that memory map has changed during running + program, but it's not going to work anyway with current + gdb. */ + struct mem_region *mr + = lookup_mem_region (bl->target_info.placed_address); + + if (mr) + { + if (automatic_hardware_breakpoints) + { + enum bp_loc_type new_type; + + if (mr->attrib.mode != MEM_RW) + new_type = bp_loc_hardware_breakpoint; + else + new_type = bp_loc_software_breakpoint; + + if (new_type != bl->loc_type) + { + static int said = 0; + + bl->loc_type = new_type; + if (!said) + { + fprintf_filtered (gdb_stdout, + _("Note: automatically using " + "hardware breakpoints for " + "read-only addresses.\n")); + said = 1; + } + } + } + else if (bl->loc_type == bp_loc_software_breakpoint + && mr->attrib.mode != MEM_RW) + warning (_("cannot set software breakpoint " + "at readonly address %s"), + paddress (bl->gdbarch, bl->address)); + } + } + + /* First check to see if we have to handle an overlay. */ + if (overlay_debugging == ovly_off + || bl->section == NULL + || !(section_is_overlay (bl->section))) + { + /* No overlay handling: just set the breakpoint. */ + + if (bl->loc_type == bp_loc_hardware_breakpoint) + val = target_insert_hw_breakpoint (bl->gdbarch, + &bl->target_info); + else + val = target_insert_breakpoint (bl->gdbarch, + &bl->target_info); + } + else + { + /* This breakpoint is in an overlay section. + Shall we set a breakpoint at the LMA? */ + if (!overlay_events_enabled) + { + /* Yes -- overlay event support is not active, + so we must try to set a breakpoint at the LMA. + This will not work for a hardware breakpoint. */ + if (bl->loc_type == bp_loc_hardware_breakpoint) + warning (_("hardware breakpoint %d not supported in overlay!"), + bl->owner->number); + else + { + CORE_ADDR addr = overlay_unmapped_address (bl->address, + bl->section); + /* Set a software (trap) breakpoint at the LMA. */ + bl->overlay_target_info = bl->target_info; + bl->overlay_target_info.placed_address = addr; + val = target_insert_breakpoint (bl->gdbarch, + &bl->overlay_target_info); + if (val != 0) + fprintf_unfiltered (tmp_error_stream, + "Overlay breakpoint %d " + "failed: in ROM?\n", + bl->owner->number); + } + } + /* Shall we set a breakpoint at the VMA? */ + if (section_is_mapped (bl->section)) + { + /* Yes. This overlay section is mapped into memory. */ + if (bl->loc_type == bp_loc_hardware_breakpoint) + val = target_insert_hw_breakpoint (bl->gdbarch, + &bl->target_info); + else + val = target_insert_breakpoint (bl->gdbarch, + &bl->target_info); + } + else + { + /* No. This breakpoint will not be inserted. + No error, but do not mark the bp as 'inserted'. */ + return 0; + } + } + + return val; + } +} + +static int +bkpt_remove_location (struct bp_location *bl) +{ + int val; + + if (bl->loc_type == bp_loc_software_breakpoint + || bl->loc_type == bp_loc_hardware_breakpoint) + { + /* "Normal" instruction breakpoint: either the standard + trap-instruction bp (bp_breakpoint), or a + bp_hardware_breakpoint. */ + + /* First check to see if we have to handle an overlay. */ + if (overlay_debugging == ovly_off + || bl->section == NULL + || !(section_is_overlay (bl->section))) + { + /* No overlay handling: just remove the breakpoint. */ + + if (bl->loc_type == bp_loc_hardware_breakpoint) + val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info); + else + val = target_remove_breakpoint (bl->gdbarch, &bl->target_info); + } + else + { + /* This breakpoint is in an overlay section. + Did we set a breakpoint at the LMA? */ + if (!overlay_events_enabled) + { + /* Yes -- overlay event support is not active, so we + should have set a breakpoint at the LMA. Remove it. + */ + /* Ignore any failures: if the LMA is in ROM, we will + have already warned when we failed to insert it. */ + if (bl->loc_type == bp_loc_hardware_breakpoint) + target_remove_hw_breakpoint (bl->gdbarch, + &bl->overlay_target_info); + else + target_remove_breakpoint (bl->gdbarch, + &bl->overlay_target_info); + } + /* Did we set a breakpoint at the VMA? + If so, we will have marked the breakpoint 'inserted'. */ + if (bl->inserted) + { + /* Yes -- remove it. Previously we did not bother to + remove the breakpoint if the section had been + unmapped, but let's not rely on that being safe. We + don't know what the overlay manager might do. */ + if (bl->loc_type == bp_loc_hardware_breakpoint) + val = target_remove_hw_breakpoint (bl->gdbarch, + &bl->target_info); + + /* However, we should remove *software* breakpoints only + if the section is still mapped, or else we overwrite + wrong code with the saved shadow contents. */ + else if (section_is_mapped (bl->section)) + val = target_remove_breakpoint (bl->gdbarch, + &bl->target_info); + else + val = 0; + } + else + { + /* No -- not inserted, so no need to remove. No error. */ + val = 0; + } + } + + /* In some cases, we might not be able to remove a breakpoint + in a shared library that has already been removed, but we + have not yet processed the shlib unload event. */ + if (val && solib_name_from_address (bl->pspace, bl->address)) + val = 0; + } + + return val; +} + +/* The breakpoint_ops structure to be used in regular breakpoints. */ + +static struct breakpoint_ops bkpt_ops = +{ + bkpt_dtor, + bkpt_allocate_location, + bkpt_re_set, + bkpt_insert, + bkpt_remove, + bkpt_breakpoint_hit, + bkpt_check_status, + bkpt_resources_needed, + bkpt_works_in_software_mode, + bkpt_print_it, + bkpt_print_one, + bkpt_print_one_detailk, + bkpt_print_mention, + bkpt_print_recreate +}; + +/* Default bp_location_ops methods. */ + +static void +bp_location_dtor (struct bp_location *self) +{ + xfree (self->cond); + xfree (self->function_name); +} + +/* Delete a breakpoint and clean up all traces of it in the data + structures. */ + +void +delete_breakpoint (struct breakpoint *bpt) +{ + struct breakpoint *b; + + gdb_assert (bpt != NULL); + + /* Has this bp already been deleted? This can happen because + multiple lists can hold pointers to bp's. bpstat lists are + especial culprits. + + One example of this happening is a watchpoint's scope bp. When + the scope bp triggers, we notice that the watchpoint is out of + scope, and delete it. We also delete its scope bp. But the + scope bp is marked "auto-deleting", and is already on a bpstat. + That bpstat is then checked for auto-deleting bp's, which are + deleted. + + A real solution to this problem might involve reference counts in + bp's, and/or giving them pointers back to their referencing + bpstat's, and teaching delete_breakpoint to only free a bp's + storage when no more references were extent. A cheaper bandaid + was chosen. */ + if (bpt->type == bp_none) + return; + + /* At least avoid this stale reference until the reference counting + of breakpoints gets resolved. */ + if (bpt->related_breakpoint != bpt) + { + struct breakpoint *related; + + if (bpt->type == bp_watchpoint_scope) + watchpoint_del_at_next_stop (bpt->related_breakpoint); + else if (bpt->related_breakpoint->type == bp_watchpoint_scope) + watchpoint_del_at_next_stop (bpt); + + /* Unlink bpt from the bpt->related_breakpoint ring. */ + for (related = bpt; related->related_breakpoint != bpt; + related = related->related_breakpoint); + related->related_breakpoint = bpt->related_breakpoint; + bpt->related_breakpoint = bpt; + } + + /* watch_command_1 creates a watchpoint but only sets its number if + update_watchpoint succeeds in creating its bp_locations. If there's + a problem in that process, we'll be asked to delete the half-created + watchpoint. In that case, don't announce the deletion. */ + if (bpt->number) + observer_notify_breakpoint_deleted (bpt); + + if (breakpoint_chain == bpt) + breakpoint_chain = bpt->next; + + ALL_BREAKPOINTS (b) + if (b->next == bpt) + { + b->next = bpt->next; + break; + } + + /* Be sure no bpstat's are pointing at the breakpoint after it's + been freed. */ + /* FIXME, how can we find all bpstat's? We just check stop_bpstat + in all threeds for now. Note that we cannot just remove bpstats + pointing at bpt from the stop_bpstat list entirely, as breakpoint + commands are associated with the bpstat; if we remove it here, + then the later call to bpstat_do_actions (&stop_bpstat); in + event-top.c won't do anything, and temporary breakpoints with + commands won't work. */ + + iterate_over_threads (bpstat_remove_breakpoint_callback, bpt); + + /* Now that breakpoint is removed from breakpoint list, update the + global location list. This will remove locations that used to + belong to this breakpoint. Do this before freeing the breakpoint + itself, since remove_breakpoint looks at location's owner. It + might be better design to have location completely + self-contained, but it's not the case now. */ + update_global_location_list (0); + + bpt->ops->dtor (bpt); + /* On the chance that someone will soon try again to delete this + same bp, we mark it as deleted before freeing its storage. */ + bpt->type = bp_none; + xfree (bpt); +} + +static void +do_delete_breakpoint_cleanup (void *b) +{ + delete_breakpoint (b); +} + +struct cleanup * +make_cleanup_delete_breakpoint (struct breakpoint *b) +{ + return make_cleanup (do_delete_breakpoint_cleanup, b); +} + +/* Iterator function to call a user-provided callback function once + for each of B and its related breakpoints. */ static void iterate_over_related_breakpoints (struct breakpoint *b, @@ -11473,129 +11698,11 @@ breakpoint_re_set_one (void *bint) { /* Get past catch_errs. */ struct breakpoint *b = (struct breakpoint *) bint; + struct cleanup *cleanups; - if (b->ops != NULL && b->ops->re_set != NULL) - { - struct cleanup *cleanups; - - cleanups = prepare_re_set_context (b); - b->ops->re_set (b); - do_cleanups (cleanups); - - return 0; - } - - switch (b->type) - { - case bp_none: - warning (_("attempted to reset apparently deleted breakpoint #%d?"), - b->number); - return 0; - case bp_breakpoint: - case bp_hardware_breakpoint: - case bp_tracepoint: - case bp_fast_tracepoint: - case bp_static_tracepoint: - case bp_gnu_ifunc_resolver: - /* Do not attempt to re-set breakpoints disabled during startup. */ - if (b->enable_state == bp_startup_disabled) - return 0; - - if (b->addr_string == NULL) - { - /* Anything without a string can't be re-set. */ - delete_breakpoint (b); - return 0; - } - - { - struct cleanup *cleanups; - - cleanups = prepare_re_set_context (b); - breakpoint_re_set_default (b); - do_cleanups (cleanups); - } - break; - - case bp_watchpoint: - case bp_hardware_watchpoint: - case bp_read_watchpoint: - case bp_access_watchpoint: - /* Watchpoint can be either on expression using entirely global - variables, or it can be on local variables. - - Watchpoints of the first kind are never auto-deleted, and - even persist across program restarts. Since they can use - variables from shared libraries, we need to reparse - expression as libraries are loaded and unloaded. - - Watchpoints on local variables can also change meaning as - result of solib event. For example, if a watchpoint uses - both a local and a global variables in expression, it's a - local watchpoint, but unloading of a shared library will make - the expression invalid. This is not a very common use case, - but we still re-evaluate expression, to avoid surprises to - the user. - - Note that for local watchpoints, we re-evaluate it only if - watchpoints frame id is still valid. If it's not, it means - the watchpoint is out of scope and will be deleted soon. In - fact, I'm not sure we'll ever be called in this case. - - If a local watchpoint's frame id is still valid, then - b->exp_valid_block is likewise valid, and we can safely use it. - - Don't do anything about disabled watchpoints, since they will - be reevaluated again when enabled. */ - update_watchpoint (b, 1 /* reparse */); - break; - /* We needn't really do anything to reset these, since the mask - that requests them is unaffected by e.g., new libraries being - loaded. */ - case bp_catchpoint: - break; - - default: - printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type); - /* fall through */ - /* Delete overlay event and longjmp master breakpoints; they will be - reset later by breakpoint_re_set. */ - case bp_overlay_event: - case bp_longjmp_master: - case bp_std_terminate_master: - case bp_exception_master: - delete_breakpoint (b); - break; - - /* This breakpoint is special, it's set up when the inferior - starts and we really don't want to touch it. */ - case bp_shlib_event: - - /* Like bp_shlib_event, this breakpoint type is special. - Once it is set up, we do not want to touch it. */ - case bp_thread_event: - - /* Keep temporary breakpoints, which can be encountered when we - step over a dlopen call and SOLIB_ADD is resetting the - breakpoints. Otherwise these should have been blown away via - the cleanup chain or by breakpoint_init_inferior when we - rerun the executable. */ - case bp_until: - case bp_finish: - case bp_watchpoint_scope: - case bp_call_dummy: - case bp_std_terminate: - case bp_step_resume: - case bp_hp_step_resume: - case bp_longjmp: - case bp_longjmp_resume: - case bp_exception: - case bp_exception_resume: - case bp_jit_event: - case bp_gnu_ifunc_resolver_return: - break; - } - + cleanups = prepare_re_set_context (b); + b->ops->re_set (b); + do_cleanups (cleanups); return 0; } @@ -12774,49 +12881,7 @@ save_breakpoints (char *filename, int fr if (filter && !filter (tp)) continue; - if (tp->ops != NULL && tp->ops->print_recreate != NULL) - (tp->ops->print_recreate) (tp, fp); - else - { - if (tp->type == bp_fast_tracepoint) - fprintf_unfiltered (fp, "ftrace"); - if (tp->type == bp_static_tracepoint) - fprintf_unfiltered (fp, "strace"); - else if (tp->type == bp_tracepoint) - fprintf_unfiltered (fp, "trace"); - else if (tp->type == bp_breakpoint && tp->disposition == disp_del) - fprintf_unfiltered (fp, "tbreak"); - else if (tp->type == bp_breakpoint) - fprintf_unfiltered (fp, "break"); - else if (tp->type == bp_hardware_breakpoint - && tp->disposition == disp_del) - fprintf_unfiltered (fp, "thbreak"); - else if (tp->type == bp_hardware_breakpoint) - fprintf_unfiltered (fp, "hbreak"); - else if (tp->type == bp_watchpoint) - fprintf_unfiltered (fp, "watch"); - else if (tp->type == bp_hardware_watchpoint) - fprintf_unfiltered (fp, "watch"); - else if (tp->type == bp_read_watchpoint) - fprintf_unfiltered (fp, "rwatch"); - else if (tp->type == bp_access_watchpoint) - fprintf_unfiltered (fp, "awatch"); - else - internal_error (__FILE__, __LINE__, - _("unhandled breakpoint type %d"), (int) tp->type); - - if (tp->exp_string) - fprintf_unfiltered (fp, " %s", tp->exp_string); - else if (tp->addr_string) - fprintf_unfiltered (fp, " %s", tp->addr_string); - else - { - char tmp[40]; - - sprintf_vma (tmp, tp->loc->address); - fprintf_unfiltered (fp, " *0x%s", tmp); - } - } + tp->ops->print_recreate (tp, fp); if (tp->thread != -1) fprintf_unfiltered (fp, " thread %d", tp->thread); ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch] [python] Expose some breakpoint operations to Python 2011-06-23 15:30 ` Pedro Alves @ 2011-06-23 15:57 ` Phil Muldoon 2011-06-23 17:04 ` Pedro Alves 0 siblings, 1 reply; 12+ messages in thread From: Phil Muldoon @ 2011-06-23 15:57 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Pedro Alves <pedro@codesourcery.com> writes: > On Thursday 23 June 2011 15:46:14, Phil Muldoon wrote: > No plan yet. I just started out by adding a single breakpoint_ops instance > that handles all breakpoint types that currently aren't using breakpoint_ops, > and moving all default actions to the corresponding callback. This would > be straightforward if the API is a good fit. But take a look at > the fallback code in print_one_breakpoint_location, and print_one_breakpoint. > Breakpoints with multiple locations are handled a bit differently than > just a fallbach, with multiple calls to print_one_breakpoint. Maybe > we could move all that !print_one code inside the new print_one > callback? Yes the multiple locations thing is a bit weird. But from (my Python) point of view, that is an internal abstraction that the Python glue code will absorb. I don't think this will affect Python API users too much. > Not sure. Also, maybe we should split printing the "what" from > the "address"? This may be an external API change. But we can always abstract that from the user by using keywords in the Python side instead of actual positional arguments. > Not sure either, but it looks bizarre to me that > current print_one implementations need to know to call annotate_field. > Then there are implementations that print free form text > surrounding those values, e.g., see print_one_catch_vfork. These > issues certainly inpact the python api. The annotate_field thing was somewhat interesting. I take care of this for the Python user though so I am not too worried about that. Where the field annotation happens is not a big deal for "me", we can move it from the py-breakpoint code back to some new refactored breakpoint.c code. The user does not need to know about this. > (You'll also note that the ->insert_location and > ->remove_location call sites reveal that something isn't fully > abstracted, since failing to insert different kinds of breakpoints > leads to different reactions in the code). > > Note, the doesn't even compile. I'm not sure about this. The Python breakpoints are just regular breakpoints - we don't even support catchpoints at this point, they are just too flaky to wrap right now. In fact breakpoints created in Python - even the internal ones - are just regular old breakpoints which we masquerade to the user. > Something else that's obviously missing with exposing breakpoint_ops > to python as is (yes I know you haven't exported all of it), is that most > certainly users will want to be able to call the "super" method. That is, > say, e.g, override, the ->check_status method, and still call the default > method, whatever it was. I actually have no (solid) plans to expose anymore of the breakpoint operations than are already exposed in this patch. The other operations require substantial knowledge of GDB's inner-workings and access to non-exported data-structures to be feasible at this youngling Python stage. It is not something that won't ever happen, but it won't happen for awhile. So in this context, refactorings should not affect the Python code. > Well, what does grep tell us? > > breakpoint.c: PRINT_SRC_ONLY: Means we printed something, and we do *not* desire > breakpoint.c: PRINT_SRC_ONLY: Means we printed something, but there is no need > breakpoint.c: if (val == PRINT_SRC_ONLY > breakpoint.h: PRINT_SRC_ONLY, > infrun.c: case PRINT_SRC_ONLY: > > Looks like it's never used? Maybe gdbtk uses it, haven't checked. > Certainly a good example of that cleaning up the house a little before > exposing the API is a good idea. Yeah I did the grep thing too. I ended up exporting it because it was there. We can just remove it if it is too flaky. While we have a strict philosophy on avoiding API changes to the Python API, we can always add content later. But I take your point. I'm trying to position this patch so that users can access a limited subset of printing breakpoint operations. The time-line is important here too. If this refactoring internally is just going to take a few weeks, hey, no big deal, I can just wait and adjust. But if it is a long term thing, I think we could expose the limited functionality we expose now. Cheers Phil -- Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham (USA), Brendan Lane (Ireland), Matt Parson (USA), Charlie Peters (USA) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch] [python] Expose some breakpoint operations to Python 2011-06-23 15:57 ` Phil Muldoon @ 2011-06-23 17:04 ` Pedro Alves 2011-06-23 18:58 ` Phil Muldoon 2011-06-24 16:42 ` more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) Pedro Alves 0 siblings, 2 replies; 12+ messages in thread From: Pedro Alves @ 2011-06-23 17:04 UTC (permalink / raw) To: gdb-patches, pmuldoon On Thursday 23 June 2011 16:56:50, Phil Muldoon wrote: > Pedro Alves <pedro@codesourcery.com> writes: > > > On Thursday 23 June 2011 15:46:14, Phil Muldoon wrote: > > > No plan yet. I just started out by adding a single breakpoint_ops instance > > that handles all breakpoint types that currently aren't using breakpoint_ops, > > and moving all default actions to the corresponding callback. This would > > be straightforward if the API is a good fit. But take a look at > > the fallback code in print_one_breakpoint_location, and print_one_breakpoint. > > Breakpoints with multiple locations are handled a bit differently than > > just a fallbach, with multiple calls to print_one_breakpoint. Maybe > > we could move all that !print_one code inside the new print_one > > callback? > > Yes the multiple locations thing is a bit weird. But from (my Python) > point of view, that is an internal abstraction that the Python glue code > will absorb. I don't think this will affect Python API users too much. What happens if you create a python breakpoint that ends up with multiple locations? Don't you end up tripping on this assertion? /* 5 and 6 */ if (b->ops != NULL && b->ops->print_one != NULL) { /* Although the print_one can possibly print all locations, calling it here is not likely to get any nice result. So, make sure there's just one location. */ gdb_assert (b->loc == NULL || b->loc->next == NULL); b->ops->print_one (b, last_loc); } > But I take your point. I'm trying to position this patch so that users > can access a limited subset of printing breakpoint operations. The > time-line is important here too. If this refactoring internally is just > going to take a few weeks, hey, no big deal, I can just wait and > adjust. But if it is a long term thing, I think we could expose the > limited functionality we expose now. I'd like to finish that conversion soon. -- Pedro Alves ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch] [python] Expose some breakpoint operations to Python 2011-06-23 17:04 ` Pedro Alves @ 2011-06-23 18:58 ` Phil Muldoon 2011-06-24 16:42 ` more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) Pedro Alves 1 sibling, 0 replies; 12+ messages in thread From: Phil Muldoon @ 2011-06-23 18:58 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Pedro Alves <pedro@codesourcery.com> writes: > On Thursday 23 June 2011 16:56:50, Phil Muldoon wrote: >> Yes the multiple locations thing is a bit weird. But from (my Python) >> point of view, that is an internal abstraction that the Python glue code >> will absorb. I don't think this will affect Python API users too much. > > What happens if you create a python breakpoint that ends up > with multiple locations? Don't you end up tripping on this > assertion? > > /* 5 and 6 */ > if (b->ops != NULL && b->ops->print_one != NULL) > { > /* Although the print_one can possibly print all locations, > calling it here is not likely to get any nice result. So, > make sure there's just one location. */ > gdb_assert (b->loc == NULL || b->loc->next == NULL); > b->ops->print_one (b, last_loc); > } Well to be fair, any breakpoint that implements breakpoint_ops will (including catchpoints). I guess the point there is that they won't, or are not likely to encounter this. Fair point. Actually I should have tested for this very scenario, so I will add it to the Python tests. What we could do is if a breakpoint has multiple locations just don't call this routine, or alter the logic to raise something less aggressive than an assert. But you have convinced me that breakpoint ops need a good going over. Any function, internal or external, that lets the user create a perfectly legitimate breakpoint, then later causes GDB to give up, because it does not how to handle it is bogus. >> But I take your point. I'm trying to position this patch so that users >> can access a limited subset of printing breakpoint operations. The >> time-line is important here too. If this refactoring internally is just >> going to take a few weeks, hey, no big deal, I can just wait and >> adjust. But if it is a long term thing, I think we could expose the >> limited functionality we expose now. > > I'd like to finish that conversion soon. I really look forward to it! In the meantime I will check-in the patch to a git branch on archer, and keep it updated. If the breakpoint ops refactoring turns into a deep-dark hole, we can always later do something like the above in solving it. Cheers, Phil ^ permalink raw reply [flat|nested] 12+ messages in thread
* more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) 2011-06-23 17:04 ` Pedro Alves 2011-06-23 18:58 ` Phil Muldoon @ 2011-06-24 16:42 ` Pedro Alves 2011-06-27 8:52 ` Phil Muldoon 2011-07-22 15:06 ` Phil Muldoon 1 sibling, 2 replies; 12+ messages in thread From: Pedro Alves @ 2011-06-24 16:42 UTC (permalink / raw) To: gdb-patches; +Cc: pmuldoon On Thursday 23 June 2011 18:04:26, Pedro Alves wrote: > I'd like to finish that conversion soon. I did a bit more work on this. Watchpoints were already using breakpoint_ops. I added a bkpt_breakpoint_ops for all software/hardware breakpoints, and a tracepoint_ops for all kinds of tracepoints, and moved the default actions to the appropriate places. There were places where I could cleanup a bit further, but I figured I'd better do those as follow ups. I think these 4 major kinds of "breakpoints" is already a good start. Further refinement could split internal / momentary breakpoints into its own ops, for example. I left behind the print_one method, as that seems will require something else, or some disentanglement. The current insert/remove abstration is at raw location level. We can't use it as is to split insert_bp_location. We may need to rename the current methods to e.g., insert_raw_location (or move them to the bp_location vtable), and add new breakpoint_ops methods that call the raw methods, and, handle the different warnings and insert-failed->revert paths as appropriate per breakpoint type. This has no regressions for me. It misses some comments and cosmetics here and there, and a ChangeLog entry. I'll try to get back to this soon, but I've got other fish to fry at the moment. -- Pedro Alves --- gdb/ada-lang.c | 56 - gdb/breakpoint.c | 2076 ++++++++++++++++++++++++--------------------- gdb/breakpoint.h | 48 - gdb/mi/mi-cmd-break.c | 2 gdb/python/py-breakpoint.c | 3 5 files changed, 1203 insertions(+), 982 deletions(-) Index: src/gdb/breakpoint.c =================================================================== --- src.orig/gdb/breakpoint.c 2011-06-23 01:25:32.000000000 +0100 +++ src/gdb/breakpoint.c 2011-06-24 17:29:05.868082452 +0100 @@ -94,6 +94,8 @@ static void ignore_command (char *, int) static int breakpoint_re_set_one (void *); +static void breakpoint_re_set_default (struct breakpoint *); + static void clear_command (char *, int); static void catch_command (char *, int); @@ -104,11 +106,14 @@ static void break_command_1 (char *, int static void mention (struct breakpoint *); +static struct breakpoint *set_raw_breakpoint_without_location (struct gdbarch *, + enum bptype, + struct breakpoint_ops *); /* This function is used in gdbtk sources and thus can not be made static. */ struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch, - struct symtab_and_line, - enum bptype); + struct symtab_and_line, + enum bptype, struct breakpoint_ops *); static void breakpoint_adjustment_warning (CORE_ADDR, CORE_ADDR, int, int); @@ -157,8 +162,6 @@ insertion_state_t; static int remove_breakpoint (struct bp_location *, insertion_state_t); static int remove_breakpoint_1 (struct bp_location *, insertion_state_t); -static enum print_stop_action print_it_typical (bpstat); - static enum print_stop_action print_bp_stop_message (bpstat bs); static int watchpoint_check (void *); @@ -1436,10 +1439,7 @@ update_watchpoint (struct breakpoint *b, (b->type, i, other_type_used); if (target_resources_ok <= 0) { - /* If there's no works_in_software_mode method, we - assume that the watchpoint works in software mode. */ - int sw_mode = (!b->ops || !b->ops->works_in_software_mode - || b->ops->works_in_software_mode (b)); + int sw_mode = b->ops->works_in_software_mode (b); if (target_resources_ok == 0 && !sw_mode) error (_("Target does not support this type of " @@ -1451,8 +1451,7 @@ update_watchpoint (struct breakpoint *b, b->type = bp_watchpoint; } } - else if (b->ops && b->ops->works_in_software_mode - && !b->ops->works_in_software_mode (b)) + else if (!b->ops->works_in_software_mode (b)) error (_("Expression cannot be implemented with " "read/access watchpoint.")); else @@ -1622,12 +1621,7 @@ insert_bp_location (struct bp_location * { /* No overlay handling: just set the breakpoint. */ - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_insert_hw_breakpoint (bl->gdbarch, - &bl->target_info); - else - val = target_insert_breakpoint (bl->gdbarch, - &bl->target_info); + val = bl->owner->ops->insert_location (bl); } else { @@ -1661,12 +1655,7 @@ insert_bp_location (struct bp_location * if (section_is_mapped (bl->section)) { /* Yes. This overlay section is mapped into memory. */ - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_insert_hw_breakpoint (bl->gdbarch, - &bl->target_info); - else - val = target_insert_breakpoint (bl->gdbarch, - &bl->target_info); + val = bl->owner->ops->insert_location (bl); } else { @@ -2088,7 +2077,7 @@ create_internal_breakpoint (struct gdbar sal.section = find_pc_overlay (sal.pc); sal.pspace = current_program_space; - b = set_raw_breakpoint (gdbarch, sal, type); + b = set_raw_breakpoint (gdbarch, sal, type, &bkpt_breakpoint_ops); b->number = internal_breakpoint_number--; b->disposition = disp_donttouch; @@ -2547,11 +2536,7 @@ remove_breakpoint_1 (struct bp_location || !(section_is_overlay (bl->section))) { /* No overlay handling: just remove the breakpoint. */ - - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info); - else - val = target_remove_breakpoint (bl->gdbarch, &bl->target_info); + val = bl->owner->ops->remove_location (bl); } else { @@ -2579,16 +2564,13 @@ remove_breakpoint_1 (struct bp_location remove the breakpoint if the section had been unmapped, but let's not rely on that being safe. We don't know what the overlay manager might do. */ - if (bl->loc_type == bp_loc_hardware_breakpoint) - val = target_remove_hw_breakpoint (bl->gdbarch, - &bl->target_info); /* However, we should remove *software* breakpoints only if the section is still mapped, or else we overwrite wrong code with the saved shadow contents. */ - else if (section_is_mapped (bl->section)) - val = target_remove_breakpoint (bl->gdbarch, - &bl->target_info); + if (bl->loc_type == bp_loc_hardware_breakpoint + || section_is_mapped (bl->section)) + val = bl->owner->ops->remove_location (bl); else val = 0; } @@ -3305,219 +3287,6 @@ watchpoint_value_print (struct value *va } } -/* This is the normal print function for a bpstat. In the future, - much of this logic could (should?) be moved to bpstat_stop_status, - by having it set different print_it values. - - Current scheme: When we stop, bpstat_print() is called. It loops - through the bpstat list of things causing this stop, calling the - print_bp_stop_message function on each one. The behavior of the - print_bp_stop_message function depends on the print_it field of - bpstat. If such field so indicates, call this function here. - - Return values from this routine (ultimately used by bpstat_print() - and normal_stop() to decide what to do): - PRINT_NOTHING: Means we already printed all we needed to print, - don't print anything else. - PRINT_SRC_ONLY: Means we printed something, and we do *not* desire - that something to be followed by a location. - PRINT_SCR_AND_LOC: Means we printed something, and we *do* desire - that something to be followed by a location. - PRINT_UNKNOWN: Means we printed nothing or we need to do some more - analysis. */ - -static enum print_stop_action -print_it_typical (bpstat bs) -{ - struct cleanup *old_chain; - struct breakpoint *b; - const struct bp_location *bl; - struct ui_stream *stb; - int bp_temp = 0; - enum print_stop_action result; - - gdb_assert (bs->bp_location_at != NULL); - - bl = bs->bp_location_at; - b = bs->breakpoint_at; - - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); - - switch (b->type) - { - case bp_breakpoint: - case bp_hardware_breakpoint: - bp_temp = b->disposition == disp_del; - if (bl->address != bl->requested_address) - breakpoint_adjustment_warning (bl->requested_address, - bl->address, - b->number, 1); - annotate_breakpoint (b->number); - if (bp_temp) - ui_out_text (uiout, "\nTemporary breakpoint "); - else - ui_out_text (uiout, "\nBreakpoint "); - if (ui_out_is_mi_like_p (uiout)) - { - ui_out_field_string (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT)); - ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); - } - ui_out_field_int (uiout, "bkptno", b->number); - ui_out_text (uiout, ", "); - result = PRINT_SRC_AND_LOC; - break; - - case bp_shlib_event: - /* Did we stop because the user set the stop_on_solib_events - variable? (If so, we report this as a generic, "Stopped due - to shlib event" message.) */ - printf_filtered (_("Stopped due to shared library event\n")); - result = PRINT_NOTHING; - break; - - case bp_thread_event: - /* Not sure how we will get here. - GDB should not stop for these breakpoints. */ - printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n")); - result = PRINT_NOTHING; - break; - - case bp_overlay_event: - /* By analogy with the thread event, GDB should not stop for these. */ - printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n")); - result = PRINT_NOTHING; - break; - - case bp_longjmp_master: - /* These should never be enabled. */ - printf_filtered (_("Longjmp Master Breakpoint: gdb should not stop!\n")); - result = PRINT_NOTHING; - break; - - case bp_std_terminate_master: - /* These should never be enabled. */ - printf_filtered (_("std::terminate Master Breakpoint: " - "gdb should not stop!\n")); - result = PRINT_NOTHING; - break; - - case bp_exception_master: - /* These should never be enabled. */ - printf_filtered (_("Exception Master Breakpoint: " - "gdb should not stop!\n")); - result = PRINT_NOTHING; - break; - - case bp_watchpoint: - case bp_hardware_watchpoint: - annotate_watchpoint (b->number); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER)); - mention (b); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nOld value = "); - watchpoint_value_print (bs->old_val, stb->stream); - ui_out_field_stream (uiout, "old", stb); - ui_out_text (uiout, "\nNew value = "); - watchpoint_value_print (b->val, stb->stream); - ui_out_field_stream (uiout, "new", stb); - ui_out_text (uiout, "\n"); - /* More than one watchpoint may have been triggered. */ - result = PRINT_UNKNOWN; - break; - - case bp_read_watchpoint: - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER)); - mention (b); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nValue = "); - watchpoint_value_print (b->val, stb->stream); - ui_out_field_stream (uiout, "value", stb); - ui_out_text (uiout, "\n"); - result = PRINT_UNKNOWN; - break; - - case bp_access_watchpoint: - if (bs->old_val != NULL) - { - annotate_watchpoint (b->number); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); - mention (b); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nOld value = "); - watchpoint_value_print (bs->old_val, stb->stream); - ui_out_field_stream (uiout, "old", stb); - ui_out_text (uiout, "\nNew value = "); - } - else - { - mention (b); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nValue = "); - } - watchpoint_value_print (b->val, stb->stream); - ui_out_field_stream (uiout, "new", stb); - ui_out_text (uiout, "\n"); - result = PRINT_UNKNOWN; - break; - - /* Fall through, we don't deal with these types of breakpoints - here. */ - - case bp_finish: - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_FUNCTION_FINISHED)); - result = PRINT_UNKNOWN; - break; - - case bp_until: - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_LOCATION_REACHED)); - result = PRINT_UNKNOWN; - break; - - case bp_none: - case bp_longjmp: - case bp_longjmp_resume: - case bp_exception: - case bp_exception_resume: - case bp_step_resume: - case bp_hp_step_resume: - case bp_watchpoint_scope: - case bp_call_dummy: - case bp_std_terminate: - case bp_tracepoint: - case bp_fast_tracepoint: - case bp_jit_event: - case bp_gnu_ifunc_resolver: - case bp_gnu_ifunc_resolver_return: - default: - result = PRINT_UNKNOWN; - break; - } - - do_cleanups (old_chain); - return result; -} - /* Generic routine for printing messages indicating why we stopped. The behavior of this function depends on the value 'print_it' in the bpstat structure. Under some circumstances we @@ -3549,14 +3318,10 @@ print_bp_stop_message (bpstat bs) if (b == NULL) return PRINT_UNKNOWN; - /* Normal case. Call the breakpoint's print_it method, or - print_it_typical. */ - if (b->ops != NULL && b->ops->print_it != NULL) - return b->ops->print_it (b); - else - return print_it_typical (bs); + /* Normal case. Call the breakpoint's print_it method. */ + return b->ops->print_it (bs); } - break; + break; default: internal_error (__FILE__, __LINE__, @@ -3851,10 +3616,11 @@ watchpoint_check (void *p) So we can't even detect the first assignment to it and watch after that (since the garbage may or may not equal the first value assigned). */ - /* We print all the stop information in print_it_typical(), but - in this case, by the time we call print_it_typical() this bp - will be deleted already. So we have no choice but print the - information here. */ + /* We print all the stop information in + breakpoint_ops->print_it, but in this case, by the time we + call breakpoint_ops->print_it this bp will be deleted + already. So we have no choice but print the information + here. */ if (ui_out_is_mi_like_p (uiout)) ui_out_field_string (uiout, "reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_SCOPE)); @@ -3873,60 +3639,19 @@ which its expression is valid.\n"); } /* Return true if it looks like target has stopped due to hitting - breakpoint location BL. This function does not check if we - should stop, only if BL explains the stop. */ + breakpoint location BL. This function does not check if we should + stop, only if BL explains the stop. */ + static int bpstat_check_location (const struct bp_location *bl, struct address_space *aspace, CORE_ADDR bp_addr) { struct breakpoint *b = bl->owner; - /* BL is from existing struct breakpoint. */ + /* BL is from an existing breakpoint. */ gdb_assert (b != NULL); - if (b->ops && b->ops->breakpoint_hit) - return b->ops->breakpoint_hit (bl, aspace, bp_addr); - - /* By definition, the inferior does not report stops at - tracepoints. */ - if (is_tracepoint (b)) - return 0; - - if (!is_watchpoint (b) - && b->type != bp_hardware_breakpoint - && b->type != bp_catchpoint) /* a non-watchpoint bp */ - { - if (!breakpoint_address_match (bl->pspace->aspace, bl->address, - aspace, bp_addr)) - return 0; - if (overlay_debugging /* unmapped overlay section */ - && section_is_overlay (bl->section) - && !section_is_mapped (bl->section)) - return 0; - } - - /* Continuable hardware watchpoints are treated as non-existent if the - reason we stopped wasn't a hardware watchpoint (we didn't stop on - some data address). Otherwise gdb won't stop on a break instruction - in the code (not from a breakpoint) when a hardware watchpoint has - been defined. Also skip watchpoints which we know did not trigger - (did not match the data address). */ - - if (is_hardware_watchpoint (b) - && b->watchpoint_triggered == watch_triggered_no) - return 0; - - if (b->type == bp_hardware_breakpoint) - { - if (bl->address != bp_addr) - return 0; - if (overlay_debugging /* unmapped overlay section */ - && section_is_overlay (bl->section) - && !section_is_mapped (bl->section)) - return 0; - } - - return 1; + return b->ops->breakpoint_hit (bl, aspace, bp_addr); } /* If BS refers to a watchpoint, determine if the watched values @@ -4307,27 +4032,11 @@ bpstat_stop_status (struct address_space if (!bs->stop) continue; - bpstat_check_watchpoint (bs); - if (!bs->stop) - continue; - b = bs->breakpoint_at; - - if (b->ops != NULL && b->ops->check_status != NULL) + b->ops->check_status (bs); + if (bs->stop) { - b->ops->check_status (bs); - if (!bs->stop) - continue; - } - - if (b->type == bp_thread_event || b->type == bp_overlay_event - || b->type == bp_longjmp_master - || b->type == bp_std_terminate_master - || b->type == bp_exception_master) - /* We do not stop for these. */ - bs->stop = 0; - else - bpstat_check_breakpoint_conditions (bs, ptid); + bpstat_check_breakpoint_conditions (bs, ptid); if (bs->stop) { @@ -4360,6 +4069,7 @@ bpstat_stop_status (struct address_space /* Print nothing for this entry if we dont stop or dont print. */ if (bs->stop == 0 || bs->print == 0) bs->print_it = print_it_noop; + } } /* If we aren't stopping, the value of some hardware watchpoint may @@ -4992,19 +4702,9 @@ print_one_breakpoint_location (struct br ui_out_text (uiout, "\n"); - if (!part_of_multiple && b->ops && b->ops->print_one_detail) + if (!part_of_multiple) b->ops->print_one_detail (b, uiout); - if (!part_of_multiple && b->static_trace_marker_id) - { - gdb_assert (b->type == bp_static_tracepoint); - - ui_out_text (uiout, "\tmarker id is "); - ui_out_field_string (uiout, "static-tracepoint-marker-string-id", - b->static_trace_marker_id); - ui_out_text (uiout, "\n"); - } - if (part_of_multiple && frame_id_p (b->frame_id)) { annotate_field (6); @@ -5695,6 +5395,8 @@ init_bp_location (struct bp_location *lo { memset (loc, 0, sizeof (*loc)); + gdb_assert (ops != NULL); + loc->ops = ops; loc->owner = owner; loc->cond = NULL; @@ -5753,28 +5455,13 @@ init_bp_location (struct bp_location *lo static struct bp_location * allocate_bp_location (struct breakpoint *bpt) { - struct bp_location *loc; - - if (bpt->ops && bpt->ops->allocate_location) - return bpt->ops->allocate_location (bpt); - - loc = xmalloc (sizeof (struct bp_location)); - init_bp_location (loc, NULL, bpt); - return loc; + return bpt->ops->allocate_location (bpt); } static void free_bp_location (struct bp_location *loc) { - if (loc->ops && loc->ops->dtor) - loc->ops->dtor (loc); - - if (loc->cond) - xfree (loc->cond); - - if (loc->function_name) - xfree (loc->function_name); - + loc->ops->dtor (loc); xfree (loc); } @@ -5830,6 +5517,8 @@ init_raw_breakpoint_without_location (st { memset (b, 0, sizeof (*b)); + gdb_assert (ops != NULL); + b->ops = ops; b->type = bptype; b->gdbarch = gdbarch; @@ -5849,16 +5538,15 @@ init_raw_breakpoint_without_location (st /* Helper to set_raw_breakpoint below. Creates a breakpoint that has type BPTYPE and has no locations as yet. */ -/* This function is used in gdbtk sources and thus can not be made - static. */ static struct breakpoint * set_raw_breakpoint_without_location (struct gdbarch *gdbarch, - enum bptype bptype) + enum bptype bptype, + struct breakpoint_ops *ops) { struct breakpoint *b = XNEW (struct breakpoint); - init_raw_breakpoint_without_location (b, gdbarch, bptype, NULL); + init_raw_breakpoint_without_location (b, gdbarch, bptype, ops); add_to_breakpoint_chain (b); return b; } @@ -5994,11 +5682,12 @@ init_raw_breakpoint (struct breakpoint * struct breakpoint * set_raw_breakpoint (struct gdbarch *gdbarch, - struct symtab_and_line sal, enum bptype bptype) + struct symtab_and_line sal, enum bptype bptype, + struct breakpoint_ops *ops) { struct breakpoint *b = XNEW (struct breakpoint); - init_raw_breakpoint (b, gdbarch, sal, bptype, NULL); + init_raw_breakpoint (b, gdbarch, sal, bptype, ops); add_to_breakpoint_chain (b); return b; } @@ -6341,9 +6030,10 @@ breakpoint_hit_catch_fork (const struct catchpoints. */ static enum print_stop_action -print_it_catch_fork (struct breakpoint *b) +print_it_catch_fork (bpstat bs) { - struct fork_catchpoint *c = (struct fork_catchpoint *) b; + struct breakpoint *b = bs->breakpoint_at; + struct fork_catchpoint *c = (struct fork_catchpoint *) bs->breakpoint_at; annotate_catchpoint (b->number); printf_filtered (_("\nCatchpoint %d (forked process %d), "), @@ -6400,18 +6090,18 @@ print_recreate_catch_fork (struct breakp static struct breakpoint_ops catch_fork_breakpoint_ops = { - NULL, /* dtor */ - NULL, /* allocate_location */ - NULL, /* re_set */ + bkpt_dtor, + bkpt_allocate_location, + null_re_set, insert_catch_fork, remove_catch_fork, breakpoint_hit_catch_fork, - NULL, /* check_status */ - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + null_check_status, + null_resources_needed, + null_works_in_software_mode, print_it_catch_fork, print_one_catch_fork, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_catch_fork, print_recreate_catch_fork }; @@ -6450,8 +6140,9 @@ breakpoint_hit_catch_vfork (const struct catchpoints. */ static enum print_stop_action -print_it_catch_vfork (struct breakpoint *b) +print_it_catch_vfork (bpstat bs) { + struct breakpoint *b = bs->breakpoint_at; struct fork_catchpoint *c = (struct fork_catchpoint *) b; annotate_catchpoint (b->number); @@ -6508,18 +6199,18 @@ print_recreate_catch_vfork (struct break static struct breakpoint_ops catch_vfork_breakpoint_ops = { - NULL, /* dtor */ - NULL, /* allocate_location */ - NULL, /* re_set */ + bkpt_dtor, + bkpt_allocate_location, + null_re_set, insert_catch_vfork, remove_catch_vfork, breakpoint_hit_catch_vfork, - NULL, /* check_status */ - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + null_check_status, + null_resources_needed, + null_works_in_software_mode, print_it_catch_vfork, print_one_catch_vfork, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_catch_vfork, print_recreate_catch_vfork }; @@ -6675,8 +6366,9 @@ breakpoint_hit_catch_syscall (const stru catchpoints. */ static enum print_stop_action -print_it_catch_syscall (struct breakpoint *b) +print_it_catch_syscall (bpstat bs) { + struct breakpoint *b = bs->breakpoint_at; /* These are needed because we want to know in which state a syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we @@ -6838,17 +6530,17 @@ print_recreate_catch_syscall (struct bre static struct breakpoint_ops catch_syscall_breakpoint_ops = { dtor_catch_syscall, - NULL, /* allocate_location */ - NULL, /* re_set */ + bkpt_allocate_location, + null_re_set, insert_catch_syscall, remove_catch_syscall, breakpoint_hit_catch_syscall, - NULL, /* check_status */ - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + null_check_status, + null_resources_needed, + null_works_in_software_mode, print_it_catch_syscall, print_one_catch_syscall, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_catch_syscall, print_recreate_catch_syscall }; @@ -6960,8 +6652,9 @@ breakpoint_hit_catch_exec (const struct } static enum print_stop_action -print_it_catch_exec (struct breakpoint *b) +print_it_catch_exec (bpstat bs) { + struct breakpoint *b = bs->breakpoint_at; struct exec_catchpoint *c = (struct exec_catchpoint *) b; annotate_catchpoint (b->number); @@ -7011,17 +6704,17 @@ print_recreate_catch_exec (struct breakp static struct breakpoint_ops catch_exec_breakpoint_ops = { dtor_catch_exec, - NULL, /* allocate_location */ - NULL, /* re_set */ + bkpt_allocate_location, + null_re_set, insert_catch_exec, remove_catch_exec, breakpoint_hit_catch_exec, - NULL, /* check_status */ - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + null_check_status, + null_resources_needed, + null_works_in_software_mode, print_it_catch_exec, print_one_catch_exec, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_catch_exec, print_recreate_catch_exec }; @@ -7054,10 +6747,7 @@ hw_breakpoint_used_count (void) { /* Special types of hardware breakpoints may use more than one register. */ - if (b->ops && b->ops->resources_needed) - i += b->ops->resources_needed (bl); - else - i++; + i += b->ops->resources_needed (bl); } } @@ -7082,10 +6772,7 @@ hw_watchpoint_used_count (enum bptype ty { /* Special types of hardware watchpoints may use more than one register. */ - if (b->ops && b->ops->resources_needed) - i += b->ops->resources_needed (bl); - else - i++; + i += b->ops->resources_needed (bl); } else if (is_hardware_watchpoint (b)) *other_type_used = 1; @@ -7191,7 +6878,7 @@ set_momentary_breakpoint (struct gdbarch one. */ gdb_assert (!frame_id_inlined_p (frame_id)); - b = set_raw_breakpoint (gdbarch, sal, type); + b = set_raw_breakpoint (gdbarch, sal, type, &bkpt_breakpoint_ops); b->enable_state = bp_enabled; b->disposition = disp_donttouch; b->frame_id = frame_id; @@ -7219,7 +6906,8 @@ clone_momentary_breakpoint (struct break if (orig == NULL) return NULL; - copy = set_raw_breakpoint_without_location (orig->gdbarch, orig->type); + copy = set_raw_breakpoint_without_location (orig->gdbarch, + orig->type, orig->ops); copy->loc = allocate_bp_location (copy); set_breakpoint_location_function (copy->loc, 1); @@ -7267,162 +6955,7 @@ set_momentary_breakpoint_at_pc (struct g static void mention (struct breakpoint *b) { - int say_where = 0; - struct cleanup *ui_out_chain; - struct value_print_options opts; - - get_user_print_options (&opts); - - if (b->ops != NULL && b->ops->print_mention != NULL) - b->ops->print_mention (b); - else - switch (b->type) - { - case bp_none: - printf_filtered (_("(apparently deleted?) Eventpoint %d: "), - b->number); - break; - case bp_watchpoint: - ui_out_text (uiout, "Watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_hardware_watchpoint: - ui_out_text (uiout, "Hardware watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_read_watchpoint: - ui_out_text (uiout, "Hardware read watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_access_watchpoint: - ui_out_text (uiout, "Hardware access (read/write) watchpoint "); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt"); - ui_out_field_int (uiout, "number", b->number); - ui_out_text (uiout, ": "); - ui_out_field_string (uiout, "exp", b->exp_string); - do_cleanups (ui_out_chain); - break; - case bp_breakpoint: - case bp_gnu_ifunc_resolver: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - if (b->disposition == disp_del) - printf_filtered (_("Temporary breakpoint")); - else - printf_filtered (_("Breakpoint")); - printf_filtered (_(" %d"), b->number); - if (b->type == bp_gnu_ifunc_resolver) - printf_filtered (_(" at gnu-indirect-function resolver")); - say_where = 1; - break; - case bp_hardware_breakpoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Hardware assisted breakpoint %d"), b->number); - say_where = 1; - break; - case bp_tracepoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Tracepoint")); - printf_filtered (_(" %d"), b->number); - say_where = 1; - break; - case bp_fast_tracepoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Fast tracepoint")); - printf_filtered (_(" %d"), b->number); - say_where = 1; - break; - case bp_static_tracepoint: - if (ui_out_is_mi_like_p (uiout)) - { - say_where = 0; - break; - } - printf_filtered (_("Static tracepoint")); - printf_filtered (_(" %d"), b->number); - say_where = 1; - break; - - case bp_until: - case bp_finish: - case bp_longjmp: - case bp_longjmp_resume: - case bp_exception: - case bp_exception_resume: - case bp_step_resume: - case bp_hp_step_resume: - case bp_call_dummy: - case bp_std_terminate: - case bp_watchpoint_scope: - case bp_shlib_event: - case bp_thread_event: - case bp_overlay_event: - case bp_jit_event: - case bp_longjmp_master: - case bp_std_terminate_master: - case bp_exception_master: - case bp_gnu_ifunc_resolver_return: - break; - } - - if (say_where) - { - /* i18n: cagney/2005-02-11: Below needs to be merged into a - single string. */ - if (b->loc == NULL) - { - printf_filtered (_(" (%s) pending."), b->addr_string); - } - else - { - if (opts.addressprint || b->source_file == NULL) - { - printf_filtered (" at "); - fputs_filtered (paddress (b->loc->gdbarch, b->loc->address), - gdb_stdout); - } - if (b->source_file) - printf_filtered (": file %s, line %d.", - b->source_file, b->line_number); - - if (b->loc->next) - { - struct bp_location *loc = b->loc; - int n = 0; - for (; loc; loc = loc->next) - ++n; - printf_filtered (" (%d locations)", n); - } - - } - } + b->ops->print_mention (b); if (ui_out_is_mi_like_p (uiout)) return; printf_filtered ("\n"); @@ -7545,7 +7078,7 @@ create_breakpoint_sal (struct gdbarch *g if (i == 0) { - b = set_raw_breakpoint (gdbarch, sal, type); + b = set_raw_breakpoint (gdbarch, sal, type, ops); set_breakpoint_number (internal, b); b->thread = thread; b->task = task; @@ -7627,7 +7160,6 @@ create_breakpoint_sal (struct gdbarch *g b->addr_string = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address)); - b->ops = ops; /* Do not mention breakpoints with a negative number, but do notify observers. */ if (!internal) @@ -8085,6 +7617,8 @@ create_breakpoint (struct gdbarch *gdbar int task = 0; int prev_bkpt_count = breakpoint_count; + gdb_assert (ops != NULL); + sals.sals = NULL; sals.nelts = 0; init_linespec_result (&canonical); @@ -8277,7 +7811,7 @@ create_breakpoint (struct gdbarch *gdbar make_cleanup (xfree, copy_arg); - b = set_raw_breakpoint_without_location (gdbarch, type_wanted); + b = set_raw_breakpoint_without_location (gdbarch, type_wanted, ops); set_breakpoint_number (internal, b); b->thread = -1; b->addr_string = canonical.canonical[0]; @@ -8285,7 +7819,6 @@ create_breakpoint (struct gdbarch *gdbar b->ignore_count = ignore_count; b->disposition = tempflag ? disp_del : disp_donttouch; b->condition_not_parsed = 1; - b->ops = ops; b->enable_state = enabled ? bp_enabled : bp_disabled; b->pspace = current_program_space; b->py_bp_object = NULL; @@ -8321,13 +7854,13 @@ create_breakpoint (struct gdbarch *gdbar return 1; } -/* Set a breakpoint. +/* Set a breakpoint. ARG is a string describing breakpoint address, condition, and thread. FLAG specifies if a breakpoint is hardware on, and if breakpoint is temporary, using BP_HARDWARE_FLAG and BP_TEMPFLAG. */ - + static void break_command_1 (char *arg, int flag, int from_tty) { @@ -8342,13 +7875,12 @@ break_command_1 (char *arg, int flag, in tempflag, type_wanted, 0 /* Ignore count */, pending_break_support, - NULL /* breakpoint_ops */, + &bkpt_breakpoint_ops, from_tty, 1 /* enabled */, 0 /* internal */); } - /* Helper function for break_command_1 and disassemble_command. */ void @@ -8528,8 +8060,9 @@ resources_needed_ranged_breakpoint (cons ranged breakpoints. */ static enum print_stop_action -print_it_ranged_breakpoint (struct breakpoint *b) +print_it_ranged_breakpoint (bpstat bs) { + struct breakpoint *b = bs->breakpoint_at; struct bp_location *bl = b->loc; gdb_assert (b->type == bp_hardware_breakpoint); @@ -8638,15 +8171,15 @@ print_recreate_ranged_breakpoint (struct static struct breakpoint_ops ranged_breakpoint_ops = { - NULL, /* dtor */ - NULL, /* allocate_location */ - NULL, /* re_set */ - NULL, /* insert */ - NULL, /* remove */ + bkpt_dtor, + bkpt_allocate_location, + bkpt_re_set, + bkpt_insert_location, + bkpt_remove_location, breakpoint_hit_ranged_breakpoint, - NULL, /* check_status */ + null_check_status, resources_needed_ranged_breakpoint, - NULL, /* works_in_software_mode */ + null_works_in_software_mode, print_it_ranged_breakpoint, print_one_ranged_breakpoint, print_one_detail_ranged_breakpoint, @@ -8796,13 +8329,12 @@ break_range_command (char *arg, int from /* Now set up the breakpoint. */ b = set_raw_breakpoint (get_current_arch (), sal_start, - bp_hardware_breakpoint); + bp_hardware_breakpoint, &ranged_breakpoint_ops); set_breakpoint_count (breakpoint_count + 1); b->number = breakpoint_count; b->disposition = disp_donttouch; b->addr_string = addr_string_start; b->addr_string_range_end = addr_string_end; - b->ops = &ranged_breakpoint_ops; b->loc->length = length; discard_cleanups (cleanup_bkpt); @@ -8921,6 +8453,39 @@ watchpoint_exp_is_const (const struct ex return 1; } +/* Implement the "re_set" breakpoint_ops method for watchpoints. */ + +static void +re_set_watchpoint (struct breakpoint *b) +{ + /* Watchpoint can be either on expression using entirely global + variables, or it can be on local variables. + + Watchpoints of the first kind are never auto-deleted, and even + persist across program restarts. Since they can use variables + from shared libraries, we need to reparse expression as libraries + are loaded and unloaded. + + Watchpoints on local variables can also change meaning as result + of solib event. For example, if a watchpoint uses both a local + and a global variables in expression, it's a local watchpoint, + but unloading of a shared library will make the expression + invalid. This is not a very common use case, but we still + re-evaluate expression, to avoid surprises to the user. + + Note that for local watchpoints, we re-evaluate it only if + watchpoints frame id is still valid. If it's not, it means the + watchpoint is out of scope and will be deleted soon. In fact, + I'm not sure we'll ever be called in this case. + + If a local watchpoint's frame id is still valid, then + b->exp_valid_block is likewise valid, and we can safely use it. + + Don't do anything about disabled watchpoints, since they will + be reevaluated again when enabled. */ + update_watchpoint (b, 1 /* reparse */); +} + /* Implement the "insert" breakpoint_ops method for hardware watchpoints. */ static int @@ -8943,102 +8508,90 @@ remove_watchpoint (struct bp_location *b bl->owner->cond_exp); } -/* Implement the "resources_needed" breakpoint_ops method for - hardware watchpoints. */ - static int -resources_needed_watchpoint (const struct bp_location *bl) +breakpoint_hit_watchpoint (const struct bp_location *bl, + struct address_space *aspace, CORE_ADDR bp_addr) { - int length = bl->owner->exact? 1 : bl->length; - - return target_region_ok_for_hw_watchpoint (bl->address, length); -} + struct breakpoint *b = bl->owner; -/* Implement the "works_in_software_mode" breakpoint_ops method for - hardware watchpoints. */ + /* Continuable hardware watchpoints are treated as non-existent if the + reason we stopped wasn't a hardware watchpoint (we didn't stop on + some data address). Otherwise gdb won't stop on a break instruction + in the code (not from a breakpoint) when a hardware watchpoint has + been defined. Also skip watchpoints which we know did not trigger + (did not match the data address). */ + if (is_hardware_watchpoint (b) + && b->watchpoint_triggered == watch_triggered_no) + return 0; -int -works_in_software_mode_watchpoint (const struct breakpoint *b) -{ - return b->type == bp_hardware_watchpoint; + return 1; } -/* The breakpoint_ops structure to be used in hardware watchpoints. */ - -static struct breakpoint_ops watchpoint_breakpoint_ops = -{ - NULL, /* dtor */ - NULL, /* allocate_location */ - NULL, /* re_set */ - insert_watchpoint, - remove_watchpoint, - NULL, /* breakpoint_hit */ - NULL, /* check_status */ - resources_needed_watchpoint, - works_in_software_mode_watchpoint, - NULL, /* print_it */ - NULL, /* print_one */ - NULL, /* print_one_detail */ - NULL, /* print_mention */ - NULL /* print_recreate */ -}; - -/* Implement the "insert" breakpoint_ops method for - masked hardware watchpoints. */ - -static int -insert_masked_watchpoint (struct bp_location *bl) +static void +check_status_watchpoint (bpstat bs) { - return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask, - bl->watchpoint_type); -} - -/* Implement the "remove" breakpoint_ops method for - masked hardware watchpoints. */ + gdb_assert (is_watchpoint (bs->breakpoint_at)); -static int -remove_masked_watchpoint (struct bp_location *bl) -{ - return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask, - bl->watchpoint_type); + bpstat_check_watchpoint (bs); } /* Implement the "resources_needed" breakpoint_ops method for - masked hardware watchpoints. */ + hardware watchpoints. */ static int -resources_needed_masked_watchpoint (const struct bp_location *bl) +resources_needed_watchpoint (const struct bp_location *bl) { - return target_masked_watch_num_registers (bl->address, - bl->owner->hw_wp_mask); + int length = bl->owner->exact? 1 : bl->length; + + return target_region_ok_for_hw_watchpoint (bl->address, length); } /* Implement the "works_in_software_mode" breakpoint_ops method for - masked hardware watchpoints. */ + hardware watchpoints. */ static int -works_in_software_mode_masked_watchpoint (const struct breakpoint *b) +works_in_software_mode_watchpoint (const struct breakpoint *b) { - return 0; + return b->type == bp_hardware_watchpoint; } -/* Implement the "print_it" breakpoint_ops method for - masked hardware watchpoints. */ - static enum print_stop_action -print_it_masked_watchpoint (struct breakpoint *b) +print_it_watchpoint (bpstat bs) { - /* Masked watchpoints have only one location. */ - gdb_assert (b->loc && b->loc->next == NULL); + struct cleanup *old_chain; + struct breakpoint *b; + const struct bp_location *bl; + struct ui_stream *stb; + enum print_stop_action result; + + gdb_assert (bs->bp_location_at != NULL); + + bl = bs->bp_location_at; + b = bs->breakpoint_at; + + stb = ui_out_stream_new (uiout); + old_chain = make_cleanup_ui_out_stream_delete (stb); switch (b->type) { + case bp_watchpoint: case bp_hardware_watchpoint: annotate_watchpoint (b->number); if (ui_out_is_mi_like_p (uiout)) ui_out_field_string (uiout, "reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER)); + mention (b); + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nOld value = "); + watchpoint_value_print (bs->old_val, stb->stream); + ui_out_field_stream (uiout, "old", stb); + ui_out_text (uiout, "\nNew value = "); + watchpoint_value_print (b->val, stb->stream); + ui_out_field_stream (uiout, "new", stb); + ui_out_text (uiout, "\n"); + /* More than one watchpoint may have been triggered. */ + result = PRINT_UNKNOWN; break; case bp_read_watchpoint: @@ -9046,26 +8599,223 @@ print_it_masked_watchpoint (struct break ui_out_field_string (uiout, "reason", async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER)); + mention (b); + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nValue = "); + watchpoint_value_print (b->val, stb->stream); + ui_out_field_stream (uiout, "value", stb); + ui_out_text (uiout, "\n"); + result = PRINT_UNKNOWN; break; case bp_access_watchpoint: - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); + if (bs->old_val != NULL) + { + annotate_watchpoint (b->number); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); + mention (b); + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nOld value = "); + watchpoint_value_print (bs->old_val, stb->stream); + ui_out_field_stream (uiout, "old", stb); + ui_out_text (uiout, "\nNew value = "); + } + else + { + mention (b); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nValue = "); + } + watchpoint_value_print (b->val, stb->stream); + ui_out_field_stream (uiout, "new", stb); + ui_out_text (uiout, "\n"); + result = PRINT_UNKNOWN; break; default: - internal_error (__FILE__, __LINE__, - _("Invalid hardware watchpoint type.")); + result = PRINT_UNKNOWN; } - mention (b); - ui_out_text (uiout, _("\n\ -Check the underlying instruction at PC for the memory\n\ -address and value which triggered this watchpoint.\n")); - ui_out_text (uiout, "\n"); - - /* More than one watchpoint may have been triggered. */ + do_cleanups (old_chain); + return result; +} + +/* Implement the "print_mention" breakpoint_ops method for hardware + watchpoints. */ + +static void +print_mention_watchpoint (struct breakpoint *b) +{ + struct cleanup *ui_out_chain; + + switch (b->type) + { + case bp_watchpoint: + ui_out_text (uiout, "Watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); + break; + case bp_hardware_watchpoint: + ui_out_text (uiout, "Hardware watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); + break; + case bp_read_watchpoint: + ui_out_text (uiout, "Hardware read watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt"); + break; + case bp_access_watchpoint: + ui_out_text (uiout, "Hardware access (read/write) watchpoint "); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt"); + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid hardware watchpoint type.")); + } + + ui_out_field_int (uiout, "number", b->number); + ui_out_text (uiout, ": "); + ui_out_field_string (uiout, "exp", b->exp_string); + do_cleanups (ui_out_chain); +} + +/* Implement the "print_recreate" breakpoint_ops method for + watchpoints. */ + +static void +print_recreate_watchpoint (struct breakpoint *b, struct ui_file *fp) +{ + char tmp[40]; + + switch (b->type) + { + case bp_watchpoint: + case bp_hardware_watchpoint: + fprintf_unfiltered (fp, "watch"); + break; + case bp_read_watchpoint: + fprintf_unfiltered (fp, "rwatch"); + break; + case bp_access_watchpoint: + fprintf_unfiltered (fp, "awatch"); + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid watchpoint type.")); + } + + fprintf_unfiltered (fp, " %s", b->exp_string); +} + +/* The breakpoint_ops structure to be used in hardware watchpoints. */ + +static struct breakpoint_ops watchpoint_breakpoint_ops = +{ + bkpt_dtor, + bkpt_allocate_location, + re_set_watchpoint, + insert_watchpoint, + remove_watchpoint, + breakpoint_hit_watchpoint, + check_status_watchpoint, + resources_needed_watchpoint, + works_in_software_mode_watchpoint, + print_it_watchpoint, + NULL, /* print_one */ + null_print_one_detail, + print_mention_watchpoint, + print_recreate_watchpoint +}; + +/* Implement the "insert" breakpoint_ops method for + masked hardware watchpoints. */ + +static int +insert_masked_watchpoint (struct bp_location *bl) +{ + return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask, + bl->watchpoint_type); +} + +/* Implement the "remove" breakpoint_ops method for + masked hardware watchpoints. */ + +static int +remove_masked_watchpoint (struct bp_location *bl) +{ + return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask, + bl->watchpoint_type); +} + +/* Implement the "resources_needed" breakpoint_ops method for + masked hardware watchpoints. */ + +static int +resources_needed_masked_watchpoint (const struct bp_location *bl) +{ + return target_masked_watch_num_registers (bl->address, + bl->owner->hw_wp_mask); +} + +/* Implement the "works_in_software_mode" breakpoint_ops method for + masked hardware watchpoints. */ + +static int +works_in_software_mode_masked_watchpoint (const struct breakpoint *b) +{ + return 0; +} + +/* Implement the "print_it" breakpoint_ops method for + masked hardware watchpoints. */ + +static enum print_stop_action +print_it_masked_watchpoint (bpstat bs) +{ + struct breakpoint *b = bs->breakpoint_at; + + /* Masked watchpoints have only one location. */ + gdb_assert (b->loc && b->loc->next == NULL); + + switch (b->type) + { + case bp_hardware_watchpoint: + annotate_watchpoint (b->number); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER)); + break; + + case bp_read_watchpoint: + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER)); + break; + + case bp_access_watchpoint: + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid hardware watchpoint type.")); + } + + mention (b); + ui_out_text (uiout, _("\n\ +Check the underlying instruction at PC for the memory\n\ +address and value which triggered this watchpoint.\n")); + ui_out_text (uiout, "\n"); + + /* More than one watchpoint may have been triggered. */ return PRINT_UNKNOWN; } @@ -9149,13 +8899,13 @@ print_recreate_masked_watchpoint (struct static struct breakpoint_ops masked_watchpoint_breakpoint_ops = { - NULL, /* dtor */ - NULL, /* allocate_location */ - NULL, /* re_set */ + bkpt_dtor, + bkpt_allocate_location, + re_set_watchpoint, insert_masked_watchpoint, remove_masked_watchpoint, - NULL, /* breakpoint_hit */ - NULL, /* check_status */ + breakpoint_hit_watchpoint, + check_status_watchpoint, resources_needed_masked_watchpoint, works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint, @@ -9394,12 +9144,18 @@ watch_command_1 (char *arg, int accessfl } /* Now set up the breakpoint. */ - b = set_raw_breakpoint_without_location (NULL, bp_type); + if (use_mask) + b = set_raw_breakpoint_without_location (NULL, bp_type, + &masked_watchpoint_breakpoint_ops); + else + b = set_raw_breakpoint_without_location (NULL, bp_type, + &watchpoint_breakpoint_ops); b->thread = thread; b->disposition = disp_donttouch; b->exp = exp; b->exp_valid_block = exp_valid_block; b->cond_exp_valid_block = cond_exp_valid_block; + b->pspace = current_program_space; if (just_location) { struct type *t = value_type (val); @@ -9425,13 +9181,11 @@ watch_command_1 (char *arg, int accessfl if (use_mask) { b->hw_wp_mask = mask; - b->ops = &masked_watchpoint_breakpoint_ops; } else { b->val = val; b->val_valid = 1; - b->ops = &watchpoint_breakpoint_ops; } if (cond_start) @@ -9881,8 +9635,9 @@ catch_exec_command_1 (char *arg, int fro } static enum print_stop_action -print_it_exception_catchpoint (struct breakpoint *b) +print_it_exception_catchpoint (bpstat bs) { + struct breakpoint *b = bs->breakpoint_at; int bp_temp, bp_throw; annotate_catchpoint (b->number); @@ -9968,18 +9723,18 @@ print_recreate_exception_catchpoint (str } static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = { - NULL, /* dtor */ - NULL, /* allocate_location */ - NULL, /* re_set */ - NULL, /* insert */ - NULL, /* remove */ - NULL, /* breakpoint_hit */ - NULL, /* check_status */ - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + bkpt_dtor, + bkpt_allocate_location, + bkpt_re_set, + bkpt_insert_location, + bkpt_remove_location, + bkpt_breakpoint_hit, + bkpt_check_status, + bkpt_resources_needed, + null_works_in_software_mode, print_it_exception_catchpoint, print_one_exception_catchpoint, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_exception_catchpoint, print_recreate_exception_catchpoint }; @@ -10678,127 +10433,730 @@ update_global_location_list (int should_ } } - /* Rescan breakpoints at the same address and section, marking the - first one as "first" and any others as "duplicates". This is so - that the bpt instruction is only inserted once. If we have a - permanent breakpoint at the same place as BPT, make that one the - official one, and the rest as duplicates. Permanent breakpoints - are sorted first for the same address. - - Do the same for hardware watchpoints, but also considering the - watchpoint's type (regular/access/read) and length. */ + /* Rescan breakpoints at the same address and section, marking the + first one as "first" and any others as "duplicates". This is so + that the bpt instruction is only inserted once. If we have a + permanent breakpoint at the same place as BPT, make that one the + official one, and the rest as duplicates. Permanent breakpoints + are sorted first for the same address. + + Do the same for hardware watchpoints, but also considering the + watchpoint's type (regular/access/read) and length. */ + + bp_loc_first = NULL; + wp_loc_first = NULL; + awp_loc_first = NULL; + rwp_loc_first = NULL; + ALL_BP_LOCATIONS (loc, locp) + { + /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always + non-NULL. */ + struct breakpoint *b = loc->owner; + struct bp_location **loc_first_p; + + if (b->enable_state == bp_disabled + || b->enable_state == bp_call_disabled + || b->enable_state == bp_startup_disabled + || !loc->enabled + || loc->shlib_disabled + || !breakpoint_address_is_meaningful (b) + || is_tracepoint (b)) + continue; + + /* Permanent breakpoint should always be inserted. */ + if (b->enable_state == bp_permanent && ! loc->inserted) + internal_error (__FILE__, __LINE__, + _("allegedly permanent breakpoint is not " + "actually inserted")); + + if (b->type == bp_hardware_watchpoint) + loc_first_p = &wp_loc_first; + else if (b->type == bp_read_watchpoint) + loc_first_p = &rwp_loc_first; + else if (b->type == bp_access_watchpoint) + loc_first_p = &awp_loc_first; + else + loc_first_p = &bp_loc_first; + + if (*loc_first_p == NULL + || (overlay_debugging && loc->section != (*loc_first_p)->section) + || !breakpoint_locations_match (loc, *loc_first_p)) + { + *loc_first_p = loc; + loc->duplicate = 0; + continue; + } + + loc->duplicate = 1; + + if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted + && b->enable_state != bp_permanent) + internal_error (__FILE__, __LINE__, + _("another breakpoint was inserted on top of " + "a permanent breakpoint")); + } + + if (breakpoints_always_inserted_mode () && should_insert + && (have_live_inferiors () + || (gdbarch_has_global_breakpoints (target_gdbarch)))) + insert_breakpoint_locations (); + + do_cleanups (cleanups); +} + +void +breakpoint_retire_moribund (void) +{ + struct bp_location *loc; + int ix; + + for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix) + if (--(loc->events_till_retirement) == 0) + { + decref_bp_location (&loc); + VEC_unordered_remove (bp_location_p, moribund_locations, ix); + --ix; + } +} + +static void +update_global_location_list_nothrow (int inserting) +{ + struct gdb_exception e; + + TRY_CATCH (e, RETURN_MASK_ERROR) + update_global_location_list (inserting); +} + +/* Clear BKP from a BPS. */ + +static void +bpstat_remove_bp_location (bpstat bps, struct breakpoint *bpt) +{ + bpstat bs; + + for (bs = bps; bs; bs = bs->next) + if (bs->breakpoint_at == bpt) + { + bs->breakpoint_at = NULL; + bs->old_val = NULL; + /* bs->commands will be freed later. */ + } +} + +/* Callback for iterate_over_threads. */ +static int +bpstat_remove_breakpoint_callback (struct thread_info *th, void *data) +{ + struct breakpoint *bpt = data; + + bpstat_remove_bp_location (th->control.stop_bpstat, bpt); + return 0; +} + +/* Helper for breakpoint and tracepoint breakpoint_ops->mention + callbacks. */ + +static void +say_where (struct breakpoint *b) +{ + struct value_print_options opts; + + get_user_print_options (&opts); + + /* i18n: cagney/2005-02-11: Below needs to be merged into a + single string. */ + if (b->loc == NULL) + { + printf_filtered (_(" (%s) pending."), b->addr_string); + } + else + { + if (opts.addressprint || b->source_file == NULL) + { + printf_filtered (" at "); + fputs_filtered (paddress (b->loc->gdbarch, b->loc->address), + gdb_stdout); + } + if (b->source_file) + printf_filtered (": file %s, line %d.", + b->source_file, b->line_number); + + if (b->loc->next) + { + struct bp_location *loc = b->loc; + int n = 0; + for (; loc; loc = loc->next) + ++n; + printf_filtered (" (%d locations)", n); + } + } +} + +/* Default breakpoint_ops methods that do nothing. */ + +void +null_re_set (struct breakpoint *b) +{ + /* Nothing to re-set. */ +} + +void +null_check_status (bpstat bs) +{ + /* nothing */ +} + +/* A "works_in_software_mode" breakpoint_ops method that just internal + errors. */ + +int +null_works_in_software_mode (const struct breakpoint *b) +{ + gdb_assert_not_reached (""); +} + +/* A "resources_needed" breakpoint_ops method that just internal + errors. */ + +int +null_resources_needed (const struct bp_location *bl) +{ + gdb_assert_not_reached (""); +} + +void +null_print_one_detail (const struct breakpoint *self, + struct ui_out *uiout) +{ + /* nothing */ +} + +/* Default bp_location_ops methods. */ + +static void +bp_location_dtor (struct bp_location *self) +{ + xfree (self->cond); + xfree (self->function_name); +} + +static const struct bp_location_ops bp_location_ops = +{ + bp_location_dtor +}; + +/* Default breakpoint_ops methods. */ + +void +bkpt_dtor (struct breakpoint *self) +{ + decref_counted_command_line (&self->commands); + xfree (self->cond_string); + xfree (self->cond_exp); + xfree (self->addr_string); + xfree (self->addr_string_range_end); + xfree (self->exp); + xfree (self->exp_string); + xfree (self->exp_string_reparse); + value_free (self->val); + xfree (self->source_file); +} + +struct bp_location * +bkpt_allocate_location (struct breakpoint *self) +{ + struct bp_location *loc; + + loc = XNEW (struct bp_location); + init_bp_location (loc, &bp_location_ops, self); + return loc; +} + +void +bkpt_re_set (struct breakpoint *b) +{ + switch (b->type) + { + case bp_breakpoint: + case bp_hardware_breakpoint: + case bp_gnu_ifunc_resolver: + /* Do not attempt to re-set breakpoints disabled during + startup. */ + if (b->enable_state == bp_startup_disabled) + return; + + if (b->addr_string == NULL) + { + /* Anything without a string can't be re-set. */ + delete_breakpoint (b); + return; + } + + breakpoint_re_set_default (b); + break; + + default: + printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type); + /* fall through */ + /* Delete overlay event and longjmp master breakpoints; they + will be reset later by breakpoint_re_set. */ + case bp_overlay_event: + case bp_longjmp_master: + case bp_std_terminate_master: + case bp_exception_master: + delete_breakpoint (b); + break; + + /* This breakpoint is special, it's set up when the inferior + starts and we really don't want to touch it. */ + case bp_shlib_event: + + /* Like bp_shlib_event, this breakpoint type is special. Once + it is set up, we do not want to touch it. */ + case bp_thread_event: + + /* Keep temporary breakpoints, which can be encountered when we + step over a dlopen call and SOLIB_ADD is resetting the + breakpoints. Otherwise these should have been blown away via + the cleanup chain or by breakpoint_init_inferior when we + rerun the executable. */ + case bp_until: + case bp_finish: + case bp_watchpoint_scope: + case bp_call_dummy: + case bp_std_terminate: + case bp_step_resume: + case bp_hp_step_resume: + case bp_longjmp: + case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: + case bp_jit_event: + case bp_gnu_ifunc_resolver_return: + break; + } +} + +int +bkpt_insert_location (struct bp_location *bl) +{ + if (bl->loc_type == bp_loc_hardware_breakpoint) + return target_insert_hw_breakpoint (bl->gdbarch, + &bl->target_info); + else + return target_insert_breakpoint (bl->gdbarch, + &bl->target_info); +} + +int +bkpt_remove_location (struct bp_location *bl) +{ + if (bl->loc_type == bp_loc_hardware_breakpoint) + return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info); + else + return target_remove_breakpoint (bl->gdbarch, &bl->target_info); +} + +int +bkpt_breakpoint_hit (const struct bp_location *bl, + struct address_space *aspace, CORE_ADDR bp_addr) +{ + struct breakpoint *b = bl->owner; + + if (!breakpoint_address_match (bl->pspace->aspace, bl->address, + aspace, bp_addr)) + return 0; + + if (overlay_debugging /* unmapped overlay section */ + && section_is_overlay (bl->section) + && !section_is_mapped (bl->section)) + return 0; + + return 1; +} + +void +bkpt_check_status (bpstat bs) +{ + struct breakpoint *b = bs->breakpoint_at; + + if (b->type == bp_thread_event + || b->type == bp_overlay_event + || b->type == bp_longjmp_master + || b->type == bp_std_terminate_master + || b->type == bp_exception_master) + /* We do not stop for these. */ + bs->stop = 0; +} + +int +bkpt_resources_needed (const struct bp_location *bl) +{ + gdb_assert (bl->owner->type == bp_hardware_breakpoint); + + return 1; +} + +int +bkpt_works_in_software_mode (const struct breakpoint *b) +{ + gdb_assert_not_reached (""); +} + +enum print_stop_action +bkpt_print_it (bpstat bs) +{ + struct cleanup *old_chain; + struct breakpoint *b; + const struct bp_location *bl; + struct ui_stream *stb; + int bp_temp = 0; + enum print_stop_action result; + + gdb_assert (bs->bp_location_at != NULL); + + bl = bs->bp_location_at; + b = bs->breakpoint_at; + + stb = ui_out_stream_new (uiout); + old_chain = make_cleanup_ui_out_stream_delete (stb); + + switch (b->type) + { + case bp_breakpoint: + case bp_hardware_breakpoint: + bp_temp = b->disposition == disp_del; + if (bl->address != bl->requested_address) + breakpoint_adjustment_warning (bl->requested_address, + bl->address, + b->number, 1); + annotate_breakpoint (b->number); + if (bp_temp) + ui_out_text (uiout, "\nTemporary breakpoint "); + else + ui_out_text (uiout, "\nBreakpoint "); + if (ui_out_is_mi_like_p (uiout)) + { + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT)); + ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); + } + ui_out_field_int (uiout, "bkptno", b->number); + ui_out_text (uiout, ", "); + result = PRINT_SRC_AND_LOC; + break; + + case bp_shlib_event: + /* Did we stop because the user set the stop_on_solib_events + variable? (If so, we report this as a generic, "Stopped due + to shlib event" message.) */ + printf_filtered (_("Stopped due to shared library event\n")); + result = PRINT_NOTHING; + break; + + case bp_thread_event: + /* Not sure how we will get here. + GDB should not stop for these breakpoints. */ + printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n")); + result = PRINT_NOTHING; + break; + + case bp_overlay_event: + /* By analogy with the thread event, GDB should not stop for these. */ + printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n")); + result = PRINT_NOTHING; + break; + + case bp_longjmp_master: + /* These should never be enabled. */ + printf_filtered (_("Longjmp Master Breakpoint: gdb should not stop!\n")); + result = PRINT_NOTHING; + break; + + case bp_std_terminate_master: + /* These should never be enabled. */ + printf_filtered (_("std::terminate Master Breakpoint: " + "gdb should not stop!\n")); + result = PRINT_NOTHING; + break; + + case bp_exception_master: + /* These should never be enabled. */ + printf_filtered (_("Exception Master Breakpoint: " + "gdb should not stop!\n")); + result = PRINT_NOTHING; + break; + + /* Fall through, we don't deal with these types of breakpoints + here. */ + + case bp_finish: + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_FUNCTION_FINISHED)); + result = PRINT_UNKNOWN; + break; + + case bp_until: + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_LOCATION_REACHED)); + result = PRINT_UNKNOWN; + break; + + case bp_none: + case bp_longjmp: + case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: + case bp_step_resume: + case bp_hp_step_resume: + case bp_watchpoint_scope: + case bp_call_dummy: + case bp_std_terminate: + case bp_tracepoint: + case bp_fast_tracepoint: + case bp_jit_event: + case bp_gnu_ifunc_resolver: + case bp_gnu_ifunc_resolver_return: + default: + result = PRINT_UNKNOWN; + break; + } + + do_cleanups (old_chain); + return result; +} + +void +bkpt_print_mention (struct breakpoint *b) +{ + if (ui_out_is_mi_like_p (uiout)) + return; + + switch (b->type) + { + case bp_breakpoint: + case bp_gnu_ifunc_resolver: + if (b->disposition == disp_del) + printf_filtered (_("Temporary breakpoint")); + else + printf_filtered (_("Breakpoint")); + printf_filtered (_(" %d"), b->number); + if (b->type == bp_gnu_ifunc_resolver) + printf_filtered (_(" at gnu-indirect-function resolver")); + say_where (b); + break; + case bp_hardware_breakpoint: + printf_filtered (_("Hardware assisted breakpoint %d"), b->number); + say_where (b); + break; + case bp_until: + case bp_finish: + case bp_longjmp: + case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: + case bp_step_resume: + case bp_hp_step_resume: + case bp_call_dummy: + case bp_std_terminate: + case bp_watchpoint_scope: + case bp_shlib_event: + case bp_thread_event: + case bp_overlay_event: + case bp_jit_event: + case bp_longjmp_master: + case bp_std_terminate_master: + case bp_exception_master: + case bp_gnu_ifunc_resolver_return: + break; + } +} + +void +bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp) +{ + if (tp->type == bp_breakpoint && tp->disposition == disp_del) + fprintf_unfiltered (fp, "tbreak"); + else if (tp->type == bp_breakpoint) + fprintf_unfiltered (fp, "break"); + else if (tp->type == bp_hardware_breakpoint + && tp->disposition == disp_del) + fprintf_unfiltered (fp, "thbreak"); + else if (tp->type == bp_hardware_breakpoint) + fprintf_unfiltered (fp, "hbreak"); + else + internal_error (__FILE__, __LINE__, + _("unhandled breakpoint type %d"), (int) tp->type); - bp_loc_first = NULL; - wp_loc_first = NULL; - awp_loc_first = NULL; - rwp_loc_first = NULL; - ALL_BP_LOCATIONS (loc, locp) + if (tp->exp_string) + fprintf_unfiltered (fp, " %s", tp->exp_string); + else if (tp->addr_string) + fprintf_unfiltered (fp, " %s", tp->addr_string); + else { - /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always - non-NULL. */ - struct breakpoint *b = loc->owner; - struct bp_location **loc_first_p; + char tmp[40]; - if (b->enable_state == bp_disabled - || b->enable_state == bp_call_disabled - || b->enable_state == bp_startup_disabled - || !loc->enabled - || loc->shlib_disabled - || !breakpoint_address_is_meaningful (b) - || is_tracepoint (b)) - continue; + sprintf_vma (tmp, tp->loc->address); + fprintf_unfiltered (fp, " *0x%s", tmp); + } +} - /* Permanent breakpoint should always be inserted. */ - if (b->enable_state == bp_permanent && ! loc->inserted) - internal_error (__FILE__, __LINE__, - _("allegedly permanent breakpoint is not " - "actually inserted")); +/* The breakpoint_ops structure to be used in regular breakpoints. */ - if (b->type == bp_hardware_watchpoint) - loc_first_p = &wp_loc_first; - else if (b->type == bp_read_watchpoint) - loc_first_p = &rwp_loc_first; - else if (b->type == bp_access_watchpoint) - loc_first_p = &awp_loc_first; - else - loc_first_p = &bp_loc_first; +struct breakpoint_ops bkpt_breakpoint_ops = +{ + bkpt_dtor, + bkpt_allocate_location, + bkpt_re_set, + bkpt_insert_location, + bkpt_remove_location, + bkpt_breakpoint_hit, + bkpt_check_status, + bkpt_resources_needed, + null_works_in_software_mode, + bkpt_print_it, + NULL, /* print_one */ + null_print_one_detail, + bkpt_print_mention, + bkpt_print_recreate +}; - if (*loc_first_p == NULL - || (overlay_debugging && loc->section != (*loc_first_p)->section) - || !breakpoint_locations_match (loc, *loc_first_p)) - { - *loc_first_p = loc; - loc->duplicate = 0; - continue; - } +/* The breakpoint_ops structure to be used in tracepoints. */ - loc->duplicate = 1; +void +tracepoint_re_set (struct breakpoint *b) +{ + breakpoint_re_set_default (b); +} - if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted - && b->enable_state != bp_permanent) - internal_error (__FILE__, __LINE__, - _("another breakpoint was inserted on top of " - "a permanent breakpoint")); - } +static int +tracepoint_insert_location (struct bp_location *bl) +{ + gdb_assert_not_reached (""); +} - if (breakpoints_always_inserted_mode () && should_insert - && (have_live_inferiors () - || (gdbarch_has_global_breakpoints (target_gdbarch)))) - insert_breakpoint_locations (); +static int +tracepoint_remove_location (struct bp_location *bl) +{ + gdb_assert_not_reached (""); +} - do_cleanups (cleanups); +static int +tracepoint_breakpoint_hit (const struct bp_location *bl, + struct address_space *aspace, CORE_ADDR bp_addr) +{ + /* By definition, the inferior does not report stops at + tracepoints. */ + return 0; } -void -breakpoint_retire_moribund (void) +static void +tracepoint_check_status (bpstat bs) { - struct bp_location *loc; - int ix; + gdb_assert_not_reached (""); +} - for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix) - if (--(loc->events_till_retirement) == 0) - { - decref_bp_location (&loc); - VEC_unordered_remove (bp_location_p, moribund_locations, ix); - --ix; - } +static int +tracepoint_works_in_software_mode (const struct breakpoint *b) +{ + gdb_assert_not_reached (""); +} + +static enum print_stop_action +tracepoint_print_it (bpstat bs) +{ + gdb_assert_not_reached (""); } static void -update_global_location_list_nothrow (int inserting) +tracepoint_print_one_detail (const struct breakpoint *self, + struct ui_out *uiout) { - struct gdb_exception e; + if (self->static_trace_marker_id) + { + gdb_assert (self->type == bp_static_tracepoint); - TRY_CATCH (e, RETURN_MASK_ERROR) - update_global_location_list (inserting); + ui_out_text (uiout, "\tmarker id is "); + ui_out_field_string (uiout, "static-tracepoint-marker-string-id", + self->static_trace_marker_id); + ui_out_text (uiout, "\n"); + } } -/* Clear BKP from a BPS. */ - static void -bpstat_remove_bp_location (bpstat bps, struct breakpoint *bpt) +tracepoint_print_mention (struct breakpoint *b) { - bpstat bs; + if (ui_out_is_mi_like_p (uiout)) + return; - for (bs = bps; bs; bs = bs->next) - if (bs->breakpoint_at == bpt) - { - bs->breakpoint_at = NULL; - bs->old_val = NULL; - /* bs->commands will be freed later. */ - } + switch (b->type) + { + case bp_tracepoint: + printf_filtered (_("Tracepoint")); + printf_filtered (_(" %d"), b->number); + break; + case bp_fast_tracepoint: + printf_filtered (_("Fast tracepoint")); + printf_filtered (_(" %d"), b->number); + break; + case bp_static_tracepoint: + printf_filtered (_("Static tracepoint")); + printf_filtered (_(" %d"), b->number); + break; + } + + say_where (b); } -/* Callback for iterate_over_threads. */ -static int -bpstat_remove_breakpoint_callback (struct thread_info *th, void *data) +static void +tracepoint_print_recreate (struct breakpoint *tp, struct ui_file *fp) { - struct breakpoint *bpt = data; + if (tp->type == bp_fast_tracepoint) + fprintf_unfiltered (fp, "ftrace"); + if (tp->type == bp_static_tracepoint) + fprintf_unfiltered (fp, "strace"); + else if (tp->type == bp_tracepoint) + fprintf_unfiltered (fp, "trace"); + else + internal_error (__FILE__, __LINE__, + _("unhandled tracepoint type %d"), (int) tp->type); - bpstat_remove_bp_location (th->control.stop_bpstat, bpt); - return 0; + if (tp->exp_string) + fprintf_unfiltered (fp, " %s", tp->exp_string); + else if (tp->addr_string) + fprintf_unfiltered (fp, " %s", tp->addr_string); + else + { + char tmp[40]; + + sprintf_vma (tmp, tp->loc->address); + fprintf_unfiltered (fp, " *0x%s", tmp); + } } +struct breakpoint_ops tracepoint_breakpoint_ops = +{ + bkpt_dtor, + bkpt_allocate_location, + tracepoint_re_set, + tracepoint_insert_location, + tracepoint_remove_location, + tracepoint_breakpoint_hit, + tracepoint_check_status, + null_resources_needed, + tracepoint_works_in_software_mode, + tracepoint_print_it, + NULL, /* print_one */ + tracepoint_print_one_detail, + tracepoint_print_mention, + tracepoint_print_recreate +}; + /* Delete a breakpoint and clean up all traces of it in the data structures. */ @@ -10863,21 +11221,6 @@ delete_breakpoint (struct breakpoint *bp break; } - if (bpt->ops != NULL && bpt->ops->dtor != NULL) - bpt->ops->dtor (bpt); - - decref_counted_command_line (&bpt->commands); - xfree (bpt->cond_string); - xfree (bpt->cond_exp); - xfree (bpt->addr_string); - xfree (bpt->addr_string_range_end); - xfree (bpt->exp); - xfree (bpt->exp_string); - xfree (bpt->exp_string_reparse); - value_free (bpt->val); - xfree (bpt->source_file); - - /* Be sure no bpstat's are pointing at the breakpoint after it's been freed. */ /* FIXME, how can we find all bpstat's? We just check stop_bpstat @@ -10898,11 +11241,10 @@ delete_breakpoint (struct breakpoint *bp self-contained, but it's not the case now. */ update_global_location_list (0); - + bpt->ops->dtor (bpt); /* On the chance that someone will soon try again to delete this same bp, we mark it as deleted before freeing its storage. */ bpt->type = bp_none; - xfree (bpt); } @@ -11421,7 +11763,11 @@ addr_string_to_sals (struct breakpoint * return sals; } -void +/* The default re_set method, for typical hardware or software + breakpoints. Reevaluate the breakpoint and recreate its + locations. */ + +static void breakpoint_re_set_default (struct breakpoint *b) { int found; @@ -11473,129 +11819,11 @@ breakpoint_re_set_one (void *bint) { /* Get past catch_errs. */ struct breakpoint *b = (struct breakpoint *) bint; + struct cleanup *cleanups; - if (b->ops != NULL && b->ops->re_set != NULL) - { - struct cleanup *cleanups; - - cleanups = prepare_re_set_context (b); - b->ops->re_set (b); - do_cleanups (cleanups); - - return 0; - } - - switch (b->type) - { - case bp_none: - warning (_("attempted to reset apparently deleted breakpoint #%d?"), - b->number); - return 0; - case bp_breakpoint: - case bp_hardware_breakpoint: - case bp_tracepoint: - case bp_fast_tracepoint: - case bp_static_tracepoint: - case bp_gnu_ifunc_resolver: - /* Do not attempt to re-set breakpoints disabled during startup. */ - if (b->enable_state == bp_startup_disabled) - return 0; - - if (b->addr_string == NULL) - { - /* Anything without a string can't be re-set. */ - delete_breakpoint (b); - return 0; - } - - { - struct cleanup *cleanups; - - cleanups = prepare_re_set_context (b); - breakpoint_re_set_default (b); - do_cleanups (cleanups); - } - break; - - case bp_watchpoint: - case bp_hardware_watchpoint: - case bp_read_watchpoint: - case bp_access_watchpoint: - /* Watchpoint can be either on expression using entirely global - variables, or it can be on local variables. - - Watchpoints of the first kind are never auto-deleted, and - even persist across program restarts. Since they can use - variables from shared libraries, we need to reparse - expression as libraries are loaded and unloaded. - - Watchpoints on local variables can also change meaning as - result of solib event. For example, if a watchpoint uses - both a local and a global variables in expression, it's a - local watchpoint, but unloading of a shared library will make - the expression invalid. This is not a very common use case, - but we still re-evaluate expression, to avoid surprises to - the user. - - Note that for local watchpoints, we re-evaluate it only if - watchpoints frame id is still valid. If it's not, it means - the watchpoint is out of scope and will be deleted soon. In - fact, I'm not sure we'll ever be called in this case. - - If a local watchpoint's frame id is still valid, then - b->exp_valid_block is likewise valid, and we can safely use it. - - Don't do anything about disabled watchpoints, since they will - be reevaluated again when enabled. */ - update_watchpoint (b, 1 /* reparse */); - break; - /* We needn't really do anything to reset these, since the mask - that requests them is unaffected by e.g., new libraries being - loaded. */ - case bp_catchpoint: - break; - - default: - printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type); - /* fall through */ - /* Delete overlay event and longjmp master breakpoints; they will be - reset later by breakpoint_re_set. */ - case bp_overlay_event: - case bp_longjmp_master: - case bp_std_terminate_master: - case bp_exception_master: - delete_breakpoint (b); - break; - - /* This breakpoint is special, it's set up when the inferior - starts and we really don't want to touch it. */ - case bp_shlib_event: - - /* Like bp_shlib_event, this breakpoint type is special. - Once it is set up, we do not want to touch it. */ - case bp_thread_event: - - /* Keep temporary breakpoints, which can be encountered when we - step over a dlopen call and SOLIB_ADD is resetting the - breakpoints. Otherwise these should have been blown away via - the cleanup chain or by breakpoint_init_inferior when we - rerun the executable. */ - case bp_until: - case bp_finish: - case bp_watchpoint_scope: - case bp_call_dummy: - case bp_std_terminate: - case bp_step_resume: - case bp_hp_step_resume: - case bp_longjmp: - case bp_longjmp_resume: - case bp_exception: - case bp_exception_resume: - case bp_jit_event: - case bp_gnu_ifunc_resolver_return: - break; - } - + cleanups = prepare_re_set_context (b); + b->ops->re_set (b); + do_cleanups (cleanups); return 0; } @@ -12347,7 +12575,7 @@ trace_command (char *arg, int from_tty) bp_tracepoint /* type_wanted */, 0 /* Ignore count */, pending_break_support, - NULL, + &tracepoint_breakpoint_ops, from_tty, 1 /* enabled */, 0 /* internal */)) @@ -12364,7 +12592,7 @@ ftrace_command (char *arg, int from_tty) bp_fast_tracepoint /* type_wanted */, 0 /* Ignore count */, pending_break_support, - NULL, + &tracepoint_breakpoint_ops, from_tty, 1 /* enabled */, 0 /* internal */)) @@ -12383,7 +12611,7 @@ strace_command (char *arg, int from_tty) bp_static_tracepoint /* type_wanted */, 0 /* Ignore count */, pending_break_support, - NULL, + &tracepoint_breakpoint_ops, from_tty, 1 /* enabled */, 0 /* internal */)) @@ -12448,7 +12676,7 @@ create_tracepoint_from_upload (struct up utp->type /* type_wanted */, 0 /* Ignore count */, pending_break_support, - NULL, + &tracepoint_breakpoint_ops, 0 /* from_tty */, utp->enabled /* enabled */, 0 /* internal */)) @@ -12774,49 +13002,7 @@ save_breakpoints (char *filename, int fr if (filter && !filter (tp)) continue; - if (tp->ops != NULL && tp->ops->print_recreate != NULL) - (tp->ops->print_recreate) (tp, fp); - else - { - if (tp->type == bp_fast_tracepoint) - fprintf_unfiltered (fp, "ftrace"); - if (tp->type == bp_static_tracepoint) - fprintf_unfiltered (fp, "strace"); - else if (tp->type == bp_tracepoint) - fprintf_unfiltered (fp, "trace"); - else if (tp->type == bp_breakpoint && tp->disposition == disp_del) - fprintf_unfiltered (fp, "tbreak"); - else if (tp->type == bp_breakpoint) - fprintf_unfiltered (fp, "break"); - else if (tp->type == bp_hardware_breakpoint - && tp->disposition == disp_del) - fprintf_unfiltered (fp, "thbreak"); - else if (tp->type == bp_hardware_breakpoint) - fprintf_unfiltered (fp, "hbreak"); - else if (tp->type == bp_watchpoint) - fprintf_unfiltered (fp, "watch"); - else if (tp->type == bp_hardware_watchpoint) - fprintf_unfiltered (fp, "watch"); - else if (tp->type == bp_read_watchpoint) - fprintf_unfiltered (fp, "rwatch"); - else if (tp->type == bp_access_watchpoint) - fprintf_unfiltered (fp, "awatch"); - else - internal_error (__FILE__, __LINE__, - _("unhandled breakpoint type %d"), (int) tp->type); - - if (tp->exp_string) - fprintf_unfiltered (fp, " %s", tp->exp_string); - else if (tp->addr_string) - fprintf_unfiltered (fp, " %s", tp->addr_string); - else - { - char tmp[40]; - - sprintf_vma (tmp, tp->loc->address); - fprintf_unfiltered (fp, " *0x%s", tmp); - } - } + tp->ops->print_recreate (tp, fp); if (tp->thread != -1) fprintf_unfiltered (fp, " thread %d", tp->thread); Index: src/gdb/ada-lang.c =================================================================== --- src.orig/gdb/ada-lang.c 2011-06-22 18:52:55.000000000 +0100 +++ src/gdb/ada-lang.c 2011-06-24 17:04:42.348082956 +0100 @@ -10860,6 +10860,8 @@ dtor_exception (enum exception_catchpoin struct ada_catchpoint *c = (struct ada_catchpoint *) b; xfree (c->excep_string); + + bkpt_dtor (b); } /* Implement the ALLOCATE_LOCATION method in the breakpoint_ops @@ -10887,7 +10889,7 @@ re_set_exception (enum exception_catchpo /* Call the base class's method. This updates the catchpoint's locations. */ - breakpoint_re_set_default (b); + bkpt_re_set (b); /* Reparse the exception conditional expressions. One for each location. */ @@ -10946,8 +10948,10 @@ check_status_exception (enum exception_c for all exception catchpoint kinds. */ static enum print_stop_action -print_it_exception (enum exception_catchpoint_kind ex, struct breakpoint *b) +print_it_exception (enum exception_catchpoint_kind ex, bpstat bs) { + struct breakpoint *b = bs->breakpoint_at; + annotate_catchpoint (b->number); if (ui_out_is_mi_like_p (uiout)) @@ -11149,9 +11153,9 @@ check_status_catch_exception (bpstat bs) } static enum print_stop_action -print_it_catch_exception (struct breakpoint *b) +print_it_catch_exception (bpstat bs) { - return print_it_exception (ex_catch_exception, b); + return print_it_exception (ex_catch_exception, bs); } static void @@ -11177,15 +11181,15 @@ static struct breakpoint_ops catch_excep dtor_catch_exception, allocate_location_catch_exception, re_set_catch_exception, - NULL, /* insert */ - NULL, /* remove */ - NULL, /* breakpoint_hit */ + bkpt_insert_location, + bkpt_remove_location, + bkpt_breakpoint_hit, check_status_catch_exception, - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + bkpt_resources_needed, + null_works_in_software_mode, print_it_catch_exception, print_one_catch_exception, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_catch_exception, print_recreate_catch_exception }; @@ -11217,9 +11221,9 @@ check_status_catch_exception_unhandled ( } static enum print_stop_action -print_it_catch_exception_unhandled (struct breakpoint *b) +print_it_catch_exception_unhandled (bpstat bs) { - return print_it_exception (ex_catch_exception_unhandled, b); + return print_it_exception (ex_catch_exception_unhandled, bs); } static void @@ -11246,15 +11250,15 @@ static struct breakpoint_ops catch_excep dtor_catch_exception_unhandled, allocate_location_catch_exception_unhandled, re_set_catch_exception_unhandled, - NULL, /* insert */ - NULL, /* remove */ - NULL, /* breakpoint_hit */ + bkpt_insert_location, + bkpt_remove_location, + bkpt_breakpoint_hit, check_status_catch_exception_unhandled, - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + bkpt_resources_needed, + null_works_in_software_mode, print_it_catch_exception_unhandled, print_one_catch_exception_unhandled, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_catch_exception_unhandled, print_recreate_catch_exception_unhandled }; @@ -11286,9 +11290,9 @@ check_status_catch_assert (bpstat bs) } static enum print_stop_action -print_it_catch_assert (struct breakpoint *b) +print_it_catch_assert (bpstat bs) { - return print_it_exception (ex_catch_assert, b); + return print_it_exception (ex_catch_assert, bs); } static void @@ -11313,15 +11317,15 @@ static struct breakpoint_ops catch_asser dtor_catch_assert, allocate_location_catch_assert, re_set_catch_assert, - NULL, /* insert */ - NULL, /* remove */ - NULL, /* breakpoint_hit */ + bkpt_insert_location, + bkpt_remove_location, + bkpt_breakpoint_hit, check_status_catch_assert, - NULL, /* resources_needed */ - NULL, /* works_in_software_mode */ + bkpt_resources_needed, + null_works_in_software_mode, print_it_catch_assert, print_one_catch_assert, - NULL, /* print_one_detail */ + null_print_one_detail, print_mention_catch_assert, print_recreate_catch_assert }; Index: src/gdb/breakpoint.h =================================================================== --- src.orig/gdb/breakpoint.h 2011-06-22 18:52:55.000000000 +0100 +++ src/gdb/breakpoint.h 2011-06-24 17:27:56.988082476 +0100 @@ -422,8 +422,8 @@ struct breakpoint_ops void (*re_set) (struct breakpoint *self); /* Insert the breakpoint or watchpoint or activate the catchpoint. - Return 0 for success, 1 if the breakpoint, watchpoint or catchpoint - type is not supported, -1 for failure. */ + Return 0 for success, 1 if the breakpoint, watchpoint or + catchpoint type is not supported, -1 for failure. */ int (*insert_location) (struct bp_location *); /* Remove the breakpoint/catchpoint that was previously inserted @@ -454,7 +454,7 @@ struct breakpoint_ops /* The normal print routine for this breakpoint, called when we hit it. */ - enum print_stop_action (*print_it) (struct breakpoint *); + enum print_stop_action (*print_it) (struct bpstats *bs); /* Display information about this breakpoint, for "info breakpoints". */ @@ -801,9 +801,19 @@ struct bpstat_what print_it_done, print_it_noop. */ enum print_stop_action { + /* We printed nothing or we need to do some more analysis. */ PRINT_UNKNOWN = -1, + + /* We printed something, and we *do* desire that something to be + followed by a location. */ PRINT_SRC_AND_LOC, + + /* We printed something, and we do *not* desire that something to + be followed by a location. */ PRINT_SRC_ONLY, + + /* We already printed all we needed to print, don't print anything + else. */ PRINT_NOTHING }; @@ -980,12 +990,6 @@ extern void breakpoint_re_set (void); extern void breakpoint_re_set_thread (struct breakpoint *); -/* The default re_set method, for typical hardware or software - breakpoints. Reevaluate the breakpoint and recreate its - locations. */ - -extern void breakpoint_re_set_default (struct breakpoint *); - extern struct breakpoint *set_momentary_breakpoint (struct gdbarch *, struct symtab_and_line, struct frame_id, enum bptype); @@ -1025,6 +1029,32 @@ extern void awatch_command_wrapper (char extern void rwatch_command_wrapper (char *, int, int); extern void tbreak_command (char *, int); +extern void null_re_set (struct breakpoint *b); +extern int null_works_in_software_mode (const struct breakpoint *b); +extern int null_resources_needed (const struct bp_location *bl); +extern void null_check_status (bpstat bs); +extern void null_print_one_detail (const struct breakpoint *self, + struct ui_out *uiout); + +extern struct breakpoint_ops bkpt_breakpoint_ops; + +extern void bkpt_dtor (struct breakpoint *self); +extern struct bp_location *bkpt_allocate_location (struct breakpoint *self); +extern void bkpt_re_set (struct breakpoint *b); +extern int bkpt_insert_location (struct bp_location *bl); +extern int bkpt_remove_location (struct bp_location *bl); +extern int bkpt_breakpoint_hit (const struct bp_location *bl, + struct address_space *aspace, + CORE_ADDR bp_addr); +extern void bkpt_check_status (bpstat bs); +extern int bkpt_resources_needed (const struct bp_location *bl); +extern int bkpt_works_in_software_mode (const struct breakpoint *b); +extern enum print_stop_action bkpt_print_it (bpstat bs); +extern void null_print_one_detail (const struct breakpoint *self, + struct ui_out *uiout); +extern void bkpt_print_mention (struct breakpoint *b); +extern void bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp); + /* Arguments to pass as context to some catch command handlers. */ #define CATCH_PERMANENT ((void *) (uintptr_t) 0) #define CATCH_TEMPORARY ((void *) (uintptr_t) 1) Index: src/gdb/mi/mi-cmd-break.c =================================================================== --- src.orig/gdb/mi/mi-cmd-break.c 2011-04-27 12:26:59.000000000 +0100 +++ src/gdb/mi/mi-cmd-break.c 2011-06-24 15:54:42.148084408 +0100 @@ -169,7 +169,7 @@ mi_cmd_break_insert (char *command, char temp_p, type_wanted, ignore_count, pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE, - NULL, 0, enabled, 0); + &bkpt_breakpoint_ops, 0, enabled, 0); do_cleanups (back_to); } Index: src/gdb/python/py-breakpoint.c =================================================================== --- src.orig/gdb/python/py-breakpoint.c 2011-04-27 13:08:51.000000000 +0100 +++ src/gdb/python/py-breakpoint.c 2011-06-24 15:55:01.898084401 +0100 @@ -633,7 +633,8 @@ bppy_init (PyObject *self, PyObject *arg 0, bp_breakpoint, 0, AUTO_BOOLEAN_TRUE, - NULL, 0, 1, internal_bp); + &bkpt_breakpoint_ops, + 0, 1, internal_bp); break; } case bp_watchpoint: ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) 2011-06-24 16:42 ` more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) Pedro Alves @ 2011-06-27 8:52 ` Phil Muldoon 2011-07-22 15:06 ` Phil Muldoon 1 sibling, 0 replies; 12+ messages in thread From: Phil Muldoon @ 2011-06-27 8:52 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Pedro Alves <pedro@codesourcery.com> writes: >> I'd like to finish that conversion soon. Thanks for the patch! > I did a bit more work on this. Watchpoints were already using > breakpoint_ops. I added a bkpt_breakpoint_ops for all software/hardware > breakpoints, and a tracepoint_ops for all kinds of tracepoints, > and moved the default actions to the appropriate places. There > were places where I could cleanup a bit further, but I figured > I'd better do those as follow ups. I think these 4 major > kinds of "breakpoints" is already a good start. Further > refinement could split internal / momentary breakpoints > into its own ops, for example. I've not converted my Python patch to use this yet, but it looks like it would be fairly simple. FWIW, I think this is great. > I left behind the print_one method, as that seems will > require something else, or some disentanglement. I don't have the file open at this moment, but if I remember correctly this is the callback that can fail with breakpoints that have multiple locations? If we could convert that assert() to an error() I could catch it and deal with it. If I remember correctly, asserts do not propagate through the exception framework as normal GDB errors, so we would have to do something here to let the Python code manage this error? Generally, as a side point, asserts are somewhat the bane of my life especially if they do not indicate fatal GDB situations. > The current insert/remove abstration is at raw location level. > We can't use it as is to split insert_bp_location. We may need > to rename the current methods to e.g., insert_raw_location (or > move them to the bp_location vtable), and add new breakpoint_ops > methods that call the raw methods, and, handle the different > warnings and insert-failed->revert paths as appropriate per > breakpoint type. Sounds good to me. I was thinking on this from the Python side, when (if) we finally propagate this functionality to the API. Right now I do not see how we could abstract these functions enough (into a more discrete GDB-side API) to allow the Python user to use them safely. It seems to require an awful lot of internals from GDB to make accurate decision, and I am a little uncomfortable with allowing this level of introspection from the Python side. On could argue this allows for a deeper, more powerful API, but there is a risk that internals could change that would force a Python API break. Anyway, I ramble on ... I think your logic is sound with the baser more raw callbacks. > > This has no regressions for me. It misses some comments and > cosmetics here and there, and a ChangeLog entry. I'll try to > get back to this soon, but I've got other fish to fry at > the moment. Thanks for doing this. I do not see any regressions either. Cheers, Phil -- Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham (USA), Brendan Lane (Ireland), Matt Parson (USA), Charlie Peters (USA) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) 2011-06-24 16:42 ` more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) Pedro Alves 2011-06-27 8:52 ` Phil Muldoon @ 2011-07-22 15:06 ` Phil Muldoon 2011-07-22 15:20 ` Pedro Alves 1 sibling, 1 reply; 12+ messages in thread From: Phil Muldoon @ 2011-07-22 15:06 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Pedro Alves <pedro@codesourcery.com> writes: > On Thursday 23 June 2011 18:04:26, Pedro Alves wrote: > >> I'd like to finish that conversion soon. > > I did a bit more work on this. > This has no regressions for me. It misses some comments and > cosmetics here and there, and a ChangeLog entry. I'll try to > get back to this soon, but I've got other fish to fry at > the moment. Pedro, Hi! Have you had any more time to look at this? Cheers, Phil ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) 2011-07-22 15:06 ` Phil Muldoon @ 2011-07-22 15:20 ` Pedro Alves 0 siblings, 0 replies; 12+ messages in thread From: Pedro Alves @ 2011-07-22 15:20 UTC (permalink / raw) To: pmuldoon; +Cc: gdb-patches On Friday 22 July 2011 14:48:02, Phil Muldoon wrote: > Pedro Alves <pedro@codesourcery.com> writes: > > > On Thursday 23 June 2011 18:04:26, Pedro Alves wrote: > > > >> I'd like to finish that conversion soon. > > > > I did a bit more work on this. > > > This has no regressions for me. It misses some comments and > > cosmetics here and there, and a ChangeLog entry. I'll try to > > get back to this soon, but I've got other fish to fry at > > the moment. > > Pedro, > > Hi! > > Have you had any more time to look at this? Stay tuned. :-) -- Pedro Alves ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2011-07-22 14:30 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-06-23 12:35 [patch] [python] Expose some breakpoint operations to Python Phil Muldoon 2011-06-23 13:19 ` Eli Zaretskii 2011-06-23 14:07 ` Pedro Alves 2011-06-23 14:46 ` Phil Muldoon 2011-06-23 15:30 ` Pedro Alves 2011-06-23 15:57 ` Phil Muldoon 2011-06-23 17:04 ` Pedro Alves 2011-06-23 18:58 ` Phil Muldoon 2011-06-24 16:42 ` more OO, use breakpoints_ops for all kinds of breakpoints (Re: [patch] [python] Expose some breakpoint operations to Python) Pedro Alves 2011-06-27 8:52 ` Phil Muldoon 2011-07-22 15:06 ` Phil Muldoon 2011-07-22 15:20 ` Pedro Alves
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox