/* Everything about breakpoints, for GDB.
- Copyright (C) 1986, 1987, 1989, 1990 Free Software Foundation, Inc.
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
This file is part of GDB.
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <stdio.h>
-#include <ctype.h>
#include "defs.h"
-#include "param.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 "command.h"
#include "inferior.h"
#include "target.h"
+#include "language.h"
#include <string.h>
+#include "demangle.h"
+
+/* local function prototypes */
+
+static void
+catch_command_1 PARAMS ((char *, int, int));
+
+static void
+enable_delete_command PARAMS ((char *, int));
+
+static void
+enable_delete_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+enable_once_command PARAMS ((char *, int));
+
+static void
+enable_once_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+disable_command PARAMS ((char *, int));
+
+static void
+disable_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+enable_command PARAMS ((char *, int));
+
+static void
+enable_breakpoint PARAMS ((struct breakpoint *));
+
+static void
+map_breakpoint_numbers PARAMS ((char *, void (*)(struct breakpoint *)));
+
+static void
+ignore_command PARAMS ((char *, int));
+
+static int
+breakpoint_re_set_one PARAMS ((char *));
+
+static void
+delete_command PARAMS ((char *, int));
+
+static void
+clear_command PARAMS ((char *, int));
+
+static void
+catch_command PARAMS ((char *, int));
+
+static struct symtabs_and_lines
+get_catch_sals PARAMS ((int));
+
+static void
+watch_command PARAMS ((char *, int));
+
+static void
+tbreak_command PARAMS ((char *, int));
+
+static void
+break_command_1 PARAMS ((char *, int, int));
+
+static void
+mention PARAMS ((struct breakpoint *));
+
+static struct breakpoint *
+set_raw_breakpoint PARAMS ((struct symtab_and_line));
+
+static void
+check_duplicates PARAMS ((CORE_ADDR));
+
+static void
+describe_other_breakpoints PARAMS ((CORE_ADDR));
+
+static void
+breakpoints_info PARAMS ((char *, int));
+
+static void
+breakpoint_1 PARAMS ((int, int));
+
+static bpstat
+bpstat_alloc PARAMS ((struct breakpoint *, bpstat));
+
+static int
+breakpoint_cond_eval PARAMS ((char *));
+
+static void
+cleanup_executing_breakpoints PARAMS ((int));
+
+static void
+commands_command PARAMS ((char *, int));
+
+static void
+condition_command PARAMS ((char *, int));
+
+static int
+get_number PARAMS ((char **));
+
+static void
+set_breakpoint_count PARAMS ((int));
+
extern int addressprint; /* Print machine addresses? */
extern int demangle; /* Print de-mangled symbol names? */
-extern int catch_errors ();
-extern void set_next_address (); /* ...for x/ command */
-
/* Are we executing breakpoint commands? */
static int executing_breakpoint_commands;
-/* States of enablement of breakpoint.
- `temporary' means disable when hit.
- `delete' means delete when hit. */
-
-enum enable { disabled, enabled, temporary, delete};
-
-/* Not that the ->silent field is not currently used by any commands
- (though the code is in there if it was to be, and set_raw_breakpoint
- does set it to 0). I implemented it because I thought it would be
- useful for a hack I had to put in; I'm going to leave it in because
- I can see how there might be times when it would indeed be useful */
-
-/* This is for a breakpoint or a watchpoint. */
-
-struct breakpoint
-{
- struct breakpoint *next;
- /* Number assigned to distinguish breakpoints. */
- int number;
- /* Address to break at, or NULL if not a breakpoint. */
- CORE_ADDR address;
- /* Line number of this address. Redundant. Only matters if address
- is non-NULL. */
- int line_number;
- /* Symtab of file of this address. Redundant. Only matters if address
- is non-NULL. */
- struct symtab *symtab;
- /* Zero means disabled; remember the info but don't break here. */
- enum enable enable;
- /* Non-zero means a silent breakpoint (don't print frame info
- if we stop here). */
- unsigned char silent;
- /* Number of stops at this breakpoint that should
- be continued automatically before really stopping. */
- int ignore_count;
- /* "Real" contents of byte where breakpoint has been inserted.
- Valid only when breakpoints are in the program. Under the complete
- control of the target insert_breakpoint and remove_breakpoint routines.
- No other code should assume anything about the value(s) here. */
- char shadow_contents[BREAKPOINT_MAX];
- /* Nonzero if this breakpoint is now inserted. Only matters if address
- is non-NULL. */
- char inserted;
- /* Nonzero if this is not the first breakpoint in the list
- for the given address. Only matters if address is non-NULL. */
- char duplicate;
- /* Chain of command lines to execute when this breakpoint is hit. */
- struct command_line *commands;
- /* Stack depth (address of frame). If nonzero, break only if fp
- equals this. */
- FRAME_ADDR frame;
- /* Conditional. Break only if this expression's value is nonzero. */
- struct expression *cond;
-
- /* String we used to set the breakpoint (malloc'd). Only matters if
- address is non-NULL. */
- char *addr_string;
- /* String form of the breakpoint condition (malloc'd), or NULL if there
- is no condition. */
- char *cond_string;
-
- /* The expression we are watching, or NULL if not a watchpoint. */
- struct expression *exp;
- /* The largest block within which it is valid, or NULL if it is
- valid anywhere (e.g. consists just of global symbols). */
- struct block *exp_valid_block;
- /* Value of the watchpoint the last time we checked it. */
- value val;
-};
+/* Walk the following statement or block through all breakpoints.
+ ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current
+ breakpoint. */
#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)
+
/* Chain of all breakpoints defined. */
struct breakpoint *breakpoint_chain;
{
breakpoint_count = num;
set_internalvar (lookup_internalvar ("bpnum"),
- value_from_long (builtin_type_int, (LONGEST) num));
+ value_from_longest (builtin_type_int, (LONGEST) num));
}
/* Default address, symtab and line to put a breakpoint at
struct symtab *default_breakpoint_symtab;
int default_breakpoint_line;
-static void delete_breakpoint ();
-void breakpoint_auto_delete ();
-
/* Flag indicating extra verbosity for xgdb. */
extern int xgdb_verbose;
\f
}
else
{
+ if (*p == '-')
+ ++p;
while (*p >= '0' && *p <= '9')
++p;
if (p == *pp)
{
if (b->cond)
{
- free (b->cond);
+ free ((PTR)b->cond);
b->cond = 0;
}
if (b->cond_string != NULL)
- free (b->cond_string);
+ free ((PTR)b->cond_string);
if (*p == 0)
{
b->cond = 0;
b->cond_string = NULL;
if (from_tty)
- printf ("Breakpoint %d now unconditional.\n", bnum);
+ printf_filtered ("Breakpoint %d now unconditional.\n", bnum);
}
else
{
/* I don't know if it matters whether this is the string the user
typed in or the decompiled expression. */
b->cond_string = savestring (arg, strlen (arg));
- b->cond = parse_c_1 (&arg, block_for_pc (b->address), 0);
+ b->cond = parse_exp_1 (&arg, block_for_pc (b->address), 0);
if (*arg)
error ("Junk at end of expression");
}
if (b->number == bnum)
{
if (from_tty && input_from_terminal_p ())
- {
- printf ("Type commands for when breakpoint %d is hit, one per line.\n\
+ printf_filtered ("Type commands for when breakpoint %d is hit, one per line.\n\
End with a line saying just \"end\".\n", bnum);
- fflush (stdout);
- }
l = read_command_lines ();
free_command_lines (&b->commands);
b->commands = l;
extern int memory_breakpoint_size; /* from mem-break.c */
/* Like target_read_memory() but if breakpoints are inserted, return
- the shadow contents instead of the breakpoints themselves. */
+ the shadow contents instead of the breakpoints themselves.
+
+ Read "memory data" from whatever target or inferior we have.
+ Returns zero if successful, errno value if not. EIO is used
+ for address out of bounds. If breakpoints are inserted, returns
+ shadow contents, not the breakpoints themselves. From breakpoint.c. */
+
int
read_memory_nobpt (memaddr, myaddr, len)
CORE_ADDR memaddr;
ALL_BREAKPOINTS (b)
{
- if (b->address == NULL || !b->inserted)
+ if (b->type == bp_watchpoint || !b->inserted)
continue;
else if (b->address + memory_breakpoint_size <= memaddr)
/* The breakpoint is entirely before the chunk of memory
bptlen -= (membpt + bptlen) - (memaddr + len);
}
- bcopy (b->shadow_contents + bptoffset,
- myaddr + membpt - memaddr, bptlen);
+ memcpy (myaddr + membpt - memaddr,
+ b->shadow_contents + bptoffset, bptlen);
if (membpt > memaddr)
{
int disabled_breaks = 0;
ALL_BREAKPOINTS (b)
- if (b->address != NULL
+ if (b->type != bp_watchpoint
&& b->enable != disabled
&& ! b->inserted
&& ! b->duplicate)
#endif
{
fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number);
+#ifdef ONE_PROCESS_WRITETEXT
+ fprintf (stderr,
+ "The same program may be running in another process.\n");
+#endif
memory_error (val, b->address); /* which bombs us out */
}
}
#endif /* BREAKPOINT_DEBUG */
ALL_BREAKPOINTS (b)
- if (b->address != NULL && b->inserted)
+ if (b->type != bp_watchpoint && b->inserted)
{
val = target_remove_breakpoint(b->address, b->shadow_contents);
if (val)
return val;
b->inserted = 0;
#ifdef BREAKPOINT_DEBUG
- printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
- b->address, b->shadow_contents[0], b->shadow_contents[1]);
+ printf ("Removed breakpoint at %s",
+ local_hex_string(b->address));
+ printf (", shadow %s",
+ local_hex_string(b->shadow_contents[0]));
+ printf (", %s.\n",
+ local_hex_string(b->shadow_contents[1]));
#endif /* BREAKPOINT_DEBUG */
}
\f
/* bpstat stuff. External routines' interfaces are documented
in breakpoint.h. */
+
+/* Clear a bpstat so that it says we are not at any breakpoint.
+ Also free any storage that is part of a bpstat. */
+
void
bpstat_clear (bsp)
bpstat *bsp;
q = p->next;
if (p->old_val != NULL)
value_free (p->old_val);
- free (p);
+ free ((PTR)p);
p = q;
}
*bsp = NULL;
}
+/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that
+ is part of the bpstat is copied as well. */
+
bpstat
bpstat_copy (bs)
bpstat bs;
for (; bs != NULL; bs = bs->next)
{
tmp = (bpstat) xmalloc (sizeof (*tmp));
- bcopy (bs, tmp, sizeof (*tmp));
+ memcpy (tmp, bs, sizeof (*tmp));
if (p == NULL)
/* This is the first thing in the chain. */
retval = tmp;
return retval;
}
+/* Find the bpstat associated with this breakpoint */
+
+bpstat
+bpstat_find_breakpoint(bsp, 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;
+}
+
+/* Return the breakpoint number of the first breakpoint we are stopped
+ at. *BSP upon return is a bpstat which points to the remaining
+ breakpoints stopped at (but which is not guaranteed to be good for
+ anything but further calls to bpstat_num).
+ Return 0 if passed a bpstat which does not indicate any breakpoints. */
+
int
bpstat_num (bsp)
bpstat *bsp;
}
}
+/* Modify BS so that the actions will not be performed. */
+
void
bpstat_clear_actions (bs)
bpstat bs;
location. Any of these commands could cause the process to proceed
beyond this point, etc. We look out for such changes by checking
the global "breakpoint_proceeded" after each command. */
+
void
bpstat_do_actions (bsp)
bpstat *bsp;
goto top;
}
}
- clear_momentary_breakpoints ();
executing_breakpoint_commands = 0;
discard_cleanups (old_chain);
}
+/* Print a message indicating what happened. Returns nonzero to
+ say that only the source line should be printed after this (zero
+ return means print the frame as well as the source line). */
+
int
bpstat_print (bs)
bpstat bs;
{
/* bs->breakpoint_at can be NULL if it was a momentary breakpoint
which has since been deleted. */
- if (bs == NULL || bs->breakpoint_at == NULL)
+ if (bs == NULL
+ || bs->breakpoint_at == NULL
+ || (bs->breakpoint_at->type != bp_breakpoint
+ && bs->breakpoint_at->type != bp_watchpoint))
return 0;
/* If bpstat_stop_status says don't print, OK, we won't. An example
if (!bs->print)
return 0;
- if (bs->breakpoint_at->address != NULL)
+ if (bs->breakpoint_at->type == bp_breakpoint)
{
/* I think the user probably only wants to see one breakpoint
number, not all of them. */
breakpoint_cond_eval (exp)
char *exp;
{
- return value_zerop (evaluate_expression ((struct expression *)exp));
+ return !value_true (evaluate_expression ((struct expression *)exp));
}
/* Allocate a new bpstat and chain it to the current one. */
bs->breakpoint_at = b;
/* If the condition is false, etc., don't do the commands. */
bs->commands = NULL;
- bs->momentary = b->number == -3;
+ bs->momentary = b->disposition == delete;
bs->old_val = NULL;
return bs;
}
int real_breakpoint = 0;
#endif
/* Root of the chain of bpstat's */
- struct bpstat__struct root_bs[1];
+ struct bpstat root_bs[1];
/* Pointer to the last thing in the chain currently. */
bpstat bs = root_bs;
if (b->enable == disabled)
continue;
- if (b->address != NULL && b->address != bp_addr)
+
+ if (b->type != bp_watchpoint && b->address != bp_addr)
continue;
+ /* Come here if it's a watchpoint, or if the break address matches */
+
bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */
this_bp_stop = 1;
this_bp_print = 1;
- if (b->exp != NULL) /* Watchpoint */
+ if (b->type == bp_watchpoint)
{
int within_current_scope;
if (b->exp_valid_block != NULL)
select_frame (get_current_frame (), 0);
value_is_zero
= catch_errors (breakpoint_cond_eval, (char *)(b->cond),
- "Error occurred in testing breakpoint condition.");
+ "Error in testing breakpoint condition:\n");
+ /* FIXME-someday, should give breakpoint # */
free_all_values ();
}
if (b->cond && value_is_zero)
else
{
/* We will stop here */
- if (b->enable == temporary)
+ if (b->disposition == disable)
b->enable = disabled;
bs->commands = b->commands;
if (b->silent)
return bs;
}
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+ without hardware support). This isn't related to a specific bpstat,
+ just to things like whether watchpoints are set. */
+
int
bpstat_should_step ()
{
struct breakpoint *b;
ALL_BREAKPOINTS (b)
- if (b->enable != disabled && b->exp != NULL)
+ if (b->enable == enabled && b->type == bp_watchpoint)
return 1;
return 0;
}
is nonzero, process only watchpoints. */
static void
-breakpoint_1 (bnum, watchpoints)
+breakpoint_1 (bnum, allflag)
int bnum;
- int watchpoints;
+ int allflag;
{
register struct breakpoint *b;
register struct command_line *l;
register struct symbol *sym;
CORE_ADDR last_addr = (CORE_ADDR)-1;
- int header_printed = 0;
+ int found_a_breakpoint = 0;
+ static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint",
+ "longjmp", "longjmp resume"};
+ static char *bpdisps[] = {"del", "dis", "keep"};
+ static char bpenables[] = "ny";
+
+ if (!breakpoint_chain)
+ {
+ printf_filtered ("No breakpoints or watchpoints.\n");
+ return;
+ }
ALL_BREAKPOINTS (b)
- if (bnum == -1 || bnum == b->number)
+ if (bnum == -1
+ || bnum == b->number)
{
- if (b->address == NULL && !watchpoints)
- {
- if (bnum == -1)
- continue;
- error ("That is a watchpoint, not a breakpoint.");
- }
- if (b->address != NULL && watchpoints)
- {
- if (bnum == -1)
- continue;
- error ("That is a breakpoint, not a watchpoint.");
- }
-
- if (!header_printed)
+/* We only print out user settable breakpoints unless the allflag is set. */
+ if (!allflag
+ && b->type != bp_breakpoint
+ && b->type != bp_watchpoint)
+ continue;
+
+ if (!found_a_breakpoint++)
+ printf_filtered ("Num Type Disp Enb %sWhat\n",
+ addressprint ? "Address " : "");
+
+ printf_filtered ("%-3d %-14s %-4s %-3c ",
+ b->number,
+ bptypes[(int)b->type],
+ bpdisps[(int)b->disposition],
+ bpenables[(int)b->enable]);
+ switch (b->type)
{
- if (watchpoints)
- printf_filtered (" Enb Expression\n");
- else if (addressprint)
- printf_filtered (" Enb Address Where\n");
- else
- printf_filtered (" Enb Where\n");
- header_printed = 1;
- }
-
- printf_filtered ("#%-3d %c ", b->number, "nyod"[(int) b->enable]);
- if (b->address == NULL) {
- printf_filtered (" ");
- print_expression (b->exp, stdout);
- } else {
+ case bp_watchpoint:
+ print_expression (b->exp, stdout);
+ break;
+ case bp_breakpoint:
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
if (addressprint)
- printf_filtered (" 0x%08x ", b->address);
+ printf_filtered ("%s ", local_hex_string_custom(b->address, "08"));
last_addr = b->address;
if (b->symtab)
sym = find_pc_function (b->address);
if (sym)
{
- fputs_filtered (" in ", stdout);
- fputs_demangled (SYMBOL_NAME (sym), stdout, 1);
+ fputs_filtered ("in ", stdout);
+ fputs_demangled (SYMBOL_NAME (sym), stdout,
+ DMGL_ANSI | DMGL_PARAMS);
fputs_filtered (" at ", stdout);
}
fputs_filtered (b->symtab->filename, stdout);
printf_filtered ("\n");
if (b->frame)
- printf_filtered ("\tstop only in stack frame at 0x%x\n", b->frame);
+ printf_filtered ("\tstop only in stack frame at %s\n",
+ local_hex_string(b->frame));
if (b->cond)
{
printf_filtered ("\tstop only if ");
}
}
- if (!header_printed)
- {
- char *which = watchpoints ? "watch" : "break";
- if (bnum == -1)
- printf_filtered ("No %spoints.\n", which);
- else
- printf_filtered ("No %spoint numbered %d.\n", which, bnum);
- }
-
- /* Compare against (CORE_ADDR)-1 in case some compiler decides
- that a comparison of an unsigned with -1 is always false. */
- if (last_addr != (CORE_ADDR)-1)
- set_next_address (last_addr);
+ if (!found_a_breakpoint
+ && bnum != -1)
+ printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum);
+ else
+ /* Compare against (CORE_ADDR)-1 in case some compiler decides
+ that a comparison of an unsigned with -1 is always false. */
+ if (last_addr != (CORE_ADDR)-1)
+ set_next_address (last_addr);
}
/* ARGSUSED */
breakpoint_1 (bnum, 0);
}
+#if MAINTENANCE_CMDS
+
/* ARGSUSED */
static void
-watchpoints_info (bnum_exp, from_tty)
+maintenance_info_breakpoints (bnum_exp, from_tty)
char *bnum_exp;
int from_tty;
{
breakpoint_1 (bnum, 1);
}
+#endif
+
/* Print a message describing any breakpoints set at PC. */
static void
(b->enable == disabled) ? " (disabled)" : "",
(others > 1) ? "," : ((others == 1) ? " and" : ""));
}
- printf ("also set at pc 0x%x.\n", pc);
+ printf ("also set at pc %s.\n", local_hex_string(pc));
}
}
\f
register struct breakpoint *b;
register int count = 0;
- if (address == NULL) /* Watchpoints are uninteresting */
+ if (address == 0) /* Watchpoints are uninteresting */
return;
ALL_BREAKPOINTS (b)
register struct breakpoint *b, *b1;
b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
- bzero (b, sizeof *b);
+ memset (b, 0, sizeof (*b));
b->address = sal.pc;
b->symtab = sal.symtab;
b->line_number = sal.line;
b->silent = 0;
b->ignore_count = 0;
b->commands = NULL;
- b->frame = NULL;
+ b->frame = 0;
/* Add this breakpoint to the end of the chain
so that a list of breakpoints will come out in order
return b;
}
+static void
+create_longjmp_breakpoint(func_name)
+ char *func_name;
+{
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+ static int internal_breakpoint_number = -1;
+
+ if (func_name != NULL)
+ {
+ struct minimal_symbol *m;
+
+ m = lookup_minimal_symbol(func_name, (struct objfile *)NULL);
+ if (m)
+ sal.pc = m->address;
+ else
+ return;
+ }
+ else
+ sal.pc = 0;
+
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ b = set_raw_breakpoint(sal);
+ if (!b) return;
+
+ b->type = func_name != NULL ? bp_longjmp : bp_longjmp_resume;
+ b->disposition = donttouch;
+ b->enable = disabled;
+ b->silent = 1;
+ if (func_name)
+ b->addr_string = strsave(func_name);
+ b->number = internal_breakpoint_number--;
+}
+
+/* Call this routine when stepping and nexting to enable a breakpoint if we do
+ a longjmp(). When we hit that breakpoint, call
+ set_longjmp_resume_breakpoint() to figure out where we are going. */
+
+void
+enable_longjmp_breakpoint()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp)
+ {
+ b->enable = enabled;
+ check_duplicates (b->address);
+ }
+}
+
+void
+disable_longjmp_breakpoint()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if ( b->type == bp_longjmp
+ || b->type == bp_longjmp_resume)
+ {
+ b->enable = disabled;
+ check_duplicates (b->address);
+ }
+}
+
+/* Call this after hitting the longjmp() breakpoint. Use this to set a new
+ breakpoint at the target of the jmp_buf.
+
+ FIXME - This ought to be done by setting a temporary breakpoint that gets
+ deleted automatically...
+*/
+
+void
+set_longjmp_resume_breakpoint(pc, frame)
+ CORE_ADDR pc;
+ FRAME frame;
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_longjmp_resume)
+ {
+ b->address = pc;
+ b->enable = enabled;
+ if (frame != NULL)
+ b->frame = FRAME_FP(frame);
+ else
+ b->frame = 0;
+ check_duplicates (b->address);
+ return;
+ }
+}
+
/* Set a breakpoint that will evaporate an end of command
at address specified by SAL.
Restrict it to frame FRAME if FRAME is nonzero. */
-void
-set_momentary_breakpoint (sal, frame)
+struct breakpoint *
+set_momentary_breakpoint (sal, frame, type)
struct symtab_and_line sal;
FRAME frame;
+ enum bptype type;
{
register struct breakpoint *b;
b = set_raw_breakpoint (sal);
- b->number = -3;
- b->enable = delete;
+ b->type = type;
+ b->enable = enabled;
+ b->disposition = donttouch;
b->frame = (frame ? FRAME_FP (frame) : 0);
+ return b;
}
+#if 0
void
clear_momentary_breakpoints ()
{
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
- if (b->number == -3)
+ if (b->disposition == delete)
{
delete_breakpoint (b);
break;
}
}
+#endif
\f
/* Tell the user we have just set a breakpoint B. */
static void
mention (b)
struct breakpoint *b;
{
- if (b->exp)
+ switch (b->type)
{
+ case bp_watchpoint:
printf_filtered ("Watchpoint %d: ", b->number);
print_expression (b->exp, stdout);
- }
- else
- {
- printf_filtered ("Breakpoint %d at 0x%x", b->number, b->address);
+ break;
+ case bp_breakpoint:
+ printf_filtered ("Breakpoint %d at %s", b->number,
+ local_hex_string(b->address));
if (b->symtab)
printf_filtered (": file %s, line %d.",
b->symtab->filename, b->line_number);
+ break;
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ break;
}
printf_filtered ("\n");
}
sal.symtab = s;
sal.line = line;
- sal.pc = find_line_pc (sal.symtab, sal.line);
- if (sal.pc == 0)
- error ("No line %d in file \"%s\".\n", sal.line, sal.symtab->filename);
- else
- {
- describe_other_breakpoints (sal.pc);
+ sal.pc = 0;
+ resolve_sal_pc (&sal); /* Might error out */
+ describe_other_breakpoints (sal.pc);
- b = set_raw_breakpoint (sal);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
- b->cond = 0;
- b->addr_string = addr_string;
- if (tempflag)
- b->enable = temporary;
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_breakpoint;
+ b->cond = 0;
+ b->addr_string = addr_string;
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
- mention (b);
- }
+ mention (b);
}
-#endif
+#endif /* 0 */
\f
/* Set a breakpoint according to ARG (function, linenum or *address)
and make it temporary if TEMPFLAG is nonzero. */
char *addr_end;
int i;
- CORE_ADDR pc;
sals.sals = NULL;
sals.nelts = 0;
if (! sals.nelts)
return;
+ /* Resolve all line numbers to PC's, and verify that conditions
+ can be parsed, before setting any breakpoints. */
for (i = 0; i < sals.nelts; i++)
{
- sal = sals.sals[i];
- if (sal.pc == 0 && sal.symtab != 0)
- {
- pc = find_line_pc (sal.symtab, sal.line);
- if (pc == 0)
- error ("No line %d in file \"%s\".",
- sal.line, sal.symtab->filename);
- }
- else
- pc = sal.pc;
+ resolve_sal_pc (&sals.sals[i]);
while (arg && *arg)
{
{
arg += 2;
cond_start = arg;
- cond = parse_c_1 (&arg, block_for_pc (pc), 0);
+ cond = parse_exp_1 (&arg, block_for_pc (sals.sals[i].pc), 0);
cond_end = arg;
}
else
error ("Junk at end of arguments.");
}
- sals.sals[i].pc = pc;
}
+ /* Now set all the breakpoints. */
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
b = set_raw_breakpoint (sal);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
+ b->type = bp_breakpoint;
b->cond = cond;
if (addr_start)
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
- if (tempflag)
- b->enable = temporary;
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
mention (b);
}
printf ("Multiple breakpoints were set.\n");
printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
}
- free (sals.sals);
+ free ((PTR)sals.sals);
+}
+
+/* Helper function for break_command_1 and disassemble_command. */
+
+void
+resolve_sal_pc (sal)
+ struct symtab_and_line *sal;
+{
+ CORE_ADDR pc;
+
+ if (sal->pc == 0 && sal->symtab != 0)
+ {
+ pc = find_line_pc (sal->symtab, sal->line);
+ if (pc == 0)
+ error ("No line %d in file \"%s\".",
+ sal->line, sal->symtab->filename);
+ sal->pc = pc;
+ }
}
void
struct block *exp_valid_block;
struct value *val;
- sal.pc = NULL;
+ sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
/* Parse arguments. */
innermost_block = NULL;
- exp = parse_c_expression (arg);
+ exp = parse_expression (arg);
exp_valid_block = innermost_block;
val = evaluate_expression (exp);
release_value (val);
b = set_raw_breakpoint (sal);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
+ b->type = bp_watchpoint;
+ b->disposition = donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
b->val = val;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
FRAME prev_frame = get_prev_frame (selected_frame);
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
clear_proceed_status ();
error ("Couldn't get information on specified line.");
sal = sals.sals[0];
- free (sals.sals); /* malloc'd, so freed */
+ free ((PTR)sals.sals); /* malloc'd, so freed */
if (*arg)
error ("Junk at end of arguments.");
- if (sal.pc == 0 && sal.symtab != 0)
- sal.pc = find_line_pc (sal.symtab, sal.line);
+ resolve_sal_pc (&sal);
- if (sal.pc == 0)
- error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename);
-
- set_momentary_breakpoint (sal, selected_frame);
+ breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until);
+ old_chain = make_cleanup(delete_breakpoint, breakpoint);
+
/* Keep within the current frame */
if (prev_frame)
fi = get_frame_info (prev_frame);
sal = find_pc_line (fi->pc, 0);
sal.pc = fi->pc;
- set_momentary_breakpoint (sal, prev_frame);
+ breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until);
+ make_cleanup(delete_breakpoint, breakpoint);
}
proceed (-1, -1, 0);
+ do_cleanups(old_chain);
}
\f
#if 0
get_catch_sals (this_level_only)
int this_level_only;
{
- extern struct blockvector *blockvector_for_pc ();
register struct blockvector *bl;
register struct block *block;
int index, have_default = 0;
bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
- bzero (blocks_searched, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+ memset (blocks_searched, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
while (block != 0)
{
/* Commands to deal with catching exceptions. */
-void
+static void
catch_command_1 (arg, tempflag, from_tty)
char *arg;
int tempflag;
register struct breakpoint *b;
char *save_arg;
int i;
- CORE_ADDR pc;
sal.line = sal.pc = sal.end = 0;
sal.symtab = 0;
save_arg = arg;
for (i = 0; i < sals.nelts; i++)
{
- sal = sals.sals[i];
- if (sal.pc == 0 && sal.symtab != 0)
- {
- pc = find_line_pc (sal.symtab, sal.line);
- if (pc == 0)
- error ("No line %d in file \"%s\".",
- sal.line, sal.symtab->filename);
- }
- else
- pc = sal.pc;
+ resolve_sal_pc (&sals.sals[i]);
while (arg && *arg)
{
if (arg[0] == 'i' && arg[1] == 'f'
&& (arg[2] == ' ' || arg[2] == '\t'))
- cond = (struct expression *) parse_c_1 ((arg += 2, &arg),
- block_for_pc (pc), 0);
+ cond = parse_exp_1 ((arg += 2, &arg),
+ block_for_pc (sals.sals[i].pc), 0);
else
error ("Junk at end of arguments.");
}
arg = save_arg;
- sals.sals[i].pc = pc;
}
for (i = 0; i < sals.nelts; i++)
describe_other_breakpoints (sal.pc);
b = set_raw_breakpoint (sal);
- b->number = ++breakpoint_count;
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_breakpoint;
b->cond = cond;
- if (tempflag)
- b->enable = temporary;
+ b->enable = enabled;
+ b->disposition = tempflag ? delete : donttouch;
- printf ("Breakpoint %d at 0x%x", b->number, b->address);
+ printf ("Breakpoint %d at %s", b->number, local_hex_string(b->address));
if (b->symtab)
printf (": file %s, line %d.", b->symtab->filename, b->line_number);
printf ("\n");
printf ("Multiple breakpoints were set.\n");
printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
}
- free (sals.sals);
+ free ((PTR)sals.sals);
}
#if 0
ALL_BREAKPOINTS (b)
while (b->next
- && b->next->address != NULL
+ && b->next->type != bp_watchpoint
&& (sal.pc ? b->next->address == sal.pc
: (b->next->symtab == sal.symtab
&& b->next->line_number == sal.line)))
}
if (from_tty) putchar ('\n');
}
- free (sals.sals);
+ free ((PTR)sals.sals);
}
\f
/* Delete breakpoint in BS if they are `delete' breakpoints.
bpstat bs;
{
for (; bs; bs = bs->next)
- if (bs->breakpoint_at && bs->breakpoint_at->enable == delete)
+ if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete)
delete_breakpoint (bs->breakpoint_at);
}
/* Delete a breakpoint and clean up all traces of it in the data structures. */
-static void
+void
delete_breakpoint (bpt)
struct breakpoint *bpt;
{
free_command_lines (&bpt->commands);
if (bpt->cond)
- free (bpt->cond);
+ free ((PTR)bpt->cond);
if (bpt->cond_string != NULL)
- free (bpt->cond_string);
+ free ((PTR)bpt->cond_string);
if (bpt->addr_string != NULL)
- free (bpt->addr_string);
+ free ((PTR)bpt->addr_string);
- if (xgdb_verbose && bpt->number >=0)
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
printf ("breakpoint #%d deleted\n", bpt->number);
/* Be sure no bpstat's are pointing at it after it's been freed. */
for (bs = stop_bpstat; bs; bs = bs->next)
if (bs->breakpoint_at == bpt)
bs->breakpoint_at = NULL;
- free (bpt);
+ free ((PTR)bpt);
}
-static void map_breakpoint_numbers ();
-
static void
delete_command (arg, from_tty)
char *arg;
struct breakpoint *b = (struct breakpoint *)bint; /* get past catch_errs */
int i;
struct symtabs_and_lines sals;
- struct symtab_and_line sal;
char *s;
+ enum enable save_enable;
- if (b->address != NULL && b->addr_string != NULL)
+ switch (b->type)
{
+ case bp_breakpoint:
+ if (b->addr_string == NULL)
+ {
+ /* Anything without a string can't be re-set. */
+ delete_breakpoint (b);
+ return 0;
+ }
+ /* In case we have a problem, disable this breakpoint. We'll restore
+ its status if we succeed. */
+ save_enable = b->enable;
+ b->enable = disabled;
+
s = b->addr_string;
sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0);
for (i = 0; i < sals.nelts; i++)
{
- sal = sals.sals[i];
-
- b->symtab = sal.symtab;
- b->line_number = sal.line;
- if (sal.pc == 0 && sal.symtab != 0)
+ resolve_sal_pc (&sals.sals[i]);
+ if (b->symtab != sals.sals[i].symtab
+ || b->line_number != sals.sals[i].line
+ || b->address != sals.sals[i].pc)
{
- sal.pc = find_line_pc (sal.symtab, sal.line);
- if (sal.pc == 0)
- error ("No line %d in file \"%s\".",
- sal.line, sal.symtab->filename);
- }
- b->address = sal.pc;
+ b->symtab = sals.sals[i].symtab;
+ b->line_number = sals.sals[i].line;
+ b->address = sals.sals[i].pc;
- if (b->cond_string != NULL)
- {
- s = b->cond_string;
- b->cond = parse_c_1 (&s, block_for_pc (sal.pc), 0);
- }
+ if (b->cond_string != NULL)
+ {
+ s = b->cond_string;
+ b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0);
+ }
- check_duplicates (b->address);
+ check_duplicates (b->address);
- mention (b);
+ mention (b);
+ }
+ b->enable = save_enable; /* Restore it, this worked. */
}
- free (sals.sals);
- }
- else
- {
- /* Anything without a string can't be re-set. */
+ free ((PTR)sals.sals);
+ break;
+ case bp_watchpoint:
+ /* FIXME! This is the wrong thing to do.... */
+ delete_breakpoint (b);
+ break;
+ default:
+ printf_filtered ("Deleting unknown breakpoint type %d\n", b->type);
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
delete_breakpoint (b);
+ break;
}
+
return 0;
}
void
breakpoint_re_set ()
{
- struct breakpoint *b;
+ struct breakpoint *b, *temp;
+ static char message1[] = "Error in re-setting breakpoint %d:\n";
+ char message[sizeof (message1) + 30 /* slop */];
- ALL_BREAKPOINTS (b)
+ /* If we have no current source symtab, and we have any breakpoints,
+ go through the work of making a source context. */
+ if (current_source_symtab == NULL)
+ {
+ ALL_BREAKPOINTS (b)
+ {
+ select_source_symtab (NULL);
+ break; /* We only care if there are any, and
+ don't need to do it N times. */
+ }
+ }
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
{
- b->symtab = 0; /* Be sure we don't point to old dead symtab */
- (void) catch_errors (breakpoint_re_set_one, (char *) b,
- "Error in re-setting breakpoint");
+ sprintf (message, message1, b->number); /* Format possible error msg */
+ catch_errors (breakpoint_re_set_one, (char *) b, message);
}
+ create_longjmp_breakpoint("longjmp");
+ create_longjmp_breakpoint("_longjmp");
+ create_longjmp_breakpoint("siglongjmp");
+ create_longjmp_breakpoint(NULL);
+
+#if 0
+ /* Took this out (temporaliy at least), since it produces an extra
+ blank line at startup. This messes up the gdbtests. -PB */
/* Blank line to finish off all those mention() messages we just printed. */
printf_filtered ("\n");
+#endif
}
\f
/* Set ignore-count of breakpoint number BPTNUM to COUNT.
if (!from_tty)
return;
else if (count == 0)
- printf ("Will stop next time breakpoint %d is reached.", bptnum);
+ printf_filtered ("Will stop next time breakpoint %d is reached.",
+ bptnum);
else if (count == 1)
- printf ("Will ignore next crossing of breakpoint %d.", bptnum);
+ printf_filtered ("Will ignore next crossing of breakpoint %d.",
+ bptnum);
else
- printf ("Will ignore next %d crossings of breakpoint %d.",
+ printf_filtered ("Will ignore next %d crossings of breakpoint %d.",
count, bptnum);
return;
}
set_ignore_count (num,
longest_to_int (value_as_long (parse_and_eval (p))),
from_tty);
- printf ("\n");
+ printf_filtered ("\n");
}
\f
/* Call FUNCTION on each of the breakpoints
static void
map_breakpoint_numbers (args, function)
char *args;
- void (*function) ();
+ void (*function) PARAMS ((struct breakpoint *));
{
register char *p = args;
char *p1;
{
bpt->enable = enabled;
- if (xgdb_verbose && bpt->number >= 0)
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
printf ("breakpoint #%d enabled\n", bpt->number);
check_duplicates (bpt->address);
- if (bpt->val != NULL)
+ if (bpt->type == bp_watchpoint)
{
if (bpt->exp_valid_block != NULL
&& !contained_in (get_selected_block (), bpt->exp_valid_block))
struct breakpoint *bpt;
if (args == 0)
ALL_BREAKPOINTS (bpt)
- enable_breakpoint (bpt);
+ switch (bpt->type)
+ {
+ case bp_breakpoint:
+ case bp_watchpoint:
+ enable_breakpoint (bpt);
+ default:
+ continue;
+ }
else
map_breakpoint_numbers (args, enable_breakpoint);
}
{
bpt->enable = disabled;
- if (xgdb_verbose && bpt->number >= 0)
- printf ("breakpoint #%d disabled\n", bpt->number);
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
+ printf_filtered ("breakpoint #%d disabled\n", bpt->number);
check_duplicates (bpt->address);
}
register struct breakpoint *bpt;
if (args == 0)
ALL_BREAKPOINTS (bpt)
- disable_breakpoint (bpt);
+ switch (bpt->type)
+ {
+ case bp_breakpoint:
+ case bp_watchpoint:
+ disable_breakpoint (bpt);
+ default:
+ continue;
+ }
else
map_breakpoint_numbers (args, disable_breakpoint);
}
enable_once_breakpoint (bpt)
struct breakpoint *bpt;
{
- bpt->enable = temporary;
+ bpt->enable = enabled;
+ bpt->disposition = disable;
check_duplicates (bpt->address);
}
enable_delete_breakpoint (bpt)
struct breakpoint *bpt;
{
- bpt->enable = delete;
+ bpt->enable = enabled;
+ bpt->disposition = delete;
check_duplicates (bpt->address);
}
return sals;
}
\f
-
-/* Chain containing all defined enable commands. */
-
-extern struct cmd_list_element
- *enablelist, *disablelist,
- *deletelist, *enablebreaklist;
-
-extern struct cmd_list_element *cmdlist;
-
void
_initialize_breakpoint ()
{
add_com ("condition", class_breakpoint, condition_command,
"Specify breakpoint number N to break only if COND is true.\n\
-N is an integer; COND is a C expression to be evaluated whenever\n\
-breakpoint N is reached. Actually break only when COND is nonzero.");
+N is an integer; COND is an expression to be evaluated whenever\n\
+breakpoint N is reached. ");
add_com ("tbreak", class_breakpoint, tbreak_command,
"Set a temporary breakpoint. Args like \"break\" command.\n\
add_com_alias ("brea", "break", class_run, 1);
add_info ("breakpoints", breakpoints_info,
- "Status of all breakpoints, or breakpoint number NUMBER.\n\
-Second column is \"y\" for enabled breakpoint, \"n\" for disabled,\n\
-\"o\" for enabled once (disable when hit), \"d\" for enable but delete when hit.\n\
-Then come the address and the file/line number.\n\n\
+ "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 MAINTENANCE_CMDS
+
+ 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);
+
+#endif /* MAINTENANCE_CMDS */
+
add_com ("catch", class_breakpoint, catch_command,
"Set breakpoints to catch exceptions that are raised.\n\
Argument may be a single exception to catch, multiple exceptions\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression changes.");
- add_info ("watchpoints", watchpoints_info,
- "Status of all watchpoints, or watchpoint number NUMBER.\n\
-Second column is \"y\" for enabled watchpoints, \"n\" for disabled.");
+ add_info ("watchpoints", breakpoints_info,
+ "Synonym for ``info breakpoints''.");
}
+
+#ifdef IBM6000_TARGET
+/* Where should this function go? It is used by AIX only. FIXME. */
+
+/* Breakpoint address relocation used to be done in breakpoint_re_set(). That
+ approach the following problem:
+
+ before running the program, if a file is list, then a breakpoint is
+ set (just the line number), then if we switch into another file and run
+ the program, just a line number as a breakpoint address was not
+ descriptive enough and breakpoint was ending up in a different file's
+ similar line.
+
+ I don't think any other platform has this breakpoint relocation problem, so this
+ is not an issue for other platforms. */
+
+void
+fixup_breakpoints (low, high, delta)
+ CORE_ADDR low;
+ CORE_ADDR high;
+ CORE_ADDR delta;
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->address >= low && b->address <= high)
+ b->address += delta;
+ }
+}
+#endif