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