@@ -196,7 +196,20 @@ blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section,
return NULL;
if (pblock)
- *pblock = b;
+ {
+ struct symtab_and_line sal = find_pc_sect_line (pc, section, 0);
+ if (sal.line != 0 && sal.pc == pc && sal.is_weak)
+ {
+ const struct block *b2 = find_block_in_blockvector (bl, pc - 1);
+ const struct block *b0 = b;
+ while (b0->superblock () && !b0->function ())
+ b0 = b0->superblock ();
+ if (b0->contains (b2))
+ b = b2;
+ }
+ *pblock = b;
+ }
+
return bl;
}
@@ -10763,10 +10763,6 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
return false;
}
- /* Empty range entries have no effect. */
- if (range_beginning == range_end)
- continue;
-
/* Only DW_RLE_offset_pair needs the base address added. */
if (rlet == DW_RLE_offset_pair)
{
@@ -10885,10 +10881,6 @@ dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu, dwarf_tag tag,
return 0;
}
- /* Empty range entries have no effect. */
- if (range_beginning == range_end)
- continue;
-
range_beginning = (unrelocated_addr) ((CORE_ADDR) range_beginning
+ (CORE_ADDR) *base);
range_end = (unrelocated_addr) ((CORE_ADDR) range_end
@@ -11110,8 +11102,7 @@ dwarf2_get_pc_bounds (struct die_info *die, unrelocated_addr *lowpc,
if (ret == PC_BOUNDS_NOT_PRESENT || ret == PC_BOUNDS_INVALID)
return ret;
- /* partial_die_info::read has also the strict LOW < HIGH requirement. */
- if (high <= low)
+ if (low > high || (low == high && die->tag != DW_TAG_inlined_subroutine))
return PC_BOUNDS_INVALID;
/* When using the GNU linker, .gnu.linkonce. sections are used to
@@ -18062,21 +18053,9 @@ class lnp_state_machine
/* Additional bits of state we need to track. */
- /* The last file that we called dwarf2_start_subfile for.
- This is only used for TLLs. */
- unsigned int m_last_file = 0;
/* The last file a line number was recorded for. */
struct subfile *m_last_subfile = NULL;
- /* The address of the last line entry. */
- unrelocated_addr m_last_address;
-
- /* Set to true when a previous line at the same address (using
- m_last_address) had LEF_IS_STMT set in m_flags. This is reset to false
- when a line entry at a new address (m_address different to
- m_last_address) is processed. */
- bool m_stmt_at_address = false;
-
/* When true, record the lines we decode. */
bool m_currently_recording_lines = true;
@@ -18234,7 +18213,8 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
static void
dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
- unrelocated_addr address, struct dwarf2_cu *cu)
+ unrelocated_addr address, struct dwarf2_cu *cu,
+ bool end_sequence)
{
if (subfile == NULL)
return;
@@ -18247,7 +18227,8 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
paddress (gdbarch, (CORE_ADDR) address));
}
- dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu);
+ dwarf_record_line_1 (gdbarch, subfile, end_sequence ? 0 : -1, address,
+ LEF_IS_STMT, cu);
}
void
@@ -18275,38 +18256,17 @@ lnp_state_machine::record_line (bool end_sequence)
/* For now we ignore lines not starting on an instruction boundary.
But not when processing end_sequence for compatibility with the
previous version of the code. */
- else if (m_op_index == 0 || end_sequence)
- {
- /* When we switch files we insert an end maker in the first file,
- switch to the second file and add a new line entry. The
- problem is that the end marker inserted in the first file will
- discard any previous line entries at the same address. If the
- line entries in the first file are marked as is-stmt, while
- the new line in the second file is non-stmt, then this means
- the end marker will discard is-stmt lines so we can have a
- non-stmt line. This means that there are less addresses at
- which the user can insert a breakpoint.
-
- To improve this we track the last address in m_last_address,
- and whether we have seen an is-stmt at this address. Then
- when switching files, if we have seen a stmt at the current
- address, and we are switching to create a non-stmt line, then
- discard the new line. */
- bool file_changed
- = m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
- bool ignore_this_line
- = ((file_changed && !end_sequence && m_last_address == m_address
- && ((m_flags & LEF_IS_STMT) == 0)
- && m_stmt_at_address)
- || (!end_sequence && m_line == 0));
-
- if ((file_changed && !ignore_this_line) || end_sequence)
+ else if ((m_op_index == 0 && m_line != 0) || end_sequence)
+ {
+ if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
+ || end_sequence)
{
dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
- m_currently_recording_lines ? m_cu : nullptr);
+ m_currently_recording_lines ? m_cu : nullptr,
+ end_sequence || (m_flags & LEF_IS_STMT) != 0);
}
- if (!end_sequence && !ignore_this_line)
+ if (!end_sequence)
{
linetable_entry_flags lte_flags = m_flags;
if (producer_is_codewarrior (m_cu))
@@ -18326,15 +18286,6 @@ lnp_state_machine::record_line (bool end_sequence)
m_last_line = m_line;
}
}
-
- /* Track whether we have seen any IS_STMT true at m_address in case we
- have multiple line table entries all at m_address. */
- if (m_last_address != m_address)
- {
- m_stmt_at_address = false;
- m_last_address = m_address;
- }
- m_stmt_at_address |= (m_flags & LEF_IS_STMT) != 0;
}
lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
@@ -18348,8 +18299,7 @@ lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
This is currently used by MIPS code,
cf. `mips_adjust_dwarf2_line'. */
m_address ((unrelocated_addr) gdbarch_adjust_dwarf2_line (arch, 0, 0)),
- m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0),
- m_last_address (m_address)
+ m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0)
{
}
@@ -996,7 +996,8 @@ prepare_one_step (thread_info *tp, struct step_command_fsm *sm)
if (sym->aclass () == LOC_BLOCK)
{
const block *block = sym->value_block ();
- if (block->end () < tp->control.step_range_end)
+ if (block->end () < tp->control.step_range_end
+ && block->end () > tp->control.step_range_start)
tp->control.step_range_end = block->end ();
}
}
@@ -8114,6 +8114,34 @@ process_event_stop_test (struct execution_control_state *ecs)
return;
}
+ /* Handle the case when subroutines have multiple ranges.
+ When we step from one part to the next part of the same subroutine,
+ all subroutine levels are skipped again which begin here.
+ Compensate for this by removing all skipped subroutines,
+ which were already executing from the user's perspective. */
+
+ if (get_stack_frame_id (frame)
+ == ecs->event_thread->control.step_stack_frame_id
+ && inline_skipped_frames (ecs->event_thread)
+ && ecs->event_thread->control.step_frame_id.artificial_depth > 0
+ && ecs->event_thread->control.step_frame_id.code_addr_p)
+ {
+ const struct block *prev, *curr;
+ int depth = 0;
+ prev = block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
+ curr = block_for_pc (ecs->event_thread->stop_pc ());
+ while (curr != nullptr && !curr->contains (prev))
+ {
+ if (curr->inlined_p ())
+ depth ++;
+ else if (curr->function () != nullptr)
+ break;
+ curr = curr->superblock ();
+ }
+ while (inline_skipped_frames (ecs->event_thread) > depth)
+ step_into_inline_frame (ecs->event_thread);
+ }
+
/* 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. */
@@ -8172,6 +8200,8 @@ process_event_stop_test (struct execution_control_state *ecs)
infrun_debug_printf ("stepping through inlined function");
if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
+ || ecs->event_thread->stop_pc () != stop_pc_sal.pc
+ || !stop_pc_sal.is_stmt
|| inline_frame_is_marked_for_skip (false, ecs->event_thread))
keep_going (ecs);
else
@@ -8220,7 +8250,8 @@ process_event_stop_test (struct execution_control_state *ecs)
end_stepping_range (ecs);
return;
}
- else if (*curr_frame_id == original_frame_id)
+ else if (get_stack_frame_id (frame)
+ == ecs->event_thread->control.step_stack_frame_id)
{
/* We are not at the start of a statement, and we have not changed
frame.
@@ -3290,7 +3290,10 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
0) instead of a real line. */
if (prev && prev->line
- && (!best || prev->unrelocated_pc () > best->unrelocated_pc ()))
+ && (!best || prev->unrelocated_pc () > best->unrelocated_pc ()
+ || (prev->unrelocated_pc () == best->unrelocated_pc ()
+ && (best->pc (objfile) == pc
+ ? !best->is_stmt : best->is_weak))))
{
best = prev;
best_symtab = iter_s;
@@ -3309,7 +3312,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
&& (tmp - 1)->unrelocated_pc () == tmp->unrelocated_pc ()
&& (tmp - 1)->line != 0 && !tmp->is_stmt)
--tmp;
- if (tmp->is_stmt)
+ if (tmp->is_stmt && (tmp->pc (objfile) == pc || !tmp->is_weak))
best = tmp;
}
@@ -3333,18 +3336,14 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
We used to return alt->line - 1 here, but that could be
anywhere; if we don't have line number info for this PC,
don't make some up. */
- val.pc = pc;
- }
- else if (best->line == 0)
- {
- /* If our best fit is in a range of PC's for which no line
- number info is available (line number is zero) then we didn't
- find any valid line information. */
+ if (notcurrent)
+ pc++;
val.pc = pc;
}
else
{
val.is_stmt = best->is_stmt;
+ val.is_weak = best->is_weak;
val.symtab = best_symtab;
val.line = best->line;
val.pc = best->pc (objfile);
new file mode 100644
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2024 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/>. */
+
+static int test0 (void)
+{
+ asm (""); /* line 20 */
+ return 1; /* line 21 */
+}
+
+int __attribute__((noinline, noclone))
+#ifdef __CET__
+ __attribute__((nocf_check))
+#endif
+test1 (int x)
+{
+ asm ("");
+ return x+1; /* line 31 */
+}
+
+int
+main()
+{ test1 (test0 ()); /* line 36 */
+ test1 (test0 ()); /* line 37 */
+ return 0; /* line 38 */
+}
new file mode 100644
@@ -0,0 +1,51 @@
+# Copyright 2024 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/>.
+
+standard_testfile .c
+
+if { ![test_compiler_info gcc*] || ![supports_statement_frontiers] } {
+ untested "this test needs gcc with statement frontiers"
+ return -1
+}
+
+global srcfile testfile
+
+set options {debug nowarnings optimize=-O2}
+lappend options additional_flags=-gstatement-frontiers
+
+if { [prepare_for_testing "failed to prepare" $binfile \
+ $srcfile $options] } {
+ return -1
+}
+
+if ![runto_main] {
+ return
+}
+
+gdb_test "frame 0" "\\s*\\#0\\s+main.*${srcfile}:36.*" "in main"
+gdb_test_multiple "step" "step into test0" {
+ -re ".*test0.*${srcfile}:20.*$::gdb_prompt $" {
+ gdb_test "step" ".*line 21.*" $gdb_test_name
+ }
+ -re ".*test0.*${srcfile}:21.*$::gdb_prompt $" {
+ pass $gdb_test_name
+ }
+}
+gdb_test "frame 1" "\\s*\\#1\\s+main.*${srcfile}:36.*" "frame1"
+gdb_test "step" ".*test1.*${srcfile}:31.*" "step into test1"
+gdb_test "frame 1" "\\s*\\#1.*in main.*${srcfile}:36.*" "frame2"
+gdb_test "step" ".*main.*${srcfile}:37.*" "step back to main"
+gdb_test "next" ".*return 0;.*" "step over test0+1"
+gdb_test "frame 0" "\\s*\\#0\\s+main.*${srcfile}:38.*" "in main again"
new file mode 100644
@@ -0,0 +1,33 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2024 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/>. */
+
+/* PR 25987 */
+struct MyClass;
+struct ptr {
+ MyClass* get() { return t; } /* line 21 */
+ MyClass* t;
+};
+struct MyClass { void call(); };
+void MyClass::call() {
+ *(volatile char*)-1 = 1; /* line 26 */
+}
+static void intermediate(ptr p) {
+ p.get()->call(); /* line 29 */
+}
+int main() {
+ intermediate(ptr{new MyClass});
+}
new file mode 100644
@@ -0,0 +1,51 @@
+# Copyright 2024 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/>.
+
+# PR 25987
+standard_testfile .cc
+
+if { ![test_compiler_info gcc*] || ![supports_statement_frontiers] } {
+ untested "this test needs gcc with statement frontiers"
+ return -1
+}
+
+set options {c++ debug nowarnings optimize=-Og}
+lappend options additional_flags=-gstatement-frontiers
+if { [prepare_for_testing "failed to prepare" $testfile \
+ $srcfile $options] } {
+ return -1
+}
+
+if ![runto_main] {
+ return
+}
+
+gdb_test "bt" "\\s*\\#0\\s+main.*" "in main"
+#break at the empty inline function ptr::get
+gdb_test "b get" ".*" "break at get"
+gdb_test "c" ".*" "continue to get"
+#call frame 1 is at line 29
+gdb_test "bt" [multi_line "\\s*\\#0\\s+ptr::get\[^\r\]*${srcfile}:21" \
+ "\\s*\\#1\\s+intermediate\[^\r\]*${srcfile}:29" \
+ ".*"] \
+ "at get"
+#print a local value here
+gdb_test "p t" ".*(\\\$1 = \\(MyClass \\*\\) 0x|value has been optimized out).*" "print t"
+gdb_test "c" ".*SIGSEGV.*" "continue to SIGSEGV"
+#call frame 1 is at line 29
+gdb_test "bt" [multi_line "\\s*\\#0\\s+\[^\r\]*MyClass::call\[^\r\]*${srcfile}:26" \
+ "\\s*\\#1\\s+0x\[^\r\]*intermediate\[^\r\]*${srcfile}:29" \
+ ".*"] \
+ "at call"
@@ -47,8 +47,7 @@ tree_check (tree *t, int i)
int __attribute__((noinline, noclone))
get_alias_set (tree *t)
-{
- if (t != NULL
+{ if (t != NULL
&& TREE_TYPE (t).z != 1
&& TREE_TYPE (t).z != 2
&& TREE_TYPE (t).z != 3)
@@ -60,7 +59,6 @@ tree xx;
int
main()
-{
- get_alias_set (&xx); /* Beginning of main */
+{ get_alias_set (&xx);
return 0;
} // main
@@ -15,7 +15,8 @@
standard_testfile .cc
-if {[test_compiler_info gcc*] && ![supports_statement_frontiers] } {
+if { ![test_compiler_info gcc*] || ![supports_statement_frontiers] } {
+ untested "this test needs gcc with statement frontiers"
return -1
}
@@ -24,17 +25,8 @@ if {[test_compiler_info gcc*] && ![supports_statement_frontiers] } {
proc do_test { use_header } {
global srcfile testfile
- if { $use_header } {
- # This test will not pass due to poor debug information
- # generated by GCC (at least upto 10.x). See
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474
- return
- }
-
set options {c++ debug nowarnings optimize=-O2}
- if { [supports_statement_frontiers] } {
- lappend options additional_flags=-gstatement-frontiers
- }
+ lappend options additional_flags=-gstatement-frontiers
if { $use_header } {
lappend options additional_flags=-DUSE_NEXT_INLINE_H
set executable "$testfile-with-header"
@@ -53,131 +45,28 @@ proc do_test { use_header } {
with_test_prefix $prefix {
- set main_location [gdb_get_line_number "Beginning of main" $srcfile]
-
- if ![runto $main_location qualified] {
+ if ![runto_main] {
return
}
gdb_test "bt" "\\s*\\#0\\s+main.*" "in main"
- set line1 {\t\{}
- set line2 {\t if \(t != NULL}
- gdb_test_multiple "step" "step into get_alias_set" {
- -re -wrap $line1 {
- gdb_test "next" $line2 $gdb_test_name
- }
- -re -wrap $line2 {
- pass $gdb_test_name
- }
- }
+ gdb_test "step" ".*" "step into get_alias_set"
gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
"not in inline 1"
-
- # It's possible that this first failure (when not using a header
- # file) is GCC's fault, though the remaining failures would best
- # be fixed by adding location views support (though it could be
- # that some easier heuristic could be figured out). Still, it is
- # not certain that the first failure wouldn't also be fixed by
- # having location view support, so for now it is tagged as such.
- set have_kfail [expr [test_compiler_info gcc*] && !$use_header]
-
- set ok 1
- gdb_test_multiple "next" "next step 1" {
- -re -wrap "if \\(t->x != i\\)" {
- set ok 0
- send_gdb "next\n"
- exp_continue
- }
- -re -wrap ".*TREE_TYPE.* != 1" {
- if { $ok } {
- pass $gdb_test_name
- } else {
- if { $have_kfail } {
- setup_kfail "*-*-*" symtab/25507
- }
- fail $gdb_test_name
- }
- }
- }
+ gdb_test "next" ".*TREE_TYPE.*" "next step 1"
gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
"not in inline 2"
-
- set ok 1
- gdb_test_multiple "next" "next step 2" {
- -re -wrap "return x;" {
- set ok 0
- send_gdb "next\n"
- exp_continue
- }
- -re -wrap ".*TREE_TYPE.* != 2" {
- if { $ok } {
- pass $gdb_test_name
- } else {
- if { $have_kfail } {
- setup_kfail "*-*-*" symtab/25507
- }
- fail $gdb_test_name
- }
- }
- }
+ gdb_test "next" ".*TREE_TYPE.*" "next step 2"
gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
"not in inline 3"
-
- set ok 1
- gdb_test_multiple "next" "next step 3" {
- -re -wrap "return x;" {
- set ok 0
- send_gdb "next\n"
- exp_continue
- }
- -re -wrap ".*TREE_TYPE.* != 3\\)" {
- if { $ok } {
- pass $gdb_test_name
- } else {
- if { $have_kfail } {
- setup_kfail "*-*-*" symtab/25507
- }
- fail $gdb_test_name
- }
- }
- }
+ gdb_test "next" ".*TREE_TYPE.*" "next step 3"
gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
"not in inline 4"
-
- set ok 1
- gdb_test_multiple "next" "next step 4" {
- -re -wrap "(if \\(t != NULL|\} // get_alias_set)" {
- send_gdb "next\n"
- exp_continue
- }
- -re -wrap "return x;" {
- set ok 0
- send_gdb "next\n"
- exp_continue
- }
- -re -wrap "return 0.*" {
- if { $ok } {
- pass $gdb_test_name
- } else {
- if { $have_kfail } {
- setup_kfail "*-*-*" symtab/25507
- }
- fail $gdb_test_name
- }
- }
- }
+ gdb_test "next" "return 0.*" "next step 4"
gdb_test "bt" \
"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
"not in inline 5"
- if {!$use_header} {
- # With the debug from GCC 10.x (and earlier) GDB is currently
- # unable to successfully complete the following tests when we
- # are not using a header file.
- kfail symtab/25507 "stepping tests"
- return
- }
-
clean_restart ${executable}
if ![runto_main] {
@@ -194,22 +83,84 @@ proc do_test { use_header } {
gdb_test "step" ".*if \\(t->x != i\\).*" "step 2"
gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
"in inline 1 pass 2"
- gdb_test "step" ".*TREE_TYPE.*" "step 3"
+ gdb_test "step" ".*return x.*" "step 3"
+ gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+ "return from inline 1 pass 2"
+ gdb_test "step" ".*TREE_TYPE.*" "step 4"
gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
"not in inline 2 pass 2"
- gdb_test "step" ".*if \\(t->x != i\\).*" "step 4"
+ gdb_test "step" ".*if \\(t->x != i\\).*" "step 5"
gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
"in inline 2 pass 2"
- gdb_test "step" ".*TREE_TYPE.*" "step 5"
+ gdb_test "step" ".*return x.*" "step 6"
+ gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+ "return from inline 2 pass 2"
+ gdb_test "step" ".*TREE_TYPE.*" "step 7"
gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
"not in inline 3 pass 2"
- gdb_test "step" ".*if \\(t->x != i\\).*" "step 6"
+ gdb_test "step" ".*if \\(t->x != i\\).*" "step 8"
gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
"in inline 3 pass 2"
- gdb_test "step" "return 0.*" "step 7"
+ gdb_test "step" ".*return x.*" "step 9"
+ gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+ "return from inline 3 pass 2"
+ gdb_test "step" "return 0.*" "step 10"
gdb_test "bt" \
"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
"not in inline 4 pass 2"
+
+ clean_restart ${executable}
+
+ if ![runto_main] {
+ return
+ }
+
+ gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 3"
+ gdb_test "step" ".*" "step into get_alias_set pass 3"
+ gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+ "in get_alias_set pass 3"
+ gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 3"
+ gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+ "not in inline 1 pass 3"
+ gdb_test "step" ".*if \\(t->x != i\\).*" "step 2 pass 3"
+ gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+ "in inline 1 pass 3"
+ gdb_test_multiple "p t->x = 2" "change value pass 3" {
+ -re ".*value has been optimized out.*$::gdb_prompt $" {
+ gdb_test "p xx.x = 2" ".* = 2.*" $gdb_test_name
+ }
+ -re ".* = 2.*$::gdb_prompt $" {
+ pass $gdb_test_name
+ }
+ }
+ gdb_test "step" ".*abort.*" "step 3, pass 3"
+ gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+ "abort from inline 1 pass 3"
+
+ clean_restart ${executable}
+
+ if ![runto_main] {
+ return
+ }
+
+ gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 4"
+ gdb_test "skip tree_check" ".*" "skip tree_check pass 4"
+ gdb_test "step" ".*" "step into get_alias_set pass 4"
+ gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+ "in get_alias_set pass 4"
+ gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 4"
+ gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+ "not in inline 1 pass 4"
+ gdb_test "step" ".*TREE_TYPE.*" "step 2 pass 4"
+ gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+ "not in inline 2 pass 4"
+ gdb_test "step" ".*TREE_TYPE.*" "step 3 pass 4"
+ gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+ "not in inline 3 pass 4"
+ gdb_test "step" "return 0.*" "step 4 pass 4"
+ gdb_test "bt" \
+ "\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
+ "not in inline 4 pass 4"
}
}