| # Copyright 2019-2021 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 .c .S |
| |
| 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} |
| {line [gdb_get_line_number "main prologue"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address main_label} |
| {line [gdb_get_line_number "main set global_var"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address main_label2} |
| {line [gdb_get_line_number "main call aaa"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address main_label2} |
| {line [gdb_get_line_number "aaa return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address main_label2} |
| {line [gdb_get_line_number "bbb return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address main_label2} |
| {line [gdb_get_line_number "ccc return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address main_label3} |
| {line [gdb_get_line_number "main end"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address $main_end} |
| {DW_LNE_end_sequence} |
| |
| {DW_LNE_set_address $ddd_start} |
| {line [gdb_get_line_number "ddd prologue"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address ddd_label} |
| {line [gdb_get_line_number "ddd return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address ddd_label2} |
| {line [gdb_get_line_number "ddd end"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address $ddd_end} |
| {DW_LNE_end_sequence} |
| |
| {DW_LNE_set_address $eee_start} |
| {line [gdb_get_line_number "eee prologue"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address eee_label} |
| {line [gdb_get_line_number "eee return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address eee_label2} |
| {line [gdb_get_line_number "eee end"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address $eee_end} |
| {DW_LNE_end_sequence} |
| |
| {DW_LNE_set_address $fff_start} |
| {line [gdb_get_line_number "fff prologue"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address fff_label} |
| {line [gdb_get_line_number "fff return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address fff_label} |
| {line [gdb_get_line_number "ggg return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address fff_label} |
| {line [gdb_get_line_number "hhh return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address fff_label} |
| {line [gdb_get_line_number "iii return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address fff_label2} |
| {line [gdb_get_line_number "fff end"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address $fff_end} |
| {DW_LNE_end_sequence} |
| |
| {DW_LNE_set_address $jjj_start} |
| {line [gdb_get_line_number "jjj prologue"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address jjj_label} |
| {line [gdb_get_line_number "jjj return"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address jjj_label2} |
| {line [gdb_get_line_number "jjj end"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address $jjj_end} |
| {DW_LNE_end_sequence} |
| |
| {DW_LNE_set_address $kkk_start} |
| {line [gdb_get_line_number "kkk prologue"]} |
| {DW_LNS_copy} |
| {DW_LNE_set_address kkk_label} |
| {line [gdb_get_line_number "kkk return"]} |
| {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'" |
| } |