# 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 . # 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'" }