From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9687 invoked by alias); 3 May 2010 20:02:40 -0000 Received: (qmail 9659 invoked by uid 22791); 3 May 2010 20:02:34 -0000 X-SWARE-Spam-Status: No, hits=-5.5 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_GJ,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 03 May 2010 20:02:22 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o43K2KQU014353 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 3 May 2010 16:02:20 -0400 Received: from host0.dyn.jankratochvil.net (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o43K2HRm029842 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 3 May 2010 16:02:19 -0400 Received: from host0.dyn.jankratochvil.net (localhost [127.0.0.1]) by host0.dyn.jankratochvil.net (8.14.4/8.14.4) with ESMTP id o43K2HJ1001314 for ; Mon, 3 May 2010 22:02:17 +0200 Received: (from jkratoch@localhost) by host0.dyn.jankratochvil.net (8.14.4/8.14.4/Submit) id o43K2H4r001313 for gdb-patches@sourceware.org; Mon, 3 May 2010 22:02:17 +0200 Date: Mon, 03 May 2010 20:02:00 -0000 From: Jan Kratochvil To: gdb-patches@sourceware.org Subject: [patch 3/3] bpstat_what removal Message-ID: <20100503200217.GD30386@host0.dyn.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-08-17) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-05/txt/msg00050.txt.bz2 Hi, the simple idea is to inline bpstat_what into handle_inferior_event. This removes enum bpstat_what_main_action and struct bpstat_what currently acting just as an interface between these two functions. solib_add() needs to stay delayed as it has too disturbing effect on the content of stop_bpstat. breakpoint_type_name is there just for DEBUG_INFRUN. Thanks, Jan gdb/ 2010-05-03 Jan Kratochvil * breakpoint.c (bpstat_what): Remove. (breakpoint_type_name): New. * breakpoint.h (enum bpstat_what_main_action, struct bpstat_what) (bpstat_what): Remove. (breakpoint_type_name): New prototype. * infrun.c (handle_inferior_event): Clear frame and gdbarch before deciding what action to take. New variables bs, print_frame_max, stop_step_max, perform_max and perform_shlib. Replace the bpstat_what call by new inlined deciding code. Reinitialize even gdbarch when frame gets reinitialized. gdb/testsuite/ 2010-05-03 Jan Kratochvil * break-solib-event.exp: New. --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -4161,250 +4161,6 @@ bpstat_stop_status (struct address_space *aspace, return root_bs->next; } -/* Tell what to do about this bpstat. */ -struct bpstat_what -bpstat_what (bpstat bs) -{ - /* Classify each bpstat as one of the following. */ - enum class - { - /* This bpstat element has no effect on the main_action. */ - no_effect = 0, - - /* There was a watchpoint, stop but don't print. */ - wp_silent, - - /* There was a watchpoint, stop and print. */ - wp_noisy, - - /* There was a breakpoint but we're not stopping. */ - bp_nostop, - - /* There was a breakpoint, stop but don't print. */ - bp_silent, - - /* There was a breakpoint, stop and print. */ - bp_noisy, - - /* We hit the longjmp breakpoint. */ - long_jump, - - /* We hit the longjmp_resume breakpoint. */ - long_resume, - - /* We hit the step_resume breakpoint. */ - step_resume, - - /* We hit the shared library event breakpoint. */ - shlib_event, - - /* We hit the jit event breakpoint. */ - jit_event, - - /* This is just used to count how many enums there are. */ - class_last - }; - - /* Here is the table which drives this routine. So that we can - format it pretty, we define some abbreviations for the - enum bpstat_what codes. */ -#define kc BPSTAT_WHAT_KEEP_CHECKING -#define ss BPSTAT_WHAT_STOP_SILENT -#define sn BPSTAT_WHAT_STOP_NOISY -#define sgl BPSTAT_WHAT_SINGLE -#define slr BPSTAT_WHAT_SET_LONGJMP_RESUME -#define clr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME -#define sr BPSTAT_WHAT_STEP_RESUME -#define shl BPSTAT_WHAT_CHECK_SHLIBS -#define jit BPSTAT_WHAT_CHECK_JIT - -/* "Can't happen." Might want to print an error message. - abort() is not out of the question, but chances are GDB is just - a bit confused, not unusable. */ -#define err BPSTAT_WHAT_STOP_NOISY - - /* Given an old action and a class, come up with a new action. */ - /* One interesting property of this table is that wp_silent is the same - as bp_silent and wp_noisy is the same as bp_noisy. That is because - after stopping, the check for whether to step over a breakpoint - (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without - reference to how we stopped. We retain separate wp_silent and - bp_silent codes in case we want to change that someday. - - Another possibly interesting property of this table is that - there's a partial ordering, priority-like, of the actions. Once - you've decided that some action is appropriate, you'll never go - back and decide something of a lower priority is better. The - ordering is: - - kc < jit clr sgl shl slr sn sr ss - sgl < jit shl slr sn sr ss - slr < jit err shl sn sr ss - clr < jit err shl sn sr ss - ss < jit shl sn sr - sn < jit shl sr - jit < shl sr - shl < sr - sr < - - What I think this means is that we don't need a damned table - here. If you just put the rows and columns in the right order, - it'd look awfully regular. We could simply walk the bpstat list - and choose the highest priority action we find, with a little - logic to handle the 'err' cases. */ - - /* step_resume entries: a step resume breakpoint overrides another - breakpoint of signal handling (see comment in wait_for_inferior - at where we set the step_resume breakpoint). */ - - static const enum bpstat_what_main_action - table[(int) class_last][(int) BPSTAT_WHAT_LAST] = - { - /* old action */ - /* kc ss sn sgl slr clr sr shl jit */ -/* no_effect */ {kc, ss, sn, sgl, slr, clr, sr, shl, jit}, -/* wp_silent */ {ss, ss, sn, ss, ss, ss, sr, shl, jit}, -/* wp_noisy */ {sn, sn, sn, sn, sn, sn, sr, shl, jit}, -/* bp_nostop */ {sgl, ss, sn, sgl, slr, slr, sr, shl, jit}, -/* bp_silent */ {ss, ss, sn, ss, ss, ss, sr, shl, jit}, -/* bp_noisy */ {sn, sn, sn, sn, sn, sn, sr, shl, jit}, -/* long_jump */ {slr, ss, sn, slr, slr, err, sr, shl, jit}, -/* long_resume */ {clr, ss, sn, err, err, err, sr, shl, jit}, -/* step_resume */ {sr, sr, sr, sr, sr, sr, sr, sr, sr }, -/* shlib */ {shl, shl, shl, shl, shl, shl, sr, shl, shl}, -/* jit_event */ {jit, jit, jit, jit, jit, jit, sr, jit, jit} - }; - -#undef kc -#undef ss -#undef sn -#undef sgl -#undef slr -#undef clr -#undef err -#undef sr -#undef ts -#undef shl -#undef jit - enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING; - struct bpstat_what retval; - - retval.call_dummy = STOP_NONE; - for (; bs != NULL; bs = bs->next) - { - enum class bs_class = no_effect; - if (bs->breakpoint_at == NULL) - /* I suspect this can happen if it was a momentary breakpoint - which has since been deleted. */ - continue; - if (bs->breakpoint_at->owner == NULL) - bs_class = bp_nostop; - else - switch (bs->breakpoint_at->owner->type) - { - case bp_none: - continue; - - case bp_breakpoint: - case bp_hardware_breakpoint: - case bp_until: - case bp_finish: - if (bs->stop) - { - if (bs->print) - bs_class = bp_noisy; - else - bs_class = bp_silent; - } - else - bs_class = bp_nostop; - break; - case bp_watchpoint: - case bp_hardware_watchpoint: - case bp_read_watchpoint: - case bp_access_watchpoint: - if (bs->stop) - { - if (bs->print) - bs_class = wp_noisy; - else - bs_class = wp_silent; - } - else - /* There was a watchpoint, but we're not stopping. - This requires no further action. */ - bs_class = no_effect; - break; - case bp_longjmp: - bs_class = long_jump; - break; - case bp_longjmp_resume: - bs_class = long_resume; - break; - case bp_step_resume: - if (bs->stop) - { - bs_class = step_resume; - } - else - /* It is for the wrong frame. */ - bs_class = bp_nostop; - break; - case bp_watchpoint_scope: - bs_class = bp_nostop; - break; - case bp_shlib_event: - bs_class = shlib_event; - break; - case bp_jit_event: - bs_class = jit_event; - break; - case bp_thread_event: - case bp_overlay_event: - case bp_longjmp_master: - case bp_std_terminate_master: - bs_class = bp_nostop; - break; - case bp_catchpoint: - if (bs->stop) - { - if (bs->print) - bs_class = bp_noisy; - else - bs_class = bp_silent; - } - else - /* There was a catchpoint, but we're not stopping. - This requires no further action. */ - bs_class = no_effect; - break; - case bp_call_dummy: - /* Make sure the action is stop (silent or noisy), - so infrun.c pops the dummy frame. */ - bs_class = bp_silent; - retval.call_dummy = STOP_STACK_DUMMY; - break; - case bp_std_terminate: - /* Make sure the action is stop (silent or noisy), - so infrun.c pops the dummy frame. */ - bs_class = bp_silent; - retval.call_dummy = STOP_STD_TERMINATE; - break; - case bp_tracepoint: - case bp_fast_tracepoint: - /* Tracepoint hits should not be reported back to GDB, and - if one got through somehow, it should have been filtered - out already. */ - internal_error (__FILE__, __LINE__, - _("bpstat_what: tracepoint encountered")); - break; - } - current_action = table[(int) bs_class][(int) current_action]; - } - retval.main_action = current_action; - return retval; -} - /* 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. */ @@ -10999,6 +10755,65 @@ save_command (char *arg, int from_tty) help_list (save_cmdlist, "save ", -1, gdb_stdout); } +const char * +breakpoint_type_name (enum bptype bptype) +{ + switch (bptype) + { + case bp_none: + return "bp_none"; + case bp_breakpoint: + return "bp_breakpoint"; + case bp_hardware_breakpoint: + return "bp_hardware_breakpoint"; + case bp_until: + return "bp_until"; + case bp_finish: + return "bp_finish"; + case bp_watchpoint: + return "bp_watchpoint"; + case bp_hardware_watchpoint: + return "bp_hardware_watchpoint"; + case bp_read_watchpoint: + return "bp_read_watchpoint"; + case bp_access_watchpoint: + return "bp_access_watchpoint"; + case bp_longjmp: + return "bp_longjmp"; + case bp_longjmp_resume: + return "bp_longjmp_resume"; + case bp_step_resume: + return "bp_step_resume"; + case bp_watchpoint_scope: + return "bp_watchpoint_scope"; + case bp_call_dummy: + return "bp_call_dummy"; + case bp_std_terminate: + return "bp_std_terminate"; + case bp_shlib_event: + return "bp_shlib_event"; + case bp_thread_event: + return "bp_thread_event"; + case bp_overlay_event: + return "bp_overlay_event"; + case bp_longjmp_master: + return "bp_longjmp_master"; + case bp_std_terminate_master: + return "bp_std_terminate_master"; + case bp_catchpoint: + return "bp_catchpoint"; + case bp_tracepoint: + return "bp_tracepoint"; + case bp_fast_tracepoint: + return "bp_fast_tracepoint"; + case bp_jit_event: + return "bp_jit_event"; + } + internal_error (__FILE__, __LINE__, _("Invalid breakpoint type %d"), + (int) bptype); + return NULL; +} + void _initialize_breakpoint (void) { --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -561,58 +561,6 @@ extern bpstat bpstat_copy (bpstat); extern bpstat bpstat_stop_status (struct address_space *aspace, CORE_ADDR pc, ptid_t ptid); -/* This bpstat_what stuff tells wait_for_inferior what to do with a - breakpoint (a challenging task). */ - -enum bpstat_what_main_action - { - /* Perform various other tests; that is, this bpstat does not - say to perform any action (e.g. failed watchpoint and nothing - else). */ - BPSTAT_WHAT_KEEP_CHECKING, - - /* Rather than distinguish between noisy and silent stops here, it - might be cleaner to have bpstat_print make that decision (also - taking into account stop_print_frame and source_only). But the - implications are a bit scary (interaction with auto-displays, etc.), - so I won't try it. */ - - /* Stop silently. */ - BPSTAT_WHAT_STOP_SILENT, - - /* Stop and print. */ - BPSTAT_WHAT_STOP_NOISY, - - /* Remove breakpoints, single step once, then put them back in and - go back to what we were doing. It's possible that this should be - removed from the main_action and put into a separate field, to more - cleanly handle BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE. */ - BPSTAT_WHAT_SINGLE, - - /* Set longjmp_resume breakpoint, remove all other breakpoints, - and continue. The "remove all other breakpoints" part is required - if we are also stepping over another breakpoint as well as doing - the longjmp handling. */ - BPSTAT_WHAT_SET_LONGJMP_RESUME, - - /* Clear longjmp_resume breakpoint, then handle as - BPSTAT_WHAT_KEEP_CHECKING. */ - BPSTAT_WHAT_CLEAR_LONGJMP_RESUME, - - /* Clear step resume breakpoint, and keep checking. */ - BPSTAT_WHAT_STEP_RESUME, - - /* Check the dynamic linker's data structures for new libraries, then - keep checking. */ - BPSTAT_WHAT_CHECK_SHLIBS, - - /* Check for new JITed code. */ - BPSTAT_WHAT_CHECK_JIT, - - /* This is just used to keep track of how many enums there are. */ - BPSTAT_WHAT_LAST - }; - /* An enum indicating the kind of "stack dummy" stop. This is a bit of a misnomer because only one kind of truly a stack dummy. */ enum stop_stack_kind @@ -627,17 +575,6 @@ enum stop_stack_kind STOP_STD_TERMINATE }; -struct bpstat_what - { - enum bpstat_what_main_action main_action; - - /* Did we hit a call dummy breakpoint? This only goes with a main_action - of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of - continuing from a call dummy without popping the frame is not a - useful one). */ - enum stop_stack_kind call_dummy; - }; - /* The possible return values for print_bpstat, print_it_normal, print_it_done, print_it_noop. bpstat_print depends on ther ordering where each item is an information subset of the previous one. */ @@ -650,9 +587,6 @@ enum print_stop_action PRINT_UNKNOWN }; -/* Tell what to do about this bpstat. */ -struct bpstat_what bpstat_what (bpstat); - /* Find the bpstat associated with a breakpoint. NULL otherwise. */ bpstat bpstat_find_breakpoint (bpstat, struct breakpoint *); @@ -1050,4 +984,6 @@ extern void check_tracepoint_command (char *line, void *closure); extern void start_rbreak_breakpoints (void); extern void end_rbreak_breakpoints (void); +extern const char *breakpoint_type_name (enum bptype bptype); + #endif /* !defined (BREAKPOINT_H) */ --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3947,185 +3947,357 @@ process_event_stop_test: return; } + /* Breakpoints may get deleted and created in the block below. It calls + reinit_frame_cache thus invalidating current_frame. In this block one + needs to explicitly get_current_frame. */ + frame = NULL; + gdbarch = NULL; + /* Handle cases caused by hitting a breakpoint. */ { - CORE_ADDR jmp_buf_pc; - struct bpstat_what what; - - what = bpstat_what (ecs->event_thread->stop_bpstat); - - if (what.call_dummy) + bpstat bs; + enum print_frame { - stop_stack_dummy = what.call_dummy; + /* pf_default is pf_yes. */ + pf_default, + /* stop_print_frame value 0. */ + pf_no, + /* stop_print_frame value 1. */ + pf_yes, } - - switch (what.main_action) + print_frame_max = pf_default; + enum stop_step { - case BPSTAT_WHAT_SET_LONGJMP_RESUME: - /* If we hit the breakpoint at longjmp while stepping, we - install a momentary breakpoint at the target of the - jmp_buf. */ - - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n"); - - ecs->event_thread->stepping_over_breakpoint = 1; - - if (!gdbarch_get_longjmp_target_p (gdbarch) - || !gdbarch_get_longjmp_target (gdbarch, frame, &jmp_buf_pc)) + /* ss_default is ss_print_yes. */ + ss_default, + /* ecs->event_thread->stop_step value 1. */ + ss_print_no, + /* ecs->event_thread->stop_step value 0. */ + ss_print_yes, + } + stop_step_max = ss_default; + enum perform + { + pe_undef, + /* Break from this block and check other possibilities why to stop. */ + pe_check_more, + /* Call stop_stepping (ecs). */ + pe_stop, + /* Like pe_stop but also print_stop_reason (END_STEPPING_RANGE, 0). */ + pe_stop_end_range, + /* Call keep_going (ecs) and return without breaking from this block + and checking other possibilities why to stop. Some operations need + to finish before an already stepped on breakpoint is displayed to + the user. */ + pe_going, + } + perform_max = pe_check_more; + /* solib_add may call breakpoint_re_set which would clear many + BREAKPOINT_AT entries still going to be processed. breakpoint_re_set + does not keep the same bp_location's even if they actually do not + change. */ + int perform_shlib = 0; + + for (bs = ecs->event_thread->stop_bpstat; bs != NULL; bs = bs->next) + { + /* Decisions for this specific BS, they get mapped to their *_max + variants at the end of this BS processing. */ + enum print_frame print_frame = pf_default; + enum stop_step stop_step = ss_default; + enum perform perform = pe_undef; + enum bptype bptype; + + if (bs->breakpoint_at == NULL) { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "\ -infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); - keep_going (ecs); - return; + /* I suspect this can happen if it was a momentary breakpoint + which has since been deleted. */ + bptype = bp_none; } + else if (bs->breakpoint_at->owner == NULL) + { + ecs->event_thread->stepping_over_breakpoint = 1; + bptype = bp_none; + } + else + bptype = bs->breakpoint_at->owner->type; - /* We're going to replace the current step-resume breakpoint - with a longjmp-resume breakpoint. */ - delete_step_resume_breakpoint (ecs->event_thread); - - /* Insert a breakpoint at resume address. */ - insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc); - - keep_going (ecs); - return; - - case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n"); - - gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL); - delete_step_resume_breakpoint (ecs->event_thread); - - ecs->event_thread->stop_step = 1; - print_stop_reason (END_STEPPING_RANGE, 0); - stop_stepping (ecs); - return; + fprintf_unfiltered (gdb_stdlog, "infrun: %s\n", + breakpoint_type_name (bptype)); - case BPSTAT_WHAT_SINGLE: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SINGLE\n"); - ecs->event_thread->stepping_over_breakpoint = 1; - /* Still need to check other stuff, at least the case - where we are stepping and step out of the right range. */ - break; + switch (bptype) + { + case bp_none: + perform = pe_check_more; + break; + case bp_breakpoint: + case bp_hardware_breakpoint: + case bp_until: + case bp_finish: + if (bs->stop) + { + print_frame = bs->print ? pf_yes : pf_no; + perform = pe_stop; + } + else + { + ecs->event_thread->stepping_over_breakpoint = 1; + perform = pe_check_more; + } + break; + case bp_watchpoint: + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_access_watchpoint: + case bp_catchpoint: + if (bs->stop) + { + print_frame = bs->print ? pf_yes : pf_no; + perform = pe_stop; + } + else + { + /* There was a watchpoint or catchpoint, but we're not + stopping. This requires no further action. */ + perform = pe_check_more; + } + break; + case bp_longjmp: + { + struct frame_info *frame = get_current_frame (); + struct gdbarch *gdbarch = get_frame_arch (frame); - case BPSTAT_WHAT_STOP_NOISY: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n"); - stop_print_frame = 1; + /* If we hit the breakpoint at longjmp while stepping, we + install a momentary breakpoint at the target of the + jmp_buf. */ - /* We are about to nuke the step_resume_breakpointt via the - cleanup chain, so no need to worry about it here. */ + CORE_ADDR jmp_buf_pc; + if (gdbarch_get_longjmp_target_p (gdbarch) + && gdbarch_get_longjmp_target (gdbarch, frame, &jmp_buf_pc)) + { + /* We're going to replace the current step-resume breakpoint + with a longjmp-resume breakpoint. */ + delete_step_resume_breakpoint (ecs->event_thread); - stop_stepping (ecs); - return; + /* Insert a breakpoint at resume address. */ + insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc); + } - case BPSTAT_WHAT_STOP_SILENT: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n"); - stop_print_frame = 0; + ecs->event_thread->stepping_over_breakpoint = 1; + perform = pe_going; + } + break; + case bp_longjmp_resume: + gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL); + delete_step_resume_breakpoint (ecs->event_thread); + stop_step = ss_print_no; + perform = pe_stop_end_range; + break; + case bp_step_resume: + if (bs->stop) + { + delete_step_resume_breakpoint (ecs->event_thread); + if (ecs->event_thread->step_after_step_resume_breakpoint) + { + /* Back when the step-resume breakpoint was inserted, we + were trying to single-step off a breakpoint. Go back + to doing that. pe_going must override pe_check_more so + that we do not stop again on that breakpoint. */ + ecs->event_thread->step_after_step_resume_breakpoint = 0; + ecs->event_thread->stepping_over_breakpoint = 1; + perform = pe_going; + } + else if (stop_pc == ecs->stop_func_start + && execution_direction == EXEC_REVERSE) + { + /* We are stepping over a function call in reverse, and + just hit the step-resume breakpoint at the start + address of the function. Go back to single-stepping, + which should take us back to the function call. */ + ecs->event_thread->stepping_over_breakpoint = 1; + perform = pe_going; + } + else + perform = pe_check_more; + } + else + { + /* It is for the wrong frame. */ + ecs->event_thread->stepping_over_breakpoint = 1; + perform = pe_check_more; + } + break; + case bp_watchpoint_scope: + case bp_thread_event: + case bp_overlay_event: + case bp_longjmp_master: + case bp_std_terminate_master: + ecs->event_thread->stepping_over_breakpoint = 1; + perform = pe_check_more; + break; + case bp_shlib_event: + perform_shlib = 1; + + /* If requested, stop when the dynamic linker notifies + gdb of events. This allows the user to get control + and place breakpoints in initializer routines for + dynamically loaded objects (among other things). */ + if (stop_on_solib_events || stop_stack_dummy) + perform = pe_stop; + else + { + /* We want to step over this breakpoint, then keep going. */ + ecs->event_thread->stepping_over_breakpoint = 1; + perform = pe_check_more; + } + break; + case bp_jit_event: + /* Switch terminal for any messages produced by breakpoint_re_set. */ + target_terminal_ours_for_output (); - /* We are about to nuke the step_resume_breakpoin via the - cleanup chain, so no need to worry about it here. */ + { + struct frame_info *frame = get_current_frame (); + struct gdbarch *gdbarch = get_frame_arch (frame); - stop_stepping (ecs); - return; + jit_event_handler (gdbarch); + } - case BPSTAT_WHAT_STEP_RESUME: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n"); + target_terminal_inferior (); - delete_step_resume_breakpoint (ecs->event_thread); - if (ecs->event_thread->step_after_step_resume_breakpoint) - { - /* Back when the step-resume breakpoint was inserted, we - were trying to single-step off a breakpoint. Go back - to doing that. */ - ecs->event_thread->step_after_step_resume_breakpoint = 0; + /* We want to step over this breakpoint, then keep going. */ ecs->event_thread->stepping_over_breakpoint = 1; - keep_going (ecs); - return; - } - if (stop_pc == ecs->stop_func_start - && execution_direction == EXEC_REVERSE) - { - /* We are stepping over a function call in reverse, and - just hit the step-resume breakpoint at the start - address of the function. Go back to single-stepping, - which should take us back to the function call. */ - ecs->event_thread->stepping_over_breakpoint = 1; - keep_going (ecs); - return; + perform = pe_check_more; + break; + case bp_call_dummy: + /* Make sure the action is stop (silent or noisy), + so infrun.c pops the dummy frame. */ + stop_stack_dummy = STOP_STACK_DUMMY; + print_frame = pf_no; + perform = pe_stop; + break; + case bp_std_terminate: + /* Make sure the action is stop (silent or noisy), + so infrun.c pops the dummy frame. */ + stop_stack_dummy = STOP_STD_TERMINATE; + print_frame = pf_no; + perform = pe_stop; + break; + case bp_tracepoint: + case bp_fast_tracepoint: + /* Tracepoint hits should not be reported back to GDB, and + if one got through somehow, it should have been filtered + out already. */ + internal_error (__FILE__, __LINE__, + _("handle_inferior_event: tracepoint encountered")); + break; + default: + internal_error (__FILE__, __LINE__, + _("handle_inferior_event: Unhandled bptype %s"), + breakpoint_type_name (bptype)); + break; } - break; - case BPSTAT_WHAT_CHECK_SHLIBS: - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n"); + /* PERFORM must be always decided. */ + if (perform == pe_undef) + internal_error (__FILE__, __LINE__, + _("handle_inferior_event: Unset perform, bptype %s"), + breakpoint_type_name (bptype)); - /* Check for any newly added shared libraries if we're - supposed to be adding them automatically. Switch - terminal for any messages produced by - breakpoint_re_set. */ - target_terminal_ours_for_output (); - /* NOTE: cagney/2003-11-25: Make certain that the target - stack's section table is kept up-to-date. Architectures, - (e.g., PPC64), use the section table to perform - operations such as address => section name and hence - require the table to contain all sections (including - those found in shared libraries). */ + if (debug_infrun) + { + const char *bptype_s = breakpoint_type_name (bptype); + + if (print_frame != pf_default) + fprintf_unfiltered (gdb_stdlog, "infrun: %s: print_frame %s\n", + bptype_s, print_frame == pf_no ? "pf_no" + : "pf_yes"); + if (stop_step != ss_default) + fprintf_unfiltered (gdb_stdlog, "infrun: %s: stop_step %s\n", + bptype_s, stop_step_max == ss_print_no + ? "ss_print_no (stop_step 1)" + : "ss_print_yes (stop_step 0)"); + fprintf_unfiltered (gdb_stdlog, "infrun: %s: perform %s\n", + bptype_s, + perform == pe_going + ? "pe_going" + : perform == pe_check_more + ? "pe_check_more" + : perform == pe_stop + ? "pe_stop" : "pe_stop_end_range"); + } + + if (print_frame_max < print_frame) + print_frame_max = print_frame; + if (stop_step_max < stop_step) + stop_step_max = stop_step; + if (perform_max < perform) + perform_max = perform; + } + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + _("infrun: summary: print_frame %s\n" + "infrun: summary: stop_step %s\n" + "infrun: summary: perform %s\n"), + print_frame_max == pf_default + ? "pf_default (pf_yes)" + : print_frame_max == pf_no ? "pf_no" : "pf_yes", + stop_step_max == ss_default + ? "ss_default (ss_print_yes (stop_step 0))" + : stop_step_max == ss_print_no + ? "ss_print_no (stop_step 1)" + : "ss_print_yes (stop_step 0)", + perform_max == pe_check_more + ? "pe_check_more" + : perform_max == pe_stop + ? "pe_stop" : perform_max == pe_stop_end_range + ? "pe_stop_end_range" : "pe_going"); + if (print_frame_max == pf_default) + print_frame_max = pf_yes; + if (stop_step_max == ss_default) + stop_step_max = ss_print_yes; + gdb_assert (perform_max != pe_undef); + + if (perform_shlib) + { + /* Check for any newly added shared libraries if we're + supposed to be adding them automatically. Switch + terminal for any messages produced by + breakpoint_re_set. */ + target_terminal_ours_for_output (); + /* NOTE: cagney/2003-11-25: Make certain that the target + stack's section table is kept up-to-date. Architectures, + (e.g., PPC64), use the section table to perform + operations such as address => section name and hence + require the table to contain all sections (including + those found in shared libraries). */ #ifdef SOLIB_ADD - SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); + SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add); #else - solib_add (NULL, 0, ¤t_target, auto_solib_add); + solib_add (NULL, 0, ¤t_target, auto_solib_add); #endif - target_terminal_inferior (); - - /* If requested, stop when the dynamic linker notifies - gdb of events. This allows the user to get control - and place breakpoints in initializer routines for - dynamically loaded objects (among other things). */ - if (stop_on_solib_events || stop_stack_dummy) - { - stop_stepping (ecs); - return; - } - else - { - /* We want to step over this breakpoint, then keep going. */ - ecs->event_thread->stepping_over_breakpoint = 1; - break; - } - } - break; - - case BPSTAT_WHAT_CHECK_JIT: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_JIT\n"); - - /* Switch terminal for any messages produced by breakpoint_re_set. */ - target_terminal_ours_for_output (); - - jit_event_handler (gdbarch); - - target_terminal_inferior (); - - /* We want to step over this breakpoint, then keep going. */ - ecs->event_thread->stepping_over_breakpoint = 1; - - break; - - case BPSTAT_WHAT_LAST: - /* Not a real code, but listed here to shut up gcc -Wall. */ + target_terminal_inferior (); + } - case BPSTAT_WHAT_KEEP_CHECKING: + stop_print_frame = print_frame_max == pf_yes; + ecs->event_thread->stop_step = stop_step_max == ss_print_no; + switch (perform_max) + { + case pe_check_more: + /* Still need to check other stuff, at least the case + where we are stepping and step out of the right range. */ break; - } + case pe_stop_end_range: + print_stop_reason (END_STEPPING_RANGE, 0); + /* FALLTHRU */ + case pe_stop: + /* We are about to nuke the step_resume_breakpointt via the + cleanup chain, so no need to worry about it here. */ + stop_stepping (ecs); + return; + case pe_going: + keep_going (ecs); + return; + } } /* We come here if we hit a breakpoint but should not @@ -4258,6 +4430,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); the frame cache to be re-initialized, making our FRAME variable a dangling pointer. */ frame = get_current_frame (); + gdbarch = get_frame_arch (frame); /* If stepping through a line, keep going if still within it. --- /dev/null +++ b/gdb/testsuite/gdb.base/break-solib-event.exp @@ -0,0 +1,90 @@ +# Copyright 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if {[skip_shlib_tests]} { + return 0 +} + +set testfile "break-solib-event" +set libfile "unloadshr" +set libfile2 "unloadshr2" +set libname "${testfile}-{libfile}.sl" +set libname2 "${testfile}-{libfile2}.sl" +set libsrcfile ${libfile}.c +set libsrcfile2 ${libfile2}.c +set srcfile $srcdir/$subdir/unload.c +set executable $testfile +set binfile $objdir/$subdir/$executable +set shlibdir ${objdir}/${subdir} +set libsrc $srcdir/$subdir/$libfile.c +set libsrc2 $srcdir/$subdir/$libfile2.c +set lib_sl $objdir/$subdir/$libname +set lib_sl2 $objdir/$subdir/$libname2 +set lib_dlopen [shlib_target_file ${libname}] +set lib_dlopen2 [shlib_target_file ${libname2}] +set lib_syms [shlib_symbol_file ${libname}] +set lib_syms2 [shlib_symbol_file ${libname2}] + +if [get_compiler_info ${binfile}] { + return -1 +} + +set lib_opts debug +set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${lib_dlopen}\" additional_flags=-DSHLIB_NAME2\=\"${lib_dlopen2}\"] + +if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != "" + || [gdb_compile_shlib $libsrc2 $lib_sl2 $lib_opts] != "" + || [gdb_compile $srcfile $binfile executable $exec_opts] != ""} { + untested "Couldn't compile $libsrc or $libsrc2 or $srcfile." + return -1 +} + +clean_restart $executable +gdb_load_shlibs $lib_sl $lib_sl2 + +gdb_test "set stop-on-solib-events 1" + +set event_msg "Stopped due to shared library event" + +gdb_run_cmd +gdb_test "" "${event_msg}.*" "stop at event" + +# gdb_breakpoint {*$pc} or {*$} creates a "floating" breakpoint - changing its +# position on breakpoint_re_set (which happens on bp_shlib_event). +set test {p/x $pc} +set event "" +gdb_test_multiple $test $test { + -re " = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" { + set event $expect_out(1,string) + pass $test + } +} +gdb_breakpoint "*$event" + +set test {commands $bpnum} +gdb_test_multiple $test $test { + -re "\r\n>$" { + pass $test + } +} +set test {echo event-hit\n} +gdb_test_multiple $test $test { + -re "\r\n>$" { + pass $test + } +} +gdb_test "end" + +gdb_test "continue" "${event_msg}.*event-hit.*"