diff options
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r-- | gdb/breakpoint.c | 369 |
1 files changed, 264 insertions, 105 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index c5acf96..fd6a0ba 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -19,7 +19,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" @@ -32,10 +31,16 @@ static char break_insn[] = BREAKPOINT; /* States of enablement of breakpoint. `temporary' means disable when hit. - `once' means delete 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 */ + struct breakpoint { struct breakpoint *next; @@ -49,6 +54,9 @@ struct breakpoint 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; @@ -62,8 +70,9 @@ struct breakpoint char duplicate; /* Chain of command lines to execute when this breakpoint is hit. */ struct command_line *commands; - /* Stack depth (frame). If nonzero, break only if fp equals this. */ - FRAME frame; + /* 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; }; @@ -95,10 +104,6 @@ int default_breakpoint_line; struct command_line *breakpoint_commands; -START_FILE - -extern char *read_line (); - static void delete_breakpoint (); void clear_momentary_breakpoints (); void breakpoint_auto_delete (); @@ -161,9 +166,6 @@ commands_command (arg) register int bnum; struct command_line *l; - if (arg == 0) - error_no_arg ("breakpoint number"); - /* If we allowed this, we would have problems with when to free the storage, if we change the commands currently being read from. */ @@ -171,15 +173,21 @@ commands_command (arg) if (breakpoint_commands) error ("Can't use the \"commands\" command among a breakpoint's commands."); - p = arg; - if (! (*p >= '0' && *p <= '9')) - error ("Argument must be integer (a breakpoint number)."); - - while (*p >= '0' && *p <= '9') p++; - if (*p) - error ("Unexpected extra arguments following breakpoint number."); - - bnum = atoi (arg); + /* Allow commands by itself to refer to the last breakpoint. */ + if (arg == 0) + bnum = breakpoint_count; + else + { + p = arg; + if (! (*p >= '0' && *p <= '9')) + error ("Argument must be integer (a breakpoint number)."); + + while (*p >= '0' && *p <= '9') p++; + if (*p) + error ("Unexpected extra arguments following breakpoint number."); + + bnum = atoi (arg); + } ALL_BREAKPOINTS (b) if (b->number == bnum) @@ -254,7 +262,10 @@ insert_breakpoints () register struct breakpoint *b; int val; -/* printf ("Inserting breakpoints.\n"); */ +#ifdef BREAKPOINT_DEBUG + printf ("Inserting breakpoints.\n"); +#endif /* BREAKPOINT_DEBUG */ + ALL_BREAKPOINTS (b) if (b->enable != disabled && ! b->inserted && ! b->duplicate) { @@ -262,8 +273,10 @@ insert_breakpoints () val = write_memory (b->address, break_insn, sizeof break_insn); if (val) return val; -/* printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", - b->address, b->shadow_contents[0], b->shadow_contents[1]); */ +#ifdef BREAKPOINT_DEBUG + printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", + b->address, b->shadow_contents[0], b->shadow_contents[1]); +#endif /* BREAKPOINT_DEBUG */ b->inserted = 1; } return 0; @@ -275,7 +288,10 @@ remove_breakpoints () register struct breakpoint *b; int val; -/* printf ("Removing breakpoints.\n"); */ +#ifdef BREAKPOINT_DEBUG + printf ("Removing breakpoints.\n"); +#endif /* BREAKPOINT_DEBUG */ + ALL_BREAKPOINTS (b) if (b->inserted) { @@ -283,8 +299,10 @@ remove_breakpoints () if (val) return val; b->inserted = 0; -/* printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", - b->address, b->shadow_contents[0], b->shadow_contents[1]); */ +#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]); +#endif /* BREAKPOINT_DEBUG */ } return 0; @@ -293,7 +311,7 @@ remove_breakpoints () /* Clear the "inserted" flag in all breakpoints. This is done when the inferior is loaded. */ -int +void mark_breakpoints_out () { register struct breakpoint *b; @@ -334,12 +352,13 @@ breakpoint_cond_eval (exp) or -2 if breakpoint says it has deleted itself and don't stop, or -3 if hit a breakpoint number -3 (delete when program stops), or else the number of the breakpoint, - with 0x1000000 added for a silent breakpoint. */ + with 0x1000000 added (or subtracted, for a negative return value) for + a silent breakpoint. */ int -breakpoint_stop_status (pc, frame) +breakpoint_stop_status (pc, frame_address) CORE_ADDR pc; - FRAME frame; + FRAME_ADDR frame_address; { register struct breakpoint *b; register int cont = 0; @@ -350,7 +369,7 @@ breakpoint_stop_status (pc, frame) ALL_BREAKPOINTS (b) if (b->enable != disabled && b->address == pc) { - if (b->frame && b->frame != frame) + if (b->frame && b->frame != frame_address) cont = -1; else { @@ -376,11 +395,15 @@ breakpoint_stop_status (pc, frame) if (b->enable == temporary) b->enable = disabled; breakpoint_commands = b->commands; - if (breakpoint_commands - && !strcmp ("silent", breakpoint_commands->line)) + if (b->silent + || (breakpoint_commands + && !strcmp ("silent", breakpoint_commands->line))) { - breakpoint_commands = breakpoint_commands->next; - return 0x1000000 + b->number; + if (breakpoint_commands) + breakpoint_commands = breakpoint_commands->next; + return (b->number > 0 ? + 0x1000000 + b->number : + b->number - 0x1000000); } return b->number; } @@ -538,6 +561,7 @@ set_raw_breakpoint (sal) b->line_number = sal.line; b->enable = enabled; b->next = 0; + b->silent = 0; /* Add this breakpoint to the end of the chain so that a list of breakpoints will come out in order @@ -571,7 +595,7 @@ set_momentary_breakpoint (sal, frame) b = set_raw_breakpoint (sal); b->number = -3; b->enable = delete; - b->frame = frame; + b->frame = (frame ? FRAME_FP (frame) : 0); } void @@ -622,14 +646,12 @@ set_breakpoint (s, line, tempflag) } /* Set a breakpoint according to ARG (function, linenum or *address) - and make it temporary if TEMPFLAG is nonzero. - - LINE_NUM is for C++. */ + and make it temporary if TEMPFLAG is nonzero. */ static void -break_command_1 (arg, tempflag, from_tty, line_num) +break_command_1 (arg, tempflag, from_tty) char *arg; - int tempflag, from_tty, line_num; + int tempflag, from_tty; { struct symtabs_and_lines sals; struct symtab_and_line sal; @@ -637,6 +659,7 @@ break_command_1 (arg, tempflag, from_tty, line_num) register struct breakpoint *b; char *save_arg; int i; + CORE_ADDR pc; sals.sals = NULL; sals.nelts = 0; @@ -644,58 +667,64 @@ break_command_1 (arg, tempflag, from_tty, line_num) sal.line = sal.pc = sal.end = 0; sal.symtab = 0; - if (arg) - { - CORE_ADDR pc; - sals = decode_line_1 (&arg, 1, 0, 0); + /* If no arg given, or if first arg is 'if ', use the default breakpoint. */ - if (! sals.nelts) return; - save_arg = arg; - for (i = 0; i < sals.nelts; i++) + if (!arg || (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t'))) + { + if (default_breakpoint_valid) { - 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; - - while (*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); - else - error ("Junk at end of arguments."); - } - arg = save_arg; - sals.sals[i].pc = pc; + sals.sals = (struct symtab_and_line *) + malloc (sizeof (struct symtab_and_line)); + sal.pc = default_breakpoint_address; + sal.line = default_breakpoint_line; + sal.symtab = default_breakpoint_symtab; + sals.sals[0] = sal; + sals.nelts = 1; } - } - else if (default_breakpoint_valid) - { - sals.sals = (struct symtab_and_line *) malloc (sizeof (struct symtab_and_line)); - sal.pc = default_breakpoint_address; - sal.line = default_breakpoint_line; - sal.symtab = default_breakpoint_symtab; - sals.sals[0] = sal; - sals.nelts = 1; + else + error ("No default breakpoint address now."); } else - error ("No default breakpoint address now."); + if (default_breakpoint_valid) + sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, + default_breakpoint_line); + else + sals = decode_line_1 (&arg, 1, 0, 0); + + if (! sals.nelts) + return; + save_arg = arg; for (i = 0; i < sals.nelts; i++) { sal = sals.sals[i]; - sal.line += line_num; /** C++ **/ - if (line_num != 0) - { /* get the pc for a particular line */ - sal.pc = find_line_pc (sal.symtab, sal.line); + 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; + + 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); + else + error ("Junk at end of arguments."); } + arg = save_arg; + sals.sals[i].pc = pc; + } + + for (i = 0; i < sals.nelts; i++) + { + sal = sals.sals[i]; if (from_tty) describe_other_breakpoints (sal.pc); @@ -711,6 +740,12 @@ break_command_1 (arg, tempflag, from_tty, line_num) printf (": file %s, line %d.", b->symtab->filename, b->line_number); printf ("\n"); } + + if (sals.nelts > 1) + { + printf ("Multiple breakpoints were set.\n"); + printf ("Use the \"delete\" command to delete unwanted breakpoints.\n"); + } free (sals.sals); } @@ -719,7 +754,7 @@ break_command (arg, from_tty) char *arg; int from_tty; { - break_command_1 (arg, 0, from_tty, 0); + break_command_1 (arg, 0, from_tty); } static void @@ -727,7 +762,62 @@ tbreak_command (arg, from_tty) char *arg; int from_tty; { - break_command_1 (arg, 1, from_tty, 0); + break_command_1 (arg, 1, from_tty); +} + +/* + * Helper routine for the until_command routine in infcmd.c. Here + * because it uses the mechanisms of breakpoints. + */ +void +until_break_command(arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + FRAME frame = get_current_frame (); + FRAME prev_frame = get_prev_frame (frame); + + /* Set a breakpoint where the user wants it and at return from + this function */ + + if (default_breakpoint_valid) + sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, + default_breakpoint_line); + else + sals = decode_line_1 (&arg, 1, 0, 0); + + if (sals.nelts != 1) + error ("Couldn't get information on specified line."); + + sal = sals.sals[0]; + free (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); + + if (sal.pc == 0) + error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename); + + set_momentary_breakpoint (sal, 0); + + /* Keep within the current frame */ + + if (prev_frame) + { + struct frame_info *fi; + + fi = get_frame_info (prev_frame); + sal = find_pc_line (fi->pc, 0); + sal.pc = fi->pc; + set_momentary_breakpoint (sal, prev_frame); + } + + proceed (-1, -1, 0); } static void @@ -742,7 +832,9 @@ clear_command (arg, from_tty) int i; if (arg) - sals = decode_line_spec (arg, 1); + { + sals = decode_line_spec (arg, 1); + } else { sals.sals = (struct symtab_and_line *) malloc (sizeof (struct symtab_and_line)); @@ -801,7 +893,7 @@ clear_command (arg, from_tty) } free (sals.sals); } - + /* Delete breakpoint number BNUM if it is a `delete' breakpoint. This is called after breakpoint BNUM has been hit. Also delete any breakpoint numbered -3 unless there are breakpoint @@ -851,7 +943,7 @@ delete_breakpoint (bpt) free (bpt); } -void map_breakpoint_numbers (); +static void map_breakpoint_numbers (); static void delete_command (arg, from_tty) @@ -1048,19 +1140,41 @@ enable_delete_command (args) map_breakpoint_numbers (args, enable_delete_breakpoint); } +/* + * Use default_breakpoint_'s, or nothing if they aren't valid. + */ +struct symtabs_and_lines +decode_line_spec_1 (string, funfirstline) + 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); + else + sals = decode_line_1 (&string, funfirstline, 0, 0); + if (*string) + error ("Junk at end of line specification: %s", string); + return sals; +} + /* Chain containing all defined enable commands. */ -struct cmd_list_element *enablelist; +extern struct cmd_list_element + *enablelist, *disablelist, + *deletelist, *enablebreaklist; extern struct cmd_list_element *cmdlist; -static -initialize () +void +_initialize_breakpoint () { breakpoint_chain = 0; breakpoint_count = 0; - enablelist = 0; add_com ("ignore", class_breakpoint, ignore_command, "Set ignore-count of breakpoint number N to COUNT."); @@ -1068,6 +1182,7 @@ initialize () 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\ @@ -1085,35 +1200,80 @@ so it will be disabled when hit. Equivalent to \"break\" followed\n\ by using \"enable once\" on the breakpoint number."); add_prefix_cmd ("enable", class_breakpoint, enable_command, - "Enable some breakpoints. Give breakpoint numbers as arguments.\n\ + "Enable some breakpoints or auto-display expressions.\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.", +With a subcommand you can enable temporarily.\n\ +\n\ +The \"display\" subcommand applies to auto-displays instead of breakpoints.", &enablelist, "enable ", 1, &cmdlist); - add_cmd ("delete", 0, enable_delete_command, + add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command, + "Enable some breakpoints or auto-display expressions.\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\ +May be abbreviates to simply \"enable\".\n\ +With a subcommand you can enable temporarily.", + &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.\n\ +See the \"tbreak\" command which sets a breakpoint and enables it once.", + &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", 0, enable_once_command, + 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.\n\ See the \"tbreak\" command which sets a breakpoint and enables it once.", &enablelist); - add_com ("disable", class_breakpoint, disable_command, - "Disable some breakpoints. Give breakpoint numbers as arguments.\n\ -With no arguments, disable all breakpoints.\n\ -A disabled breakpoint is not forgotten,\n\ -but it has no effect until enabled again."); + add_prefix_cmd ("disable", class_breakpoint, disable_command, + "Disable some breakpoints or auto-display expressions.\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\ +\n\ +The \"display\" subcommand applies to auto-displays instead of breakpoints.", + &disablelist, "disable ", 1, &cmdlist); add_com_alias ("dis", "disable", class_breakpoint, 1); - add_com ("delete", class_breakpoint, delete_command, - "Delete breakpoints, specifying breakpoint numbers; or all breakpoints.\n\ + add_abbrev_cmd ("breakpoints", class_breakpoint, disable_command, + "Disable some breakpoints or auto-display expressions.\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."); +To delete all breakpoints, give no argument.\n\ +\n\ +The \"display\" subcommand applies to auto-displays instead of breakpoints.", + &deletelist, "delete ", 1, &cmdlist); add_com_alias ("d", "delete", class_breakpoint, 1); + add_com_alias ("unset", "delete", class_breakpoint, 1); + + add_abbrev_cmd ("breakpoints", 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\ +This command may be abbreviated \"delete\".", + &deletelist); add_com ("clear", class_breakpoint, clear_command, "Clear breakpoint at specified line or function.\n\ @@ -1152,4 +1312,3 @@ Convenience variable \"$_\" and default examine address for \"x\"\n\ are set to the address of the last breakpoint listed."); } -END_FILE |