#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"
#ifdef UI_OUT
#include "ui-out.h"
#endif
#include "gdb-events.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 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 *);
static void break_at_finish_command (char *, int);
static void break_at_finish_at_depth_command (char *, int);
void tbreak_command (char *, int);
static 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);
static void check_duplicates (CORE_ADDR, asection *);
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);
void set_breakpoint_count (int);
#if 0
static struct breakpoint *create_temp_exception_breakpoint (CORE_ADDR);
#endif
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;
}
args_for_catchpoint_enable;
static int watchpoint_check (PTR);
static int cover_target_enable_exception_callback (PTR);
static void maintenance_info_breakpoints (char *, int);
#ifdef GET_LONGJMP_TARGET
static void create_longjmp_breakpoint (char *);
#endif
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 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 void awatch_command (char *, int);
static void do_enable_breakpoint (struct breakpoint *, enum bpdisp);
static int can_use_hw_watchpoints;
void _initialize_breakpoint (void);
void set_breakpoint_count (int);
extern int addressprint;
static int internal_breakpoint_number = -1;
static int executing_breakpoint_commands;
#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;
value_ptr 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)
{
free ((PTR) b->cond);
b->cond = 0;
}
if (b->cond_string != NULL)
free ((PTR) 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 == 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 != disabled
&& b->enable != shlib_disabled
&& b->enable != call_disabled
&& !b->inserted
&& !b->duplicate)
{
if (b->type == bp_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
else
{
if (overlay_debugging && b->section &&
section_is_overlay (b->section))
{
CORE_ADDR addr;
addr = overlay_unmapped_address (b->address, b->section);
val = target_insert_breakpoint (addr, b->shadow_contents);
val = 0;
if (section_is_mapped (b->section))
val = target_insert_breakpoint (b->address,
b->shadow_contents);
}
else
val = target_insert_breakpoint (b->address, b->shadow_contents);
}
if (val)
{
#if defined (DISABLE_UNSETTABLE_BREAK)
if (DISABLE_UNSETTABLE_BREAK (b->address))
{
val = 0;
b->enable = 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.", 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 != disabled
&& b->enable != shlib_disabled
&& b->enable != 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 = disabled;
}
else
{
int val;
args_for_catchpoint_enable args;
args.kind = b->type == bp_catch_catch ?
EX_EVENT_CATCH : EX_EVENT_THROW;
args.enable = 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 = 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 == enabled
&& b->disposition != del_at_next_stop
&& !b->inserted
&& !b->duplicate)
{
struct frame_info *saved_frame;
int saved_level, within_current_scope;
value_ptr mark = value_mark ();
value_ptr 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);
(void) 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 = del_at_next_stop;
b->disposition = 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 == enabled
&& !b->inserted
&& !b->duplicate)
{
val = -1;
switch (b->type)
{
case bp_catch_fork:
val = target_insert_fork_catchpoint (inferior_pid);
break;
case bp_catch_vfork:
val = target_insert_vfork_catchpoint (inferior_pid);
break;
case bp_catch_exec:
val = target_insert_exec_catchpoint (inferior_pid);
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;
int saved_inferior_pid = inferior_pid;
inferior_pid = 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)
{
inferior_pid = saved_inferior_pid;
return val;
}
}
}
inferior_pid = saved_inferior_pid;
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)
{
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;
}
}
int
detach_breakpoints (int pid)
{
register struct breakpoint *b;
int val;
int saved_inferior_pid = inferior_pid;
if (pid == inferior_pid)
error ("Cannot detach breakpoints of inferior_pid");
inferior_pid = pid;
ALL_BREAKPOINTS (b)
{
if (b->inserted)
{
val = remove_breakpoint (b, mark_inserted);
if (val != 0)
{
inferior_pid = saved_inferior_pid;
return val;
}
}
}
inferior_pid = saved_inferior_pid;
return 0;
}
static int
remove_breakpoint (struct breakpoint *b, insertion_state_t is)
{
int val;
if (b->enable == 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 (b->type == bp_hardware_breakpoint)
val = target_remove_hw_breakpoint (b->address, b->shadow_contents);
else
{
if (overlay_debugging && b->section &&
section_is_overlay (b->section))
{
CORE_ADDR addr;
addr = overlay_unmapped_address (b->address, b->section);
val = target_remove_breakpoint (addr, b->shadow_contents);
val = 0;
if (section_is_mapped (b->section))
val = target_remove_breakpoint (b->address,
b->shadow_contents);
}
else
val = target_remove_breakpoint (b->address, b->shadow_contents);
}
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 == enabled
&& !b->duplicate)
{
value_ptr v, 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 == enabled
&& !b->duplicate)
{
val = -1;
switch (b->type)
{
case bp_catch_fork:
val = target_remove_fork_catchpoint (inferior_pid);
break;
case bp_catch_vfork:
val = target_remove_vfork_catchpoint (inferior_pid);
break;
case bp_catch_exec:
val = target_remove_exec_catchpoint (inferior_pid);
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 == 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 == 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 == enabled
|| b->enable == permanent)
&& b->address == pc)
{
if (overlay_debugging &&
section_is_overlay (b->section) &&
!section_is_mapped (b->section))
continue;
else if (b->enable == 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, int pid)
{
struct breakpoint *b;
int thread;
thread = pid_to_thread_id (pid);
ALL_BREAKPOINTS (b)
if (b->enable != disabled
&& b->enable != shlib_disabled
&& b->enable != 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);
free ((PTR) 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)
{
if (bsp == NULL)
error ("Internal error (bpstat_find_step_resume_breakpoint)");
for (; bsp != NULL; bsp = bsp->next)
{
if ((bsp->breakpoint_at != NULL) &&
(bsp->breakpoint_at->type == bp_step_resume))
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;
if (executing_breakpoint_commands)
return;
executing_breakpoint_commands = 1;
old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
if (target_can_async_p ())
{
gdb_set_async_override (1);
make_cleanup (gdb_set_async_override, 0);
}
top:
bs = *bsp;
breakpoint_proceeded = 0;
for (; bs != NULL; bs = bs->next)
{
cmd = bs->commands;
while (cmd != NULL)
{
gdb_set_async_override (1);
execute_control_command (cmd);
if (breakpoint_proceeded)
break;
else
cmd = cmd->next;
}
if (breakpoint_proceeded)
goto top;
else
bs->commands = NULL;
}
executing_breakpoint_commands = 0;
gdb_set_async_override (0);
discard_cleanups (old_chain);
}
static enum print_stop_action
print_it_typical (bpstat bs)
{
#ifdef UI_OUT
struct cleanup *old_chain;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
#endif
if (bs->breakpoint_at == NULL)
return PRINT_UNKNOWN;
switch (bs->breakpoint_at->type)
{
case bp_breakpoint:
case bp_hardware_breakpoint:
#ifdef UI_OUT
annotate_breakpoint (bs->breakpoint_at->number);
ui_out_text (uiout, "\nBreakpoint ");
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
ui_out_field_string (uiout, "reason", "breakpoint-hit");
ui_out_field_int (uiout, "bkptno", bs->breakpoint_at->number);
ui_out_text (uiout, ", ");
return PRINT_SRC_AND_LOC;
#else
annotate_breakpoint (bs->breakpoint_at->number);
printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number);
return PRINT_SRC_AND_LOC;
#endif
break;
case bp_shlib_event:
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_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);
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
ui_out_field_string (uiout, "reason", "watchpoint-trigger");
mention (bs->breakpoint_at);
ui_out_list_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_list_end (uiout);
ui_out_text (uiout, "\n");
#else
mention (bs->breakpoint_at);
printf_filtered ("\nOld value = ");
value_print (bs->old_val, gdb_stdout, 0, Val_pretty_default);
printf_filtered ("\nNew value = ");
value_print (bs->breakpoint_at->val, gdb_stdout, 0,
Val_pretty_default);
printf_filtered ("\n");
#endif
value_free (bs->old_val);
bs->old_val = NULL;
}
return PRINT_UNKNOWN;
break;
case bp_read_watchpoint:
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
ui_out_field_string (uiout, "reason", "read-watchpoint-trigger");
mention (bs->breakpoint_at);
ui_out_list_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_list_end (uiout);
ui_out_text (uiout, "\n");
#else
mention (bs->breakpoint_at);
printf_filtered ("\nValue = ");
value_print (bs->breakpoint_at->val, gdb_stdout, 0,
Val_pretty_default);
printf_filtered ("\n");
#endif
return PRINT_UNKNOWN;
break;
case bp_access_watchpoint:
#ifdef UI_OUT
if (bs->old_val != NULL)
{
annotate_watchpoint (bs->breakpoint_at->number);
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
mention (bs->breakpoint_at);
ui_out_list_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 (interpreter_p && strcmp (interpreter_p, "mi") == 0)
ui_out_list_begin (uiout, "value");
ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
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_list_end (uiout);
ui_out_text (uiout, "\n");
#else
if (bs->old_val != NULL)
{
annotate_watchpoint (bs->breakpoint_at->number);
mention (bs->breakpoint_at);
printf_filtered ("\nOld value = ");
value_print (bs->old_val, gdb_stdout, 0, Val_pretty_default);
value_free (bs->old_val);
bs->old_val = NULL;
printf_filtered ("\nNew value = ");
}
else
{
mention (bs->breakpoint_at);
printf_filtered ("\nValue = ");
}
value_print (bs->breakpoint_at->val, gdb_stdout, 0,
Val_pretty_default);
printf_filtered ("\n");
#endif
return PRINT_UNKNOWN;
break;
case bp_finish:
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
ui_out_field_string (uiout, "reason", "function-finished");
#endif
return PRINT_UNKNOWN;
break;
case bp_until:
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
ui_out_field_string (uiout, "reason", "location-reached");
#endif
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 ("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)
{
value_ptr 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;
}
#define WP_DELETED 1
#define WP_VALUE_CHANGED 2
#define WP_VALUE_NOT_CHANGED 3
#define BP_TEMPFLAG 1
#define BP_HARDWAREFLAG 2
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)
select_frame (fr, -1);
}
if (within_current_scope)
{
value_ptr mark = value_mark ();
value_ptr new_val = evaluate_expression (bs->breakpoint_at->exp);
if (!value_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
{
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
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");
#else
printf_filtered ("\
Watchpoint %d deleted because the program has left the block in\n\
which its expression is valid.\n", bs->breakpoint_at->number);
#endif
if (b->related_breakpoint)
b->related_breakpoint->disposition = del_at_next_stop;
b->disposition = 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 == disabled
|| b->enable == shlib_disabled
|| b->enable == 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 ||
(overlay_debugging &&
section_is_overlay (b->section) &&
!section_is_mapped (b->section)))
continue;
if (b->type == bp_hardware_breakpoint
&& b->address != (*pc - DECR_PC_AFTER_HW_BREAK))
continue;
if ((b->type == bp_catch_load)
#if defined(SOLIB_HAVE_LOAD_EVENT)
&& (!SOLIB_HAVE_LOAD_EVENT (inferior_pid)
|| ((b->dll_pathname != NULL)
&& (strcmp (b->dll_pathname,
SOLIB_LOADED_LIBRARY_PATHNAME (inferior_pid))
!= 0)))
#endif
)
continue;
if ((b->type == bp_catch_unload)
#if defined(SOLIB_HAVE_UNLOAD_EVENT)
&& (!SOLIB_HAVE_UNLOAD_EVENT (inferior_pid)
|| ((b->dll_pathname != NULL)
&& (strcmp (b->dll_pathname,
SOLIB_UNLOADED_LIBRARY_PATHNAME (inferior_pid))
!= 0)))
#endif
)
continue;
if ((b->type == bp_catch_fork)
&& !target_has_forked (inferior_pid, &b->forked_inferior_pid))
continue;
if ((b->type == bp_catch_vfork)
&& !target_has_vforked (inferior_pid, &b->forked_inferior_pid))
continue;
if ((b->type == bp_catch_exec)
&& !target_has_execd (inferior_pid, &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 = del_at_next_stop;
b->disposition = 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;
value_ptr 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 = del_at_next_stop;
b->disposition = 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)
{
select_frame (get_current_frame (), 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 == disable)
b->enable = 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:
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;
}
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 == 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 == 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)
free (ep->triggered_dll_pathname);
if (ep->type == bp_catch_load)
dll_pathname = SOLIB_LOADED_LIBRARY_PATHNAME (inferior_pid);
else
dll_pathname = SOLIB_UNLOADED_LIBRARY_PATHNAME (inferior_pid);
#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_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];
#ifdef UI_OUT
struct ui_stream *stb = ui_out_stream_new (uiout);
struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
#endif
annotate_record ();
#ifdef UI_OUT
ui_out_list_begin (uiout, "bkpt");
#endif
annotate_field (0);
#ifdef UI_OUT
ui_out_field_int (uiout, "number", b->number);
#else
printf_filtered ("%-3d ", b->number);
#endif
annotate_field (1);
if (((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
|| ((int) b->type != bptypes[(int) b->type].type))
internal_error ("bptypes table does not describe type #%d.",
(int) b->type);
#ifdef UI_OUT
ui_out_field_string (uiout, "type", bptypes[(int) b->type].description);
#else
printf_filtered ("%-14s ", bptypes[(int) b->type].description);
#endif
annotate_field (2);
#ifdef UI_OUT
ui_out_field_string (uiout, "disp", bpdisps[(int) b->disposition]);
#else
printf_filtered ("%-4s ", bpdisps[(int) b->disposition]);
#endif
annotate_field (3);
#ifdef UI_OUT
ui_out_field_fmt (uiout, "enabled", "%c", bpenables[(int) b->enable]);
ui_out_spaces (uiout, 2);
#else
printf_filtered ("%-3c ", bpenables[(int) b->enable]);
#endif
strcpy (wrap_indent, " ");
if (addressprint)
strcat (wrap_indent, " ");
switch (b->type)
{
case bp_none:
internal_error ("print_one_breakpoint: bp_none encountered\n");
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
#ifdef UI_OUT
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "what", stb);
#else
annotate_field (5);
print_expression (b->exp, gdb_stdout);
#endif
break;
case bp_catch_load:
case bp_catch_unload:
#ifdef UI_OUT
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, "\" ");
}
#else
annotate_field (5);
if (b->dll_pathname == NULL)
printf_filtered ("<any library> ");
else
printf_filtered ("library \"%s\" ", b->dll_pathname);
#endif
break;
case bp_catch_fork:
case bp_catch_vfork:
#ifdef UI_OUT
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);
}
#else
annotate_field (5);
if (b->forked_inferior_pid != 0)
printf_filtered ("process %d ", b->forked_inferior_pid);
break;
#endif
case bp_catch_exec:
#ifdef UI_OUT
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, "\" ");
}
#else
annotate_field (5);
if (b->exec_pathname != NULL)
printf_filtered ("program \"%s\" ", b->exec_pathname);
#endif
break;
case bp_catch_catch:
#ifdef UI_OUT
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
ui_out_field_string (uiout, "what", "exception catch");
ui_out_spaces (uiout, 1);
#else
annotate_field (5);
printf_filtered ("exception catch ");
#endif
break;
case bp_catch_throw:
#ifdef UI_OUT
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
ui_out_field_string (uiout, "what", "exception throw");
ui_out_spaces (uiout, 1);
#else
annotate_field (5);
printf_filtered ("exception throw ");
#endif
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:
#ifdef UI_OUT
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
{
print_address_symbolic (b->address, stb->stream, demangle, "");
ui_out_field_stream (uiout, "at", stb);
}
#else
if (addressprint)
{
annotate_field (4);
printf_filtered
("%s ",
local_hex_string_custom
((unsigned long) b->address, "08l"));
}
annotate_field (5);
*last_addr = b->address;
if (b->source_file)
{
sym = find_pc_sect_function (b->address, b->section);
if (sym)
{
fputs_filtered ("in ", gdb_stdout);
fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
if (annotation_level < 2)
wrap_here (wrap_indent);
fputs_filtered (" at ", gdb_stdout);
}
fputs_filtered (b->source_file, gdb_stdout);
printf_filtered (":%d", b->line_number);
}
else
print_address_symbolic (b->address, gdb_stdout, demangle, " ");
#endif
break;
}
if (b->thread != -1)
{
#ifdef UI_OUT
ui_out_text (uiout, " thread ");
ui_out_field_int (uiout, "thread", b->thread);
#else
printf_filtered (" thread %d", b->thread);
#endif
}
#ifdef UI_OUT
ui_out_text (uiout, "\n");
#else
printf_filtered ("\n");
#endif
if (b->frame)
{
annotate_field (6);
if (annotation_level < 2)
printf_filtered ("\tstop only in stack frame at ");
#ifdef UI_OUT
ui_out_text (uiout, "\tstop only in stack frame at ");
ui_out_field_core_addr (uiout, "frame", b->frame);
ui_out_text (uiout, "\n");
#else
printf_filtered ("\tstop only in stack frame at ");
print_address_numeric (b->frame, 1, gdb_stdout);
printf_filtered ("\n");
#endif
}
if (b->cond)
{
annotate_field (7);
#ifdef UI_OUT
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");
#else
printf_filtered ("\tstop only if ");
print_expression (b->cond, gdb_stdout);
printf_filtered ("\n");
#endif
}
if (b->thread != -1)
{
#ifdef UI_OUT
ui_out_text (uiout, "\tstop only in thread ");
ui_out_field_int (uiout, "thread", b->thread);
ui_out_text (uiout, "\n");
#else
printf_filtered ("\tstop only in thread %d\n", b->thread);
#endif
}
if (show_breakpoint_hit_counts && b->hit_count)
{
#ifdef UI_OUT
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");
#else
if (ep_is_catchpoint (b))
printf_filtered ("\tcatchpoint");
else
printf_filtered ("\tbreakpoint");
printf_filtered (" already hit %d time%s\n",
b->hit_count, (b->hit_count == 1 ? "" : "s"));
#endif
}
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
if (show_breakpoint_hit_counts && b->hit_count == 0)
ui_out_field_int (uiout, "times", b->hit_count);
#endif
if (b->ignore_count)
{
annotate_field (8);
#ifdef UI_OUT
ui_out_text (uiout, "\tignore next ");
ui_out_field_int (uiout, "ignore", b->ignore_count);
ui_out_text (uiout, " hits\n");
#else
printf_filtered ("\tignore next %d hits\n", b->ignore_count);
#endif
}
if ((l = b->commands))
{
int offset = 4;
annotate_field (9);
#if 0
ui_out_list_begin (uiout, "script");
print_command_lines (uiout, l, 4);
ui_out_list_end (uiout);
#else
if (annotation_level >= 2)
printf_filtered ("commands-start\n");
while (l)
{
print_command_line (l, offset, gdb_stdout);
l = l->next;
}
if (annotation_level >= 2)
printf_filtered ("commands-end\n");
#endif
}
#ifdef UI_OUT
ui_out_list_end (uiout);
do_cleanups (old_chain);
#endif
}
struct captured_breakpoint_query_args
{
int bnum;
};
static int
do_captured_breakpoint_query (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 ( int bnum)
{
struct captured_breakpoint_query_args args;
args.bnum = bnum;
return catch_errors (do_captured_breakpoint_query, &args,
NULL, RETURN_MASK_ALL);
}
static void
breakpoint_1 (int bnum, int allflag)
{
register struct breakpoint *b;
CORE_ADDR last_addr = (CORE_ADDR) -1;
int found_a_breakpoint = 0;
#ifdef UI_OUT
if (addressprint)
ui_out_table_begin (uiout, 10, "BreakpointTable");
else
ui_out_table_begin (uiout, 9, "BreakpointTable");
#endif
ALL_BREAKPOINTS (b)
if (bnum == -1
|| bnum == b->number)
{
if (!allflag
&& 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++)
{
annotate_breakpoints_headers ();
#ifdef UI_OUT
annotate_field (0);
ui_out_table_header (uiout, 6, ui_left, "Number");
annotate_field (1);
ui_out_table_header (uiout, 14, ui_left, "Type");
annotate_field (2);
ui_out_table_header (uiout, 11, ui_left, "Disposition");
annotate_field (3);
ui_out_table_header (uiout, 7, ui_left, "Enabled");
if (addressprint)
{
annotate_field (4);
ui_out_table_header (uiout, 10, ui_left, "Address");
}
annotate_field (5);
ui_out_table_header (uiout, 40, ui_noalign, "What");
annotate_field (6);
ui_out_table_header (uiout, 10, ui_left, "StackFrame");
annotate_field (7);
ui_out_table_header (uiout, 9, ui_left, "Condition");
annotate_field (8);
ui_out_table_header (uiout, 11, ui_left, "IgnoreCount");
annotate_field (9);
ui_out_table_header (uiout, 8, ui_left, "Commands");
ui_out_table_body (uiout);
#else
annotate_field (0);
printf_filtered ("Num ");
annotate_field (1);
printf_filtered ("Type ");
annotate_field (2);
printf_filtered ("Disp ");
annotate_field (3);
printf_filtered ("Enb ");
if (addressprint)
{
annotate_field (4);
printf_filtered ("Address ");
}
annotate_field (5);
printf_filtered ("What\n");
annotate_field (6);
printf_filtered ("StackFrame");
annotate_field (7);
printf_filtered ("Condition");
annotate_field (8);
printf_filtered ("IgnoreCount");
annotate_field (9);
printf_filtered ("Commands\n");
#endif
annotate_breakpoints_table ();
}
print_one_breakpoint (b, &last_addr);
}
if (!found_a_breakpoint)
{
#ifdef UI_OUT
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 (bnum == -1)
printf_filtered ("No breakpoints or watchpoints.\n");
else
printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum);
#endif
}
else
{
if (last_addr != (CORE_ADDR) -1)
set_next_address (last_addr);
}
#ifdef UI_OUT
ui_out_table_end (uiout);
#endif
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 == 0 ||
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 == 0 ||
b->section == section)
{
others--;
printf_filtered
("%d%s%s ",
b->number,
((b->enable == disabled ||
b->enable == shlib_disabled ||
b->enable == call_disabled) ? " (disabled)"
: b->enable == 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 void
check_duplicates (CORE_ADDR address, asection *section)
{
register struct breakpoint *b;
register int count = 0;
struct breakpoint *perm_bp = 0;
if (address == 0)
return;
ALL_BREAKPOINTS (b)
if (b->enable != disabled
&& b->enable != shlib_disabled
&& b->enable != call_disabled
&& b->address == address
&& (overlay_debugging == 0 || b->section == section))
{
if (b->enable == permanent)
{
perm_bp = b;
break;
}
count++;
b->duplicate = count > 1;
}
if (perm_bp)
{
perm_bp->duplicate = 0;
if (! perm_bp->inserted)
internal_error ("allegedly permanent breakpoint is not "
"actually inserted");
ALL_BREAKPOINTS (b)
if (b != perm_bp)
{
if (b->inserted)
internal_error ("another breakpoint was inserted on top of "
"a permanent breakpoint");
if (b->enable != disabled
&& b->enable != shlib_disabled
&& b->enable != call_disabled
&& b->address == address
&& (overlay_debugging == 0 || b->section == section))
b->duplicate = 1;
}
}
}
struct breakpoint *
set_raw_breakpoint (struct symtab_and_line sal)
{
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->language = current_language->la_language;
b->input_radix = input_radix;
b->thread = -1;
b->line_number = sal.line;
b->enable = 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 (sal.pc, sal.section);
breakpoints_changed ();
return b;
}
void
make_breakpoint_permanent (struct breakpoint *b)
{
b->enable = permanent;
b->inserted = 1;
}
#ifdef GET_LONGJMP_TARGET
static void
create_longjmp_breakpoint (char *func_name)
{
struct symtab_and_line sal;
struct breakpoint *b;
INIT_SAL (&sal);
if (func_name != NULL)
{
struct minimal_symbol *m;
m = lookup_minimal_symbol_text (func_name, NULL,
(struct objfile *) NULL);
if (m)
sal.pc = SYMBOL_VALUE_ADDRESS (m);
else
return;
}
sal.section = find_pc_overlay (sal.pc);
b = set_raw_breakpoint (sal);
if (!b)
return;
b->type = func_name != NULL ? bp_longjmp : bp_longjmp_resume;
b->disposition = donttouch;
b->enable = disabled;
b->silent = 1;
if (func_name)
b->addr_string = strsave (func_name);
b->number = internal_breakpoint_number--;
}
#endif
void
enable_longjmp_breakpoint (void)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp)
{
b->enable = enabled;
check_duplicates (b->address, b->section);
}
}
void
disable_longjmp_breakpoint (void)
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp
|| b->type == bp_longjmp_resume)
{
b->enable = disabled;
check_duplicates (b->address, b->section);
}
}
struct breakpoint *
create_thread_event_breakpoint (CORE_ADDR address)
{
struct breakpoint *b;
struct symtab_and_line sal;
char addr_string[80];
INIT_SAL (&sal);
sal.pc = address;
sal.section = find_pc_overlay (sal.pc);
if ((b = set_raw_breakpoint (sal)) == NULL)
return NULL;
b->number = internal_breakpoint_number--;
b->disposition = donttouch;
b->type = bp_thread_event;
b->enable = enabled;
sprintf (addr_string, "*0x%s", paddr (b->address));
b->addr_string = strsave (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;
struct symtab_and_line sal;
INIT_SAL (&sal);
sal.pc = address;
sal.section = find_pc_overlay (sal.pc);
b = set_raw_breakpoint (sal);
b->number = internal_breakpoint_number--;
b->disposition = donttouch;
b->type = bp_shlib_event;
return b;
}
void
disable_breakpoints_in_shlibs (int silent)
{
struct breakpoint *b;
int disabled_shlib_breaks = 0;
ALL_BREAKPOINTS (b)
{
int disable = 0;
char buf[1];
#if defined (PC_SOLIB)
if (((b->type == bp_breakpoint) ||
(b->type == bp_hardware_breakpoint)) &&
b->enable == enabled &&
!b->duplicate &&
PC_SOLIB (b->address))
{
disable = 1;
}
#else
if (((b->type == bp_breakpoint) ||
(b->type == bp_hardware_breakpoint)) &&
b->enable == enabled &&
!b->duplicate)
{
if (target_read_memory (b->address, buf, 1) != 0)
{
disable = 1;
}
}
#endif
if (disable)
{
b->enable = 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);
}
}
}
if (!silent && disabled_shlib_breaks)
printf_filtered ("\n");
}
void
re_enable_breakpoints_in_shlibs (int silent)
{
struct breakpoint *b;
int enabled_shlib_breaks = 0;
int disabled_shlib_breaks = 0;
ALL_BREAKPOINTS (b)
if (b->enable == shlib_disabled)
{
char buf[1];
if (target_read_memory (b->address, buf, 1) == 0)
{
b->enable = 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");
ALL_BREAKPOINTS (b)
if (b->enable == enabled)
{
char buf[1];
if (target_read_memory (b->address, buf, 1) != 0)
{
b->enable = 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);
}
}
}
if (!silent && disabled_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 (free, sals.sals);
if (canonical != (char **) NULL)
{
make_cleanup (free, canonical);
canonical_strings_chain = make_cleanup (null_cleanup, 0);
if (canonical[0] != NULL)
make_cleanup (free, canonical[0]);
}
resolve_sal_pc (&sals.sals[0]);
if (canonical != (char **) NULL)
discard_cleanups (canonical_strings_chain);
b = set_raw_breakpoint (sals.sals[0]);
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 = enabled;
b->disposition = tempflag ? del : 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);
}
b->type = bp_kind;
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);
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 = enabled;
b->disposition = tempflag ? del : donttouch;
b->forked_inferior_pid = 0;
b->type = bp_kind;
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);
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 = enabled;
b->disposition = tempflag ? del : donttouch;
b->type = bp_catch_exec;
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 == 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 == 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 == 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 = enabled;
if (frame != NULL)
b->frame = frame->frame;
else
b->frame = 0;
check_duplicates (b->address, b->section);
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 == enabled))
{
b->enable = call_disabled;
check_duplicates (b->address, b->section);
}
}
}
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 == call_disabled))
{
b->enable = enabled;
check_duplicates (b->address, b->section);
}
}
}
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);
b->type = type;
b->enable = enabled;
b->disposition = donttouch;
b->frame = (frame ? frame->frame : 0);
if (in_thread_list (inferior_pid))
b->thread = pid_to_thread_id (inferior_pid);
return b;
}
static void
mention (struct breakpoint *b)
{
int say_where = 0;
#ifdef UI_OUT
struct cleanup *old_chain;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
#endif
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;
#ifdef UI_OUT
case bp_watchpoint:
ui_out_text (uiout, "Watchpoint ");
ui_out_list_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_list_end (uiout);
break;
case bp_hardware_watchpoint:
ui_out_text (uiout, "Hardware watchpoint ");
ui_out_list_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_list_end (uiout);
break;
#else
case bp_watchpoint:
printf_filtered ("Watchpoint %d: ", b->number);
print_expression (b->exp, gdb_stdout);
break;
case bp_hardware_watchpoint:
printf_filtered ("Hardware watchpoint %d: ", b->number);
print_expression (b->exp, gdb_stdout);
break;
#endif
#ifdef UI_OUT
case bp_read_watchpoint:
ui_out_text (uiout, "Hardware read watchpoint ");
ui_out_list_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_list_end (uiout);
break;
case bp_access_watchpoint:
ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
ui_out_list_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_list_end (uiout);
break;
#else
case bp_read_watchpoint:
printf_filtered ("Hardware read watchpoint %d: ", b->number);
print_expression (b->exp, gdb_stdout);
break;
case bp_access_watchpoint:
printf_filtered ("Hardware access (read/write) watchpoint %d: ",
b->number);
print_expression (b->exp, gdb_stdout);
break;
#endif
case bp_breakpoint:
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
{
say_where = 0;
break;
}
#endif
printf_filtered ("Breakpoint %d", b->number);
say_where = 1;
break;
case bp_hardware_breakpoint:
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
{
say_where = 0;
break;
}
#endif
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:
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);
TUIDO (((TuiOpaqueFuncPtr) tui_vAllSetHasBreakAt, b, 1));
TUIDO (((TuiOpaqueFuncPtr) tuiUpdateAllExecInfos));
}
#ifdef UI_OUT
do_cleanups (old_chain);
#endif
#ifdef UI_OUT
if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
return;
#endif
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 thread, int ignore_count, int from_tty)
{
if (type == bp_hardware_breakpoint)
{
int target_resources_ok;
hw_breakpoint_used_count ();
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);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->type = type;
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 = 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;
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;
}
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);
}
}
}
static void
break_command_1 (char *arg, int flag, int from_tty)
{
int tempflag, hardwareflag;
struct symtabs_and_lines sals;
register struct expression **cond = 0;
char **cond_string = (char **) NULL;
char *addr_start = arg;
char **addr_string;
struct cleanup *old_chain;
struct cleanup *breakpoint_chain = NULL;
int i;
int thread = -1;
int ignore_count = 0;
hardwareflag = flag & BP_HARDWAREFLAG;
tempflag = flag & BP_TEMPFLAG;
sals.sals = NULL;
sals.nelts = 0;
addr_string = NULL;
parse_breakpoint_sals (&arg, &sals, &addr_string);
if (!sals.nelts)
return;
old_chain = make_cleanup (null_cleanup, 0);
make_cleanup (free, sals.sals);
make_cleanup (free, addr_string);
cond = xcalloc (sals.nelts, sizeof (struct expression *));
make_cleanup (free, cond);
cond_string = xcalloc (sals.nelts, sizeof (char **));
make_cleanup (free, cond_string);
breakpoint_chain = make_cleanup (null_cleanup, 0);
for (i = 0; i < sals.nelts; i++)
{
if (addr_string[i] != NULL)
make_cleanup (free, addr_string[i]);
}
breakpoint_sals_to_pc (&sals, addr_start);
thread = -1;
for (i = 0; i < sals.nelts; i++)
{
char *tok = arg;
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[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
make_cleanup (free, cond[i]);
cond_end = tok;
cond_string[i] = savestring (cond_start, cond_end - cond_start);
make_cleanup (free, cond_string[i]);
}
else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
{
char *tmptok;
tok = end_tok + 1;
tmptok = tok;
thread = strtol (tok, &tok, 0);
if (tok == tmptok)
error ("Junk after thread keyword.");
if (!valid_thread_id (thread))
error ("Unknown thread %d\n", thread);
}
else
error ("Junk at end of arguments.");
}
}
create_breakpoints (sals, addr_string, cond, cond_string,
hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
tempflag ? del : donttouch,
thread, ignore_count, from_tty);
if (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);
}
struct captured_breakpoint_args
{
char *address;
char *condition;
int hardwareflag;
int tempflag;
int thread;
int ignore_count;
int futureflag;
};
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 rc = GDB_RC_OK;
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);
b->number = ++breakpoint_count;
b->addr_string = savestring (args->address, strlen (args->address));
b->enable = shlib_disabled;
b->inserted = 0;
b->ignore_count = args->ignore_count;
b->disposition = args->tempflag ? del : donttouch;
b->type = bp_breakpoint;
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 (free, addr_string);
make_cleanup (free, sals.sals);
cond = xcalloc (sals.nelts, sizeof (struct expression *));
make_cleanup (free, cond);
cond_string = xcalloc (sals.nelts, sizeof (char **));
make_cleanup (free, cond_string);
breakpoint_chain = make_cleanup (null_cleanup, 0);
for (i = 0; i < sals.nelts; i++)
{
if (addr_string[i] != NULL)
make_cleanup (free, addr_string[i]);
}
if (*address_end != '\0')
error ("Garbage %s following breakpoint address", address_end);
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 (free, 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 ? del : donttouch,
args->thread, args->ignore_count, 0);
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 thread, int ignore_count, int futureflag)
{
struct captured_breakpoint_args args;
args.address = address;
args.condition = condition;
args.hardwareflag = hardwareflag;
args.tempflag = tempflag;
args.thread = thread;
args.ignore_count = ignore_count;
args.futureflag = futureflag;
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, *level_arg, *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);
free (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;
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);
free (beg_addr_string);
old_chain = make_cleanup (free, 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);
free (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
break_command (char *arg, int from_tty)
{
break_command_1 (arg, 0, from_tty);
}
static void
break_at_finish_command (char *arg, int from_tty)
{
break_at_finish_command_1 (arg, 0, from_tty);
}
static void
break_at_finish_at_depth_command (char *arg, int from_tty)
{
break_at_finish_at_depth_command_1 (arg, 0, from_tty);
}
static int future_break_command_1_tty;
static int
future_break_command_1 (char *args)
{
break_command_1 (args, 0, future_break_command_1_tty);
return 1;
}
static void
future_break_command (char *args, int from_tty)
{
int ret;
if (args == 0 || *args == 0)
{
error ("future-break requires an argument.\n");
}
future_break_command_1_tty = from_tty;
ret = catch_errors (future_break_command_1, args,
"Unable to set breakpoint: ", RETURN_MASK_ALL);
if (!ret)
{
struct symtab_and_line sal =
{0, 0};
struct breakpoint *b = set_raw_breakpoint (sal);
printf_unfiltered
("Will attempt to resolve \"%s\" on future dynamic loads.\n", args);
b->number = ++breakpoint_count;
b->addr_string = savestring (args, strlen (args));
b->enable = shlib_disabled;
b->inserted = 0;
b->disposition = donttouch;
b->type = bp_breakpoint;
if (modify_breakpoint_hook)
modify_breakpoint_hook (b);
}
}
void
tbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_TEMPFLAG, from_tty);
}
static 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
b = set_raw_breakpoint (sal);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = 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 (mem_cnt && target_resources_ok > 0)
b->type = bp_type;
else
b->type = bp_watchpoint;
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);
set_breakpoint_count (breakpoint_count + 1);
scope_breakpoint->number = breakpoint_count;
scope_breakpoint->type = bp_watchpoint_scope;
scope_breakpoint->enable = enabled;
scope_breakpoint->disposition = 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;
}
#ifdef UI_OUT
void
watch_command_wrapper (char *arg, int from_tty)
{
watch_command (arg, from_tty);
}
#endif
static void
watch_command (char *arg, int from_tty)
{
watch_command_1 (arg, hw_write, from_tty);
}
#ifdef UI_OUT
void
rwatch_command_wrapper (char *arg, int from_tty)
{
rwatch_command (arg, from_tty);
}
#endif
static void
rwatch_command (char *arg, int from_tty)
{
watch_command_1 (arg, hw_read, from_tty);
}
#ifdef UI_OUT
void
awatch_command_wrapper (char *arg, int from_tty)
{
awatch_command (arg, from_tty);
}
#endif
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];
free ((PTR) 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);
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);
int nsyms;
register int i;
register struct symbol *sym;
nsyms = BLOCK_NSYMS (b);
for (i = 0; i < nsyms; i++)
{
sym = BLOCK_SYM (b, i);
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 (inferior_pid, 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 (inferior_pid, 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;
if (!sal)
return;
b = set_raw_breakpoint (*sal);
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 = enabled;
b->disposition = tempflag ? del : donttouch;
switch (ex_event)
{
case EX_EVENT_THROW:
b->type = bp_catch_throw;
break;
case EX_EVENT_CATCH:
b->type = bp_catch_catch;
break;
default:
b->type = bp_none;
b->enable = disabled;
error ("Internal error -- invalid catchpoint kind");
}
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);
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);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->type = bp_breakpoint;
b->cond = cond;
b->enable = enabled;
b->disposition = tempflag ? del : 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.");
}
free ((PTR) sals.sals);
}
#if 0
static struct breakpoint *
create_temp_exception_breakpoint (CORE_ADDR pc)
{
struct symtab_and_line sal;
struct breakpoint *b;
INIT_SAL (&sal);
sal.pc = pc;
sal.symtab = NULL;
sal.line = 0;
b = set_raw_breakpoint (sal);
if (!b)
error ("Internal error -- couldn't set temp exception breakpoint");
b->type = bp_breakpoint;
b->disposition = del;
b->enable = enabled;
b->silent = 1;
b->number = internal_breakpoint_number--;
return b;
}
#endif
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);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->type = bp_breakpoint;
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 == 0 ||
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 == 0 ||
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');
}
free ((PTR) 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 == del
&& bs->stop)
delete_breakpoint (bs->breakpoint_at);
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->disposition == 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_uninserted);
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 = 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;
}
if (tui_version)
{
int clearIt;
ALL_BREAKPOINTS (b)
{
clearIt = (b->address != bpt->address);
if (!clearIt)
break;
}
if (clearIt)
{
TUIDO (((TuiOpaqueFuncPtr) tui_vAllSetHasBreakAt, bpt, 0));
TUIDO (((TuiOpaqueFuncPtr) tuiUpdateAllExecInfos));
}
}
check_duplicates (bpt->address, bpt->section);
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 != disabled
&& b->enable != shlib_disabled
&& b->enable != call_disabled)
{
int val;
if (b->enable == permanent)
internal_error ("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)
free (bpt->cond);
if (bpt->cond_string != NULL)
free (bpt->cond_string);
if (bpt->addr_string != NULL)
free (bpt->addr_string);
if (bpt->exp != NULL)
free (bpt->exp);
if (bpt->exp_string != NULL)
free (bpt->exp_string);
if (bpt->val != NULL)
value_free (bpt->val);
if (bpt->source_file != NULL)
free (bpt->source_file);
if (bpt->dll_pathname != NULL)
free (bpt->dll_pathname);
if (bpt->triggered_dll_pathname != NULL)
free (bpt->triggered_dll_pathname);
if (bpt->exec_pathname != NULL)
free (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;
free ((PTR) 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->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->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 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;
}
if (strncmp (b->addr_string, "@metrowerks:", strlen ("@metrowerks:")) == 0)
{
return 0;
}
save_enable = b->enable;
if (b->enable != disabled)
{
b->enable = 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)
free ((PTR) b->cond);
b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0);
}
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)
free (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 = save_enable;
check_duplicates (b->address, b->section);
}
free ((PTR) sals.sals);
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
innermost_block = NULL;
if (b->exp)
free ((PTR) b->exp);
b->exp = parse_expression (b->exp_string);
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)
free ((PTR) b->cond);
b->cond = parse_exp_1 (&s, (struct block *) 0, 0);
}
if (b->enable == enabled)
if (modify_breakpoint_hook)
modify_breakpoint_hook (b);
mention (b);
value_free_to_mark (mark);
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:
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 == 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 ();
#ifdef GET_LONGJMP_TARGET
create_longjmp_breakpoint ("longjmp");
create_longjmp_breakpoint ("_longjmp");
create_longjmp_breakpoint ("siglongjmp");
create_longjmp_breakpoint ("_siglongjmp");
create_longjmp_breakpoint (NULL);
#endif
#if 0
printf_filtered ("\n");
#endif
}
void
breakpoint_re_set_thread (struct breakpoint *b)
{
if (b->thread != -1)
{
if (in_thread_list (inferior_pid))
b->thread = pid_to_thread_id (inferior_pid);
}
}
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);
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 == permanent)
return;
bpt->enable = disabled;
check_duplicates (bpt->address, bpt->section);
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 != permanent)
bpt->enable = enabled;
bpt->disposition = disposition;
check_duplicates (bpt->address, bpt->section);
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 = 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 = 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, 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, del);
}
static void
enable_delete_command (char *args, int from_tty)
{
map_breakpoint_numbers (args, enable_delete_breakpoint);
}
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. ");
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.");
add_com ("txbreak", class_breakpoint, tbreak_at_finish_command,
"Set temporary breakpoint at procedure exit. Either there should\n\
be no argument or the argument must be a depth.\n");
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.");
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.");
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));
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\
Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL));
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);
add_com ("xbreak", class_breakpoint, break_at_finish_command,
concat ("Set breakpoint at procedure exit. \n\
Argument may be function name, or \"*\" and an address.\n\
If function is specified, break at end of code for that function.\n\
If an address is specified, break at the end of the function that contains \n\
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\
Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL));
add_com_alias ("xb", "xbreak", class_breakpoint, 1);
add_com_alias ("xbr", "xbreak", class_breakpoint, 1);
add_com_alias ("xbre", "xbreak", class_breakpoint, 1);
add_com_alias ("xbrea", "xbreak", class_breakpoint, 1);
if (xdb_commands)
{
add_com_alias ("ba", "break", class_breakpoint, 1);
add_com_alias ("bu", "ubreak", class_breakpoint, 1);
add_com ("bx", class_breakpoint, break_at_finish_at_depth_command,
"Set breakpoint at procedure exit. Either there should\n\
be no argument or the argument must be a depth.\n");
}
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.");
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.");
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.");
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.");
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);
can_use_hw_watchpoints = 1;
}
void
do_breakpoint_move (bpt, new_line_number)
struct breakpoint *bpt;
int new_line_number;
{
struct symtab_and_line sal;
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';
free (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];
free ((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 (old_address, bpt->section);
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 != 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)
{
free (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;
}
}