#include "jit.h"
#include "xml-syscall.h"
#include "parser-defs.h"
+#include "gdb_regex.h"
+#include "probe.h"
#include "cli/cli-utils.h"
#include "continuations.h"
#include "stack.h"
#include "skip.h"
-#include "record.h"
#include "gdb_regex.h"
#include "ax-gdb.h"
static void create_breakpoints_sal_default (struct gdbarch *,
struct linespec_result *,
struct linespec_sals *,
- char *, enum bptype,
+ char *, char *, enum bptype,
enum bpdisp, int, int,
int,
const struct breakpoint_ops *,
breakpoints. */
struct breakpoint_ops bkpt_breakpoint_ops;
+/* Breakpoints set on probes. */
+static struct breakpoint_ops bkpt_probe_breakpoint_ops;
+
+/* Dynamic printf class type. */
+static struct breakpoint_ops dprintf_breakpoint_ops;
+
/* A reference-counted struct command_line. This lets multiple
breakpoints share a single command list. */
struct counted_command_line
int
breakpoints_always_inserted_mode (void)
{
- return ((always_inserted_mode == always_inserted_on
- || (always_inserted_mode == always_inserted_auto && non_stop))
- && !RECORD_IS_USED);
+ return (always_inserted_mode == always_inserted_on
+ || (always_inserted_mode == always_inserted_auto && non_stop));
}
static const char condition_evaluation_both[] = "host or target";
set_condition_evaluation_mode (char *args, int from_tty,
struct cmd_list_element *c)
{
- struct breakpoint *b;
const char *old_mode, *new_mode;
if ((condition_evaluation_mode_1 == condition_evaluation_target)
is_breakpoint (const struct breakpoint *bpt)
{
return (bpt->type == bp_breakpoint
- || bpt->type == bp_hardware_breakpoint);
+ || bpt->type == bp_hardware_breakpoint
+ || bpt->type == bp_dprintf);
}
/* Return true if BPT is of any hardware watchpoint kind. */
insert_breakpoint_locations ();
}
+/* Invoke CALLBACK for each of bp_location. */
+
+void
+iterate_over_bp_locations (walk_bp_location_callback callback)
+{
+ struct bp_location *loc, **loc_tmp;
+
+ ALL_BP_LOCATIONS (loc, loc_tmp)
+ {
+ callback (loc, NULL);
+ }
+}
+
/* This is used when we need to synch breakpoint conditions between GDB and the
target. It is the case with deleting and disabling of breakpoints when using
always-inserted mode. */
/* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
+ /* True if we have looked for longjmp probes. */
+ int longjmp_searched;
+
+ /* SystemTap probe points for longjmp (if any). */
+ VEC (probe_p) *longjmp_probes;
+
/* Minimal symbol for "std::terminate()" (if any). */
struct minimal_symbol *terminate_msym;
/* Minimal symbol for "_Unwind_DebugHook" (if any). */
struct minimal_symbol *exception_msym;
+
+ /* True if we have looked for exception probes. */
+ int exception_searched;
+
+ /* SystemTap probe points for unwinding (if any). */
+ VEC (probe_p) *exception_probes;
};
static const struct objfile_data *breakpoint_objfile_key;
return bp_objfile_data;
}
+static void
+free_breakpoint_probes (struct objfile *obj, void *data)
+{
+ struct breakpoint_objfile_data *bp_objfile_data = data;
+
+ VEC_free (probe_p, bp_objfile_data->longjmp_probes);
+ VEC_free (probe_p, bp_objfile_data->exception_probes);
+}
+
static void
create_overlay_event_breakpoint (void)
{
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ if (!bp_objfile_data->longjmp_searched)
+ {
+ bp_objfile_data->longjmp_probes
+ = find_probes_in_objfile (objfile, "libc", "longjmp");
+ bp_objfile_data->longjmp_searched = 1;
+ }
+
+ if (bp_objfile_data->longjmp_probes != NULL)
+ {
+ int i;
+ struct probe *probe;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ for (i = 0;
+ VEC_iterate (probe_p,
+ bp_objfile_data->longjmp_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_longjmp_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-probe-stap libc:longjmp");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
for (i = 0; i < NUM_LONGJMP_NAMES; i++)
{
struct breakpoint *b;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ /* We prefer the SystemTap probe point if it exists. */
+ if (!bp_objfile_data->exception_searched)
+ {
+ bp_objfile_data->exception_probes
+ = find_probes_in_objfile (objfile, "libgcc", "unwind");
+ bp_objfile_data->exception_searched = 1;
+ }
+
+ if (bp_objfile_data->exception_probes != NULL)
+ {
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ int i;
+ struct probe *probe;
+
+ for (i = 0;
+ VEC_iterate (probe_p,
+ bp_objfile_data->exception_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_exception_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-probe-stap libgcc:unwind");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
+ /* Otherwise, try the hook function. */
+
if (msym_not_found_p (bp_objfile_data->exception_msym))
continue;
PC of the former breakpoint. */
this_action = BPSTAT_WHAT_KEEP_CHECKING;
break;
+
+ case bp_dprintf:
+ this_action = BPSTAT_WHAT_STOP_SILENT;
+ break;
+
default:
internal_error (__FILE__, __LINE__,
_("bpstat_what: unhandled bptype %d"), (int) bptype);
{bp_tracepoint, "tracepoint"},
{bp_fast_tracepoint, "fast tracepoint"},
{bp_static_tracepoint, "static tracepoint"},
+ {bp_dprintf, "dprintf"},
{bp_jit_event, "jit events"},
{bp_gnu_ifunc_resolver, "STT_GNU_IFUNC resolver"},
{bp_gnu_ifunc_resolver_return, "STT_GNU_IFUNC resolver return"},
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_static_tracepoint:
+ case bp_dprintf:
case bp_jit_event:
case bp_gnu_ifunc_resolver:
case bp_gnu_ifunc_resolver_return:
case bp_exception_master:
case bp_gnu_ifunc_resolver:
case bp_gnu_ifunc_resolver_return:
+ case bp_dprintf:
loc->loc_type = bp_loc_software_breakpoint;
mark_breakpoint_location_modified (loc);
break;
{
int is_gnu_ifunc;
const char *function_name;
+ CORE_ADDR func_addr;
find_pc_partial_function_gnu_ifunc (loc->address, &function_name,
- NULL, NULL, &is_gnu_ifunc);
+ &func_addr, NULL, &is_gnu_ifunc);
if (is_gnu_ifunc && !explicit_loc)
{
/* Create only the whole new breakpoint of this type but do not
mess more complicated breakpoints with multiple locations. */
b->type = bp_gnu_ifunc_resolver;
+ /* Remember the resolver's address for use by the return
+ breakpoint. */
+ loc->related_address = func_addr;
}
}
struct solib_catchpoint *c;
struct gdbarch *gdbarch = get_current_arch ();
int tempflag;
- regex_t compiled;
struct cleanup *cleanup;
tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
ptid_t ptid;
struct target_waitstatus last;
struct syscall s;
- char *syscall_id;
get_last_target_status (&ptid, &last);
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
+ copy->loc->probe = orig->loc->probe;
if (orig->loc->source_file != NULL)
copy->loc->source_file = xstrdup (orig->loc->source_file);
loc->requested_address = sal->pc;
loc->address = adjusted_address;
loc->pspace = sal->pspace;
+ loc->probe = sal->probe;
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
loc->gdbarch = loc_gdbarch;
return retval;
}
+/* The style in which to perform a dynamic printf. This is a user
+ option because different output options have different tradeoffs;
+ if GDB does the printing, there is better error handling if there
+ is a problem with any of the arguments, but using an inferior
+ function lets you have special-purpose printers and sending of
+ output to the same place as compiled-in print functions. (Future
+ styles may include the ability to do a target-side printf.) */
+
+static const char dprintf_style_gdb[] = "gdb";
+static const char dprintf_style_call[] = "call";
+static const char *const dprintf_style_enums[] = {
+ dprintf_style_gdb,
+ dprintf_style_call,
+ NULL
+};
+static const char *dprintf_style = dprintf_style_gdb;
+
+/* The function to use for dynamic printf if the preferred style is to
+ call into the inferior. The value is simply a string that is
+ copied into the command, so it can be anything that GDB can
+ evaluate to a callable address, not necessarily a function name. */
+
+static char *dprintf_function = "";
+
+/* The channel to use for dynamic printf if the preferred style is to
+ call into the inferior; if a nonempty string, it will be passed to
+ the call as the first argument, with the format string as the
+ second. As with the dprintf function, this can be anything that
+ GDB knows how to evaluate, so in addition to common choices like
+ "stderr", this could be an app-specific expression like
+ "mystreams[curlogger]". */
+
+static char *dprintf_channel = "";
+
+/* Build a command list for the dprintf corresponding to the current
+ settings of the dprintf style options. */
+
+static void
+update_dprintf_command_list (struct breakpoint *b)
+{
+ char *dprintf_args = b->extra_string;
+ char *printf_line = NULL;
+
+ if (!dprintf_args)
+ return;
+
+ dprintf_args = skip_spaces (dprintf_args);
+
+ /* Allow a comma, as it may have terminated a location, but don't
+ insist on it. */
+ if (*dprintf_args == ',')
+ ++dprintf_args;
+ dprintf_args = skip_spaces (dprintf_args);
+
+ if (*dprintf_args != '"')
+ error (_("Bad format string, missing '\"'."));
+
+ if (strcmp (dprintf_style, "gdb") == 0)
+ printf_line = xstrprintf ("printf %s", dprintf_args);
+ else if (strcmp (dprintf_style, "call") == 0)
+ {
+ if (!dprintf_function)
+ error (_("No function supplied for dprintf call"));
+
+ if (dprintf_channel && strlen (dprintf_channel) > 0)
+ printf_line = xstrprintf ("call (void) %s (%s,%s)",
+ dprintf_function,
+ dprintf_channel,
+ dprintf_args);
+ else
+ printf_line = xstrprintf ("call (void) %s (%s)",
+ dprintf_function,
+ dprintf_args);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ _("Invalid dprintf style."));
+
+ /* Manufacture a printf/continue sequence. */
+ if (printf_line)
+ {
+ struct command_line *printf_cmd_line, *cont_cmd_line = NULL;
+
+ cont_cmd_line = xmalloc (sizeof (struct command_line));
+ cont_cmd_line->control_type = simple_control;
+ cont_cmd_line->body_count = 0;
+ cont_cmd_line->body_list = NULL;
+ cont_cmd_line->next = NULL;
+ cont_cmd_line->line = xstrdup ("continue");
+
+ printf_cmd_line = xmalloc (sizeof (struct command_line));
+ printf_cmd_line->control_type = simple_control;
+ printf_cmd_line->body_count = 0;
+ printf_cmd_line->body_list = NULL;
+ printf_cmd_line->next = cont_cmd_line;
+ printf_cmd_line->line = printf_line;
+
+ breakpoint_set_commands (b, printf_cmd_line);
+ }
+}
+
+/* Update all dprintf commands, making their command lists reflect
+ current style settings. */
+static void
+update_dprintf_commands (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->type == bp_dprintf)
+ update_dprintf_command_list (b);
+ }
+}
/* Create a breakpoint with SAL as location. Use ADDR_STRING
as textual description of the location, and COND_STRING
init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
char *filter, char *cond_string,
+ char *extra_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
init_raw_breakpoint (b, gdbarch, sal, type, ops);
b->thread = thread;
b->task = task;
-
+
b->cond_string = cond_string;
+ b->extra_string = extra_string;
b->ignore_count = ignore_count;
b->enable_state = enabled ? bp_enabled : bp_disabled;
b->disposition = disposition;
char *arg = b->cond_string;
loc->cond = parse_exp_1 (&arg, block_for_pc (loc->address), 0);
if (*arg)
- error (_("Garbage %s follows condition"), arg);
+ error (_("Garbage '%s' follows condition"), arg);
}
- }
+
+ /* Dynamic printf requires and uses additional arguments on the
+ command line, otherwise it's an error. */
+ if (type == bp_dprintf)
+ {
+ if (b->extra_string)
+ update_dprintf_command_list (b);
+ else
+ error (_("Format string required"));
+ }
+ else if (b->extra_string)
+ error (_("Garbage '%s' at end of command"), b->extra_string);
+ }
b->display_canonical = display_canonical;
if (addr_string)
create_breakpoint_sal (struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
char *filter, char *cond_string,
+ char *extra_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
init_breakpoint_sal (b, gdbarch,
sals, addr_string,
- filter, cond_string,
+ filter, cond_string, extra_string,
type, disposition,
thread, task, ignore_count,
ops, from_tty,
static void
create_breakpoints_sal (struct gdbarch *gdbarch,
struct linespec_result *canonical,
- char *cond_string,
+ char *cond_string, char *extra_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
create_breakpoint_sal (gdbarch, lsal->sals,
addr_string,
filter_string,
- cond_string, type, disposition,
+ cond_string, extra_string,
+ type, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal, flags,
canonical->special_display);
}
else
{
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
/* Force almost all breakpoints to be in terms of the
current_source_symtab (which is decode_line_1's default).
This should produce the results we want almost all of the
- time while leaving default_breakpoint_* alone. */
- if (last_displayed_sal_is_valid ())
+ time while leaving default_breakpoint_* alone.
+
+ ObjC: However, don't match an Objective-C method name which
+ may have a '+' or '-' succeeded by a '['. */
+ if (last_displayed_sal_is_valid ()
+ && (!cursal.symtab
+ || ((strchr ("+-", (*address)[0]) != NULL)
+ && ((*address)[1] != '['))))
decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
get_last_displayed_symtab (),
get_last_displayed_line (),
canonical, NULL, NULL);
else
decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
- (struct symtab *) NULL, 0,
- canonical, NULL, NULL);
+ cursal.symtab, cursal.line, canonical, NULL, NULL);
}
}
PC identifies the context at which the condition should be parsed.
If no condition is found, *COND_STRING is set to NULL.
If no thread is found, *THREAD is set to -1. */
-static void
-find_condition_and_thread (char *tok, CORE_ADDR pc,
- char **cond_string, int *thread, int *task)
+
+static void
+find_condition_and_thread (char *tok, CORE_ADDR pc,
+ char **cond_string, int *thread, int *task,
+ char **rest)
{
*cond_string = NULL;
*thread = -1;
char *cond_end = NULL;
tok = skip_spaces (tok);
-
+
+ if ((*tok == '"' || *tok == ',') && rest)
+ {
+ *rest = savestring (tok, strlen (tok));
+ return;
+ }
+
end_tok = skip_to_space (tok);
-
+
toklen = end_tok - tok;
-
+
if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
{
struct expression *expr;
expr = parse_exp_1 (&tok, block_for_pc (pc), 0);
xfree (expr);
cond_end = tok;
- *cond_string = savestring (cond_start,
- cond_end - cond_start);
+ *cond_string = savestring (cond_start, cond_end - cond_start);
}
else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
{
char *tmptok;
-
+
tok = end_tok + 1;
tmptok = tok;
*thread = strtol (tok, &tok, 0);
if (!valid_task_id (*task))
error (_("Unknown task %d."), *task);
}
+ else if (rest)
+ {
+ *rest = savestring (tok, strlen (tok));
+ return;
+ }
else
error (_("Junk at end of arguments."));
}
{
VEC(static_tracepoint_marker_p) *markers = NULL;
struct symtabs_and_lines sals;
- struct symtab_and_line sal;
- struct symbol *sym;
struct cleanup *old_chain;
char *p = &(*arg_p)[3];
char *endp;
int
create_breakpoint (struct gdbarch *gdbarch,
- char *arg, char *cond_string, int thread,
+ char *arg, char *cond_string,
+ int thread, char *extra_string,
int parse_condition_and_thread,
int tempflag, enum bptype type_wanted,
int ignore_count,
struct linespec_result canonical;
struct cleanup *old_chain;
struct cleanup *bkpt_chain = NULL;
- int i;
int pending = 0;
int task = 0;
int prev_bkpt_count = breakpoint_count;
if (parse_condition_and_thread)
{
+ char *rest;
/* Here we only parse 'arg' to separate condition
from thread number, so parsing in context of first
sal is OK. When setting the breakpoint we'll
re-parse it in context of each sal. */
cond_string = NULL;
thread = -1;
+ rest = NULL;
find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
- &thread, &task);
+ &thread, &task, &rest);
if (cond_string)
make_cleanup (xfree, cond_string);
+ if (rest)
+ make_cleanup (xfree, rest);
+ if (rest)
+ extra_string = rest;
}
else
{
cond_string = xstrdup (cond_string);
make_cleanup (xfree, cond_string);
}
+ /* Create a private copy of any extra string. */
+ if (extra_string)
+ {
+ extra_string = xstrdup (extra_string);
+ make_cleanup (xfree, extra_string);
+ }
}
ops->create_breakpoints_sal (gdbarch, &canonical, lsal,
- cond_string, type_wanted,
+ cond_string, extra_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
from_tty, enabled, internal, flags);
b->addr_string = copy_arg;
b->cond_string = NULL;
+ b->extra_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->condition_not_parsed = 1;
enum bptype type_wanted = (flag & BP_HARDWAREFLAG
? bp_hardware_breakpoint
: bp_breakpoint);
+ struct breakpoint_ops *ops;
+ const char *arg_cp = arg;
+
+ /* Matching breakpoints on probes. */
+ if (arg && probe_linespec_to_ops (&arg_cp) != NULL)
+ ops = &bkpt_probe_breakpoint_ops;
+ else
+ ops = &bkpt_breakpoint_ops;
create_breakpoint (get_current_arch (),
arg,
- NULL, 0, 1 /* parse arg */,
+ NULL, 0, NULL, 1 /* parse arg */,
tempflag, type_wanted,
0 /* Ignore count */,
pending_break_support,
- &bkpt_breakpoint_ops,
+ ops,
from_tty,
1 /* enabled */,
0 /* internal */,
break_command_1 (arg, 0, from_tty);
}
+void dprintf_command (char *arg, int from_tty);
+
+/* The dynamic printf command is mostly like a regular breakpoint, but
+ with a prewired command list consisting of a single output command,
+ built from extra arguments supplied on the dprintf command
+ line. */
+
+void
+dprintf_command (char *arg, int from_tty)
+{
+ create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, NULL, 1 /* parse arg */,
+ 0, bp_dprintf,
+ 0 /* Ignore count */,
+ pending_break_support,
+ &dprintf_breakpoint_ops,
+ from_tty,
+ 1 /* enabled */,
+ 0 /* internal */,
+ 0);
+}
+
/* Implement the "breakpoint_hit" breakpoint_ops method for
ranged breakpoints. */
const struct target_waitstatus *ws)
{
if (ws->kind != TARGET_WAITKIND_STOPPED
- || ws->value.sig != TARGET_SIGNAL_TRAP)
+ || ws->value.sig != GDB_SIGNAL_TRAP)
return 0;
return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
{
struct symtabs_and_lines sals;
struct symtab_and_line sal;
- struct frame_info *frame = get_selected_frame (NULL);
- struct gdbarch *frame_gdbarch = get_frame_arch (frame);
- struct frame_id stack_frame_id = get_stack_frame_id (frame);
- struct frame_id caller_frame_id = frame_unwind_caller_id (frame);
+ struct frame_info *frame;
+ struct gdbarch *frame_gdbarch;
+ struct frame_id stack_frame_id;
+ struct frame_id caller_frame_id;
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2 = NULL;
struct cleanup *old_chain;
old_chain = make_cleanup (null_cleanup, NULL);
- /* Installing a breakpoint invalidates the frame chain (as it may
- need to switch threads), so do any frame handling first. */
+ /* Note linespec handling above invalidates the frame chain.
+ Installing a breakpoint also invalidates the frame chain (as it
+ may need to switch threads), so do any frame handling before
+ that. */
+
+ frame = get_selected_frame (NULL);
+ frame_gdbarch = get_frame_arch (frame);
+ stack_frame_id = get_stack_frame_id (frame);
+ caller_frame_id = frame_unwind_caller_id (frame);
/* Keep within the current frame, or in frames called by the current
one. */
stack_frame_id, bp_until);
make_cleanup_delete_breakpoint (breakpoint);
- proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
+ proceed (-1, GDB_SIGNAL_DEFAULT, 0);
/* If we are running asynchronously, and proceed call above has
actually managed to start the target, arrange for breakpoints to
trigger_func_name = "__cxa_throw";
create_breakpoint (get_current_arch (),
- trigger_func_name, cond_string, -1,
+ trigger_func_name, cond_string, -1, NULL,
0 /* condition and thread are valid. */,
tempflag, bp_breakpoint,
0,
struct linespec_result *c,
struct linespec_sals *lsal,
char *cond_string,
+ char *extra_string,
enum bptype type_wanted,
enum bpdisp disposition,
int thread,
struct breakpoint *b = bl->owner;
if (ws->kind != TARGET_WAITKIND_STOPPED
- || ws->value.sig != TARGET_SIGNAL_TRAP)
+ || ws->value.sig != GDB_SIGNAL_TRAP)
return 0;
if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
case bp_hardware_breakpoint:
printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
break;
+ case bp_dprintf:
+ printf_filtered (_("Dprintf %d"), b->number);
+ break;
}
say_where (b);
struct linespec_result *canonical,
struct linespec_sals *lsal,
char *cond_string,
+ char *extra_string,
enum bptype type_wanted,
enum bpdisp disposition,
int thread,
int internal, unsigned flags)
{
create_breakpoints_sal_default (gdbarch, canonical, lsal,
- cond_string, type_wanted,
+ cond_string, extra_string,
+ type_wanted,
disposition, thread, task,
ignore_count, ops, from_tty,
enabled, internal, flags);
/* Nothing to mention. These breakpoints are internal. */
}
+/* Specific methods for probe breakpoints. */
+
+static int
+bkpt_probe_insert_location (struct bp_location *bl)
+{
+ int v = bkpt_insert_location (bl);
+
+ if (v == 0)
+ {
+ /* The insertion was successful, now let's set the probe's semaphore
+ if needed. */
+ bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch);
+ }
+
+ return v;
+}
+
+static int
+bkpt_probe_remove_location (struct bp_location *bl)
+{
+ /* Let's clear the semaphore before removing the location. */
+ bl->probe->pops->clear_semaphore (bl->probe, bl->gdbarch);
+
+ return bkpt_remove_location (bl);
+}
+
+static void
+bkpt_probe_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ struct linespec_sals lsal;
+
+ lsal.sals = parse_probes (arg, canonical);
+
+ *copy_arg = xstrdup (canonical->addr_string);
+ lsal.canonical = xstrdup (*copy_arg);
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+}
+
+static void
+bkpt_probe_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ *sals = parse_probes (s, NULL);
+ if (!sals->sals)
+ error (_("probe not found"));
+}
+
/* The breakpoint_ops structure to be used in tracepoints. */
static void
struct linespec_result *canonical,
struct linespec_sals *lsal,
char *cond_string,
+ char *extra_string,
enum bptype type_wanted,
enum bpdisp disposition,
int thread,
int internal, unsigned flags)
{
create_breakpoints_sal_default (gdbarch, canonical, lsal,
- cond_string, type_wanted,
+ cond_string, extra_string,
+ type_wanted,
disposition, thread, task,
ignore_count, ops, from_tty,
enabled, internal, flags);
struct breakpoint_ops tracepoint_breakpoint_ops;
+/* The breakpoint_ops structure to be use on tracepoints placed in a
+ static probe. */
+
+static void
+tracepoint_probe_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ /* We use the same method for breakpoint on probes. */
+ bkpt_probe_create_sals_from_address (arg, canonical, type_wanted,
+ addr_start, copy_arg);
+}
+
+static void
+tracepoint_probe_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ /* We use the same method for breakpoint on probes. */
+ bkpt_probe_decode_linespec (b, s, sals);
+}
+
+static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
+
/* The breakpoint_ops structure to be used on static tracepoints with
markers (`-m'). */
struct linespec_result *canonical,
struct linespec_sals *lsal,
char *cond_string,
+ char *extra_string,
enum bptype type_wanted,
enum bpdisp disposition,
int thread,
tp = XCNEW (struct tracepoint);
init_breakpoint_sal (&tp->base, gdbarch, expanded,
addr_string, NULL,
- cond_string, type_wanted, disposition,
+ cond_string, extra_string,
+ type_wanted, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal, flags,
canonical->special_display);
struct tracepoint *tp = (struct tracepoint *) b;
struct static_tracepoint_marker marker;
CORE_ADDR pc;
- int i;
pc = sal.pc;
if (sal.line)
char *cond_string = 0;
int thread = -1;
int task = 0;
+ char *extra_string = NULL;
find_condition_and_thread (s, sals.sals[0].pc,
- &cond_string, &thread, &task);
+ &cond_string, &thread, &task,
+ &extra_string);
if (cond_string)
b->cond_string = cond_string;
b->thread = thread;
b->task = task;
+ if (extra_string)
+ b->extra_string = extra_string;
b->condition_not_parsed = 0;
}
struct linespec_result *canonical,
struct linespec_sals *lsal,
char *cond_string,
+ char *extra_string,
enum bptype type_wanted,
enum bpdisp disposition,
int thread,
int internal, unsigned flags)
{
create_breakpoints_sal (gdbarch, canonical, cond_string,
+ extra_string,
type_wanted, disposition,
thread, task, ignore_count, ops, from_tty,
enabled, internal, flags);
}
/* Complete syscall names. Used by "catch syscall". */
-static char **
+static VEC (char_ptr) *
catch_syscall_completer (struct cmd_list_element *cmd,
char *text, char *word)
{
const char **list = get_syscall_names ();
- char **retlist
+ VEC (char_ptr) *retlist
= (list == NULL) ? NULL : complete_on_enum (list, text, word);
xfree (list);
static void
trace_command (char *arg, int from_tty)
{
+ struct breakpoint_ops *ops;
+ const char *arg_cp = arg;
+
+ if (arg && probe_linespec_to_ops (&arg_cp))
+ ops = &tracepoint_probe_breakpoint_ops;
+ else
+ ops = &tracepoint_breakpoint_ops;
+
if (create_breakpoint (get_current_arch (),
arg,
- NULL, 0, 1 /* parse arg */,
+ NULL, 0, NULL, 1 /* parse arg */,
0 /* tempflag */,
bp_tracepoint /* type_wanted */,
0 /* Ignore count */,
pending_break_support,
- &tracepoint_breakpoint_ops,
+ ops,
from_tty,
1 /* enabled */,
0 /* internal */, 0))
{
if (create_breakpoint (get_current_arch (),
arg,
- NULL, 0, 1 /* parse arg */,
+ NULL, 0, NULL, 1 /* parse arg */,
0 /* tempflag */,
bp_fast_tracepoint /* type_wanted */,
0 /* Ignore count */,
if (create_breakpoint (get_current_arch (),
arg,
- NULL, 0, 1 /* parse arg */,
+ NULL, 0, NULL, 1 /* parse arg */,
0 /* tempflag */,
bp_static_tracepoint /* type_wanted */,
0 /* Ignore count */,
if (!create_breakpoint (get_current_arch (),
addr_str,
- utp->cond_string, -1, 0 /* parse cond/thread */,
+ utp->cond_string, -1, NULL,
+ 0 /* parse cond/thread */,
0 /* tempflag */,
utp->type /* type_wanted */,
0 /* Ignore count */,
add_catch_command (char *name, char *docstring,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element *command),
- char **(*completer) (struct cmd_list_element *cmd,
- char *text, char *word),
+ completer_ftype *completer,
void *user_data_catch,
void *user_data_tcatch)
{
ops->print_it = momentary_bkpt_print_it;
ops->print_mention = momentary_bkpt_print_mention;
+ /* Probe breakpoints. */
+ ops = &bkpt_probe_breakpoint_ops;
+ *ops = bkpt_breakpoint_ops;
+ ops->insert_location = bkpt_probe_insert_location;
+ ops->remove_location = bkpt_probe_remove_location;
+ ops->create_sals_from_address = bkpt_probe_create_sals_from_address;
+ ops->decode_linespec = bkpt_probe_decode_linespec;
+
/* GNU v3 exception catchpoints. */
ops = &gnu_v3_exception_catchpoint_ops;
*ops = bkpt_breakpoint_ops;
ops->create_breakpoints_sal = tracepoint_create_breakpoints_sal;
ops->decode_linespec = tracepoint_decode_linespec;
+ /* Probe tracepoints. */
+ ops = &tracepoint_probe_breakpoint_ops;
+ *ops = tracepoint_breakpoint_ops;
+ ops->create_sals_from_address = tracepoint_probe_create_sals_from_address;
+ ops->decode_linespec = tracepoint_probe_decode_linespec;
+
/* Static tracepoints with marker (`-m'). */
ops = &strace_marker_breakpoint_ops;
*ops = tracepoint_breakpoint_ops;
ops->print_one = print_one_catch_solib;
ops->print_mention = print_mention_catch_solib;
ops->print_recreate = print_recreate_catch_solib;
+
+ ops = &dprintf_breakpoint_ops;
+ *ops = bkpt_base_breakpoint_ops;
+ ops->re_set = bkpt_re_set;
+ ops->resources_needed = bkpt_resources_needed;
+ ops->print_it = bkpt_print_it;
+ ops->print_mention = bkpt_print_mention;
+ ops->print_recreate = bkpt_print_recreate;
}
void
observer_attach_inferior_exit (clear_syscall_counts);
observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
- breakpoint_objfile_key = register_objfile_data ();
+ breakpoint_objfile_key
+ = register_objfile_data_with_cleanup (NULL, free_breakpoint_probes);
catch_syscall_inferior_data
= register_inferior_data_with_cleanup (catch_syscall_inferior_data_cleanup);
an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
range (including START-LOCATION and END-LOCATION)."));
+ c = add_com ("dprintf", class_breakpoint, dprintf_command, _("\
+Set a dynamic printf at specified line or function.\n\
+dprintf location,format string,arg1,arg2,...\n\
+location may be a line number, function name, or \"*\" and an address.\n\
+If a line number is specified, break at start of code for that line.\n\
+If a function is specified, break at start of code for that function.\n\
+"));
+ set_cmd_completer (c, location_completer);
+
+ add_setshow_enum_cmd ("dprintf-style", class_support,
+ dprintf_style_enums, &dprintf_style, _("\
+Set the style of usage for dynamic printf."), _("\
+Show the style of usage for dynamic printf."), _("\
+This setting chooses how GDB will do a dynamic printf.\n\
+If the value is \"gdb\", then the printing is done by GDB to its own\n\
+console, as with the \"printf\" command.\n\
+If the value is \"call\", the print is done by calling a function in your\n\
+program; by default printf(), but you can choose a different function or\n\
+output stream by setting dprintf-function and dprintf-channel."),
+ update_dprintf_commands, NULL,
+ &setlist, &showlist);
+
+ dprintf_function = xstrdup ("printf");
+ add_setshow_string_cmd ("dprintf-function", class_support,
+ &dprintf_function, _("\
+Set the function to use for dynamic printf"), _("\
+Show the function to use for dynamic printf"), NULL,
+ update_dprintf_commands, NULL,
+ &setlist, &showlist);
+
+ dprintf_channel = xstrdup ("");
+ add_setshow_string_cmd ("dprintf-channel", class_support,
+ &dprintf_channel, _("\
+Set the channel to use for dynamic printf"), _("\
+Show the channel to use for dynamic printf"), NULL,
+ update_dprintf_commands, NULL,
+ &setlist, &showlist);
+
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);