1# Copyright 2020 Free Software Foundation, Inc. 2 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16# This test shows the importance of not corrupting the order of line 17# table information. When multiple lines are given for the same 18# address the compiler usually lists these in the order in which we 19# would expect to encounter them. When stepping through nested inline 20# frames the last line given for an address is assumed by GDB to be 21# the most inner frame, and this is what GDB displays. 22# 23# If we corrupt the order of the line table entries then GDB will 24# display the wrong line as being the inner most frame. 25 26load_lib dwarf.exp 27 28# This test can only be run on targets which support DWARF-2 and use gas. 29if {![dwarf2_support]} { 30 return 0 31} 32 33# The .c files use __attribute__. 34if [get_compiler_info] { 35 return -1 36} 37if !$gcc_compiled { 38 return 0 39} 40 41standard_testfile dw2-is-stmt.c dw2-is-stmt.S 42 43set asm_file [standard_output_file $srcfile2] 44Dwarf::assemble $asm_file { 45 global srcdir subdir srcfile 46 declare_labels lines_label 47 48 get_func_info main 49 50 cu {} { 51 compile_unit { 52 {language @DW_LANG_C} 53 {name dw2-is-stmt.c} 54 {low_pc 0 addr} 55 {stmt_list ${lines_label} DW_FORM_sec_offset} 56 } { 57 subprogram { 58 {external 1 flag} 59 {name main} 60 {low_pc $main_start addr} 61 {high_pc "$main_start + $main_len" addr} 62 } {} 63 } 64 } 65 66 lines {version 2 default_is_stmt 0} lines_label { 67 include_dir "${srcdir}/${subdir}" 68 file_name "$srcfile" 1 69 70 program { 71 {DW_LNE_set_address main} 72 {line [gdb_get_line_number "main prologue"]} 73 {DW_LNS_negate_stmt} 74 {DW_LNS_copy} 75 76 {DW_LNE_set_address line_label_1} 77 {line [gdb_get_line_number "main, set var to 99"]} 78 {DW_LNS_copy} 79 80 {DW_LNE_set_address line_label_2} 81 {line [gdb_get_line_number "main, set var to 0"]} 82 {DW_LNS_negate_stmt} 83 {DW_LNS_copy} 84 85 {DW_LNE_set_address line_label_3} 86 {DW_LNS_negate_stmt} 87 {DW_LNS_copy} 88 89 {DW_LNE_set_address line_label_4} 90 {DW_LNS_negate_stmt} 91 {DW_LNS_copy} 92 93 {DW_LNE_set_address line_label_5} 94 {line [gdb_get_line_number "main end"]} 95 {DW_LNS_negate_stmt} 96 {DW_LNS_copy} 97 98 {DW_LNE_set_address ${main_end}} 99 {DW_LNE_end_sequence} 100 } 101 } 102} 103 104if { [prepare_for_testing "failed to prepare" ${testfile} \ 105 [list $srcfile $asm_file] {nodebug}] } { 106 return -1 107} 108 109if ![runto_main] { 110 return -1 111} 112 113# First, break by address at a location we know is marked as not a 114# statement. GDB should still correctly report the file and line 115# number. 116gdb_breakpoint "*line_label_2" 117gdb_continue_to_breakpoint "*line_label_2" 118 119# Now step by instruction. We should skip over the is-stmt location 120# for this line, and land on the next source line. 121gdb_test "step" "/\\* main end \\*/" \ 122 "step to end from line_label_2" 123 124# Restart the test. This time, stop at a location we know is marked 125# as a statement. 126clean_restart ${binfile} 127runto_main 128 129gdb_breakpoint "*line_label_3" 130gdb_continue_to_breakpoint "*line_label_3" 131 132# Now step by instruction. As you would expect we should leave this 133# line and stop at the next source line. 134gdb_test "step" "/\\* main end \\*/" \ 135 "step to end from line_label_3" 136 137# Restart the test, this time, step through line by line, ensure we 138# only stop at the places where is-stmt is true. 139clean_restart ${binfile} 140runto_main 141 142# Get the values of the labels where we expect to stop. 143set ll1 [get_hexadecimal_valueof "&line_label_1" "INVALID"] 144set ll2 [get_hexadecimal_valueof "&line_label_2" "INVALID"] 145set ll3 [get_hexadecimal_valueof "&line_label_3" "INVALID"] 146set ll5 [get_hexadecimal_valueof "&line_label_5" "INVALID"] 147 148# The first stop should be at line_label_1 149with_test_prefix "check we're at line_label_1" { 150 set pc [get_hexadecimal_valueof "\$pc" "NO-PC"] 151 gdb_assert { $ll1 == $pc } "check initial \$pc is line_label_1" 152} 153 154# Now step, this should take us to line_label_3 which is the next 155# location marked as is-stmt. 156with_test_prefix "step to line_label_3" { 157 gdb_test "step" "/\\* main, set var to 0 \\*/" 158 set pc [get_hexadecimal_valueof "\$pc" "NO-PC"] 159 gdb_assert { $ll3 == $pc } "check initial \$pc is line_label_3" 160} 161 162# A final step should take us to line_label_5. 163with_test_prefix "step to line_label_5" { 164 gdb_test "step" "/\\* main end \\*/" 165 set pc [get_hexadecimal_valueof "\$pc" "NO-PC"] 166 gdb_assert { $ll5 == $pc } "check initial \$pc" 167} 168 169# Now restart the test, and place a breakpoint by line number. GDB 170# should select the location that is marked as is-stmt. 171clean_restart ${binfile} 172runto_main 173set linum [gdb_get_line_number "main, set var to 0"] 174gdb_breakpoint "$srcfile:$linum" 175gdb_continue_to_breakpoint "Breakpoint on line, set var to 0" 176set pc [get_hexadecimal_valueof "\$pc" "NO-PC"] 177gdb_assert { $ll3 == $pc } "check initial \$pc" 178 179# Restart the test again, this time we will test stepping by 180# instruction. 181clean_restart ${binfile} 182runto_main 183 184# We will be at line_label_1 at this point - we already tested this 185# above. Now single instruction step forward until we get to 186# line_label_2. Every instruction before line_label_2 should be 187# attributed to the 'var = 99' line. For most targets there will only 188# be a single instruction between line_label_1 and line_label_2, but 189# we allow for up to 25 (just a random number). 190 191set $i 0 192set pc [get_hexadecimal_valueof "\$pc" "NO-PC" \ 193 "get pc before stepi loop at line_label_1"] 194while { $pc < $ll2 } { 195 incr i 196 set line_changed -1 197 gdb_test_multiple "stepi" "stepi until line_label_2, $i" { 198 -re "main, set var to 99.*$gdb_prompt" { 199 set line_changed 0 200 } 201 -re "main, set var to 0.*$gdb_prompt " { 202 set line_changed 1 203 } 204 } 205 gdb_assert { $line_changed != -1 } \ 206 "ensure we saw a valid line pattern, $i" 207 set pc [get_hexadecimal_valueof "\$pc" "NO-PC" \ 208 "get pc inside stepi loop from line_label_1, $i"] 209 if { $ll2 == $pc } { 210 gdb_assert { $line_changed } \ 211 "line must change at line_label_2" 212 } else { 213 gdb_assert { !$line_changed } \ 214 "line should not change until line_label_2, $i" 215 } 216} 217 218# Now single instruction step forward until GDB reports a new source 219# line, at which point we should be at line_label_5. 220 221set $i 0 222set pc [get_hexadecimal_valueof "\$pc" "NO-PC" \ 223 "get pc before stepi loop at line_label_2"] 224while { $pc < $ll5 } { 225 incr i 226 set line_changed -1 227 gdb_test_multiple "stepi" "stepi until line_label_5, $i" { 228 -re "main, set var to 0.*$gdb_prompt" { 229 set line_changed 0 230 } 231 -re "main end.*$gdb_prompt " { 232 set line_changed 1 233 } 234 } 235 gdb_assert { $line_changed != -1 } \ 236 "ensure we saw a valid line pattern, $i" 237 set pc [get_hexadecimal_valueof "\$pc" "NO-PC" \ 238 "get pc inside stepi loop from line_label_2, $i"] 239 if { $ll5 == $pc } { 240 gdb_assert { $line_changed } \ 241 "line must change at line_label_5" 242 } else { 243 gdb_assert { !$line_changed } \ 244 "line should not change until line_label_5, $i" 245 } 246} 247