]>
Commit | Line | Data |
---|---|---|
1d506c26 | 1 | # Copyright 2008-2024 Free Software Foundation, Inc. |
edb3359d DJ |
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 | ||
8980e177 PA |
16 | load_lib mi-support.exp |
17 | set MIFLAGS "-i=mi" | |
18 | ||
efc9d70a TT |
19 | standard_testfile .c inline-markers.c |
20 | ||
5b362f04 | 21 | if {[prepare_for_testing "failed to prepare" $testfile \ |
1f960ced | 22 | [list $srcfile $srcfile2] {debug additional_flags=-Winline}]} { |
edb3359d DJ |
23 | return -1 |
24 | } | |
25 | ||
019ebafc | 26 | gdb_test_no_output "set listsize 1" |
edb3359d DJ |
27 | |
28 | runto_main | |
29 | ||
edb3359d DJ |
30 | get_debug_format |
31 | if { [skip_inline_frame_tests] } { | |
5b362f04 | 32 | untested "skipping inline frame tests" |
edb3359d DJ |
33 | return |
34 | } | |
35 | ||
36 | # First, check that the things we expected to be inlined really were, | |
37 | # and those that shouldn't be weren't. | |
38 | set line1 [gdb_get_line_number "set breakpoint 1 here" ${srcfile2}] | |
39 | gdb_breakpoint $srcfile2:$line1 | |
40 | set line2 [gdb_get_line_number "set breakpoint 2 here" ${srcfile2}] | |
41 | gdb_breakpoint $srcfile2:$line2 | |
42 | ||
43 | gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (1)" | |
44 | gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*main.*" \ | |
45 | "backtrace from bar (1)" | |
46 | gdb_test "up" "#1 .*func1.*" "up from bar (1)" | |
47 | gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (1)" | |
48 | ||
49 | gdb_test "continue" ".*set breakpoint 1 here.*" "continue to bar (2)" | |
50 | gdb_test "backtrace" "#0 bar.*#1 .*func1.*#2 .*func2.*#3 .*main.*" \ | |
51 | "backtrace from bar (2)" | |
52 | gdb_test "up" "#1 .*func1.*" "up from bar (2)" | |
53 | gdb_test "info frame" ".*inlined into frame.*" "func1 inlined (2)" | |
54 | gdb_test "up" "#2 .*func2.*" "up from func1 (2)" | |
55 | gdb_test "info frame" ".*inlined into frame.*" "func2 inlined (2)" | |
56 | ||
57 | gdb_test "continue" ".*set breakpoint 2 here.*" "continue to marker" | |
58 | gdb_test "backtrace" "#0 marker.*#1 .*main.*" "backtrace from marker" | |
59 | gdb_test "info frame" ".*called by frame.*" "marker not inlined" | |
60 | ||
61 | # Next, check that we can next over inlined functions. We should not end up | |
62 | # inside any of them. | |
63 | delete_breakpoints | |
64 | runto_main | |
65 | ||
66 | # The lines before the first inlined call. | |
67 | set first "x = 7|y = 8" | |
68 | ||
69 | # Some extra lines that end up in our stepping due to code motion. | |
70 | set opt "start of main|result = 0" | |
71 | ||
72 | # We start this test with a "list" instead of a "next", in case the | |
73 | # first non-prologue instruction in main comes from the inlined function. | |
74 | set msg "next over inlined functions" | |
75 | gdb_test_multiple "list" $msg { | |
76 | -re "($first|result = func1|result = func2|$opt).*$gdb_prompt $" { | |
77 | send_gdb "next\r" | |
78 | exp_continue | |
79 | } | |
80 | -re "marker \\\(\\\);\r\n$gdb_prompt $" { | |
81 | pass $msg | |
82 | } | |
83 | } | |
84 | ||
85 | # Check that when next shows the call of func1, it has not happened yet. | |
86 | runto_main | |
87 | ||
88 | # Like the return value of gdb_test: -1 something is wrong, 0 passed, 1 failed. | |
89 | set bt_test -1 | |
90 | set x_test -1 | |
91 | set func1_step -1 | |
92 | ||
93 | set last_was_func1_call 0 | |
94 | set msg "next past inlined func1" | |
95 | gdb_test_multiple "list" $msg { | |
96 | -re "($first|$opt).*$gdb_prompt $" { | |
97 | set last_was_func1_call 0 | |
98 | send_gdb "next\r" | |
99 | exp_continue | |
100 | } | |
101 | -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" { | |
102 | # Check whether x has been set. If 0, we may be doing something | |
103 | # else associated with this line besides the inlined call - e.g. | |
104 | # loading the address of result. If 7, we may be at the call site. | |
105 | # If 15, though, we might be past the call and back at the store to | |
106 | # result - that's OK, as long as we weren't just here (see | |
107 | # func1_step above). | |
108 | set x_val -1 | |
109 | gdb_test_multiple "print x" "" { | |
110 | -re "\\\$$decimal = (\[0-9\]*)\r\n$gdb_prompt $" { | |
111 | set x_val $expect_out(1,string) | |
112 | } | |
113 | -re "$gdb_prompt $" { } | |
114 | } | |
115 | if { $x_val == 0 || $x_val == 7 } { | |
116 | if { $x_test != 1 } { | |
117 | set x_test 0 | |
118 | } | |
119 | } elseif { $x_val == 15 } { | |
120 | if { $func1_step == -1 } { | |
121 | # We passed func1 without stopping at the call site. | |
122 | set x_test 1 | |
123 | } | |
124 | } else { | |
125 | set x_test 1 | |
126 | } | |
127 | ||
128 | # func1 should not show up on backtraces if we are at its call | |
129 | # site. | |
130 | if { $bt_test != 1 } { | |
131 | set bt_test [gdb_test "backtrace" "#0 \[^#]*main.*" ""] | |
132 | } | |
133 | ||
134 | # When we next over func1, we should not return to the same | |
135 | # line. But we might go past the line, according to source | |
136 | # code order, and then come back. A valid but odd layout is | |
137 | # body of func1, load result's address into a register using | |
138 | # the source location of "result = 0" several lines down, and | |
139 | # then return to this line for the store. GCC 4.3 does that | |
140 | # on ARM. | |
141 | if { $last_was_func1_call } { | |
142 | set func1_step 1 | |
143 | } elseif { $func1_step == -1 } { | |
144 | set func1_step 0 | |
145 | } | |
146 | set last_was_func1_call 1 | |
147 | ||
148 | send_gdb "next\r" | |
149 | exp_continue | |
150 | } | |
151 | ||
152 | -re "result = func2 \\\(\\\);\r\n$gdb_prompt $" { | |
153 | pass $msg | |
154 | } | |
155 | } | |
156 | ||
157 | if { $x_test == 0 } { | |
158 | pass "print x before func1" | |
159 | } else { | |
160 | fail "print x before func1" | |
161 | } | |
162 | ||
163 | if { $bt_test == 0 } { | |
164 | pass "backtrace does not include func1" | |
165 | } else { | |
166 | fail "backtrace does not include func1" | |
167 | } | |
168 | ||
169 | if { $bt_test == 0 } { | |
170 | pass "stepped over call to func1" | |
171 | } else { | |
172 | fail "stepped over call to func1" | |
173 | } | |
174 | ||
175 | # Next, check that we can single step into inlined functions. We should always | |
176 | # "stop" at the call sites before entering them. | |
177 | runto_main | |
178 | ||
179 | set msg "step into func1" | |
180 | set saw_call_site 0 | |
181 | gdb_test_multiple "list" $msg { | |
182 | -re "($first|$opt).*$gdb_prompt $" { | |
183 | send_gdb "step\r" | |
184 | exp_continue | |
185 | } | |
186 | -re "result = func1.*$gdb_prompt $" { | |
187 | set saw_call_site 1 | |
188 | send_gdb "step\r" | |
189 | exp_continue | |
190 | } | |
191 | -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" { | |
192 | if { $saw_call_site } { | |
193 | pass $msg | |
194 | } else { | |
195 | fail $msg | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | # Check finish out of an inlined function. | |
201 | set msg "finish from func1" | |
202 | gdb_test_multiple "finish" $msg { | |
203 | -re "result = func1 \\\(\\\);\r\n$gdb_prompt $" { | |
204 | pass $msg | |
205 | } | |
206 | -re "($first|$opt).*$gdb_prompt $" { | |
207 | # Whoops. We finished, but ended up back at an earlier line. Keep | |
208 | # trying. | |
209 | send_gdb "step\r" | |
210 | exp_continue | |
211 | } | |
212 | -re "func1 \\\(\\\) at .*\r\n$decimal.*bar \\\(\\\);\r\n$gdb_prompt $" { | |
213 | send_gdb "finish\r" | |
214 | exp_continue | |
215 | } | |
216 | } | |
217 | ||
218 | # Test some corner cases involving consecutive inlined functions. | |
219 | set line3 [gdb_get_line_number "set breakpoint 3 here"] | |
220 | gdb_breakpoint $line3 | |
221 | gdb_continue_to_breakpoint "consecutive func1" | |
222 | ||
223 | gdb_test "next" ".*func1 .*first call.*" "next to first func1" | |
340d00fb | 224 | gdb_test "next" ".*func1 .*second call.*" "next to second func1" |
edb3359d DJ |
225 | |
226 | # It is easier when the two inlined functions are not on the same line. | |
227 | set line4 [gdb_get_line_number "set breakpoint 4 here"] | |
228 | gdb_breakpoint $line4 | |
229 | gdb_continue_to_breakpoint "func1 then func3" | |
230 | ||
231 | gdb_test "next" ".*func1 \\\(\\\);" "next to func1 before func3" | |
232 | gdb_test "next" ".*func3 \\\(\\\);" "next to func3" | |
233 | ||
234 | # Test finishing out of one thing and into another. | |
235 | set line5 [gdb_get_line_number "set breakpoint 5 here"] | |
236 | gdb_breakpoint $line5 | |
237 | gdb_continue_to_breakpoint "finish into func1" | |
238 | ||
239 | gdb_test "next" ".*marker \\\(\\\);" "next to finish marker" | |
240 | gdb_test "step" ".*set breakpoint 2 here.*" "step into finish marker" | |
b4cbb4a3 EBM |
241 | |
242 | # Some architectures will have one or more instructions after | |
243 | # the call instruction which still are part of the call sequence, | |
244 | # so it should be expected to return to the caller line after issue | |
245 | # a 'finish' command. | |
246 | gdb_test_multiple "finish" "finish from marker" { | |
247 | -re "func1 \\\(\\\);.*\r\n$gdb_prompt $" { | |
248 | pass "finish from marker to func1" | |
249 | } | |
250 | -re "marker \\\(\\\);.*\r\n$gdb_prompt $" { | |
251 | pass "finish from marker" | |
252 | gdb_test "step" "func1 \\\(\\\);.*" "step after marker to reach func1" | |
253 | } | |
254 | } | |
edb3359d DJ |
255 | |
256 | gdb_test "step" "bar \\\(\\\);" "step into func1 for finish" | |
257 | gdb_test "finish" "func3 \\\(\\\);" "finish from func1 to func3" | |
258 | ||
259 | # Test a deeper call stack. | |
260 | set line6 [gdb_get_line_number "set breakpoint 6 here"] | |
261 | gdb_breakpoint $line6 | |
262 | gdb_continue_to_breakpoint "before the outer_inline call" | |
263 | gdb_test "step" "marker \\\(\\\) at .*" "reach 1 the outer_inline call" | |
b4cbb4a3 EBM |
264 | gdb_test_multiple "finish" "finish from marker" { |
265 | -re "main \\\(\\\) at .*outer_inline2 \\\(\\\);.*\r\n$gdb_prompt $" { | |
266 | pass "reach outer_inline2" | |
267 | } | |
268 | -re "main \\\(\\\) at .*marker \\\(\\\);.*\r\n$gdb_prompt $" { | |
269 | pass "finish from marker" | |
270 | gdb_test "step" "outer_inline2 \\\(\\\);.*" "step after marker to reach outer_inline2" | |
271 | } | |
272 | } | |
edb3359d DJ |
273 | gdb_test "bt" "#0 main.*" "backtrace at main of outer_inline" |
274 | gdb_test "step" "outer_inline2 \\\(\\\) at .*" "enter outer_inline2" | |
275 | gdb_test "bt" "#0 outer_inline2.*#1 main.*" "backtrace at outer_inline2" | |
276 | gdb_test "step" "outer_inline1 \\\(\\\) at .*" "enter outer_inline1 from outer_inline2" | |
277 | ||
278 | set msg "backtrace at outer_inline1" | |
279 | gdb_test_multiple "bt" $msg { | |
280 | -re "#0 outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" { | |
281 | pass $msg | |
282 | } | |
283 | -re "#0 $hex in outer_inline1.*#1 outer_inline2.*#2 main.*$gdb_prompt $" { | |
284 | # Binutils PR gas/6717. Gas moves .loc past .p2align and the | |
285 | # leading nop of the inlined call appears to be on the same line | |
286 | # as main's call to marker. | |
287 | xfail $msg | |
288 | gdb_test "step" "noinline \\\(\\\);" "step to call of noinline" | |
289 | } | |
290 | } | |
291 | ||
292 | gdb_test "step" "noinline \\\(\\\) at .*" "enter noinline from outer_inline1" | |
293 | gdb_test "bt" "#0 noinline.*#1 .*outer_inline1.*#2 .*outer_inline2.*#3 main.*" "backtrace at noinline from outer_inline1" | |
294 | gdb_test "step" "inlined_fn \\\(\\\) at .*" "enter inlined_fn from noinline" | |
295 | gdb_test "bt" "#0 inlined_fn.*#1 noinline.*#2 .*outer_inline1.*#3 .*outer_inline2.*#4 main.*" "backtrace at inlined_fn from noinline" | |
296 | gdb_test "info frame" ".*inlined into frame.*" "inlined_fn from noinline inlined" | |
297 | gdb_test "up" "#1 noinline.*" "up to noinline" | |
298 | gdb_test "info frame" ".*\n called by frame.*" "noinline from outer_inline1 not inlined" | |
299 | gdb_test "up" "#2 .*outer_inline1.*" "up to outer_inline1" | |
300 | gdb_test "info frame" ".*inlined into frame.*" "outer_inline1 inlined" | |
301 | gdb_test "up" "#3 .*outer_inline2.*" "up to outer_inline2" | |
302 | gdb_test "info frame" ".*inlined into frame.*" "outer_inline2 inlined" | |
303 | gdb_test "up" "#4 main.*" "up from outer_inline2" | |
304 | gdb_test "info frame" ".*\n caller of frame.*" "main not inlined" | |
8980e177 PA |
305 | |
306 | gdb_exit | |
307 | ||
308 | # Send a CLI "step" command over MI. CLI_OUTPUT_RE is a regexp that | |
309 | # matches the expected CLI output. MESSAGE is used as test message. | |
310 | ||
311 | proc mi_cli_step {cli_output_re message} { | |
312 | global mi_gdb_prompt | |
313 | global srcfile | |
314 | global decimal | |
315 | ||
316 | send_gdb "interpreter-exec console \"step\"\n" | |
317 | gdb_expect { | |
318 | -re "\\^running\r\n\\*running,thread-id=\"all\"\r\n${mi_gdb_prompt}${cli_output_re}" { | |
319 | pass $message | |
320 | } | |
321 | timeout { | |
322 | fail "$message (timeout)" | |
323 | } | |
324 | eof { | |
325 | fail "$message (eof)" | |
326 | } | |
327 | } | |
328 | ||
329 | # mi_expect_stop handles "set mi-async on/off" differences. | |
330 | mi_expect_stop "end-stepping-range" "\[^\r\n\]*" "" ".*$srcfile" "$decimal" \ | |
331 | "" "got *stopped for $message" | |
332 | } | |
333 | ||
334 | # Test that stepping into an inlined function with the CLI "step" | |
335 | # command run while the top interpreter is MI results in the expected | |
336 | # CLI output sent to MI's console. | |
337 | with_test_prefix "mi" { | |
338 | if [mi_gdb_start] { | |
cdd42066 | 339 | return |
8980e177 PA |
340 | } |
341 | mi_gdb_load ${binfile} | |
f71e6719 | 342 | mi_runto_main |
8980e177 PA |
343 | |
344 | set line_number [gdb_get_line_number "set mi break here"] | |
345 | mi_gdb_test "-break-insert ${srcfile}:${line_number}" \ | |
346 | {\^done,bkpt=.number="2",type="breakpoint".*\}} \ | |
347 | "set breakpoint" | |
348 | ||
349 | mi_execute_to "exec-continue" "breakpoint-hit" "main" "" ".*" ".*" \ | |
350 | { "" "disp=\"keep\"" } "breakpoint hit" | |
351 | ||
352 | incr line_number 2 | |
353 | ||
354 | # Step to the line that does an inline call. | |
355 | set re "~\"$line_number\\\\t result = func1 \\(\\);\\\\n\"\r\n" | |
356 | mi_cli_step "${re}" "step to inline call" | |
357 | ||
358 | # Step into the inlined function. | |
359 | set re [multi_line \ | |
360 | "~\"func1 \\(\\) at .*$srcfile:$decimal\\\\n\"" \ | |
361 | "~\"$decimal\\\\t bar \\(\\);\\\\n\"\r\n"] | |
362 | mi_cli_step "${re}" "step into inline call" | |
363 | } |