diff options
-rw-r--r-- | gdb/ChangeLog | 13 | ||||
-rw-r--r-- | gdb/frame.c | 9 | ||||
-rw-r--r-- | gdb/inline-frame.c | 30 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.c | 158 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.exp | 379 |
6 files changed, 579 insertions, 15 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5dd5165..855e928 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,18 @@ 2020-01-24 Andrew Burgess <andrew.burgess@embecosm.com> + * frame.c (find_frame_sal): Move call to get_next_frame into more + inner scope. + * inline-frame.c (inilne_state) <inline_state>: Update argument + types. + (inilne_state) <skipped_symbol>: Rename to... + (inilne_state) <skipped_symbols>: ...this, and change to a vector. + (skip_inline_frames): Build vector of skipped symbols and use this + to reate the inline_state. + (inline_skipped_symbol): Add a comment and some assertions, fetch + skipped symbol from the list. + +2020-01-24 Andrew Burgess <andrew.burgess@embecosm.com> + * buildsym.c (lte_is_less_than): Delete. (buildsym_compunit::end_symtab_with_blockvector): Create local lambda function to sort line table entries, and use diff --git a/gdb/frame.c b/gdb/frame.c index 9ec93eb..d74d1d5 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -2508,14 +2508,15 @@ find_frame_sal (frame_info *frame) int notcurrent; CORE_ADDR pc; - /* If the next frame represents an inlined function call, this frame's - sal is the "call site" of that inlined function, which can not - be inferred from get_frame_pc. */ - next_frame = get_next_frame (frame); if (frame_inlined_callees (frame) > 0) { struct symbol *sym; + /* If the current frame has some inlined callees, and we have a next + frame, then that frame must be an inlined frame. In this case + this frame's sal is the "call site" of the next frame's inlined + function, which can not be inferred from get_frame_pc. */ + next_frame = get_next_frame (frame); if (next_frame) sym = get_frame_function (next_frame); else diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c index 0ee1de3..c650195 100644 --- a/gdb/inline-frame.c +++ b/gdb/inline-frame.c @@ -37,9 +37,9 @@ struct inline_state { inline_state (thread_info *thread_, int skipped_frames_, CORE_ADDR saved_pc_, - symbol *skipped_symbol_) + std::vector<symbol *> &&skipped_symbols_) : thread (thread_), skipped_frames (skipped_frames_), saved_pc (saved_pc_), - skipped_symbol (skipped_symbol_) + skipped_symbols (std::move (skipped_symbols_)) {} /* The thread this data relates to. It should be a currently @@ -56,10 +56,10 @@ struct inline_state any skipped frames. */ CORE_ADDR saved_pc; - /* Only valid if SKIPPED_FRAMES is non-zero. This is the symbol - of the outermost skipped inline function. It's used to find the - call site of the current frame. */ - struct symbol *skipped_symbol; + /* Only valid if SKIPPED_FRAMES is non-zero. This is the list of all + function symbols that have been skipped, from inner most to outer + most. It is used to find the call site of the current frame. */ + std::vector<struct symbol *> skipped_symbols; }; static std::vector<inline_state> inline_states; @@ -341,7 +341,7 @@ void skip_inline_frames (thread_info *thread, bpstat stop_chain) { const struct block *frame_block, *cur_block; - struct symbol *last_sym = NULL; + std::vector<struct symbol *> skipped_syms; int skip_count = 0; /* This function is called right after reinitializing the frame @@ -369,7 +369,7 @@ skip_inline_frames (thread_info *thread, bpstat stop_chain) break; skip_count++; - last_sym = BLOCK_FUNCTION (cur_block); + skipped_syms.push_back (BLOCK_FUNCTION (cur_block)); } else break; @@ -382,7 +382,8 @@ skip_inline_frames (thread_info *thread, bpstat stop_chain) } gdb_assert (find_inline_frame_state (thread) == NULL); - inline_states.emplace_back (thread, skip_count, this_pc, last_sym); + inline_states.emplace_back (thread, skip_count, this_pc, + std::move (skipped_syms)); if (skip_count != 0) reinit_frame_cache (); @@ -421,9 +422,16 @@ struct symbol * inline_skipped_symbol (thread_info *thread) { inline_state *state = find_inline_frame_state (thread); - gdb_assert (state != NULL); - return state->skipped_symbol; + + /* This should only be called when we are skipping at least one frame, + hence SKIPPED_FRAMES will be greater than zero when we get here. + We initialise SKIPPED_FRAMES at the same time as we build + SKIPPED_SYMBOLS, hence it should be true that SKIPPED_FRAMES never + indexes outside of the SKIPPED_SYMBOLS vector. */ + gdb_assert (state->skipped_frames > 0); + gdb_assert (state->skipped_frames <= state->skipped_symbols.size ()); + return state->skipped_symbols[state->skipped_frames - 1]; } /* Return the number of functions inlined into THIS_FRAME. Some of diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 0785315..d56c26d 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2020-01-24 Andrew Burgess <andrew.burgess@embecosm.com> + * gdb.dwarf2/dw2-inline-many-frames.c: New file. + * gdb.dwarf2/dw2-inline-many-frames.exp: New file. + +2020-01-24 Andrew Burgess <andrew.burgess@embecosm.com> + * gdb.dwarf2/dw2-inline-stepping.c: New file. * gdb.dwarf2/dw2-inline-stepping.exp: New file. diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.c new file mode 100644 index 0000000..37905c1 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.c @@ -0,0 +1,158 @@ +/* Copyright 2019-2020 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/>. */ + +/* This test sets up a call stack that looks like this: + + #11 #10 #9 #8 #7 #6 #5 #4 #3 #2 #1 #0 + main -> aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg -> hhh -> iii -> jjj -> kkk + \_______________________/ \________/ \______________________/ \________/ + Inline sequence #1 Normal Inline sequence #2 Normal + + We use the 'start' command to move into main, after that we 'step' + through each function until we are in kkk. We then use the 'up' command + to look back at each from to main. + + The test checks that we can handle and step through sequences of more + than one inline frame (so 'main .... ccc', and 'fff .... iii'), and also + that we can move around in a stack that contains more than one disjoint + sequence of inline frames. + + The order of the functions in this file is deliberately mixed up so that + the line numbers are not "all ascending" or "all descending" in the line + table. */ + +#define INLINE_FUNCTION __attribute__ ((always_inline)) static inline +#define NON_INLINE_FUNCTION __attribute__ ((noinline)) + +volatile int global_var = 0; + +INLINE_FUNCTION int aaa (); +INLINE_FUNCTION int bbb (); +INLINE_FUNCTION int ccc (); + +NON_INLINE_FUNCTION int ddd (); +NON_INLINE_FUNCTION int eee (); +NON_INLINE_FUNCTION int fff (); + +INLINE_FUNCTION int ggg (); +INLINE_FUNCTION int hhh (); +INLINE_FUNCTION int iii (); + +NON_INLINE_FUNCTION int jjj (); +NON_INLINE_FUNCTION int kkk (); + +INLINE_FUNCTION int +aaa () +{ /* aaa prologue */ + asm ("aaa_label: .globl aaa_label"); + return bbb () + 1; /* aaa return */ +} /* aaa end */ + +NON_INLINE_FUNCTION int +jjj () +{ /* jjj prologue */ + int ans; + asm ("jjj_label: .globl jjj_label"); + ans = kkk () + 1; /* jjj return */ + asm ("jjj_label2: .globl jjj_label2"); + return ans; +} /* jjj end */ + +INLINE_FUNCTION int +ggg () +{ /* ggg prologue */ + asm ("ggg_label: .globl ggg_label"); + return hhh () + 1; /* ggg return */ +} /* ggg end */ + +INLINE_FUNCTION int +ccc () +{ /* ccc prologue */ + asm ("ccc_label: .globl ccc_label"); + return ddd () + 1; /* ccc return */ +} /* ccc end */ + +NON_INLINE_FUNCTION int +fff () +{ /* fff prologue */ + int ans; + asm ("fff_label: .globl fff_label"); + ans = ggg () + 1; /* fff return */ + asm ("fff_label2: .globl fff_label2"); + return ans; +} /* fff end */ + +NON_INLINE_FUNCTION int +kkk () +{ /* kkk prologue */ + asm ("kkk_label: .globl kkk_label"); + return global_var; /* kkk return */ +} /* kkk end */ + +INLINE_FUNCTION int +bbb () +{ /* bbb prologue */ + asm ("bbb_label: .globl bbb_label"); + return ccc () + 1; /* bbb return */ +} /* bbb end */ + +INLINE_FUNCTION int +hhh () +{ /* hhh prologue */ + asm ("hh_label: .globl hhh_label"); + return iii () + 1; /* hhh return */ +} /* hhh end */ + +int +main () +{ /* main prologue */ + int ans; + asm ("main_label: .globl main_label"); + global_var = 0; /* main set global_var */ + asm ("main_label2: .globl main_label2"); + ans = aaa () + 1; /* main call aaa */ + asm ("main_label3: .globl main_label3"); + return ans; +} /* main end */ + +NON_INLINE_FUNCTION int +ddd () +{ /* ddd prologue */ + int ans; + asm ("ddd_label: .globl ddd_label"); + ans = eee () + 1; /* ddd return */ + asm ("ddd_label2: .globl ddd_label2"); + return ans; +} /* ddd end */ + +INLINE_FUNCTION int +iii () +{ /* iii prologue */ + int ans; + asm ("iii_label: .globl iii_label"); + ans = jjj () + 1; /* iii return */ + asm ("iii_label2: .globl iii_label2"); + return ans; +} /* iii end */ + +NON_INLINE_FUNCTION int +eee () +{ /* eee prologue */ + int ans; + asm ("eee_label: .globl eee_label"); + ans = fff () + 1; /* eee return */ + asm ("eee_label2: .globl eee_label2"); + return ans; +} /* eee end */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.exp new file mode 100644 index 0000000..146af8c --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-many-frames.exp @@ -0,0 +1,379 @@ +# Copyright 2019-2020 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/>. + +# This test shows the importance of not corrupting the order of line +# table information. When multiple lines are given for the same +# address the compiler usually lists these in the order in which we +# would expect to encounter them. When stepping through nested inline +# frames the last line given for an address is assumed by GDB to be +# the most inner frame, and this is what GDB displays. +# +# If we corrupt the order of the line table entries then GDB will +# display the wrong line as being the inner most frame. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# The .c files use __attribute__. +if [get_compiler_info] { + return -1 +} +if !$gcc_compiled { + return 0 +} + +standard_testfile dw2-inline-many-frames.c dw2-inline-many-frames.S + +# Extract the start, length, and end for function called NAME and +# create suitable variables in the callers scope. +proc get_func_info { name } { + global srcdir subdir srcfile + + upvar 1 "${name}_start" func_start + upvar 1 "${name}_len" func_len + upvar 1 "${name}_end" func_end + + lassign [function_range ${name} [list ${srcdir}/${subdir}/$srcfile]] \ + func_start func_len + set func_end "$func_start + $func_len" +} + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + global srcdir subdir srcfile srcfile2 + declare_labels ranges_label lines_label + declare_labels aaa_label bbb_label ccc_label + declare_labels ggg_label hhh_label iii_label + + get_func_info main + get_func_info ddd + get_func_info eee + get_func_info fff + get_func_info jjj + get_func_info kkk + + set call_in_main [gdb_get_line_number "main call aaa"] + set call_in_aaa [gdb_get_line_number "aaa return"] + set call_in_bbb [gdb_get_line_number "bbb return"] + set call_in_ccc [gdb_get_line_number "ccc return"] + set call_in_fff [gdb_get_line_number "fff return"] + set call_in_ggg [gdb_get_line_number "ggg return"] + set call_in_hhh [gdb_get_line_number "hhh return"] + set call_in_iii [gdb_get_line_number "iii return"] + + cu {} { + compile_unit { + {language @DW_LANG_C} + {name dw2-inline-stepping.c} + {low_pc 0 addr} + {stmt_list ${lines_label} DW_FORM_sec_offset} + {ranges ${ranges_label} DW_FORM_sec_offset} + } { + subprogram { + {external 1 flag} + {name ddd} + {low_pc $ddd_start addr} + {high_pc "$ddd_start + $ddd_len" addr} + } + subprogram { + {external 1 flag} + {name eee} + {low_pc $eee_start addr} + {high_pc "$eee_start + $eee_len" addr} + } + subprogram { + {external 1 flag} + {name jjj} + {low_pc $jjj_start addr} + {high_pc "$jjj_start + $jjj_len" addr} + } + subprogram { + {external 1 flag} + {name kkk} + {low_pc $kkk_start addr} + {high_pc "$kkk_start + $kkk_len" addr} + } + aaa_label: subprogram { + {name aaa} + {inline 3 data1} + } + bbb_label: subprogram { + {name bbb} + {inline 3 data1} + } + ccc_label: subprogram { + {name ccc} + {inline 3 data1} + } + ggg_label: subprogram { + {name ggg} + {inline 3 data1} + } + hhh_label: subprogram { + {name hhh} + {inline 3 data1} + } + iii_label: subprogram { + {name iii} + {inline 3 data1} + } + subprogram { + {external 1 flag} + {name main} + {low_pc $main_start addr} + {high_pc "$main_start + $main_len" addr} + } { + inlined_subroutine { + {abstract_origin %$aaa_label} + {low_pc main_label2 addr} + {high_pc main_label3 addr} + {call_file 1 data1} + {call_line $call_in_main data1} + } { + inlined_subroutine { + {abstract_origin %$bbb_label} + {low_pc main_label2 addr} + {high_pc main_label3 addr} + {call_file 1 data1} + {call_line $call_in_aaa data1} + } { + inlined_subroutine { + {abstract_origin %$ccc_label} + {low_pc main_label2 addr} + {high_pc main_label3 addr} + {call_file 1 data1} + {call_line $call_in_bbb data1} + } + } + } + } + subprogram { + {external 1 flag} + {name fff} + {low_pc $fff_start addr} + {high_pc "$fff_start + $fff_len" addr} + } { + inlined_subroutine { + {abstract_origin %$ggg_label} + {low_pc fff_label addr} + {high_pc main_label2 addr} + {call_file 1 data1} + {call_line $call_in_fff data1} + } { + inlined_subroutine { + {abstract_origin %$hhh_label} + {low_pc fff_label addr} + {high_pc fff_label2 addr} + {call_file 1 data1} + {call_line $call_in_ggg data1} + } { + inlined_subroutine { + {abstract_origin %$iii_label} + {low_pc fff_label addr} + {high_pc fff_label2 addr} + {call_file 1 data1} + {call_line $call_in_hhh data1} + } + } + } + } + } + } + + lines {version 2} lines_label { + include_dir "${srcdir}/${subdir}" + file_name "$srcfile" 1 + + program { + {DW_LNE_set_address $main_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "main prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address main_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "main set global_var"] - [gdb_get_line_number "main prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address main_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "main call aaa"] - [gdb_get_line_number "main set global_var"]]} + {DW_LNS_copy} + {DW_LNE_set_address main_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "aaa return"] - [gdb_get_line_number "main call aaa"]]} + {DW_LNS_copy} + {DW_LNE_set_address main_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "bbb return"] - [gdb_get_line_number "aaa return"]]} + {DW_LNS_copy} + {DW_LNE_set_address main_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "ccc return"] - [gdb_get_line_number "bbb return"]]} + {DW_LNS_copy} + {DW_LNE_set_address main_label3} + {DW_LNS_advance_line [expr [gdb_get_line_number "main end"] - [gdb_get_line_number "ccc return"]]} + {DW_LNS_copy} + {DW_LNE_set_address $main_end} + {DW_LNE_end_sequence} + + {DW_LNE_set_address $ddd_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "ddd prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address ddd_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "ddd return"] - [gdb_get_line_number "ddd prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address ddd_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "ddd end"] - [gdb_get_line_number "ddd return"]]} + {DW_LNS_copy} + {DW_LNE_set_address $ddd_end} + {DW_LNE_end_sequence} + + {DW_LNE_set_address $eee_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "eee prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address eee_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "eee return"] - [gdb_get_line_number "eee prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address eee_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "eee end"] - [gdb_get_line_number "eee return"]]} + {DW_LNS_copy} + {DW_LNE_set_address $eee_end} + {DW_LNE_end_sequence} + + {DW_LNE_set_address $fff_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "fff prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address fff_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "fff return"] - [gdb_get_line_number "fff prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address fff_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "ggg return"] - [gdb_get_line_number "fff return"]]} + {DW_LNS_copy} + {DW_LNE_set_address fff_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "hhh return"] - [gdb_get_line_number "ggg return"]]} + {DW_LNS_copy} + {DW_LNE_set_address fff_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "iii return"] - [gdb_get_line_number "hhh return"]]} + {DW_LNS_copy} + {DW_LNE_set_address fff_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "fff end"] - [gdb_get_line_number "fff return"]]} + {DW_LNS_copy} + {DW_LNE_set_address $fff_end} + {DW_LNE_end_sequence} + + {DW_LNE_set_address $jjj_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "jjj prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address jjj_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "jjj return"] - [gdb_get_line_number "jjj prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address jjj_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "jjj end"] - [gdb_get_line_number "jjj return"]]} + {DW_LNS_copy} + {DW_LNE_set_address $jjj_end} + {DW_LNE_end_sequence} + + {DW_LNE_set_address $kkk_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "kkk prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address kkk_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "kkk return"] - [gdb_get_line_number "kkk prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address $kkk_end} + {DW_LNE_end_sequence} + } + } + + ranges {is_64 [is_64_target]} { + ranges_label: sequence { + {range {${main_start}} ${main_end}} + {range {${ddd_start}} ${ddd_end}} + {range {${eee_start}} ${eee_end}} + {range {${fff_start}} ${fff_end}} + {range {${jjj_start}} ${jjj_end}} + {range {${kkk_start}} ${kkk_end}} + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +# First we step through all of the functions until we get the 'kkk'. +set patterns [list "main call aaa" \ + "aaa return" \ + "bbb return" \ + "ccc return" \ + "ddd return" \ + "eee return" \ + "fff return" \ + "ggg return" \ + "hhh return" \ + "iii return" \ + "jjj return" \ + "kkk return" ] +foreach p $patterns { + gdb_test "step" "/\\* $p \\*/" \ + "step to '$p'" +} + +# Now check the backtrace. +set line_in_main [gdb_get_line_number "main call aaa"] +set line_in_aaa [gdb_get_line_number "aaa return"] +set line_in_bbb [gdb_get_line_number "bbb return"] +set line_in_ccc [gdb_get_line_number "ccc return"] +set line_in_ddd [gdb_get_line_number "ddd return"] +set line_in_eee [gdb_get_line_number "eee return"] +set line_in_fff [gdb_get_line_number "fff return"] +set line_in_ggg [gdb_get_line_number "ggg return"] +set line_in_hhh [gdb_get_line_number "hhh return"] +set line_in_iii [gdb_get_line_number "iii return"] +set line_in_jjj [gdb_get_line_number "jjj return"] +set line_in_kkk [gdb_get_line_number "kkk return"] + +gdb_test "bt" [multi_line \ + "#0 kkk \\(\\) at \[^\r\n\]+${srcfile}:${line_in_kkk}" \ + "#1 $hex in jjj \\(\\) at \[^\r\n\]+${srcfile}:${line_in_jjj}" \ + "#2 $hex in iii \\(\\) at \[^\r\n\]+${srcfile}:${line_in_iii}" \ + "#3 hhh \\(\\) at \[^\r\n\]+${srcfile}:${line_in_hhh}" \ + "#4 ggg \\(\\) at \[^\r\n\]+${srcfile}:${line_in_ggg}" \ + "#5 fff \\(\\) at \[^\r\n\]+${srcfile}:${line_in_fff}" \ + "#6 $hex in eee \\(\\) at \[^\r\n\]+${srcfile}:${line_in_eee}" \ + "#7 $hex in ddd \\(\\) at \[^\r\n\]+${srcfile}:${line_in_ddd}" \ + "#8 $hex in ccc \\(\\) at \[^\r\n\]+${srcfile}:${line_in_ccc}" \ + "#9 bbb \\(\\) at \[^\r\n\]+${srcfile}:${line_in_bbb}" \ + "#10 aaa \\(\\) at \[^\r\n\]+${srcfile}:${line_in_aaa}" \ + "#11 main \\(\\) at \[^\r\n\]+${srcfile}:${line_in_main}" ] + +# Now check we can use 'up' to inspect each frame correctly. +set patterns [list \ + "jjj return" \ + "iii return" \ + "hhh return" \ + "ggg return" \ + "fff return" \ + "eee return" \ + "ddd return" \ + "ccc return" \ + "bbb return" \ + "aaa return" \ + "main call aaa" ] +foreach p $patterns { + gdb_test "up" "/\\* $p \\*/" \ + "up to '$p'" +} |