#include "symtab.h"
#include "frame.h"
#include "breakpoint.h"
+#include "tracepoint.h"
#include "gdbtypes.h"
#include "expression.h"
#include "gdbcore.h"
#include "wrapper.h"
#include "valprint.h"
+/* readline include files */
+#include "readline/readline.h"
+#include "readline/history.h"
+
+/* readline defines this. */
+#undef savestring
+
#include "mi/mi-common.h"
/* Arguments to pass as context to some catch command handlers. */
static void maintenance_info_breakpoints (char *, int);
-static void create_overlay_event_breakpoint (char *);
-
static int hw_breakpoint_used_count (void);
static int hw_watchpoint_used_count (enum bptype, int *);
static void insert_breakpoint_locations (void);
+static void tracepoints_info (char *, int);
+
+static void delete_trace_command (char *, int);
+
+static void enable_trace_command (char *, int);
+
+static void disable_trace_command (char *, int);
+
+static void trace_pass_command (char *, int);
+
+/* Flag indicating that a command has proceeded the inferior past the
+ current breakpoint. */
+
+static int breakpoint_proceeded;
+
static const char *
bpdisp_text (enum bpdisp disp)
{
B ? (TMP=B->global_next, 1): 0; \
B = TMP)
+/* Iterator for tracepoints only. */
+
+#define ALL_TRACEPOINTS(B) \
+ for (B = breakpoint_chain; B; B = B->next) \
+ if ((B)->type == bp_tracepoint)
+
/* Chains of all breakpoints defined. */
struct breakpoint *breakpoint_chain;
int breakpoint_count;
+/* Number of last tracepoint made. */
+
+int tracepoint_count;
+
/* Return whether a breakpoint is an active enabled breakpoint. */
static int
breakpoint_enabled (struct breakpoint *b)
arg = p;
/* I don't know if it matters whether this is the string the user
typed in or the decompiled expression. */
- b->cond_string = savestring (arg, strlen (arg));
+ b->cond_string = xstrdup (arg);
b->condition_not_parsed = 0;
for (loc = b->loc; loc; loc = loc->next)
{
b->type = bp_watchpoint;
else
{
- int target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT
+ int target_resources_ok = target_can_use_hardware_watchpoint
(bp_hardware_watchpoint, i + mem_cnt, other_type_used);
if (target_resources_ok <= 0)
b->type = bp_watchpoint;
if (!bpt->enabled || bpt->shlib_disabled || bpt->duplicate)
return 0;
+ /* Tracepoints are inserted by the target at a time of its choosing,
+ not by us. */
+ if (bpt->owner->type == bp_tracepoint)
+ return 0;
+
return 1;
}
if (!breakpoints_always_inserted_mode ()
&& (target_has_execution
- || (gdbarch_has_global_solist (target_gdbarch)
- && target_supports_multi_process ())))
+ || gdbarch_has_global_breakpoints (target_gdbarch)))
/* update_global_location_list does not insert breakpoints
when always_inserted_mode is not enabled. Explicitly
insert them now. */
return 0;
}
+static int internal_breakpoint_number = -1;
+
+static struct breakpoint *
+create_internal_breakpoint (CORE_ADDR address, enum bptype type)
+{
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+
+ init_sal (&sal); /* initialize to zeroes */
+
+ sal.pc = address;
+ sal.section = find_pc_overlay (sal.pc);
+
+ b = set_raw_breakpoint (sal, type);
+ b->number = internal_breakpoint_number--;
+ b->disposition = disp_donttouch;
+
+ return b;
+}
+
+static void
+create_overlay_event_breakpoint (char *func_name, struct objfile *objfile)
+{
+ struct breakpoint *b;
+ struct minimal_symbol *m;
+
+ if ((m = lookup_minimal_symbol_text (func_name, objfile)) == NULL)
+ return;
+
+ b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m),
+ bp_overlay_event);
+ b->addr_string = xstrdup (func_name);
+
+ if (overlay_debugging == ovly_auto)
+ {
+ b->enable_state = bp_enabled;
+ overlay_events_enabled = 1;
+ }
+ else
+ {
+ b->enable_state = bp_disabled;
+ overlay_events_enabled = 0;
+ }
+ update_global_location_list (1);
+}
+
void
update_breakpoints_after_exec (void)
{
struct breakpoint *b;
struct breakpoint *temp;
struct bp_location *bploc;
+ struct objfile *objfile;
/* We're about to delete breakpoints from GDB's lists. If the
INSERTED flag is true, GDB will try to lift the breakpoints by
}
}
/* FIXME what about longjmp breakpoints? Re-create them here? */
- create_overlay_event_breakpoint ("_ovly_debug_event");
+ ALL_OBJFILES (objfile)
+ create_overlay_event_breakpoint ("_ovly_debug_event", objfile);
}
int
/* If breakpoint locations are shared across processes, then there's
nothing to do. */
- if (gdbarch_has_global_solist (target_gdbarch))
+ if (gdbarch_has_global_breakpoints (target_gdbarch))
return;
ALL_BP_LOCATIONS (bpt)
breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
{
const struct bp_location *bpt;
- int thread;
-
- thread = pid_to_thread_id (ptid);
-
+ /* The thread and task IDs associated to PTID, computed lazily. */
+ int thread = -1;
+ int task = 0;
+
ALL_BP_LOCATIONS (bpt)
{
if (bpt->loc_type != bp_loc_software_breakpoint
&& bpt->loc_type != bp_loc_hardware_breakpoint)
continue;
- if ((breakpoint_enabled (bpt->owner)
- || bpt->owner->enable_state == bp_permanent)
- && bpt->address == pc
- && (bpt->owner->thread == -1 || bpt->owner->thread == thread))
+ if (!breakpoint_enabled (bpt->owner)
+ && bpt->owner->enable_state != bp_permanent)
+ continue;
+
+ if (bpt->address != pc)
+ continue;
+
+ if (bpt->owner->thread != -1)
{
- if (overlay_debugging
- && section_is_overlay (bpt->section)
- && !section_is_mapped (bpt->section))
- continue; /* unmapped overlay -- can't be a match */
- else
- return 1;
+ /* This is a thread-specific breakpoint. Check that ptid
+ matches that thread. If thread hasn't been computed yet,
+ it is now time to do so. */
+ if (thread == -1)
+ thread = pid_to_thread_id (ptid);
+ if (bpt->owner->thread != thread)
+ continue;
}
+
+ if (bpt->owner->task != 0)
+ {
+ /* This is a task-specific breakpoint. Check that ptid
+ matches that task. If task hasn't been computed yet,
+ it is now time to do so. */
+ if (task == 0)
+ task = ada_get_task_number (ptid);
+ if (bpt->owner->task != task)
+ continue;
+ }
+
+ if (overlay_debugging
+ && section_is_overlay (bpt->section)
+ && !section_is_mapped (bpt->section))
+ continue; /* unmapped overlay -- can't be a match */
+
+ return 1;
}
return 0;
}
}
+/* Called when a command is about to proceed the inferior. */
+
+static void
+breakpoint_about_to_proceed (void)
+{
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ {
+ struct thread_info *tp = inferior_thread ();
+
+ /* Allow inferior function calls in breakpoint commands to not
+ interrupt the command list. When the call finishes
+ successfully, the inferior will be standing at the same
+ breakpoint as if nothing happened. */
+ if (tp->in_infcall)
+ return;
+ }
+
+ breakpoint_proceeded = 1;
+}
+
/* Stub for cleaning up our state if we error-out of a breakpoint command */
static void
cleanup_executing_breakpoints (void *ignore)
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
+ case bp_tracepoint:
default:
result = PRINT_UNKNOWN;
break;
int
watchpoints_triggered (struct target_waitstatus *ws)
{
- int stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (*ws);
+ int stopped_by_watchpoint = target_stopped_by_watchpoint ();
CORE_ADDR addr;
struct breakpoint *b;
that the watchpoint frame couldn't be found by frame_find_by_id()
because the current PC is currently in an epilogue. Calling
gdbarch_in_function_epilogue_p() also when fr == NULL fixes that. */
- if ((!within_current_scope || fr == get_current_frame ())
- && gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ()))
- return WP_VALUE_NOT_CHANGED;
+ if (!within_current_scope || fr == get_current_frame ())
+ {
+ struct frame_info *frame = get_current_frame ();
+ struct gdbarch *frame_arch = get_frame_arch (frame);
+ CORE_ADDR frame_pc = get_frame_pc (frame);
+
+ if (gdbarch_in_function_epilogue_p (frame_arch, frame_pc))
+ return WP_VALUE_NOT_CHANGED;
+ }
if (fr && within_current_scope)
/* If we end up stopping, the current frame will get selected
in normal_stop. So this call to select_frame won't affect
if (bl->cond && bl->owner->disposition != disp_del_at_next_stop)
{
+ /* We use value_mark and value_free_to_mark because it could
+ be a long time before we return to the command level and
+ call free_all_values. We can't call free_all_values
+ because we might be in the middle of evaluating a
+ function call. */
+ struct value *mark = value_mark ();
+
/* Need to select the frame, with all that implies
so that the conditions will have the right context. */
select_frame (get_current_frame ());
"Error in testing breakpoint condition:\n",
RETURN_MASK_ALL);
/* FIXME-someday, should give breakpoint # */
- free_all_values ();
+ value_free_to_mark (mark);
}
if (bl->cond && value_is_zero)
{
bs_class = bp_silent;
retval.call_dummy = 1;
break;
+ case bp_tracepoint:
+ /* Tracepoint hits should not be reported back to GDB, and
+ if one got through somehow, it should have been filtered
+ out already. */
+ internal_error (__FILE__, __LINE__,
+ _("bpstat_what: bp_tracepoint encountered"));
+ break;
}
current_action = table[(int) bs_class][(int) current_action];
}
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
- if (breakpoint_enabled (b) && b->type == bp_watchpoint)
+ if (breakpoint_enabled (b) && b->type == bp_watchpoint && b->loc != NULL)
return 1;
return 0;
}
{bp_thread_event, "thread events"},
{bp_overlay_event, "overlay events"},
{bp_catchpoint, "catchpoint"},
+ {bp_tracepoint, "tracepoint"},
};
static char bpenables[] = "nynny";
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
+ case bp_tracepoint:
if (opts.addressprint)
{
annotate_field (4);
break;
}
- if (!part_of_multiple && b->thread != -1)
+ if (!part_of_multiple)
{
- /* FIXME: This seems to be redundant and lost here; see the
- "stop only in" line a little further down. */
- ui_out_text (uiout, " thread ");
- ui_out_field_int (uiout, "thread", b->thread);
+ if (b->thread != -1)
+ {
+ /* FIXME: This seems to be redundant and lost here; see the
+ "stop only in" line a little further down. */
+ ui_out_text (uiout, " thread ");
+ ui_out_field_int (uiout, "thread", b->thread);
+ }
+ else if (b->task != 0)
+ {
+ ui_out_text (uiout, " task ");
+ ui_out_field_int (uiout, "task", b->task);
+ }
}
ui_out_text (uiout, "\n");
because the condition is an internal implementation detail
that we do not want to expose to the user. */
annotate_field (7);
- ui_out_text (uiout, "\tstop only if ");
+ if (b->type == bp_tracepoint)
+ ui_out_text (uiout, "\ttrace only if ");
+ else
+ ui_out_text (uiout, "\tstop only if ");
ui_out_field_string (uiout, "cond", b->cond_string);
ui_out_text (uiout, "\n");
}
do_cleanups (script_chain);
}
+ if (!part_of_multiple && b->pass_count)
+ {
+ annotate_field (10);
+ ui_out_text (uiout, "\tpass count ");
+ ui_out_field_int (uiout, "pass", b->pass_count);
+ ui_out_text (uiout, " \n");
+ }
+
+ if (!part_of_multiple && b->step_count)
+ {
+ annotate_field (11);
+ ui_out_text (uiout, "\tstep count ");
+ ui_out_field_int (uiout, "step", b->step_count);
+ ui_out_text (uiout, " \n");
+ }
+
+ if (!part_of_multiple && b->actions)
+ {
+ struct action_line *action;
+ annotate_field (12);
+ for (action = b->actions; action; action = action->next)
+ {
+ ui_out_text (uiout, " A\t");
+ ui_out_text (uiout, action->action);
+ ui_out_text (uiout, "\n");
+ }
+ }
+
if (ui_out_is_mi_like_p (uiout) && !part_of_multiple)
{
if (b->addr_string)
return (b->type == bp_breakpoint
|| b->type == bp_catchpoint
|| b->type == bp_hardware_breakpoint
+ || b->type == bp_tracepoint
|| b->type == bp_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint
switch (bpt->type)
{
case bp_breakpoint:
+ case bp_tracepoint:
case bp_until:
case bp_finish:
case bp_longjmp:
set_breakpoint_location_function (struct bp_location *loc)
{
if (loc->owner->type == bp_breakpoint
- || loc->owner->type == bp_hardware_breakpoint)
+ || loc->owner->type == bp_hardware_breakpoint
+ || loc->owner->type == bp_tracepoint)
{
find_pc_partial_function (loc->address, &(loc->function_name),
NULL, NULL);
if (sal.symtab == NULL)
b->source_file = NULL;
else
- b->source_file = savestring (sal.symtab->filename,
- strlen (sal.symtab->filename));
+ b->source_file = xstrdup (sal.symtab->filename);
b->loc->section = sal.section;
b->line_number = sal.line;
bl->inserted = 1;
}
-static struct breakpoint *
-create_internal_breakpoint (CORE_ADDR address, enum bptype type)
-{
- static int internal_breakpoint_number = -1;
- struct symtab_and_line sal;
- struct breakpoint *b;
-
- init_sal (&sal); /* initialize to zeroes */
-
- sal.pc = address;
- sal.section = find_pc_overlay (sal.pc);
-
- b = set_raw_breakpoint (sal, type);
- b->number = internal_breakpoint_number--;
- b->disposition = disp_donttouch;
-
- return b;
-}
-
-
static void
create_longjmp_breakpoint (char *func_name)
{
}
}
-static void
-create_overlay_event_breakpoint_1 (char *func_name, struct objfile *objfile)
-{
- struct breakpoint *b;
- struct minimal_symbol *m;
-
- if ((m = lookup_minimal_symbol_text (func_name, objfile)) == NULL)
- return;
-
- b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m),
- bp_overlay_event);
- b->addr_string = xstrdup (func_name);
-
- if (overlay_debugging == ovly_auto)
- {
- b->enable_state = bp_enabled;
- overlay_events_enabled = 1;
- }
- else
- {
- b->enable_state = bp_disabled;
- overlay_events_enabled = 0;
- }
- update_global_location_list (1);
-}
-
-static void
-create_overlay_event_breakpoint (char *func_name)
-{
- struct objfile *objfile;
- ALL_OBJFILES (objfile)
- create_overlay_event_breakpoint_1 (func_name, objfile);
-}
-
void
enable_overlay_breakpoints (void)
{
becomes enabled, or the duplicate is removed, gdb will try to insert
all breakpoints. If we don't set shlib_disabled here, we'll try
to insert those breakpoints and fail. */
- if (((b->type == bp_breakpoint) || (b->type == bp_hardware_breakpoint))
+ if (((b->type == bp_breakpoint)
+ || (b->type == bp_hardware_breakpoint)
+ || (b->type == bp_tracepoint))
&& !loc->shlib_disabled
#ifdef PC_SOLIB
&& PC_SOLIB (loc->address)
struct breakpoint *b = loc->owner;
if ((loc->loc_type == bp_loc_hardware_breakpoint
|| loc->loc_type == bp_loc_software_breakpoint)
- && !loc->shlib_disabled)
+ && !loc->shlib_disabled
+ && (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint)
+ && solib_contains_address_p (solib, loc->address))
{
-#ifdef PC_SOLIB
- char *so_name = PC_SOLIB (loc->address);
-#else
- char *so_name = solib_name_from_address (loc->address);
-#endif
- if (so_name && !strcmp (so_name, solib->so_name))
- {
- loc->shlib_disabled = 1;
- /* At this point, we cannot rely on remove_breakpoint
- succeeding so we must mark the breakpoint as not inserted
- to prevent future errors occurring in remove_breakpoints. */
- loc->inserted = 0;
- if (!disabled_shlib_breaks)
- {
- target_terminal_ours_for_output ();
- warning (_("Temporarily disabling breakpoints for unloaded shared library \"%s\""),
- so_name);
- }
- disabled_shlib_breaks = 1;
+ loc->shlib_disabled = 1;
+ /* At this point, we cannot rely on remove_breakpoint
+ succeeding so we must mark the breakpoint as not inserted
+ to prevent future errors occurring in remove_breakpoints. */
+ loc->inserted = 0;
+ if (!disabled_shlib_breaks)
+ {
+ target_terminal_ours_for_output ();
+ warning (_("Temporarily disabling breakpoints for unloaded shared library \"%s\""),
+ solib->so_name);
}
+ disabled_shlib_breaks = 1;
}
}
}
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
- b->cond_string = (cond_string == NULL) ?
- NULL : savestring (cond_string, strlen (cond_string));
+ b->cond_string = (cond_string == NULL) ? NULL : xstrdup (cond_string);
b->thread = -1;
b->addr_string = NULL;
b->enable_state = bp_enabled;
return b;
}
+/* Make a deep copy of momentary breakpoint ORIG. Returns NULL if
+ ORIG is NULL. */
+
+struct breakpoint *
+clone_momentary_breakpoint (struct breakpoint *orig)
+{
+ struct breakpoint *copy;
+
+ /* If there's nothing to clone, then return nothing. */
+ if (orig == NULL)
+ return NULL;
+
+ copy = set_raw_breakpoint_without_location (orig->type);
+ copy->loc = allocate_bp_location (copy);
+ set_breakpoint_location_function (copy->loc);
+
+ copy->loc->requested_address = orig->loc->requested_address;
+ copy->loc->address = orig->loc->address;
+ copy->loc->section = orig->loc->section;
+
+ if (orig->source_file == NULL)
+ copy->source_file = NULL;
+ else
+ copy->source_file = xstrdup (orig->source_file);
+
+ copy->line_number = orig->line_number;
+ copy->frame_id = orig->frame_id;
+ copy->thread = orig->thread;
+
+ copy->enable_state = bp_enabled;
+ copy->disposition = disp_donttouch;
+ copy->number = internal_breakpoint_number--;
+
+ update_global_location_list_nothrow (0);
+ return copy;
+}
+
struct breakpoint *
set_momentary_breakpoint_at_pc (CORE_ADDR pc, enum bptype type)
{
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_until:
case bp_finish:
create_breakpoint (struct symtabs_and_lines sals, char *addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count,
+ int thread, int task, int ignore_count,
struct breakpoint_ops *ops, int from_tty, int enabled)
{
struct breakpoint *b = NULL;
{
int i = hw_breakpoint_used_count ();
int target_resources_ok =
- TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint,
+ target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
i + 1, 0);
if (target_resources_ok == 0)
error (_("No hardware breakpoint support in the target."));
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->thread = thread;
+ b->task = task;
b->cond_string = cond_string;
b->ignore_count = ignore_count;
create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count,
+ int thread, int task, int ignore_count,
struct breakpoint_ops *ops, int from_tty,
int enabled)
{
create_breakpoint (expanded, addr_string[i],
cond_string, type, disposition,
- thread, ignore_count, ops, from_tty, enabled);
+ thread, task, ignore_count, ops, from_tty, enabled);
}
-
- update_global_location_list (1);
}
/* Parse ARG which is assumed to be a SAL specification possibly
sal.line = default_breakpoint_line;
sal.symtab = default_breakpoint_symtab;
sal.section = find_pc_overlay (sal.pc);
+
+ /* "break" without arguments is equivalent to "break *PC" where PC is
+ the default_breakpoint_address. So make sure to set
+ sal.explicit_pc to prevent GDB from trying to expand the list of
+ sals to include all other instances with the same symtab and line.
+ */
+ sal.explicit_pc = 1;
+
sals->sals[0] = sal;
sals->nelts = 1;
}
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)
+ char **cond_string, int *thread, int *task)
{
*cond_string = NULL;
*thread = -1;
if (!valid_thread_id (*thread))
error (_("Unknown thread %d."), *thread);
}
+ else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
+ {
+ char *tmptok;
+
+ tok = end_tok + 1;
+ tmptok = tok;
+ *task = strtol (tok, &tok, 0);
+ if (tok == tmptok)
+ error (_("Junk after task keyword."));
+ if (!valid_task_id (*task))
+ error (_("Unknown task %d\n"), *task);
+ }
else
error (_("Junk at end of arguments."));
}
static void
break_command_really (char *arg, char *cond_string, int thread,
int parse_condition_and_thread,
- int tempflag, int hardwareflag,
+ int tempflag, int hardwareflag, int traceflag,
int ignore_count,
enum auto_boolean pending_break_support,
struct breakpoint_ops *ops,
int i;
int pending = 0;
int not_found = 0;
+ enum bptype type_wanted;
+ int task = 0;
sals.sals = NULL;
sals.nelts = 0;
if (!pending)
breakpoint_sals_to_pc (&sals, addr_start);
+ type_wanted = (traceflag
+ ? bp_tracepoint
+ : (hardwareflag ? bp_hardware_breakpoint : bp_breakpoint));
+
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
re-parse it in context of each sal. */
cond_string = NULL;
thread = -1;
- find_condition_and_thread (arg, sals.sals[0].pc, &cond_string, &thread);
+ find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
+ &thread, &task);
if (cond_string)
make_cleanup (xfree, cond_string);
}
make_cleanup (xfree, cond_string);
}
}
- create_breakpoints (sals, addr_string, cond_string,
- hardwareflag ? bp_hardware_breakpoint
- : bp_breakpoint,
+ create_breakpoints (sals, addr_string, cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
- thread, ignore_count, ops, from_tty, enabled);
+ thread, task, ignore_count, ops, from_tty, enabled);
}
else
{
make_cleanup (xfree, copy_arg);
- b = set_raw_breakpoint_without_location (hardwareflag
- ? bp_hardware_breakpoint
- : bp_breakpoint);
+ b = set_raw_breakpoint_without_location (type_wanted);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->thread = -1;
b->ops = ops;
b->enable_state = enabled ? bp_enabled : bp_disabled;
- update_global_location_list (1);
mention (b);
}
discard_cleanups (breakpoint_chain);
/* But cleanup everything else. */
do_cleanups (old_chain);
+
+ /* error call may happen here - have BREAKPOINT_CHAIN already discarded. */
+ update_global_location_list (1);
}
/* Set a breakpoint.
break_command_really (arg,
NULL, 0, 1 /* parse arg */,
- tempflag, hardwareflag,
+ tempflag, hardwareflag, 0 /* traceflag */,
0 /* Ignore count */,
pending_break_support,
NULL /* breakpoint_ops */,
{
break_command_really (address, condition, thread,
0 /* condition and thread are valid. */,
- tempflag, hardwareflag,
+ tempflag, hardwareflag, 0 /* traceflag */,
ignore_count,
pending
? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
/* If this SAL corresponds to a breakpoint inserted using
a line number, then skip the function prologue if necessary. */
if (sal->explicit_line)
- skip_prologue_sal (sal);
+ {
+ /* Preserve the original line number. */
+ int saved_line = sal->line;
+ skip_prologue_sal (sal);
+ sal->line = saved_line;
+ }
}
if (sal->section == 0 && sal->symtab != NULL)
{
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
- TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_type, i + mem_cnt,
+ target_can_use_hardware_watchpoint (bp_type, i + mem_cnt,
other_type_used);
if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
error (_("Target does not support this type of hardware watchpoint."));
CORE_ADDR vaddr = VALUE_ADDRESS (v) + value_offset (v);
int len = TYPE_LENGTH (value_type (v));
- if (!TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len))
+ if (!target_region_ok_for_hw_watchpoint (vaddr, len))
return 0;
else
found_memory_cnt++;
breakpoint_adjustment_warning (b->loc->requested_address,
b->loc->address,
b->number, 1);
- bp_temp = b->loc->owner->disposition == disp_del;
+ bp_temp = b->disposition == disp_del;
ui_out_text (uiout,
bp_temp ? "Temporary catchpoint "
: "Catchpoint ");
int bp_temp;
int bp_throw;
- bp_temp = b->loc->owner->disposition == disp_del;
+ bp_temp = b->disposition == disp_del;
bp_throw = strstr (b->addr_string, "throw") != NULL;
ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
: _("Catchpoint "));
break_command_really (trigger_func_name, cond_string, -1,
0 /* condition and thread are valid. */,
- tempflag, 0,
+ tempflag, 0, 0,
0,
AUTO_BOOLEAN_TRUE /* pending */,
&gnu_v3_exception_catchpoint_ops, from_tty,
if (breakpoints_always_inserted_mode () && should_insert
&& (target_has_execution
- || (gdbarch_has_global_solist (target_gdbarch)
- && target_supports_multi_process ())))
+ || (gdbarch_has_global_breakpoints (target_gdbarch))))
insert_breakpoint_locations ();
do_cleanups (cleanups);
if (sals.sals[i].symtab == NULL)
b->source_file = NULL;
else
- b->source_file =
- savestring (sals.sals[i].symtab->filename,
- strlen (sals.sals[i].symtab->filename));
+ b->source_file = xstrdup (sals.sals[i].symtab->filename);
if (b->line_number == 0)
b->line_number = sals.sals[i].line;
return 0;
case bp_breakpoint:
case bp_hardware_breakpoint:
+ case bp_tracepoint:
if (b->addr_string == NULL)
{
/* Anything without a string can't be re-set. */
{
char *cond_string = 0;
int thread = -1;
+ int task = 0;
+
find_condition_and_thread (s, sals.sals[0].pc,
- &cond_string, &thread);
+ &cond_string, &thread, &task);
if (cond_string)
b->cond_string = cond_string;
b->thread = thread;
+ b->task = task;
b->condition_not_parsed = 0;
}
expanded = expand_line_sal_maybe (sals.sals[0]);
return 0;
}
-/* Re-set all breakpoints after symbols have been re-loaded. */
+/* Re-set all breakpoints after symbols have been re-loaded.
+
+ If OBJFILE is non-null, create overlay break point only in OBJFILE
+ (speed optimization). Otherwise rescan all loaded objfiles. */
+
void
-breakpoint_re_set (void)
+breakpoint_re_set_objfile (struct objfile *objfile)
{
struct breakpoint *b, *temp;
enum language save_language;
}
set_language (save_language);
input_radix = save_input_radix;
-
- create_overlay_event_breakpoint ("_ovly_debug_event");
+
+ if (objfile == NULL)
+ ALL_OBJFILES (objfile)
+ create_overlay_event_breakpoint ("_ovly_debug_event", objfile);
+ else
+ create_overlay_event_breakpoint ("_ovly_debug_event", objfile);
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded. */
+
+void
+breakpoint_re_set (void)
+{
+ breakpoint_re_set_objfile (NULL);
}
\f
/* Reset the thread number of this breakpoint:
bpt->number);
continue;
case bp_breakpoint:
+ case bp_tracepoint:
case bp_catchpoint:
case bp_hardware_breakpoint:
case bp_watchpoint:
int i;
i = hw_breakpoint_used_count ();
target_resources_ok =
- TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint,
+ target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
i + 1, 0);
if (target_resources_ok == 0)
error (_("No hardware breakpoint support in the target."));
bpt->number);
continue;
case bp_breakpoint:
+ case bp_tracepoint:
case bp_catchpoint:
case bp_hardware_breakpoint:
case bp_watchpoint:
return 0;
}
+/* Tracepoint-specific operations. */
+
+/* Set tracepoint count to NUM. */
+static void
+set_tracepoint_count (int num)
+{
+ tracepoint_count = num;
+ set_internalvar (lookup_internalvar ("tpnum"),
+ value_from_longest (builtin_type_int32, (LONGEST) num));
+}
+
+void
+trace_command (char *arg, int from_tty)
+{
+ break_command_really (arg,
+ NULL, 0, 1 /* parse arg */,
+ 0 /* tempflag */, 0 /* hardwareflag */,
+ 1 /* traceflag */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ NULL,
+ from_tty,
+ 1 /* enabled */);
+ set_tracepoint_count (breakpoint_count);
+}
+
+/* Print information on tracepoint number TPNUM_EXP, or all if
+ omitted. */
+
+static void
+tracepoints_info (char *tpnum_exp, int from_tty)
+{
+ struct breakpoint *b;
+ int tps_to_list = 0;
+
+ /* In the no-arguments case, say "No tracepoints" if none found. */
+ if (tpnum_exp == 0)
+ {
+ ALL_TRACEPOINTS (b)
+ {
+ if (b->number >= 0)
+ {
+ tps_to_list = 1;
+ break;
+ }
+ }
+ if (!tps_to_list)
+ {
+ ui_out_message (uiout, 0, "No tracepoints.\n");
+ return;
+ }
+ }
+
+ /* Otherwise be the same as "info break". */
+ breakpoints_info (tpnum_exp, from_tty);
+}
+
+/* The 'enable trace' command enables tracepoints.
+ Not supported by all targets. */
+static void
+enable_trace_command (char *args, int from_tty)
+{
+ enable_command (args, from_tty);
+}
+
+/* The 'disable trace' command disables tracepoints.
+ Not supported by all targets. */
+static void
+disable_trace_command (char *args, int from_tty)
+{
+ disable_command (args, from_tty);
+}
+
+/* Remove a tracepoint (or all if no argument) */
+static void
+delete_trace_command (char *arg, int from_tty)
+{
+ struct breakpoint *b, *temp;
+
+ dont_repeat ();
+
+ if (arg == 0)
+ {
+ int breaks_to_delete = 0;
+
+ /* Delete all breakpoints if no argument.
+ Do not delete internal or call-dummy breakpoints, these
+ have to be deleted with an explicit breakpoint number argument. */
+ ALL_TRACEPOINTS (b)
+ {
+ if (b->number >= 0)
+ {
+ breaks_to_delete = 1;
+ break;
+ }
+ }
+
+ /* Ask user only if there are some breakpoints to delete. */
+ if (!from_tty
+ || (breaks_to_delete && query (_("Delete all tracepoints? "))))
+ {
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ if (b->type == bp_tracepoint &&
+ b->number >= 0)
+ delete_breakpoint (b);
+ }
+ }
+ }
+ else
+ map_breakpoint_numbers (arg, delete_breakpoint);
+}
+
+/* Set passcount for tracepoint.
+
+ First command argument is passcount, second is tracepoint number.
+ If tracepoint number omitted, apply to most recently defined.
+ Also accepts special argument "all". */
+
+static void
+trace_pass_command (char *args, int from_tty)
+{
+ struct breakpoint *t1 = (struct breakpoint *) -1, *t2;
+ unsigned int count;
+ int all = 0;
+
+ if (args == 0 || *args == 0)
+ error (_("passcount command requires an argument (count + optional TP num)"));
+
+ count = strtoul (args, &args, 10); /* Count comes first, then TP num. */
+
+ while (*args && isspace ((int) *args))
+ args++;
+
+ if (*args && strncasecmp (args, "all", 3) == 0)
+ {
+ args += 3; /* Skip special argument "all". */
+ all = 1;
+ if (*args)
+ error (_("Junk at end of arguments."));
+ }
+ else
+ t1 = get_tracepoint_by_number (&args, 1, 1);
+
+ do
+ {
+ if (t1)
+ {
+ ALL_TRACEPOINTS (t2)
+ if (t1 == (struct breakpoint *) -1 || t1 == t2)
+ {
+ t2->pass_count = count;
+ observer_notify_tracepoint_modified (t2->number);
+ if (from_tty)
+ printf_filtered (_("Setting tracepoint %d's passcount to %d\n"),
+ t2->number, count);
+ }
+ if (! all && *args)
+ t1 = get_tracepoint_by_number (&args, 1, 0);
+ }
+ }
+ while (*args);
+}
+
+struct breakpoint *
+get_tracepoint (int num)
+{
+ struct breakpoint *t;
+
+ ALL_TRACEPOINTS (t)
+ if (t->number == num)
+ return t;
+
+ return NULL;
+}
+
+/* Utility: parse a tracepoint number and look it up in the list.
+ If MULTI_P is true, there might be a range of tracepoints in ARG.
+ if OPTIONAL_P is true, then if the argument is missing, the most
+ recent tracepoint (tracepoint_count) is returned. */
+struct breakpoint *
+get_tracepoint_by_number (char **arg, int multi_p, int optional_p)
+{
+ extern int tracepoint_count;
+ struct breakpoint *t;
+ int tpnum;
+ char *instring = arg == NULL ? NULL : *arg;
+
+ if (arg == NULL || *arg == NULL || ! **arg)
+ {
+ if (optional_p)
+ tpnum = tracepoint_count;
+ else
+ error_no_arg (_("tracepoint number"));
+ }
+ else
+ tpnum = multi_p ? get_number_or_range (arg) : get_number (arg);
+
+ if (tpnum <= 0)
+ {
+ if (instring && *instring)
+ printf_filtered (_("bad tracepoint number at or near '%s'\n"),
+ instring);
+ else
+ printf_filtered (_("Tracepoint argument missing and no previous tracepoint\n"));
+ return NULL;
+ }
+
+ ALL_TRACEPOINTS (t)
+ if (t->number == tpnum)
+ {
+ return t;
+ }
+
+ /* FIXME: if we are in the middle of a range we don't want to give
+ a message. The current interface to get_number_or_range doesn't
+ allow us to discover this. */
+ printf_unfiltered ("No tracepoint number %d.\n", tpnum);
+ return NULL;
+}
+
+/* save-tracepoints command */
+static void
+tracepoint_save_command (char *args, int from_tty)
+{
+ struct breakpoint *tp;
+ int any_tp = 0;
+ struct action_line *line;
+ FILE *fp;
+ char *i1 = " ", *i2 = " ";
+ char *indent, *actionline, *pathname;
+ char tmp[40];
+ struct cleanup *cleanup;
+
+ if (args == 0 || *args == 0)
+ error (_("Argument required (file name in which to save tracepoints)"));
+
+ /* See if we have anything to save. */
+ ALL_TRACEPOINTS (tp)
+ {
+ any_tp = 1;
+ break;
+ }
+ if (!any_tp)
+ {
+ warning (_("save-tracepoints: no tracepoints to save."));
+ return;
+ }
+
+ pathname = tilde_expand (args);
+ cleanup = make_cleanup (xfree, pathname);
+ if (!(fp = fopen (pathname, "w")))
+ error (_("Unable to open file '%s' for saving tracepoints (%s)"),
+ args, safe_strerror (errno));
+ make_cleanup_fclose (fp);
+
+ ALL_TRACEPOINTS (tp)
+ {
+ if (tp->addr_string)
+ fprintf (fp, "trace %s\n", tp->addr_string);
+ else
+ {
+ sprintf_vma (tmp, tp->loc->address);
+ fprintf (fp, "trace *0x%s\n", tmp);
+ }
+
+ if (tp->pass_count)
+ fprintf (fp, " passcount %d\n", tp->pass_count);
+
+ if (tp->actions)
+ {
+ fprintf (fp, " actions\n");
+ indent = i1;
+ for (line = tp->actions; line; line = line->next)
+ {
+ struct cmd_list_element *cmd;
+
+ QUIT; /* allow user to bail out with ^C */
+ actionline = line->action;
+ while (isspace ((int) *actionline))
+ actionline++;
+
+ fprintf (fp, "%s%s\n", indent, actionline);
+ if (*actionline != '#') /* skip for comment lines */
+ {
+ cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
+ if (cmd == 0)
+ error (_("Bad action list item: %s"), actionline);
+ if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+ indent = i2;
+ else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+ indent = i1;
+ }
+ }
+ }
+ }
+ do_cleanups (cleanup);
+ if (from_tty)
+ printf_filtered (_("Tracepoints saved to file '%s'.\n"), args);
+ return;
+}
+
+/* Create a vector of all tracepoints. */
+
+VEC(breakpoint_p) *
+all_tracepoints ()
+{
+ VEC(breakpoint_p) *tp_vec = 0;
+ struct breakpoint *tp;
+
+ ALL_TRACEPOINTS (tp)
+ {
+ VEC_safe_push (breakpoint_p, tp_vec, tp);
+ }
+
+ return tp_vec;
+}
+
\f
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
before a breakpoint is set. */
breakpoint_count = 0;
+ tracepoint_count = 0;
+
add_com ("ignore", class_breakpoint, ignore_command, _("\
Set ignore-count of breakpoint number N to COUNT.\n\
Usage is `ignore N COUNT'."));
can_use_hw_watchpoints = 1;
+ /* Tracepoint manipulation commands. */
+
+ c = add_com ("trace", class_breakpoint, trace_command, _("\
+Set a tracepoint at specified line or function.\n\
+\n"
+BREAK_ARGS_HELP ("trace") "\n\
+Do \"help tracepoints\" for info on other tracepoint commands."));
+ set_cmd_completer (c, location_completer);
+
+ add_com_alias ("tp", "trace", class_alias, 0);
+ add_com_alias ("tr", "trace", class_alias, 1);
+ add_com_alias ("tra", "trace", class_alias, 1);
+ add_com_alias ("trac", "trace", class_alias, 1);
+
+ add_info ("tracepoints", tracepoints_info, _("\
+Status of tracepoints, or tracepoint number NUMBER.\n\
+Convenience variable \"$tpnum\" contains the number of the\n\
+last tracepoint set."));
+
+ add_info_alias ("tp", "tracepoints", 1);
+
+ add_cmd ("tracepoints", class_trace, delete_trace_command, _("\
+Delete specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means delete all tracepoints."),
+ &deletelist);
+
+ c = add_cmd ("tracepoints", class_trace, disable_trace_command, _("\
+Disable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means disable all tracepoints."),
+ &disablelist);
+ deprecate_cmd (c, "disable");
+
+ c = add_cmd ("tracepoints", class_trace, enable_trace_command, _("\
+Enable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means enable all tracepoints."),
+ &enablelist);
+ deprecate_cmd (c, "enable");
+
+ add_com ("passcount", class_trace, trace_pass_command, _("\
+Set the passcount for a tracepoint.\n\
+The trace will end when the tracepoint has been passed 'count' times.\n\
+Usage: passcount COUNT TPNUM, where TPNUM may also be \"all\";\n\
+if TPNUM is omitted, passcount refers to the last tracepoint defined."));
+
+ c = add_com ("save-tracepoints", class_trace, tracepoint_save_command, _("\
+Save current tracepoint definitions as a script.\n\
+Use the 'source' command in another debug session to restore them."));
+ set_cmd_completer (c, filename_completer);
+
add_prefix_cmd ("breakpoint", class_maintenance, set_breakpoint_cmd, _("\
Breakpoint specific settings\n\
Configure various breakpoint-specific variables such as\n\
&breakpoint_show_cmdlist);
automatic_hardware_breakpoints = 1;
+
+ observer_attach_about_to_proceed (breakpoint_about_to_proceed);
}