#include "defs.h"
#include <ctype.h>
#include "symtab.h"
#include "frame.h"
#include "breakpoint.h"
#include "gdbtypes.h"
#include "expression.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "value.h"
#include "command.h"
#include "inferior.h"
#include "gdbthread.h"
#include "target.h"
#include "language.h"
#include "gdb_string.h"
#include "demangle.h"
#include "annotate.h"
#include "symfile.h"
#include "objfiles.h"
#include "linespec.h"
#include "completer.h"
#include "gdb.h"
#include "ui-out.h"
#include "cli-out.h"
#include "gdb-events.h"
#include "top.h"
#include "ui-file.h"
#include <time.h>
#include <locale.h>
extern int allow_objc_selectors_flag;
static int dont_mention = 0;
static void until_break_command_continuation (struct continuation_arg *arg);
static void catch_command_1 (char *, int, int);
static void enable_delete_command (char *, int);
static void enable_delete_breakpoint (struct breakpoint *);
static void enable_once_command (char *, int);
static void enable_once_breakpoint (struct breakpoint *);
static void disable_command (char *, int);
static void enable_command (char *, int);
static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
static void ignore_command (char *, int);
static void breakpoint_re_set_all ();
static int breakpoint_re_set_one (PTR);
static void clear_command (char *, int);
static void catch_command (char *, int);
static void handle_gnu_4_16_catch_command (char *, int, int);
static struct symtabs_and_lines get_catch_sals (int);
static void watch_command (char *, int);
static int can_use_hardware_watchpoint (struct value *);
extern void break_at_finish_command (char *, int);
extern void break_at_finish_at_depth_command (char *, int);
extern void tbreak_at_finish_command (char *, int);
static void break_command_1 (char *, int, int);
static void mention (struct breakpoint *);
struct breakpoint *set_raw_breakpoint (struct symtab_and_line, enum bptype);
static void check_duplicates (struct breakpoint *);
static void describe_other_breakpoints (CORE_ADDR, asection *);
static void breakpoints_info (char *, int);
static void breakpoint_1 (int, int);
static bpstat bpstat_alloc (struct breakpoint *, bpstat);
static int breakpoint_cond_eval (PTR);
static void cleanup_executing_breakpoints (PTR);
static void commands_command (char *, int);
static void condition_command (char *, int);
static int get_number_trailer (char **, int);
static void
async_breakpoint_command_continuation (struct continuation_arg *arg);
void set_breakpoint_count (int);
typedef enum
{
mark_inserted,
mark_uninserted
}
insertion_state_t;
static int remove_breakpoint (struct breakpoint *, insertion_state_t);
static enum print_stop_action print_it_typical (bpstat);
static enum print_stop_action print_bp_stop_message (bpstat bs);
typedef struct
{
enum exception_event_kind kind;
int enable_p;
}
args_for_catchpoint_enable;
static int watchpoint_check (PTR);
static int cover_target_enable_exception_callback (PTR);
static void maintenance_info_breakpoints (char *, int);
static void create_longjmp_breakpoint (char *);
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 hbreak_command (char *, int);
static void thbreak_command (char *, int);
static void watch_command_1 (char *, int, int);
static void rwatch_command (char *, int);
static void awatch_command (char *, int);
static void do_enable_breakpoint (struct breakpoint *, enum bpdisp);
static void solib_load_unload_1 (char *hookname,
int tempflag,
char *dll_pathname,
char *cond_string, enum bptype bp_kind);
static void create_fork_vfork_event_catchpoint (int tempflag,
char *cond_string,
enum bptype bp_kind);
static int do_captured_breakpoint (void *data);
static void break_at_finish_at_depth_command_1 (char *arg,
int flag, int from_tty);
static void break_at_finish_command_1 (char *arg, int flag, int from_tty);
static void stop_command (char *arg, int from_tty);
static void stopin_command (char *arg, int from_tty);
static void stopat_command (char *arg, int from_tty);
static char *ep_find_event_name_end (char *arg);
static char *ep_parse_optional_if_clause (char **arg);
static char *ep_parse_optional_filename (char **arg);
#if defined(CHILD_INSERT_EXEC_CATCHPOINT)
static void catch_exec_command_1 (char *arg, int tempflag, int from_tty);
#endif
static void create_exception_catchpoint (int tempflag, char *cond_string,
enum exception_event_kind ex_event,
struct symtab_and_line *sal);
static void catch_exception_command_1 (enum exception_event_kind ex_event,
char *arg, int tempflag, int from_tty);
static void tcatch_command (char *arg, int from_tty);
static void ep_skip_leading_whitespace (char **s);
static int can_use_hw_watchpoints;
void _initialize_breakpoint (void);
extern int addressprint;
static int executing_breakpoint_commands;
static int overlay_events_enabled;
#define ALL_BREAKPOINTS(B) for (B = breakpoint_chain; B; B = B->next)
#define ALL_BREAKPOINTS_SAFE(B,TMP) \
for (B = breakpoint_chain; \
B ? (TMP=B->next, 1): 0; \
B = TMP)
int must_shift_inst_regs =
#if defined(SHIFT_INST_REGS)
1
#else
0
#endif
;
int show_breakpoint_hit_counts = 1;
struct breakpoint *breakpoint_chain;
int breakpoint_count;
static struct exception_event_record *current_exception_event;
int exception_catchpoints_are_fragile = 0;
int exception_support_initialized = 0;
#ifndef SOLIB_LOADED_LIBRARY_PATHNAME
#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) ""
#endif
#ifndef SOLIB_UNLOADED_LIBRARY_PATHNAME
#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) ""
#endif
#ifndef SOLIB_CREATE_CATCH_LOAD_HOOK
#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag,filename,cond_string) \
error ("catch of library loads not yet implemented on this platform")
#endif
#ifndef SOLIB_CREATE_CATCH_UNLOAD_HOOK
#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename,cond_string) \
error ("catch of library unloads not yet implemented on this platform")
#endif
void
set_breakpoint_count (int num)
{
breakpoint_count = num;
set_internalvar (lookup_internalvar ("bpnum"),
value_from_longest (builtin_type_int, (LONGEST) num));
}
int
get_breakpoint_count ()
{
return breakpoint_count;
}
void
clear_breakpoint_hit_counts (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
b->hit_count = 0;
}
int default_breakpoint_valid;
CORE_ADDR default_breakpoint_address;
struct symtab *default_breakpoint_symtab;
int default_breakpoint_line;
static int
get_number_trailer (char **pp, int trailer)
{
int retval = 0;
char *p = *pp;
if (p == NULL)
return breakpoint_count;
else if (*p == '$')
{
char *varname;
char *start = ++p;
struct value *val;
while (isalnum (*p) || *p == '_')
p++;
varname = (char *) alloca (p - start + 1);
strncpy (varname, start, p - start);
varname[p - start] = '\0';
val = value_of_internalvar (lookup_internalvar (varname));
if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT)
retval = (int) value_as_long (val);
else
{
printf_filtered ("Convenience variable must have integer value.\n");
retval = 0;
}
}
else
{
if (*p == '-')
++p;
while (*p >= '0' && *p <= '9')
++p;
if (p == *pp)
{
while (*p && !isspace((int) *p))
++p;
retval = 0;
}
else
retval = atoi (*pp);
}
if (!(isspace (*p) || *p == '\0' || *p == trailer))
{
while (!(isspace (*p) || *p == '\0' || *p == trailer))
++p;
retval = 0;
}
while (isspace (*p))
p++;
*pp = p;
return retval;
}
int
get_number (char **pp)
{
return get_number_trailer (pp, '\0');
}
int
get_number_or_range (char **pp)
{
static int last_retval, end_value;
static char *end_ptr;
static int in_range = 0;
if (**pp != '-')
{
last_retval = get_number_trailer (pp, '-');
if (**pp == '-')
{
char **temp;
temp = &end_ptr;
end_ptr = *pp + 1;
while (isspace ((int) *end_ptr))
end_ptr++;
end_value = get_number (temp);
if (end_value < last_retval)
{
error ("inverted range");
}
else if (end_value == last_retval)
{
*pp = end_ptr;
}
else
in_range = 1;
}
}
else if (! in_range)
error ("negative value");
else
{
if (++last_retval == end_value)
{
*pp = end_ptr;
in_range = 0;
}
}
return last_retval;
}
static void
condition_command (char *arg, int from_tty)
{
register struct breakpoint *b;
char *p;
register int bnum;
if (arg == 0)
error_no_arg ("breakpoint number");
p = arg;
bnum = get_number (&p);
if (bnum == 0)
error ("Bad breakpoint argument: '%s'", arg);
ALL_BREAKPOINTS (b)
if (b->number == bnum)
{
if (b->cond)
{
xfree (b->cond);
b->cond = 0;
}
if (b->cond_string != NULL)
xfree (b->cond_string);
if (*p == 0)
{
b->cond = 0;
b->cond_string = NULL;
if (from_tty)
printf_filtered ("Breakpoint %d now unconditional.\n", bnum);
}
else
{
arg = p;
b->cond_string = savestring (arg, strlen (arg));
b->cond = parse_exp_1 (&arg, block_for_pc (b->address), 0);
if (*arg)
error ("Junk at end of expression");
}
breakpoints_changed ();
return;
}
error ("No breakpoint number %d.", bnum);
}
static void
commands_command (char *arg, int from_tty)
{
register struct breakpoint *b;
char *p;
register int bnum;
struct command_line *l;
if (executing_breakpoint_commands)
error ("Can't use the \"commands\" command among a breakpoint's commands.");
p = arg;
bnum = get_number (&p);
if (p && *p)
error ("Unexpected extra arguments following breakpoint number.");
ALL_BREAKPOINTS (b)
if (b->number == bnum)
{
char tmpbuf[128];
sprintf (tmpbuf,
"Type commands for when breakpoint %d is hit, one per line.",
bnum);
l = read_command_lines (tmpbuf, from_tty);
free_command_lines (&b->commands);
b->commands = l;
breakpoints_changed ();
return;
}
error ("No breakpoint number %d.", bnum);
}
int
read_memory_nobpt (CORE_ADDR memaddr, char *myaddr, unsigned len)
{
int status;
struct breakpoint *b;
CORE_ADDR bp_addr = 0;
int bp_size = 0;
if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
return target_read_memory (memaddr, myaddr, len);
ALL_BREAKPOINTS (b)
{
if (b->type == bp_none)
warning ("reading through apparently deleted breakpoint #%d?",
b->number);
if (b->type == bp_watchpoint
|| b->type == bp_hardware_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint)
continue;
if (!b->inserted)
continue;
bp_addr = b->address;
bp_size = 0;
if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
continue;
if (bp_size == 0)
continue;
if (bp_addr + bp_size <= memaddr)
continue;
if (bp_addr >= memaddr + len)
continue;
{
int bptoffset = 0;
if (bp_addr < memaddr)
{
bp_size -= memaddr - bp_addr;
bptoffset = memaddr - bp_addr;
bp_addr = memaddr;
}
if (bp_addr + bp_size > memaddr + len)
{
bp_size -= (bp_addr + bp_size) - (memaddr + len);
}
memcpy (myaddr + bp_addr - memaddr,
b->shadow_contents + bptoffset, bp_size);
if (bp_addr > memaddr)
{
status = read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
if (status != 0)
return status;
}
if (bp_addr + bp_size < memaddr + len)
{
status = read_memory_nobpt (bp_addr + bp_size,
myaddr + bp_addr + bp_size - memaddr,
memaddr + len - (bp_addr + bp_size));
if (status != 0)
return status;
}
return 0;
}
}
return target_read_memory (memaddr, myaddr, len);
}
int
insert_breakpoints (void)
{
register struct breakpoint *b, *temp;
int return_val = 0;
int val = 0;
int disabled_breaks = 0;
static char message1[] = "Error inserting catchpoint %d:\n";
static char message[sizeof (message1) + 30];
breakpoint_update ();
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->enable_state == bp_permanent)
continue;
else if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
&& b->type != bp_catch_fork
&& b->type != bp_catch_vfork
&& b->type != bp_catch_exec
&& b->type != bp_catch_throw
&& b->type != bp_catch_catch
&& b->enable_state != bp_disabled
&& b->enable_state != bp_shlib_disabled
&& b->enable_state != bp_call_disabled
&& !b->inserted
&& !b->duplicate)
{
if (overlay_debugging == ovly_off
|| b->section == NULL
|| !(section_is_overlay (b->section)))
{
if (b->type == bp_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->address,
b->shadow_contents);
else
val = target_insert_breakpoint (b->address, b->shadow_contents);
}
else
{
if (!overlay_events_enabled)
{
if (b->type == bp_hardware_breakpoint)
warning ("hardware breakpoint %d not supported in overlay!\n",
b->number);
else
{
CORE_ADDR addr = overlay_unmapped_address (b->address,
b->section);
val = target_insert_breakpoint (addr, b->shadow_contents);
if (val != 0)
warning ("overlay breakpoint %d failed: in ROM?",
b->number);
}
}
if (section_is_mapped (b->section))
{
if (b->type == bp_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->address,
b->shadow_contents);
else
val = target_insert_breakpoint (b->address,
b->shadow_contents);
}
else
{
continue;
}
}
if (val)
{
#if defined (DISABLE_UNSETTABLE_BREAK)
if (DISABLE_UNSETTABLE_BREAK (b->address))
{
val = 0;
b->enable_state = bp_shlib_disabled;
if (!disabled_breaks)
{
target_terminal_ours_for_output ();
printf_filtered ("Temporarily disabling shared library breakpoints:");
}
disabled_breaks = 1;
printf_filtered (" %d", b->number);
}
else
#endif
{
target_terminal_ours_for_output ();
warning ("Cannot insert breakpoint %d; disabling it.", b->number);
#ifdef ONE_PROCESS_WRITETEXT
warning ("The same program may be running in another process.");
#endif
memory_error (val, b->address);
}
}
else
b->inserted = 1;
if (val)
return_val = val;
}
else if (ep_is_exception_catchpoint (b)
&& b->enable_state != bp_disabled
&& b->enable_state != bp_shlib_disabled
&& b->enable_state != bp_call_disabled
&& !b->inserted
&& !b->duplicate)
{
sprintf (message, message1, b->number);
val = target_insert_breakpoint (b->address, b->shadow_contents);
if (val)
{
target_terminal_ours_for_output ();
warning ("Cannot insert catchpoint %d; disabling it.",
b->number);
b->enable_state = bp_disabled;
}
else
{
int val;
args_for_catchpoint_enable args;
args.kind = b->type == bp_catch_catch ?
EX_EVENT_CATCH : EX_EVENT_THROW;
args.enable_p = 1;
val = catch_errors (cover_target_enable_exception_callback,
&args,
message, RETURN_MASK_ALL);
if (val != 0 && val != -1)
{
b->inserted = 1;
}
if (val == -1)
{
target_terminal_ours_for_output ();
warning ("Cannot insert catchpoint %d; disabling it.",
b->number);
b->enable_state = bp_disabled;
}
}
if (val)
return_val = val;
}
else if ((b->type == bp_hardware_watchpoint ||
b->type == bp_read_watchpoint ||
b->type == bp_access_watchpoint)
&& b->enable_state == bp_enabled
&& b->disposition != disp_del_at_next_stop
&& !b->inserted
&& !b->duplicate)
{
struct frame_info *saved_frame;
int saved_level, within_current_scope;
struct value *mark = value_mark ();
struct value *v;
saved_frame = selected_frame;
saved_level = selected_frame_level;
if (b->exp_valid_block == NULL)
within_current_scope = 1;
else
{
struct frame_info *fi;
get_current_frame ();
fi = find_frame_addr_in_frame_chain (b->watchpoint_frame);
within_current_scope = (fi != NULL);
if (within_current_scope)
select_frame (fi, -1);
}
if (within_current_scope)
{
v = evaluate_expression (b->exp);
VALUE_CONTENTS (v);
value_release_to_mark (mark);
b->val_chain = v;
b->inserted = 1;
for (; v; v = v->next)
{
if (VALUE_LVAL (v) == lval_memory
&& ! VALUE_LAZY (v))
{
struct type *vtype = check_typedef (VALUE_TYPE (v));
if (v == b->val_chain
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR addr;
int len, type;
addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
len = TYPE_LENGTH (VALUE_TYPE (v));
type = hw_write;
if (b->type == bp_read_watchpoint)
type = hw_read;
else if (b->type == bp_access_watchpoint)
type = hw_access;
val = target_insert_watchpoint (addr, len, type);
if (val == -1)
{
b->inserted = 0;
}
val = 0;
}
}
}
if (!b->inserted)
{
remove_breakpoint (b, mark_uninserted);
warning ("Could not insert hardware watchpoint %d.",
b->number);
val = -1;
}
}
else
{
printf_filtered ("Hardware watchpoint %d deleted ", b->number);
printf_filtered ("because the program has left the block \n");
printf_filtered ("in which its expression is valid.\n");
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
}
if ((saved_frame != selected_frame) ||
(saved_level != selected_frame_level))
select_frame (saved_frame, saved_level);
if (val)
return_val = val;
}
else if ((b->type == bp_catch_fork
|| b->type == bp_catch_vfork
|| b->type == bp_catch_exec)
&& b->enable_state == bp_enabled
&& !b->inserted
&& !b->duplicate)
{
val = -1;
switch (b->type)
{
case bp_catch_fork:
val = target_insert_fork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_vfork:
val = target_insert_vfork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_exec:
val = target_insert_exec_catchpoint (PIDGET (inferior_ptid));
break;
default:
warning ("Internal error, %s line %d.", __FILE__, __LINE__);
break;
}
if (val < 0)
{
target_terminal_ours_for_output ();
warning ("Cannot insert catchpoint %d.", b->number);
}
else
b->inserted = 1;
if (val)
return_val = val;
}
}
if (disabled_breaks)
printf_filtered ("\n");
return return_val;
}
int
remove_breakpoints (void)
{
register struct breakpoint *b;
int val;
ALL_BREAKPOINTS (b)
{
if (b->inserted)
{
val = remove_breakpoint (b, mark_uninserted);
if (val != 0)
return val;
}
}
return 0;
}
int
remove_hw_watchpoints (void)
{
register struct breakpoint *b;
int val;
ALL_BREAKPOINTS (b)
{
if (b->inserted
&& (b->type == bp_hardware_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint))
{
val = remove_breakpoint (b, mark_uninserted);
if (val != 0)
return val;
}
}
return 0;
}
int
reattach_breakpoints (int pid)
{
register struct breakpoint *b;
int val;
struct cleanup *old_chain = save_inferior_ptid ();
inferior_ptid = pid_to_ptid (pid);
ALL_BREAKPOINTS (b)
{
if (b->inserted)
{
remove_breakpoint (b, mark_inserted);
if (b->type == bp_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
else
val = target_insert_breakpoint (b->address, b->shadow_contents);
if (val != 0)
{
do_cleanups (old_chain);
return val;
}
}
}
do_cleanups (old_chain);
return 0;
}
void
update_breakpoints_after_exec (void)
{
struct breakpoint *b;
struct breakpoint *temp;
mark_breakpoints_out ();
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->type == bp_shlib_event)
{
delete_breakpoint (b);
continue;
}
if (b->type == bp_thread_event || b->type == bp_overlay_event)
{
delete_breakpoint (b);
continue;
}
if (b->type == bp_step_resume)
{
delete_breakpoint (b);
continue;
}
if (b->type == bp_through_sigtramp)
{
delete_breakpoint (b);
continue;
}
if ((b->type == bp_catch_catch) || (b->type == bp_catch_throw))
{
delete_breakpoint (b);
continue;
}
if ((b->type == bp_catch_exec) ||
(b->type == bp_catch_vfork) ||
(b->type == bp_catch_fork))
{
b->address = (CORE_ADDR) NULL;
continue;
}
if (b->type == bp_finish)
{
continue;
}
if (b->addr_string == NULL)
{
delete_breakpoint (b);
continue;
}
b->address = (CORE_ADDR) NULL;
}
create_overlay_event_breakpoint ("_ovly_debug_event");
}
int
detach_breakpoints (int pid)
{
register struct breakpoint *b;
int val;
struct cleanup *old_chain = save_inferior_ptid ();
if (pid == PIDGET (inferior_ptid))
error ("Cannot detach breakpoints of inferior_ptid");
inferior_ptid = pid_to_ptid (pid);
ALL_BREAKPOINTS (b)
{
if (b->inserted)
{
val = remove_breakpoint (b, mark_inserted);
if (val != 0)
{
do_cleanups (old_chain);
return val;
}
}
}
do_cleanups (old_chain);
return 0;
}
static int
remove_breakpoint (struct breakpoint *b, insertion_state_t is)
{
int val;
if (b->enable_state == bp_permanent)
return 0;
if (b->type == bp_none)
warning ("attempted to remove apparently deleted breakpoint #%d?",
b->number);
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
&& b->type != bp_catch_fork
&& b->type != bp_catch_vfork
&& b->type != bp_catch_exec
&& b->type != bp_catch_catch
&& b->type != bp_catch_throw)
{
if (overlay_debugging == ovly_off
|| b->section == NULL
|| !(section_is_overlay (b->section)))
{
if (b->type == bp_hardware_breakpoint)
val = target_remove_hw_breakpoint (b->address,
b->shadow_contents);
else
val = target_remove_breakpoint (b->address, b->shadow_contents);
}
else
{
if (!overlay_events_enabled)
{
CORE_ADDR addr = overlay_unmapped_address (b->address,
b->section);
if (b->type != bp_hardware_breakpoint)
target_remove_hw_breakpoint (addr, b->shadow_contents);
else
target_remove_breakpoint (addr, b->shadow_contents);
}
if (b->inserted)
{
if (b->type == bp_hardware_breakpoint)
val = target_remove_hw_breakpoint (b->address,
b->shadow_contents);
else
val = target_remove_breakpoint (b->address,
b->shadow_contents);
}
else
{
val = 0;
}
}
if (val)
return val;
b->inserted = (is == mark_inserted);
}
else if ((b->type == bp_hardware_watchpoint ||
b->type == bp_read_watchpoint ||
b->type == bp_access_watchpoint)
&& b->enable_state == bp_enabled
&& !b->duplicate)
{
struct value *v;
struct value *n;
b->inserted = (is == mark_inserted);
for (v = b->val_chain; v; v = v->next)
{
if (VALUE_LVAL (v) == lval_memory
&& ! VALUE_LAZY (v))
{
struct type *vtype = check_typedef (VALUE_TYPE (v));
if (v == b->val_chain
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR addr;
int len, type;
addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
len = TYPE_LENGTH (VALUE_TYPE (v));
type = hw_write;
if (b->type == bp_read_watchpoint)
type = hw_read;
else if (b->type == bp_access_watchpoint)
type = hw_access;
val = target_remove_watchpoint (addr, len, type);
if (val == -1)
b->inserted = 1;
val = 0;
}
}
}
if ((is == mark_uninserted) && (b->inserted))
warning ("Could not remove hardware watchpoint %d.",
b->number);
for (v = b->val_chain; v; v = n)
{
n = v->next;
value_free (v);
}
b->val_chain = NULL;
}
else if ((b->type == bp_catch_fork ||
b->type == bp_catch_vfork ||
b->type == bp_catch_exec)
&& b->enable_state == bp_enabled
&& !b->duplicate)
{
val = -1;
switch (b->type)
{
case bp_catch_fork:
val = target_remove_fork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_vfork:
val = target_remove_vfork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_exec:
val = target_remove_exec_catchpoint (PIDGET (inferior_ptid));
break;
default:
warning ("Internal error, %s line %d.", __FILE__, __LINE__);
break;
}
if (val)
return val;
b->inserted = (is == mark_inserted);
}
else if ((b->type == bp_catch_catch ||
b->type == bp_catch_throw)
&& b->enable_state == bp_enabled
&& !b->duplicate)
{
val = target_remove_breakpoint (b->address, b->shadow_contents);
if (val)
return val;
b->inserted = (is == mark_inserted);
}
else if (ep_is_exception_catchpoint (b)
&& b->inserted
&& b->enable_state == bp_enabled
&& !b->duplicate)
{
val = target_remove_breakpoint (b->address, b->shadow_contents);
if (val)
return val;
b->inserted = (is == mark_inserted);
}
return 0;
}
void
mark_breakpoints_out (void)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
b->inserted = 0;
}
void
breakpoint_init_inferior (enum inf_context context)
{
register struct breakpoint *b, *temp;
static int warning_needed = 0;
ALL_BREAKPOINTS_SAFE (b, temp)
{
b->inserted = 0;
switch (b->type)
{
case bp_call_dummy:
case bp_watchpoint_scope:
delete_breakpoint (b);
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
if (b->exp_valid_block != NULL)
delete_breakpoint (b);
break;
default:
if (ep_is_exception_catchpoint (b) &&
exception_catchpoints_are_fragile)
{
warning_needed = 1;
delete_breakpoint (b);
}
break;
}
}
if (exception_catchpoints_are_fragile)
exception_support_initialized = 0;
if (warning_needed && (context != inf_exited))
{
warning ("Exception catchpoints from last run were deleted.");
warning ("You must reinsert them explicitly.");
warning_needed = 0;
}
}
enum breakpoint_here
breakpoint_here_p (CORE_ADDR pc)
{
register struct breakpoint *b;
int any_breakpoint_here = 0;
ALL_BREAKPOINTS (b)
if ((b->enable_state == bp_enabled
|| b->enable_state == bp_permanent)
&& b->address == pc)
{
if (overlay_debugging
&& section_is_overlay (b->section)
&& !section_is_mapped (b->section))
continue;
else if (b->enable_state == bp_permanent)
return permanent_breakpoint_here;
else
any_breakpoint_here = 1;
}
return any_breakpoint_here ? ordinary_breakpoint_here : 0;
}
int
breakpoint_inserted_here_p (CORE_ADDR pc)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->inserted
&& b->address == pc)
{
if (overlay_debugging
&& section_is_overlay (b->section)
&& !section_is_mapped (b->section))
continue;
else
return 1;
}
return 0;
}
int
frame_in_dummy (struct frame_info *frame)
{
struct breakpoint *b;
if (!CALL_DUMMY_P)
return 0;
if (USE_GENERIC_DUMMY_FRAMES)
return generic_pc_in_call_dummy (frame->pc, frame->frame, frame->frame);
ALL_BREAKPOINTS (b)
{
if (b->type == bp_call_dummy
&& b->frame == frame->frame
&& (frame->pc
>= (b->address
- SIZEOF_CALL_DUMMY_WORDS / sizeof (LONGEST) * REGISTER_SIZE))
&& frame->pc <= b->address)
return 1;
}
return 0;
}
int
breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
{
struct breakpoint *b;
int thread;
thread = pid_to_thread_id (ptid);
ALL_BREAKPOINTS (b)
if (b->enable_state != bp_disabled
&& b->enable_state != bp_shlib_disabled
&& b->enable_state != bp_call_disabled
&& b->address == pc
&& (b->thread == -1 || b->thread == thread))
{
if (overlay_debugging
&& section_is_overlay (b->section)
&& !section_is_mapped (b->section))
continue;
else
return 1;
}
return 0;
}
int
ep_is_catchpoint (struct breakpoint *ep)
{
return
(ep->type == bp_catch_load)
|| (ep->type == bp_catch_unload)
|| (ep->type == bp_catch_fork)
|| (ep->type == bp_catch_vfork)
|| (ep->type == bp_catch_exec)
|| (ep->type == bp_catch_catch)
|| (ep->type == bp_catch_throw);
}
int
ep_is_shlib_catchpoint (struct breakpoint *ep)
{
return
(ep->type == bp_catch_load)
|| (ep->type == bp_catch_unload);
}
int
ep_is_exception_catchpoint (struct breakpoint *ep)
{
return
(ep->type == bp_catch_catch)
|| (ep->type == bp_catch_throw);
}
void
bpstat_clear (bpstat *bsp)
{
bpstat p;
bpstat q;
if (bsp == 0)
return;
p = *bsp;
while (p != NULL)
{
q = p->next;
if (p->old_val != NULL)
value_free (p->old_val);
xfree (p);
p = q;
}
*bsp = NULL;
}
bpstat
bpstat_copy (bpstat bs)
{
bpstat p = NULL;
bpstat tmp;
bpstat retval = NULL;
if (bs == NULL)
return bs;
for (; bs != NULL; bs = bs->next)
{
tmp = (bpstat) xmalloc (sizeof (*tmp));
memcpy (tmp, bs, sizeof (*tmp));
if (p == NULL)
retval = tmp;
else
p->next = tmp;
p = tmp;
}
p->next = NULL;
return retval;
}
bpstat
bpstat_find_breakpoint (bpstat bsp, struct breakpoint *breakpoint)
{
if (bsp == NULL)
return NULL;
for (; bsp != NULL; bsp = bsp->next)
{
if (bsp->breakpoint_at == breakpoint)
return bsp;
}
return NULL;
}
struct breakpoint *
bpstat_find_step_resume_breakpoint (bpstat bsp)
{
int current_thread;
if (bsp == NULL)
error ("Internal error (bpstat_find_step_resume_breakpoint)");
current_thread = pid_to_thread_id (inferior_ptid);
for (; bsp != NULL; bsp = bsp->next)
{
if ((bsp->breakpoint_at != NULL) &&
(bsp->breakpoint_at->type == bp_step_resume) &&
(bsp->breakpoint_at->thread == current_thread ||
bsp->breakpoint_at->thread == -1))
return bsp->breakpoint_at;
}
error ("Internal error (no step_resume breakpoint found)");
}
int
bpstat_num (bpstat *bsp)
{
struct breakpoint *b;
if ((*bsp) == NULL)
return 0;
else
{
b = (*bsp)->breakpoint_at;
*bsp = (*bsp)->next;
if (b == NULL)
return -1;
else
return b->number;
}
}
void
bpstat_clear_actions (bpstat bs)
{
for (; bs != NULL; bs = bs->next)
{
bs->commands = NULL;
if (bs->old_val != NULL)
{
value_free (bs->old_val);
bs->old_val = NULL;
}
}
}
static void
cleanup_executing_breakpoints (PTR ignore)
{
executing_breakpoint_commands = 0;
}
void
bpstat_do_actions (bpstat *bsp)
{
bpstat bs;
struct cleanup *old_chain;
struct command_line *cmd;
int first_command = 0;
if (executing_breakpoint_commands)
return;
executing_breakpoint_commands = 1;
old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
top:
bs = *bsp;
breakpoint_proceeded = 0;
for (; bs != NULL; bs = bs->next)
{
cmd = bs->commands;
while (cmd != NULL)
{
first_command++;
execute_control_command (cmd);
if (breakpoint_proceeded)
break;
else
cmd = cmd->next;
}
if (breakpoint_proceeded)
{
if (event_loop_p
&& (target_can_async_p() && target_executing))
{
if (!ui_out_is_mi_like_p (uiout))
add_continuation (async_breakpoint_command_continuation, NULL);
break;
}
else
goto top;
}
else
bs->commands = NULL;
}
if (!breakpoint_proceeded && first_command && ui_out_is_mi_like_p (uiout))
{
ui_out_notify_begin (uiout, "breakpoint-command-completed");
ui_out_notify_end (uiout);
}
executing_breakpoint_commands = 0;
discard_cleanups (old_chain);
}
static void
async_breakpoint_command_continuation (struct continuation_arg *arg)
{
bpstat_do_actions (&stop_bpstat);
}
static enum print_stop_action
print_it_typical (bpstat bs)
{
struct cleanup *old_chain;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
if (bs->breakpoint_at == NULL)
return PRINT_UNKNOWN;
switch (bs->breakpoint_at->type)
{
case bp_breakpoint:
case bp_hardware_breakpoint:
annotate_breakpoint (bs->breakpoint_at->number);
ui_out_text (uiout, "\nBreakpoint ");
if (ui_out_is_mi_like_p (uiout)) {
bpstat bpstat_ptr;
int any_commands = 0;
ui_out_field_string (uiout, "reason", "breakpoint-hit");
for (bpstat_ptr = bs; bpstat_ptr != NULL ; bpstat_ptr = bpstat_ptr->next)
{
if (bpstat_ptr->commands != NULL)
{
any_commands = 1;
break;
}
}
if (any_commands)
ui_out_field_string (uiout, "commands", "yes");
else
ui_out_field_string (uiout, "commands", "no");
}
ui_out_field_int (uiout, "bkptno", bs->breakpoint_at->number);
ui_out_text (uiout, ", ");
return PRINT_SRC_AND_LOC;
break;
case bp_shlib_event:
if (interpreter_p && strncmp (interpreter_p, "mi", 2) == 0)
ui_out_field_string (uiout, "reason", "shlib-event");
else
printf_filtered ("Stopped due to shared library event\n");
return PRINT_NOTHING;
break;
case bp_thread_event:
printf_filtered ("Thread Event Breakpoint: gdb should not stop!\n");
return PRINT_NOTHING;
break;
case bp_overlay_event:
printf_filtered ("Overlay Event Breakpoint: gdb should not stop!\n");
return PRINT_NOTHING;
break;
case bp_catch_load:
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
printf_filtered ("loaded");
printf_filtered (" %s), ", bs->breakpoint_at->triggered_dll_pathname);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_unload:
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
printf_filtered ("unloaded");
printf_filtered (" %s), ", bs->breakpoint_at->triggered_dll_pathname);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_fork:
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
printf_filtered ("forked");
printf_filtered (" process %d), ",
bs->breakpoint_at->forked_inferior_pid);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_vfork:
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
printf_filtered ("vforked");
printf_filtered (" process %d), ",
bs->breakpoint_at->forked_inferior_pid);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_exec:
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered ("\nCatchpoint %d (exec'd %s), ",
bs->breakpoint_at->number,
bs->breakpoint_at->exec_pathname);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_catch:
if (current_exception_event &&
(CURRENT_EXCEPTION_KIND == EX_EVENT_CATCH))
{
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered ("\nCatchpoint %d (exception caught), ",
bs->breakpoint_at->number);
printf_filtered ("throw location ");
if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
printf_filtered ("%s:%d",
CURRENT_EXCEPTION_THROW_FILE,
CURRENT_EXCEPTION_THROW_LINE);
else
printf_filtered ("unknown");
printf_filtered (", catch location ");
if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
printf_filtered ("%s:%d",
CURRENT_EXCEPTION_CATCH_FILE,
CURRENT_EXCEPTION_CATCH_LINE);
else
printf_filtered ("unknown");
printf_filtered ("\n");
return PRINT_SRC_ONLY;
}
else
{
return PRINT_UNKNOWN;
}
break;
case bp_catch_throw:
if (current_exception_event &&
(CURRENT_EXCEPTION_KIND == EX_EVENT_THROW))
{
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered ("\nCatchpoint %d (exception thrown), ",
bs->breakpoint_at->number);
printf_filtered ("throw location ");
if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
printf_filtered ("%s:%d",
CURRENT_EXCEPTION_THROW_FILE,
CURRENT_EXCEPTION_THROW_LINE);
else
printf_filtered ("unknown");
printf_filtered (", catch location ");
if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
printf_filtered ("%s:%d",
CURRENT_EXCEPTION_CATCH_FILE,
CURRENT_EXCEPTION_CATCH_LINE);
else
printf_filtered ("unknown");
printf_filtered ("\n");
return PRINT_SRC_ONLY;
}
else
{
return PRINT_UNKNOWN;
}
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
if (bs->old_val != NULL)
{
annotate_watchpoint (bs->breakpoint_at->number);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "watchpoint-trigger");
mention (bs->breakpoint_at);
ui_out_tuple_begin (uiout, "value");
ui_out_text (uiout, "\nOld value = ");
value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
ui_out_field_stream (uiout, "old", stb);
ui_out_text (uiout, "\nNew value = ");
value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
ui_out_field_stream (uiout, "new", stb);
ui_out_tuple_end (uiout);
ui_out_text (uiout, "\n");
value_free (bs->old_val);
bs->old_val = NULL;
}
return PRINT_UNKNOWN;
break;
case bp_read_watchpoint:
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "read-watchpoint-trigger");
mention (bs->breakpoint_at);
ui_out_tuple_begin (uiout, "value");
ui_out_text (uiout, "\nValue = ");
value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
ui_out_field_stream (uiout, "value", stb);
ui_out_tuple_end (uiout);
ui_out_text (uiout, "\n");
return PRINT_UNKNOWN;
break;
case bp_access_watchpoint:
if (bs->old_val != NULL)
{
annotate_watchpoint (bs->breakpoint_at->number);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
mention (bs->breakpoint_at);
ui_out_tuple_begin (uiout, "value");
ui_out_text (uiout, "\nOld value = ");
value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
ui_out_field_stream (uiout, "old", stb);
value_free (bs->old_val);
bs->old_val = NULL;
ui_out_text (uiout, "\nNew value = ");
}
else
{
mention (bs->breakpoint_at);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
ui_out_tuple_begin (uiout, "value");
ui_out_text (uiout, "\nValue = ");
}
value_print (bs->breakpoint_at->val, stb->stream, 0,Val_pretty_default);
ui_out_field_stream (uiout, "new", stb);
ui_out_tuple_end (uiout);
ui_out_text (uiout, "\n");
return PRINT_UNKNOWN;
break;
case bp_finish:
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "function-finished");
return PRINT_UNKNOWN;
break;
case bp_until:
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "location-reached");
return PRINT_UNKNOWN;
break;
case bp_none:
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
default:
return PRINT_UNKNOWN;
}
}
static enum print_stop_action
print_bp_stop_message (bpstat bs)
{
switch (bs->print_it)
{
case print_it_noop:
return PRINT_UNKNOWN;
break;
case print_it_done:
return PRINT_SRC_AND_LOC;
break;
case print_it_normal:
return print_it_typical (bs);
break;
default:
internal_error (__FILE__, __LINE__,
"print_bp_stop_message: unrecognized enum value");
break;
}
}
enum print_stop_action
bpstat_print (bpstat bs)
{
int val;
for (; bs; bs = bs->next)
{
val = print_bp_stop_message (bs);
if (val == PRINT_SRC_ONLY
|| val == PRINT_SRC_AND_LOC
|| val == PRINT_NOTHING)
return val;
}
return PRINT_UNKNOWN;
}
static int
breakpoint_cond_eval (PTR exp)
{
struct value *mark = value_mark ();
int i = !value_true (evaluate_expression ((struct expression *) exp));
value_free_to_mark (mark);
return i;
}
static bpstat
bpstat_alloc (struct breakpoint *b, bpstat cbs )
{
bpstat bs;
bs = (bpstat) xmalloc (sizeof (*bs));
cbs->next = bs;
bs->breakpoint_at = b;
bs->commands = NULL;
bs->old_val = NULL;
bs->print_it = print_it_normal;
return bs;
}
int
watchpoint_equal (struct value *arg1, struct value *arg2)
{
register int len;
register char *p1, *p2;
if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY)
&& (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_ARRAY))
{
int len = TYPE_LENGTH (VALUE_TYPE (arg1));
if (TYPE_LENGTH (VALUE_TYPE (arg1)) != TYPE_LENGTH (VALUE_TYPE (arg2)))
return 0;
p1 = VALUE_CONTENTS (arg1);
p2 = VALUE_CONTENTS (arg2);
while (--len >= 0)
{
if (*p1++ != *p2++)
break;
}
return len < 0;
}
return value_equal (arg1, arg2);
}
#define WP_DELETED 1
#define WP_VALUE_CHANGED 2
#define WP_VALUE_NOT_CHANGED 3
#define BP_TEMPFLAG 1
#define BP_HARDWAREFLAG 2
#define BP_FUTUREFLAG 4
static int
watchpoint_check (PTR p)
{
bpstat bs = (bpstat) p;
struct breakpoint *b;
struct frame_info *fr;
int within_current_scope;
b = bs->breakpoint_at;
if (b->exp_valid_block == NULL)
within_current_scope = 1;
else
{
reinit_frame_cache ();
fr = find_frame_addr_in_frame_chain (b->watchpoint_frame);
within_current_scope = (fr != NULL);
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)
select_frame (fr, -1);
}
if (within_current_scope)
{
struct value *mark = value_mark ();
struct value *new_val = evaluate_expression (bs->breakpoint_at->exp);
if (!watchpoint_equal (b->val, new_val))
{
release_value (new_val);
value_free_to_mark (mark);
bs->old_val = b->val;
b->val = new_val;
return WP_VALUE_CHANGED;
}
else
{
value_free_to_mark (mark);
return WP_VALUE_NOT_CHANGED;
}
}
else
{
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "watchpoint-scope");
ui_out_text (uiout, "\nWatchpoint ");
ui_out_field_int (uiout, "wpnum", bs->breakpoint_at->number);
ui_out_text (uiout, " deleted because the program has left the block in\n\
which its expression is valid.\n");
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
return WP_DELETED;
}
}
bpstat
bpstat_stop_status (CORE_ADDR *pc, int not_a_breakpoint)
{
register struct breakpoint *b, *temp;
CORE_ADDR bp_addr;
int real_breakpoint = 0;
struct bpstats root_bs[1];
bpstat bs = root_bs;
static char message1[] =
"Error evaluating expression for watchpoint %d\n";
char message[sizeof (message1) + 30 ];
bp_addr = *pc - (not_a_breakpoint && !SOFTWARE_SINGLE_STEP_P () ?
0 : DECR_PC_AFTER_BREAK);
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->enable_state == bp_disabled
|| b->enable_state == bp_shlib_disabled
|| b->enable_state == bp_call_disabled)
continue;
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
&& b->type != bp_hardware_breakpoint
&& b->type != bp_catch_fork
&& b->type != bp_catch_vfork
&& b->type != bp_catch_exec
&& b->type != bp_catch_catch
&& b->type != bp_catch_throw)
{
if (b->address != bp_addr)
continue;
if (overlay_debugging
&& section_is_overlay (b->section)
&& !section_is_mapped (b->section))
continue;
}
if (b->type == bp_hardware_breakpoint)
{
if (b->address != (*pc - DECR_PC_AFTER_HW_BREAK))
continue;
if (overlay_debugging
&& section_is_overlay (b->section)
&& !section_is_mapped (b->section))
continue;
}
if ((b->type == bp_catch_load)
#if defined(SOLIB_HAVE_LOAD_EVENT)
&& (!SOLIB_HAVE_LOAD_EVENT (PIDGET (inferior_ptid))
|| ((b->dll_pathname != NULL)
&& (strcmp (b->dll_pathname,
SOLIB_LOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid)))
!= 0)))
#endif
)
continue;
if ((b->type == bp_catch_unload)
#if defined(SOLIB_HAVE_UNLOAD_EVENT)
&& (!SOLIB_HAVE_UNLOAD_EVENT (PIDGET (inferior_ptid))
|| ((b->dll_pathname != NULL)
&& (strcmp (b->dll_pathname,
SOLIB_UNLOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid)))
!= 0)))
#endif
)
continue;
if ((b->type == bp_catch_fork)
&& !target_has_forked (PIDGET (inferior_ptid),
&b->forked_inferior_pid))
continue;
if ((b->type == bp_catch_vfork)
&& !target_has_vforked (PIDGET (inferior_ptid),
&b->forked_inferior_pid))
continue;
if ((b->type == bp_catch_exec)
&& !target_has_execd (PIDGET (inferior_ptid), &b->exec_pathname))
continue;
if (ep_is_exception_catchpoint (b) &&
!(current_exception_event = target_get_current_exception_event ()))
continue;
bs = bpstat_alloc (b, bs);
bs->stop = 1;
bs->print = 1;
sprintf (message, message1, b->number);
if (b->type == bp_watchpoint ||
b->type == bp_hardware_watchpoint)
{
switch (catch_errors (watchpoint_check, bs, message,
RETURN_MASK_ALL))
{
case WP_DELETED:
bs->print_it = print_it_done;
break;
case WP_VALUE_CHANGED:
++(b->hit_count);
break;
case WP_VALUE_NOT_CHANGED:
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
default:
case 0:
printf_filtered ("Watchpoint %d deleted.\n", b->number);
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
bs->print_it = print_it_done;
break;
}
}
else if (b->type == bp_read_watchpoint ||
b->type == bp_access_watchpoint)
{
CORE_ADDR addr;
struct value *v;
int found = 0;
addr = target_stopped_data_address ();
if (addr == 0)
continue;
for (v = b->val_chain; v; v = v->next)
{
if (VALUE_LVAL (v) == lval_memory
&& ! VALUE_LAZY (v))
{
struct type *vtype = check_typedef (VALUE_TYPE (v));
if (v == b->val_chain
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR vaddr;
vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
if (addr >= vaddr &&
addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
found = 1;
}
}
}
if (found)
switch (catch_errors (watchpoint_check, bs, message,
RETURN_MASK_ALL))
{
case WP_DELETED:
bs->print_it = print_it_done;
break;
case WP_VALUE_CHANGED:
if (b->type == bp_read_watchpoint)
{
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
}
++(b->hit_count);
break;
case WP_VALUE_NOT_CHANGED:
++(b->hit_count);
break;
default:
case 0:
printf_filtered ("Watchpoint %d deleted.\n", b->number);
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
bs->print_it = print_it_done;
break;
}
else
{
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
}
}
else
{
++(b->hit_count);
real_breakpoint = 1;
}
if (b->frame &&
b->frame != (get_current_frame ())->frame)
bs->stop = 0;
else
{
int value_is_zero = 0;
if (b->cond_string)
{
select_frame (get_current_frame (), 0);
if (b->cond == NULL)
{
char *s = b->cond_string;
b->cond = parse_exp_1 (&s, get_current_block (NULL), 0);
}
value_is_zero
= catch_errors (breakpoint_cond_eval, (b->cond),
"Error in testing breakpoint condition:\n",
RETURN_MASK_ALL);
free_all_values ();
}
if (b->cond && value_is_zero)
{
bs->stop = 0;
--(b->hit_count);
}
else if (b->ignore_count > 0)
{
b->ignore_count--;
annotate_ignore_count_change ();
bs->stop = 0;
}
else
{
if (b->disposition == disp_disable)
b->enable_state = bp_disabled;
bs->commands = b->commands;
if (b->silent)
bs->print = 0;
if (bs->commands &&
(STREQ ("silent", bs->commands->line) ||
(xdb_commands && STREQ ("Q", bs->commands->line))))
{
bs->commands = bs->commands->next;
bs->print = 0;
}
}
}
if (bs->stop == 0 || bs->print == 0)
bs->print_it = print_it_noop;
}
bs->next = NULL;
bs = root_bs->next;
if (real_breakpoint && bs)
{
if (bs->breakpoint_at->type == bp_hardware_breakpoint)
{
if (DECR_PC_AFTER_HW_BREAK != 0)
{
*pc = *pc - DECR_PC_AFTER_HW_BREAK;
write_pc (*pc);
}
}
else
{
if (DECR_PC_AFTER_BREAK != 0 || must_shift_inst_regs)
{
*pc = bp_addr;
#if defined (SHIFT_INST_REGS)
SHIFT_INST_REGS ();
#else
write_pc (bp_addr);
#endif
}
}
}
if (bs && !bs->stop &&
(bs->breakpoint_at->type == bp_hardware_watchpoint ||
bs->breakpoint_at->type == bp_read_watchpoint ||
bs->breakpoint_at->type == bp_access_watchpoint))
{
remove_breakpoints ();
insert_breakpoints ();
}
return bs;
}
struct bpstat_what
bpstat_what (bpstat bs)
{
enum class
{
no_effect = 0,
wp_silent,
wp_noisy,
bp_nostop,
bp_silent,
bp_noisy,
long_jump,
long_resume,
step_resume,
through_sig,
shlib_event,
catch_shlib_event,
class_last
};
#define kc BPSTAT_WHAT_KEEP_CHECKING
#define ss BPSTAT_WHAT_STOP_SILENT
#define sn BPSTAT_WHAT_STOP_NOISY
#define sgl BPSTAT_WHAT_SINGLE
#define slr BPSTAT_WHAT_SET_LONGJMP_RESUME
#define clr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME
#define clrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE
#define sr BPSTAT_WHAT_STEP_RESUME
#define ts BPSTAT_WHAT_THROUGH_SIGTRAMP
#define shl BPSTAT_WHAT_CHECK_SHLIBS
#define shlr BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK
#define err BPSTAT_WHAT_STOP_NOISY
static const enum bpstat_what_main_action
table[(int) class_last][(int) BPSTAT_WHAT_LAST] =
{
{kc, ss, sn, sgl, slr, clr, clrs, sr, ts, shl, shlr},
{ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
{sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
{sgl, ss, sn, sgl, slr, clrs, clrs, sr, ts, shl, shlr},
{ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
{sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
{slr, ss, sn, slr, slr, err, err, sr, ts, shl, shlr},
{clr, ss, sn, clrs, err, err, err, sr, ts, shl, shlr},
{sr, sr, sr, sr, sr, sr, sr, sr, ts, shl, shlr},
{ts, ts, ts, ts, ts, ts, ts, ts, ts, shl, shlr},
{shl, shl, shl, shl, shl, shl, shl, shl, ts, shl, shlr},
{shlr, shlr, shlr, shlr, shlr, shlr, shlr, shlr, ts, shlr, shlr}
};
#undef kc
#undef ss
#undef sn
#undef sgl
#undef slr
#undef clr
#undef clrs
#undef err
#undef sr
#undef ts
#undef shl
#undef shlr
enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
struct bpstat_what retval;
retval.call_dummy = 0;
for (; bs != NULL; bs = bs->next)
{
enum class bs_class = no_effect;
if (bs->breakpoint_at == NULL)
continue;
switch (bs->breakpoint_at->type)
{
case bp_none:
continue;
case bp_breakpoint:
case bp_hardware_breakpoint:
case bp_until:
case bp_finish:
if (bs->stop)
{
if (bs->print)
bs_class = bp_noisy;
else
bs_class = bp_silent;
}
else
bs_class = bp_nostop;
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
if (bs->stop)
{
if (bs->print)
bs_class = wp_noisy;
else
bs_class = wp_silent;
}
else
bs_class = no_effect;
break;
case bp_longjmp:
bs_class = long_jump;
break;
case bp_longjmp_resume:
bs_class = long_resume;
break;
case bp_step_resume:
if (bs->stop)
{
bs_class = step_resume;
}
else
bs_class = bp_nostop;
break;
case bp_through_sigtramp:
bs_class = through_sig;
break;
case bp_watchpoint_scope:
bs_class = bp_nostop;
break;
case bp_shlib_event:
bs_class = shlib_event;
break;
case bp_thread_event:
case bp_overlay_event:
bs_class = bp_nostop;
break;
case bp_catch_load:
case bp_catch_unload:
if (bs->stop)
bs_class = catch_shlib_event;
else
bs_class = no_effect;
break;
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
if (bs->stop)
{
if (bs->print)
bs_class = bp_noisy;
else
bs_class = bp_silent;
}
else
bs_class = no_effect;
break;
case bp_catch_catch:
if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_CATCH)
bs_class = bp_nostop;
else if (bs->stop)
bs_class = bs->print ? bp_noisy : bp_silent;
break;
case bp_catch_throw:
if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_THROW)
bs_class = bp_nostop;
else if (bs->stop)
bs_class = bs->print ? bp_noisy : bp_silent;
break;
case bp_call_dummy:
bs_class = bp_silent;
retval.call_dummy = 1;
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
break;
}
current_action = table[(int) bs_class][(int) current_action];
}
retval.main_action = current_action;
return retval;
}
int
bpstat_should_step (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->enable_state == bp_enabled && b->type == bp_watchpoint)
return 1;
return 0;
}
int
bpstat_have_active_hw_watchpoints (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if ((b->enable_state == bp_enabled) &&
(b->inserted) &&
((b->type == bp_hardware_watchpoint) ||
(b->type == bp_read_watchpoint) ||
(b->type == bp_access_watchpoint)))
return 1;
return 0;
}
void
bpstat_get_triggered_catchpoints (bpstat ep_list, bpstat *cp_list)
{
struct bpstats root_bs[1];
bpstat bs = root_bs;
struct breakpoint *ep;
char *dll_pathname;
bpstat_clear (cp_list);
root_bs->next = NULL;
for (; ep_list != NULL; ep_list = ep_list->next)
{
ep = ep_list->breakpoint_at;
if (ep == NULL)
break;
if ((ep->type != bp_catch_load) &&
(ep->type != bp_catch_unload) &&
(ep->type != bp_catch_catch) &&
(ep->type != bp_catch_throw))
continue;
bs = bpstat_alloc (ep, bs);
*bs = *ep_list;
bs->next = NULL;
bs = root_bs->next;
#if defined(SOLIB_ADD)
if (ep->triggered_dll_pathname != NULL)
xfree (ep->triggered_dll_pathname);
if (ep->type == bp_catch_load)
dll_pathname = SOLIB_LOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid));
else
dll_pathname = SOLIB_UNLOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid));
#else
dll_pathname = NULL;
#endif
if (dll_pathname)
{
ep->triggered_dll_pathname = (char *)
xmalloc (strlen (dll_pathname) + 1);
strcpy (ep->triggered_dll_pathname, dll_pathname);
}
else
ep->triggered_dll_pathname = NULL;
}
*cp_list = bs;
}
static void
print_one_breakpoint (struct breakpoint *b,
CORE_ADDR *last_addr)
{
register struct command_line *l;
register struct symbol *sym;
struct ep_type_description
{
enum bptype type;
char *description;
};
static struct ep_type_description bptypes[] =
{
{bp_none, "?deleted?"},
{bp_breakpoint, "breakpoint"},
{bp_hardware_breakpoint, "hw breakpoint"},
{bp_until, "until"},
{bp_finish, "finish"},
{bp_watchpoint, "watchpoint"},
{bp_hardware_watchpoint, "hw watchpoint"},
{bp_read_watchpoint, "read watchpoint"},
{bp_access_watchpoint, "acc watchpoint"},
{bp_longjmp, "longjmp"},
{bp_longjmp_resume, "longjmp resume"},
{bp_step_resume, "step resume"},
{bp_through_sigtramp, "sigtramp"},
{bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"},
{bp_shlib_event, "shlib events"},
{bp_thread_event, "thread events"},
{bp_overlay_event, "overlay events"},
{bp_catch_load, "catch load"},
{bp_catch_unload, "catch unload"},
{bp_catch_fork, "catch fork"},
{bp_catch_vfork, "catch vfork"},
{bp_catch_exec, "catch exec"},
{bp_catch_catch, "catch catch"},
{bp_catch_throw, "catch throw"}
};
static char *bpdisps[] =
{"del", "dstp", "dis", "keep"};
static char bpenables[] = "nyscp";
char wrap_indent[80];
struct ui_stream *stb = ui_out_stream_new (uiout);
struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
annotate_record ();
ui_out_tuple_begin (uiout, "bkpt");
annotate_field (0);
ui_out_field_int (uiout, "number", b->number);
annotate_field (1);
if (((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
|| ((int) b->type != bptypes[(int) b->type].type))
internal_error (__FILE__, __LINE__,
"bptypes table does not describe type #%d.",
(int) b->type);
ui_out_field_string (uiout, "type", bptypes[(int) b->type].description);
annotate_field (2);
ui_out_field_string (uiout, "disp", bpdisps[(int) b->disposition]);
annotate_field (3);
ui_out_field_fmt (uiout, "enabled", "%c", bpenables[(int) b->enable_state]);
ui_out_spaces (uiout, 2);
strcpy (wrap_indent, " ");
if (addressprint)
{
if (TARGET_ADDR_BIT <= 32)
strcat (wrap_indent, " ");
else
strcat (wrap_indent, " ");
}
switch (b->type)
{
case bp_none:
internal_error (__FILE__, __LINE__,
"print_one_breakpoint: bp_none encountered\n");
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "what", stb);
break;
case bp_catch_load:
case bp_catch_unload:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
if (b->dll_pathname == NULL)
{
ui_out_field_string (uiout, "what", "<any library>");
ui_out_spaces (uiout, 1);
}
else
{
ui_out_text (uiout, "library \"");
ui_out_field_string (uiout, "what", b->dll_pathname);
ui_out_text (uiout, "\" ");
}
break;
case bp_catch_fork:
case bp_catch_vfork:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
if (b->forked_inferior_pid != 0)
{
ui_out_text (uiout, "process ");
ui_out_field_int (uiout, "what", b->forked_inferior_pid);
ui_out_spaces (uiout, 1);
}
case bp_catch_exec:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
if (b->exec_pathname != NULL)
{
ui_out_text (uiout, "program \"");
ui_out_field_string (uiout, "what", b->exec_pathname);
ui_out_text (uiout, "\" ");
}
break;
case bp_catch_catch:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
ui_out_field_string (uiout, "what", "exception catch");
ui_out_spaces (uiout, 1);
break;
case bp_catch_throw:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
ui_out_field_string (uiout, "what", "exception throw");
ui_out_spaces (uiout, 1);
break;
case bp_breakpoint:
case bp_hardware_breakpoint:
case bp_until:
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
if (addressprint)
{
annotate_field (4);
ui_out_field_core_addr (uiout, "addr", b->address);
}
annotate_field (5);
*last_addr = b->address;
if (b->source_file)
{
sym = find_pc_sect_function (b->address, b->section);
if (sym)
{
ui_out_text (uiout, "in ");
ui_out_field_string (uiout, "func",
SYMBOL_SOURCE_NAME (sym));
ui_out_wrap_hint (uiout, wrap_indent);
ui_out_text (uiout, " at ");
}
ui_out_field_string (uiout, "file", b->source_file);
ui_out_text (uiout, ":");
ui_out_field_int (uiout, "line", b->line_number);
}
else if (b->address != 0)
{
print_address_symbolic (b->address, stb->stream, demangle, "");
ui_out_field_stream (uiout, "at", stb);
}
else
{
ui_out_field_string (uiout, "future-address", b->addr_string);
}
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
break;
}
if (b->thread != -1)
{
ui_out_text (uiout, " thread ");
ui_out_field_int (uiout, "thread", b->thread);
}
ui_out_text (uiout, "\n");
if (b->frame)
{
annotate_field (6);
if (annotation_level < 2)
printf_filtered ("\tstop only in stack frame at ");
ui_out_text (uiout, "\tstop only in stack frame at ");
ui_out_field_core_addr (uiout, "frame", b->frame);
ui_out_text (uiout, "\n");
}
if (b->cond)
{
annotate_field (7);
ui_out_text (uiout, "\tstop only if ");
print_expression (b->cond, stb->stream);
ui_out_field_stream (uiout, "cond", stb);
ui_out_text (uiout, "\n");
}
if (b->thread != -1)
{
char buf[64];
sprintf (buf, "\tstop only in thread %d\n", b->thread);
ui_out_text (uiout, buf);
}
if (show_breakpoint_hit_counts && b->hit_count)
{
if (ep_is_catchpoint (b))
ui_out_text (uiout, "\tcatchpoint");
else
ui_out_text (uiout, "\tbreakpoint");
ui_out_text (uiout, " already hit ");
ui_out_field_int (uiout, "times", b->hit_count);
if (b->hit_count == 1)
ui_out_text (uiout, " time\n");
else
ui_out_text (uiout, " times\n");
}
if (ui_out_is_mi_like_p (uiout))
if (show_breakpoint_hit_counts && b->hit_count == 0)
ui_out_field_int (uiout, "times", b->hit_count);
if (b->ignore_count)
{
annotate_field (8);
ui_out_text (uiout, "\tignore next ");
ui_out_field_int (uiout, "ignore", b->ignore_count);
ui_out_text (uiout, " hits\n");
}
if ((l = b->commands))
{
annotate_field (9);
ui_out_tuple_begin (uiout, "commands");
print_command_lines (uiout, l, 4);
ui_out_tuple_end (uiout);
}
ui_out_tuple_end (uiout);
do_cleanups (old_chain);
}
struct captured_breakpoint_query_args
{
int bnum;
};
static int
do_captured_breakpoint_query (struct ui_out *uiout, void *data)
{
struct captured_breakpoint_query_args *args = data;
register struct breakpoint *b;
CORE_ADDR dummy_addr = 0;
ALL_BREAKPOINTS (b)
{
if (args->bnum == b->number)
{
print_one_breakpoint (b, &dummy_addr);
return GDB_RC_OK;
}
}
return GDB_RC_NONE;
}
enum gdb_rc
gdb_breakpoint_query (struct ui_out *uiout, int bnum)
{
struct captured_breakpoint_query_args args;
args.bnum = bnum;
return catch_exceptions (uiout, do_captured_breakpoint_query, &args,
NULL, RETURN_MASK_ALL);
}
static int
user_settable_breakpoint (const struct breakpoint *b)
{
return (b->type == bp_breakpoint
|| b->type == bp_catch_load
|| b->type == bp_catch_unload
|| b->type == bp_catch_fork
|| b->type == bp_catch_vfork
|| b->type == bp_catch_exec
|| b->type == bp_catch_catch
|| b->type == bp_catch_throw
|| b->type == bp_hardware_breakpoint
|| b->type == bp_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint
|| b->type == bp_hardware_watchpoint);
}
static void
breakpoint_1 (int bnum, int allflag)
{
register struct breakpoint *b;
CORE_ADDR last_addr = (CORE_ADDR) -1;
int nr_printable_breakpoints;
nr_printable_breakpoints = 0;
ALL_BREAKPOINTS (b)
if (bnum == -1
|| bnum == b->number)
{
if (allflag || user_settable_breakpoint (b))
nr_printable_breakpoints++;
}
if (addressprint)
ui_out_table_begin (uiout, 10, nr_printable_breakpoints, "BreakpointTable");
else
ui_out_table_begin (uiout, 9, nr_printable_breakpoints, "BreakpointTable");
if (nr_printable_breakpoints > 0)
annotate_breakpoints_headers ();
if (nr_printable_breakpoints > 0)
annotate_field (0);
ui_out_table_header (uiout, 6, ui_left, "number", "Number");
if (nr_printable_breakpoints > 0)
annotate_field (1);
ui_out_table_header (uiout, 14, ui_left, "type", "Type");
if (nr_printable_breakpoints > 0)
annotate_field (2);
ui_out_table_header (uiout, 11, ui_left, "disp", "Disposition");
if (nr_printable_breakpoints > 0)
annotate_field (3);
ui_out_table_header (uiout, 7, ui_left, "enabled", "Enabled");
if (addressprint)
{
if (nr_printable_breakpoints > 0)
annotate_field (4);
if (TARGET_ADDR_BIT <= 32)
ui_out_table_header (uiout, 10, ui_left, "addr", "Address");
else
ui_out_table_header (uiout, 18, ui_left, "addr", "Address");
}
if (nr_printable_breakpoints > 0)
annotate_field (5);
ui_out_table_header (uiout, 40, ui_noalign, "what", "What");
if (nr_printable_breakpoints > 0)
annotate_field (6);
ui_out_table_header (uiout, 10, ui_left, "stackframe", "StackFrame");
if (nr_printable_breakpoints > 0)
annotate_field (7);
ui_out_table_header (uiout, 9, ui_left, "condition", "Condition");
if (nr_printable_breakpoints > 0)
annotate_field (8);
ui_out_table_header (uiout, 11, ui_left, "ignorecount", "IgnoreCount");
if (nr_printable_breakpoints > 0)
annotate_field (9);
ui_out_table_header (uiout, 8, ui_left, "commands", "Commands");
ui_out_table_body (uiout);
if (nr_printable_breakpoints > 0)
annotate_breakpoints_table ();
ALL_BREAKPOINTS (b)
if (bnum == -1
|| bnum == b->number)
{
if (allflag || user_settable_breakpoint (b))
print_one_breakpoint (b, &last_addr);
}
ui_out_table_end (uiout);
if (nr_printable_breakpoints == 0)
{
if (bnum == -1)
ui_out_message (uiout, 0, "No breakpoints or watchpoints.\n");
else
ui_out_message (uiout, 0, "No breakpoint or watchpoint number %d.\n",
bnum);
}
else
{
if (last_addr != (CORE_ADDR) -1)
set_next_address (last_addr);
}
annotate_breakpoints_table_end ();
}
static void
breakpoints_info (char *bnum_exp, int from_tty)
{
int bnum = -1;
if (bnum_exp)
bnum = parse_and_eval_long (bnum_exp);
breakpoint_1 (bnum, 0);
}
static void
maintenance_info_breakpoints (char *bnum_exp, int from_tty)
{
int bnum = -1;
if (bnum_exp)
bnum = parse_and_eval_long (bnum_exp);
breakpoint_1 (bnum, 1);
}
static void
describe_other_breakpoints (CORE_ADDR pc, asection *section)
{
register int others = 0;
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->address == pc)
if (!overlay_debugging || b->section == section)
others++;
if (others > 0)
{
printf_filtered ("Note: breakpoint%s ", (others > 1) ? "s" : "");
ALL_BREAKPOINTS (b)
if (b->address == pc)
if (!overlay_debugging || b->section == section)
{
others--;
printf_filtered ("%d%s%s ",
b->number,
((b->enable_state == bp_disabled ||
b->enable_state == bp_shlib_disabled ||
b->enable_state == bp_call_disabled)
? " (disabled)"
: b->enable_state == bp_permanent
? " (permanent)"
: ""),
(others > 1) ? ","
: ((others == 1) ? " and" : ""));
}
printf_filtered ("also set at pc ");
print_address_numeric (pc, 1, gdb_stdout);
printf_filtered (".\n");
}
}
void
set_default_breakpoint (int valid, CORE_ADDR addr, struct symtab *symtab,
int line)
{
default_breakpoint_valid = valid;
default_breakpoint_address = addr;
default_breakpoint_symtab = symtab;
default_breakpoint_line = line;
}
static int
breakpoint_address_is_meaningful (struct breakpoint *bpt)
{
enum bptype type = bpt->type;
return (type != bp_watchpoint
&& type != bp_hardware_watchpoint
&& type != bp_read_watchpoint
&& type != bp_access_watchpoint
&& type != bp_catch_exec
&& type != bp_longjmp_resume
&& type != bp_catch_fork
&& type != bp_catch_vfork);
}
static void
check_duplicates (struct breakpoint *bpt)
{
register struct breakpoint *b;
register int count = 0;
struct breakpoint *perm_bp = 0;
CORE_ADDR address = bpt->address;
asection *section = bpt->section;
if (! breakpoint_address_is_meaningful (bpt))
return;
ALL_BREAKPOINTS (b)
if (b->enable_state != bp_disabled
&& b->enable_state != bp_shlib_disabled
&& b->enable_state != bp_call_disabled
&& b->address == address
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b))
{
if (b->enable_state == bp_permanent)
{
perm_bp = b;
break;
}
count++;
b->duplicate = count > 1;
}
if (perm_bp)
{
perm_bp->duplicate = 0;
if (! perm_bp->inserted)
internal_error (__FILE__, __LINE__,
"allegedly permanent breakpoint is not "
"actually inserted");
ALL_BREAKPOINTS (b)
if (b != perm_bp)
{
if (b->inserted)
internal_error (__FILE__, __LINE__,
"another breakpoint was inserted on top of "
"a permanent breakpoint");
if (b->enable_state != bp_disabled
&& b->enable_state != bp_shlib_disabled
&& b->enable_state != bp_call_disabled
&& b->address == address
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b))
b->duplicate = 1;
}
}
}
struct breakpoint *
set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
{
register struct breakpoint *b, *b1;
b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
memset (b, 0, sizeof (*b));
b->address = sal.pc;
if (sal.symtab == NULL)
b->source_file = NULL;
else
b->source_file = savestring (sal.symtab->filename,
strlen (sal.symtab->filename));
b->section = sal.section;
b->type = bptype;
b->language = current_language->la_language;
b->input_radix = input_radix;
b->thread = -1;
b->line_number = sal.line;
b->enable_state = bp_enabled;
b->next = 0;
b->silent = 0;
b->ignore_count = 0;
b->commands = NULL;
b->frame = 0;
b->dll_pathname = NULL;
b->triggered_dll_pathname = NULL;
b->forked_inferior_pid = 0;
b->exec_pathname = NULL;
b1 = breakpoint_chain;
if (b1 == 0)
breakpoint_chain = b;
else
{
while (b1->next)
b1 = b1->next;
b1->next = b;
}
check_duplicates (b);
breakpoints_changed ();
return b;
}
void
make_breakpoint_permanent (struct breakpoint *b)
{
b->enable_state = bp_permanent;
b->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);
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)
{
struct breakpoint *b;
struct minimal_symbol *m;
if (func_name == NULL)
b = create_internal_breakpoint (0, bp_longjmp_resume);
else
{
if ((m = lookup_minimal_symbol_text (func_name, NULL, NULL)) == NULL)
return;
b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
}
b->enable_state = bp_disabled;
b->silent = 1;
if (func_name)
b->addr_string = xstrdup (func_name);
}
void
enable_longjmp_breakpoint (void)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp)
{
b->enable_state = bp_enabled;
check_duplicates (b);
}
}
void
disable_longjmp_breakpoint (void)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp
|| b->type == bp_longjmp_resume)
{
b->enable_state = bp_disabled;
check_duplicates (b);
}
}
static void
create_overlay_event_breakpoint (char *func_name)
{
struct breakpoint *b;
struct minimal_symbol *m;
if ((m = lookup_minimal_symbol_text (func_name, NULL, NULL)) == 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;
}
}
void
enable_overlay_breakpoints (void)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_overlay_event)
{
b->enable_state = bp_enabled;
check_duplicates (b);
overlay_events_enabled = 1;
}
}
void
disable_overlay_breakpoints (void)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_overlay_event)
{
b->enable_state = bp_disabled;
check_duplicates (b);
overlay_events_enabled = 0;
}
}
struct breakpoint *
create_thread_event_breakpoint (CORE_ADDR address)
{
struct breakpoint *b;
char addr_string[80];
b = create_internal_breakpoint (address, bp_thread_event);
b->enable_state = bp_enabled;
sprintf (addr_string, "*0x%s", paddr (b->address));
b->addr_string = xstrdup (addr_string);
return b;
}
void
remove_thread_event_breakpoints (void)
{
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
if (b->type == bp_thread_event)
delete_breakpoint (b);
}
#ifdef SOLIB_ADD
void
remove_solib_event_breakpoints (void)
{
register struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
if (b->type == bp_shlib_event)
delete_breakpoint (b);
}
struct breakpoint *
create_solib_event_breakpoint (CORE_ADDR address)
{
struct breakpoint *b;
b = create_internal_breakpoint (address, bp_shlib_event);
return b;
}
void
disable_breakpoints_in_shlibs (int silent)
{
struct breakpoint *b;
int disabled_shlib_breaks = 0;
ALL_BREAKPOINTS (b)
{
#if defined (PC_SOLIB)
int disable = 0;
char buf[1];
if (((b->type == bp_breakpoint) ||
(b->type == bp_hardware_breakpoint)) &&
b->enable_state == bp_enabled &&
!b->duplicate &&
PC_SOLIB (b->address))
{
b->enable_state = bp_shlib_disabled;
if (!silent)
{
if (!disabled_shlib_breaks)
{
target_terminal_ours_for_output ();
printf_filtered ("Disabling shared library breakpoints:");
}
disabled_shlib_breaks = 1;
printf_filtered (" %d", b->number);
}
}
#endif
}
if (!silent && disabled_shlib_breaks)
printf_filtered ("\n");
}
void
re_enable_breakpoints_in_shlibs (int silent)
{
struct breakpoint *b;
int enabled_shlib_breaks = 0;
ALL_BREAKPOINTS (b)
if (b->enable_state == bp_shlib_disabled)
{
char buf[1];
if (target_read_memory (b->address, buf, 1) == 0)
{
b->enable_state = bp_enabled;
if (!silent)
{
if (!enabled_shlib_breaks)
{
target_terminal_ours_for_output ();
printf_filtered ("Re-enabling shared library breakpoints:");
}
enabled_shlib_breaks = 1;
printf_filtered (" %d", b->number);
}
}
}
if (!silent && enabled_shlib_breaks)
printf_filtered ("\n");
}
#endif
static void
solib_load_unload_1 (char *hookname, int tempflag, char *dll_pathname,
char *cond_string, enum bptype bp_kind)
{
struct breakpoint *b;
struct symtabs_and_lines sals;
struct cleanup *old_chain;
struct cleanup *canonical_strings_chain = NULL;
char *addr_start = hookname;
char *addr_end = NULL;
char **canonical = (char **) NULL;
int thread = -1;
sals = decode_line_1 (&hookname, 1, (struct symtab *) NULL, 0, &canonical);
addr_end = hookname;
if (sals.nelts == 0)
{
warning ("Unable to set a breakpoint on dynamic linker callback.");
warning ("Suggest linking with /opt/langtools/lib/end.o.");
warning ("GDB will be unable to track shl_load/shl_unload calls");
return;
}
if (sals.nelts != 1)
{
warning ("Unable to set unique breakpoint on dynamic linker callback.");
warning ("GDB will be unable to track shl_load/shl_unload calls");
return;
}
old_chain = make_cleanup (xfree, sals.sals);
if (canonical != (char **) NULL)
{
make_cleanup (xfree, canonical);
canonical_strings_chain = make_cleanup (null_cleanup, 0);
if (canonical[0] != NULL)
make_cleanup (xfree, canonical[0]);
}
resolve_sal_pc (&sals.sals[0]);
if (canonical != (char **) NULL)
discard_cleanups (canonical_strings_chain);
b = set_raw_breakpoint (sals.sals[0], bp_kind);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = thread;
if (canonical != (char **) NULL && canonical[0] != NULL)
b->addr_string = canonical[0];
else if (addr_start)
b->addr_string = savestring (addr_start, addr_end - addr_start);
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
if (dll_pathname == NULL)
b->dll_pathname = NULL;
else
{
b->dll_pathname = (char *) xmalloc (strlen (dll_pathname) + 1);
strcpy (b->dll_pathname, dll_pathname);
}
mention (b);
do_cleanups (old_chain);
}
void
create_solib_load_event_breakpoint (char *hookname, int tempflag,
char *dll_pathname, char *cond_string)
{
solib_load_unload_1 (hookname, tempflag, dll_pathname,
cond_string, bp_catch_load);
}
void
create_solib_unload_event_breakpoint (char *hookname, int tempflag,
char *dll_pathname, char *cond_string)
{
solib_load_unload_1 (hookname,tempflag, dll_pathname,
cond_string, bp_catch_unload);
}
static void
create_fork_vfork_event_catchpoint (int tempflag, char *cond_string,
enum bptype bp_kind)
{
struct symtab_and_line sal;
struct breakpoint *b;
int thread = -1;
INIT_SAL (&sal);
sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
b = set_raw_breakpoint (sal, bp_kind);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = thread;
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->forked_inferior_pid = 0;
mention (b);
}
void
create_fork_event_catchpoint (int tempflag, char *cond_string)
{
create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_fork);
}
void
create_vfork_event_catchpoint (int tempflag, char *cond_string)
{
create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_vfork);
}
void
create_exec_event_catchpoint (int tempflag, char *cond_string)
{
struct symtab_and_line sal;
struct breakpoint *b;
int thread = -1;
INIT_SAL (&sal);
sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
b = set_raw_breakpoint (sal, bp_catch_exec);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = thread;
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
mention (b);
}
static int
hw_breakpoint_used_count (void)
{
register struct breakpoint *b;
int i = 0;
ALL_BREAKPOINTS (b)
{
if (b->type == bp_hardware_breakpoint && b->enable_state == bp_enabled)
i++;
}
return i;
}
static int
hw_watchpoint_used_count (enum bptype type, int *other_type_used)
{
register struct breakpoint *b;
int i = 0;
*other_type_used = 0;
ALL_BREAKPOINTS (b)
{
if (b->enable_state == bp_enabled)
{
if (b->type == type)
i++;
else if ((b->type == bp_hardware_watchpoint ||
b->type == bp_read_watchpoint ||
b->type == bp_access_watchpoint)
&& b->enable_state == bp_enabled)
*other_type_used = 1;
}
}
return i;
}
void
set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_info *frame)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp_resume)
{
b->address = pc;
b->enable_state = bp_enabled;
if (frame != NULL)
b->frame = frame->frame;
else
b->frame = 0;
check_duplicates (b);
return;
}
}
void
disable_watchpoints_before_interactive_call_start (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
{
if (((b->type == bp_watchpoint)
|| (b->type == bp_hardware_watchpoint)
|| (b->type == bp_read_watchpoint)
|| (b->type == bp_access_watchpoint)
|| ep_is_exception_catchpoint (b))
&& (b->enable_state == bp_enabled))
{
b->enable_state = bp_call_disabled;
check_duplicates (b);
}
}
}
void
enable_watchpoints_after_interactive_call_stop (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
{
if (((b->type == bp_watchpoint)
|| (b->type == bp_hardware_watchpoint)
|| (b->type == bp_read_watchpoint)
|| (b->type == bp_access_watchpoint)
|| ep_is_exception_catchpoint (b))
&& (b->enable_state == bp_call_disabled))
{
b->enable_state = bp_enabled;
check_duplicates (b);
}
}
}
struct breakpoint *
set_momentary_breakpoint (struct symtab_and_line sal, struct frame_info *frame,
enum bptype type)
{
register struct breakpoint *b;
b = set_raw_breakpoint (sal, type);
b->enable_state = bp_enabled;
b->disposition = disp_donttouch;
b->frame = (frame ? frame->frame : 0);
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
return b;
}
static void
mention (struct breakpoint *b)
{
int say_where = 0;
struct cleanup *old_chain;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
if (create_breakpoint_hook)
create_breakpoint_hook (b);
breakpoint_create_event (b->number);
if (dont_mention)
return;
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_tuple_begin (uiout, "wpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
ui_out_tuple_end (uiout);
break;
case bp_hardware_watchpoint:
ui_out_text (uiout, "Hardware watchpoint ");
ui_out_tuple_begin (uiout, "wpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
ui_out_tuple_end (uiout);
break;
case bp_read_watchpoint:
ui_out_text (uiout, "Hardware read watchpoint ");
ui_out_tuple_begin (uiout, "hw-rwpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
ui_out_tuple_end (uiout);
break;
case bp_access_watchpoint:
ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
ui_out_tuple_begin (uiout, "hw-awpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
ui_out_tuple_end (uiout);
break;
case bp_breakpoint:
if (ui_out_is_mi_like_p (uiout))
{
say_where = 0;
break;
}
printf_filtered ("Breakpoint %d", b->number);
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_catch_load:
case bp_catch_unload:
printf_filtered ("Catchpoint %d (%s %s)",
b->number,
(b->type == bp_catch_load) ? "load" : "unload",
(b->dll_pathname != NULL) ?
b->dll_pathname : "<any library>");
break;
case bp_catch_fork:
case bp_catch_vfork:
printf_filtered ("Catchpoint %d (%s)",
b->number,
(b->type == bp_catch_fork) ? "fork" : "vfork");
break;
case bp_catch_exec:
printf_filtered ("Catchpoint %d (exec)",
b->number);
break;
case bp_catch_catch:
case bp_catch_throw:
printf_filtered ("Catchpoint %d (%s)",
b->number,
(b->type == bp_catch_catch) ? "catch" : "throw");
break;
case bp_until:
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_call_dummy:
case bp_watchpoint_scope:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
break;
}
if (say_where)
{
if (addressprint || b->source_file == NULL)
{
printf_filtered (" at ");
print_address_numeric (b->address, 1, gdb_stdout);
}
if (b->source_file)
printf_filtered (": file %s, line %d.",
b->source_file, b->line_number);
}
do_cleanups (old_chain);
if (ui_out_is_mi_like_p (uiout))
return;
printf_filtered ("\n");
}
static void
create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
struct expression **cond, char **cond_string,
enum bptype type, enum bpdisp disposition,
int origflags, int thread, int ignore_count, int from_tty)
{
if (type == bp_hardware_breakpoint)
{
int i = hw_breakpoint_used_count ();
int target_resources_ok =
TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint,
i + sals.nelts, 0);
if (target_resources_ok == 0)
error ("No hardware breakpoint support in the target.");
else if (target_resources_ok < 0)
error ("Hardware breakpoints used exceeds limit.");
}
{
int i;
for (i = 0; i < sals.nelts; i++)
{
struct breakpoint *b;
struct symtab_and_line sal = sals.sals[i];
if (from_tty)
describe_other_breakpoints (sal.pc, sal.section);
b = set_raw_breakpoint (sal, type);
b->original_flags = origflags;
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = cond[i];
b->thread = thread;
b->addr_string = addr_string[i];
b->cond_string = cond_string[i];
b->ignore_count = ignore_count;
b->enable_state = bp_enabled;
b->disposition = disposition;
mention (b);
}
}
}
void
parse_breakpoint_sals (char **address,
struct symtabs_and_lines *sals,
char ***addr_string)
{
char *addr_start = *address;
*addr_string = NULL;
if ((*address) == NULL
|| (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
{
if (default_breakpoint_valid)
{
struct symtab_and_line sal;
char *s;
INIT_SAL (&sal);
sals->sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
sal.pc = default_breakpoint_address;
sal.line = default_breakpoint_line;
sal.symtab = default_breakpoint_symtab;
sal.section = find_pc_overlay (sal.pc);
sals->sals[0] = sal;
sals->nelts = 1;
s = paddr_u (sal.pc);
*addr_string = (char **) xmalloc (sizeof (char **));
**addr_string = (char *) xmalloc (strlen (s) + 2);
sprintf (**addr_string, "*%s", s);
}
else
error ("No default breakpoint address now.");
}
else
{
if (default_breakpoint_valid
&& (!current_source_symtab
|| ((strchr ("+-", (*address)[0]) != NULL)
&& ((*address)[1] != '['))))
*sals = decode_line_1 (address, 1, default_breakpoint_symtab,
default_breakpoint_line, addr_string);
else
*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0, addr_string);
}
if (sals->nelts > 0 && *addr_string == NULL)
*addr_string = xcalloc (sals->nelts, sizeof (char **));
if (addr_start != (*address))
{
int i;
for (i = 0; i < sals->nelts; i++)
{
if ((*addr_string)[i] == NULL)
(*addr_string)[i] = savestring (addr_start, (*address) - addr_start);
}
}
}
void
breakpoint_sals_to_pc (struct symtabs_and_lines *sals,
char *address)
{
int i;
for (i = 0; i < sals->nelts; i++)
{
resolve_sal_pc (&sals->sals[i]);
if (PC_REQUIRES_RUN_BEFORE_USE (sals->sals[i].pc))
{
if (address == NULL)
error ("Cannot break without a running program.");
else
error ("Cannot break on %s without a running program.",
address);
}
}
}
struct captured_breakpoint_args
{
char *address;
char *condition;
int hardwareflag;
int tempflag;
int futureflag;
int thread;
int ignore_count;
int from_tty;
};
static void
break_command_1 (char *arg, int flags, int from_tty)
{
struct captured_breakpoint_args args;
args.address = arg;
args.condition = NULL;
args.hardwareflag = flags & BP_HARDWAREFLAG;
args.tempflag = flags & BP_TEMPFLAG;
args.futureflag = flags & BP_FUTUREFLAG;
args.thread = -1;
args.ignore_count = 0;
args.from_tty = from_tty;
if (args.futureflag)
{
if (args.tempflag)
error ("Future breakpoints may not be specified as temporary.");
if (args.hardwareflag)
error ("Future breakpoints may not be specified as hardware.");
}
if (args.futureflag)
{
enum gdb_rc ret = catch_errors
(do_captured_breakpoint, &args, NULL, RETURN_MASK_ALL);
if (ret != GDB_RC_OK)
{
struct symtab_and_line sal =
{0, 0};
struct breakpoint *b = set_raw_breakpoint (sal, bp_breakpoint);
printf_unfiltered
("Will attempt to resolve \"%s\" on future dynamic loads.\n", args.address);
b->number = ++breakpoint_count;
b->addr_string = savestring (args.address, strlen (args.address));
b->enable_state = bp_shlib_disabled;
b->inserted = 0;
b->disposition = disp_donttouch;
if (modify_breakpoint_hook)
modify_breakpoint_hook (b);
}
}
else
{
do_captured_breakpoint (&args);
}
}
struct captured_parse_breakpoint_sals_args
{
char **address;
struct symtabs_and_lines *sals;
char ***addr_string;
};
static int
captured_parse_breakpoint_sals (void *data)
{
struct captured_parse_breakpoint_sals_args *args
= (struct captured_parse_breakpoint_sals_args *) data;
parse_breakpoint_sals (args->address, args->sals, args->addr_string);
return (int) GDB_RC_OK;
}
static int
do_captured_breakpoint (void *data)
{
struct captured_breakpoint_args *args = data;
struct symtabs_and_lines sals;
register struct expression **cond;
struct cleanup *old_chain;
struct cleanup *breakpoint_chain = NULL;
int i;
char **addr_string;
char **cond_string;
char *address_end;
int orig_flags;
int rc = GDB_RC_OK;
orig_flags =
(args->hardwareflag ? BP_HARDWAREFLAG : 0)
| (args->tempflag ? BP_TEMPFLAG : 0)
| (args->futureflag ? BP_FUTUREFLAG : 0);
sals.sals = NULL;
sals.nelts = 0;
address_end = args->address;
addr_string = NULL;
if (args->futureflag)
{
struct captured_parse_breakpoint_sals_args parse_args;
parse_args.address = &address_end;
parse_args.sals = &sals;
parse_args.addr_string = &addr_string;
rc = catch_errors (captured_parse_breakpoint_sals, &parse_args,
NULL, RETURN_MASK_ALL);
}
else
{
parse_breakpoint_sals (&address_end, &sals, &addr_string);
}
if (args->futureflag && rc != GDB_RC_OK)
{
if (args->futureflag)
{
struct symtab_and_line sal = {0, 0};
struct breakpoint *b = set_raw_breakpoint (sal, bp_breakpoint);
b->number = ++breakpoint_count;
b->addr_string = savestring (args->address, strlen (args->address));
b->enable_state = bp_shlib_disabled;
b->inserted = 0;
b->ignore_count = args->ignore_count;
b->disposition = args->tempflag ? disp_del : disp_donttouch;
if (args->condition != NULL)
{
b->cond_string = savestring (args->condition,
strlen (args->condition));
}
b->thread = args->thread;
mention (b);
return GDB_RC_OK;
}
else
return GDB_RC_NONE;
}
else if (!sals.nelts)
return GDB_RC_NONE;
old_chain = make_cleanup (null_cleanup, 0);
make_cleanup (xfree, addr_string);
make_cleanup (xfree, sals.sals);
cond = xcalloc (sals.nelts, sizeof (struct expression *));
make_cleanup (xfree, cond);
cond_string = xcalloc (sals.nelts, sizeof (char **));
make_cleanup (xfree, cond_string);
breakpoint_chain = make_cleanup (null_cleanup, 0);
for (i = 0; i < sals.nelts; i++)
{
if (addr_string[i] != NULL)
make_cleanup (xfree, addr_string[i]);
}
{
char *tok = address_end;
while (tok && *tok)
{
char *end_tok;
int toklen;
char *cond_start = NULL;
char *cond_end = NULL;
while (*tok == ' ' || *tok == '\t')
tok++;
end_tok = tok;
while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
end_tok++;
toklen = end_tok - tok;
if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
{
tok = cond_start = end_tok + 1;
cond_end = cond_start;
while (*cond_end != '\000')
cond_end++;
args->condition = tok;
tok = cond_end;
}
else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
{
char *tmptok;
tok = end_tok + 1;
tmptok = tok;
args->thread = strtol (tok, &tok, 0);
if (tok == tmptok)
error ("Junk after thread keyword.");
if (! valid_thread_id (args->thread))
error ("Unknown thread %d\n", args->thread);
}
else
error ("Junk at end of arguments.");
}
}
breakpoint_sals_to_pc (&sals, args->address);
for (i = 0; i < sals.nelts; i++)
{
if (args->condition != NULL)
{
char *tok = args->condition;
cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
if (*tok != '\0')
error ("Garbage %s follows condition", tok);
make_cleanup (xfree, cond[i]);
cond_string[i] = xstrdup (args->condition);
}
}
create_breakpoints (sals, addr_string, cond, cond_string,
args->hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
args->tempflag ? disp_del : disp_donttouch, orig_flags,
args->thread, args->ignore_count, args->from_tty);
if (args->from_tty && (sals.nelts > 1))
{
warning ("Multiple breakpoints were set.");
warning ("Use the \"delete\" command to delete unwanted breakpoints.");
}
discard_cleanups (breakpoint_chain);
do_cleanups (old_chain);
return GDB_RC_OK;
}
enum gdb_rc
gdb_breakpoint (char *address, char *condition,
int hardwareflag, int tempflag, int futureflag,
int thread, int ignore_count)
{
struct captured_breakpoint_args args;
args.address = address;
args.condition = condition;
args.hardwareflag = hardwareflag;
args.tempflag = tempflag;
args.futureflag = futureflag;
args.thread = thread;
args.ignore_count = ignore_count;
return catch_errors (do_captured_breakpoint, &args,
NULL, RETURN_MASK_ALL);
}
static void
break_at_finish_at_depth_command_1 (char *arg, int flag, int from_tty)
{
struct frame_info *frame;
CORE_ADDR low, high, selected_pc = 0;
char *extra_args = NULL;
char *level_arg;
char *addr_string;
int extra_args_len = 0, if_arg = 0;
if (!arg ||
(arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
{
if (default_breakpoint_valid)
{
if (selected_frame)
{
selected_pc = selected_frame->pc;
if (arg)
if_arg = 1;
}
else
error ("No selected frame.");
}
else
error ("No default breakpoint address now.");
}
else
{
extra_args = strchr (arg, ' ');
if (extra_args)
{
extra_args++;
extra_args_len = strlen (extra_args);
level_arg = (char *) xmalloc (extra_args - arg);
strncpy (level_arg, arg, extra_args - arg - 1);
level_arg[extra_args - arg - 1] = '\0';
}
else
{
level_arg = (char *) xmalloc (strlen (arg) + 1);
strcpy (level_arg, arg);
}
frame = parse_frame_specification (level_arg);
if (frame)
selected_pc = frame->pc;
else
selected_pc = 0;
}
if (if_arg)
{
extra_args = arg;
extra_args_len = strlen (arg);
}
if (selected_pc)
{
if (find_pc_partial_function (selected_pc, (char **) NULL, &low, &high))
{
addr_string = (char *) xmalloc (26 + extra_args_len);
if (extra_args_len)
sprintf (addr_string, "*0x%s %s", paddr_nz (high), extra_args);
else
sprintf (addr_string, "*0x%s", paddr_nz (high));
break_command_1 (addr_string, flag, from_tty);
xfree (addr_string);
}
else
error ("No function contains the specified address");
}
else
error ("Unable to set breakpoint at procedure exit");
}
static void
break_at_finish_command_1 (char *arg, int flag, int from_tty)
{
char *addr_string, *break_string, *beg_addr_string;
CORE_ADDR low, high;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct cleanup *old_chain;
char *extra_args = NULL;
int extra_args_len = 0;
int i, if_arg = 0;
if (!arg ||
(arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
{
if (default_breakpoint_valid)
{
if (selected_frame)
{
addr_string = (char *) xmalloc (15);
sprintf (addr_string, "*0x%s", paddr_nz (selected_frame->pc));
if (arg)
if_arg = 1;
}
else
error ("No selected frame.");
}
else
error ("No default breakpoint address now.");
}
else
{
addr_string = (char *) xmalloc (strlen (arg) + 1);
strcpy (addr_string, arg);
}
if (if_arg)
{
extra_args = arg;
extra_args_len = strlen (arg);
}
else if (arg)
{
extra_args = strchr (arg, ' ');
if (extra_args)
{
extra_args++;
extra_args_len = strlen (extra_args);
}
}
sals.sals = NULL;
sals.nelts = 0;
beg_addr_string = addr_string;
sals = decode_line_1 (&addr_string, 1, (struct symtab *) NULL, 0,
(char ***) NULL);
xfree (beg_addr_string);
old_chain = make_cleanup (xfree, sals.sals);
for (i = 0; (i < sals.nelts); i++)
{
sal = sals.sals[i];
if (find_pc_partial_function (sal.pc, (char **) NULL, &low, &high))
{
break_string = (char *) xmalloc (extra_args_len + 26);
if (extra_args_len)
sprintf (break_string, "*0x%s %s", paddr_nz (high), extra_args);
else
sprintf (break_string, "*0x%s", paddr_nz (high));
break_command_1 (break_string, flag, from_tty);
xfree (break_string);
}
else
error ("No function contains the specified address");
}
if (sals.nelts > 1)
{
warning ("Multiple breakpoints were set.\n");
warning ("Use the \"delete\" command to delete unwanted breakpoints.");
}
do_cleanups (old_chain);
}
void
resolve_sal_pc (struct symtab_and_line *sal)
{
CORE_ADDR pc;
CORE_ADDR end;
if (sal->pc == 0 && sal->symtab != NULL)
{
if (!find_line_pc_range (*sal, &pc, &end))
error ("No line %d in file \"%s\".",
sal->line, sal->symtab->filename);
sal->pc = pc;
}
if (sal->section == 0 && sal->symtab != NULL)
{
struct blockvector *bv;
struct block *b;
struct symbol *sym;
int index;
bv = blockvector_for_pc_sect (sal->pc, 0, &index, sal->symtab);
if (bv != NULL)
{
b = BLOCKVECTOR_BLOCK (bv, index);
sym = block_function (b);
if (sym != NULL)
{
fixup_symbol_section (sym, sal->symtab->objfile);
sal->section = SYMBOL_BFD_SECTION (sym);
}
else
{
struct minimal_symbol *msym;
msym = lookup_minimal_symbol_by_pc (sal->pc);
if (msym)
sal->section = SYMBOL_BFD_SECTION (msym);
}
}
}
}
void
future_break_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_FUTUREFLAG, from_tty);
}
void
break_command (char *arg, int from_tty)
{
break_command_1 (arg, 0, from_tty);
}
void
break_at_finish_command (char *arg, int from_tty)
{
break_at_finish_command_1 (arg, 0, from_tty);
}
void
break_at_finish_at_depth_command (char *arg, int from_tty)
{
break_at_finish_at_depth_command_1 (arg, 0, from_tty);
}
void
tbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_TEMPFLAG, from_tty);
}
void
tbreak_at_finish_command (char *arg, int from_tty)
{
break_at_finish_command_1 (arg, BP_TEMPFLAG, from_tty);
}
static void
hbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_HARDWAREFLAG, from_tty);
}
static void
thbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty);
}
static void
stop_command (char *arg, int from_tty)
{
printf_filtered ("Specify the type of breakpoint to set.\n\
Usage: stop in <function | address>\n\
stop at <line>\n");
}
static void
stopin_command (char *arg, int from_tty)
{
int badInput = 0;
if (arg == (char *) NULL)
badInput = 1;
else if (*arg != '*')
{
char *argptr = arg;
int hasColon = 0;
while (*argptr && !hasColon)
{
hasColon = (*argptr == ':');
argptr++;
}
if (hasColon)
badInput = (*argptr != ':');
else
badInput = isdigit (*arg);
}
if (badInput)
printf_filtered ("Usage: stop in <function | address>\n");
else
break_command_1 (arg, 0, from_tty);
}
static void
stopat_command (char *arg, int from_tty)
{
int badInput = 0;
if (arg == (char *) NULL || *arg == '*')
badInput = 1;
else
{
char *argptr = arg;
int hasColon = 0;
while (*argptr && !hasColon)
{
hasColon = (*argptr == ':');
argptr++;
}
if (hasColon)
badInput = (*argptr == ':');
else
badInput = !isdigit (*arg);
}
if (badInput)
printf_filtered ("Usage: stop at <line>\n");
else
break_command_1 (arg, 0, from_tty);
}
static void
watch_command_1 (char *arg, int accessflag, int from_tty)
{
struct breakpoint *b;
struct symtab_and_line sal;
struct expression *exp;
struct block *exp_valid_block;
struct value *val, *mark;
struct frame_info *frame;
struct frame_info *prev_frame = NULL;
char *exp_start = NULL;
char *exp_end = NULL;
char *tok, *end_tok;
int toklen;
char *cond_start = NULL;
char *cond_end = NULL;
struct expression *cond = NULL;
int i, other_type_used, target_resources_ok = 0;
enum bptype bp_type;
int mem_cnt = 0;
INIT_SAL (&sal);
innermost_block = NULL;
exp_start = arg;
exp = parse_exp_1 (&arg, 0, 0);
exp_end = arg;
exp_valid_block = innermost_block;
mark = value_mark ();
val = evaluate_expression (exp);
release_value (val);
if (VALUE_LAZY (val))
value_fetch_lazy (val);
tok = arg;
while (*tok == ' ' || *tok == '\t')
tok++;
end_tok = tok;
while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
end_tok++;
toklen = end_tok - tok;
if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
{
tok = cond_start = end_tok + 1;
cond = parse_exp_1 (&tok, 0, 0);
cond_end = tok;
}
if (*tok)
error ("Junk at end of command.");
if (accessflag == hw_read)
bp_type = bp_read_watchpoint;
else if (accessflag == hw_access)
bp_type = bp_access_watchpoint;
else
bp_type = bp_hardware_watchpoint;
mem_cnt = can_use_hardware_watchpoint (val);
if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint)
error ("Expression cannot be implemented with read/access watchpoint.");
if (mem_cnt != 0)
{
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
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.");
if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
error ("Target can only support one kind of HW watchpoint at a time.");
}
#if defined(HPUXHPPA)
if (!target_has_execution)
{
warning ("can't do that without a running program; try \"break main\", \"run\" first");
return;
}
#endif
if (!mem_cnt || target_resources_ok <= 0)
bp_type = bp_watchpoint;
b = set_raw_breakpoint (sal, bp_type);
b->original_flags = accessflag;
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
b->cond = cond;
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
b->cond_string = 0;
frame = block_innermost_frame (exp_valid_block);
if (frame)
{
prev_frame = get_prev_frame (frame);
b->watchpoint_frame = frame->frame;
}
else
b->watchpoint_frame = (CORE_ADDR) 0;
if (innermost_block)
{
if (prev_frame)
{
struct breakpoint *scope_breakpoint;
struct symtab_and_line scope_sal;
INIT_SAL (&scope_sal);
scope_sal.pc = get_frame_pc (prev_frame);
scope_sal.section = find_pc_overlay (scope_sal.pc);
scope_breakpoint = set_raw_breakpoint (scope_sal,
bp_watchpoint_scope);
set_breakpoint_count (breakpoint_count + 1);
scope_breakpoint->number = breakpoint_count;
scope_breakpoint->enable_state = bp_enabled;
scope_breakpoint->disposition = disp_del;
scope_breakpoint->frame = prev_frame->frame;
scope_breakpoint->address = get_frame_pc (prev_frame);
b->related_breakpoint = scope_breakpoint;
}
}
value_free_to_mark (mark);
if (create_breakpoint_hook)
create_breakpoint_hook (b);
mention (b);
}
#if !defined(TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT)
#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(BYTE_SIZE) \
((BYTE_SIZE) <= (REGISTER_SIZE))
#endif
#if !defined(TARGET_REGION_OK_FOR_HW_WATCHPOINT)
#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(ADDR,LEN) \
(TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(LEN))
#endif
static int
can_use_hardware_watchpoint (struct value *v)
{
int found_memory_cnt = 0;
if (!can_use_hw_watchpoints)
return 0;
for (; v; v = v->next)
{
if (VALUE_LVAL (v) == lval_memory)
{
if (VALUE_LAZY (v))
;
else
{
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))
return 0;
else
found_memory_cnt++;
}
}
else if (v->lval != not_lval && v->modifiable == 0)
return 0;
else if (v->lval == lval_register)
return 0;
}
return found_memory_cnt;
}
void
watch_command_wrapper (char *arg, int from_tty)
{
watch_command (arg, from_tty);
}
static void
watch_command (char *arg, int from_tty)
{
watch_command_1 (arg, hw_write, from_tty);
}
void
rwatch_command_wrapper (char *arg, int from_tty)
{
rwatch_command (arg, from_tty);
}
static void
rwatch_command (char *arg, int from_tty)
{
watch_command_1 (arg, hw_read, from_tty);
}
void
awatch_command_wrapper (char *arg, int from_tty)
{
awatch_command (arg, from_tty);
}
static void
awatch_command (char *arg, int from_tty)
{
watch_command_1 (arg, hw_access, from_tty);
}
static void
until_break_command_continuation (struct continuation_arg *arg)
{
struct cleanup *cleanups;
cleanups = (struct cleanup *) arg->data.pointer;
do_exec_cleanups (cleanups);
}
void
until_break_command (char *arg, int from_tty)
{
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct frame_info *prev_frame = get_prev_frame (selected_frame);
struct breakpoint *breakpoint;
struct cleanup *old_chain;
struct continuation_arg *arg1;
clear_proceed_status ();
if (default_breakpoint_valid)
sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
default_breakpoint_line, (char ***) NULL);
else
sals = decode_line_1 (&arg, 1, (struct symtab *) NULL,
0, (char ***) NULL);
if (sals.nelts != 1)
error ("Couldn't get information on specified line.");
sal = sals.sals[0];
xfree (sals.sals);
if (*arg)
error ("Junk at end of arguments.");
resolve_sal_pc (&sal);
breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until);
if (!event_loop_p || !target_can_async_p ())
old_chain = make_cleanup_delete_breakpoint (breakpoint);
else
old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
if (event_loop_p && target_can_async_p ())
{
arg1 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg1->next = NULL;
arg1->data.pointer = old_chain;
add_continuation (until_break_command_continuation, arg1);
}
if (prev_frame)
{
sal = find_pc_line (prev_frame->pc, 0);
sal.pc = prev_frame->pc;
breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until);
if (!event_loop_p || !target_can_async_p ())
make_cleanup_delete_breakpoint (breakpoint);
else
make_exec_cleanup_delete_breakpoint (breakpoint);
}
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
if (!event_loop_p || !target_can_async_p ())
do_cleanups (old_chain);
}
#if 0
static int
catch_breakpoint (char *name)
{
}
static int
disable_catch_breakpoint (void)
{
}
static int
delete_catch_breakpoint (void)
{
}
static int
enable_catch_breakpoint (void)
{
}
#endif
struct sal_chain
{
struct sal_chain *next;
struct symtab_and_line sal;
};
#if 0
static struct symtabs_and_lines
map_catch_names (char *args, int (*function) ())
{
register char *p = args;
register char *p1;
struct symtabs_and_lines sals;
#if 0
struct sal_chain *sal_chain = 0;
#endif
if (p == 0)
error_no_arg ("one or more catch names");
sals.nelts = 0;
sals.sals = NULL;
while (*p)
{
p1 = p;
if (p1[0] == 'i' && p1[1] == 'f'
&& (p1[2] == ' ' || p1[2] == '\t'))
break;
if (isalpha (*p1))
{
p1++;
while (isalnum (*p1) || *p1 == '_' || *p1 == '$')
p1++;
}
if (*p1 && *p1 != ' ' && *p1 != '\t')
error ("Arguments must be catch names.");
*p1 = 0;
#if 0
if (function (p))
{
struct sal_chain *next = (struct sal_chain *)
alloca (sizeof (struct sal_chain));
next->next = sal_chain;
next->sal = get_catch_sal (p);
sal_chain = next;
goto win;
}
#endif
printf_unfiltered ("No catch clause for exception %s.\n", p);
#if 0
win:
#endif
p = p1;
while (*p == ' ' || *p == '\t')
p++;
}
}
#endif
static struct symtabs_and_lines
get_catch_sals (int this_level_only)
{
register struct blockvector *bl;
register struct block *block;
int index, have_default = 0;
CORE_ADDR pc;
struct symtabs_and_lines sals;
struct sal_chain *sal_chain = 0;
char *blocks_searched;
if (selected_frame == NULL)
error ("No selected frame.");
block = get_frame_block (selected_frame, 0);
pc = selected_frame->pc;
sals.nelts = 0;
sals.sals = NULL;
if (block == 0)
error ("No symbol table info available.\n");
bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
memset (blocks_searched, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
while (block != 0)
{
CORE_ADDR end = BLOCK_END (block) - 4;
int last_index;
if (bl != blockvector_for_pc (end, &index))
error ("blockvector blotch");
if (BLOCKVECTOR_BLOCK (bl, index) != block)
error ("blockvector botch");
last_index = BLOCKVECTOR_NBLOCKS (bl);
index += 1;
while (index < last_index
&& BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
index++;
while (index < last_index
&& BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
{
if (blocks_searched[index] == 0)
{
struct block *b = BLOCKVECTOR_BLOCK (bl, index);
register int i;
register struct symbol *sym;
ALL_BLOCK_SYMBOLS (b, i, sym)
{
if (STREQ (SYMBOL_NAME (sym), "default"))
{
if (have_default)
continue;
have_default = 1;
}
if (SYMBOL_CLASS (sym) == LOC_LABEL)
{
struct sal_chain *next = (struct sal_chain *)
alloca (sizeof (struct sal_chain));
next->next = sal_chain;
next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym),
0);
sal_chain = next;
}
}
blocks_searched[index] = 1;
}
index++;
}
if (have_default)
break;
if (sal_chain && this_level_only)
break;
if (BLOCK_FUNCTION (block))
break;
block = BLOCK_SUPERBLOCK (block);
}
if (sal_chain)
{
struct sal_chain *tmp_chain;
for (index = 0, tmp_chain = sal_chain; tmp_chain;
tmp_chain = tmp_chain->next)
index++;
sals.nelts = index;
sals.sals = (struct symtab_and_line *)
xmalloc (index * sizeof (struct symtab_and_line));
for (index = 0; sal_chain; sal_chain = sal_chain->next, index++)
sals.sals[index] = sal_chain->sal;
}
return sals;
}
static void
ep_skip_leading_whitespace (char **s)
{
if ((s == NULL) || (*s == NULL))
return;
while (isspace (**s))
*s += 1;
}
static char *
ep_find_event_name_end (char *arg)
{
char *s = arg;
char *event_name_end = NULL;
if (arg == NULL)
return NULL;
while (*s != '\0')
{
if (!isalnum (*s) && (*s != '_'))
break;
event_name_end = s;
s++;
}
return event_name_end;
}
static char *
ep_parse_optional_if_clause (char **arg)
{
char *cond_string;
if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !isspace ((*arg)[2]))
return NULL;
(*arg) += 2;
ep_skip_leading_whitespace (arg);
cond_string = *arg;
(*arg) += strlen (cond_string);
return cond_string;
}
static char *
ep_parse_optional_filename (char **arg)
{
static char filename[1024];
char *arg_p = *arg;
int i;
char c;
if ((*arg_p == '\0') || isspace (*arg_p))
return NULL;
for (i = 0;; i++)
{
c = *arg_p;
if (isspace (c))
c = '\0';
filename[i] = c;
if (c == '\0')
break;
arg_p++;
}
*arg = arg_p;
return filename;
}
typedef enum
{
catch_fork, catch_vfork
}
catch_fork_kind;
#if defined(CHILD_INSERT_FORK_CATCHPOINT) || defined(CHILD_INSERT_VFORK_CATCHPOINT)
static void catch_fork_command_1 (catch_fork_kind fork_kind,
char *arg, int tempflag, int from_tty);
static void
catch_fork_command_1 (catch_fork_kind fork_kind, char *arg, int tempflag,
int from_tty)
{
char *cond_string = NULL;
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
if ((*arg != '\0') && !isspace (*arg))
error ("Junk at end of arguments.");
switch (fork_kind)
{
case catch_fork:
create_fork_event_catchpoint (tempflag, cond_string);
break;
case catch_vfork:
create_vfork_event_catchpoint (tempflag, cond_string);
break;
default:
error ("unsupported or unknown fork kind; cannot catch it");
break;
}
}
#endif
#if defined(CHILD_INSERT_EXEC_CATCHPOINT)
static void
catch_exec_command_1 (char *arg, int tempflag, int from_tty)
{
char *cond_string = NULL;
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
if ((*arg != '\0') && !isspace (*arg))
error ("Junk at end of arguments.");
create_exec_event_catchpoint (tempflag, cond_string);
}
#endif
#if defined(SOLIB_ADD)
static void
catch_load_command_1 (char *arg, int tempflag, int from_tty)
{
char *dll_pathname = NULL;
char *cond_string = NULL;
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
if (cond_string == NULL)
{
dll_pathname = ep_parse_optional_filename (&arg);
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
}
if ((*arg != '\0') && !isspace (*arg))
error ("Junk at end of arguments.");
SOLIB_CREATE_CATCH_LOAD_HOOK (PIDGET (inferior_ptid), tempflag,
dll_pathname, cond_string);
}
static void
catch_unload_command_1 (char *arg, int tempflag, int from_tty)
{
char *dll_pathname = NULL;
char *cond_string = NULL;
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
if (cond_string == NULL)
{
dll_pathname = ep_parse_optional_filename (&arg);
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
}
if ((*arg != '\0') && !isspace (*arg))
error ("Junk at end of arguments.");
SOLIB_CREATE_CATCH_UNLOAD_HOOK (PIDGET (inferior_ptid), tempflag,
dll_pathname, cond_string);
}
#endif
static void
create_exception_catchpoint (int tempflag, char *cond_string,
enum exception_event_kind ex_event,
struct symtab_and_line *sal)
{
struct breakpoint *b;
int thread = -1;
enum bptype bptype;
if (!sal)
return;
switch (ex_event)
{
case EX_EVENT_THROW:
bptype = bp_catch_throw;
break;
case EX_EVENT_CATCH:
bptype = bp_catch_catch;
break;
default:
error ("Internal error -- invalid catchpoint kind");
}
b = set_raw_breakpoint (*sal, bptype);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = thread;
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
mention (b);
}
static void
catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
int tempflag, int from_tty)
{
char *cond_string = NULL;
struct symtab_and_line *sal = NULL;
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
if ((*arg != '\0') && !isspace (*arg))
error ("Junk at end of arguments.");
if ((ex_event != EX_EVENT_THROW) &&
(ex_event != EX_EVENT_CATCH))
error ("Unsupported or unknown exception event; cannot catch it");
sal = target_enable_exception_callback (ex_event, 1);
if (sal)
{
if (sal != (struct symtab_and_line *) -1)
create_exception_catchpoint (tempflag, cond_string, ex_event, sal);
else
return;
}
else
{
if (ex_event == EX_EVENT_CATCH)
{
handle_gnu_4_16_catch_command (arg, tempflag, from_tty);
}
else if (ex_event == EX_EVENT_THROW)
{
warning ("Unsupported with this platform/compiler combination.");
warning ("Perhaps you can achieve the effect you want by setting");
warning ("a breakpoint on __raise_exception().");
}
}
}
static int
cover_target_enable_exception_callback (PTR arg)
{
args_for_catchpoint_enable *args = arg;
struct symtab_and_line *sal;
sal = target_enable_exception_callback (args->kind, args->enable_p);
if (sal == NULL)
return 0;
else if (sal == (struct symtab_and_line *) -1)
return -1;
else
return 1;
}
static void
handle_gnu_4_16_catch_command (char *arg, int tempflag, int from_tty)
{
struct symtabs_and_lines sals;
struct symtab_and_line sal;
register struct expression *cond = 0;
register struct breakpoint *b;
char *save_arg;
int i;
INIT_SAL (&sal);
if (!arg || (arg[0] == 'i' && arg[1] == 'f'
&& (arg[2] == ' ' || arg[2] == '\t')))
{
sals = get_catch_sals (0);
}
else
{
error ("catch NAME not implemented");
#if 0
sals = map_catch_names (arg, catch_breakpoint);
#endif
}
if (!sals.nelts)
return;
save_arg = arg;
for (i = 0; i < sals.nelts; i++)
{
resolve_sal_pc (&sals.sals[i]);
while (arg && *arg)
{
if (arg[0] == 'i' && arg[1] == 'f'
&& (arg[2] == ' ' || arg[2] == '\t'))
cond = parse_exp_1 ((arg += 2, &arg),
block_for_pc (sals.sals[i].pc), 0);
else
error ("Junk at end of arguments.");
}
arg = save_arg;
}
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
if (from_tty)
describe_other_breakpoints (sal.pc, sal.section);
b = set_raw_breakpoint (sal, bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = cond;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
if (create_breakpoint_hook)
create_breakpoint_hook (b);
if (from_tty)
mention (b);
}
if (sals.nelts > 1)
{
warning ("Multiple breakpoints were set.");
warning ("Use the \"delete\" command to delete unwanted breakpoints.");
}
xfree (sals.sals);
}
static void
catch_command_1 (char *arg, int tempflag, int from_tty)
{
char *arg1_start = arg;
char *arg1_end;
int arg1_length;
if (arg1_start == NULL)
{
error ("Catch requires an event name.");
}
arg1_end = ep_find_event_name_end (arg1_start);
if (arg1_end == NULL)
error ("catch requires an event");
arg1_length = arg1_end + 1 - arg1_start;
if (strncmp (arg1_start, "signal", arg1_length) == 0)
{
error ("Catch of signal not yet implemented");
}
else if (strncmp (arg1_start, "catch", arg1_length) == 0)
{
catch_exception_command_1 (EX_EVENT_CATCH, arg1_end + 1,
tempflag, from_tty);
}
else if (strncmp (arg1_start, "throw", arg1_length) == 0)
{
catch_exception_command_1 (EX_EVENT_THROW, arg1_end + 1,
tempflag, from_tty);
}
else if (strncmp (arg1_start, "thread_start", arg1_length) == 0)
{
error ("Catch of thread_start not yet implemented");
}
else if (strncmp (arg1_start, "thread_exit", arg1_length) == 0)
{
error ("Catch of thread_exit not yet implemented");
}
else if (strncmp (arg1_start, "thread_join", arg1_length) == 0)
{
error ("Catch of thread_join not yet implemented");
}
else if (strncmp (arg1_start, "start", arg1_length) == 0)
{
error ("Catch of start not yet implemented");
}
else if (strncmp (arg1_start, "exit", arg1_length) == 0)
{
error ("Catch of exit not yet implemented");
}
else if (strncmp (arg1_start, "fork", arg1_length) == 0)
{
#if defined(CHILD_INSERT_FORK_CATCHPOINT)
catch_fork_command_1 (catch_fork, arg1_end + 1, tempflag, from_tty);
#else
error ("Catch of fork not yet implemented");
#endif
}
else if (strncmp (arg1_start, "vfork", arg1_length) == 0)
{
#if defined(CHILD_INSERT_VFORK_CATCHPOINT)
catch_fork_command_1 (catch_vfork, arg1_end + 1, tempflag, from_tty);
#else
error ("Catch of vfork not yet implemented");
#endif
}
else if (strncmp (arg1_start, "exec", arg1_length) == 0)
{
#if defined(CHILD_INSERT_EXEC_CATCHPOINT)
catch_exec_command_1 (arg1_end + 1, tempflag, from_tty);
#else
error ("Catch of exec not yet implemented");
#endif
}
else if (strncmp (arg1_start, "load", arg1_length) == 0)
{
#if defined(SOLIB_ADD)
catch_load_command_1 (arg1_end + 1, tempflag, from_tty);
#else
error ("Catch of load not implemented");
#endif
}
else if (strncmp (arg1_start, "unload", arg1_length) == 0)
{
#if defined(SOLIB_ADD)
catch_unload_command_1 (arg1_end + 1, tempflag, from_tty);
#else
error ("Catch of load not implemented");
#endif
}
else if (strncmp (arg1_start, "stop", arg1_length) == 0)
{
error ("Catch of stop not yet implemented");
}
else
{
error ("Unknown event kind specified for catch");
}
}
struct breakpoint *
set_breakpoint_sal (struct symtab_and_line sal)
{
struct breakpoint *b;
b = set_raw_breakpoint (sal, bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = 0;
b->thread = -1;
return b;
}
#if 0
static void
disable_catch (char *args)
{
}
static void
enable_catch (char *args)
{
}
static void
delete_catch (char *args)
{
}
#endif
static void
catch_command (char *arg, int from_tty)
{
catch_command_1 (arg, 0, from_tty);
}
static void
tcatch_command (char *arg, int from_tty)
{
catch_command_1 (arg, 1, from_tty);
}
static void
clear_command (char *arg, int from_tty)
{
register struct breakpoint *b, *b1;
int default_match;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
register struct breakpoint *found;
int i;
if (arg)
{
sals = decode_line_spec (arg, 1);
default_match = 0;
}
else
{
sals.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
INIT_SAL (&sal);
sal.line = default_breakpoint_line;
sal.symtab = default_breakpoint_symtab;
sal.pc = default_breakpoint_address;
if (sal.symtab == 0)
error ("No source file specified.");
sals.sals[0] = sal;
sals.nelts = 1;
default_match = 1;
}
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
found = (struct breakpoint *) 0;
while (breakpoint_chain
&& (((sal.pc && (breakpoint_chain->address == sal.pc))
&& (!overlay_debugging
|| breakpoint_chain->section == sal.section))
|| ((default_match || (0 == sal.pc))
&& breakpoint_chain->source_file != NULL
&& sal.symtab != NULL
&& STREQ (breakpoint_chain->source_file, sal.symtab->filename)
&& breakpoint_chain->line_number == sal.line)))
{
b1 = breakpoint_chain;
breakpoint_chain = b1->next;
b1->next = found;
found = b1;
}
ALL_BREAKPOINTS (b)
while (b->next
&& b->next->type != bp_none
&& b->next->type != bp_watchpoint
&& b->next->type != bp_hardware_watchpoint
&& b->next->type != bp_read_watchpoint
&& b->next->type != bp_access_watchpoint
&& (((sal.pc && (b->next->address == sal.pc))
&& (!overlay_debugging || b->next->section == sal.section))
|| ((default_match || (0 == sal.pc))
&& b->next->source_file != NULL
&& sal.symtab != NULL
&& STREQ (b->next->source_file, sal.symtab->filename)
&& b->next->line_number == sal.line)))
{
b1 = b->next;
b->next = b1->next;
b1->next = found;
found = b1;
}
if (found == 0)
{
if (arg)
error ("No breakpoint at %s.", arg);
else
error ("No breakpoint at this line.");
}
if (found->next)
from_tty = 1;
if (from_tty)
printf_unfiltered ("Deleted breakpoint%s ", found->next ? "s" : "");
breakpoints_changed ();
while (found)
{
if (from_tty)
printf_unfiltered ("%d ", found->number);
b1 = found->next;
delete_breakpoint (found);
found = b1;
}
if (from_tty)
putchar_unfiltered ('\n');
}
xfree (sals.sals);
}
void
breakpoint_auto_delete (bpstat bs)
{
struct breakpoint *b, *temp;
for (; bs; bs = bs->next)
if (bs->breakpoint_at && bs->breakpoint_at->disposition == disp_del
&& bs->stop)
delete_breakpoint (bs->breakpoint_at);
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->disposition == disp_del_at_next_stop)
delete_breakpoint (b);
}
}
void
delete_breakpoint (struct breakpoint *bpt)
{
register struct breakpoint *b;
register bpstat bs;
if (bpt == NULL)
error ("Internal error (attempted to delete a NULL breakpoint)");
if (bpt->type == bp_none)
return;
if (delete_breakpoint_hook)
delete_breakpoint_hook (bpt);
breakpoint_delete_event (bpt->number);
if (bpt->inserted)
remove_breakpoint (bpt, mark_inserted);
if (breakpoint_chain == bpt)
breakpoint_chain = bpt->next;
if (ep_is_exception_catchpoint (bpt) && target_has_execution)
{
static char message1[] = "Error in deleting catchpoint %d:\n";
static char message[sizeof (message1) + 30];
args_for_catchpoint_enable args;
sprintf (message, message1, bpt->number);
args.kind = bpt->type == bp_catch_catch ?
EX_EVENT_CATCH : EX_EVENT_THROW;
args.enable_p = 0;
catch_errors (cover_target_enable_exception_callback, &args,
message, RETURN_MASK_ALL);
}
ALL_BREAKPOINTS (b)
if (b->next == bpt)
{
b->next = bpt->next;
break;
}
check_duplicates (bpt);
if (bpt->inserted
&& bpt->type != bp_hardware_watchpoint
&& bpt->type != bp_read_watchpoint
&& bpt->type != bp_access_watchpoint
&& bpt->type != bp_catch_fork
&& bpt->type != bp_catch_vfork
&& bpt->type != bp_catch_exec)
{
ALL_BREAKPOINTS (b)
if (b->address == bpt->address
&& b->section == bpt->section
&& !b->duplicate
&& b->enable_state != bp_disabled
&& b->enable_state != bp_shlib_disabled
&& b->enable_state != bp_call_disabled)
{
int val;
if (b->enable_state == bp_permanent)
internal_error (__FILE__, __LINE__,
"another breakpoint was inserted on top of "
"a permanent breakpoint");
if (b->type == bp_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
else
val = target_insert_breakpoint (b->address, b->shadow_contents);
if (val != 0)
{
target_terminal_ours_for_output ();
warning ("Cannot insert breakpoint %d:", b->number);
memory_error (val, b->address);
}
else
b->inserted = 1;
}
}
free_command_lines (&bpt->commands);
if (bpt->cond)
xfree (bpt->cond);
if (bpt->cond_string != NULL)
xfree (bpt->cond_string);
if (bpt->addr_string != NULL)
xfree (bpt->addr_string);
if (bpt->exp != NULL)
xfree (bpt->exp);
if (bpt->exp_string != NULL)
xfree (bpt->exp_string);
if (bpt->val != NULL)
value_free (bpt->val);
if (bpt->source_file != NULL)
xfree (bpt->source_file);
if (bpt->dll_pathname != NULL)
xfree (bpt->dll_pathname);
if (bpt->triggered_dll_pathname != NULL)
xfree (bpt->triggered_dll_pathname);
if (bpt->exec_pathname != NULL)
xfree (bpt->exec_pathname);
for (bs = stop_bpstat; bs; bs = bs->next)
if (bs->breakpoint_at == bpt)
{
bs->breakpoint_at = NULL;
bs->commands = NULL;
bs->old_val = NULL;
}
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);
}
struct cleanup *
make_exec_cleanup_delete_breakpoint (struct breakpoint *b)
{
return make_exec_cleanup (do_delete_breakpoint_cleanup, b);
}
void
delete_command (char *arg, int from_tty)
{
struct breakpoint *b, *temp;
if (arg == 0)
{
int breaks_to_delete = 0;
ALL_BREAKPOINTS (b)
{
if (b->type != bp_call_dummy &&
b->type != bp_shlib_event &&
b->type != bp_thread_event &&
b->type != bp_overlay_event &&
b->number >= 0)
breaks_to_delete = 1;
}
if (!from_tty
|| (breaks_to_delete && query ("Delete all breakpoints? ")))
{
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->type != bp_call_dummy &&
b->type != bp_shlib_event &&
b->type != bp_thread_event &&
b->type != bp_overlay_event &&
b->number >= 0)
delete_breakpoint (b);
}
}
}
else
map_breakpoint_numbers (arg, delete_breakpoint);
}
static int
breakpoint_re_set_one (PTR bint)
{
struct breakpoint *b = (struct breakpoint *) bint;
struct value *mark;
int i;
struct symtabs_and_lines sals;
char *s;
enum enable_state save_enable;
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_catch_load:
case bp_catch_unload:
if (b->addr_string == NULL)
{
warning ("Unable to reset breakpoint %d (no address string available); deleting", b->number);
delete_breakpoint (b);
return 0;
}
save_enable = b->enable_state;
if (b->enable_state != bp_disabled)
b->enable_state = bp_shlib_disabled;
set_language (b->language);
input_radix = b->input_radix;
s = b->addr_string;
allow_objc_selectors_flag = 0;
sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL);
allow_objc_selectors_flag = 1;
if (NULL == sals.sals)
{
return 0;
}
for (i = 0; i < sals.nelts; i++)
{
resolve_sal_pc (&sals.sals[i]);
if (b->cond_string != NULL)
{
s = b->cond_string;
if (b->cond)
xfree (b->cond);
b->cond = NULL;
}
if (b->address != sals.sals[i].pc
|| (b->source_file != NULL
&& sals.sals[i].symtab != NULL
&& (!STREQ (b->source_file, sals.sals[i].symtab->filename)
|| b->line_number != sals.sals[i].line)
)
|| ((b->source_file == NULL) != (sals.sals[i].symtab == NULL))
)
{
if (b->source_file != NULL)
xfree (b->source_file);
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->line_number = sals.sals[i].line;
b->address = sals.sals[i].pc;
if (modify_breakpoint_hook)
modify_breakpoint_hook (b);
mention (b);
}
b->section = sals.sals[i].section;
b->enable_state = save_enable;
check_duplicates (b);
}
xfree (sals.sals);
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
innermost_block = NULL;
save_enable = b->enable_state;
if (b->enable_state != bp_disabled)
b->enable_state = bp_shlib_disabled;
set_language (b->language);
input_radix = b->input_radix;
s = b->addr_string;
{
char *s = b->exp_string;
char *tmp = b->exp;
if (! gdb_parse_exp_1 (&s, innermost_block, 0, &b->exp))
{
warning ("Unable to reset watchpoint %d (unable to parse expression); deleting", b->number);
delete_breakpoint (b);
return 0;
}
if (tmp)
xfree (tmp);
b->exp_valid_block = innermost_block;
}
mark = value_mark ();
if (b->val)
value_free (b->val);
b->val = evaluate_expression (b->exp);
release_value (b->val);
if (VALUE_LAZY (b->val))
value_fetch_lazy (b->val);
if (b->cond_string != NULL)
{
s = b->cond_string;
if (b->cond)
xfree (b->cond);
b->cond = parse_exp_1 (&s, (struct block *) 0, 0);
}
if (b->enable_state == bp_enabled)
{
if (modify_breakpoint_hook)
modify_breakpoint_hook (b);
mention (b);
}
value_free_to_mark (mark);
b->enable_state = save_enable;
break;
case bp_catch_catch:
case bp_catch_throw:
break;
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
break;
default:
printf_filtered ("Deleting unknown breakpoint type %d\n", b->type);
case bp_longjmp:
case bp_longjmp_resume:
case bp_overlay_event:
delete_breakpoint (b);
break;
case bp_shlib_event:
case bp_thread_event:
case bp_until:
case bp_finish:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_step_resume:
break;
}
return 0;
}
unsigned int symbol_generation = 1;
unsigned int breakpoint_generation = 0;
void breakpoint_update ()
{
if (breakpoint_generation != symbol_generation) {
breakpoint_re_set_all ();
breakpoint_generation = symbol_generation;
}
}
void
breakpoint_re_set (void)
{
symbol_generation++;
}
void
breakpoint_re_set_all ()
{
struct breakpoint *b, *temp;
enum language save_language;
int save_input_radix;
static char message1[] = "Error in re-setting breakpoint %d:\n";
char message[sizeof (message1) + 30 ];
#ifdef SOLIB_ADD
disable_breakpoints_in_shlibs (0);
#endif
save_language = current_language->la_language;
save_input_radix = input_radix;
ALL_BREAKPOINTS_SAFE (b, temp)
{
struct ui_file *old_stderr = NULL;
sprintf (message, message1, b->number);
dont_mention = 1;
old_stderr = gdb_stderr;
if (b->enable_state == bp_shlib_disabled) {
gdb_stderr = gdb_null;
}
catch_errors (breakpoint_re_set_one, b, message, RETURN_MASK_ALL);
dont_mention = 0;
gdb_stderr = old_stderr;
}
set_language (save_language);
input_radix = save_input_radix;
breakpoints_changed ();
if (GET_LONGJMP_TARGET_P ())
{
create_longjmp_breakpoint ("longjmp");
create_longjmp_breakpoint ("_longjmp");
create_longjmp_breakpoint ("siglongjmp");
create_longjmp_breakpoint ("_siglongjmp");
create_longjmp_breakpoint (NULL);
}
create_overlay_event_breakpoint ("_ovly_debug_event");
}
void
breakpoint_re_set_thread (struct breakpoint *b)
{
if (b->thread != -1)
{
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
}
}
void
set_ignore_count (int bptnum, int count, int from_tty)
{
register struct breakpoint *b;
if (count < 0)
count = 0;
ALL_BREAKPOINTS (b)
if (b->number == bptnum)
{
b->ignore_count = count;
if (!from_tty)
return;
else if (count == 0)
printf_filtered ("Will stop next time breakpoint %d is reached.",
bptnum);
else if (count == 1)
printf_filtered ("Will ignore next crossing of breakpoint %d.",
bptnum);
else
printf_filtered ("Will ignore next %d crossings of breakpoint %d.",
count, bptnum);
breakpoints_changed ();
return;
}
error ("No breakpoint number %d.", bptnum);
}
void
breakpoint_clear_ignore_counts (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
b->ignore_count = 0;
}
static void
ignore_command (char *args, int from_tty)
{
char *p = args;
register int num;
if (p == 0)
error_no_arg ("a breakpoint number");
num = get_number (&p);
if (num == 0)
error ("bad breakpoint number: '%s'", args);
if (*p == 0)
error ("Second argument (specified ignore-count) is missing.");
set_ignore_count (num,
longest_to_int (value_as_long (parse_and_eval (p))),
from_tty);
if (from_tty)
printf_filtered ("\n");
breakpoints_changed ();
}
static void
map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
{
register char *p = args;
char *p1;
register int num;
register struct breakpoint *b, *tmp;
int match;
if (p == 0)
error_no_arg ("one or more breakpoint numbers");
while (*p)
{
match = 0;
p1 = p;
num = get_number_or_range (&p1);
if (num == 0)
{
warning ("bad breakpoint number at or near '%s'", p);
}
else
{
ALL_BREAKPOINTS_SAFE (b, tmp)
if (b->number == num)
{
struct breakpoint *related_breakpoint = b->related_breakpoint;
match = 1;
function (b);
if (related_breakpoint)
function (related_breakpoint);
break;
}
if (match == 0)
printf_unfiltered ("No breakpoint number %d.\n", num);
}
p = p1;
}
}
void
disable_breakpoint (struct breakpoint *bpt)
{
if (bpt->type == bp_watchpoint_scope)
return;
if (bpt->enable_state == bp_permanent)
return;
bpt->enable_state = bp_disabled;
check_duplicates (bpt);
breakpoints_changed ();
if (modify_breakpoint_hook)
modify_breakpoint_hook (bpt);
breakpoint_modify_event (bpt->number);
}
static void
disable_command (char *args, int from_tty)
{
register struct breakpoint *bpt;
if (args == 0)
ALL_BREAKPOINTS (bpt)
switch (bpt->type)
{
case bp_none:
warning ("attempted to disable apparently deleted breakpoint #%d?",
bpt->number);
continue;
case bp_breakpoint:
case bp_catch_load:
case bp_catch_unload:
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
case bp_catch_catch:
case bp_catch_throw:
case bp_hardware_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
disable_breakpoint (bpt);
default:
continue;
}
else
map_breakpoint_numbers (args, disable_breakpoint);
}
static void
do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
{
struct frame_info *save_selected_frame = NULL;
int save_selected_frame_level = -1;
int target_resources_ok, other_type_used;
struct value *mark;
if (bpt->type == bp_hardware_breakpoint)
{
int i;
i = hw_breakpoint_used_count ();
target_resources_ok =
TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint,
i + 1, 0);
if (target_resources_ok == 0)
error ("No hardware breakpoint support in the target.");
else if (target_resources_ok < 0)
error ("Hardware breakpoints used exceeds limit.");
}
if (bpt->enable_state != bp_permanent)
bpt->enable_state = bp_enabled;
bpt->disposition = disposition;
check_duplicates (bpt);
breakpoints_changed ();
if (bpt->type == bp_watchpoint ||
bpt->type == bp_hardware_watchpoint ||
bpt->type == bp_read_watchpoint ||
bpt->type == bp_access_watchpoint)
{
if (bpt->exp_valid_block != NULL)
{
struct frame_info *fr =
get_current_frame ();
fr = find_frame_addr_in_frame_chain (bpt->watchpoint_frame);
if (fr == NULL)
{
printf_filtered ("\
Cannot enable watchpoint %d because the block in which its expression\n\
is valid is not currently in scope.\n", bpt->number);
bpt->enable_state = bp_disabled;
return;
}
save_selected_frame = selected_frame;
save_selected_frame_level = selected_frame_level;
select_frame (fr, -1);
}
value_free (bpt->val);
mark = value_mark ();
bpt->val = evaluate_expression (bpt->exp);
release_value (bpt->val);
if (VALUE_LAZY (bpt->val))
value_fetch_lazy (bpt->val);
if (bpt->type == bp_hardware_watchpoint ||
bpt->type == bp_read_watchpoint ||
bpt->type == bp_access_watchpoint)
{
int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
int mem_cnt = can_use_hardware_watchpoint (bpt->val);
(void) mem_cnt, i;
target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
bpt->type, i + mem_cnt, other_type_used);
if (target_resources_ok < 0)
{
printf_filtered ("\
Cannot enable watchpoint %d because target watch resources\n\
have been allocated for other watchpoints.\n", bpt->number);
bpt->enable_state = bp_disabled;
value_free_to_mark (mark);
return;
}
}
if (save_selected_frame_level >= 0)
select_frame (save_selected_frame, save_selected_frame_level);
value_free_to_mark (mark);
}
if (modify_breakpoint_hook)
modify_breakpoint_hook (bpt);
breakpoint_modify_event (bpt->number);
}
void
enable_breakpoint (struct breakpoint *bpt)
{
do_enable_breakpoint (bpt, bpt->disposition);
}
static void
enable_command (char *args, int from_tty)
{
register struct breakpoint *bpt;
if (args == 0)
ALL_BREAKPOINTS (bpt)
switch (bpt->type)
{
case bp_none:
warning ("attempted to enable apparently deleted breakpoint #%d?",
bpt->number);
continue;
case bp_breakpoint:
case bp_catch_load:
case bp_catch_unload:
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
case bp_catch_catch:
case bp_catch_throw:
case bp_hardware_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
enable_breakpoint (bpt);
default:
continue;
}
else
map_breakpoint_numbers (args, enable_breakpoint);
}
static void
enable_once_breakpoint (struct breakpoint *bpt)
{
do_enable_breakpoint (bpt, disp_disable);
}
static void
enable_once_command (char *args, int from_tty)
{
map_breakpoint_numbers (args, enable_once_breakpoint);
}
static void
enable_delete_breakpoint (struct breakpoint *bpt)
{
do_enable_breakpoint (bpt, disp_del);
}
static void
enable_delete_command (char *args, int from_tty)
{
map_breakpoint_numbers (args, enable_delete_breakpoint);
}
static void
write_one_breakpoint (struct breakpoint *b, struct ui_file *stream, struct ui_out *uiout)
{
register struct command_line *l;
switch (b->type)
{
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
switch (b->original_flags)
{
case hw_read:
fprintf_unfiltered (stream, "rwatch %s", b->exp_string);
break;
case hw_access:
fprintf_unfiltered (stream, "awatch %s", b->exp_string);
break;
case hw_execute:
internal_error (__FILE__, __LINE__, "execute watchpoints unsupported");
break;
case hw_write:
default:
fprintf_unfiltered (stream, "watch %s", b->exp_string);
break;
}
case bp_catch_load:
case bp_catch_unload:
fprintf_unfiltered (stream, "%scatch %sload", b->disposition == disp_del ? "t" : "",
b->type == bp_catch_unload ? "un" : "");
if (b->dll_pathname != NULL)
fputs_unfiltered (b->dll_pathname, stream);
break;
case bp_catch_fork:
fprintf_unfiltered (stream, "%scatch fork", b->disposition == disp_del ? "t" : "");
break;
case bp_catch_vfork:
fprintf_unfiltered (stream, "%scatch vfork", b->disposition == disp_del ? "t" : "");
break;
case bp_catch_exec:
fprintf_unfiltered (stream, "%scatch exec", b->disposition == disp_del ? "t" : "");
break;
case bp_catch_catch:
fprintf_unfiltered (stream, "%scatch catch", b->disposition == disp_del ? "t" : "");
break;
case bp_catch_throw:
fprintf_unfiltered (stream, "%scatch throw", b->disposition == disp_del ? "t" : "");
break;
case bp_breakpoint:
case bp_hardware_breakpoint:
{
char *hardwareflag, *futureflag, *tempflag;
hardwareflag = (b->type == bp_hardware_breakpoint) ? "h" : "";
futureflag = ((b->enable_state == bp_shlib_disabled) ||
(b->original_flags & BP_FUTUREFLAG)) ? "future-" : "";
tempflag = (b->disposition == disp_del) ? "t" : "";
fprintf_unfiltered (stream, "%s%s%sbreak", futureflag, tempflag, hardwareflag);
if (b->addr_string)
{
int len = strlen(b->addr_string) - 1;
if (b->addr_string[len] == ' ')
b->addr_string[len] = 0;
else
len = 0;
fprintf_unfiltered (stream, " %s", b->addr_string);
if (len)
b->addr_string[len] = ' ';
}
else if (b->source_file)
fprintf_unfiltered (stream, " %s:%d", b->source_file, b->line_number);
else
fprintf_unfiltered(stream, " %s",
local_hex_string_custom((unsigned long) b->address, "08l"));
}
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
break;
}
if (b->thread != -1)
fprintf_unfiltered (stream, " thread %d", b->thread);
if (b->cond_string)
fprintf_unfiltered (stream, " if %s", b->cond_string);
fputc_unfiltered ('\n', stream);
if ((l = b->commands))
{
fputs_unfiltered ("commands\n", stream);
print_command_lines (uiout, l, 4);
fputs_unfiltered ("end\n", stream);
}
if (b->ignore_count)
fprintf_unfiltered (stream, "ignore $bpnum %d\n", b->ignore_count);
if (b->enable_state == bp_disabled)
fputs_unfiltered ("disable $bpnum\n", stream);
}
static void
save_breakpoints_command (char *arg, int from_tty)
{
struct cleanup *cleanups;
register struct breakpoint *b;
int found_a_breakpoint = 0;
int current_radix = -1;
int skip;
struct ui_file *stream = NULL;
struct ui_out *uiout = NULL;
time_t t;
char **argv;
char *pathname, buf[256];
dont_repeat ();
if (arg == NULL)
error ("Arguments missing: file name in which to save breakpoint commands");
else if ((argv = buildargv (arg)) == NULL)
nomem (0);
cleanups = make_cleanup_freeargv (argv);
pathname = tilde_expand (arg);
make_cleanup (xfree, pathname);
ALL_BREAKPOINTS (b)
{
if (b->type != bp_breakpoint
&& b->type != bp_catch_load
&& b->type != bp_catch_unload
&& b->type != bp_catch_fork
&& b->type != bp_catch_vfork
&& b->type != bp_catch_exec
&& b->type != bp_catch_catch
&& b->type != bp_catch_throw
&& b->type != bp_hardware_breakpoint
&& b->type != bp_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
&& b->type != bp_hardware_watchpoint)
continue;
if (! found_a_breakpoint++)
{
stream = gdb_fopen (pathname, FOPEN_WT);
if (stream == NULL)
error ("Unable to open file '%s' for saving breakpoints (%s)",
arg, strerror (errno));
make_cleanup_ui_file_delete (stream);
uiout = cli_out_new (stream);
if (uiout == NULL)
error ("Unable to create cli_out from file for saving breakpoints");
make_cleanup_ui_out_delete (uiout);
if (time (&t) != -1)
{
char *l = setlocale (LC_ALL, NULL);
if (l)
{
char *orig_locale = strcpy (xmalloc (strlen (l) + 1), l);
setlocale (LC_ALL, "");
if (strftime (buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime (&t)))
fprintf_unfiltered (stream, "# Saved breakpoints file created on %s\n\n", buf);
setlocale (LC_ALL, orig_locale);
}
}
fprintf_unfiltered (stream, "set $current_radix = $input_radix\n"
"set input-radix 012\n\n");
current_radix = 10;
}
skip = (b->commands || b->ignore_count || b->enable_state == bp_disabled);
if (skip)
fputc_unfiltered ('\n', stream);
if (b->input_radix != current_radix)
{
current_radix = b->input_radix;
fprintf_unfiltered (stream, "set input-radix 0%o\n", current_radix);
}
write_one_breakpoint (b, stream, uiout);
if (skip && b->next)
fputc_unfiltered ('\n', stream);
}
if (! found_a_breakpoint)
printf_filtered ("No breakpoints or watchpoints to save.\n");
else
{
fputs_unfiltered ("\n", stream);
if (current_radix != 10)
fputs_unfiltered ("set input-radix 012\n", stream);
fputs_unfiltered ("set input-radix $current_radix\n", stream);
if (from_tty)
printf_filtered ("Breakpoints saved to file '%s'.\n", arg);
}
do_cleanups (cleanups);
}
struct symtabs_and_lines
decode_line_spec_1 (char *string, int funfirstline)
{
struct symtabs_and_lines sals;
if (string == 0)
error ("Empty line specification.");
if (default_breakpoint_valid)
sals = decode_line_1 (&string, funfirstline,
default_breakpoint_symtab,
default_breakpoint_line,
(char ***) NULL);
else
sals = decode_line_1 (&string, funfirstline,
(struct symtab *) NULL, 0, (char ***) NULL);
if (*string)
error ("Junk at end of line specification: %s", string);
return sals;
}
void
_initialize_breakpoint (void)
{
struct cmd_list_element *c;
breakpoint_chain = 0;
breakpoint_count = 0;
add_com ("ignore", class_breakpoint, ignore_command,
"Set ignore-count of breakpoint number N to COUNT.\n\
Usage is `ignore N COUNT'.");
if (xdb_commands)
add_com_alias ("bc", "ignore", class_breakpoint, 1);
add_com ("commands", class_breakpoint, commands_command,
"Set commands to be executed when a breakpoint is hit.\n\
Give breakpoint number as argument after \"commands\".\n\
With no argument, the targeted breakpoint is the last one set.\n\
The commands themselves follow starting on the next line.\n\
Type a line containing \"end\" to indicate the end of them.\n\
Give \"silent\" as the first line to make the breakpoint silent;\n\
then no output is printed when it is hit, except what the commands print.");
add_com ("condition", class_breakpoint, condition_command,
"Specify breakpoint number N to break only if COND is true.\n\
Usage is `condition N COND', where N is an integer and COND is an\n\
expression to be evaluated whenever breakpoint N is reached.");
c = add_com ("tbreak", class_breakpoint, tbreak_command,
"Set a temporary breakpoint. Args like \"break\" command.\n\
Like \"break\" except the breakpoint is only temporary,\n\
so it will be deleted when hit. Equivalent to \"break\" followed\n\
by using \"enable delete\" on the breakpoint number.");
set_cmd_completer (c, location_completer);
c = add_com ("hbreak", class_breakpoint, hbreak_command,
"Set a hardware assisted breakpoint. Args like \"break\" command.\n\
Like \"break\" except the breakpoint requires hardware support,\n\
some target hardware may not have this support.");
set_cmd_completer (c, location_completer);
c = add_com ("thbreak", class_breakpoint, thbreak_command,
"Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\
Like \"hbreak\" except the breakpoint is only temporary,\n\
so it will be deleted when hit.");
set_cmd_completer (c, location_completer);
add_prefix_cmd ("enable", class_breakpoint, enable_command,
"Enable some breakpoints.\n\
Give breakpoint numbers (separated by spaces) as arguments.\n\
With no subcommand, breakpoints are enabled until you command otherwise.\n\
This is used to cancel the effect of the \"disable\" command.\n\
With a subcommand you can enable temporarily.",
&enablelist, "enable ", 1, &cmdlist);
if (xdb_commands)
add_com ("ab", class_breakpoint, enable_command,
"Enable some breakpoints.\n\
Give breakpoint numbers (separated by spaces) as arguments.\n\
With no subcommand, breakpoints are enabled until you command otherwise.\n\
This is used to cancel the effect of the \"disable\" command.\n\
With a subcommand you can enable temporarily.");
add_com_alias ("en", "enable", class_breakpoint, 1);
add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command,
"Enable some breakpoints.\n\
Give breakpoint numbers (separated by spaces) as arguments.\n\
This is used to cancel the effect of the \"disable\" command.\n\
May be abbreviated to simply \"enable\".\n",
&enablebreaklist, "enable breakpoints ", 1, &enablelist);
add_cmd ("once", no_class, enable_once_command,
"Enable breakpoints for one hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it becomes disabled.",
&enablebreaklist);
add_cmd ("delete", no_class, enable_delete_command,
"Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it is deleted.",
&enablebreaklist);
add_cmd ("delete", no_class, enable_delete_command,
"Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it is deleted.",
&enablelist);
add_cmd ("once", no_class, enable_once_command,
"Enable breakpoints for one hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it becomes disabled.",
&enablelist);
add_prefix_cmd ("disable", class_breakpoint, disable_command,
"Disable some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To disable all breakpoints, give no argument.\n\
A disabled breakpoint is not forgotten, but has no effect until reenabled.",
&disablelist, "disable ", 1, &cmdlist);
add_com_alias ("dis", "disable", class_breakpoint, 1);
add_com_alias ("disa", "disable", class_breakpoint, 1);
if (xdb_commands)
add_com ("sb", class_breakpoint, disable_command,
"Disable some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To disable all breakpoints, give no argument.\n\
A disabled breakpoint is not forgotten, but has no effect until reenabled.");
add_cmd ("breakpoints", class_alias, disable_command,
"Disable some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To disable all breakpoints, give no argument.\n\
A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
This command may be abbreviated \"disable\".",
&disablelist);
add_prefix_cmd ("delete", class_breakpoint, delete_command,
"Delete some breakpoints or auto-display expressions.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To delete all breakpoints, give no argument.\n\
\n\
Also a prefix command for deletion of other GDB objects.\n\
The \"unset\" command is also an alias for \"delete\".",
&deletelist, "delete ", 1, &cmdlist);
add_com_alias ("d", "delete", class_breakpoint, 1);
if (xdb_commands)
add_com ("db", class_breakpoint, delete_command,
"Delete some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To delete all breakpoints, give no argument.\n");
add_cmd ("breakpoints", class_alias, delete_command,
"Delete some breakpoints or auto-display expressions.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To delete all breakpoints, give no argument.\n\
This command may be abbreviated \"delete\".",
&deletelist);
add_com ("clear", class_breakpoint, clear_command,
concat ("Clear breakpoint at specified line or function.\n\
Argument may be line number, function name, or \"*\" and an address.\n\
If line number is specified, all breakpoints in that line are cleared.\n\
If function is specified, breakpoints at beginning of function are cleared.\n\
If an address is specified, breakpoints at that address are cleared.\n\n",
"With no argument, clears all breakpoints in the line that the selected frame\n\
is executing in.\n\
\n\
See also the \"delete\" command which clears breakpoints by number.", NULL));
c = add_com ("break", class_breakpoint, break_command,
concat ("Set breakpoint at specified line or function.\n\
Argument may be line number, function name, or \"*\" and an address.\n\
If line number is specified, break at start of code for that line.\n\
If function is specified, break at start of code for that function.\n\
If an address is specified, break at that exact address.\n",
"With no arg, uses current execution address of selected stack frame.\n\
This is useful for breaking on return to a stack frame.\n\
\n\
Multiple breakpoints at one place are permitted, and useful if conditional.\n\
\n\
break ... if <cond> sets condition <cond> on the breakpoint as it is created.\n\
\n\
Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL));
set_cmd_completer (c, location_completer);
add_com_alias ("b", "break", class_run, 1);
add_com_alias ("br", "break", class_run, 1);
add_com_alias ("bre", "break", class_run, 1);
add_com_alias ("brea", "break", class_run, 1);
add_com ("future-break", class_breakpoint, future_break_command,
"Set breakpoint at expression. If it can't be done now, attempt it\n"
"again each time code is dynamically loaded.");
add_com_alias ("fb", "future-break", class_breakpoint, 2);
if (xdb_commands)
{
add_com_alias ("ba", "break", class_breakpoint, 1);
add_com_alias ("bu", "ubreak", class_breakpoint, 1);
}
if (dbx_commands)
{
add_abbrev_prefix_cmd ("stop", class_breakpoint, stop_command,
"Break in function/address or break at a line in the current file.",
&stoplist, "stop ", 1, &cmdlist);
add_cmd ("in", class_breakpoint, stopin_command,
"Break in function or address.\n", &stoplist);
add_cmd ("at", class_breakpoint, stopat_command,
"Break at a line in the current file.\n", &stoplist);
add_com ("status", class_info, breakpoints_info,
concat ("Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
The \"Type\" column indicates one of:\n\
\tbreakpoint - normal breakpoint\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
address and file/line number respectively.\n\n",
"Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed.\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set.", NULL));
}
add_info ("breakpoints", breakpoints_info,
concat ("Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
The \"Type\" column indicates one of:\n\
\tbreakpoint - normal breakpoint\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
address and file/line number respectively.\n\n",
"Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed.\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set.", NULL));
if (xdb_commands)
add_com ("lb", class_breakpoint, breakpoints_info,
concat ("Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
The \"Type\" column indicates one of:\n\
\tbreakpoint - normal breakpoint\n\
\twatchpoint - watchpoint\n\
The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
address and file/line number respectively.\n\n",
"Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed.\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set.", NULL));
add_cmd ("breakpoints", class_maintenance, maintenance_info_breakpoints,
concat ("Status of all breakpoints, or breakpoint number NUMBER.\n\
The \"Type\" column indicates one of:\n\
\tbreakpoint - normal breakpoint\n\
\twatchpoint - watchpoint\n\
\tlongjmp - internal breakpoint used to step through longjmp()\n\
\tlongjmp resume - internal breakpoint at the target of longjmp()\n\
\tuntil - internal breakpoint used by the \"until\" command\n\
\tfinish - internal breakpoint used by the \"finish\" command\n",
"The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\
breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\
address and file/line number respectively.\n\n",
"Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed.\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set.", NULL),
&maintenanceinfolist);
add_com ("catch", class_breakpoint, catch_command,
"Set catchpoints to catch events.\n\
Raised signals may be caught:\n\
\tcatch signal - all signals\n\
\tcatch signal <signame> - a particular signal\n\
Raised exceptions may be caught:\n\
\tcatch throw - all exceptions, when thrown\n\
\tcatch throw <exceptname> - a particular exception, when thrown\n\
\tcatch catch - all exceptions, when caught\n\
\tcatch catch <exceptname> - a particular exception, when caught\n\
Thread or process events may be caught:\n\
\tcatch thread_start - any threads, just after creation\n\
\tcatch thread_exit - any threads, just before expiration\n\
\tcatch thread_join - any threads, just after joins\n\
Process events may be caught:\n\
\tcatch start - any processes, just after creation\n\
\tcatch exit - any processes, just before expiration\n\
\tcatch fork - calls to fork()\n\
\tcatch vfork - calls to vfork()\n\
\tcatch exec - calls to exec()\n\
Dynamically-linked library events may be caught:\n\
\tcatch load - loads of any library\n\
\tcatch load <libname> - loads of a particular library\n\
\tcatch unload - unloads of any library\n\
\tcatch unload <libname> - unloads of a particular library\n\
The act of your program's execution stopping may also be caught:\n\
\tcatch stop\n\n\
C++ exceptions may be caught:\n\
\tcatch throw - all exceptions, when thrown\n\
\tcatch catch - all exceptions, when caught\n\
\n\
Do \"help set follow-fork-mode\" for info on debugging your program\n\
after a fork or vfork is caught.\n\n\
Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
add_com ("tcatch", class_breakpoint, tcatch_command,
"Set temporary catchpoints to catch events.\n\
Args like \"catch\" command.\n\
Like \"catch\" except the catchpoint is only temporary,\n\
so it will be deleted when hit. Equivalent to \"catch\" followed\n\
by using \"enable delete\" on the catchpoint number.");
c = add_com ("watch", class_breakpoint, watch_command,
"Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression changes.");
set_cmd_completer (c, location_completer);
c = add_com ("rwatch", class_breakpoint, rwatch_command,
"Set a read watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression is read.");
set_cmd_completer (c, location_completer);
c = add_com ("awatch", class_breakpoint, awatch_command,
"Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression is either read or written.");
set_cmd_completer (c, location_completer);
add_info ("watchpoints", breakpoints_info,
"Synonym for ``info breakpoints''.");
c = add_set_cmd ("show_breakpoint_hit_counts", class_support, var_zinteger,
(char *) &show_breakpoint_hit_counts,
"Set if GDB should show breakpoint hit counts.\n\
This will affect the output of 'info debug'",
&setlist);
add_show_from_set (c, &showlist);
c = add_set_cmd ("can-use-hw-watchpoints", class_support, var_zinteger,
(char *) &can_use_hw_watchpoints,
"Set debugger's willingness to use watchpoint hardware.\n\
If zero, gdb will not use hardware for new watchpoints, even if\n\
such is available. (However, any hardware watchpoints that were\n\
created before setting this to nonzero, will continue to use watchpoint\n\
hardware.)",
&setlist);
add_show_from_set (c, &showlist);
c = add_cmd ("save-breakpoints", class_breakpoint, save_breakpoints_command,
"Save current breakpoint definitions as a script.\n\
Use the -command option or 'source' command in another debug\n\
'session to restore them.", &cmdlist);
set_cmd_completer (c, filename_completer);
add_com_alias ("save_breakpoints", "save-breakpoints", class_breakpoint, 1);
add_com_alias ("save_bp", "save-breakpoints", class_breakpoint, 1);
add_com_alias ("savebp", "save-breakpoints", class_breakpoint, 1);
can_use_hw_watchpoints = 1;
}
void
do_breakpoint_move (bpt, new_line_number)
struct breakpoint *bpt;
int new_line_number;
{
char new_line_spec[1024];
char *argp;
struct symtabs_and_lines sals;
CORE_ADDR new_address;
CORE_ADDR old_address;
int error_value;
int typeOK;
typeOK = (bpt->type == bp_breakpoint);
if (!typeOK)
{
printf_unfiltered ("breakpoint has the wrong type; cannot move it.\n");
return;
}
if (bpt->address == 0)
{
if (bpt->addr_string && !bpt->inserted)
{
char *colon = strchr (bpt->addr_string, ':');
if (colon)
{
char *cp = colon + 1;
char line_number_buffer[20];
char *nlsp;
while (*cp != '\0')
{
if (!isdigit (*cp))
return;
cp++;
}
sprintf (line_number_buffer, "%d", new_line_number);
nlsp = new_line_spec;
cp = bpt->addr_string;
while (*cp != ':')
*nlsp++ = *cp++;
*nlsp++ = ':';
cp = line_number_buffer;
while (*cp != '\0')
*nlsp++ = *cp++;
*nlsp++ = '\0';
xfree (bpt->addr_string);
bpt->addr_string = savestring (new_line_spec,
strlen (new_line_spec) + 1);
}
return;
}
else
return;
}
else if (!bpt->source_file)
return;
(void) sprintf (new_line_spec, "%s:%d",
bpt->source_file,
new_line_number);
argp = new_line_spec;
sals = decode_line_1 (&argp, 1, NULL, 0, NULL);
if (sals.nelts == 1)
{
struct symtab_and_line sal = sals.sals[0];
xfree ((PTR) sals.sals);
find_line_pc_range (sal, &sal.pc, &sal.end);
if (sal.pc != 0)
new_address = sal.pc;
else
return;
}
else
{
return;
}
if (bpt->inserted)
remove_breakpoint (bpt, mark_inserted);
old_address = bpt->address;
bpt->address = new_address;
error_value = 0;
check_duplicates (bpt);
if (bpt->inserted
&& bpt->type != bp_hardware_watchpoint
&& bpt->type != bp_read_watchpoint
&& bpt->type != bp_access_watchpoint)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
{
if (b->address == old_address
&& !b->duplicate
&& b->enable_state != bp_disabled)
{
int val;
val = target_insert_breakpoint (b->address, b->shadow_contents);
if (val != 0)
{
error_value = 1;
}
else
{
b->inserted = 1;
}
}
}
}
if (!error_value && bpt->inserted)
{
int val;
val = target_insert_breakpoint (bpt->address, bpt->shadow_contents);
if (val != 0)
{
error_value = 2;
}
}
if (!error_value)
{
if (bpt->addr_string)
{
xfree (bpt->addr_string);
bpt->addr_string = savestring (new_line_spec,
strlen (new_line_spec) + 1);
}
bpt->line_number = new_line_number;
if (modify_breakpoint_hook)
modify_breakpoint_hook (bpt);
}
else
{
bpt->address = old_address;
}
}
struct breakpoint *
find_finish_breakpoint (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_finish)
return b;
return NULL;
}