aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/breakpoint.c39
-rw-r--r--gdb/breakpoint.h6
-rw-r--r--gdb/infrun.c27
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