aboutsummaryrefslogtreecommitdiff
path: root/gdb/infrun.c
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2009-06-28 00:20:24 +0000
committerDaniel Jacobowitz <drow@false.org>2009-06-28 00:20:24 +0000
commitedb3359dff90ef8a3352408bfef8ce1438c2b2e1 (patch)
tree36b3ee7b866889c22ffb06aaa2ad0dfad826ab10 /gdb/infrun.c
parentc7ce8faacb57cd10f919caff6c5018c4526e752e (diff)
downloadgdb-edb3359dff90ef8a3352408bfef8ce1438c2b2e1.zip
gdb-edb3359dff90ef8a3352408bfef8ce1438c2b2e1.tar.gz
gdb-edb3359dff90ef8a3352408bfef8ce1438c2b2e1.tar.bz2
gdb/
* NEWS: Document inlined function support. * Makefile.in (SFILES): Add inline-frame.c. (COMMON_OBS): Add inline-frame.o. * block.c (contained_in): Rewrite to use lexical nesting. (block_linkage_function): Skip inlined function blocks. (block_inlined_p): New. * block.h (struct block): Update comment. (block_inlined_p): New prototype. * blockframe.c (get_frame_block): Handle inlined functions. (get_frame_function): Do not use block_linkage_function. (block_innermost_frame): Use get_frame_block and contained_in. * breakpoint.c (watchpoint_check): Remove extra reinit_frame_cache. Skip over inlined functions. Simplify epilogue check. (bpstat_check_breakpoint_conditions): Use get_stack_frame_id. Update comments. (set_momentary_breakpoint): Only accept non-inlined frames. (watch_command_1): Use frame_unwind_caller_pc and frame_unwind_caller_id instead of get_prev_frame. (until_break_command): Likewise. Use get_stack_frame_id. * buildsym.c (end_symtab): Set SYMBOL_SYMTAB for block functions. * dwarf2loc.c (dwarf_expr_frame_base): Use block_linkage_function. * dwarf2read.c (process_die): Handle DW_TAG_inlined_subroutine. (read_func_scope, new_symbol): Likewise. Handle arguments specially for inlined functions without call site information. (inherit_abstract_dies): Allow tag mismatch for inlined subroutines. (die_specification): Treat DW_AT_abstract_origin as a specification. (read_type_die): Handle DW_TAG_inlined_subroutine. * frame-unwind.c (frame_unwind_init): Add inline_frame_unwind. * frame.c (fprint_frame_id): Print inline depth. (fprint_frame_type): Handle INLINE_FRAME and SENTINEL_FRAME. (skip_inlined_frames, get_stack_frame_id): New. (frame_unwind_caller_id): Use skip_inlined_frames. (frame_id_inlined_p): New. (frame_id_eq): Make the logic match the comments. Add inline_depth check. (frame_id_inner): Handle inlined functions. (frame_unwind_pc): New function, copied from frame_unwind_caller_pc. (frame_unwind_caller_pc): Use skip_inlined_frames and frame_unwind_pc. (get_prev_frame_1): Check for inline frames. Split out frame allocation to get_prev_frame_raw. (get_prev_frame_raw): New function. (get_prev_frame): Handle inline frames. (get_frame_pc): Use frame_unwind_pc. (get_frame_address_in_block): Skip inlined frames on both sides. (pc_notcurrent): Delete. (find_frame_sal): Rewrite to handle inline call sites. Use get_frame_address_in_block. (deprecated_update_frame_pc_hack): Make static. * frame.h: Update comments. (struct frame_id): Add inline_depth. (enum frame_type): Add INLINE_FRAME. (frame_id_inlined_p, get_stack_frame_id): New prototypes. * gdbthread.h (struct thread_info): Add step_stack_frame_id field. * infcmd.c (set_step_frame): New function. (step_once): Use set_step_frame. Handle inlined functions. (until_next_command): Use set_step_frame. (finish_backward), finish_forward): Use get_stack_frame_id. (finish_command): Support inlined functions. * inferior.h (set_step_info): New prototype. * infrun.c (RESUME_ALL): Use minus_one_ptid. (clear_proceed_status): Clear step_stack_frame_id. (init_wait_for_inferior): Call clear_inline_frame_state. (init_execution_control_state): Make static. (set_step_info): New function. (init_thread_stepping_state): Do not set the symtab or line here. (stepped_in_from): New function. (handle_inferior_event): Handle inlined functions. Use set_step_info. (insert_step_resume_breakpoint_at_frame): Use get_stack_frame_id. (struct inferior_status): Add step_stack_frame_id. (save_inferior_status, restore_inferior_status): Save and restore step_stack_frame_id. * inline-frame.c, inline-frame.h: New files. * minsyms.c (prim_record_minimal_symbol_and_info): Use XCALLOC. * regcache.c (regcache_write_pc): Call reinit_frame_cache. * s390-tdep.c (s390_prologue_frame_unwind_cache): Handle INLINE_FRAME. * stack.c (frame_show_address): New. (print_frame_info, print_frame): Use it. (find_frame_funname): Use get_frame_function. Handle inlined blocks. (frame_info): Mark inlined functions. (backtrace_command_1): Use get_current_user_frame. (print_frame_local_vars, print_frame_label_vars): Update comments. (return_command): Refuse inlined functions. * symtab.c (lookup_symbol_aux_local): Stop at inlined function boundaries. (find_function_start_sal): Avoid inlined functions. (completion_list_add_fields): New function. (default_make_symbol_completion_list): Use it. Use block_static_block and block_global_block. Check for inlined functions. (skip_prologue_using_sal): Avoid line number comparison across inlining. * symtab.h (struct symbol): Add is_inlined. (SYMBOL_INLINED): New. * target.c (target_resume): Call clear_inline_frame_state. * valops.c (value_of_variable): Check block_inlined_p. gdb/doc/ * gdb.texinfo (Debugging Optimized Code): New chapter. (Compiling for Debugging): Reference it. Move some text to the new section. gdb/testsuite/ * gdb.base/break.exp: Add an XFAIL for gcc/36748. * gdb.cp/annota2.exp: Accept frames-invalid in more places. * gdb.opt/Makefile.in (EXECUTABLES): Update. * gdb.opt/clobbered-registers-O2.exp: Update to GPL v3. * gdb.opt/inline-bt.c, gdb.opt/inline-bt.exp, gdb.opt/inline-cmds.c, gdb.opt/inline-cmds.exp, gdb.opt/inline-locals.c, gdb.opt/inline-locals.exp, gdb.opt/inline-markers.c: New files. * lib/gdb.exp (skip_inline_frame_tests): New function. (skip_inline_var_tests): New function.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r--gdb/infrun.c147
1 files changed, 129 insertions, 18 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 5f1b16b..a2ab386 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -49,6 +49,7 @@
#include "mi/mi-common.h"
#include "event-top.h"
#include "record.h"
+#include "inline-frame.h"
/* Prototypes for local functions */
@@ -209,7 +210,7 @@ static unsigned char *signal_program;
/* Value to pass to target_resume() to cause all threads to resume */
-#define RESUME_ALL (pid_to_ptid (-1))
+#define RESUME_ALL minus_one_ptid
/* Command list pointer for the "stop" placeholder. */
@@ -1316,6 +1317,7 @@ clear_proceed_status_thread (struct thread_info *tp)
tp->step_range_start = 0;
tp->step_range_end = 0;
tp->step_frame_id = null_frame_id;
+ tp->step_stack_frame_id = null_frame_id;
tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
tp->stop_requested = 0;
@@ -1689,6 +1691,9 @@ init_wait_for_inferior (void)
init_infwait_state ();
displaced_step_clear ();
+
+ /* Discard any skipped inlined frames. */
+ clear_inline_frame_state (minus_one_ptid);
}
@@ -1744,7 +1749,7 @@ struct execution_control_state
int wait_some_more;
};
-void init_execution_control_state (struct execution_control_state *ecs);
+static void init_execution_control_state (struct execution_control_state *ecs);
void handle_inferior_event (struct execution_control_state *ecs);
@@ -2137,10 +2142,23 @@ fetch_inferior_event (void *client_data)
display_gdb_prompt (0);
}
+/* Record the frame and location we're currently stepping through. */
+void
+set_step_info (struct frame_info *frame, struct symtab_and_line sal)
+{
+ struct thread_info *tp = inferior_thread ();
+
+ tp->step_frame_id = get_frame_id (frame);
+ tp->step_stack_frame_id = get_stack_frame_id (frame);
+
+ tp->current_symtab = sal.symtab;
+ tp->current_line = sal.line;
+}
+
/* Prepare an execution control state for looping through a
wait_for_inferior-type loop. */
-void
+static void
init_execution_control_state (struct execution_control_state *ecs)
{
ecs->random_signal = 0;
@@ -2151,16 +2169,10 @@ init_execution_control_state (struct execution_control_state *ecs)
void
init_thread_stepping_state (struct thread_info *tss)
{
- struct symtab_and_line sal;
-
tss->stepping_over_breakpoint = 0;
tss->step_after_step_resume_breakpoint = 0;
tss->stepping_through_solib_after_catch = 0;
tss->stepping_through_solib_catchpoints = NULL;
-
- sal = find_pc_line (tss->prev_pc, 0);
- tss->current_line = sal.line;
- tss->current_symtab = sal.symtab;
}
/* Return the cached copy of the last pid/waitstatus returned by
@@ -2337,6 +2349,22 @@ ensure_not_running (void)
error_is_running ();
}
+static int
+stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
+{
+ for (frame = get_prev_frame (frame);
+ frame != NULL;
+ frame = get_prev_frame (frame))
+ {
+ if (frame_id_eq (get_frame_id (frame), step_frame_id))
+ return 1;
+ if (get_frame_type (frame) != INLINE_FRAME)
+ break;
+ }
+
+ return 0;
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
appropriate action. */
@@ -3065,6 +3093,12 @@ targets should add new threads to the thread list themselves in non-stop mode.")
ecs->random_signal = 0;
stopped_by_random_signal = 0;
+ /* Hide inlined functions starting here, unless we just performed stepi or
+ nexti. After stepi and nexti, always show the innermost frame (not any
+ inline function call sites). */
+ if (ecs->event_thread->step_range_end != 1)
+ skip_inline_frames (ecs->ptid);
+
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
&& ecs->event_thread->trap_expected
&& gdbarch_single_step_through_delay_p (gdbarch)
@@ -3302,8 +3336,8 @@ process_event_stop_test:
&& ecs->event_thread->stop_signal != TARGET_SIGNAL_0
&& (ecs->event_thread->step_range_start <= stop_pc
&& stop_pc < ecs->event_thread->step_range_end)
- && frame_id_eq (get_frame_id (frame),
- ecs->event_thread->step_frame_id)
+ && frame_id_eq (get_stack_frame_id (frame),
+ ecs->event_thread->step_stack_frame_id)
&& ecs->event_thread->step_resume_breakpoint == NULL)
{
/* The inferior is about to take a signal that will take it
@@ -3727,10 +3761,10 @@ infrun: not switching back to stepped thread, it has vanished\n");
NOTE: frame_id_eq will never report two invalid frame IDs as
being equal, so to get into this block, both the current and
previous frame must have valid frame IDs. */
- if (!frame_id_eq (get_frame_id (frame),
- ecs->event_thread->step_frame_id)
+ if (!frame_id_eq (get_stack_frame_id (frame),
+ ecs->event_thread->step_stack_frame_id)
&& (frame_id_eq (frame_unwind_caller_id (frame),
- ecs->event_thread->step_frame_id)
+ ecs->event_thread->step_stack_frame_id)
|| execution_direction == EXEC_REVERSE))
{
CORE_ADDR real_stop_pc;
@@ -3974,6 +4008,82 @@ infrun: not switching back to stepped thread, it has vanished\n");
return;
}
+ /* Look for "calls" to inlined functions, part one. If the inline
+ frame machinery detected some skipped call sites, we have entered
+ a new inline function. */
+
+ if (frame_id_eq (get_frame_id (get_current_frame ()),
+ ecs->event_thread->step_frame_id)
+ && inline_skipped_frames (ecs->ptid))
+ {
+ struct symtab_and_line call_sal;
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepped into inlined function\n");
+
+ find_frame_sal (get_current_frame (), &call_sal);
+
+ if (ecs->event_thread->step_over_calls != STEP_OVER_ALL)
+ {
+ /* For "step", we're going to stop. But if the call site
+ for this inlined function is on the same source line as
+ we were previously stepping, go down into the function
+ first. Otherwise stop at the call site. */
+
+ if (call_sal.line == ecs->event_thread->current_line
+ && call_sal.symtab == ecs->event_thread->current_symtab)
+ step_into_inline_frame (ecs->ptid);
+
+ ecs->event_thread->stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+ else
+ {
+ /* For "next", we should stop at the call site if it is on a
+ different source line. Otherwise continue through the
+ inlined function. */
+ if (call_sal.line == ecs->event_thread->current_line
+ && call_sal.symtab == ecs->event_thread->current_symtab)
+ keep_going (ecs);
+ else
+ {
+ ecs->event_thread->stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ }
+ return;
+ }
+ }
+
+ /* Look for "calls" to inlined functions, part two. If we are still
+ in the same real function we were stepping through, but we have
+ to go further up to find the exact frame ID, we are stepping
+ through a more inlined call beyond its call site. */
+
+ if (get_frame_type (get_current_frame ()) == INLINE_FRAME
+ && !frame_id_eq (get_frame_id (get_current_frame ()),
+ ecs->event_thread->step_frame_id)
+ && stepped_in_from (get_current_frame (),
+ ecs->event_thread->step_frame_id))
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepping through inlined function\n");
+
+ if (ecs->event_thread->step_over_calls == STEP_OVER_ALL)
+ keep_going (ecs);
+ else
+ {
+ ecs->event_thread->stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ }
+ return;
+ }
+
if ((stop_pc == stop_pc_sal.pc)
&& (ecs->event_thread->current_line != stop_pc_sal.line
|| ecs->event_thread->current_symtab != stop_pc_sal.symtab))
@@ -3999,9 +4109,7 @@ infrun: not switching back to stepped thread, it has vanished\n");
ecs->event_thread->step_range_start = stop_pc_sal.pc;
ecs->event_thread->step_range_end = stop_pc_sal.end;
- ecs->event_thread->step_frame_id = get_frame_id (frame);
- ecs->event_thread->current_line = stop_pc_sal.line;
- ecs->event_thread->current_symtab = stop_pc_sal.symtab;
+ set_step_info (frame, stop_pc_sal);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
@@ -4188,7 +4296,7 @@ insert_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch, get_frame_pc (return_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
- insert_step_resume_breakpoint_at_sal (sr_sal, get_frame_id (return_frame));
+ insert_step_resume_breakpoint_at_sal (sr_sal, get_stack_frame_id (return_frame));
}
/* Similar to insert_step_resume_breakpoint_at_frame, except
@@ -5266,6 +5374,7 @@ struct inferior_status
CORE_ADDR step_range_start;
CORE_ADDR step_range_end;
struct frame_id step_frame_id;
+ struct frame_id step_stack_frame_id;
enum step_over_calls_kind step_over_calls;
CORE_ADDR step_resume_break_address;
int stop_after_trap;
@@ -5295,6 +5404,7 @@ save_inferior_status (void)
inf_status->step_range_start = tp->step_range_start;
inf_status->step_range_end = tp->step_range_end;
inf_status->step_frame_id = tp->step_frame_id;
+ inf_status->step_stack_frame_id = tp->step_stack_frame_id;
inf_status->step_over_calls = tp->step_over_calls;
inf_status->stop_after_trap = stop_after_trap;
inf_status->stop_soon = inf->stop_soon;
@@ -5348,6 +5458,7 @@ restore_inferior_status (struct inferior_status *inf_status)
tp->step_range_start = inf_status->step_range_start;
tp->step_range_end = inf_status->step_range_end;
tp->step_frame_id = inf_status->step_frame_id;
+ tp->step_stack_frame_id = inf_status->step_stack_frame_id;
tp->step_over_calls = inf_status->step_over_calls;
stop_after_trap = inf_status->stop_after_trap;
inf->stop_soon = inf_status->stop_soon;