#include "defs.h"
#include <time.h>
#include <ctype.h>
#include "symtab.h"
#include "frame.h"
#include "breakpoint.h"
#include "gdbtypes.h"
#include "expression.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "value.h"
#include "command.h"
#include "inferior.h"
#include "gdbthread.h"
#include "target.h"
#include "language.h"
#include "gdb_string.h"
#include "demangle.h"
#include "annotate.h"
#include "symfile.h"
#include "objfiles.h"
#include "source.h"
#include "linespec.h"
#include "completer.h"
#include "gdb.h"
#include "ui-out.h"
#include "cli/cli-script.h"
#include "cli-out.h"
#include "gdb_assert.h"
#include "block.h"
#include "wrapper.h"
#include "solib.h"
#include "solist.h"
#include "observer.h"
#include "exceptions.h"
#include "gdb_regex.h"
#include "gdb-events.h"
#include "readline/tilde.h"
#include "mi/mi-common.h"
#include "inlining.h"
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 (void *);
static void breakpoint_re_set_all ();
static void clear_command (char *, int);
static void catch_command (char *, int);
static void watch_command (char *, int);
static int can_use_hardware_watchpoint (struct value *);
struct breakpoint_list
{
struct breakpoint_list *next;
struct breakpoint *bp;
};
static int breakpoint_address_is_meaningful (struct breakpoint *);
static int break_command_1 (char *, int, int, struct breakpoint *);
static int break_command_2 (char *, int, int, struct breakpoint *,
char *, int *, struct breakpoint_list **);
static void mention (struct breakpoint *);
struct breakpoint *set_raw_breakpoint (struct symtab_and_line, enum bptype,
int pending_p);
static void check_duplicates (struct breakpoint *);
static void breakpoint_adjustment_warning (CORE_ADDR, CORE_ADDR, int, int);
static CORE_ADDR adjust_breakpoint_address (CORE_ADDR bpaddr,
enum bptype bptype);
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 (void *);
static char *exception_throw_type_regexp;
static char *exception_catch_type_regexp;
static int exception_catchpoint_catch_enabled;
static int exception_catchpoint_throw_enabled;
static int current_exception_should_stop(void);
static void cleanup_executing_breakpoints (void *);
static void commands_command (char *, int);
static void condition_command (char *, int);
static void condition_command_1 (struct breakpoint *b, char *condition, int from_tty);
static int get_number_trailer (char **, int);
static void do_captured_parse_breakpoint (struct ui_out *, void *);
static enum print_stop_action
print_exception_catchpoint (struct breakpoint *b);
static void
print_one_exception_catchpoint (struct breakpoint *b, CORE_ADDR *last_addr);
static void
print_mention_exception_catchpoint (struct breakpoint *b);
static void
async_breakpoint_command_continuation (struct continuation_arg *arg);
void set_breakpoint_count (int);
typedef enum
{
mark_inserted,
mark_uninserted
}
insertion_state_t;
static int remove_breakpoint (struct bp_location *, insertion_state_t);
static enum print_stop_action print_it_typical (bpstat);
static enum print_stop_action print_bp_stop_message (bpstat bs);
typedef struct
{
enum exception_event_kind kind;
int enable_p;
}
args_for_catchpoint_enable;
static int watchpoint_check (void *);
static int cover_target_enable_exception_callback (void *);
static void maintenance_info_breakpoints (char *, int);
static void create_longjmp_breakpoint (char *);
static void create_overlay_event_breakpoint (char *);
static int hw_breakpoint_used_count (void);
static int hw_watchpoint_used_count (enum bptype, int *);
static void hbreak_command (char *, int);
static void thbreak_command (char *, int);
static void watch_command_1 (char *, int, int, 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 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);
static struct breakpoint *create_exception_catchpoint (int tempflag, char *cond_string,
int gnu_v3_p,
enum exception_event_kind ex_event,
struct symtab_and_line *sal);
static void catch_exception_command_1 (enum exception_event_kind ex_event,
char *arg, int tempflag, int from_tty);
static void tcatch_command (char *arg, int from_tty);
static void ep_skip_leading_whitespace (char **s);
static int exception_catchpoint_catch_enabled;
static int exception_catchpoint_throw_enabled;
static void restore_saved_pending_break_support (void * val);
static void breakpoint_sals_to_pc (struct symtabs_and_lines *sals, char *address);
static int safe_breakpoint_sals_to_pc (struct symtabs_and_lines *sals,
char *address);
int symbol_generation = 1;
int breakpoint_generation = 0;
static int dont_mention = 0;
static void set_bp_objfile (struct breakpoint *b, struct symtab_and_line *sal);
static void print_catch_info (struct breakpoint *b);
static int can_use_hw_watchpoints;
static void
show_can_use_hw_watchpoints (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
fprintf_filtered (file, _("\
Debugger's willingness to use watchpoint hardware is %s.\n"),
value);
}
static enum auto_boolean pending_break_support;
static void
show_pending_break_support (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
fprintf_filtered (file, _("\
Debugger's behavior regarding pending breakpoints is %s.\n"),
value);
}
void _initialize_breakpoint (void);
extern int addressprint;
static int executing_breakpoint_commands;
static int overlay_events_enabled;
#define ALL_BREAKPOINTS(B) for (B = breakpoint_chain; B; B = B->next)
#define ALL_BREAKPOINTS_SAFE(B,TMP) \
for (B = breakpoint_chain; \
B ? (TMP=B->next, 1): 0; \
B = TMP)
#define ALL_BP_LOCATIONS(B) for (B = bp_location_chain; B; B = B->next)
#define ALL_BP_LOCATIONS_SAFE(B,TMP) \
for (B = bp_location_chain; \
B ? (TMP=B->next, 1): 0; \
B = TMP)
int show_breakpoint_hit_counts = 1;
struct breakpoint *breakpoint_chain;
struct bp_location *bp_location_chain;
int breakpoint_count;
static void
add_breakpoint_to_new_list (struct breakpoint_list **new_breakpoints,
struct breakpoint *bp)
{
struct breakpoint_list *new_bp = (struct breakpoint_list *)
xmalloc (sizeof (struct breakpoint_list));
new_bp->next = *new_breakpoints;
new_bp->bp = bp;
*new_breakpoints = new_bp;
}
static void
clear_new_breakpoint_list (struct breakpoint_list *new_breakpoints)
{
while (new_breakpoints != NULL)
{
struct breakpoint_list *list_ptr;
list_ptr = new_breakpoints;
new_breakpoints = list_ptr->next;
xfree (list_ptr);
}
}
static struct exception_event_record *current_exception_event;
int deprecated_exception_catchpoints_are_fragile = 0;
int deprecated_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
static int
breakpoint_enabled (struct breakpoint *b)
{
return (b->enable_state == bp_enabled && !b->pending);
}
void
set_breakpoint_count (int num)
{
breakpoint_count = num;
set_internalvar (lookup_internalvar ("bpnum"),
value_from_longest (builtin_type_int, (LONGEST) num));
}
void
clear_breakpoint_hit_counts (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
b->hit_count = 0;
}
int default_breakpoint_valid;
CORE_ADDR default_breakpoint_address;
struct symtab *default_breakpoint_symtab;
int default_breakpoint_line;
static int
get_number_trailer (char **pp, int trailer)
{
int retval = 0;
char *p = *pp;
if (p == NULL)
return breakpoint_count;
else if (*p == '$')
{
char *varname;
char *start = ++p;
struct value *val;
while (isalnum (*p) || *p == '_')
p++;
varname = (char *) alloca (p - start + 1);
strncpy (varname, start, p - start);
varname[p - start] = '\0';
val = value_of_internalvar (lookup_internalvar (varname));
if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
retval = (int) value_as_long (val);
else
{
printf_filtered (_("Convenience variable must have integer value.\n"));
retval = 0;
}
}
else
{
if (*p == '-')
++p;
while (*p >= '0' && *p <= '9')
++p;
if (p == *pp)
{
while (*p && !isspace((int) *p))
++p;
retval = 0;
}
else
retval = atoi (*pp);
}
if (!(isspace (*p) || *p == '\0' || *p == trailer))
{
while (!(isspace (*p) || *p == '\0' || *p == trailer))
++p;
retval = 0;
}
while (isspace (*p))
p++;
*pp = p;
return retval;
}
int
get_number (char **pp)
{
return get_number_trailer (pp, '\0');
}
int
get_number_or_range (char **pp)
{
static int last_retval, end_value;
static char *end_ptr;
static int in_range = 0;
if (**pp != '-')
{
last_retval = get_number_trailer (pp, '-');
if (**pp == '-')
{
char **temp;
temp = &end_ptr;
end_ptr = *pp + 1;
while (isspace ((int) *end_ptr))
end_ptr++;
end_value = get_number (temp);
if (end_value < last_retval)
{
error (_("inverted range"));
}
else if (end_value == last_retval)
{
*pp = end_ptr;
}
else
in_range = 1;
}
}
else if (! in_range)
error (_("negative value"));
else
{
if (++last_retval == end_value)
{
*pp = end_ptr;
in_range = 0;
}
}
return last_retval;
}
static void
condition_command (char *arg, int from_tty)
{
struct breakpoint *b;
char *p;
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)
{
condition_command_1 (b, p, from_tty);
breakpoints_changed ();
breakpoint_modify_event (b->number);
return;
}
error (_("No breakpoint number %d."), bnum);
}
static void
condition_command_1 (struct breakpoint *b, char *condition, int from_tty)
{
if (b->cond)
{
xfree (b->cond);
b->cond = 0;
}
if (b->cond_string != NULL)
xfree (b->cond_string);
if (condition == 0 || *condition == 0)
{
b->cond = 0;
b->cond_string = NULL;
if (from_tty)
printf_filtered ("Breakpoint %d now unconditional.\n", b->number);
}
else
{
int parse_successful;
b->cond_string = savestring (condition, strlen (condition));
if (!b->pending)
{
parse_successful = gdb_parse_exp_1 (&condition,
block_for_pc (b->loc->address),
0, &(b->cond));
if (!parse_successful)
error ("Error parsing breakpoint condition. "
"Will try again when we hit the breakpoint.");
else if (*condition)
error ("Junk at end of expression.");
}
}
return;
}
static void
commands_command (char *arg, int from_tty)
{
struct breakpoint *b;
char *p;
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 = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.",
bnum);
struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
l = read_command_lines (tmpbuf, from_tty);
do_cleanups (cleanups);
free_command_lines (&b->commands);
b->commands = l;
breakpoints_changed ();
breakpoint_modify_event (b->number);
return;
}
error (_("No breakpoint number %d."), bnum);
}
struct breakpoint *
find_breakpoint (int bpnum)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
{
if (b->number == bpnum)
return b;
}
return NULL;
}
void
breakpoint_add_commands (struct breakpoint *b, struct command_line *commands)
{
free_command_lines (&b->commands);
b->commands = commands;
breakpoints_changed ();
breakpoint_modify_event (b->number);
}
void
breakpoint_print_commands (struct ui_out *uiout, struct breakpoint *b)
{
struct cleanup *list_cleanup;
list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "commands");
if (b->commands)
print_command_lines (uiout, b->commands, 0);
do_cleanups (list_cleanup);
}
int
deprecated_read_memory_nobpt (CORE_ADDR memaddr, gdb_byte *myaddr,
unsigned len)
{
int status;
struct bp_location *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_BP_LOCATIONS (b)
{
if (b->owner->type == bp_none)
warning (_("reading through apparently deleted breakpoint #%d?"),
b->owner->number);
if (b->loc_type != bp_loc_software_breakpoint)
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 = deprecated_read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
if (status != 0)
return status;
}
if (bp_addr + bp_size < memaddr + len)
{
status = deprecated_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);
}
static void
insert_catchpoint (struct ui_out *uo, void *args)
{
struct breakpoint *b = (struct breakpoint *) args;
switch (b->type)
{
case bp_catch_fork:
target_insert_fork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_vfork:
target_insert_vfork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_exec:
target_insert_exec_catchpoint (PIDGET (inferior_ptid));
break;
default:
internal_error (__FILE__, __LINE__, _("unknown breakpoint type"));
break;
}
}
static void free_valchain (struct bp_location *b)
{
struct value *v;
struct value *n;
for (v = b->owner->val_chain; v; v = n)
{
n = value_next (v);
value_free (v);
}
b->owner->val_chain = NULL;
}
static int
insert_bp_location (struct bp_location *bpt,
struct ui_file *tmp_error_stream,
int *disabled_breaks, int *process_warning,
int *hw_breakpoint_error)
{
int val = 0;
if (!breakpoint_enabled (bpt->owner))
return 0;
if (bpt->loc_type != bp_loc_hardware_watchpoint
&& !(target_check_is_objfile_loaded (bpt->owner->bp_objfile)
|| (bpt->address != 0x0 && bpt->owner->bp_objfile == NULL)))
{
bpt->inserted = 0;
return 0;
}
if (bpt->inserted || bpt->duplicate)
return 0;
if (bpt->loc_type == bp_loc_software_breakpoint
|| bpt->loc_type == bp_loc_hardware_breakpoint)
{
if (overlay_debugging == ovly_off
|| bpt->section == NULL
|| !(section_is_overlay (bpt->section)))
{
if (bpt->loc_type == bp_loc_hardware_breakpoint)
val = target_insert_hw_breakpoint (bpt->address,
bpt->shadow_contents);
else
val = target_insert_breakpoint (bpt->address,
bpt->shadow_contents);
}
else
{
if (!overlay_events_enabled)
{
if (bpt->loc_type == bp_loc_hardware_breakpoint)
warning (_("hardware breakpoint %d not supported in overlay!"),
bpt->owner->number);
else
{
CORE_ADDR addr = overlay_unmapped_address (bpt->address,
bpt->section);
val = target_insert_breakpoint (addr, bpt->shadow_contents);
if (val != 0)
fprintf_unfiltered (tmp_error_stream,
"Overlay breakpoint %d failed: in ROM?",
bpt->owner->number);
}
}
if (section_is_mapped (bpt->section))
{
if (bpt->loc_type == bp_loc_hardware_breakpoint)
val = target_insert_hw_breakpoint (bpt->address,
bpt->shadow_contents);
else
val = target_insert_breakpoint (bpt->address,
bpt->shadow_contents);
}
else
{
return 0;
}
}
if (val)
{
if (
#if defined (DISABLE_UNSETTABLE_BREAK)
DISABLE_UNSETTABLE_BREAK (bpt->address)
#else
solib_address (bpt->address)
#endif
)
{
val = 0;
bpt->owner->enable_state = bp_shlib_disabled;
if (!*disabled_breaks)
{
fprintf_unfiltered (tmp_error_stream,
"Temporarily disabling shared library breakpoints:\n");
}
*disabled_breaks = 1;
fprintf_unfiltered (tmp_error_stream,
" %d", bpt->owner->number);
}
else
{
#ifdef ONE_PROCESS_WRITETEXT
*process_warning = 1;
#endif
if (bpt->loc_type == bp_loc_hardware_breakpoint)
{
*hw_breakpoint_error = 1;
fprintf_unfiltered (tmp_error_stream,
"Cannot insert hardware breakpoint %d.\n",
bpt->owner->number);
}
else
{
fprintf_unfiltered (tmp_error_stream,
"Cannot insert breakpoint %d.\n",
bpt->owner->number);
fprintf_filtered (tmp_error_stream,
"Error accessing memory address ");
deprecated_print_address_numeric (bpt->address, 1, tmp_error_stream);
fprintf_filtered (tmp_error_stream, ": %s.\n",
safe_strerror (val));
}
}
}
else
bpt->inserted = 1;
return val;
}
else if (bpt->loc_type == bp_loc_hardware_watchpoint
&& bpt->owner->disposition != disp_del_at_next_stop)
{
int within_current_scope;
struct value *mark = value_mark ();
struct value *v;
struct frame_id saved_frame_id;
saved_frame_id = get_frame_id (deprecated_selected_frame);
if (bpt->owner->exp_valid_block == NULL)
within_current_scope = 1;
else
{
struct frame_info *fi;
fi = frame_find_by_id (bpt->owner->watchpoint_frame);
within_current_scope = (fi != NULL);
if (within_current_scope)
select_frame (fi);
}
if (within_current_scope)
{
free_valchain (bpt);
v = evaluate_expression (bpt->owner->exp);
value_contents (v);
value_release_to_mark (mark);
bpt->owner->val_chain = v;
bpt->inserted = 1;
for (; v; v = value_next (v))
{
if (VALUE_LVAL (v) == lval_memory
&& ! value_lazy (v))
{
struct type *vtype = check_typedef (value_type (v));
if (v == bpt->owner->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 (bpt->owner->type == bp_read_watchpoint)
type = hw_read;
else if (bpt->owner->type == bp_access_watchpoint)
type = hw_access;
val = target_insert_watchpoint (addr, len, type);
if (val == -1)
{
bpt->inserted = 0;
}
val = 0;
}
}
}
if (!bpt->inserted)
{
remove_breakpoint (bpt, mark_uninserted);
*hw_breakpoint_error = 1;
fprintf_unfiltered (tmp_error_stream,
"Could not insert hardware watchpoint %d.\n",
bpt->owner->number);
val = -1;
}
}
else
{
printf_filtered (_("\
Hardware watchpoint %d deleted because the program has left the block \n\
in which its expression is valid.\n"),
bpt->owner->number);
if (bpt->owner->related_breakpoint)
bpt->owner->related_breakpoint->disposition = disp_del_at_next_stop;
bpt->owner->disposition = disp_del_at_next_stop;
}
select_frame (frame_find_by_id (saved_frame_id));
return val;
}
else if (ep_is_exception_catchpoint (bpt->owner))
{
val = target_insert_breakpoint (bpt->address, bpt->shadow_contents);
if (val)
{
fprintf_unfiltered (tmp_error_stream,
"Cannot insert catchpoint %d; disabling it.\n",
bpt->owner->number);
fprintf_filtered (tmp_error_stream,
"Error accessing memory address ");
deprecated_print_address_numeric (bpt->address, 1, tmp_error_stream);
fprintf_filtered (tmp_error_stream, ": %s.\n",
safe_strerror (val));
bpt->owner->enable_state = bp_disabled;
}
else
{
char *message = xstrprintf ("Error inserting catchpoint %d:\n",
bpt->owner->number);
struct cleanup *cleanups = make_cleanup (xfree, message);
int val;
args_for_catchpoint_enable args;
args.kind = bpt->owner->type == bp_catch_catch ?
EX_EVENT_CATCH : EX_EVENT_THROW;
args.enable_p = 1;
val = catch_errors (cover_target_enable_exception_callback,
&args, message, RETURN_MASK_ALL);
do_cleanups (cleanups);
if (val != 0 && val != -1)
bpt->inserted = 1;
if (val == -1)
{
fprintf_unfiltered (tmp_error_stream,
"Cannot insert catchpoint %d; disabling it.\n",
bpt->owner->number);
bpt->owner->enable_state = bp_disabled;
}
}
return val;
}
else if (bpt->owner->type == bp_catch_fork
|| bpt->owner->type == bp_catch_vfork
|| bpt->owner->type == bp_catch_exec)
{
struct gdb_exception e = catch_exception (uiout, insert_catchpoint,
bpt->owner, RETURN_MASK_ERROR);
exception_fprintf (gdb_stderr, e, "warning: inserting catchpoint %d: ",
bpt->owner->number);
if (e.reason < 0)
bpt->owner->enable_state = bp_disabled;
else
bpt->inserted = 1;
return 0;
}
return 0;
}
int
insert_breakpoints (void)
{
struct bp_location *b, *temp;
int return_val = 0;
int val = 0;
int disabled_breaks = 0;
int hw_breakpoint_error = 0;
int process_warning = 0;
int retval;
struct ui_file *tmp_error_stream = mem_fileopen ();
make_cleanup_ui_file_delete (tmp_error_stream);
fprintf_unfiltered (tmp_error_stream, "Warning:\n");
breakpoint_update ();
ALL_BP_LOCATIONS_SAFE (b, temp)
{
if (!breakpoint_enabled (b->owner))
continue;
retval = 1;
if ((b->loc_type == bp_loc_hardware_watchpoint
|| b->owner->type == bp_watchpoint) && !b->owner->val)
{
struct value *val;
val = evaluate_expression (b->owner->exp);
release_value (val);
if (value_lazy (val))
{
retval = gdb_value_fetch_lazy (val);
if (retval == 0)
warning ("Could not set watchpoint %d", b->owner->number);
else
b->owner->val = val;
}
}
if (retval)
{
val = insert_bp_location (b, tmp_error_stream,
&disabled_breaks, &process_warning,
&hw_breakpoint_error);
if (val)
return_val = val;
}
}
if (disabled_breaks)
fprintf_unfiltered (tmp_error_stream, "\n");
if (return_val)
{
if (hw_breakpoint_error)
{
fprintf_unfiltered (tmp_error_stream,
"Could not insert hardware breakpoints:\n\
You may have requested too many hardware breakpoints/watchpoints.\n");
}
#ifdef ONE_PROCESS_WRITETEXT
if (process_warning)
fprintf_unfiltered (tmp_error_stream,
"The same program may be running in another process.");
#endif
target_terminal_ours_for_output ();
ui_file_put (tmp_error_stream, (ui_file_put_method_ftype *) ui_file_write,
gdb_stderr);
}
return return_val;
}
int
remove_breakpoints (void)
{
struct bp_location *b;
int retval = 0;
ALL_BP_LOCATIONS (b)
{
if (b->inserted)
{
int val;
val = remove_breakpoint (b, mark_uninserted);
if (val != 0)
{
warning ("Could not remove breakpoint at \"0x%s\".", paddr_nz (b->address));
retval = val;
}
}
}
return retval;
}
int
remove_hw_watchpoints (void)
{
struct bp_location *b;
int val;
ALL_BP_LOCATIONS (b)
{
if (b->inserted && b->loc_type == bp_loc_hardware_watchpoint)
{
val = remove_breakpoint (b, mark_uninserted);
if (val != 0)
return val;
}
}
return 0;
}
int
reattach_breakpoints (int pid)
{
struct bp_location *b;
int val;
struct cleanup *old_chain = save_inferior_ptid ();
inferior_ptid = pid_to_ptid (pid);
ALL_BP_LOCATIONS (b)
{
if (b->inserted)
{
remove_breakpoint (b, mark_inserted);
if (b->loc_type == bp_loc_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
else
val = target_insert_breakpoint (b->address, b->shadow_contents);
if (val != 0)
{
do_cleanups (old_chain);
return val;
}
}
}
do_cleanups (old_chain);
return 0;
}
void
update_breakpoints_after_exec (void)
{
struct breakpoint *b;
struct breakpoint *temp;
mark_breakpoints_out ();
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->type == bp_shlib_event)
{
delete_breakpoint (b);
continue;
}
if (b->type == bp_thread_event || b->type == bp_overlay_event)
{
delete_breakpoint (b);
continue;
}
if (b->type == bp_step_resume)
{
delete_breakpoint (b);
continue;
}
if (b->type == bp_through_sigtramp)
{
delete_breakpoint (b);
continue;
}
if ((b->type == bp_catch_catch) || (b->type == bp_catch_throw))
{
delete_breakpoint (b);
continue;
}
if ((b->type == bp_catch_exec) ||
(b->type == bp_catch_vfork) ||
(b->type == bp_catch_fork))
{
b->loc->address = (CORE_ADDR) NULL;
continue;
}
if (b->type == bp_finish)
{
continue;
}
if (b->addr_string == NULL)
{
delete_breakpoint (b);
continue;
}
b->loc->address = (CORE_ADDR) NULL;
}
create_overlay_event_breakpoint ("_ovly_debug_event");
}
int
detach_breakpoints (int pid)
{
struct bp_location *b;
int val;
struct cleanup *old_chain = save_inferior_ptid ();
if (pid == PIDGET (inferior_ptid))
error (_("Cannot detach breakpoints of inferior_ptid"));
inferior_ptid = pid_to_ptid (pid);
ALL_BP_LOCATIONS (b)
{
if (b->inserted)
{
val = remove_breakpoint (b, mark_inserted);
if (val != 0)
{
do_cleanups (old_chain);
return val;
}
}
}
do_cleanups (old_chain);
return 0;
}
static int
remove_breakpoint (struct bp_location *b, insertion_state_t is)
{
int val;
if (b->owner->enable_state == bp_permanent)
return 0;
if (b->owner->type == bp_none)
warning (_("attempted to remove apparently deleted breakpoint #%d?"),
b->owner->number);
if (b->loc_type == bp_loc_software_breakpoint
|| b->loc_type == bp_loc_hardware_breakpoint)
{
if (overlay_debugging == ovly_off
|| b->section == NULL
|| !(section_is_overlay (b->section)))
{
if (b->loc_type == bp_loc_hardware_breakpoint)
val = target_remove_hw_breakpoint (b->address,
b->shadow_contents);
else
val = target_remove_breakpoint (b->address, b->shadow_contents);
}
else
{
if (!overlay_events_enabled)
{
CORE_ADDR addr = overlay_unmapped_address (b->address,
b->section);
if (b->loc_type == bp_loc_hardware_breakpoint)
target_remove_hw_breakpoint (addr, b->shadow_contents);
else
target_remove_breakpoint (addr, b->shadow_contents);
}
if (b->inserted)
{
if (b->loc_type == bp_loc_hardware_breakpoint)
val = target_remove_hw_breakpoint (b->address,
b->shadow_contents);
else
val = target_remove_breakpoint (b->address,
b->shadow_contents);
}
else
{
val = 0;
}
}
if (val)
return val;
b->inserted = (is == mark_inserted);
}
else if (b->loc_type == bp_loc_hardware_watchpoint
&& breakpoint_enabled (b->owner)
&& !b->duplicate)
{
struct value *v;
b->inserted = (is == mark_inserted);
for (v = b->owner->val_chain; v; v = value_next (v))
{
if (VALUE_LVAL (v) == lval_memory
&& ! value_lazy (v))
{
struct type *vtype = check_typedef (value_type (v));
if (v == b->owner->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->owner->type == bp_read_watchpoint)
type = hw_read;
else if (b->owner->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->owner->number);
}
else if ((b->owner->type == bp_catch_fork ||
b->owner->type == bp_catch_vfork ||
b->owner->type == bp_catch_exec)
&& breakpoint_enabled (b->owner)
&& !b->duplicate)
{
val = -1;
switch (b->owner->type)
{
case bp_catch_fork:
val = target_remove_fork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_vfork:
val = target_remove_vfork_catchpoint (PIDGET (inferior_ptid));
break;
case bp_catch_exec:
val = target_remove_exec_catchpoint (PIDGET (inferior_ptid));
break;
default:
warning (_("Internal error, %s line %d."), __FILE__, __LINE__);
break;
}
if (val)
return val;
b->inserted = (is == mark_inserted);
}
else if ((b->owner->type == bp_catch_catch ||
b->owner->type == bp_catch_throw)
&& breakpoint_enabled (b->owner)
&& !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->owner)
&& b->inserted
&& breakpoint_enabled (b->owner)
&& !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)
{
struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
bpt->inserted = 0;
}
void
breakpoint_init_inferior (enum inf_context context)
{
struct breakpoint *b, *temp;
struct bp_location *bpt;
static int warning_needed = 0;
ALL_BP_LOCATIONS (bpt)
bpt->inserted = 0;
ALL_BREAKPOINTS_SAFE (b, temp)
{
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);
if (context == inf_starting)
{
if (b->val)
value_free (b->val);
b->val = NULL;
}
break;
default:
if (ep_is_exception_catchpoint (b)
&& deprecated_exception_catchpoints_are_fragile)
{
warning_needed = 1;
delete_breakpoint (b);
}
break;
}
}
if (deprecated_exception_catchpoints_are_fragile)
deprecated_exception_support_initialized = 0;
if (warning_needed && (context != inf_exited))
{
warning (_("Exception catchpoints from last run were deleted.\n"
"You must reinsert them explicitly."));
warning_needed = 0;
}
}
enum breakpoint_here
breakpoint_here_p (CORE_ADDR pc)
{
struct bp_location *bpt;
int any_breakpoint_here = 0;
ALL_BP_LOCATIONS (bpt)
{
if (bpt->loc_type != bp_loc_software_breakpoint
&& bpt->loc_type != bp_loc_hardware_breakpoint)
continue;
if ((breakpoint_enabled (bpt->owner)
|| bpt->owner->enable_state == bp_permanent)
&& bpt->address == pc)
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
&& !section_is_mapped (bpt->section))
continue;
else if (bpt->owner->enable_state == bp_permanent)
return permanent_breakpoint_here;
else
any_breakpoint_here = 1;
}
}
return any_breakpoint_here ? ordinary_breakpoint_here : 0;
}
int
breakpoint_inserted_here_p (CORE_ADDR pc)
{
struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
{
if (bpt->loc_type != bp_loc_software_breakpoint
&& bpt->loc_type != bp_loc_hardware_breakpoint)
continue;
if (bpt->inserted
&& bpt->address == pc)
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
&& !section_is_mapped (bpt->section))
continue;
else
return 1;
}
}
return 0;
}
int
software_breakpoint_inserted_here_p (CORE_ADDR pc)
{
struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
{
if (bpt->loc_type != bp_loc_software_breakpoint)
continue;
if ((breakpoint_enabled (bpt->owner)
|| bpt->owner->enable_state == bp_permanent)
&& bpt->inserted
&& bpt->address == pc)
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
&& !section_is_mapped (bpt->section))
continue;
else
return 1;
}
}
return 0;
}
int
breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
{
struct bp_location *bpt;
int thread;
thread = pid_to_thread_id (ptid);
ALL_BP_LOCATIONS (bpt)
{
if (bpt->loc_type != bp_loc_software_breakpoint
&& bpt->loc_type != bp_loc_hardware_breakpoint)
continue;
if ((breakpoint_enabled (bpt->owner)
|| bpt->owner->enable_state == bp_permanent)
&& bpt->address == pc
&& (bpt->owner->thread == -1 || bpt->owner->thread == thread))
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
&& !section_is_mapped (bpt->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)
|| (ep->type == bp_gnu_v3_catch_catch)
|| (ep->type == bp_gnu_v3_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)
|| (ep->type == bp_gnu_v3_catch_catch)
|| (ep->type == bp_gnu_v3_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_command_lines (&p->commands);
xfree (p);
p = q;
}
*bsp = NULL;
}
bpstat
bpstat_copy (bpstat bs)
{
bpstat p = NULL;
bpstat tmp;
bpstat retval = NULL;
if (bs == NULL)
return bs;
for (; bs != NULL; bs = bs->next)
{
tmp = (bpstat) xmalloc (sizeof (*tmp));
memcpy (tmp, bs, sizeof (*tmp));
if (bs->commands != NULL)
tmp->commands = copy_command_lines (bs->commands);
if (bs->old_val != NULL)
tmp->old_val = value_copy (bs->old_val);
if (tmp->old_val != NULL)
release_value (tmp->old_val);
if (p == NULL)
retval = tmp;
else
p->next = tmp;
p = tmp;
}
p->next = NULL;
return retval;
}
bpstat
bpstat_find_breakpoint (bpstat bsp, struct breakpoint *breakpoint)
{
if (bsp == NULL)
return NULL;
for (; bsp != NULL; bsp = bsp->next)
{
if (bsp->breakpoint_at == breakpoint)
return bsp;
}
return NULL;
}
struct breakpoint *
bpstat_find_step_resume_breakpoint (bpstat bsp)
{
int current_thread;
gdb_assert (bsp != NULL);
current_thread = pid_to_thread_id (inferior_ptid);
for (; bsp != NULL; bsp = bsp->next)
{
if ((bsp->breakpoint_at != NULL) &&
(bsp->breakpoint_at->type == bp_step_resume) &&
(bsp->breakpoint_at->thread == current_thread ||
bsp->breakpoint_at->thread == -1))
return bsp->breakpoint_at;
}
internal_error (__FILE__, __LINE__, _("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)
{
free_command_lines (&bs->commands);
if (bs->old_val != NULL)
{
value_free (bs->old_val);
bs->old_val = NULL;
}
}
}
static void
cleanup_executing_breakpoints (void *ignore)
{
executing_breakpoint_commands = 0;
}
void
bpstat_do_actions (bpstat *bsp)
{
bpstat bs;
struct cleanup *old_chain;
int first_command = 0;
bpstat bs_copy;
struct cleanup *bpstat_cleanup_chain;
if (executing_breakpoint_commands)
return;
executing_breakpoint_commands = 1;
old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
top:
if (bsp == NULL)
{
do_cleanups (old_chain);
return;
}
bs_copy = bpstat_copy (*bsp);
bpstat_cleanup_chain = make_cleanup ((void (*) (void *)) bpstat_clear,
&bs_copy);
bpstat_clear_actions (*bsp);
breakpoint_proceeded = 0;
for (bs = bs_copy; bs != NULL; bs = bs->next)
{
struct command_line *cmd;
cmd = bs->commands;
while (cmd != NULL)
{
first_command++;
execute_control_command (cmd);
if (breakpoint_proceeded)
break;
else
cmd = cmd->next;
}
if (breakpoint_proceeded)
{
if (target_can_async_p() && target_executing)
{
if (!ui_out_is_mi_like_p (uiout))
add_continuation (async_breakpoint_command_continuation, NULL);
break;
}
else
{
do_cleanups (bpstat_cleanup_chain);
goto top;
}
}
}
if (!breakpoint_proceeded && first_command && ui_out_is_mi_like_p (uiout))
{
struct cleanup *notify_cleanup =
make_cleanup_ui_out_notify_begin_end (uiout, "breakpoint-command-completed");
do_cleanups (notify_cleanup);
}
do_cleanups (old_chain);
}
static void
async_breakpoint_command_continuation (struct continuation_arg *arg)
{
bpstat_do_actions (&stop_bpstat);
}
static enum print_stop_action
print_it_typical (bpstat bs)
{
struct cleanup *old_chain, *ui_out_chain;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
if (bs->breakpoint_at == NULL)
return PRINT_UNKNOWN;
switch (bs->breakpoint_at->type)
{
case bp_breakpoint:
case bp_inlined_breakpoint:
case bp_hardware_breakpoint:
if (bs->breakpoint_at->loc->address != bs->breakpoint_at->loc->requested_address)
breakpoint_adjustment_warning (bs->breakpoint_at->loc->requested_address,
bs->breakpoint_at->loc->address,
bs->breakpoint_at->number, 1);
annotate_breakpoint (bs->breakpoint_at->number);
ui_out_text (uiout, "\nBreakpoint ");
ui_out_print_annotation_string (uiout, 0, "reason", async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
if (ui_out_is_mi_like_p (uiout))
{
bpstat bpstat_ptr;
int any_commands = 0;
for (bpstat_ptr = bs;
bpstat_ptr != NULL;
bpstat_ptr = bpstat_ptr->next)
{
if (bpstat_ptr->commands != NULL)
{
any_commands = 1;
break;
}
}
if (any_commands)
ui_out_field_string (uiout, "commands", "yes");
else
ui_out_field_string (uiout, "commands", "no");
}
ui_out_print_annotation_int (uiout, 0, "times", bs->breakpoint_at->hit_count);
ui_out_print_annotation_int (uiout, 1, "bkptno", bs->breakpoint_at->number);
ui_out_text (uiout, ", ");
return PRINT_SRC_AND_LOC;
break;
case bp_shlib_event:
ui_out_print_annotation_string (uiout, 0, "reason", "shlib-event");
ui_out_text (uiout, "Stopped due to shared library event\n");
return PRINT_NOTHING;
break;
case bp_thread_event:
printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n"));
return PRINT_NOTHING;
break;
case bp_overlay_event:
printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n"));
return PRINT_NOTHING;
break;
case bp_catch_load:
annotate_catchpoint (bs->breakpoint_at->number);
printf_filtered (_("\nCatchpoint %d (loaded %s), "),
bs->breakpoint_at->number,
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 (unloaded %s), "),
bs->breakpoint_at->number,
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 (forked process %d), "),
bs->breakpoint_at->number,
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 (vforked process %d), "),
bs->breakpoint_at->number,
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:
case bp_catch_throw:
case bp_gnu_v3_catch_catch:
case bp_gnu_v3_catch_throw:
return print_exception_catchpoint (bs->breakpoint_at);
case bp_watchpoint:
case bp_hardware_watchpoint:
if (bs->old_val != NULL)
{
annotate_watchpoint (bs->breakpoint_at->number);
ui_out_print_annotation_string (uiout, 0, "reason",
async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
mention (bs->breakpoint_at);
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (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);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
value_free (bs->old_val);
bs->old_val = NULL;
}
return PRINT_UNKNOWN;
break;
case bp_read_watchpoint:
ui_out_print_annotation_string (uiout, 0, "reason",
async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
mention (bs->breakpoint_at);
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (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);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
return PRINT_UNKNOWN;
break;
case bp_access_watchpoint:
if (bs->old_val != NULL)
{
annotate_watchpoint (bs->breakpoint_at->number);
ui_out_print_annotation_string (uiout, 0, "reason",
async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
mention (bs->breakpoint_at);
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (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);
ui_out_print_annotation_string (uiout, 0, "reason",
async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
}
value_print (bs->breakpoint_at->val, stb->stream, 0,Val_pretty_default);
ui_out_field_stream (uiout, "new", stb);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
return PRINT_UNKNOWN;
break;
case bp_finish:
ui_out_print_annotation_string (uiout, 0, "reason",
async_reason_lookup (EXEC_ASYNC_FUNCTION_FINISHED));
return PRINT_UNKNOWN;
break;
case bp_until:
ui_out_print_annotation_string (uiout, 0, "reason", "location-reached");
return PRINT_UNKNOWN;
break;
case bp_none:
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
default:
return PRINT_UNKNOWN;
}
}
static void
print_catch_info (struct breakpoint *b)
{
char * event_type;
if (CURRENT_EXCEPTION_KIND == EX_EVENT_THROW)
event_type = "throw";
else
event_type = "catch";
ui_out_text (uiout, "\nCatchpoint ");
ui_out_field_int (uiout, "breakpoint",
b->number);
ui_out_text (uiout, " (exception caught), throw location ");
if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
{
ui_out_field_string (uiout, "throw-file", CURRENT_EXCEPTION_THROW_FILE);
ui_out_text (uiout, ":");
ui_out_field_int (uiout, "throw-line", CURRENT_EXCEPTION_THROW_LINE);
}
else
{
ui_out_field_skip (uiout, "throw-file");
ui_out_text (uiout, "unknown");
ui_out_field_skip (uiout, "throw-line");
}
ui_out_text (uiout, ", catch location ");
if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
{
ui_out_field_string (uiout, "catch-file", CURRENT_EXCEPTION_CATCH_FILE);
ui_out_text (uiout, ":");
ui_out_field_int (uiout, "catch-line", CURRENT_EXCEPTION_CATCH_LINE);
}
else
{
ui_out_field_skip (uiout, "catch-file");
ui_out_text (uiout, "unknown");
ui_out_field_skip (uiout, "catch-line");
}
ui_out_text (uiout, ", exception type ");
if (CURRENT_EXCEPTION_TYPE)
ui_out_field_string (uiout, "exception-type",
CURRENT_EXCEPTION_TYPE);
else
{
ui_out_field_skip (uiout, "exception-type");
ui_out_text (uiout, "unknown");
}
ui_out_text (uiout, "\n");
}
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:
if (bs->breakpoint_at != NULL && bs->breakpoint_at->ops != NULL
&& bs->breakpoint_at->ops->print_it != NULL)
return bs->breakpoint_at->ops->print_it (bs->breakpoint_at);
else
return print_it_typical (bs);
break;
default:
internal_error (__FILE__, __LINE__,
_("print_bp_stop_message: unrecognized enum value"));
break;
}
}
enum print_stop_action
bpstat_print (bpstat bs)
{
int val;
for (; bs; bs = bs->next)
{
val = print_bp_stop_message (bs);
if (val == PRINT_SRC_ONLY
|| val == PRINT_SRC_AND_LOC
|| val == PRINT_NOTHING)
return val;
}
return PRINT_UNKNOWN;
}
static int
breakpoint_cond_eval (void *exp)
{
struct value *mark = value_mark ();
int i = !value_true (evaluate_expression ((struct expression *) exp));
value_free_to_mark (mark);
return i;
}
static bpstat
bpstat_alloc (struct breakpoint *b, bpstat cbs )
{
bpstat bs;
bs = (bpstat) xmalloc (sizeof (*bs));
cbs->next = bs;
bs->breakpoint_at = b;
bs->commands = NULL;
bs->old_val = NULL;
bs->print_it = print_it_normal;
return bs;
}
static int
watchpoint_equal (struct value *arg1, struct value *arg2)
{
const gdb_byte *p1, *p2;
if ((TYPE_CODE (value_type (arg1)) == TYPE_CODE_ARRAY)
&& (TYPE_CODE (value_type (arg2)) == TYPE_CODE_ARRAY))
{
int len = TYPE_LENGTH (value_type (arg1));
if (TYPE_LENGTH (value_type (arg1)) != TYPE_LENGTH (value_type (arg2)))
return 0;
p1 = value_contents (arg1);
p2 = value_contents (arg2);
while (--len >= 0)
{
if (*p1++ != *p2++)
break;
}
return len < 0;
}
return value_equal (arg1, arg2);
}
#define WP_DELETED 1
#define WP_VALUE_CHANGED 2
#define WP_VALUE_NOT_CHANGED 3
#define BP_TEMPFLAG 1
#define BP_HARDWAREFLAG 2
#define BP_FUTUREFLAG 4
static int
watchpoint_check (void *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 = frame_find_by_id (b->watchpoint_frame);
within_current_scope = (fr != NULL);
if ((!within_current_scope || fr == get_current_frame ())
&& gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ()))
return WP_VALUE_NOT_CHANGED;
if (fr && within_current_scope)
select_frame (fr);
}
if (within_current_scope)
{
if (b->val)
{
struct value *mark = value_mark ();
struct value *new_val = evaluate_expression (bs->breakpoint_at->exp);
if (!watchpoint_equal (b->val, new_val))
{
release_value (new_val);
value_free_to_mark (mark);
bs->old_val = b->val;
b->val = new_val;
return WP_VALUE_CHANGED;
}
else
{
value_free_to_mark (mark);
return WP_VALUE_NOT_CHANGED;
}
}
else
return WP_VALUE_NOT_CHANGED;
}
else
{
ui_out_print_annotation_string (uiout, 0, "reason",
async_reason_lookup (EXEC_ASYNC_WATCHPOINT_SCOPE));
ui_out_text (uiout, "\nWatchpoint ");
ui_out_field_int (uiout, "wpnum", bs->breakpoint_at->number);
ui_out_text (uiout, " deleted because the program has left the block in\n\
which its expression is valid.\n");
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
return WP_DELETED;
}
}
bpstat
bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid, int stopped_by_watchpoint)
{
struct breakpoint *b, *temp;
int real_breakpoint = 0;
struct bpstats root_bs[1];
bpstat bs = root_bs;
int thread_id = pid_to_thread_id (ptid);
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
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
&& b->type != bp_gnu_v3_catch_catch
&& b->type != bp_gnu_v3_catch_throw)
{
if (b->loc->address != bp_addr)
continue;
if (overlay_debugging
&& section_is_overlay (b->loc->section)
&& !section_is_mapped (b->loc->section))
continue;
}
if ((b->type == bp_hardware_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint)
&& !stopped_by_watchpoint)
continue;
if (b->type == bp_hardware_breakpoint)
{
if (b->loc->address != bp_addr)
continue;
if (overlay_debugging
&& section_is_overlay (b->loc->section)
&& !section_is_mapped (b->loc->section))
continue;
}
if ((b->type == bp_catch_load)
#if defined(SOLIB_HAVE_LOAD_EVENT)
&& (!SOLIB_HAVE_LOAD_EVENT (PIDGET (inferior_ptid))
|| ((b->dll_pathname != NULL)
&& (strcmp (b->dll_pathname,
SOLIB_LOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid)))
!= 0)))
#endif
)
continue;
if ((b->type == bp_catch_unload)
#if defined(SOLIB_HAVE_UNLOAD_EVENT)
&& (!SOLIB_HAVE_UNLOAD_EVENT (PIDGET (inferior_ptid))
|| ((b->dll_pathname != NULL)
&& (strcmp (b->dll_pathname,
SOLIB_UNLOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid)))
!= 0)))
#endif
)
continue;
if ((b->type == bp_catch_fork)
&& !inferior_has_forked (PIDGET (inferior_ptid),
&b->forked_inferior_pid))
continue;
if ((b->type == bp_catch_vfork)
&& !inferior_has_vforked (PIDGET (inferior_ptid),
&b->forked_inferior_pid))
continue;
if ((b->type == bp_catch_exec)
&& !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname))
continue;
if (ep_is_exception_catchpoint (b))
{
if (b->loc->address != bp_addr)
continue;
if (!(current_exception_event = target_get_current_exception_event ()))
continue;
}
bs = bpstat_alloc (b, bs);
bs->stop = 1;
bs->print = 1;
if (ep_is_exception_catchpoint (b))
{
if (!current_exception_should_stop()) {
bs->stop = 0;
bs->print_it = print_it_noop;
continue;
}
}
else if (b->type == bp_watchpoint ||
b->type == bp_hardware_watchpoint)
{
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
b->number);
struct cleanup *cleanups = make_cleanup (xfree, message);
int e = catch_errors (watchpoint_check, bs, message,
RETURN_MASK_ALL);
do_cleanups (cleanups);
switch (e)
{
case WP_DELETED:
bs->print_it = print_it_done;
break;
case WP_VALUE_CHANGED:
++(b->hit_count);
break;
case WP_VALUE_NOT_CHANGED:
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
default:
case 0:
printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
bs->print_it = print_it_done;
break;
}
}
else if (b->type == bp_read_watchpoint ||
b->type == bp_access_watchpoint)
{
CORE_ADDR addr;
struct value *v;
int found = 0;
if (!target_stopped_data_address (¤t_target, &addr))
continue;
for (v = b->val_chain; v; v = value_next (v))
{
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)
{
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
b->number);
struct cleanup *cleanups = make_cleanup (xfree, message);
int e = catch_errors (watchpoint_check, bs, message,
RETURN_MASK_ALL);
do_cleanups (cleanups);
switch (e)
{
case WP_DELETED:
bs->print_it = print_it_done;
break;
case WP_VALUE_CHANGED:
if (b->type == bp_read_watchpoint)
{
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
}
++(b->hit_count);
break;
case WP_VALUE_NOT_CHANGED:
++(b->hit_count);
break;
default:
case 0:
printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
bs->print_it = print_it_done;
break;
}
}
else
{
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
}
}
else
{
++(b->hit_count);
real_breakpoint = 1;
}
if (frame_id_p (b->frame_id)
&& !frame_id_eq (b->frame_id, get_frame_id (get_current_frame ()))
&& (get_frame_type (get_current_frame ()) != INLINED_FRAME
|| !frame_id_eq (step_frame_id, b->frame_id)))
bs->stop = 0;
else
{
int value_is_zero = 0;
if (b->type == bp_inlined_breakpoint)
inlined_subroutine_adjust_position_for_breakpoint (b);
if (b->cond_string)
{
int parse_succeeded = 1;
select_frame (get_current_frame ());
if (b->cond == NULL)
{
char *s = b->cond_string;
parse_succeeded = gdb_parse_exp_1 (&s, get_selected_block (NULL),
0, &(b->cond));
}
if (parse_succeeded)
{
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->thread != -1 && b->thread != thread_id)
{
bs->stop = 0;
--(b->hit_count);
}
else if (b->ignore_count > 0)
{
b->ignore_count--;
annotate_ignore_count_change ();
bs->stop = 0;
}
else
{
if (b->disposition == disp_disable)
b->enable_state = bp_disabled;
if (b->silent)
bs->print = 0;
bs->commands = b->commands;
if (bs->commands &&
(strcmp ("silent", bs->commands->line) == 0
|| (xdb_commands && strcmp ("Q", bs->commands->line) == 0)))
{
bs->commands = bs->commands->next;
bs->print = 0;
}
bs->commands = copy_command_lines (bs->commands);
}
}
if (bs->stop == 0 || bs->print == 0)
bs->print_it = print_it_noop;
}
bs->next = NULL;
bs = root_bs->next;
if (bs && !bs->stop)
{
switch (bs->breakpoint_at->type)
{
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
remove_breakpoints ();
insert_breakpoints ();
break;
default:
break;
}
}
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_inlined_breakpoint:
case bp_hardware_breakpoint:
case bp_until:
case bp_finish:
if (bs->stop)
{
if (bs->print)
bs_class = bp_noisy;
else
bs_class = bp_silent;
}
else
bs_class = bp_nostop;
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
if (bs->stop)
{
if (bs->print)
bs_class = wp_noisy;
else
bs_class = wp_silent;
}
else
bs_class = no_effect;
break;
case bp_longjmp:
bs_class = long_jump;
break;
case bp_longjmp_resume:
bs_class = long_resume;
break;
case bp_step_resume:
if (bs->stop)
{
bs_class = step_resume;
}
else
bs_class = bp_nostop;
break;
case bp_through_sigtramp:
bs_class = through_sig;
break;
case bp_watchpoint_scope:
bs_class = bp_nostop;
break;
case bp_shlib_event:
bs_class = shlib_event;
break;
case bp_thread_event:
case bp_overlay_event:
bs_class = bp_nostop;
break;
case bp_catch_load:
case bp_catch_unload:
if (bs->stop)
bs_class = catch_shlib_event;
else
bs_class = no_effect;
break;
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
if (bs->stop)
{
if (bs->print)
bs_class = bp_noisy;
else
bs_class = bp_silent;
}
else
bs_class = no_effect;
break;
case bp_catch_catch:
if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_CATCH)
bs_class = bp_nostop;
else if (bs->stop)
bs_class = bs->print ? bp_noisy : bp_silent;
break;
case bp_catch_throw:
if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_THROW)
bs_class = bp_nostop;
else if (bs->stop)
bs_class = bs->print ? bp_noisy : bp_silent;
break;
case bp_gnu_v3_catch_catch:
case bp_gnu_v3_catch_throw:
if (bs->stop)
bs_class = bs->print ? bp_noisy : bp_silent;
break;
case bp_call_dummy:
bs_class = bp_silent;
retval.call_dummy = 1;
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
break;
}
current_action = table[(int) bs_class][(int) current_action];
}
retval.main_action = current_action;
return retval;
}
int
bpstat_should_step (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (breakpoint_enabled (b) && b->type == bp_watchpoint)
return 1;
return 0;
}
int
bpstat_have_active_hw_watchpoints (void)
{
struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
if (breakpoint_enabled (bpt->owner)
&& bpt->inserted
&& bpt->loc_type == bp_loc_hardware_watchpoint)
return 1;
return 0;
}
void
bpstat_get_triggered_catchpoints (bpstat ep_list, bpstat *cp_list)
{
struct bpstats root_bs[1];
bpstat bs = root_bs;
struct breakpoint *ep;
char *dll_pathname;
bpstat_clear (cp_list);
root_bs->next = NULL;
for (; ep_list != NULL; ep_list = ep_list->next)
{
ep = ep_list->breakpoint_at;
if (ep == NULL)
break;
if ((ep->type != bp_catch_load) &&
(ep->type != bp_catch_unload) &&
(ep->type != bp_catch_catch) &&
(ep->type != bp_catch_throw))
continue;
bs = bpstat_alloc (ep, bs);
*bs = *ep_list;
bs->next = NULL;
bs = root_bs->next;
#if defined(SOLIB_ADD)
if (ep->triggered_dll_pathname != NULL)
xfree (ep->triggered_dll_pathname);
if (ep->type == bp_catch_load)
dll_pathname = SOLIB_LOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid));
else
dll_pathname = SOLIB_UNLOADED_LIBRARY_PATHNAME (
PIDGET (inferior_ptid));
#else
dll_pathname = NULL;
#endif
if (dll_pathname)
{
ep->triggered_dll_pathname = (char *)
xmalloc (strlen (dll_pathname) + 1);
strcpy (ep->triggered_dll_pathname, dll_pathname);
}
else
ep->triggered_dll_pathname = NULL;
}
*cp_list = bs;
}
static void
print_one_breakpoint (struct breakpoint *b,
CORE_ADDR *last_addr)
{
struct command_line *l;
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_inlined_breakpoint, "inlined subroutine breakpoint"},
{bp_hardware_breakpoint, "hw breakpoint"},
{bp_until, "until"},
{bp_finish, "finish"},
{bp_watchpoint, "watchpoint"},
{bp_hardware_watchpoint, "hw watchpoint"},
{bp_read_watchpoint, "read watchpoint"},
{bp_access_watchpoint, "acc watchpoint"},
{bp_longjmp, "longjmp"},
{bp_longjmp_resume, "longjmp resume"},
{bp_step_resume, "step resume"},
{bp_through_sigtramp, "sigtramp"},
{bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"},
{bp_shlib_event, "shlib events"},
{bp_thread_event, "thread events"},
{bp_overlay_event, "overlay events"},
{bp_catch_load, "catch load"},
{bp_catch_unload, "catch unload"},
{bp_catch_fork, "catch fork"},
{bp_catch_vfork, "catch vfork"},
{bp_catch_exec, "catch exec"},
{bp_catch_catch, "catch catch"},
{bp_catch_throw, "catch throw"}
, {bp_gnu_v3_catch_catch, "catch catch"}
, {bp_gnu_v3_catch_throw, "catch throw"}
};
static char *bpdisps[] =
{"del", "dstp", "dis", "keep"};
static char bpenables[] = "nyscp";
char wrap_indent[80];
struct ui_stream *stb = ui_out_stream_new (uiout);
struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
struct cleanup *bkpt_chain;
annotate_record ();
bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "bkpt");
annotate_field (0);
ui_out_field_int (uiout, "number", b->number);
annotate_field (1);
if (((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
|| ((int) b->type != bptypes[(int) b->type].type))
internal_error (__FILE__, __LINE__,
_("bptypes table does not describe type #%d."),
(int) b->type);
ui_out_field_string (uiout, "type", bptypes[(int) b->type].description);
annotate_field (2);
ui_out_field_string (uiout, "disp", bpdisps[(int) b->disposition]);
annotate_field (3);
ui_out_field_fmt (uiout, "enabled", "%c", bpenables[(int) b->enable_state]);
ui_out_spaces (uiout, 2);
strcpy (wrap_indent, " ");
if (addressprint)
{
if (TARGET_ADDR_BIT <= 32)
strcat (wrap_indent, " ");
else
strcat (wrap_indent, " ");
}
if (b->ops != NULL && b->ops->print_one != NULL)
b->ops->print_one (b, last_addr);
else
switch (b->type)
{
case bp_none:
internal_error (__FILE__, __LINE__,
_("print_one_breakpoint: bp_none encountered\n"));
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
gdb_print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "what", stb);
break;
case bp_catch_load:
case bp_catch_unload:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
if (b->dll_pathname == NULL)
{
ui_out_field_string (uiout, "what", "<any library>");
ui_out_spaces (uiout, 1);
}
else
{
ui_out_text (uiout, "library \"");
ui_out_field_string (uiout, "what", b->dll_pathname);
ui_out_text (uiout, "\" ");
}
break;
case bp_catch_fork:
case bp_catch_vfork:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
if (b->forked_inferior_pid != 0)
{
ui_out_text (uiout, "process ");
ui_out_field_int (uiout, "what", b->forked_inferior_pid);
ui_out_spaces (uiout, 1);
}
case bp_catch_exec:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
if (b->exec_pathname != NULL)
{
ui_out_text (uiout, "program \"");
ui_out_field_string (uiout, "what", b->exec_pathname);
ui_out_text (uiout, "\" ");
}
break;
case bp_catch_catch:
case bp_gnu_v3_catch_catch:
case bp_catch_throw:
case bp_gnu_v3_catch_throw:
print_one_exception_catchpoint (b, 0);
case bp_breakpoint:
case bp_inlined_breakpoint:
case bp_hardware_breakpoint:
case bp_until:
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
if (addressprint)
{
annotate_field (4);
if (b->pending)
ui_out_field_string (uiout, "addr", "<PENDING>");
else
ui_out_field_core_addr (uiout, "addr", b->loc->address);
}
annotate_field (5);
*last_addr = b->loc->address;
if (b->source_file)
{
sym = find_pc_sect_function (b->loc->address, b->loc->section);
if (sym)
{
ui_out_text (uiout, "in ");
ui_out_field_string (uiout, "func",
SYMBOL_PRINT_NAME (sym));
ui_out_wrap_hint (uiout, wrap_indent);
ui_out_text (uiout, " at ");
}
ui_out_field_string (uiout, "file", b->source_file);
ui_out_text (uiout, ":");
ui_out_field_int (uiout, "line", b->line_number);
}
else if (b->pending)
{
ui_out_field_string (uiout, "pending", b->addr_string);
}
else
{
print_address_symbolic (b->loc->address, stb->stream, demangle, "");
ui_out_field_stream (uiout, "at", stb);
}
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
}
if (b->thread != -1)
{
ui_out_text (uiout, " thread ");
ui_out_field_int (uiout, "thread", b->thread);
}
if (ui_out_is_mi_like_p (uiout) && b->bp_objfile != NULL)
{
if (b->bp_objfile->name != NULL)
ui_out_field_string (uiout, "shlib", b->bp_objfile->name);
else
ui_out_field_skip (uiout, "shlib");
}
ui_out_text (uiout, "\n");
if (frame_id_p (b->frame_id))
{
annotate_field (6);
ui_out_text (uiout, "\tstop only in stack frame at ");
ui_out_field_core_addr (uiout, "frame", b->frame_id.stack_addr);
ui_out_text (uiout, "\n");
}
if (b->cond || b->cond_string)
{
struct ui_file *prev_stderr = gdb_stderr;
annotate_field (7);
gdb_stderr = gdb_null;
if (b->cond && gdb_print_expression (b->cond, stb->stream))
{
ui_out_text (uiout, "\tstop only if ");
ui_out_field_stream (uiout, "cond", stb);
}
else
{
if (b->cond_string)
{
ui_out_text (uiout, "\tcondition not yet parsed: ");
ui_out_field_string (uiout, "cond", b->cond_string);
}
else
ui_out_field_string (uiout, "cond", "Error printing condition string");
}
ui_out_text (uiout, "\n");
gdb_stderr = prev_stderr;
}
if (b->pending && b->cond_string)
{
annotate_field (7);
ui_out_text (uiout, "\tstop only if ");
ui_out_field_string (uiout, "cond", b->cond_string);
ui_out_text (uiout, "\n");
}
if (b->thread != -1)
{
ui_out_text (uiout, "\tstop only in thread ");
ui_out_field_int (uiout, "thread", b->thread);
ui_out_text (uiout, "\n");
}
if (show_breakpoint_hit_counts && b->hit_count)
{
if (ep_is_catchpoint (b))
ui_out_text (uiout, "\tcatchpoint");
else
ui_out_text (uiout, "\tbreakpoint");
ui_out_text (uiout, " already hit ");
ui_out_field_int (uiout, "times", b->hit_count);
if (b->hit_count == 1)
ui_out_text (uiout, " time\n");
else
ui_out_text (uiout, " times\n");
}
if (ui_out_is_mi_like_p (uiout))
if (show_breakpoint_hit_counts && b->hit_count == 0)
ui_out_field_int (uiout, "times", b->hit_count);
if (b->ignore_count)
{
annotate_field (8);
ui_out_text (uiout, "\tignore next ");
ui_out_field_int (uiout, "ignore", b->ignore_count);
ui_out_text (uiout, " hits\n");
}
if ((l = b->commands))
{
struct cleanup *script_chain;
annotate_field (9);
script_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "commands");
print_command_lines (uiout, l, 4);
do_cleanups (script_chain);
}
do_cleanups (bkpt_chain);
do_cleanups (old_chain);
}
struct captured_breakpoint_query_args
{
int bnum;
};
static int
do_captured_breakpoint_query (struct ui_out *uiout, void *data)
{
struct captured_breakpoint_query_args *args = data;
struct breakpoint *b;
CORE_ADDR dummy_addr = 0;
ALL_BREAKPOINTS (b)
{
if (args->bnum == b->number)
{
print_one_breakpoint (b, &dummy_addr);
return GDB_RC_OK;
}
}
return GDB_RC_NONE;
}
enum gdb_rc
gdb_breakpoint_query (struct ui_out *uiout, int bnum, char **error_message)
{
struct captured_breakpoint_query_args args;
args.bnum = bnum;
return catch_exceptions_with_msg (uiout, do_captured_breakpoint_query, &args,
error_message, RETURN_MASK_ALL);
}
static int
user_settable_breakpoint (const struct breakpoint *b)
{
return (b->type == bp_breakpoint
|| b->type == bp_inlined_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_gnu_v3_catch_catch
|| b->type == bp_gnu_v3_catch_throw
|| b->type == bp_hardware_breakpoint
|| b->type == bp_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint
|| b->type == bp_hardware_watchpoint);
}
static void
breakpoint_1 (int bnum, int allflag)
{
struct breakpoint *b;
CORE_ADDR last_addr = (CORE_ADDR) -1;
int nr_printable_breakpoints;
struct cleanup *bkpttbl_chain;
nr_printable_breakpoints = 0;
ALL_BREAKPOINTS (b)
if (bnum == -1
|| bnum == b->number)
{
if (allflag || user_settable_breakpoint (b))
nr_printable_breakpoints++;
}
if (addressprint)
bkpttbl_chain
= make_cleanup_ui_out_table_begin_end (uiout, 6, nr_printable_breakpoints,
"BreakpointTable");
else
bkpttbl_chain
= make_cleanup_ui_out_table_begin_end (uiout, 5, nr_printable_breakpoints,
"BreakpointTable");
if (nr_printable_breakpoints > 0)
annotate_breakpoints_headers ();
if (nr_printable_breakpoints > 0)
annotate_field (0);
ui_out_table_header (uiout, 3, ui_left, "number", "Num");
if (nr_printable_breakpoints > 0)
annotate_field (1);
ui_out_table_header (uiout, 14, ui_left, "type", "Type");
if (nr_printable_breakpoints > 0)
annotate_field (2);
ui_out_table_header (uiout, 4, ui_left, "disp", "Disp");
if (nr_printable_breakpoints > 0)
annotate_field (3);
ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");
if (addressprint)
{
if (nr_printable_breakpoints > 0)
annotate_field (4);
if (TARGET_ADDR_BIT <= 32)
ui_out_table_header (uiout, 10, ui_left, "addr", "Address");
else
ui_out_table_header (uiout, 18, ui_left, "addr", "Address");
}
if (nr_printable_breakpoints > 0)
annotate_field (5);
ui_out_table_header (uiout, 40, ui_noalign, "what", "What");
ui_out_table_body (uiout);
if (nr_printable_breakpoints > 0)
annotate_breakpoints_table ();
ALL_BREAKPOINTS (b)
if (bnum == -1
|| bnum == b->number)
{
if (allflag || user_settable_breakpoint (b))
print_one_breakpoint (b, &last_addr);
}
do_cleanups (bkpttbl_chain);
if (nr_printable_breakpoints == 0)
{
if (bnum == -1)
ui_out_message (uiout, 0, "No breakpoints or watchpoints.\n");
else
ui_out_message (uiout, 0, "No breakpoint or watchpoint number %d.\n",
bnum);
}
else
{
if (last_addr != (CORE_ADDR) -1)
set_next_address (last_addr);
}
annotate_breakpoints_table_end ();
}
static void
breakpoints_info (char *bnum_exp, int from_tty)
{
int bnum = -1;
if (bnum_exp)
bnum = parse_and_eval_long (bnum_exp);
breakpoint_1 (bnum, 0);
}
static void
maintenance_info_breakpoints (char *bnum_exp, int from_tty)
{
int bnum = -1;
if (bnum_exp)
bnum = parse_and_eval_long (bnum_exp);
breakpoint_1 (bnum, 1);
}
static void
describe_other_breakpoints (CORE_ADDR pc, asection *section)
{
int others = 0;
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->loc->address == pc)
if (!b->pending && (!overlay_debugging || b->loc->section == section)
&& breakpoint_address_is_meaningful (b))
others++;
if (others > 0)
{
if (others == 1)
printf_filtered (_("Note: breakpoint "));
else
printf_filtered (_("Note: breakpoints "));
ALL_BREAKPOINTS (b)
if (b->loc->address == pc)
if (!b->pending && (!overlay_debugging || b->loc->section == section)
&& breakpoint_address_is_meaningful (b))
{
others--;
printf_filtered ("%d%s%s ",
b->number,
((b->enable_state == bp_disabled ||
b->enable_state == bp_shlib_disabled ||
b->enable_state == bp_call_disabled)
? " (disabled)"
: b->enable_state == bp_permanent
? " (permanent)"
: ""),
(others > 1) ? ","
: ((others == 1) ? " and" : ""));
}
printf_filtered (_("also set at pc "));
deprecated_print_address_numeric (pc, 1, gdb_stdout);
printf_filtered (".\n");
}
}
void
set_default_breakpoint (int valid, CORE_ADDR addr, struct symtab *symtab,
int line)
{
default_breakpoint_valid = valid;
default_breakpoint_address = addr;
default_breakpoint_symtab = symtab;
default_breakpoint_line = line;
}
static int
breakpoint_address_is_meaningful (struct breakpoint *bpt)
{
enum bptype type = bpt->type;
return (type != bp_watchpoint
&& type != bp_hardware_watchpoint
&& type != bp_read_watchpoint
&& type != bp_access_watchpoint
&& type != bp_catch_exec
&& type != bp_longjmp_resume
&& type != bp_catch_fork
&& type != bp_catch_vfork);
}
static void
check_duplicates (struct breakpoint *bpt)
{
struct bp_location *b;
int count = 0;
struct bp_location *perm_bp = 0;
CORE_ADDR address = bpt->loc->address;
asection *section = bpt->loc->section;
if (! breakpoint_address_is_meaningful (bpt))
return;
ALL_BP_LOCATIONS (b)
if (b->owner->enable_state != bp_disabled
&& b->owner->enable_state != bp_shlib_disabled
&& !b->owner->pending
&& b->owner->enable_state != bp_call_disabled
&& b->address == address
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b->owner))
{
if (b->owner->enable_state == bp_permanent)
{
perm_bp = b;
break;
}
count++;
b->duplicate = count > 1;
}
if (perm_bp)
{
perm_bp->duplicate = 0;
if (! perm_bp->inserted)
internal_error (__FILE__, __LINE__,
_("allegedly permanent breakpoint is not "
"actually inserted"));
ALL_BP_LOCATIONS (b)
if (b != perm_bp)
{
if (b->owner->enable_state != bp_disabled
&& b->owner->enable_state != bp_shlib_disabled
&& !b->owner->pending
&& b->owner->enable_state != bp_call_disabled
&& b->address == address
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b->owner))
{
if (b->inserted)
internal_error (__FILE__, __LINE__,
_("another breakpoint was inserted on top of "
"a permanent breakpoint"));
b->duplicate = 1;
}
}
}
}
static void
breakpoint_adjustment_warning (CORE_ADDR from_addr, CORE_ADDR to_addr,
int bnum, int have_bnum)
{
char astr1[40];
char astr2[40];
strcpy (astr1, hex_string_custom ((unsigned long) from_addr, 8));
strcpy (astr2, hex_string_custom ((unsigned long) to_addr, 8));
if (have_bnum)
warning (_("Breakpoint %d address previously adjusted from %s to %s."),
bnum, astr1, astr2);
else
warning (_("Breakpoint address adjusted from %s to %s."), astr1, astr2);
}
static CORE_ADDR
adjust_breakpoint_address (CORE_ADDR bpaddr, enum bptype bptype)
{
if (!gdbarch_adjust_breakpoint_address_p (current_gdbarch))
{
return bpaddr;
}
else if (bptype == bp_watchpoint
|| bptype == bp_hardware_watchpoint
|| bptype == bp_read_watchpoint
|| bptype == bp_access_watchpoint
|| bptype == bp_catch_fork
|| bptype == bp_catch_vfork
|| bptype == bp_catch_exec)
{
return bpaddr;
}
else
{
CORE_ADDR adjusted_bpaddr;
adjusted_bpaddr = gdbarch_adjust_breakpoint_address (current_gdbarch,
bpaddr);
if (adjusted_bpaddr != bpaddr)
breakpoint_adjustment_warning (bpaddr, adjusted_bpaddr, 0, 0);
return adjusted_bpaddr;
}
}
static struct bp_location *
allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type)
{
struct bp_location *loc, *loc_p;
loc = xmalloc (sizeof (struct bp_location));
memset (loc, 0, sizeof (*loc));
loc->owner = bpt;
switch (bp_type)
{
case bp_breakpoint:
case bp_inlined_breakpoint:
case bp_until:
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
case bp_catch_load:
case bp_catch_unload:
case bp_gnu_v3_catch_catch:
case bp_gnu_v3_catch_throw:
loc->loc_type = bp_loc_software_breakpoint;
break;
case bp_hardware_breakpoint:
loc->loc_type = bp_loc_hardware_breakpoint;
break;
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
loc->loc_type = bp_loc_hardware_watchpoint;
break;
case bp_watchpoint:
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
case bp_catch_catch:
case bp_catch_throw:
loc->loc_type = bp_loc_other;
break;
default:
internal_error (__FILE__, __LINE__, _("unknown breakpoint type"));
}
loc_p = bp_location_chain;
if (loc_p == 0)
bp_location_chain = loc;
else
{
while (loc_p->next)
loc_p = loc_p->next;
loc_p->next = loc;
}
return loc;
}
static
void set_bp_objfile (struct breakpoint *b, struct symtab_and_line *sal)
{
if (sal->symtab != NULL)
b->bp_objfile = sal->symtab->objfile;
else if (sal->section != NULL)
{
struct obj_section *osect;
osect = find_pc_sect_section (sal->pc, sal->section);
if (osect)
b->bp_objfile = osect->objfile;
}
else
{
struct obj_section *osect;
osect = find_pc_section (sal->pc);
if (osect)
b->bp_objfile = osect->objfile;
}
if (b->bp_objfile && b->bp_objfile->separate_debug_objfile_backlink)
b->bp_objfile = b->bp_objfile->separate_debug_objfile_backlink;
}
struct breakpoint *
set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype, int pending_p)
{
struct breakpoint *b, *b1;
b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
memset (b, 0, sizeof (*b));
b->loc = allocate_bp_location (b, bptype);
b->loc->requested_address = sal.pc;
b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
bptype);
if (sal.symtab == NULL)
b->source_file = NULL;
else
b->source_file = savestring (sal.symtab->filename,
strlen (sal.symtab->filename));
b->loc->section = sal.section;
b->type = bptype;
b->language = current_language->la_language;
b->input_radix = input_radix;
b->thread = -1;
b->line_number = sal.line;
b->enable_state = bp_enabled;
b->next = 0;
b->silent = 0;
b->ignore_count = 0;
b->commands = NULL;
b->frame_id = null_frame_id;
b->dll_pathname = NULL;
b->triggered_dll_pathname = NULL;
b->forked_inferior_pid = 0;
b->exec_pathname = NULL;
b->ops = NULL;
b->pending = pending_p;
b->requested_shlib = NULL;
b->bp_objfile = NULL;
b->bp_objfile_name = NULL;
if (!b->pending)
set_bp_objfile (b, &sal);
b1 = breakpoint_chain;
if (b1 == 0)
breakpoint_chain = b;
else
{
while (b1->next)
b1 = b1->next;
b1->next = b;
}
check_duplicates (b);
breakpoints_changed ();
return b;
}
void
make_breakpoint_permanent (struct breakpoint *b)
{
b->enable_state = bp_permanent;
b->loc->inserted = 1;
}
static struct breakpoint *
create_internal_breakpoint (CORE_ADDR address, enum bptype type)
{
static int internal_breakpoint_number = -1;
struct symtab_and_line sal;
struct breakpoint *b;
init_sal (&sal);
sal.pc = address;
sal.section = find_pc_overlay (sal.pc);
b = set_raw_breakpoint (sal, type, 0);
b->number = internal_breakpoint_number--;
b->disposition = disp_donttouch;
b->bp_set_state = bp_state_set;
return b;
}
static void
create_longjmp_breakpoint (char *func_name)
{
struct breakpoint *b;
struct minimal_symbol *m;
if (func_name == NULL)
b = create_internal_breakpoint (0, bp_longjmp_resume);
else
{
if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
return;
b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
}
b->enable_state = bp_disabled;
b->silent = 1;
if (func_name)
b->addr_string = xstrdup (func_name);
}
void
enable_longjmp_breakpoint (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp)
{
b->enable_state = bp_enabled;
check_duplicates (b);
}
}
void
disable_longjmp_breakpoint (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp
|| b->type == bp_longjmp_resume)
{
b->enable_state = bp_disabled;
check_duplicates (b);
}
}
static void
create_overlay_event_breakpoint (char *func_name)
{
struct breakpoint *b;
struct minimal_symbol *m;
if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
return;
b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m),
bp_overlay_event);
b->addr_string = xstrdup (func_name);
if (overlay_debugging == ovly_auto)
{
b->enable_state = bp_enabled;
overlay_events_enabled = 1;
}
else
{
b->enable_state = bp_disabled;
overlay_events_enabled = 0;
}
}
void
enable_overlay_breakpoints (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_overlay_event)
{
b->enable_state = bp_enabled;
check_duplicates (b);
overlay_events_enabled = 1;
}
}
void
disable_overlay_breakpoints (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_overlay_event)
{
b->enable_state = bp_disabled;
check_duplicates (b);
overlay_events_enabled = 0;
}
}
struct breakpoint *
create_thread_event_breakpoint (CORE_ADDR address)
{
struct breakpoint *b;
b = create_internal_breakpoint (address, bp_thread_event);
b->enable_state = bp_enabled;
b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
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);
}
struct captured_parse_breakpoint_args
{
char **arg_p;
struct symtabs_and_lines *sals_p;
char ***addr_string_p;
char *requested_shlib;
int *not_found_ptr;
};
struct lang_and_radix
{
enum language lang;
int radix;
};
static void
do_restore_lang_radix_cleanup (void *old)
{
struct lang_and_radix *p = old;
set_language (p->lang);
input_radix = p->radix;
}
static int
resolve_pending_breakpoint (struct breakpoint *b)
{
int rc;
struct lang_and_radix old_lr;
struct cleanup *old_chain;
int choices[1] = {-1};
old_lr.lang = current_language->la_language;
old_lr.radix = input_radix;
old_chain = make_cleanup (do_restore_lang_radix_cleanup, &old_lr);
set_language (b->language);
input_radix = b->input_radix;
rc = break_command_2 (b->addr_string, b->flag, b->from_tty, b,
b->requested_shlib, choices, NULL);
if (rc == GDB_RC_OK)
{
printf_filtered ("Pending breakpoint %d - \"%s\" resolved\n", b->number, b->addr_string);
delete_breakpoint (b);
}
do_cleanups (old_chain);
return rc;
}
void
remove_solib_event_breakpoints (void)
{
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
if (b->type == bp_shlib_event)
delete_breakpoint (b);
}
struct breakpoint *
create_solib_event_breakpoint (CORE_ADDR address)
{
struct breakpoint *b;
b = create_internal_breakpoint (address, bp_shlib_event);
return b;
}
void
disable_breakpoints_in_shlibs (int silent)
{
struct breakpoint *b;
int disabled_shlib_breaks = 0;
ALL_BREAKPOINTS (b)
{
#if defined (PC_SOLIB)
if (((b->type == bp_breakpoint) || (b->type == bp_hardware_breakpoint)
|| (b->type == bp_inlined_breakpoint))
&& breakpoint_enabled (b) && !b->loc->duplicate)
{
b->enable_state = bp_shlib_disabled;
if (!silent)
{
if (!disabled_shlib_breaks)
{
target_terminal_ours_for_output ();
warning (_("Temporarily disabling shared library breakpoints:"));
}
disabled_shlib_breaks = 1;
warning (_("breakpoint #%d "), b->number);
}
}
#endif
}
if (!silent && disabled_shlib_breaks)
printf_filtered ("\n");
}
void
disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
{
struct breakpoint *b;
int disabled_shlib_breaks = 0;
ALL_BREAKPOINTS (b)
{
if ((b->loc->loc_type == bp_loc_hardware_breakpoint
|| b->loc->loc_type == bp_loc_software_breakpoint)
&& breakpoint_enabled (b) && !b->loc->duplicate)
{
#ifdef PC_SOLIB
char *so_name = PC_SOLIB (b->loc->address);
#else
char *so_name = solib_address (b->loc->address);
#endif
if (so_name && !strcmp (so_name, solib->so_name))
{
b->enable_state = bp_shlib_disabled;
b->loc->inserted = 0;
if (!disabled_shlib_breaks)
{
target_terminal_ours_for_output ();
warning (_("Temporarily disabling breakpoints for unloaded shared library \"%s\""),
so_name);
}
disabled_shlib_breaks = 1;
}
}
}
}
void
re_enable_breakpoints_in_shlibs (int silent)
{
struct breakpoint *b, *tmp;
ALL_BREAKPOINTS_SAFE (b, tmp)
{
if (b->enable_state == bp_shlib_disabled)
{
gdb_byte buf[1];
if (target_read_memory (b->loc->address, buf, 1) == 0)
{
b->enable_state = bp_enabled;
if (!silent)
{
target_terminal_ours_for_output ();
printf_filtered ("Re-enabling shared library breakpoint %d\n",
b->number);
}
}
}
else if (b->pending && (b->enable_state == bp_enabled))
{
char *message = xstrprintf ("Error resolving pending breakpoint %d: ",
b->number);
struct cleanup *cleanups = make_cleanup (xfree, message);
catch_errors ((catch_errors_ftype *) resolve_pending_breakpoint, (void *) b,
message, RETURN_MASK_ALL);
do_cleanups (cleanups);
}
}
}
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, NULL, 0);
addr_end = hookname;
if (sals.nelts == 0)
{
warning (_("Unable to set a breakpoint on dynamic linker callback.\n"
"Suggest linking with /opt/langtools/lib/end.o.\n"
"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.\n"
"GDB will be unable to track shl_load/shl_unload calls."));
return;
}
old_chain = make_cleanup (xfree, sals.sals);
if (canonical != (char **) NULL)
{
make_cleanup (xfree, canonical);
canonical_strings_chain = make_cleanup (null_cleanup, 0);
if (canonical[0] != NULL)
make_cleanup (xfree, canonical[0]);
}
resolve_sal_pc (&sals.sals[0]);
if (canonical != (char **) NULL)
discard_cleanups (canonical_strings_chain);
b = set_raw_breakpoint (sals.sals[0], bp_kind, 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_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
if (dll_pathname == NULL)
b->dll_pathname = NULL;
else
{
b->dll_pathname = (char *) xmalloc (strlen (dll_pathname) + 1);
strcpy (b->dll_pathname, dll_pathname);
}
mention (b);
do_cleanups (old_chain);
}
void
create_solib_load_event_breakpoint (char *hookname, int tempflag,
char *dll_pathname, char *cond_string)
{
solib_load_unload_1 (hookname, tempflag, dll_pathname,
cond_string, bp_catch_load);
}
void
create_solib_unload_event_breakpoint (char *hookname, int tempflag,
char *dll_pathname, char *cond_string)
{
solib_load_unload_1 (hookname, tempflag, dll_pathname,
cond_string, bp_catch_unload);
}
static void
create_fork_vfork_event_catchpoint (int tempflag, char *cond_string,
enum bptype bp_kind)
{
struct symtab_and_line sal;
struct breakpoint *b;
int thread = -1;
init_sal (&sal);
sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
b = set_raw_breakpoint (sal, bp_kind, 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;
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->forked_inferior_pid = 0;
mention (b);
}
void
create_fork_event_catchpoint (int tempflag, char *cond_string)
{
create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_fork);
}
void
create_vfork_event_catchpoint (int tempflag, char *cond_string)
{
create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_vfork);
}
void
create_exec_event_catchpoint (int tempflag, char *cond_string)
{
struct symtab_and_line sal;
struct breakpoint *b;
int thread = -1;
init_sal (&sal);
sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
b = set_raw_breakpoint (sal, bp_catch_exec, 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;
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
mention (b);
}
static int
hw_breakpoint_used_count (void)
{
struct breakpoint *b;
int i = 0;
ALL_BREAKPOINTS (b)
{
if (b->type == bp_hardware_breakpoint && b->enable_state == bp_enabled)
i++;
}
return i;
}
static int
hw_watchpoint_used_count (enum bptype type, int *other_type_used)
{
struct breakpoint *b;
int i = 0;
*other_type_used = 0;
ALL_BREAKPOINTS (b)
{
if (breakpoint_enabled (b))
{
if (b->type == type)
i++;
else if ((b->type == bp_hardware_watchpoint ||
b->type == bp_read_watchpoint ||
b->type == bp_access_watchpoint))
*other_type_used = 1;
}
}
return i;
}
void
set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_id frame_id)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_longjmp_resume)
{
b->loc->requested_address = pc;
b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
b->type);
b->enable_state = bp_enabled;
b->frame_id = frame_id;
check_duplicates (b);
return;
}
}
void
disable_watchpoints_before_interactive_call_start (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
{
if (((b->type == bp_watchpoint)
|| (b->type == bp_hardware_watchpoint)
|| (b->type == bp_read_watchpoint)
|| (b->type == bp_access_watchpoint)
|| ep_is_exception_catchpoint (b))
&& breakpoint_enabled (b))
{
b->enable_state = bp_call_disabled;
check_duplicates (b);
}
}
}
void
enable_watchpoints_after_interactive_call_stop (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
{
if (((b->type == bp_watchpoint)
|| (b->type == bp_hardware_watchpoint)
|| (b->type == bp_read_watchpoint)
|| (b->type == bp_access_watchpoint)
|| ep_is_exception_catchpoint (b))
&& (b->enable_state == bp_call_disabled))
{
b->enable_state = bp_enabled;
check_duplicates (b);
}
}
}
struct breakpoint *
set_momentary_breakpoint (struct symtab_and_line sal, struct frame_id frame_id,
enum bptype type)
{
struct breakpoint *b;
b = set_raw_breakpoint (sal, type, 0);
b->enable_state = bp_enabled;
b->disposition = disp_donttouch;
b->frame_id = frame_id;
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
return b;
}
static void
mention (struct breakpoint *b)
{
int say_where = 0;
struct cleanup *old_chain, *ui_out_chain;
struct ui_stream *stb;
if (dont_mention)
return;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
if (deprecated_create_breakpoint_hook)
deprecated_create_breakpoint_hook (b);
breakpoint_create_event (b->number);
if (b->ops != NULL && b->ops->print_mention != NULL)
b->ops->print_mention (b);
else
switch (b->type)
{
case bp_none:
printf_filtered (_("(apparently deleted?) Eventpoint %d: "), b->number);
break;
case bp_watchpoint:
ui_out_text (uiout, "Watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
gdb_print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
do_cleanups (ui_out_chain);
break;
case bp_hardware_watchpoint:
ui_out_text (uiout, "Hardware watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
gdb_print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
do_cleanups (ui_out_chain);
break;
case bp_read_watchpoint:
ui_out_text (uiout, "Hardware read watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
gdb_print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
do_cleanups (ui_out_chain);
break;
case bp_access_watchpoint:
ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
gdb_print_expression (b->exp, stb->stream);
ui_out_field_stream (uiout, "exp", stb);
do_cleanups (ui_out_chain);
break;
case bp_breakpoint:
if (ui_out_is_mi_like_p (uiout))
{
say_where = 0;
break;
}
printf_filtered (_("Breakpoint %d"), b->number);
say_where = 1;
break;
case bp_inlined_breakpoint:
if (ui_out_is_mi_like_p (uiout))
{
say_where = 0;
break;
}
printf_filtered (_("Breakpoint %d (inlined %s)"), b->number,
b->addr_string);
say_where = 1;
break;
case bp_hardware_breakpoint:
if (ui_out_is_mi_like_p (uiout))
{
say_where = 0;
break;
}
printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
say_where = 1;
break;
case bp_catch_load:
case bp_catch_unload:
printf_filtered (_("Catchpoint %d (%s %s)"),
b->number,
(b->type == bp_catch_load) ? "load" : "unload",
(b->dll_pathname != NULL) ?
b->dll_pathname : "<any library>");
break;
case bp_catch_fork:
case bp_catch_vfork:
printf_filtered (_("Catchpoint %d (%s)"),
b->number,
(b->type == bp_catch_fork) ? "fork" : "vfork");
break;
case bp_catch_exec:
printf_filtered (_("Catchpoint %d (exec)"),
b->number);
break;
case bp_catch_catch:
case bp_catch_throw:
case bp_gnu_v3_catch_catch:
case bp_gnu_v3_catch_throw:
ui_out_text (uiout, "Catchpoint ");
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout,
"catchpoint");
ui_out_field_int (uiout, "catchno", b->number);
ui_out_text (uiout, " (");
ui_out_field_string (uiout, "type",
(b->type == bp_catch_catch) ? "catch" : "throw");
do_cleanups (ui_out_chain);
ui_out_text (uiout, ")");
break;
case bp_until:
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_call_dummy:
case bp_watchpoint_scope:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
break;
}
if (say_where)
{
if (b->pending)
{
printf_filtered (_(" (%s) pending."), b->addr_string);
}
else
{
if (addressprint || b->source_file == NULL)
{
printf_filtered (" at ");
deprecated_print_address_numeric (b->loc->address, 1, gdb_stdout);
}
if (b->source_file)
printf_filtered (": file %s, line %d.",
b->source_file, b->line_number);
}
}
do_cleanups (old_chain);
if (ui_out_is_mi_like_p (uiout))
return;
printf_filtered ("\n");
}
static void
create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
struct expression **cond, char **cond_string,
char *requested_shlib,
enum bptype type, enum bpdisp disposition,
int thread, int ignore_count, int from_tty,
struct breakpoint *pending_bp,
struct breakpoint_list **new_breakpoints)
{
if (type == bp_hardware_breakpoint)
{
int i = hw_breakpoint_used_count ();
int target_resources_ok =
TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint,
i + sals.nelts, 0);
if (target_resources_ok == 0)
error (_("No hardware breakpoint support in the target."));
else if (target_resources_ok < 0)
error (_("Hardware breakpoints used exceeds limit."));
}
{
int i;
for (i = 0; i < sals.nelts; i++)
{
struct breakpoint *b;
struct symtab_and_line sal = sals.sals[i];
if (from_tty)
describe_other_breakpoints (sal.pc, sal.section);
b = set_raw_breakpoint (sal, type, 0);
if (sals.nelts == 1 && pending_bp != NULL)
{
struct breakpoint *bpt;
ALL_BREAKPOINTS (bpt)
{
if (bpt->next == b)
{
bpt->next = b->next;
break;
}
}
if (pending_bp == breakpoint_chain)
{
b->next = pending_bp->next;
breakpoint_chain = b;
}
else
{
ALL_BREAKPOINTS (bpt)
{
if (bpt->next == pending_bp)
{
bpt->next = b;
b->next = pending_bp->next;
break;
}
}
}
b->number = pending_bp->number;
}
else
{
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
}
b->cond = cond[i];
b->thread = thread;
if (addr_string[i])
b->addr_string = addr_string[i];
else
b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
b->cond_string = cond_string[i];
b->ignore_count = ignore_count;
b->enable_state = bp_enabled;
b->disposition = disposition;
if (pending_bp)
{
char *arg;
if (pending_bp->cond_string)
{
int parse_succeeded;
arg = pending_bp->cond_string;
b->cond_string = savestring (arg, strlen (arg));
parse_succeeded = gdb_parse_exp_1 (&arg, block_for_pc (b->loc->address), 0, &b->cond);
if (!parse_succeeded || *arg)
{
if (b->cond != NULL)
{
xfree (b->cond);
b->cond = NULL;
}
if (!parse_succeeded)
warning ("Error parsing breakpoint condition expression");
else if (*arg)
warning ("Junk at end of pending breakpoint condition expression");
}
}
if (pending_bp->commands)
b->commands = copy_command_lines (pending_bp->commands);
b->ignore_count = pending_bp->ignore_count;
b->thread = pending_bp->thread;
}
if (pending_bp != NULL)
breakpoint_resolve_event (pending_bp->number, b->number);
if (requested_shlib)
b->requested_shlib = xstrdup (requested_shlib);
set_bp_objfile (b, &sal);
b->bp_set_state = bp_state_set;
if (new_breakpoints != NULL)
add_breakpoint_to_new_list (new_breakpoints, b);
mention (b);
}
if (type != bp_inlined_breakpoint)
{
struct symtabs_and_lines new_sals;
char **new_addr_string;
struct expression **new_cond;
char **new_cond_string;
new_sals = check_for_additional_inlined_breakpoint_locations (sals,
addr_string,
cond,
cond_string,
&new_addr_string,
&new_cond,
&new_cond_string);
if (new_sals.nelts > 0)
create_breakpoints (new_sals, new_addr_string, new_cond, new_cond_string,
requested_shlib, bp_inlined_breakpoint, disposition,
thread, ignore_count, from_tty, pending_bp,
new_breakpoints);
}
}
}
static void
parse_breakpoint_sals (char **address,
struct symtabs_and_lines *sals,
char ***addr_string,
char *requested_shlib,
int *not_found_ptr)
{
char *addr_start = *address;
struct cleanup *restrict_cleanup;
*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;
{
char *s;
s = paddr_u (sal.pc);
*addr_string = (char **) xmalloc (sizeof (char **));
**addr_string = (char *) xmalloc (strlen (s) + 2);
sprintf (**addr_string, "*%s", s);
}
}
else
error (_("No default breakpoint address now."));
}
else
{
struct symtab_and_line cursal = get_current_source_symtab_and_line ();
if (requested_shlib != NULL)
{
struct objfile *obj, *objnext;
restrict_cleanup = make_cleanup_restrict_to_shlib (requested_shlib);
if (restrict_cleanup == (void *) -1)
{
*not_found_ptr = 1;
if (pending_break_support == AUTO_BOOLEAN_TRUE)
throw_error (NOT_FOUND_ERROR, "");
else
throw_error (GENERIC_ERROR,
_("Couldn't locate shared library \"%s\" for breakpoint."),
requested_shlib);
}
ALL_OBJFILES_SAFE (obj, objnext)
objfile_set_load_state (obj, OBJF_SYM_ALL, 0);
}
else
restrict_cleanup = make_cleanup (null_cleanup, NULL);
if (default_breakpoint_valid
&& (!cursal.symtab
|| ((strchr ("+-", (*address)[0]) != NULL)
&& ((*address)[1] != '['))))
*sals = decode_line_1 (address, 1, default_breakpoint_symtab,
default_breakpoint_line, addr_string,
not_found_ptr, 0);
else
*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
addr_string, not_found_ptr, 1);
do_cleanups (restrict_cleanup);
}
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);
}
}
}
static 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]);
#ifdef DEPRECATED_PC_REQUIRES_RUN_BEFORE_USE
if (DEPRECATED_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);
}
#endif
}
}
struct safe_sals_to_pc_args
{
struct symtabs_and_lines *sals;
char *address;
};
static int
wrap_breakpoint_sals_to_pc (char *a)
{
struct safe_sals_to_pc_args *args = (struct safe_sals_to_pc_args *) a;
breakpoint_sals_to_pc (args->sals, args->address);
return 1;
}
static int
safe_breakpoint_sals_to_pc (struct symtabs_and_lines *sals, char *address)
{
struct safe_sals_to_pc_args args;
args.sals = sals;
args.address = address;
if (!catch_errors ((catch_errors_ftype *) wrap_breakpoint_sals_to_pc, &args,
"", RETURN_MASK_ALL))
{
return 0;
}
return 1;
}
static void
do_captured_parse_breakpoint (struct ui_out *ui, void *data)
{
struct captured_parse_breakpoint_args *args = data;
parse_breakpoint_sals (args->arg_p, args->sals_p, args->addr_string_p,
args->requested_shlib, args->not_found_ptr);
}
static int
break_command_1 (char *arg, int flag, int from_tty, struct breakpoint *pending_bp)
{
char *requested_shlib;
if (!arg)
requested_shlib = NULL;
else
{
while (isspace (*arg))
arg++;
if (*arg == '-' && *(arg+1) == 's' && strstr(arg, "-shlib") == arg)
{
char *begin;
int len;
arg += 6;
while (isspace (*arg))
arg++;
if (*arg == '\0')
error ("No value for \"-shlib\"");
if (*arg == '"')
{
int bs = 0;
arg++;
begin = arg;
while (*arg != '"' || bs)
{
if (*arg == '\0')
error ("No close quote in \"-shlib\" argument.");
if (*arg == '\\')
{
if (bs)
bs = 0;
else
bs = 1;
}
else
bs = 0;
arg++;
}
len = arg - begin;
arg++;
}
else
{
begin = arg;
while (!isspace (*arg) && *arg != '\0')
arg++;
len = arg - begin;
}
requested_shlib = malloc (len + 1);
strncpy (requested_shlib, begin, len);
requested_shlib[len] = '\0';
while (isspace (*arg))
arg++;
}
else
requested_shlib = NULL;
}
return break_command_2 (arg, flag, from_tty, pending_bp, requested_shlib, NULL, NULL);
}
static int
break_command_2 (char *arg, int flag, int from_tty,
struct breakpoint *pending_bp,
char *requested_shlib, int *indices,
struct breakpoint_list **new_breakpoints)
{
struct gdb_exception e;
int tempflag, hardwareflag;
struct symtabs_and_lines sals;
struct expression **cond = 0;
struct symtab_and_line pending_sal;
char **cond_string = (char **) NULL;
char *copy_arg;
char *addr_start = arg;
char **addr_string;
struct cleanup *old_chain;
struct cleanup *breakpoint_chain = NULL;
struct captured_parse_breakpoint_args parse_args;
int i;
int pending = 0;
int thread = -1;
int ignore_count = 0;
int not_found = 0;
hardwareflag = flag & BP_HARDWAREFLAG;
tempflag = flag & BP_TEMPFLAG;
sals.sals = NULL;
sals.nelts = 0;
addr_string = NULL;
parse_args.arg_p = &arg;
parse_args.sals_p = &sals;
parse_args.addr_string_p = &addr_string;
parse_args.requested_shlib = requested_shlib;
parse_args.not_found_ptr = ¬_found;
e = catch_exception (uiout, do_captured_parse_breakpoint,
&parse_args, RETURN_MASK_ALL);
if (e.reason == 0 && sals.nelts > 1)
{
if (indices != NULL)
{
if (indices[0] != -1)
{
int nsals;
int i;
struct symtab_and_line *new_sals;
for (nsals = 0; indices[nsals] != -1; nsals++) { ; }
new_sals = (struct symtab_and_line *)
xmalloc (nsals * sizeof (struct symtab_and_line));
for (i = 0; i < nsals; i++)
{
if (0 <= indices[i] && indices[i] < sals.nelts)
new_sals[i] = sals.sals[indices[i]];
else
{
xfree (new_sals);
error ("Index %d out of range: %d", i, indices[i]);
}
}
xfree (sals.sals);
sals.nelts = nsals;
sals.sals = new_sals;
}
}
else if (ui_out_is_mi_like_p (uiout))
{
struct cleanup *old_chain, *list_cleanup;
int retval;
old_chain = make_cleanup (xfree, addr_string);
make_cleanup (xfree, sals.sals);
retval = safe_breakpoint_sals_to_pc (&sals, addr_start);
if (!retval)
{
do_cleanups (old_chain);
return GDB_RC_FAIL;
}
make_cleanup_ui_out_list_begin_end (uiout, "matches");
for (i = 0; i < sals.nelts; i++)
{
struct symtab_and_line sal = sals.sals[i];
list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "b");
ui_out_field_int (uiout, "index", i);
if (addr_string[i] != NULL)
ui_out_field_string (uiout, "canonical", addr_string[i]);
else
ui_out_field_skip (uiout, "canonical");
if (sal.symtab && sal.symtab->filename)
ui_out_field_string (uiout, "file", sal.symtab->filename);
if (sal.symtab && sal.symtab->objfile && sal.symtab->objfile->name)
ui_out_field_string (uiout, "binary", sal.symtab->objfile->name);
else if (sal.section && sal.section->owner && sal.section->owner->filename)
ui_out_field_string (uiout, "binary", sal.section->owner->filename);
ui_out_field_int (uiout, "line", sal.line);
ui_out_field_core_addr (uiout, "addr", sal.pc);
do_cleanups (list_cleanup);
}
do_cleanups (old_chain);
return GDB_RC_NONE;
}
}
switch (e.reason)
{
case RETURN_QUIT:
exception_print (gdb_stderr, e);
return e.reason;
case RETURN_ERROR:
switch (e.error)
{
default:
if (!not_found)
{
exception_print (gdb_stderr, e);
return e.reason;
}
case NOT_FOUND_ERROR:
if (pending_bp)
return e.reason;
if (pending_break_support != AUTO_BOOLEAN_TRUE
|| requested_shlib == NULL)
exception_print (gdb_stderr, e);
if (pending_break_support == AUTO_BOOLEAN_FALSE)
throw_exception (e);
if (pending_break_support == AUTO_BOOLEAN_AUTO &&
!nquery ("Make breakpoint pending on future shared library load? "))
return e.reason;
copy_arg = xstrdup (addr_start);
addr_string = ©_arg;
sals.nelts = 1;
sals.sals = &pending_sal;
pending_sal.pc = 0;
pending = 1;
break;
}
default:
if (!sals.nelts)
return GDB_RC_FAIL;
}
old_chain = make_cleanup (null_cleanup, 0);
if (!pending)
{
make_cleanup (xfree, sals.sals);
make_cleanup (xfree, addr_string);
}
cond = xcalloc (sals.nelts, sizeof (struct expression *));
make_cleanup (xfree, cond);
cond_string = xcalloc (sals.nelts, sizeof (char **));
make_cleanup (xfree, cond_string);
breakpoint_chain = make_cleanup (null_cleanup, 0);
for (i = 0; i < sals.nelts; i++)
{
if (addr_string[i] != NULL)
make_cleanup (xfree, addr_string[i]);
}
if (!pending)
{
int retval;
retval = safe_breakpoint_sals_to_pc (&sals, addr_start);
if (!retval)
{
do_cleanups (old_chain);
return GDB_RC_FAIL;
}
}
thread = -1;
if (!pending)
{
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 (xfree, cond[i]);
cond_end = tok;
cond_string[i] = savestring (cond_start,
cond_end - cond_start);
make_cleanup (xfree, 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."), thread);
}
else
error (_("Junk at end of arguments."));
}
}
create_breakpoints (sals, addr_string, cond, cond_string,
requested_shlib,
hardwareflag ? bp_hardware_breakpoint
: bp_breakpoint,
tempflag ? disp_del : disp_donttouch,
thread, ignore_count, from_tty,
pending_bp, new_breakpoints);
}
else
{
struct symtab_and_line sal;
struct breakpoint *b;
sal.symtab = NULL;
sal.pc = 0;
make_cleanup (xfree, copy_arg);
b = set_raw_breakpoint (sal, hardwareflag ? bp_hardware_breakpoint
: bp_breakpoint, 1);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = *cond;
b->thread = thread;
b->addr_string = *addr_string;
b->cond_string = *cond_string;
b->ignore_count = ignore_count;
b->pending = 1;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->from_tty = from_tty;
b->flag = flag;
if (requested_shlib != NULL)
b->requested_shlib = xstrdup (requested_shlib);
mention (b);
}
if (sals.nelts > 1 && !ui_out_is_mi_like_p (uiout))
warning (_("Multiple breakpoints were set.\n"
"Use the \"delete\" command to delete unwanted breakpoints."));
discard_cleanups (breakpoint_chain);
do_cleanups (old_chain);
return GDB_RC_OK;
}
struct captured_breakpoint_args
{
char *address;
char *condition;
int hardwareflag;
int tempflag;
int thread;
int ignore_count;
};
static int
do_captured_breakpoint (struct ui_out *uiout, void *data)
{
struct captured_breakpoint_args *args = data;
struct symtabs_and_lines sals;
struct expression **cond;
struct cleanup *old_chain;
struct cleanup *breakpoint_chain = NULL;
int i;
char **addr_string;
char **cond_string;
char *address_end;
sals.sals = NULL;
sals.nelts = 0;
address_end = args->address;
addr_string = NULL;
parse_breakpoint_sals (&address_end, &sals, &addr_string, NULL, 0);
if (!sals.nelts)
return GDB_RC_NONE;
old_chain = make_cleanup (null_cleanup, 0);
make_cleanup (xfree, addr_string);
make_cleanup (xfree, sals.sals);
cond = xcalloc (sals.nelts, sizeof (struct expression *));
make_cleanup (xfree, cond);
cond_string = xcalloc (sals.nelts, sizeof (char **));
make_cleanup (xfree, cond_string);
breakpoint_chain = make_cleanup (null_cleanup, 0);
for (i = 0; i < sals.nelts; i++)
{
if (addr_string[i] != NULL)
make_cleanup (xfree, addr_string[i]);
}
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 (xfree, cond[i]);
cond_string[i] = xstrdup (args->condition);
}
}
create_breakpoints (sals, addr_string, cond, cond_string,
NULL,
args->hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
args->tempflag ? disp_del : disp_donttouch,
args->thread, args->ignore_count, 0,
NULL, NULL);
discard_cleanups (breakpoint_chain);
do_cleanups (old_chain);
return GDB_RC_OK;
}
enum gdb_rc
fsf_gdb_breakpoint (char *address, char *condition,
int hardwareflag, int tempflag,
int thread, int ignore_count,
char **error_message)
{
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;
return catch_exceptions_with_msg (uiout, do_captured_breakpoint, &args,
error_message, RETURN_MASK_ALL);
}
enum gdb_rc
gdb_breakpoint (char *address, char *condition,
int hardwareflag, int tempflag,
int futureflag,
int thread, int ignore_count,
int *indices, char *requested_shlib,
char **error_message)
{
struct cleanup *wipe;
int retval = GDB_RC_OK;
int flag;
struct breakpoint_list *new_breakpoints = NULL, *new_bp;
wipe = make_cleanup (restore_saved_pending_break_support,
(void *) pending_break_support);
if (futureflag)
pending_break_support = AUTO_BOOLEAN_TRUE;
else
pending_break_support = AUTO_BOOLEAN_FALSE;
flag = 0;
if (hardwareflag)
flag |= BP_HARDWAREFLAG;
if (tempflag)
flag |= BP_TEMPFLAG;
break_command_2 (address, flag, 0, NULL, requested_shlib, indices, &new_breakpoints);
for (new_bp = new_breakpoints; new_bp != NULL; new_bp = new_bp->next)
{
new_bp->bp->ignore_count = ignore_count;
if (condition != NULL)
condition_command_1 (new_bp->bp, condition, 0);
}
clear_new_breakpoint_list (new_breakpoints);
do_cleanups (wipe);
return retval;
}
void
resolve_sal_pc (struct symtab_and_line *sal)
{
CORE_ADDR pc;
if (sal->pc == 0 && sal->symtab != NULL)
{
CORE_ADDR end;
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, NULL);
}
void
tbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_TEMPFLAG, from_tty, NULL);
}
static void
hbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_HARDWAREFLAG, from_tty, NULL);
}
static void
thbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty, NULL);
}
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, NULL);
}
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, NULL);
}
static void
watch_command_1 (char *arg, int accessflag, int by_location, 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;
char *exp_string = 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);
if (by_location)
{
struct value *orig_val;
char *addr_str, *type_str, *tmp_str;
exp_start = arg;
exp = parse_exp_1 (&arg, 0, 0);
exp_end = arg;
orig_val = evaluate_expression (exp);
if (value_lazy (orig_val))
value_fetch_lazy (orig_val);
orig_val = value_addr (orig_val);
type_str = type_sprint (value_type (orig_val), "", -1);
addr_str = paddr_nz (value_as_address (orig_val));
exp_string = (char *) xmalloc (2 + strlen (type_str) + 6 + strlen (addr_str) + 1);
sprintf (exp_string, "*((%s) 0x%s)", type_str, addr_str);
xfree (type_str);
tmp_str = exp_string;
exp = parse_exp_1 (&tmp_str, 0, 0);
exp_valid_block = NULL;
innermost_block = NULL;
}
else
{
innermost_block = NULL;
exp_start = arg;
exp = parse_exp_1 (&arg, 0, 0);
exp_end = arg;
exp_valid_block = innermost_block;
exp_string = savestring (exp_start, exp_end - exp_start);
}
mark = value_mark ();
val = evaluate_expression (exp);
if (TYPE_CODE (value_type (val)) == TYPE_CODE_ERROR)
error ("Can not watch an expression of unknown type.");
release_value (val);
if (value_lazy (val))
value_fetch_lazy (val);
tok = arg;
while (*tok == ' ' || *tok == '\t')
tok++;
end_tok = tok;
while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
end_tok++;
toklen = end_tok - tok;
if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
{
tok = cond_start = end_tok + 1;
cond = parse_exp_1 (&tok, 0, 0);
cond_end = tok;
}
if (*tok)
error (_("Junk at end of command."));
if (accessflag == hw_read)
bp_type = bp_read_watchpoint;
else if (accessflag == hw_access)
bp_type = bp_access_watchpoint;
else
bp_type = bp_hardware_watchpoint;
mem_cnt = can_use_hardware_watchpoint (val);
if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint)
error (_("Expression cannot be implemented with read/access watchpoint."));
if (mem_cnt != 0)
{
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_type, i + mem_cnt,
other_type_used);
if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
error (_("Target does not support this type of hardware watchpoint."));
if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
error (_("Target can only support one kind of HW watchpoint at a time."));
}
#if defined(HPUXHPPA)
if (!target_has_execution)
{
warning (_("can't do that without a running program; try \"break main\"), \"run\" first");
return;
}
#endif
if (!mem_cnt || target_resources_ok <= 0)
bp_type = bp_watchpoint;
b = set_raw_breakpoint (sal, bp_type, 0);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
b->exp_string = exp_string;
b->val = val;
b->cond = cond;
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
b->cond_string = 0;
b->bp_set_state = bp_state_set;
frame = block_innermost_frame (exp_valid_block);
if (frame)
{
prev_frame = get_prev_frame (frame);
b->watchpoint_frame = get_frame_id (frame);
}
else
{
memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
}
if (innermost_block)
{
if (prev_frame)
{
struct breakpoint *scope_breakpoint;
scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
bp_watchpoint_scope);
scope_breakpoint->enable_state = bp_enabled;
scope_breakpoint->disposition = disp_del;
scope_breakpoint->frame_id = get_frame_id (prev_frame);
scope_breakpoint->loc->requested_address
= get_frame_pc (prev_frame);
scope_breakpoint->loc->address
= adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
scope_breakpoint->type);
b->related_breakpoint = scope_breakpoint;
}
}
value_free_to_mark (mark);
mention (b);
}
#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;
struct value *head = v;
if (!can_use_hw_watchpoints)
return 0;
for (; v; v = value_next (v))
{
if (VALUE_LVAL (v) == lval_memory)
{
if (value_lazy (v))
;
else
{
struct type *vtype = check_typedef (value_type (v));
if (v == head
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
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 (VALUE_LVAL (v) != not_lval
&& deprecated_value_modifiable (v) == 0)
return 0;
else if (VALUE_LVAL (v) == lval_register)
return 0;
else if (VALUE_LVAL (v) == lval_register_literal)
return 0;
}
return found_memory_cnt;
}
void
watch_command_wrapper (char *arg, int by_location, int from_tty)
{
watch_command_1 (arg, hw_write, by_location, from_tty);
}
int
detect_location_arg (char **arg)
{
int by_location = 0;
if (arg == NULL || *arg == NULL)
return 0;
while (**arg == ' ' || **arg == '\t')
(*arg)++;
if (strstr (*arg, "-location ") == *arg)
{
by_location = 1;
(*arg) += strlen ("-location ");
}
return by_location;
}
static void
watch_command (char *arg, int from_tty)
{
int by_location = detect_location_arg (&arg);
watch_command_1 (arg, hw_write, by_location, from_tty);
}
void
rwatch_command_wrapper (char *arg, int by_location, int from_tty)
{
watch_command_1 (arg, hw_read, by_location, from_tty);
}
static void
rwatch_command (char *arg, int from_tty)
{
int by_location = detect_location_arg (&arg);
watch_command_1 (arg, hw_read, by_location, from_tty);
}
void
awatch_command_wrapper (char *arg, int by_location, int from_tty)
{
watch_command_1 (arg, hw_access, by_location, from_tty);
}
static void
awatch_command (char *arg, int from_tty)
{
int by_location = detect_location_arg (&arg);
watch_command_1 (arg, hw_access, by_location, 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, int anywhere)
{
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct frame_info *prev_frame = get_prev_frame (deprecated_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, NULL, 0);
else
sals = decode_line_1 (&arg, 1, (struct symtab *) NULL,
0, (char ***) NULL, NULL, 0);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
sal = sals.sals[0];
xfree (sals.sals);
if (*arg)
error (_("Junk at end of arguments."));
resolve_sal_pc (&sal);
if (anywhere)
breakpoint = set_momentary_breakpoint (sal, null_frame_id, bp_until);
else
breakpoint = set_momentary_breakpoint (sal,
get_frame_id (deprecated_selected_frame),
bp_until);
if (!target_can_async_p ())
old_chain = make_cleanup_delete_breakpoint (breakpoint);
else
old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
if (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 (get_frame_pc (prev_frame), 0);
sal.pc = get_frame_pc (prev_frame);
breakpoint = set_momentary_breakpoint (sal, get_frame_id (prev_frame),
bp_until);
if (!target_can_async_p ())
make_cleanup_delete_breakpoint (breakpoint);
else
make_exec_cleanup_delete_breakpoint (breakpoint);
}
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
if (!target_can_async_p ())
do_cleanups (old_chain);
}
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;
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;
}
}
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);
}
static void
catch_load_command_1 (char *arg, int tempflag, int from_tty)
{
char *dll_pathname = NULL;
char *cond_string = NULL;
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
if (cond_string == NULL)
{
dll_pathname = ep_parse_optional_filename (&arg);
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
}
if ((*arg != '\0') && !isspace (*arg))
error (_("Junk at end of arguments."));
SOLIB_CREATE_CATCH_LOAD_HOOK (PIDGET (inferior_ptid), tempflag,
dll_pathname, cond_string);
}
static void
catch_unload_command_1 (char *arg, int tempflag, int from_tty)
{
char *dll_pathname = NULL;
char *cond_string = NULL;
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
if (cond_string == NULL)
{
dll_pathname = ep_parse_optional_filename (&arg);
ep_skip_leading_whitespace (&arg);
cond_string = ep_parse_optional_if_clause (&arg);
}
if ((*arg != '\0') && !isspace (*arg))
error (_("Junk at end of arguments."));
SOLIB_CREATE_CATCH_UNLOAD_HOOK (PIDGET (inferior_ptid), tempflag,
dll_pathname, cond_string);
}
static char * gnu_v3_catch_symbol = "__cxa_begin_catch";
static char *gnu_v3_throw_symbol = "__cxa_throw";
static enum print_stop_action print_exception_catchpoint (struct breakpoint *b);
static void print_one_exception_catchpoint (struct breakpoint *b, CORE_ADDR *last_addr);
static void print_mention_exception_catchpoint (struct breakpoint *b);
static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
print_exception_catchpoint,
print_one_exception_catchpoint,
print_mention_exception_catchpoint
};
struct breakpoint *
create_exception_catchpoint (int tempflag, char *cond_string,
int gnu_v3_p,
enum exception_event_kind ex_event,
struct symtab_and_line *sal)
{
struct breakpoint *b;
int thread = -1;
enum bptype bptype;
char *addr_string = NULL;
if (!sal)
error (_("Internal error -- no exception support"));
switch (ex_event)
{
case EX_EVENT_THROW:
if (gnu_v3_p)
{
bptype = bp_gnu_v3_catch_throw;
addr_string = xstrdup (gnu_v3_throw_symbol);
}
else
bptype = bp_catch_throw;
break;
case EX_EVENT_CATCH:
if (gnu_v3_p)
{
bptype = bp_gnu_v3_catch_catch;
addr_string = xstrdup (gnu_v3_catch_symbol);
}
else
bptype = bp_catch_catch;
break;
default:
error (_("Internal error -- invalid catchpoint kind"));
}
b = set_raw_breakpoint (*sal, bptype, 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;
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
if (gnu_v3_p)
{
b->addr_string = addr_string;
b->ops = &gnu_v3_exception_catchpoint_ops;
}
mention (b);
return b;
}
static enum print_stop_action
print_exception_catchpoint (struct breakpoint *b)
{
switch (b->type)
{
case bp_gnu_v3_catch_catch:
printf_filtered ("\nCatchpoint %d (exception caught).",
b->number);
case bp_catch_catch:
if (current_exception_event &&
(CURRENT_EXCEPTION_KIND == EX_EVENT_CATCH))
{
annotate_catchpoint (b->number);
print_catch_info (b);
ui_out_print_annotation_string (uiout, 0, "reason", "catch-exception");
if (ui_out_is_mi_like_p (uiout))
{
return PRINT_SRC_AND_LOC;
}
else
{
return PRINT_SRC_ONLY;
}
}
else
{
return PRINT_UNKNOWN;
}
break;
case bp_gnu_v3_catch_throw:
printf_filtered ("\nCatchpoint %d (exception thrown).",
b->number);
case bp_catch_throw:
if (current_exception_event &&
(CURRENT_EXCEPTION_KIND == EX_EVENT_THROW))
{
annotate_catchpoint (b->number);
print_catch_info (b);
ui_out_print_annotation_string (uiout, 0, "reason", "throw-exception");
if (ui_out_is_mi_like_p (uiout))
{
return PRINT_SRC_AND_LOC;
}
else
return PRINT_SRC_ONLY;
}
else
{
return PRINT_UNKNOWN;
}
break;
default:
return PRINT_SRC_AND_LOC;
}
}
static void
print_one_exception_catchpoint (struct breakpoint *b, CORE_ADDR *last_addr)
{
if (addressprint)
{
annotate_field (4);
ui_out_field_core_addr (uiout, "addr", b->loc->address);
}
*last_addr = b->loc->address;
annotate_field (5);
switch (b->type)
{
case bp_catch_catch:
case bp_gnu_v3_catch_catch:
ui_out_field_string (uiout, "what", "exception catch");
break;
case bp_catch_throw:
case bp_gnu_v3_catch_throw:
ui_out_field_string (uiout, "what", "exception throw");
break;
default:
break;
}
ui_out_spaces (uiout, 1);
}
static void
print_mention_exception_catchpoint (struct breakpoint *b)
{
if (strstr (b->addr_string, "throw") != NULL)
printf_filtered (_("Catchpoint %d (throw)"), b->number);
else
printf_filtered (_("Catchpoint %d (catch)"), b->number);
}
int
handle_gnu_v3_exceptions (enum exception_event_kind ex_event)
{
if (ex_event == EX_EVENT_CATCH)
exception_catchpoint_catch_enabled = 1;
else if (ex_event == EX_EVENT_THROW)
exception_catchpoint_throw_enabled = 1;
return 1;
}
struct sal_chain
{
struct sal_chain *next;
struct symtab_and_line sal;
};
void
gnu_v3_update_exception_catchpoints (enum exception_event_kind ex_event,
int tempflag, char *cond_string)
{
enum bptype type;
char *trigger_func_name, *nameptr;
struct objfile *objfile;
struct minimal_symbol *msymbol;
unsigned int hash;
switch (ex_event)
{
case EX_EVENT_CATCH:
exception_catchpoint_catch_enabled = 1;
trigger_func_name = xstrdup (gnu_v3_catch_symbol);
type = bp_gnu_v3_catch_catch;
break;
case EX_EVENT_THROW:
trigger_func_name = xstrdup (gnu_v3_throw_symbol);
exception_catchpoint_throw_enabled = 1;
type = bp_gnu_v3_catch_throw;
break;
default:
internal_error (__FILE__, __LINE__,
"update_exception_catchpoint: bad argument.");
}
nameptr = trigger_func_name;
hash = msymbol_hash (nameptr) % MINIMAL_SYMBOL_HASH_SIZE;
ALL_OBJFILES (objfile)
{
for (msymbol = objfile->msymbol_hash[hash];
msymbol != NULL;
msymbol = msymbol->hash_next)
if (MSYMBOL_TYPE (msymbol) == mst_text
&& strcmp_iw (SYMBOL_LINKAGE_NAME (msymbol), nameptr) == 0)
{
CORE_ADDR catchpoint_address;
CORE_ADDR past_prologue;
struct symtab_and_line sal;
struct breakpoint *b;
int found_it = 0;
init_sal (&sal);
sal.symtab = NULL;
catchpoint_address = SYMBOL_VALUE_ADDRESS (msymbol);
past_prologue = SKIP_PROLOGUE (catchpoint_address);
sal.pc = past_prologue;
sal.line = 0;
sal.end = past_prologue;
ALL_BREAKPOINTS (b)
{
if ((b->type == type)
&& (b->loc->address == sal.pc))
{
found_it = 1;
break;
}
}
if (!found_it)
{
b = create_exception_catchpoint (tempflag, cond_string,
1, ex_event,
&sal);
if (objfile->name != NULL)
b->requested_shlib = xstrdup(objfile->name);
b->bp_objfile = objfile;
if (!target_check_is_objfile_loaded (objfile))
b->bp_set_state = bp_state_waiting_load;
else
b->bp_set_state = bp_state_set;
}
}
}
}
int
update_exception_catchpoints (enum exception_event_kind ex_event,
int tempflag, char *cond_string,
int delete, struct objfile *objfile)
{
struct symtabs_and_lines *sals;
if (ex_event == EX_EVENT_CATCH)
exception_catchpoint_catch_enabled = 1;
else if (ex_event == EX_EVENT_THROW)
exception_catchpoint_throw_enabled = 1;
sals = target_find_exception_catchpoints (ex_event,
objfile);
if (sals && sals != (struct symtabs_and_lines *) -1)
{
int i;
if (delete)
{
struct breakpoint *b, *tmp;
enum bptype type;
int found_it;
switch (ex_event)
{
case EX_EVENT_CATCH:
type = bp_catch_catch;
break;
case EX_EVENT_THROW:
type = bp_catch_throw;
break;
default:
internal_error (__FILE__, __LINE__,
"update_exception_catchpoint: bad argument.");
}
ALL_BREAKPOINTS_SAFE (b, tmp)
{
if (b->type == type)
{
found_it = 0;
for (i = 0; i < sals->nelts; i++)
{
if (b->loc->address == sals->sals[i].pc)
{
sals->sals[i].pc = (CORE_ADDR) -1;
found_it = 1;
break;
}
}
if (!found_it)
delete_breakpoint(b);
}
}
for (i = 0; i < sals->nelts; i++)
if (sals->sals[i].pc != (CORE_ADDR) -1)
create_exception_catchpoint (tempflag, cond_string, 1,
ex_event, &(sals->sals[i]));
}
else
{
for (i = 0; i < sals->nelts; i++)
{
create_exception_catchpoint (tempflag, cond_string, 1,
ex_event, &(sals->sals[i]));
}
}
if (sals->nelts > 0)
xfree (sals->sals);
xfree (sals);
}
else
return 0;
return 1;
}
static int
current_exception_should_stop (void)
{
char *obj_type = CURRENT_EXCEPTION_TYPE;
char *exception_type_regexp;
char *msg;
if (!obj_type)
return 1;
if (CURRENT_EXCEPTION_KIND == EX_EVENT_THROW)
exception_type_regexp = exception_throw_type_regexp;
else
exception_type_regexp = exception_catch_type_regexp;
if (exception_type_regexp)
{
msg = (char *) re_comp (exception_type_regexp);
if (msg)
{
warning ("Error compiling exception type regexp: %s", msg);
return 1;
}
return re_exec (obj_type);
}
else
return 1;
}
static void
catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
int tempflag, int from_tty)
{
char *cond_string = NULL;
int retval;
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"));
if (handle_gnu_v3_exceptions (ex_event))
{
gnu_v3_update_exception_catchpoints (ex_event, tempflag, cond_string);
return;
}
retval = target_enable_exception_callback (ex_event, 1);
if (!retval)
error (_("Could not enable exception callback"));
if (!update_exception_catchpoints (ex_event, tempflag, cond_string,
0, NULL))
warning (_("Unsupported with this platform/compiler combination."));
}
static int
cover_target_enable_exception_callback (void *arg)
{
args_for_catchpoint_enable *args = arg;
return target_enable_exception_callback (args->kind, args->enable_p);
}
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)
{
exception_catchpoint_catch_enabled = 1;
catch_exception_command_1 (EX_EVENT_CATCH, arg1_end + 1,
tempflag, from_tty);
}
else if (strncmp (arg1_start, "throw", arg1_length) == 0)
{
exception_catchpoint_throw_enabled = 1;
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)
{
catch_fork_command_1 (catch_fork, arg1_end + 1, tempflag, from_tty);
}
else if (strncmp (arg1_start, "vfork", arg1_length) == 0)
{
catch_fork_command_1 (catch_vfork, arg1_end + 1, tempflag, from_tty);
}
else if (strncmp (arg1_start, "exec", arg1_length) == 0)
{
catch_exec_command_1 (arg1_end + 1, tempflag, from_tty);
}
else if (strncmp (arg1_start, "load", arg1_length) == 0)
{
catch_load_command_1 (arg1_end + 1, tempflag, from_tty);
}
else if (strncmp (arg1_start, "unload", arg1_length) == 0)
{
catch_unload_command_1 (arg1_end + 1, tempflag, from_tty);
}
else if (strncmp (arg1_start, "stop", arg1_length) == 0)
{
error (_("Catch of stop not yet implemented"));
}
else
{
error (_("Unknown event kind specified for catch"));
}
}
int
exception_catchpoints_enabled (enum exception_event_kind ex_event)
{
switch (ex_event)
{
case EX_EVENT_CATCH:
return exception_catchpoint_catch_enabled;
break;
case EX_EVENT_THROW:
return exception_catchpoint_throw_enabled;
break;
default:
internal_error (__FILE__, __LINE__,
"Unknown event kind for execption_catchpoints_enabled");
return 0;
}
}
void
disable_exception_catch (enum exception_event_kind ex_event)
{
struct breakpoint *b, *temp;
enum bptype type, gnu_v3_type;
if (! handle_gnu_v3_exceptions (ex_event))
{
target_enable_exception_callback (ex_event, 0);
}
switch (ex_event)
{
case EX_EVENT_THROW:
exception_catchpoint_throw_enabled = 0;
type = bp_catch_throw;
gnu_v3_type = bp_gnu_v3_catch_throw;
break;
case EX_EVENT_CATCH:
exception_catchpoint_catch_enabled = 0;
type = bp_catch_catch;
gnu_v3_type = bp_gnu_v3_catch_catch;
break;
default:
internal_error (__FILE__, __LINE__,
"disable_exception_catch: invalid event type.");
}
ALL_BREAKPOINTS_SAFE (b, temp)
if (b->type == type || b->type == gnu_v3_type)
delete_breakpoint (b);
}
struct breakpoint *
set_breakpoint_sal (struct symtab_and_line sal)
{
struct breakpoint *b;
b = set_raw_breakpoint (sal, bp_breakpoint, 0);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->cond = 0;
b->thread = -1;
return b;
}
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)
{
struct breakpoint *b, *tmp, *prev, *found;
int default_match;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
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));
make_cleanup (xfree, sals.sals);
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;
}
found = NULL;
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
prev = NULL;
ALL_BREAKPOINTS_SAFE (b, tmp)
{
if (b->type != bp_none
&& b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
&& (((sal.pc && (b->loc->address == sal.pc))
&& (!section_is_overlay (b->loc->section)
|| b->loc->section == sal.section))
|| ((default_match || (0 == sal.pc))
&& b->source_file != NULL
&& sal.symtab != NULL
&& strcmp (b->source_file, sal.symtab->filename) == 0
&& b->line_number == sal.line)))
{
if (b == breakpoint_chain)
{
breakpoint_chain = b->next;
}
else
{
prev->next = b->next;
}
b->next = found;
found = b;
}
else
{
prev = b;
}
}
}
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)
{
if (!found->next)
printf_unfiltered (_("Deleted breakpoint "));
else
printf_unfiltered (_("Deleted breakpoints "));
}
breakpoints_changed ();
while (found)
{
if (from_tty)
printf_unfiltered ("%d ", found->number);
tmp = found->next;
delete_breakpoint (found);
found = tmp;
}
if (from_tty)
putchar_unfiltered ('\n');
}
void
breakpoint_auto_delete (bpstat bs)
{
struct breakpoint *b, *temp;
for (; bs; bs = bs->next)
if (bs->breakpoint_at && bs->breakpoint_at->disposition == disp_del
&& bs->stop)
delete_breakpoint (bs->breakpoint_at);
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->disposition == disp_del_at_next_stop)
delete_breakpoint (b);
}
}
void
delete_breakpoint (struct breakpoint *bpt)
{
struct breakpoint *b;
bpstat bs;
struct bp_location *loc;
gdb_assert (bpt != NULL);
if (bpt->type == bp_none)
return;
if (deprecated_delete_breakpoint_hook)
deprecated_delete_breakpoint_hook (bpt);
breakpoint_delete_event (bpt->number);
if (bpt->loc->inserted)
remove_breakpoint (bpt->loc, mark_inserted);
free_valchain (bpt->loc);
if (breakpoint_chain == bpt)
breakpoint_chain = bpt->next;
if (bp_location_chain == bpt->loc)
bp_location_chain = bpt->loc->next;
if (ep_is_exception_catchpoint (bpt) && target_has_execution)
{
char *message = xstrprintf ("Error in deleting catchpoint %d:\n",
bpt->number);
struct cleanup *cleanups = make_cleanup (xfree, message);
args_for_catchpoint_enable args;
args.kind = bpt->type == bp_catch_catch ?
EX_EVENT_CATCH : EX_EVENT_THROW;
args.enable_p = 0;
catch_errors (cover_target_enable_exception_callback, &args,
message, RETURN_MASK_ALL);
do_cleanups (cleanups);
}
ALL_BREAKPOINTS (b)
if (b->next == bpt)
{
b->next = bpt->next;
break;
}
ALL_BP_LOCATIONS (loc)
if (loc->next == bpt->loc)
{
loc->next = bpt->loc->next;
break;
}
check_duplicates (bpt);
if (bpt->loc->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->loc->address == bpt->loc->address
&& b->loc->section == bpt->loc->section
&& !b->loc->duplicate
&& b->enable_state != bp_disabled
&& b->enable_state != bp_shlib_disabled
&& !b->pending
&& b->enable_state != bp_call_disabled)
{
int val;
if (b->enable_state == bp_permanent)
internal_error (__FILE__, __LINE__,
_("another breakpoint was inserted on top of "
"a permanent breakpoint"));
if (b->type == bp_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->loc->address, b->loc->shadow_contents);
else
val = target_insert_breakpoint (b->loc->address, b->loc->shadow_contents);
if (val != 0)
{
struct ui_file *tmp_error_stream = mem_fileopen ();
make_cleanup_ui_file_delete (tmp_error_stream);
if (b->type == bp_hardware_breakpoint)
{
fprintf_unfiltered (tmp_error_stream,
"Cannot insert hardware breakpoint %d.\n"
"You may have requested too many hardware breakpoints.\n",
b->number);
}
else
{
fprintf_unfiltered (tmp_error_stream, "Cannot insert breakpoint %d.\n", b->number);
fprintf_filtered (tmp_error_stream, "Error accessing memory address ");
deprecated_print_address_numeric (b->loc->address, 1, tmp_error_stream);
fprintf_filtered (tmp_error_stream, ": %s.\n",
safe_strerror (val));
}
fprintf_unfiltered (tmp_error_stream,"The same program may be running in another process.");
target_terminal_ours_for_output ();
error_stream(tmp_error_stream);
}
else
b->loc->inserted = 1;
}
}
free_command_lines (&bpt->commands);
if (bpt->cond)
xfree (bpt->cond);
if (bpt->cond_string != NULL)
xfree (bpt->cond_string);
if (bpt->addr_string != NULL)
xfree (bpt->addr_string);
if (bpt->exp != NULL)
xfree (bpt->exp);
if (bpt->exp_string != NULL)
xfree (bpt->exp_string);
if (bpt->val != NULL)
value_free (bpt->val);
if (bpt->source_file != NULL)
xfree (bpt->source_file);
if (bpt->dll_pathname != NULL)
xfree (bpt->dll_pathname);
if (bpt->triggered_dll_pathname != NULL)
xfree (bpt->triggered_dll_pathname);
if (bpt->exec_pathname != NULL)
xfree (bpt->exec_pathname);
if (bpt->requested_shlib != NULL)
xfree (bpt->requested_shlib);
if (bpt->bp_objfile_name != NULL)
xfree (bpt->bp_objfile_name);
for (bs = stop_bpstat; bs; bs = bs->next)
if (bs->breakpoint_at == bpt)
{
bs->breakpoint_at = NULL;
bs->old_val = NULL;
}
bpt->type = bp_none;
xfree (bpt->loc);
xfree (bpt);
}
static void
do_delete_breakpoint_cleanup (void *b)
{
delete_breakpoint (b);
}
struct cleanup *
make_cleanup_delete_breakpoint (struct breakpoint *b)
{
return make_cleanup (do_delete_breakpoint_cleanup, b);
}
struct cleanup *
make_exec_cleanup_delete_breakpoint (struct breakpoint *b)
{
return make_exec_cleanup (do_delete_breakpoint_cleanup, b);
}
void
delete_command (char *arg, int from_tty)
{
struct breakpoint *b, *temp;
dont_repeat ();
if (arg == 0)
{
int breaks_to_delete = 0;
ALL_BREAKPOINTS (b)
{
if (b->type != bp_call_dummy &&
b->type != bp_shlib_event &&
b->type != bp_thread_event &&
b->type != bp_overlay_event &&
b->number >= 0)
breaks_to_delete = 1;
}
if (!from_tty
|| (breaks_to_delete && query (_("Delete all breakpoints? "))))
{
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->type != bp_call_dummy &&
b->type != bp_shlib_event &&
b->type != bp_thread_event &&
b->type != bp_overlay_event &&
b->number >= 0)
delete_breakpoint (b);
}
}
}
else
map_breakpoint_numbers (arg, delete_breakpoint);
}
static int
breakpoint_re_set_one (void *bint)
{
struct breakpoint *b = (struct breakpoint *) bint;
struct value *mark;
int i;
int found;
int j;
struct symtabs_and_lines sals;
char *s;
enum enable_state save_enable;
struct expression *s_exp;
struct cleanup *restrict_cleanup;
switch (b->type)
{
case bp_none:
warning (_("attempted to reset apparently deleted breakpoint #%d?"),
b->number);
return 0;
case bp_gnu_v3_catch_throw:
case bp_gnu_v3_catch_catch:
case bp_breakpoint:
case bp_inlined_breakpoint:
case bp_hardware_breakpoint:
case bp_catch_load:
case bp_catch_unload:
case bp_thread_event:
if (b->addr_string == NULL)
{
delete_breakpoint (b);
return 0;
}
if (b->pending)
break;
save_enable = b->enable_state;
if (b->enable_state != bp_disabled)
b->enable_state = bp_shlib_disabled;
set_language (b->language);
input_radix = b->input_radix;
s = b->addr_string;
if (b->requested_shlib != NULL)
{
if (b->type != bp_gnu_v3_catch_throw
&& b->type != bp_gnu_v3_catch_catch)
{
if (objfile_name_set_load_state (b->requested_shlib, OBJF_SYM_ALL, 0) == -1)
{
warning ("Couldn't raise load state for requested shlib: \"%s\" "
"for breakpoint %d.\n",
b->requested_shlib, b->number);
return 0;
}
}
restrict_cleanup
= make_cleanup_restrict_to_shlib (b->requested_shlib);
if (restrict_cleanup == (void *) -1)
{
warning ("Couldn't find requested shlib: \"%s\" "
"for breakpoint %d.\n",
b->requested_shlib, b->number);
return 0;
}
}
else if (b->bp_objfile_name != NULL)
{
if (b->type != bp_gnu_v3_catch_throw
&& b->type != bp_gnu_v3_catch_catch)
{
if (objfile_name_set_load_state (b->bp_objfile_name, OBJF_SYM_ALL, 0) == -1)
{
warning ("Couldn't raise load state for requested objfile: \"%s\" "
"for breakpoint %d/\n", b->bp_objfile_name, b->number);
}
}
restrict_cleanup
= make_cleanup_restrict_to_objfile_by_name (b->bp_objfile_name);
if (restrict_cleanup == (void *) -1)
{
warning ("Couldn't find requested objfile: \"%s\" "
"for breakpoint %d.\n", b->bp_objfile_name, b->number);
}
}
else
restrict_cleanup = make_cleanup (null_cleanup, NULL);
sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL, NULL, 0);
if (NULL == sals.sals)
{
do_cleanups (restrict_cleanup);
return 0;
}
found = 0;
if (sals.nelts > 1)
for (j = 0; j < sals.nelts && !found; j++)
{
struct objfile *bp_objfile = NULL;
struct obj_section *osect = NULL;
struct symtab_and_line *sal = &(sals.sals[j]);
CORE_ADDR base_pc;
CORE_ADDR offset;
CORE_ADDR target_pc;
if (sal->symtab != NULL)
bp_objfile = sal->symtab->objfile;
else if (sal->section != NULL)
{
osect = find_pc_sect_section (sal->pc, sal->section);
if (osect)
bp_objfile = osect->objfile;
}
else
{
osect = find_pc_section (sal->pc);
if (osect)
bp_objfile = osect->objfile;
}
if (bp_objfile && bp_objfile->separate_debug_objfile_backlink)
bp_objfile = bp_objfile->separate_debug_objfile_backlink;
if (!bp_objfile)
continue;
base_pc = b->loc->address;
target_pc = sals.sals[j].pc;
if (base_pc == target_pc)
{
i = j;
found = 1;
}
else
{
offset = 0;
ALL_OBJFILE_OSECTIONS (bp_objfile, osect)
if (bp_objfile->separate_debug_objfile_backlink == NULL
&& osect->addr <= sals.sals[j].pc
&& sals.sals[j].pc<= osect->endaddr)
{
offset = ANOFFSET (bp_objfile->section_offsets,
osect->the_bfd_section->index);
break;
}
if (base_pc + offset == target_pc)
{
i = j;
found = 1;
}
}
}
if (!found)
i = sals.nelts - 1;
{
resolve_sal_pc (&sals.sals[i]);
if (b->cond_string != NULL)
{
s = b->cond_string;
if (b->cond)
{
xfree (b->cond);
b->cond = NULL;
}
}
set_bp_objfile (b, &sals.sals[i]);
if (!(target_check_is_objfile_loaded (b->bp_objfile)
|| (b->loc->address != 0x0 && b->bp_objfile == NULL)))
{
b->bp_set_state = bp_state_waiting_load;
return 0;
}
if (b->loc->address != sals.sals[i].pc
|| (b->source_file != NULL
&& sals.sals[i].symtab != NULL
&& (strcmp (b->source_file, sals.sals[i].symtab->filename) != 0
|| b->line_number != sals.sals[i].line)
)
|| ((b->source_file == NULL) != (sals.sals[i].symtab == NULL))
)
{
if (b->source_file != NULL)
xfree (b->source_file);
if (sals.sals[i].symtab == NULL)
b->source_file = NULL;
else
b->source_file =
savestring (sals.sals[i].symtab->filename,
strlen (sals.sals[i].symtab->filename));
b->line_number = sals.sals[i].line;
b->loc->requested_address = sals.sals[i].pc;
b->loc->address
= adjust_breakpoint_address (b->loc->requested_address,
b->type);
if (deprecated_modify_breakpoint_hook)
deprecated_modify_breakpoint_hook (b);
mention (b);
breakpoints_changed ();
}
b->loc->section = sals.sals[i].section;
b->enable_state = save_enable;
do_cleanups (restrict_cleanup);
b->bp_set_state = bp_state_set;
check_duplicates (b);
}
xfree (sals.sals);
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
innermost_block = NULL;
s = b->exp_string;
if (! gdb_parse_exp_1 (&s, innermost_block, 0, &s_exp))
{
warning ("Unable to reset watchpoint %d (unable to "
"parse expression); deleting", b->number);
delete_breakpoint (b);
return 0;
}
if (b->exp)
xfree (b->exp);
b->exp = s_exp;
b->exp_valid_block = innermost_block;
mark = value_mark ();
if (b->val)
{
value_free (b->val);
b->val = NULL;
}
b->val = evaluate_expression (b->exp);
release_value (b->val);
if (value_lazy (b->val) && breakpoint_enabled (b))
value_fetch_lazy (b->val);
if (b->cond_string != NULL)
{
s = b->cond_string;
if (b->cond)
{
xfree (b->cond);
b->cond = NULL;
}
b->cond = parse_exp_1 (&s, (struct block *) 0, 0);
}
if (breakpoint_enabled (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:
case bp_overlay_event:
delete_breakpoint (b);
break;
case bp_shlib_event:
case bp_until:
case bp_finish:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_step_resume:
break;
}
return 0;
}
static void
restrict_search_cleanup (void *ignored)
{
objfile_restrict_search (0);
objfile_clear_restrict_list ();
}
void
breakpoint_update ()
{
if (breakpoint_generation != symbol_generation)
{
struct cleanup *old_cleanups;
old_cleanups = make_cleanup (restrict_search_cleanup, NULL);
breakpoint_re_set_all ();
if (exception_catchpoints_enabled (EX_EVENT_THROW))
{
objfile_restrict_search (1);
gnu_v3_update_exception_catchpoints (EX_EVENT_THROW, 0, NULL);
}
if (exception_catchpoints_enabled (EX_EVENT_CATCH))
{
objfile_restrict_search (1);
gnu_v3_update_exception_catchpoints (EX_EVENT_CATCH, 0, NULL);
}
do_cleanups (old_cleanups);
breakpoint_generation = symbol_generation;
}
else
{
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
{
struct cleanup *restrict_cleanups;
char *message;
if (b->bp_set_state != bp_state_waiting_load
|| b->bp_objfile == NULL)
continue;
if (!(target_check_is_objfile_loaded (b->bp_objfile)
|| (b->loc->address != 0x0 && b->bp_objfile == NULL)))
continue;
message = xstrprintf ("Error in re-setting breakpoint %d:\n",
b->number);
restrict_cleanups = make_cleanup_restrict_to_objfile (b->bp_objfile);
make_cleanup (xfree, message);
catch_errors (breakpoint_re_set_one, b, message, RETURN_MASK_ALL);
do_cleanups (restrict_cleanups);
}
}
}
void
breakpoint_re_set (struct objfile *objfile)
{
if (objfile != NULL)
{
objfile_add_to_restrict_list (objfile);
}
symbol_generation++;
}
static void
breakpoint_re_set_all (void)
{
struct breakpoint *b, *temp;
enum language save_language;
int save_input_radix;
save_language = current_language->la_language;
save_input_radix = input_radix;
ALL_BREAKPOINTS_SAFE (b, temp)
{
char *message = xstrprintf ("Error in re-setting breakpoint %d:\n",
b->number);
struct cleanup *cleanups;
if (b->type == bp_longjmp_resume || b->type == bp_longjmp)
{
delete_breakpoint (b);
continue;
}
if (b->bp_set_state == bp_state_set)
continue;
cleanups = make_cleanup (xfree, message);
if (b->type == bp_breakpoint || b->type == bp_inlined_breakpoint)
objfile_restrict_search (1);
catch_errors (breakpoint_re_set_one, b, message, RETURN_MASK_ALL);
objfile_restrict_search (0);
do_cleanups (cleanups);
}
set_language (save_language);
input_radix = save_input_radix;
if (GET_LONGJMP_TARGET_P ())
{
create_longjmp_breakpoint ("longjmp");
create_longjmp_breakpoint ("_longjmp");
create_longjmp_breakpoint ("siglongjmp");
create_longjmp_breakpoint ("_siglongjmp");
create_longjmp_breakpoint (NULL);
}
}
void
breakpoint_re_set_thread (struct breakpoint *b)
{
if (b->thread != -1)
{
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
}
}
void
set_ignore_count (int bptnum, int count, int from_tty)
{
struct breakpoint *b;
if (count < 0)
count = 0;
ALL_BREAKPOINTS (b)
if (b->number == bptnum)
{
b->ignore_count = count;
if (from_tty)
{
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 ();
breakpoint_modify_event (b->number);
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;
int num;
if (p == 0)
error_no_arg (_("a breakpoint number"));
num = get_number (&p);
if (num == 0)
error (_("bad breakpoint number: '%s'"), args);
if (*p == 0)
error (_("Second argument (specified ignore-count) is missing."));
set_ignore_count (num,
longest_to_int (value_as_long (parse_and_eval (p))),
from_tty);
if (from_tty)
printf_filtered ("\n");
}
static void
map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
{
char *p = args;
char *p1;
int num;
struct breakpoint *b, *tmp;
int match;
if (p == 0)
error_no_arg (_("one or more breakpoint numbers"));
while (*p)
{
match = 0;
p1 = p;
num = get_number_or_range (&p1);
if (num == 0)
{
warning (_("bad breakpoint number at or near '%s'"), p);
}
else
{
ALL_BREAKPOINTS_SAFE (b, tmp)
if (b->number == num)
{
struct breakpoint *related_breakpoint = b->related_breakpoint;
match = 1;
function (b);
if (related_breakpoint)
function (related_breakpoint);
break;
}
if (match == 0)
printf_unfiltered (_("No breakpoint number %d.\n"), num);
}
p = p1;
}
}
void
disable_breakpoint (struct breakpoint *bpt)
{
if (bpt->type == bp_watchpoint_scope)
return;
if (bpt->enable_state == bp_permanent)
return;
bpt->enable_state = bp_disabled;
bpt->bp_set_state = bp_state_unset;
check_duplicates (bpt);
if (deprecated_modify_breakpoint_hook)
deprecated_modify_breakpoint_hook (bpt);
breakpoint_modify_event (bpt->number);
}
static void
disable_command (char *args, int from_tty)
{
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_inlined_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_gnu_v3_catch_catch:
case bp_gnu_v3_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)
{
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->pending)
{
if (bpt->enable_state != bp_enabled)
{
breakpoints_changed ();
if (resolve_pending_breakpoint (bpt) == GDB_RC_OK)
{
return;
}
bpt->enable_state = bp_enabled;
bpt->disposition = disposition;
}
}
else
{
if (bpt->enable_state != bp_permanent)
bpt->enable_state = bp_enabled;
bpt->bp_set_state = bp_state_set;
bpt->disposition = disposition;
check_duplicates (bpt);
breakpoints_changed ();
if (bpt->type == bp_watchpoint ||
bpt->type == bp_hardware_watchpoint ||
bpt->type == bp_read_watchpoint ||
bpt->type == bp_access_watchpoint)
{
struct frame_id saved_frame_id;
saved_frame_id = get_frame_id (get_selected_frame (NULL));
if (bpt->exp_valid_block != NULL)
{
struct frame_info *fr =
fr = frame_find_by_id (bpt->watchpoint_frame);
if (fr == NULL)
{
printf_filtered (_("\
Cannot enable watchpoint %d because the block in which its expression\n\
is valid is not currently in scope.\n"), bpt->number);
bpt->enable_state = bp_disabled;
return;
}
select_frame (fr);
}
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);
target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
bpt->type, i + mem_cnt, other_type_used);
if (target_resources_ok < 0)
{
printf_filtered (_("\
Cannot enable watchpoint %d because target watch resources\n\
have been allocated for other watchpoints.\n"), bpt->number);
bpt->enable_state = bp_disabled;
value_free_to_mark (mark);
return;
}
}
select_frame (frame_find_by_id (saved_frame_id));
value_free_to_mark (mark);
}
}
if (deprecated_modify_breakpoint_hook)
deprecated_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)
{
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_inlined_breakpoint:
case bp_catch_load:
case bp_catch_unload:
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
case bp_gnu_v3_catch_catch:
case bp_gnu_v3_catch_throw:
case bp_catch_catch:
case bp_catch_throw:
case bp_hardware_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
enable_breakpoint (bpt);
default:
continue;
}
else
map_breakpoint_numbers (args, enable_breakpoint);
}
static void
enable_once_breakpoint (struct breakpoint *bpt)
{
do_enable_breakpoint (bpt, disp_disable);
}
static void
enable_once_command (char *args, int from_tty)
{
map_breakpoint_numbers (args, enable_once_breakpoint);
}
static void
enable_delete_breakpoint (struct breakpoint *bpt)
{
do_enable_breakpoint (bpt, disp_del);
}
static void
enable_delete_command (char *args, int from_tty)
{
map_breakpoint_numbers (args, enable_delete_breakpoint);
}
static void
set_breakpoint_cmd (char *args, int from_tty)
{
}
static void
show_breakpoint_cmd (char *args, int from_tty)
{
}
static void
write_one_breakpoint (struct breakpoint *b, struct ui_file *stream, struct ui_out *uiout)
{
register struct command_line *l;
switch (b->type)
{
case bp_watchpoint:
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
switch (b->original_flags)
{
case hw_read:
fprintf_unfiltered (stream, "rwatch %s", b->exp_string);
break;
case hw_access:
fprintf_unfiltered (stream, "awatch %s", b->exp_string);
break;
case hw_execute:
internal_error (__FILE__, __LINE__,
"execute watchpoints unsupported");
break;
case hw_write:
default:
fprintf_unfiltered (stream,
"watch %s", b->exp_string);
break;
}
break;
case bp_catch_load:
case bp_catch_unload:
fprintf_unfiltered (stream, "%scatch %sload",
b->disposition == disp_del ? "t" : "",
b->type == bp_catch_unload ? "un" : "");
if (b->dll_pathname != NULL)
fputs_unfiltered (b->dll_pathname, stream);
break;
case bp_catch_fork:
fprintf_unfiltered (stream, "%scatch fork",
b->disposition == disp_del ? "t" : "");
break;
case bp_catch_vfork:
fprintf_unfiltered (stream, "%scatch vfork",
b->disposition == disp_del ? "t" : "");
break;
case bp_catch_exec:
fprintf_unfiltered (stream, "%scatch exec",
b->disposition == disp_del ? "t" : "");
break;
case bp_catch_catch:
case bp_gnu_v3_catch_catch:
fprintf_unfiltered (stream, "%scatch catch",
b->disposition == disp_del ? "t" : "");
break;
case bp_catch_throw:
case bp_gnu_v3_catch_throw:
fprintf_unfiltered (stream, "%scatch throw",
b->disposition == disp_del ? "t" : "");
break;
case bp_breakpoint:
case bp_inlined_breakpoint:
case bp_hardware_breakpoint:
{
char *hardwareflag, *futureflag, *tempflag;
hardwareflag = (b->type == bp_hardware_breakpoint) ? "h" : "";
futureflag = ((b->enable_state == bp_shlib_disabled) ||
(b->original_flags & BP_FUTUREFLAG)) ? "future-" : "";
tempflag = (b->disposition == disp_del) ? "t" : "";
fprintf_unfiltered (stream, "%s%s%sbreak", futureflag, tempflag, hardwareflag);
if (b->addr_string)
{
int len = strlen (b->addr_string) - 1;
if (b->addr_string[len] == ' ')
b->addr_string[len] = 0;
else
len = 0;
fprintf_unfiltered (stream, " %s", b->addr_string);
if (len)
b->addr_string[len] = ' ';
}
else if (b->source_file)
fprintf_unfiltered (stream, " %s:%d", b->source_file, b->line_number);
else
fprintf_unfiltered (stream, " %s",
hex_string_custom ((unsigned long) b->loc->address, 8));
}
break;
default:
internal_error (__FILE__, __LINE__, "unhandled switch case");
break;
}
if (b->thread != -1)
fprintf_unfiltered (stream, " thread %d", b->thread);
if (b->cond_string)
fprintf_unfiltered (stream, " if %s", b->cond_string);
fputc_unfiltered ('\n', stream);
if ((l = b->commands))
{
fputs_unfiltered ("commands\n", stream);
print_command_lines (uiout, l, 4);
fputs_unfiltered ("end\n", stream);
}
if (b->ignore_count)
fprintf_unfiltered (stream, "ignore $bpnum %d\n", b->ignore_count);
if (b->enable_state == bp_disabled)
fputs_unfiltered ("disable $bpnum\n", stream);
}
static void
save_breakpoints_command (char *arg, int from_tty)
{
struct cleanup *cleanups;
register struct breakpoint *b;
int found_a_breakpoint = 0;
int current_radix = -1;
int skip;
struct ui_file *stream = NULL;
struct ui_out *uiout = NULL;
time_t t;
char **argv;
char *pathname, buf[256];
dont_repeat ();
if (arg == NULL)
error ("Arguments missing: file name in which to save breakpoint commands");
else if ((argv = buildargv (arg)) == NULL)
nomem (0);
make_cleanup_freeargv (argv);
pathname = tilde_expand (*argv);
cleanups = make_cleanup (xfree, pathname);
ALL_BREAKPOINTS (b)
{
if (b->type != bp_breakpoint
&& b->type != bp_inlined_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_gnu_v3_catch_catch
&& b->type != bp_gnu_v3_catch_throw
&& b->type != bp_catch_catch
&& b->type != bp_catch_throw
&& b->type != bp_hardware_breakpoint
&& b->type != bp_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
&& b->type != bp_hardware_watchpoint)
continue;
if (! found_a_breakpoint++)
{
stream = gdb_fopen (pathname, FOPEN_WT);
if (stream == NULL)
error ("Unable to open file '%s' for saving breakpoints (%s)",
arg, strerror (errno));
make_cleanup_ui_file_delete (stream);
uiout = cli_out_new (stream);
if (uiout == NULL)
error ("Unable to create cli_out from file for saving breakpoints");
make_cleanup_ui_out_delete (uiout);
if (time (&t) != -1)
{
char *l = setlocale (LC_ALL, NULL);
if (l)
{
char *orig_locale = strcpy (xmalloc (strlen (l) + 1), l);
setlocale (LC_ALL, "");
if (strftime (buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime (&t)))
fprintf_unfiltered (stream, "# Saved breakpoints file created on %s\n\n", buf);
setlocale (LC_ALL, orig_locale);
}
}
fprintf_unfiltered (stream, "set $current_radix = $input_radix\n"
"set input-radix 012\n\n");
current_radix = 10;
}
skip = (b->commands || b->ignore_count || b->enable_state == bp_disabled);
if (skip)
fputc_unfiltered ('\n', stream);
if (b->input_radix != current_radix)
{
current_radix = b->input_radix;
fprintf_unfiltered (stream, "set input-radix 0%o\n", current_radix);
}
write_one_breakpoint (b, stream, uiout);
if (skip && b->next)
fputc_unfiltered ('\n', stream);
}
if (! found_a_breakpoint)
printf_filtered ("No breakpoints or watchpoints to save.\n");
else
{
fputs_unfiltered ("\n", stream);
if (current_radix != 10)
fputs_unfiltered ("set input-radix 012\n", stream);
fputs_unfiltered ("set input-radix $current_radix\n", stream);
if (from_tty)
printf_filtered ("Breakpoints saved to file '%s'.\n", pathname);
}
do_cleanups (cleanups);
}
struct symtabs_and_lines
decode_line_spec_1 (char *string, int funfirstline)
{
struct symtabs_and_lines sals;
if (string == 0)
error (_("Empty line specification."));
if (default_breakpoint_valid)
sals = decode_line_1 (&string, funfirstline,
default_breakpoint_symtab,
default_breakpoint_line,
(char ***) NULL, NULL, 0);
else
sals = decode_line_1 (&string, funfirstline,
(struct symtab *) NULL, 0, (char ***) NULL, NULL, 0);
if (*string)
error (_("Junk at end of line specification: %s"), string);
return sals;
}
static void
restore_saved_pending_break_support (void * val)
{
pending_break_support = (enum auto_boolean) val;
}
void
future_break_command (char *arg, int from_tty)
{
struct cleanup *wipe = make_cleanup (restore_saved_pending_break_support,
(void *) pending_break_support);
pending_break_support = AUTO_BOOLEAN_TRUE;
break_command_1 (arg, 0, from_tty, NULL);
do_cleanups (wipe);
}
struct breakpoint *
find_finish_breakpoint (void)
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_finish)
return b;
return NULL;
}
void
tell_breakpoints_objfile_changed_internal (struct objfile *objfile,
int set_pending)
{
struct breakpoint *b, *tmp;
if (objfile != NULL)
{
ALL_BREAKPOINTS_SAFE (b, tmp)
{
if (b->bp_objfile != NULL)
{
if (b->bp_objfile == objfile)
{
b->bp_set_state = bp_state_unset;
if (set_pending)
b->pending = 1;
if (b->bp_objfile->name)
b->bp_objfile_name = xstrdup (b->bp_objfile->name);
b->bp_objfile = NULL;
}
}
else if (b->bp_set_state != bp_state_unset)
{
struct obj_section *osect;
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
if ((osect->addr < b->loc->address)
&& (b->loc->address < osect->endaddr))
{
b->bp_set_state = bp_state_unset;
break;
}
}
}
}
}
else
{
ALL_BREAKPOINTS (b)
b->bp_set_state = bp_state_unset;
}
breakpoint_generation--;
}
void
tell_breakpoints_objfile_changed (struct objfile *objfile)
{
tell_breakpoints_objfile_changed_internal (objfile, 0);
}
void
tell_breakpoints_objfile_removed (struct objfile *objfile)
{
tell_breakpoints_objfile_changed_internal (objfile, 1);
}
void
_initialize_breakpoint (void)
{
static struct cmd_list_element *breakpoint_set_cmdlist;
static struct cmd_list_element *breakpoint_show_cmdlist;
struct cmd_list_element *c;
observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
breakpoint_chain = 0;
breakpoint_count = 0;
add_com ("ignore", class_breakpoint, ignore_command, _("\
Set ignore-count of breakpoint number N to COUNT.\n\
Usage is `ignore N COUNT'."));
if (xdb_commands)
add_com_alias ("bc", "ignore", class_breakpoint, 1);
add_com ("commands", class_breakpoint, commands_command, _("\
Set commands to be executed when a breakpoint is hit.\n\
Give breakpoint number as argument after \"commands\".\n\
With no argument, the targeted breakpoint is the last one set.\n\
The commands themselves follow starting on the next line.\n\
Type a line containing \"end\" to indicate the end of them.\n\
Give \"silent\" as the first line to make the breakpoint silent;\n\
then no output is printed when it is hit, except what the commands print."));
add_com ("condition", class_breakpoint, condition_command, _("\
Specify breakpoint number N to break only if COND is true.\n\
Usage is `condition N COND', where N is an integer and COND is an\n\
expression to be evaluated whenever breakpoint N is reached."));
c = add_com ("tbreak", class_breakpoint, tbreak_command, _("\
Set a temporary breakpoint. Args like \"break\" command.\n\
Like \"break\" except the breakpoint is only temporary,\n\
so it will be deleted when hit. Equivalent to \"break\" followed\n\
by using \"enable delete\" on the breakpoint number."));
set_cmd_completer (c, location_completer);
c = add_com ("hbreak", class_breakpoint, hbreak_command, _("\
Set a hardware assisted breakpoint. Args like \"break\" command.\n\
Like \"break\" except the breakpoint requires hardware support,\n\
some target hardware may not have this support."));
set_cmd_completer (c, location_completer);
c = add_com ("thbreak", class_breakpoint, thbreak_command, _("\
Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\
Like \"hbreak\" except the breakpoint is only temporary,\n\
so it will be deleted when hit."));
set_cmd_completer (c, location_completer);
add_prefix_cmd ("enable", class_breakpoint, enable_command, _("\
Enable some breakpoints.\n\
Give breakpoint numbers (separated by spaces) as arguments.\n\
With no subcommand, breakpoints are enabled until you command otherwise.\n\
This is used to cancel the effect of the \"disable\" command.\n\
With a subcommand you can enable temporarily."),
&enablelist, "enable ", 1, &cmdlist);
if (xdb_commands)
add_com ("ab", class_breakpoint, enable_command, _("\
Enable some breakpoints.\n\
Give breakpoint numbers (separated by spaces) as arguments.\n\
With no subcommand, breakpoints are enabled until you command otherwise.\n\
This is used to cancel the effect of the \"disable\" command.\n\
With a subcommand you can enable temporarily."));
add_com_alias ("en", "enable", class_breakpoint, 1);
add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command, _("\
Enable some breakpoints.\n\
Give breakpoint numbers (separated by spaces) as arguments.\n\
This is used to cancel the effect of the \"disable\" command.\n\
May be abbreviated to simply \"enable\".\n"),
&enablebreaklist, "enable breakpoints ", 1, &enablelist);
add_cmd ("once", no_class, enable_once_command, _("\
Enable breakpoints for one hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it becomes disabled."),
&enablebreaklist);
add_cmd ("delete", no_class, enable_delete_command, _("\
Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it is deleted."),
&enablebreaklist);
add_cmd ("delete", no_class, enable_delete_command, _("\
Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it is deleted."),
&enablelist);
add_cmd ("once", no_class, enable_once_command, _("\
Enable breakpoints for one hit. Give breakpoint numbers.\n\
If a breakpoint is hit while enabled in this fashion, it becomes disabled."),
&enablelist);
add_prefix_cmd ("disable", class_breakpoint, disable_command, _("\
Disable some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To disable all breakpoints, give no argument.\n\
A disabled breakpoint is not forgotten, but has no effect until reenabled."),
&disablelist, "disable ", 1, &cmdlist);
add_com_alias ("dis", "disable", class_breakpoint, 1);
add_com_alias ("disa", "disable", class_breakpoint, 1);
if (xdb_commands)
add_com ("sb", class_breakpoint, disable_command, _("\
Disable some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To disable all breakpoints, give no argument.\n\
A disabled breakpoint is not forgotten, but has no effect until reenabled."));
add_cmd ("breakpoints", class_alias, disable_command, _("\
Disable some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To disable all breakpoints, give no argument.\n\
A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
This command may be abbreviated \"disable\"."),
&disablelist);
add_prefix_cmd ("delete", class_breakpoint, delete_command, _("\
Delete some breakpoints or auto-display expressions.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To delete all breakpoints, give no argument.\n\
\n\
Also a prefix command for deletion of other GDB objects.\n\
The \"unset\" command is also an alias for \"delete\"."),
&deletelist, "delete ", 1, &cmdlist);
add_com_alias ("d", "delete", class_breakpoint, 1);
if (xdb_commands)
add_com ("db", class_breakpoint, delete_command, _("\
Delete some breakpoints.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To delete all breakpoints, give no argument.\n"));
add_cmd ("breakpoints", class_alias, delete_command, _("\
Delete some breakpoints or auto-display expressions.\n\
Arguments are breakpoint numbers with spaces in between.\n\
To delete all breakpoints, give no argument.\n\
This command may be abbreviated \"delete\"."),
&deletelist);
add_com ("clear", class_breakpoint, clear_command, _("\
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."));
c = add_com ("break", class_breakpoint, break_command, _("\
Set breakpoint at specified line or function.\n\
Argument may be line number, function name, or \"*\" and an address.\n\
If line number is specified, break at start of code for that line.\n\
If function is specified, break at start of code for that function.\n\
If an address is specified, break at that exact address.\n\
With no arg, uses current execution address of selected stack frame.\n\
This is useful for breaking on return to a stack frame.\n\
\n\
Multiple breakpoints at one place are permitted, and useful if conditional.\n\
\n\
break ... if <cond> sets condition <cond> on the breakpoint as it is created.\n\
\n\
Do \"help breakpoints\" for info on other commands dealing with breakpoints."));
set_cmd_completer (c, location_completer);
add_com_alias ("b", "break", class_run, 1);
add_com_alias ("br", "break", class_run, 1);
add_com_alias ("bre", "break", class_run, 1);
add_com_alias ("brea", "break", class_run, 1);
add_com ("future-break", class_breakpoint, future_break_command,
"Set breakpoint at expression. If it can't be done now, attempt it\n"
"again each time code is dynamically loaded.");
add_com_alias ("fb", "future-break", class_breakpoint, 2);
if (xdb_commands)
{
add_com_alias ("ba", "break", class_breakpoint, 1);
add_com_alias ("bu", "ubreak", class_breakpoint, 1);
}
if (dbx_commands)
{
add_abbrev_prefix_cmd ("stop", class_breakpoint, stop_command, _("\
Break in function/address or break at a line in the current file."),
&stoplist, "stop ", 1, &cmdlist);
add_cmd ("in", class_breakpoint, stopin_command,
_("Break in function or address."), &stoplist);
add_cmd ("at", class_breakpoint, stopat_command,
_("Break at a line in the current file."), &stoplist);
add_com ("status", class_info, breakpoints_info, _("\
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."));
}
add_info ("breakpoints", breakpoints_info, _("\
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."));
if (xdb_commands)
add_com ("lb", class_breakpoint, breakpoints_info, _("\
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."));
add_cmd ("breakpoints", class_maintenance, maintenance_info_breakpoints, _("\
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."),
&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_setshow_string_cmd ("exception-throw-type-regexp",
class_breakpoint,
&exception_throw_type_regexp,
"Set throw regexp",
"Show throw regexp",
"Set a regexp to match against the exception type of a "
"thrown object. If the regexp matches, then gdb will "
"stop at the throw of that object.",
NULL, NULL,
&setlist, &showlist);
add_setshow_string_cmd ("exception-catch-type-regexp", class_breakpoint,
&exception_catch_type_regexp,
"Set exception regexp",
"Show exception regexp",
"Set a regexp to match against the exception type of a "
"caught object. If the regexp matches, then gdb will "
"stop at the catch of that object.",
NULL, NULL,
&setlist, &showlist);
c = add_com ("watch", class_breakpoint, watch_command, _("\
Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression changes.\n\
If you pass the \"-location\" flag to the command, the expression\n\
is resolved to its location, and only that, not the full expression\n\
is watched."));
set_cmd_completer (c, location_completer);
c = add_com ("rwatch", class_breakpoint, rwatch_command, _("\
Set a read watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression is read.\n\
If you pass the \"-location\" flag to the command, the expression\n\
is resolved to its location, and only that, not the full expression\n\
is watched."));
set_cmd_completer (c, location_completer);
c = add_com ("awatch", class_breakpoint, awatch_command, _("\
Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression is either read or written.\n\
If you pass the \"-location\" flag to the command, the expression\n\
is resolved to its location, and only that, not the full expression\n\
is watched."));
set_cmd_completer (c, location_completer);
add_info ("watchpoints", breakpoints_info,
_("Synonym for ``info breakpoints''."));
add_setshow_zinteger_cmd ("can-use-hw-watchpoints", class_support,
&can_use_hw_watchpoints, _("\
Set debugger's willingness to use watchpoint hardware."), _("\
Show debugger's willingness to use watchpoint hardware."), _("\
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.)"),
NULL,
show_can_use_hw_watchpoints,
&setlist, &showlist);
can_use_hw_watchpoints = 1;
add_setshow_zinteger_cmd ("show_breakpoint_hit_counts", class_support,
&show_breakpoint_hit_counts, _("\
Set if GDB should show breakpoint hit counts.\n\
This will affect the output of 'info debug'"), _("\
Set if GDB should show breakpoint hit counts.\n\
This will affect the output of 'info debug'"), NULL,
NULL, NULL,
&setlist, &showlist);
c = add_cmd ("save-breakpoints", class_breakpoint, save_breakpoints_command,
"Save current breakpoint definitions as a script.\n\
Use the -command option or 'source' command in another debug\n\
'session to restore them.", &cmdlist);
set_cmd_completer (c, filename_completer);
add_com_alias ("save_breakpoints", "save-breakpoints", class_breakpoint, 1);
add_com_alias ("save_bp", "save-breakpoints", class_breakpoint, 1);
add_com_alias ("savebp", "save-breakpoints", class_breakpoint, 1);
add_prefix_cmd ("breakpoint", class_maintenance, set_breakpoint_cmd, _("\
Breakpoint specific settings\n\
Configure various breakpoint-specific variables such as\n\
pending breakpoint behavior"),
&breakpoint_set_cmdlist, "set breakpoint ",
0, &setlist);
add_prefix_cmd ("breakpoint", class_maintenance, show_breakpoint_cmd, _("\
Breakpoint specific settings\n\
Configure various breakpoint-specific variables such as\n\
pending breakpoint behavior"),
&breakpoint_show_cmdlist, "show breakpoint ",
0, &showlist);
add_setshow_auto_boolean_cmd ("pending", no_class,
&pending_break_support, _("\
Set debugger's behavior regarding pending breakpoints."), _("\
Show debugger's behavior regarding pending breakpoints."), _("\
If on, an unrecognized breakpoint location will cause gdb to create a\n\
pending breakpoint. If off, an unrecognized breakpoint location results in\n\
an error. If auto, an unrecognized breakpoint location results in a\n\
user-query to see if a pending breakpoint should be created."),
NULL,
show_pending_break_support,
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
pending_break_support = AUTO_BOOLEAN_AUTO;
}