# Copyright 2019-2023 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 . # 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 ![is_c_compiler_gcc] { 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'" }