X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fbreakpoint.c;h=b3494576618f85e712ab774808ef243aabab6305;hb=ac16bf075e8f8b82746c2daa5063fec3133e374b;hp=86e700eeac7a44bac8a8b4f814938ea5b77d519e;hpb=6e31adb3f7c1c5db158558c23e13d11091046d43;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 86e700eeac..b349457661 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -1,7 +1,7 @@ /* Everything about breakpoints, for GDB. Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, - 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GDB. @@ -41,10 +41,14 @@ #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 "gdb_assert.h" +#include "block.h" #include "gdb-events.h" @@ -70,16 +74,12 @@ static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *)); static void ignore_command (char *, int); -static int breakpoint_re_set_one (PTR); +static int breakpoint_re_set_one (void *); static void clear_command (char *, int); static void catch_command (char *, int); -static void handle_gnu_4_16_catch_command (char *, int, int); - -static struct symtabs_and_lines get_catch_sals (int); - static void watch_command (char *, int); static int can_use_hardware_watchpoint (struct value *); @@ -105,9 +105,9 @@ static void breakpoint_1 (int, int); static bpstat bpstat_alloc (struct breakpoint *, bpstat); -static int breakpoint_cond_eval (PTR); +static int breakpoint_cond_eval (void *); -static void cleanup_executing_breakpoints (PTR); +static void cleanup_executing_breakpoints (void *); static void commands_command (char *, int); @@ -137,9 +137,9 @@ typedef struct } args_for_catchpoint_enable; -static int watchpoint_check (PTR); +static int watchpoint_check (void *); -static int cover_target_enable_exception_callback (PTR); +static int cover_target_enable_exception_callback (void *); static void maintenance_info_breakpoints (char *, int); @@ -715,17 +715,41 @@ insert_breakpoints (void) int return_val = 0; /* return success code. */ int val = 0; int disabled_breaks = 0; + int hw_breakpoint_error = 0; +#ifdef ONE_PROCESS_WRITETEXT + int process_warning = 0; +#endif static char message1[] = "Error inserting catchpoint %d:\n"; static char message[sizeof (message1) + 30]; + struct ui_file *tmp_error_stream = mem_fileopen (); + make_cleanup_ui_file_delete (tmp_error_stream); + + /* Explicitly mark the warning -- this will only be printed if + there was an error. */ + fprintf_unfiltered (tmp_error_stream, "Warning:\n"); ALL_BREAKPOINTS_SAFE (b, temp) { - if (b->enable_state == bp_permanent) - /* Permanent breakpoints cannot be inserted or removed. */ + /* Permanent breakpoints cannot be inserted or removed. Disabled + breakpoints should not be inserted. */ + if (b->enable_state != bp_enabled) continue; - else if (b->type != bp_watchpoint + + if ((b->type == bp_watchpoint + || b->type == bp_hardware_watchpoint + || b->type == bp_read_watchpoint + || b->type == bp_access_watchpoint) && (!b->val)) + { + struct value *val; + val = evaluate_expression (b->exp); + release_value (val); + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + b->val = val; + } + if (b->type != bp_watchpoint && b->type != bp_hardware_watchpoint && b->type != bp_read_watchpoint && b->type != bp_access_watchpoint @@ -734,9 +758,6 @@ insert_breakpoints (void) && b->type != bp_catch_exec && b->type != bp_catch_throw && b->type != bp_catch_catch - && b->enable_state != bp_disabled - && b->enable_state != bp_shlib_disabled - && b->enable_state != bp_call_disabled && !b->inserted && !b->duplicate) { @@ -776,8 +797,9 @@ insert_breakpoints (void) /* Set a software (trap) breakpoint at the LMA. */ val = target_insert_breakpoint (addr, b->shadow_contents); if (val != 0) - warning ("overlay breakpoint %d failed: in ROM?", - b->number); + fprintf_unfiltered (tmp_error_stream, + "Overlay breakpoint %d failed: in ROM?", + b->number); } } /* Shall we set a breakpoint at the VMA? */ @@ -810,22 +832,41 @@ insert_breakpoints (void) b->enable_state = bp_shlib_disabled; if (!disabled_breaks) { - target_terminal_ours_for_output (); - warning ("Cannot insert breakpoint %d:", b->number); - warning ("Temporarily disabling shared library breakpoints:"); + fprintf_unfiltered (tmp_error_stream, + "Cannot insert breakpoint %d.\n", + b->number); + fprintf_unfiltered (tmp_error_stream, + "Temporarily disabling shared library breakpoints:\n"); } disabled_breaks = 1; - warning ("breakpoint #%d ", b->number); + fprintf_unfiltered (tmp_error_stream, + "breakpoint #%d\n", b->number); } else #endif { - target_terminal_ours_for_output (); - warning ("Cannot insert breakpoint %d:", b->number); #ifdef ONE_PROCESS_WRITETEXT - warning ("The same program may be running in another process."); + process_warning = 1; #endif - memory_error (val, b->address); /* which bombs us out */ + if (b->type == bp_hardware_breakpoint) + { + hw_breakpoint_error = 1; + fprintf_unfiltered (tmp_error_stream, + "Cannot insert hardware breakpoint %d.\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 "); + print_address_numeric (b->address, 1, tmp_error_stream); + fprintf_filtered (tmp_error_stream, ": %s.\n", + safe_strerror (val)); + } + } } else @@ -835,9 +876,6 @@ insert_breakpoints (void) return_val = val; /* remember failure */ } else if (ep_is_exception_catchpoint (b) - && b->enable_state != bp_disabled - && b->enable_state != bp_shlib_disabled - && b->enable_state != bp_call_disabled && !b->inserted && !b->duplicate) @@ -852,9 +890,14 @@ insert_breakpoints (void) if (val) { /* Couldn't set breakpoint for some reason */ - target_terminal_ours_for_output (); - warning ("Cannot insert catchpoint %d; disabling it.", - b->number); + fprintf_unfiltered (tmp_error_stream, + "Cannot insert catchpoint %d; disabling it.\n", + b->number); + fprintf_filtered (tmp_error_stream, + "Error accessing memory address "); + print_address_numeric (b->address, 1, tmp_error_stream); + fprintf_filtered (tmp_error_stream, ": %s.\n", + safe_strerror (val)); b->enable_state = bp_disabled; } else @@ -876,9 +919,9 @@ insert_breakpoints (void) if (val == -1) { /* something went wrong */ - target_terminal_ours_for_output (); - warning ("Cannot insert catchpoint %d; disabling it.", - b->number); + fprintf_unfiltered (tmp_error_stream, + "Cannot insert catchpoint %d; disabling it.\n", + b->number); b->enable_state = bp_disabled; } } @@ -890,7 +933,6 @@ insert_breakpoints (void) else if ((b->type == bp_hardware_watchpoint || b->type == bp_read_watchpoint || b->type == bp_access_watchpoint) - && b->enable_state == bp_enabled && b->disposition != disp_del_at_next_stop && !b->inserted && !b->duplicate) @@ -902,8 +944,8 @@ insert_breakpoints (void) /* Save the current frame and level so we can restore it after evaluating the watchpoint expression on its own frame. */ - saved_frame = selected_frame; - saved_level = frame_relative_level (selected_frame); + saved_frame = deprecated_selected_frame; + saved_level = frame_relative_level (deprecated_selected_frame); /* Determine if the watchpoint is within scope. */ if (b->exp_valid_block == NULL) @@ -955,7 +997,7 @@ insert_breakpoints (void) addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v); len = TYPE_LENGTH (VALUE_TYPE (v)); - type = hw_write; + type = hw_write; if (b->type == bp_read_watchpoint) type = hw_read; else if (b->type == bp_access_watchpoint) @@ -981,8 +1023,10 @@ insert_breakpoints (void) if (!b->inserted) { remove_breakpoint (b, mark_uninserted); - warning ("Could not insert hardware watchpoint %d.", - b->number); + hw_breakpoint_error = 1; + fprintf_unfiltered (tmp_error_stream, + "Could not insert hardware watchpoint %d.\n", + b->number); val = -1; } } @@ -997,8 +1041,8 @@ insert_breakpoints (void) } /* Restore the frame and level. */ - if ((saved_frame != selected_frame) || - (saved_level != frame_relative_level (selected_frame))) + if ((saved_frame != deprecated_selected_frame) || + (saved_level != frame_relative_level (deprecated_selected_frame))) select_frame (saved_frame); if (val) @@ -1007,7 +1051,6 @@ insert_breakpoints (void) else if ((b->type == bp_catch_fork || b->type == bp_catch_vfork || b->type == bp_catch_exec) - && b->enable_state == bp_enabled && !b->inserted && !b->duplicate) { @@ -1029,8 +1072,8 @@ insert_breakpoints (void) } if (val < 0) { - target_terminal_ours_for_output (); - warning ("Cannot insert catchpoint %d.", b->number); + fprintf_unfiltered (tmp_error_stream, + "Cannot insert catchpoint %d.", b->number); } else b->inserted = 1; @@ -1039,11 +1082,28 @@ insert_breakpoints (void) return_val = val; /* remember failure */ } } - + + if (return_val) + { + /* If a hardware breakpoint or watchpoint was inserted, add a + message about possibly exhausted resources. */ + 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 (); + error_stream (tmp_error_stream); + } return return_val; } - int remove_breakpoints (void) { @@ -1175,8 +1235,8 @@ update_breakpoints_after_exec (void) automagically. Certainly on HP-UX that's true. Jim Blandy : Actually, zero is a perfectly - valid code address on some platforms (like the mn10200 and - mn10300 simulators). We shouldn't assign any special + valid code address on some platforms (like the OBSOLETE mn10200 + and mn10300 simulators). We shouldn't assign any special interpretation to a breakpoint with a zero address. And in fact, GDB doesn't --- I can't see what that comment above is talking about. As far as I can tell, setting the address of a @@ -1520,6 +1580,14 @@ breakpoint_init_inferior (enum inf_context context) /* Likewise for watchpoints on local expressions. */ if (b->exp_valid_block != NULL) delete_breakpoint (b); + if (context == inf_starting) + { + /* Reset val field to force reread of starting value + in insert_breakpoints. */ + if (b->val) + value_free (b->val); + b->val = NULL; + } break; default: /* Likewise for exception catchpoints in dynamic-linked @@ -1606,32 +1674,31 @@ breakpoint_inserted_here_p (CORE_ADDR pc) } /* Return nonzero if FRAME is a dummy frame. We can't use - PC_IN_CALL_DUMMY because figuring out the saved SP would take too - much time, at least using get_saved_register on the 68k. This - means that for this function to work right a port must use the + DEPRECATED_PC_IN_CALL_DUMMY because figuring out the saved SP would + take too much time, at least using frame_register() on the 68k. + This means that for this function to work right a port must use the bp_call_dummy breakpoint. */ int -frame_in_dummy (struct frame_info *frame) +deprecated_frame_in_dummy (struct frame_info *frame) { struct breakpoint *b; - if (!CALL_DUMMY_P) - return 0; - - if (USE_GENERIC_DUMMY_FRAMES) - return generic_pc_in_call_dummy (frame->pc, frame->frame, frame->frame); + /* This function is used by two files: get_frame_type(), after first + checking that !DEPRECATED_USE_GENERIC_DUMMY_FRAMES; and + sparc-tdep.c, which doesn't yet use generic dummy frames anyway. */ + gdb_assert (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES); ALL_BREAKPOINTS (b) { if (b->type == bp_call_dummy - && b->frame == frame->frame + && frame_id_eq (b->frame_id, get_frame_id (frame)) /* We need to check the PC as well as the frame on the sparc, for signals.exp in the testsuite. */ - && (frame->pc + && (get_frame_pc (frame) >= (b->address - - SIZEOF_CALL_DUMMY_WORDS / sizeof (LONGEST) * REGISTER_SIZE)) - && frame->pc <= b->address) + - SIZEOF_CALL_DUMMY_WORDS / sizeof (LONGEST) * REGISTER_SIZE)) + && get_frame_pc (frame) <= b->address) return 1; } return 0; @@ -1718,6 +1785,7 @@ bpstat_clear (bpstat *bsp) q = p->next; if (p->old_val != NULL) value_free (p->old_val); + free_command_lines (&p->commands); xfree (p); p = q; } @@ -1741,6 +1809,11 @@ bpstat_copy (bpstat bs) { 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 (p == NULL) /* This is the first thing in the chain. */ retval = tmp; @@ -1830,7 +1903,7 @@ bpstat_clear_actions (bpstat bs) { for (; bs != NULL; bs = bs->next) { - bs->commands = NULL; + free_command_lines (&bs->commands); if (bs->old_val != NULL) { value_free (bs->old_val); @@ -1842,7 +1915,7 @@ bpstat_clear_actions (bpstat bs) /* Stub for cleaning up our state if we error-out of a breakpoint command */ /* ARGSUSED */ static void -cleanup_executing_breakpoints (PTR ignore) +cleanup_executing_breakpoints (void *ignore) { executing_breakpoint_commands = 0; } @@ -1899,11 +1972,9 @@ top: to look at, so start over. */ goto top; else - bs->commands = NULL; + free_command_lines (&bs->commands); } - - executing_breakpoint_commands = 0; - discard_cleanups (old_chain); + do_cleanups (old_chain); } /* This is the normal print function for a bpstat. In the future, @@ -1930,7 +2001,7 @@ top: static enum print_stop_action print_it_typical (bpstat bs) { - struct cleanup *old_chain; + 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); @@ -2091,14 +2162,14 @@ print_it_typical (bpstat bs) if (ui_out_is_mi_like_p (uiout)) ui_out_field_string (uiout, "reason", "watchpoint-trigger"); mention (bs->breakpoint_at); - ui_out_tuple_begin (uiout, "value"); + ui_out_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); - ui_out_tuple_end (uiout); + do_cleanups (ui_out_chain); ui_out_text (uiout, "\n"); value_free (bs->old_val); bs->old_val = NULL; @@ -2111,11 +2182,11 @@ print_it_typical (bpstat bs) if (ui_out_is_mi_like_p (uiout)) ui_out_field_string (uiout, "reason", "read-watchpoint-trigger"); mention (bs->breakpoint_at); - ui_out_tuple_begin (uiout, "value"); + ui_out_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); - ui_out_tuple_end (uiout); + do_cleanups (ui_out_chain); ui_out_text (uiout, "\n"); return PRINT_UNKNOWN; break; @@ -2127,7 +2198,7 @@ print_it_typical (bpstat bs) if (ui_out_is_mi_like_p (uiout)) ui_out_field_string (uiout, "reason", "access-watchpoint-trigger"); mention (bs->breakpoint_at); - ui_out_tuple_begin (uiout, "value"); + ui_out_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); @@ -2140,12 +2211,12 @@ print_it_typical (bpstat bs) mention (bs->breakpoint_at); if (ui_out_is_mi_like_p (uiout)) ui_out_field_string (uiout, "reason", "access-watchpoint-trigger"); - ui_out_tuple_begin (uiout, "value"); + ui_out_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); - ui_out_tuple_end (uiout); + do_cleanups (ui_out_chain); ui_out_text (uiout, "\n"); return PRINT_UNKNOWN; break; @@ -2259,7 +2330,7 @@ bpstat_print (bpstat bs) make it pass through catch_errors. */ static int -breakpoint_cond_eval (PTR exp) +breakpoint_cond_eval (void *exp) { struct value *mark = value_mark (); int i = !value_true (evaluate_expression ((struct expression *) exp)); @@ -2299,7 +2370,7 @@ bpstat_alloc (struct breakpoint *b, bpstat cbs /* Current "bs" value */ ) /* Check watchpoint condition. */ static int -watchpoint_check (PTR p) +watchpoint_check (void *p) { bpstat bs = (bpstat) p; struct breakpoint *b; @@ -2429,8 +2500,7 @@ bpstat_stop_status (CORE_ADDR *pc, int not_a_sw_breakpoint) trace/singlestep trap event, we would not want to subtract DECR_PC_AFTER_BREAK from the PC. */ - bp_addr = *pc - (not_a_sw_breakpoint && !SOFTWARE_SINGLE_STEP_P () ? - 0 : DECR_PC_AFTER_BREAK); + bp_addr = *pc - (not_a_sw_breakpoint ? 0 : DECR_PC_AFTER_BREAK); ALL_BREAKPOINTS_SAFE (b, temp) { @@ -2496,17 +2566,17 @@ bpstat_stop_status (CORE_ADDR *pc, int not_a_sw_breakpoint) continue; if ((b->type == bp_catch_fork) - && !target_has_forked (PIDGET (inferior_ptid), - &b->forked_inferior_pid)) + && !inferior_has_forked (PIDGET (inferior_ptid), + &b->forked_inferior_pid)) continue; if ((b->type == bp_catch_vfork) - && !target_has_vforked (PIDGET (inferior_ptid), - &b->forked_inferior_pid)) + && !inferior_has_vforked (PIDGET (inferior_ptid), + &b->forked_inferior_pid)) continue; if ((b->type == bp_catch_exec) - && !target_has_execd (PIDGET (inferior_ptid), &b->exec_pathname)) + && !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname)) continue; if (ep_is_exception_catchpoint (b) && @@ -2650,8 +2720,8 @@ bpstat_stop_status (CORE_ADDR *pc, int not_a_sw_breakpoint) real_breakpoint = 1; } - if (b->frame && - b->frame != (get_current_frame ())->frame) + if (frame_id_p (b->frame_id) + && !frame_id_eq (b->frame_id, get_frame_id (get_current_frame ()))) bs->stop = 0; else { @@ -2686,9 +2756,9 @@ bpstat_stop_status (CORE_ADDR *pc, int not_a_sw_breakpoint) /* We will stop here */ if (b->disposition == disp_disable) b->enable_state = bp_disabled; - bs->commands = b->commands; if (b->silent) bs->print = 0; + bs->commands = b->commands; if (bs->commands && (STREQ ("silent", bs->commands->line) || (xdb_commands && STREQ ("Q", bs->commands->line)))) @@ -2696,6 +2766,7 @@ bpstat_stop_status (CORE_ADDR *pc, int not_a_sw_breakpoint) bs->commands = bs->commands->next; bs->print = 0; } + bs->commands = copy_command_lines (bs->commands); } } /* Print nothing for this entry if we dont stop or if we dont print. */ @@ -3158,9 +3229,10 @@ print_one_breakpoint (struct breakpoint *b, 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 (); - ui_out_tuple_begin (uiout, "bkpt"); + bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "bkpt"); /* 1 */ annotate_field (0); @@ -3314,7 +3386,7 @@ print_one_breakpoint (struct breakpoint *b, { ui_out_text (uiout, "in "); ui_out_field_string (uiout, "func", - SYMBOL_SOURCE_NAME (sym)); + SYMBOL_PRINT_NAME (sym)); ui_out_wrap_hint (uiout, wrap_indent); ui_out_text (uiout, " at "); } @@ -3340,11 +3412,13 @@ print_one_breakpoint (struct breakpoint *b, ui_out_text (uiout, "\n"); - if (b->frame) + 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); + /* FIXME: cagney/2002-12-01: Shouldn't be poeking around inside + the frame ID. */ + ui_out_field_core_addr (uiout, "frame", b->frame_id.base); ui_out_text (uiout, "\n"); } @@ -3396,12 +3470,14 @@ print_one_breakpoint (struct breakpoint *b, if ((l = b->commands)) { + struct cleanup *script_chain; + annotate_field (9); - ui_out_tuple_begin (uiout, "script"); + script_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "script"); print_command_lines (uiout, l, 4); - ui_out_tuple_end (uiout); + do_cleanups (script_chain); } - ui_out_tuple_end (uiout); + do_cleanups (bkpt_chain); do_cleanups (old_chain); } @@ -3469,6 +3545,7 @@ breakpoint_1 (int bnum, int allflag) register struct breakpoint *b; CORE_ADDR last_addr = (CORE_ADDR) -1; int nr_printable_breakpoints; + struct cleanup *bkpttbl_chain; /* Compute the number of rows in the table. */ nr_printable_breakpoints = 0; @@ -3481,9 +3558,13 @@ breakpoint_1 (int bnum, int allflag) } if (addressprint) - ui_out_table_begin (uiout, 6, nr_printable_breakpoints, "BreakpointTable"); + bkpttbl_chain + = make_cleanup_ui_out_table_begin_end (uiout, 6, nr_printable_breakpoints, + "BreakpointTable"); else - ui_out_table_begin (uiout, 5, nr_printable_breakpoints, "BreakpointTable"); + bkpttbl_chain + = make_cleanup_ui_out_table_begin_end (uiout, 5, nr_printable_breakpoints, + "BreakpointTable"); if (nr_printable_breakpoints > 0) annotate_breakpoints_headers (); @@ -3525,7 +3606,7 @@ breakpoint_1 (int bnum, int allflag) print_one_breakpoint (b, &last_addr); } - ui_out_table_end (uiout); + do_cleanups (bkpttbl_chain); if (nr_printable_breakpoints == 0) { @@ -3765,7 +3846,7 @@ set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype) b->silent = 0; b->ignore_count = 0; b->commands = NULL; - b->frame = 0; + b->frame_id = null_frame_id; b->dll_pathname = NULL; b->triggered_dll_pathname = NULL; b->forked_inferior_pid = 0; @@ -3810,7 +3891,7 @@ create_internal_breakpoint (CORE_ADDR address, enum bptype type) struct symtab_and_line sal; struct breakpoint *b; - INIT_SAL (&sal); /* initialize to zeroes */ + init_sal (&sal); /* initialize to zeroes */ sal.pc = address; sal.section = find_pc_overlay (sal.pc); @@ -3933,14 +4014,12 @@ struct breakpoint * create_thread_event_breakpoint (CORE_ADDR address) { struct breakpoint *b; - char addr_string[80]; /* Surely an addr can't be longer than that. */ b = create_internal_breakpoint (address, bp_thread_event); b->enable_state = bp_enabled; /* addr_string has to be used or breakpoint_re_set will delete me. */ - sprintf (addr_string, "*0x%s", paddr (b->address)); - b->addr_string = xstrdup (addr_string); + xasprintf (&b->addr_string, "*0x%s", paddr (b->address)); return b; } @@ -4130,7 +4209,7 @@ create_fork_vfork_event_catchpoint (int tempflag, char *cond_string, struct breakpoint *b; int thread = -1; /* All threads. */ - INIT_SAL (&sal); + init_sal (&sal); sal.pc = 0; sal.symtab = NULL; sal.line = 0; @@ -4169,7 +4248,7 @@ create_exec_event_catchpoint (int tempflag, char *cond_string) struct breakpoint *b; int thread = -1; /* All threads. */ - INIT_SAL (&sal); + init_sal (&sal); sal.pc = 0; sal.symtab = NULL; sal.line = 0; @@ -4233,7 +4312,7 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used) that gets deleted automatically... */ void -set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_info *frame) +set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_id frame_id) { register struct breakpoint *b; @@ -4242,10 +4321,7 @@ set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_info *frame) { b->address = pc; b->enable_state = bp_enabled; - if (frame != NULL) - b->frame = frame->frame; - else - b->frame = 0; + b->frame_id = frame_id; check_duplicates (b); return; } @@ -4297,14 +4373,14 @@ enable_watchpoints_after_interactive_call_stop (void) Restrict it to frame FRAME if FRAME is nonzero. */ struct breakpoint * -set_momentary_breakpoint (struct symtab_and_line sal, struct frame_info *frame, +set_momentary_breakpoint (struct symtab_and_line sal, struct frame_id frame_id, enum bptype type) { register struct breakpoint *b; b = set_raw_breakpoint (sal, type); b->enable_state = bp_enabled; b->disposition = disp_donttouch; - b->frame = (frame ? frame->frame : 0); + b->frame_id = frame_id; /* If we're debugging a multi-threaded program, then we want momentary breakpoints to be active in only a @@ -4322,7 +4398,7 @@ static void mention (struct breakpoint *b) { int say_where = 0; - struct cleanup *old_chain; + struct cleanup *old_chain, *ui_out_chain; struct ui_stream *stb; stb = ui_out_stream_new (uiout); @@ -4344,39 +4420,39 @@ mention (struct breakpoint *b) break; case bp_watchpoint: ui_out_text (uiout, "Watchpoint "); - ui_out_tuple_begin (uiout, "wpt"); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); ui_out_field_int (uiout, "number", b->number); ui_out_text (uiout, ": "); print_expression (b->exp, stb->stream); ui_out_field_stream (uiout, "exp", stb); - ui_out_tuple_end (uiout); + do_cleanups (ui_out_chain); break; case bp_hardware_watchpoint: ui_out_text (uiout, "Hardware watchpoint "); - ui_out_tuple_begin (uiout, "wpt"); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); ui_out_field_int (uiout, "number", b->number); ui_out_text (uiout, ": "); print_expression (b->exp, stb->stream); ui_out_field_stream (uiout, "exp", stb); - ui_out_tuple_end (uiout); + do_cleanups (ui_out_chain); break; case bp_read_watchpoint: ui_out_text (uiout, "Hardware read watchpoint "); - ui_out_tuple_begin (uiout, "hw-rwpt"); + 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, ": "); print_expression (b->exp, stb->stream); ui_out_field_stream (uiout, "exp", stb); - ui_out_tuple_end (uiout); + do_cleanups (ui_out_chain); break; case bp_access_watchpoint: ui_out_text (uiout, "Hardware access (read/write) watchpoint "); - ui_out_tuple_begin (uiout, "hw-awpt"); + 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, ": "); print_expression (b->exp, stb->stream); ui_out_field_stream (uiout, "exp", stb); - ui_out_tuple_end (uiout); + do_cleanups (ui_out_chain); break; case bp_breakpoint: if (ui_out_is_mi_like_p (uiout)) @@ -4496,7 +4572,12 @@ create_breakpoints (struct symtabs_and_lines sals, char **addr_string, b->number = breakpoint_count; b->cond = cond[i]; b->thread = thread; - b->addr_string = addr_string[i]; + if (addr_string[i]) + b->addr_string = addr_string[i]; + else + /* addr_string has to be used or breakpoint_re_set will delete + me. */ + xasprintf (&b->addr_string, "*0x%s", paddr (b->address)); b->cond_string = cond_string[i]; b->ignore_count = ignore_count; b->enable_state = bp_enabled; @@ -4526,7 +4607,7 @@ parse_breakpoint_sals (char **address, if (default_breakpoint_valid) { struct symtab_and_line sal; - INIT_SAL (&sal); /* initialize to zeroes */ + init_sal (&sal); /* initialize to zeroes */ sals->sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line)); sal.pc = default_breakpoint_address; @@ -4544,10 +4625,16 @@ parse_breakpoint_sals (char **address, /* Force almost all breakpoints to be in terms of the current_source_symtab (which is decode_line_1's default). This should produce the results we want almost all of the time while - leaving default_breakpoint_* alone. */ + leaving default_breakpoint_* alone. + ObjC: However, don't match an Objective-C method name which + may have a '+' or '-' succeeded by a '[' */ + + struct symtab_and_line cursal = get_current_source_symtab_and_line (); + if (default_breakpoint_valid - && (!current_source_symtab - || (strchr ("+-", (*address)[0]) != NULL))) + && (!cursal.symtab + || ((strchr ("+-", (*address)[0]) != NULL) + && ((*address)[1] != '[')))) *sals = decode_line_1 (address, 1, default_breakpoint_symtab, default_breakpoint_line, addr_string); else @@ -4880,9 +4967,9 @@ break_at_finish_at_depth_command_1 (char *arg, int flag, int from_tty) if (default_breakpoint_valid) { - if (selected_frame) + if (deprecated_selected_frame) { - selected_pc = selected_frame->pc; + selected_pc = get_frame_pc (deprecated_selected_frame); if (arg) if_arg = 1; } @@ -4911,7 +4998,7 @@ break_at_finish_at_depth_command_1 (char *arg, int flag, int from_tty) frame = parse_frame_specification (level_arg); if (frame) - selected_pc = frame->pc; + selected_pc = get_frame_pc (frame); else selected_pc = 0; } @@ -4958,10 +5045,11 @@ break_at_finish_command_1 (char *arg, int flag, int from_tty) { if (default_breakpoint_valid) { - if (selected_frame) + if (deprecated_selected_frame) { addr_string = (char *) xmalloc (15); - sprintf (addr_string, "*0x%s", paddr_nz (selected_frame->pc)); + sprintf (addr_string, "*0x%s", + paddr_nz (get_frame_pc (deprecated_selected_frame))); if (arg) if_arg = 1; } @@ -5216,7 +5304,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty) enum bptype bp_type; int mem_cnt = 0; - INIT_SAL (&sal); /* initialize to zeroes */ + init_sal (&sal); /* initialize to zeroes */ /* Parse arguments. */ innermost_block = NULL; @@ -5317,7 +5405,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty) if (frame) { prev_frame = get_prev_frame (frame); - get_frame_id (frame, &b->watchpoint_frame); + b->watchpoint_frame = get_frame_id (frame); } else { @@ -5332,16 +5420,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty) if (prev_frame) { struct breakpoint *scope_breakpoint; - struct symtab_and_line scope_sal; - - INIT_SAL (&scope_sal); /* initialize to zeroes */ - scope_sal.pc = get_frame_pc (prev_frame); - scope_sal.section = find_pc_overlay (scope_sal.pc); - - scope_breakpoint = set_raw_breakpoint (scope_sal, - bp_watchpoint_scope); - set_breakpoint_count (breakpoint_count + 1); - scope_breakpoint->number = breakpoint_count; + scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame), + bp_watchpoint_scope); scope_breakpoint->enable_state = bp_enabled; @@ -5349,7 +5429,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty) scope_breakpoint->disposition = disp_del; /* Only break in the proper frame (help with recursion). */ - scope_breakpoint->frame = prev_frame->frame; + scope_breakpoint->frame_id = get_frame_id (prev_frame); /* Set the address at which we will stop. */ scope_breakpoint->address = get_frame_pc (prev_frame); @@ -5504,11 +5584,11 @@ until_break_command_continuation (struct continuation_arg *arg) /* ARGSUSED */ void -until_break_command (char *arg, int from_tty) +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 (selected_frame); + struct frame_info *prev_frame = get_prev_frame (deprecated_selected_frame); struct breakpoint *breakpoint; struct cleanup *old_chain; struct continuation_arg *arg1; @@ -5537,7 +5617,16 @@ until_break_command (char *arg, int from_tty) resolve_sal_pc (&sal); - breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until); + if (anywhere) + /* If the user told us to continue until a specified location, + we don't specify a frame at which we need to stop. */ + breakpoint = set_momentary_breakpoint (sal, null_frame_id, bp_until); + else + /* Otherwise, specify the current frame, because we want to stop only + at the very same frame. */ + breakpoint = set_momentary_breakpoint (sal, + get_frame_id (deprecated_selected_frame), + bp_until); if (!event_loop_p || !target_can_async_p ()) old_chain = make_cleanup_delete_breakpoint (breakpoint); @@ -5565,13 +5654,14 @@ until_break_command (char *arg, int from_tty) add_continuation (until_break_command_continuation, arg1); } - /* Keep within the current frame */ - + /* Keep within the current frame, or in frames called by the current + one. */ if (prev_frame) { - sal = find_pc_line (prev_frame->pc, 0); - sal.pc = prev_frame->pc; - breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until); + 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 (!event_loop_p || !target_can_async_p ()) make_cleanup_delete_breakpoint (breakpoint); else @@ -5584,7 +5674,7 @@ until_break_command (char *arg, int from_tty) if (!event_loop_p || !target_can_async_p ()) do_cleanups (old_chain); } - + #if 0 /* These aren't used; I don't konw what they were for. */ /* Set a breakpoint at the catch clause for NAME. */ @@ -5609,187 +5699,6 @@ enable_catch_breakpoint (void) } #endif /* 0 */ -struct sal_chain -{ - struct sal_chain *next; - struct symtab_and_line sal; -}; - -#if 0 -/* Not really used -- invocation in handle_gnu_4_16_catch_command - had been commented out in the v.4.16 sources, and stays - disabled there now because "catch NAME" syntax isn't allowed. - pai/1997-07-11 */ -/* This isn't used; I don't know what it was for. */ -/* For each catch clause identified in ARGS, run FUNCTION - with that clause as an argument. */ -static struct symtabs_and_lines -map_catch_names (char *args, int (*function) ()) -{ - register char *p = args; - register char *p1; - struct symtabs_and_lines sals; -#if 0 - struct sal_chain *sal_chain = 0; -#endif - - if (p == 0) - error_no_arg ("one or more catch names"); - - sals.nelts = 0; - sals.sals = NULL; - - while (*p) - { - p1 = p; - /* Don't swallow conditional part. */ - if (p1[0] == 'i' && p1[1] == 'f' - && (p1[2] == ' ' || p1[2] == '\t')) - break; - - if (isalpha (*p1)) - { - p1++; - while (isalnum (*p1) || *p1 == '_' || *p1 == '$') - p1++; - } - - if (*p1 && *p1 != ' ' && *p1 != '\t') - error ("Arguments must be catch names."); - - *p1 = 0; -#if 0 - if (function (p)) - { - struct sal_chain *next = (struct sal_chain *) - alloca (sizeof (struct sal_chain)); - next->next = sal_chain; - next->sal = get_catch_sal (p); - sal_chain = next; - goto win; - } -#endif - printf_unfiltered ("No catch clause for exception %s.\n", p); -#if 0 - win: -#endif - p = p1; - while (*p == ' ' || *p == '\t') - p++; - } -} -#endif - -/* This shares a lot of code with `print_frame_label_vars' from stack.c. */ - -static struct symtabs_and_lines -get_catch_sals (int this_level_only) -{ - register struct blockvector *bl; - register struct block *block; - int index, have_default = 0; - CORE_ADDR pc; - struct symtabs_and_lines sals; - struct sal_chain *sal_chain = 0; - char *blocks_searched; - - /* Not sure whether an error message is always the correct response, - but it's better than a core dump. */ - if (selected_frame == NULL) - error ("No selected frame."); - block = get_frame_block (selected_frame, 0); - pc = selected_frame->pc; - - sals.nelts = 0; - sals.sals = NULL; - - if (block == 0) - error ("No symbol table info available.\n"); - - bl = blockvector_for_pc (BLOCK_END (block) - 4, &index); - blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); - memset (blocks_searched, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); - - while (block != 0) - { - CORE_ADDR end = BLOCK_END (block) - 4; - int last_index; - - if (bl != blockvector_for_pc (end, &index)) - error ("blockvector blotch"); - if (BLOCKVECTOR_BLOCK (bl, index) != block) - error ("blockvector botch"); - last_index = BLOCKVECTOR_NBLOCKS (bl); - index += 1; - - /* Don't print out blocks that have gone by. */ - while (index < last_index - && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc) - index++; - - while (index < last_index - && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end) - { - if (blocks_searched[index] == 0) - { - struct block *b = BLOCKVECTOR_BLOCK (bl, index); - register int i; - register struct symbol *sym; - - ALL_BLOCK_SYMBOLS (b, i, sym) - { - if (STREQ (SYMBOL_NAME (sym), "default")) - { - if (have_default) - continue; - have_default = 1; - } - if (SYMBOL_CLASS (sym) == LOC_LABEL) - { - struct sal_chain *next = (struct sal_chain *) - alloca (sizeof (struct sal_chain)); - next->next = sal_chain; - next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), - 0); - sal_chain = next; - } - } - blocks_searched[index] = 1; - } - index++; - } - if (have_default) - break; - if (sal_chain && this_level_only) - break; - - /* After handling the function's top-level block, stop. - Don't continue to its superblock, the block of - per-file symbols. */ - if (BLOCK_FUNCTION (block)) - break; - block = BLOCK_SUPERBLOCK (block); - } - - if (sal_chain) - { - struct sal_chain *tmp_chain; - - /* Count the number of entries. */ - for (index = 0, tmp_chain = sal_chain; tmp_chain; - tmp_chain = tmp_chain->next) - index++; - - sals.nelts = index; - sals.sals = (struct symtab_and_line *) - xmalloc (index * sizeof (struct symtab_and_line)); - for (index = 0; sal_chain; sal_chain = sal_chain->next, index++) - sals.sals[index] = sal_chain->sal; - } - - return sals; -} - static void ep_skip_leading_whitespace (char **s) { @@ -6127,30 +6036,15 @@ catch_exception_command_1 (enum exception_event_kind ex_event, char *arg, else return; /* something went wrong with setting up callbacks */ } - else - { - /* No callbacks from runtime system for exceptions. - Try GNU C++ exception breakpoints using labels in debug info. */ - if (ex_event == EX_EVENT_CATCH) - { - handle_gnu_4_16_catch_command (arg, tempflag, from_tty); - } - else if (ex_event == EX_EVENT_THROW) - { - /* Set a breakpoint on __raise_exception () */ - warning ("Unsupported with this platform/compiler combination."); - warning ("Perhaps you can achieve the effect you want by setting"); - warning ("a breakpoint on __raise_exception()."); - } - } + warning ("Unsupported with this platform/compiler combination."); } /* Cover routine to allow wrapping target_enable_exception_catchpoints inside a catch_errors */ static int -cover_target_enable_exception_callback (PTR arg) +cover_target_enable_exception_callback (void *arg) { args_for_catchpoint_enable *args = arg; struct symtab_and_line *sal; @@ -6163,111 +6057,6 @@ cover_target_enable_exception_callback (PTR arg) return 1; /*is valid */ } - - -/* This is the original v.4.16 and earlier version of the - catch_command_1() function. Now that other flavours of "catch" - have been introduced, and since exception handling can be handled - in other ways (through target ops) also, this is used only for the - GNU C++ exception handling system. - Note: Only the "catch" flavour of GDB 4.16 is handled here. The - "catch NAME" is now no longer allowed in catch_command_1(). Also, - there was no code in GDB 4.16 for "catch throw". - - Called from catch_exception_command_1 () */ - - -static void -handle_gnu_4_16_catch_command (char *arg, int tempflag, int from_tty) -{ - /* First, translate ARG into something we can deal with in terms - of breakpoints. */ - - struct symtabs_and_lines sals; - struct symtab_and_line sal; - register struct expression *cond = 0; - register struct breakpoint *b; - char *save_arg; - int i; - - INIT_SAL (&sal); /* initialize to zeroes */ - - /* If no arg given, or if first arg is 'if ', all active catch clauses - are breakpointed. */ - - if (!arg || (arg[0] == 'i' && arg[1] == 'f' - && (arg[2] == ' ' || arg[2] == '\t'))) - { - /* Grab all active catch clauses. */ - sals = get_catch_sals (0); - } - else - { - /* Grab selected catch clauses. */ - error ("catch NAME not implemented"); - -#if 0 - /* Not sure why this code has been disabled. I'm leaving - it disabled. We can never come here now anyway - since we don't allow the "catch NAME" syntax. - pai/1997-07-11 */ - - /* This isn't used; I don't know what it was for. */ - sals = map_catch_names (arg, catch_breakpoint); -#endif - } - - if (!sals.nelts) - return; - - save_arg = arg; - for (i = 0; i < sals.nelts; i++) - { - resolve_sal_pc (&sals.sals[i]); - - while (arg && *arg) - { - if (arg[0] == 'i' && arg[1] == 'f' - && (arg[2] == ' ' || arg[2] == '\t')) - cond = parse_exp_1 ((arg += 2, &arg), - block_for_pc (sals.sals[i].pc), 0); - else - error ("Junk at end of arguments."); - } - arg = save_arg; - } - - for (i = 0; i < sals.nelts; i++) - { - sal = sals.sals[i]; - - if (from_tty) - describe_other_breakpoints (sal.pc, sal.section); - - /* Important -- this is an ordinary breakpoint. For platforms - with callback support for exceptions, - create_exception_catchpoint() will create special bp types - (bp_catch_catch and bp_catch_throw), and there is code in - insert_breakpoints() and elsewhere that depends on that. */ - b = set_raw_breakpoint (sal, bp_breakpoint); - set_breakpoint_count (breakpoint_count + 1); - b->number = breakpoint_count; - - b->cond = cond; - b->enable_state = bp_enabled; - b->disposition = tempflag ? disp_del : disp_donttouch; - - mention (b); - } - - if (sals.nelts > 1) - { - warning ("Multiple breakpoints were set."); - warning ("Use the \"delete\" command to delete unwanted breakpoints."); - } - xfree (sals.sals); -} - static void catch_command_1 (char *arg, int tempflag, int from_tty) { @@ -6461,7 +6250,7 @@ clear_command (char *arg, int from_tty) sals.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line)); make_cleanup (xfree, sals.sals); - INIT_SAL (&sal); /* initialize to zeroes */ + init_sal (&sal); /* initialize to zeroes */ sal.line = default_breakpoint_line; sal.symtab = default_breakpoint_symtab; sal.pc = default_breakpoint_address; @@ -6690,11 +6479,32 @@ delete_breakpoint (struct breakpoint *bpt) else val = target_insert_breakpoint (b->address, b->shadow_contents); + /* If there was an error in the insert, print a message, then stop execution. */ 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 "); + print_address_numeric (b->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 (); - warning ("Cannot insert breakpoint %d:", b->number); - memory_error (val, b->address); /* which bombs us out */ + error_stream(tmp_error_stream); } else b->inserted = 1; @@ -6730,14 +6540,8 @@ delete_breakpoint (struct breakpoint *bpt) if (bs->breakpoint_at == bpt) { bs->breakpoint_at = NULL; - - /* we'd call bpstat_clear_actions, but that free's stuff and due - to the multiple pointers pointing to one item with no - reference counts found anywhere through out the bpstat's (how - do you spell fragile?), we don't want to free things twice -- - better a memory leak than a corrupt malloc pool! */ - bs->commands = NULL; bs->old_val = NULL; + /* bs->commands will be freed later. */ } /* On the chance that someone will soon try again to delete this same bp, we mark it as deleted before freeing its storage. */ @@ -6812,7 +6616,7 @@ delete_command (char *arg, int from_tty) Unused in this case. */ static int -breakpoint_re_set_one (PTR bint) +breakpoint_re_set_one (void *bint) { /* get past catch_errs */ struct breakpoint *b = (struct breakpoint *) bint; @@ -6953,7 +6757,7 @@ breakpoint_re_set_one (PTR bint) value_free (b->val); b->val = evaluate_expression (b->exp); release_value (b->val); - if (VALUE_LAZY (b->val)) + if (VALUE_LAZY (b->val) && b->enable_state == bp_enabled) value_fetch_lazy (b->val); if (b->cond_string != NULL) @@ -7278,8 +7082,8 @@ is valid is not currently in scope.\n", bpt->number); return; } - save_selected_frame = selected_frame; - save_selected_frame_level = frame_relative_level (selected_frame); + save_selected_frame = deprecated_selected_frame; + save_selected_frame_level = frame_relative_level (deprecated_selected_frame); select_frame (fr); }