diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/breakpoint.c | 39 | ||||
-rw-r--r-- | gdb/breakpoint.h | 6 | ||||
-rw-r--r-- | gdb/infrun.c | 27 |
4 files changed, 79 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 83cbcf1..be9a96d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2011-10-12 Gary Benson <gbenson@redhat.com> + + * breakpoint.h (pc_at_non_inline_function): Declare. + * breakpoint.c (is_non_inline_function, + pc_at_non_inline_function): New functions. + * infrun.c (handle_inferior_event): Don't call skip_inline_frames + if the stop is at a location where functions cannot be inlined. + 2011-10-12 Pedro Alves <pedro@codesourcery.com> * linux-nat.c (stop_and_resume_callback): Don't re-resume LWPs if diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 08ff69b..ba1b08f 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -13325,6 +13325,45 @@ iterate_over_breakpoints (int (*callback) (struct breakpoint *, void *), return NULL; } +/* Zero if any of the breakpoint's locations could be a location where + functions have been inlined, nonzero otherwise. */ + +static int +is_non_inline_function (struct breakpoint *b) +{ + /* The shared library event breakpoint is set on the address of a + non-inline function. */ + if (b->type == bp_shlib_event) + return 1; + + return 0; +} + +/* Nonzero if the specified PC cannot be a location where functions + have been inlined. */ + +int +pc_at_non_inline_function (struct address_space *aspace, CORE_ADDR pc) +{ + struct breakpoint *b; + struct bp_location *bl; + + ALL_BREAKPOINTS (b) + { + if (!is_non_inline_function (b)) + continue; + + for (bl = b->loc; bl != NULL; bl = bl->next) + { + if (!bl->shlib_disabled + && bpstat_check_location (bl, aspace, pc)) + return 1; + } + } + + return 0; +} + void initialize_breakpoint_ops (void) { diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 5e5d1b9..c2116e2 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -1357,6 +1357,12 @@ extern void end_rbreak_breakpoints (void); extern struct breakpoint *iterate_over_breakpoints (int (*) (struct breakpoint *, void *), void *); +/* Nonzero if the specified PC cannot be a location where functions + have been inlined. */ + +extern int pc_at_non_inline_function (struct address_space *aspace, + CORE_ADDR pc); + extern int user_breakpoint_p (struct breakpoint *); #endif /* !defined (BREAKPOINT_H) */ diff --git a/gdb/infrun.c b/gdb/infrun.c index cc2e29b..db6a5d1 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -4044,7 +4044,32 @@ handle_inferior_event (struct execution_control_state *ecs) nexti. After stepi and nexti, always show the innermost frame (not any inline function call sites). */ if (ecs->event_thread->control.step_range_end != 1) - skip_inline_frames (ecs->ptid); + { + struct address_space *aspace = + get_regcache_aspace (get_thread_regcache (ecs->ptid)); + + /* skip_inline_frames is expensive, so we avoid it if we can + determine that the address is one where functions cannot have + been inlined. This improves performance with inferiors that + load a lot of shared libraries, because the solib event + breakpoint is defined as the address of a function (i.e. not + inline). Note that we have to check the previous PC as well + as the current one to catch cases when we have just + single-stepped off a breakpoint prior to reinstating it. + Note that we're assuming that the code we single-step to is + not inline, but that's not definitive: there's nothing + preventing the event breakpoint function from containing + inlined code, and the single-step ending up there. If the + user had set a breakpoint on that inlined code, the missing + skip_inline_frames call would break things. Fortunately + that's an extremely unlikely scenario. */ + if (!pc_at_non_inline_function (aspace, stop_pc) + && !(ecs->event_thread->suspend.stop_signal == TARGET_SIGNAL_TRAP + && ecs->event_thread->control.trap_expected + && pc_at_non_inline_function (aspace, + ecs->event_thread->prev_pc))) + skip_inline_frames (ecs->ptid); + } if (ecs->event_thread->suspend.stop_signal == TARGET_SIGNAL_TRAP && ecs->event_thread->control.trap_expected |