diff options
author | Daniel Jacobowitz <drow@false.org> | 2009-06-28 00:20:24 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2009-06-28 00:20:24 +0000 |
commit | edb3359dff90ef8a3352408bfef8ce1438c2b2e1 (patch) | |
tree | 36b3ee7b866889c22ffb06aaa2ad0dfad826ab10 /gdb/testsuite | |
parent | c7ce8faacb57cd10f919caff6c5018c4526e752e (diff) | |
download | gdb-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/testsuite')
-rw-r--r-- | gdb/testsuite/ChangeLog | 13 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/break.exp | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/annota2.exp | 3 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/Makefile.in | 2 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/clobbered-registers-O2.exp | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-bt.c | 47 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-bt.exp | 63 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-cmds.c | 85 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-cmds.exp | 308 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-locals.c | 52 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-locals.exp | 138 | ||||
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-markers.c | 36 | ||||
-rw-r--r-- | gdb/testsuite/lib/gdb.exp | 31 |
13 files changed, 785 insertions, 5 deletions
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 1cb19c7..78678fe 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2009-06-27 Daniel Jacobowitz <dan@codesourcery.com> + + * 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. + 2009-06-27 Andreas Schwab <schwab@linux-m68k.org> * gdb.cp/exception.exp: Don't require $hex before inner frame in diff --git a/gdb/testsuite/gdb.base/break.exp b/gdb/testsuite/gdb.base/break.exp index 7067dc3..20acd7e 100644 --- a/gdb/testsuite/gdb.base/break.exp +++ b/gdb/testsuite/gdb.base/break.exp @@ -880,6 +880,13 @@ gdb_expect { # marker4() is defined at line 46 when compiled with -DPROTOTYPES pass "run until breakpoint set at small function, optimized file (line bp_location14)" } + -re "Breakpoint $decimal, factorial \\(.*\\) .*\{\r\n$gdb_prompt" { + # GCC 4.3 emits bad line number information - see gcc/36748. + if { [test_compiler_info "gcc-4-3-*"] } { + setup_xfail *-*-* + } + fail "run until breakpoint set at small function, optimized file" + } -re ".*$gdb_prompt " { fail "run until breakpoint set at small function, optimized file" } diff --git a/gdb/testsuite/gdb.cp/annota2.exp b/gdb/testsuite/gdb.cp/annota2.exp index 26c8abf..1f24abd 100644 --- a/gdb/testsuite/gdb.cp/annota2.exp +++ b/gdb/testsuite/gdb.cp/annota2.exp @@ -119,10 +119,11 @@ gdb_expect { # continue until exit # this will test: # annotate-exited +# `a.x is 1' is asynchronous regarding to `frames-invalid'. # send_gdb "continue\n" gdb_expect { - -re "\r\n\032\032post-prompt\r\nContinuing.\r\n\r\n\032\032starting\(\r\n\r\n\032\032frames-invalid\)+\r\na.x is 1\r\n\r\n\032\032exited 0\r\n\r\nProgram exited normally.\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \ + -re "\r\n\032\032post-prompt\r\nContinuing.\r\n\r\n\032\032starting\(\r\n\r\n\032\032frames-invalid\)*\r\na.x is 1\r\n\(\r\n\032\032frames-invalid\r\n\)*\r\n\032\032exited 0\r\n\r\nProgram exited normally.\r\n\r\n\032\032stopped\r\n$gdb_prompt$" \ { pass "continue until exit" } -re ".*$gdb_prompt$" { fail "continue to exit" } timeout { fail "continue to exit (timeout)" } diff --git a/gdb/testsuite/gdb.opt/Makefile.in b/gdb/testsuite/gdb.opt/Makefile.in index e8bea9c..a35e59a 100644 --- a/gdb/testsuite/gdb.opt/Makefile.in +++ b/gdb/testsuite/gdb.opt/Makefile.in @@ -1,7 +1,7 @@ VPATH = @srcdir@ srcdir = @srcdir@ -EXECUTABLES = hello/hello +EXECUTABLES = clobbered-registers-O2 inline-bt inline-cmds inline-locals MISCELLANEOUS = diff --git a/gdb/testsuite/gdb.opt/clobbered-registers-O2.exp b/gdb/testsuite/gdb.opt/clobbered-registers-O2.exp index bccca91..a192fa5 100644 --- a/gdb/testsuite/gdb.opt/clobbered-registers-O2.exp +++ b/gdb/testsuite/gdb.opt/clobbered-registers-O2.exp @@ -2,7 +2,7 @@ # # 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 2 of the License, or +# 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, @@ -11,8 +11,7 @@ # 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, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# along with this program. If not, see <http://www.gnu.org/licenses/>. # # This file is part of the gdb testsuite. diff --git a/gdb/testsuite/gdb.opt/inline-bt.c b/gdb/testsuite/gdb.opt/inline-bt.c new file mode 100644 index 0000000..402e283 --- /dev/null +++ b/gdb/testsuite/gdb.opt/inline-bt.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2008 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 <http://www.gnu.org/licenses/>. */ + +int x, y; +volatile int result; + +void bar(void); + +inline int func1(void) +{ + bar (); + return x * y; +} + +inline int func2(void) +{ + return x * func1 (); +} + +int main (void) +{ + int val; + + x = 7; + y = 8; + bar (); + + val = func1 (); + result = val; + + val = func2 (); + result = val; + + return 0; +} diff --git a/gdb/testsuite/gdb.opt/inline-bt.exp b/gdb/testsuite/gdb.opt/inline-bt.exp new file mode 100644 index 0000000..10325ab --- /dev/null +++ b/gdb/testsuite/gdb.opt/inline-bt.exp @@ -0,0 +1,63 @@ +# Copyright 2008 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 <http://www.gnu.org/licenses/>. + +set testfile "inline-bt" +set srcfile ${testfile}.c +set srcfile2 "inline-markers.c" +set fullsrcfile "${srcdir}/${subdir}/${srcfile}" +set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}" +set sources [list ${fullsrcfile} ${fullsrcfile2}] +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile ${sources} ${binfile} \ + executable {debug optimize=-O2}] != "" } { + untested inline-bt.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +runto_main + +get_compiler_info $binfile +get_debug_format +if { [skip_inline_frame_tests] } { + untested inline-bt.exp + return +} + +set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile2}] +gdb_breakpoint $srcfile2:$line1 + +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" +gdb_test "backtrace" "#0 bar.*#1 .*main.*" "backtrace from bar (1)" +gdb_test "info frame" ".*called by frame.*" "bar not inlined" + +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" +gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ + "backtrace from bar (2)" +gdb_test "up" "#1 .*func1.*" "up from bar (2)" +gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" + +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (3)" +gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ + "backtrace from bar (3)" +gdb_test "up" "#1 .*func1.*" "up from bar (3)" +gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (3)" +gdb_test "up" "#2 .*func2.*" "up from func1 (3)" +gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (3)" diff --git a/gdb/testsuite/gdb.opt/inline-cmds.c b/gdb/testsuite/gdb.opt/inline-cmds.c new file mode 100644 index 0000000..b58fe92 --- /dev/null +++ b/gdb/testsuite/gdb.opt/inline-cmds.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2008 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 <http://www.gnu.org/licenses/>. */ + +int x, y; +volatile int result; + +void bar(void); +void marker(void); +void noinline(void); + +inline int func1(void) +{ + bar (); + return x * y; +} + +inline int func2(void) +{ + return x * func1 (); +} + +inline void func3(void) +{ + bar (); +} + +inline void outer_inline1(void) +{ + noinline (); +} + +inline void outer_inline2(void) +{ + outer_inline1 (); +} + +int main (void) +{ /* start of main */ + int val; + + x = 7; + y = 8; + + result = func1 (); + result = func2 (); + marker (); + + result = 0; + result = 0; /* set breakpoint 3 here */ + + func1 (); /* first call */ + func1 (); /* second call */ + marker (); + + result = 0; + result = 0; /* set breakpoint 4 here */ + + func1 (); + func3 (); + marker (); + + result = 0; + result = 0; /* set breakpoint 5 here */ + + marker (); + func1 (); + func3 (); + marker (); /* set breakpoint 6 here */ + + outer_inline2 (); + + return 0; +} diff --git a/gdb/testsuite/gdb.opt/inline-cmds.exp b/gdb/testsuite/gdb.opt/inline-cmds.exp new file mode 100644 index 0000000..43c87e5 --- /dev/null +++ b/gdb/testsuite/gdb.opt/inline-cmds.exp @@ -0,0 +1,308 @@ +# Copyright 2008 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 <http://www.gnu.org/licenses/>. + +set testfile "inline-cmds" +set srcfile "${testfile}.c" +set srcfile2 "inline-markers.c" +set fullsrcfile "${srcdir}/${subdir}/${srcfile}" +set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}" +set sources [list ${fullsrcfile} ${fullsrcfile2}] +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile $sources ${binfile} \ + executable {debug optimize=-O2}] != "" } { + untested inline-cmds.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test "set listsize 1" "" + +runto_main + +get_compiler_info $binfile +get_debug_format +if { [skip_inline_frame_tests] } { + untested inline-cmds.exp + return +} + +# First, check that the things we expected to be inlined really were, +# and those that shouldn't be weren't. +set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile2}] +gdb_breakpoint $srcfile2:$line1 +set line2 [gdb_get_line_number "set breakpoint 2 here" ${srcfile2}] +gdb_breakpoint $srcfile2:$line2 + +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" +gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ + "backtrace from bar (1)" +gdb_test "up" "#1 .*func1.*" "up from bar (1)" +gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (1)" + +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" +gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ + "backtrace from bar (2)" +gdb_test "up" "#1 .*func1.*" "up from bar (2)" +gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" +gdb_test "up" "#2 .*func2.*" "up from func1 (2)" +gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (2)" + +gdb_test "continue" ".*set breakpoint 2 here.*" "continue to marker" +gdb_test "backtrace" "#0 marker.*#1 .*main.*" "backtrace from marker" +gdb_test "info frame" ".*called by frame.*" "marker not inlined" + +# Next, check that we can next over inlined functions. We should not end up +# inside any of them. +delete_breakpoints +runto_main + +# The lines before the first inlined call. +set first "x = 7|y = 8" + +# Some extra lines that end up in our stepping due to code motion. +set opt "start of main|result = 0" + +# We start this test with a "list" instead of a "next", in case the +# first non-prologue instruction in main comes from the inlined function. +set msg "next over inlined functions" +gdb_test_multiple "list" $msg { + -re "($first|result = func1|result = func2|$opt).*$gdb_prompt $" { + send_gdb "next\r" + exp_continue + } + -re "marker \\\(\\\);\r\n$gdb_prompt $" { + pass $msg + } +} + +# Check that when next shows the call of func1, it has not happened yet. +runto_main + +# Like the return value of gdb_test: -1 something is wrong, 0 passed, 1 failed. +set bt_test -1 +set x_test -1 +set func1_step -1 + +set last_was_func1_call 0 +set msg "next past inlined func1" +gdb_test_multiple "list" $msg { + -re "($first|$opt).*$gdb_prompt $" { + set last_was_func1_call 0 + send_gdb "next\r" + exp_continue + } + -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" { + # Check whether x has been set. If 0, we may be doing something + # else associated with this line besides the inlined call - e.g. + # loading the address of result. If 7, we may be at the call site. + # If 15, though, we might be past the call and back at the store to + # result - that's OK, as long as we weren't just here (see + # func1_step above). + set x_val -1 + gdb_test_multiple "print x" "" { + -re "\\\$$decimal = (\[0-9\]*)\r\n$gdb_prompt $" { + set x_val $expect_out(1,string) + } + -re "$gdb_prompt $" { } + } + if { $x_val == 0 || $x_val == 7 } { + if { $x_test != 1 } { + set x_test 0 + } + } elseif { $x_val == 15 } { + if { $func1_step == -1 } { + # We passed func1 without stopping at the call site. + set x_test 1 + } + } else { + set x_test 1 + } + + # func1 should not show up on backtraces if we are at its call + # site. + if { $bt_test != 1 } { + set bt_test [gdb_test "backtrace" "#0 \[^#]*main.*" ""] + } + + # When we next over func1, we should not return to the same + # line. But we might go past the line, according to source + # code order, and then come back. A valid but odd layout is + # body of func1, load result's address into a register using + # the source location of "result = 0" several lines down, and + # then return to this line for the store. GCC 4.3 does that + # on ARM. + if { $last_was_func1_call } { + set func1_step 1 + } elseif { $func1_step == -1 } { + set func1_step 0 + } + set last_was_func1_call 1 + + send_gdb "next\r" + exp_continue + } + + -re "result = func2 \\\(\\\);\r\n$gdb_prompt $" { + pass $msg + } +} + +if { $x_test == 0 } { + pass "print x before func1" +} else { + fail "print x before func1" +} + +if { $bt_test == 0 } { + pass "backtrace does not include func1" +} else { + fail "backtrace does not include func1" +} + +if { $bt_test == 0 } { + pass "stepped over call to func1" +} else { + fail "stepped over call to func1" +} + +# Next, check that we can single step into inlined functions. We should always +# "stop" at the call sites before entering them. +runto_main + +set msg "step into func1" +set saw_call_site 0 +gdb_test_multiple "list" $msg { + -re "($first|$opt).*$gdb_prompt $" { + send_gdb "step\r" + exp_continue + } + -re "result = func1.*$gdb_prompt $" { + set saw_call_site 1 + send_gdb "step\r" + exp_continue + } + -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" { + if { $saw_call_site } { + pass $msg + } else { + fail $msg + } + } +} + +# Check finish out of an inlined function. +set msg "finish from func1" +gdb_test_multiple "finish" $msg { + -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" { + pass $msg + } + -re "($first|$opt).*$gdb_prompt $" { + # Whoops. We finished, but ended up back at an earlier line. Keep + # trying. + send_gdb "step\r" + exp_continue + } + -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" { + send_gdb "finish\r" + exp_continue + } +} + +# Test some corner cases involving consecutive inlined functions. +set line3 [gdb_get_line_number "set breakpoint 3 here"] +gdb_breakpoint $line3 +gdb_continue_to_breakpoint "consecutive func1" + +gdb_test "next" ".*func1 .*first call.*" "next to first func1" +set msg "next to second func1" +gdb_test_multiple "next" $msg { + -re ".*func1 .*second call.*$gdb_prompt $" { + pass $msg + } + -re ".*marker .*$gdb_prompt $" { + # This assembles to two consecutive call instructions. + # Both appear to be at the same line, because they're + # in the body of the same inlined function. This is + # reasonable for the line table. GDB should take the + # containing block and/or function into account when + # deciding how far to step. The single line table entry + # is actually two consecutive instances of the same line. + kfail gdb/NNNN $msg + } +} + +# It is easier when the two inlined functions are not on the same line. +set line4 [gdb_get_line_number "set breakpoint 4 here"] +gdb_breakpoint $line4 +gdb_continue_to_breakpoint "func1 then func3" + +gdb_test "next" ".*func1 \\\(\\\);" "next to func1 before func3" +gdb_test "next" ".*func3 \\\(\\\);" "next to func3" + +# Test finishing out of one thing and into another. +set line5 [gdb_get_line_number "set breakpoint 5 here"] +gdb_breakpoint $line5 +gdb_continue_to_breakpoint "finish into func1" + +gdb_test "next" ".*marker \\\(\\\);" "next to finish marker" +gdb_test "step" ".*set breakpoint 2 here.*" "step into finish marker" +gdb_test "finish" "func1 \\\(\\\);" "finish from marker to func1" + +gdb_test "step" "bar \\\(\\\);" "step into func1 for finish" +gdb_test "finish" "func3 \\\(\\\);" "finish from func1 to func3" + +# Test a deeper call stack. +set line6 [gdb_get_line_number "set breakpoint 6 here"] +gdb_breakpoint $line6 +gdb_continue_to_breakpoint "before the outer_inline call" +gdb_test "step" "marker \\\(\\\) at .*" "reach 1 the outer_inline call" +gdb_test "finish" "main \\\(\\\) at .*outer_inline2 \\\(\\\);" "reach outer_inline2" +gdb_test "bt" "#0 main.*" "backtrace at main of outer_inline" +gdb_test "step" "outer_inline2 \\\(\\\) at .*" "enter outer_inline2" +gdb_test "bt" "#0 outer_inline2.*#1 main.*" "backtrace at outer_inline2" +gdb_test "step" "outer_inline1 \\\(\\\) at .*" "enter outer_inline1 from outer_inline2" + +set msg "backtrace at outer_inline1" +gdb_test_multiple "bt" $msg { + -re "#0 outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" { + pass $msg + } + -re "#0 $hex in outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" { + # Binutils PR gas/6717. Gas moves .loc past .p2align and the + # leading nop of the inlined call appears to be on the same line + # as main's call to marker. + xfail $msg + gdb_test "step" "noinline \\\(\\\);" "step to call of noinline" + } +} + +gdb_test "step" "noinline \\\(\\\) at .*" "enter noinline from outer_inline1" +gdb_test "bt" "#0 noinline.*#1 .*outer_inline1.*#2 .*outer_inline2.*#3 main.*" "backtrace at noinline from outer_inline1" +gdb_test "step" "inlined_fn \\\(\\\) at .*" "enter inlined_fn from noinline" +gdb_test "bt" "#0 inlined_fn.*#1 noinline.*#2 .*outer_inline1.*#3 .*outer_inline2.*#4 main.*" "backtrace at inlined_fn from noinline" +gdb_test "info frame" ".*inlined into frame.*" "inlined_fn from noinline inlined" +gdb_test "up" "#1 noinline.*" "up to noinline" +gdb_test "info frame" ".*\n called by frame.*" "noinline from outer_inline1 not inlined" +gdb_test "up" "#2 .*outer_inline1.*" "up to outer_inline1" +gdb_test "info frame" ".*inlined into frame.*" "outer_inline1 inlined" +gdb_test "up" "#3 .*outer_inline2.*" "up to outer_inline2" +gdb_test "info frame" ".*inlined into frame.*" "outer_inline2 inlined" +gdb_test "up" "#4 main.*" "up from outer_inline2" +gdb_test "info frame" ".*\n caller of frame.*" "main not inlined" diff --git a/gdb/testsuite/gdb.opt/inline-locals.c b/gdb/testsuite/gdb.opt/inline-locals.c new file mode 100644 index 0000000..0b0ec62 --- /dev/null +++ b/gdb/testsuite/gdb.opt/inline-locals.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2008 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 <http://www.gnu.org/licenses/>. */ + +int x, y; +volatile int result; +volatile int *array_p; + +void bar(void); + +inline int func1(int arg1) +{ + int array[64]; + array_p = array; + array[0] = result; + array[1] = arg1; + bar (); + return x * y + array_p[0] * arg1; +} + +inline int func2(int arg2) +{ + return x * func1 (arg2); +} + +int main (void) +{ + int val; + + x = 7; + y = 8; + bar (); + + val = func1 (result); + result = val; + + val = func2 (result); + result = val; + + return 0; +} diff --git a/gdb/testsuite/gdb.opt/inline-locals.exp b/gdb/testsuite/gdb.opt/inline-locals.exp new file mode 100644 index 0000000..cdc180a --- /dev/null +++ b/gdb/testsuite/gdb.opt/inline-locals.exp @@ -0,0 +1,138 @@ +# Copyright 2008 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 <http://www.gnu.org/licenses/>. + +set testfile "inline-locals" +set srcfile ${testfile}.c +set srcfile2 "inline-markers.c" +set fullsrcfile "${srcdir}/${subdir}/${srcfile}" +set fullsrcfile2 "${srcdir}/${subdir}/${srcfile2}" +set sources [list ${fullsrcfile} ${fullsrcfile2}] +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile ${sources} ${binfile} \ + executable {debug optimize=-O2}] != "" } { + untested inline-locals.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +runto_main + +get_compiler_info $binfile +get_debug_format +if { [skip_inline_var_tests] } { + untested inline-bt.exp + return +} + +set no_frames [skip_inline_frame_tests] + +set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile2}] +gdb_breakpoint $srcfile2:$line1 + +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" + +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" + +if { ! $no_frames } { + gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ + "backtrace from bar (2)" + gdb_test "up" "#1 .*func1 .* at .*" "up from bar (2)" + gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" + gdb_test "info locals" "array = {.*}" "info locals above bar (2)" + + set msg "info args above bar (2)" + gdb_test_multiple "info args" $msg { + -re "arg1 = $decimal\r\n$gdb_prompt $" { + pass $msg + } + -re "arg1 = <value optimized out>\r\narg1 = <value optimized out>\r\n$gdb_prompt $" { + # GCC 4.4 loses location information for arg1 (like GCC + # 4.3) and also generates a strange DIE tree that causes + # us to display the argument twice: inlined func1 has the + # abstract func1 for DW_AT_abstract_origin but its arg1 + # child has the out of line func1's arg1 for + # DW_AT_abstract_origin, with a location list unrelated to + # the inlined instance. + if { [test_compiler_info "gcc-4-4-*"] || [test_compiler_info "gcc-4-5-*"] } { + setup_xfail *-*-* gcc/40573 + } + fail $msg + } + -re "arg1 = <value optimized out>\r\n$gdb_prompt $" { + # GCC 4.3 loses location information for arg1. GCC 4.2 is OK. + if { [test_compiler_info "gcc-4-3-*"] } { + setup_xfail *-*-* + } + fail $msg + } + } +} else { + gdb_test "up" "#1 .*main .* at .*" "up from bar (2)" + gdb_test "info locals" ".*arg1 = 0.*" "info locals above bar (2)" +} + +# Make sure that locals on the stack are found. This is an array to +# prevent it from living in a register. +gdb_test "print array\[0\]" "\\\$$decimal = 0" "print local (2)" + +if { ! $no_frames } { + # Verify that we do not print out variables from the inlined + # function's caller. + gdb_test "print val" "No symbol \"val\" in current context\\." \ + "print out of scope local" +} + +# Repeat the tests from a depth of two inlined functions, and with a +# more interesting value in the local array. +gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (3)" +if { ! $no_frames } { + gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ + "backtrace from bar (3)" + gdb_test "up" "#1 .*func1 .* at .*" "up from bar (3)" + gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (3)" + gdb_test "info locals" "array = {.*}" "info locals above bar (3)" + + set msg "info args above bar (3)" + gdb_test_multiple "info args" $msg { + -re "arg1 = $decimal\r\n$gdb_prompt $" { + pass $msg + } + -re "arg1 = <value optimized out>\r\narg1 = <value optimized out>\r\n$gdb_prompt $" { + # See the similar GCC 4.4 XFAIL above for an explanation. + if { [test_compiler_info "gcc-4-4-*"] || [test_compiler_info "gcc-4-5-*"] } { + setup_xfail *-*-* gcc/40573 + } + fail $msg + } + -re "arg1 = <value optimized out>\r\n$gdb_prompt $" { + # GCC 4.3 loses location information for arg1. GCC 4.2 is OK. + if { [test_compiler_info "gcc-4-3-*"] } { + setup_xfail *-*-* + } + fail $msg + } + } +} else { + gdb_test "up" "#1 .*main .* at .*" "up from bar (3)" + gdb_test "info locals" ".*arg1 = 1.*" "info locals above bar (3a)" + gdb_test "info locals" ".*arg2 = 184.*" "info locals above bar (3b)" +} + +gdb_test "print array\[0\]" "\\\$$decimal = 184" "print local (3)" diff --git a/gdb/testsuite/gdb.opt/inline-markers.c b/gdb/testsuite/gdb.opt/inline-markers.c new file mode 100644 index 0000000..330e242 --- /dev/null +++ b/gdb/testsuite/gdb.opt/inline-markers.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2008 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 <http://www.gnu.org/licenses/>. */ + +extern int x, y; + +void bar(void) +{ + x += y; /* set breakpoint 1 here */ +} + +void marker(void) +{ + x += y; /* set breakpoint 2 here */ +} + +inline void inlined_fn(void) +{ + x += y; +} + +void noinline(void) +{ + inlined_fn (); /* inlined */ +} diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index b20d035..200ab35 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1459,6 +1459,37 @@ proc skip_hp_tests {} { return $skip_hp } +# Return whether we should skip tests for showing inlined functions in +# backtraces. Requires get_compiler_info and get_debug_format. + +proc skip_inline_frame_tests {} { + # GDB only recognizes inlining information in DWARF 2 (DWARF 3). + if { ! [test_debug_format "DWARF 2"] } { + return 1 + } + + # GCC before 4.1 does not emit DW_AT_call_file / DW_AT_call_line. + if { ([test_compiler_info "gcc-2-*"] + || [test_compiler_info "gcc-3-*"] + || [test_compiler_info "gcc-4-0-*"]) } { + return 1 + } + + return 0 +} + +# Return whether we should skip tests for showing variables from +# inlined functions. Requires get_compiler_info and get_debug_format. + +proc skip_inline_var_tests {} { + # GDB only recognizes inlining information in DWARF 2 (DWARF 3). + if { ! [test_debug_format "DWARF 2"] } { + return 1 + } + + return 0 +} + set compiler_info "unknown" set gcc_compiled 0 set hp_cc_compiler 0 |