xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.base/jit-reader.exp (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
1# Copyright 2012-2023 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# Optionally test a Python API here as well.
17load_lib gdb-python.exp
18
19standard_testfile jit-reader-host.c
20
21if { (![istarget x86_64-*-*] && ![istarget i?86-*-*]) || ![is_lp64_target] } {
22    return -1;
23}
24
25if {[skip_shlib_tests]} {
26    return -1
27}
28
29if { ![isnative] } {
30    return -1
31}
32
33# Increase this to see more detail.
34set test_verbose 0
35
36set jit_host_src $srcfile
37set jit_host_bin $binfile
38
39# We inject the complete path to jit-reader.h into the source file
40# lest we end up (incorrectly) building against a system-installed
41# version.
42set jit_reader_header [standard_output_file "../../../../../gdb/jit-reader.h"]
43set jit_reader_flag "-DJIT_READER_H=\"$jit_reader_header\""
44
45if  { [gdb_compile "${srcdir}/${subdir}/${jit_host_src}" "${jit_host_bin}" \
46       executable  [list debug additional_flags=$jit_reader_flag]] != "" } {
47    untested "failed to compile"
48    return -1
49}
50
51set jit_reader jit-reader
52set jit_reader_src ${jit_reader}.c
53set jit_reader_bin [standard_output_file ${jit_reader}.so]
54
55if { [gdb_compile_shlib "${srcdir}/${subdir}/${jit_reader_src}" "${jit_reader_bin}" \
56	  [list debug additional_flags=$jit_reader_flag]] != "" } {
57    untested "failed to compile"
58    return -1
59}
60
61# Test "info registers" in the current frame, expecting RSP's value to
62# be SP.
63
64proc info_registers_current_frame {sp} {
65    global hex decimal
66
67    set any "\[^\r\n\]*"
68
69    set neg_decimal "-?$decimal"
70
71    set expected \
72	[multi_line \
73	     "rax            $hex +$neg_decimal" \
74	     "rbx            $hex +$neg_decimal" \
75	     "rcx            $hex +$neg_decimal" \
76	     "rdx            $hex +$neg_decimal" \
77	     "rsi            $hex +$neg_decimal" \
78	     "rdi            $hex +$neg_decimal" \
79	     "rbp            $hex +$hex" \
80	     "rsp            $sp +$sp" \
81	     "r8             $hex +$neg_decimal" \
82	     "r9             $hex +$neg_decimal" \
83	     "r10            $hex +$neg_decimal" \
84	     "r11            $hex +$neg_decimal" \
85	     "r12            $hex +$neg_decimal" \
86	     "r13            $hex +$neg_decimal" \
87	     "r14            $hex +$neg_decimal" \
88	     "r15            $hex +$neg_decimal" \
89	     "rip            $hex +$hex$any" \
90	     "eflags         $hex +\\\[$any\\\]" \
91	     "cs             $hex +$neg_decimal" \
92	     "ss             $hex +$neg_decimal" \
93	     "ds             $hex +$neg_decimal" \
94	     "es             $hex +$neg_decimal" \
95	     "fs             $hex +$neg_decimal" \
96	     "gs             $hex +$neg_decimal" \
97	    ]
98
99    # There may be more registers.
100    append expected ".*"
101
102    gdb_test "info registers" $expected
103}
104
105proc jit_reader_test {} {
106    global jit_host_bin
107    global jit_reader_bin
108    global test_verbose
109    global hex decimal
110
111    set any "\[^\r\n\]*"
112
113    clean_restart $jit_host_bin
114    gdb_load_shlib $jit_reader_bin
115
116    if {$test_verbose > 0} {
117	gdb_test_no_output "set debug jit 1"
118    }
119
120    gdb_test_no_output "jit-reader-load ${jit_reader_bin}" "jit-reader-load"
121    gdb_run_cmd
122    gdb_test "" "Program received signal SIGTRAP, .*" "expect SIGTRAP"
123
124    # Test the JIT reader unwinder.
125    with_test_prefix "with jit-reader" {
126
127	with_test_prefix "before mangling" {
128	    gdb_test "bt" \
129		[multi_line \
130		     "#0 ${any} in jit_function_stack_mangle ${any}" \
131		     "#1 ${any} in main ${any}" \
132		    ] \
133		"bt works"
134
135	    set sp_before_mangling \
136		[get_hexadecimal_valueof "\$sp" 0 "get sp"]
137
138	    gdb_test "up" "#1  $any in main $any\r\n$any  function_stack_mangle $any" \
139		"move up to caller"
140
141	    set caller_sp \
142		[get_hexadecimal_valueof "\$sp" 0 "get caller sp"]
143	}
144
145	# Step over the instruction that mangles the stack pointer.
146	# While that confuses GDB's built-in unwinder, the JIT
147	# reader's unwinder understands the mangling and should thus
148	# be able to unwind at that location.
149	with_test_prefix "after mangling" {
150	    gdb_test "si" "in jit_function_stack_mangle .*" "step over stack mangling"
151
152	    set sp_after_mangling \
153		[get_hexadecimal_valueof "\$sp" 0 "get sp"]
154
155	    gdb_assert {$sp_before_mangling != $sp_after_mangling} \
156		"sp is mangled"
157
158	    # Check that the jit unwinder manages to backtrace through
159	    # the mangled stack pointer.
160	    gdb_test "bt" \
161		[multi_line \
162		     "#0 ${any} in jit_function_stack_mangle ${any}" \
163		     "#1 ${any} in main ${any}" \
164		    ] \
165		"bt works"
166
167	    with_test_prefix "current frame" {
168		info_registers_current_frame $sp_after_mangling
169
170		gdb_test "info frame" \
171		    "Stack level 0, frame at $sp_before_mangling.*in jit_function_stack_mangle.*"
172	    }
173
174	    with_test_prefix "caller frame" {
175		gdb_test "up" "#1  $any in main $any\r\n$any  function_stack_mangle $any" \
176		    "up to caller"
177
178		# Since the JIT unwinder only provides RIP/RSP/RBP,
179		# all other registers should show as "<not saved>".
180
181		set expected \
182		    [multi_line \
183			 "rax            <not saved>" \
184			 "rbx            <not saved>" \
185			 "rcx            <not saved>" \
186			 "rdx            <not saved>" \
187			 "rsi            <not saved>" \
188			 "rdi            <not saved>" \
189			 "rbp            $hex +$hex" \
190			 "rsp            $caller_sp +$caller_sp" \
191			 "r8             <not saved>" \
192			 "r9             <not saved>" \
193			 "r10            <not saved>" \
194			 "r11            <not saved>" \
195			 "r12            <not saved>" \
196			 "r13            <not saved>" \
197			 "r14            <not saved>" \
198			 "r15            <not saved>" \
199			 "rip            $hex +$hex $any" \
200			 "eflags         <not saved>" \
201			 "cs             <not saved>" \
202			 "ss             <not saved>" \
203			 "ds             <not saved>" \
204			 "es             <not saved>" \
205			 "fs             <not saved>" \
206			 "gs             <not saved>" \
207			]
208
209		# There may be more registers.
210		append expected ".*"
211
212		gdb_test "info registers" $expected
213
214		# Make sure that "info frame" doesn't crash.
215		gdb_test "info frame" "Stack level 1, .*in main.*"
216
217		# ... and that neither does printing a pseudo
218		# register.
219		gdb_test "print /x \$ebp" " = $hex" "print pseudo register"
220
221		# There's no way for the JIT reader API to support
222		# modifyiable values.
223		gdb_test "print \$rbp = -1" \
224		    "Attempt to assign to an unmodifiable value\." \
225		    "cannot assign to register"
226	    }
227
228	    if { ![skip_python_tests] } {
229		gdb_test "python print(gdb.objfiles())" \
230		    "$any<gdb.Objfile filename=<< JIT compiled code at $hex >>>$any" \
231		    "python gdb.Objfile.__repr__ ()"
232
233		gdb_test "python print(list(map(lambda objf : objf.filename, gdb.objfiles())))" \
234		    "$any'<< JIT compiled code at $hex >>'$any" \
235		    "python gdb.Objfile.filename"
236	    }
237	}
238    }
239
240    # Now unload the jit reader, and ensure that backtracing really
241    # doesn't work without it.
242    with_test_prefix "without jit-reader" {
243	gdb_test_no_output "jit-reader-unload ${jit_reader_bin}" \
244	    "jit-reader-unload"
245
246	# Check that we're no longer using the JIT unwinder, and that
247	# the built-in unwinder cannot backtrace through the mangled
248	# stack pointer.
249	gdb_test "bt" \
250	    "Backtrace stopped: Cannot access memory at address $sp_after_mangling" \
251	    "bt shows error"
252
253	gdb_test "info frame" "Cannot access memory at address.*" \
254	    "info frame shows error"
255	info_registers_current_frame $sp_after_mangling
256	gdb_test "up" "Initial frame selected; you cannot go up\\." \
257	    "cannot go up"
258    }
259
260    with_test_prefix "with jit-reader again" {
261	gdb_test_no_output "jit-reader-load ${jit_reader_bin}" "jit-reader-load"
262
263	# Check that the jit unwinder manages to backtrace through
264	# the mangled stack pointer.
265	gdb_test "bt" \
266	    [multi_line \
267		 "#0 ${any} in jit_function_stack_mangle ${any}" \
268		 "#1 ${any} in main ${any}" \
269		]
270    }
271
272    if {![skip_python_tests]} {
273	gdb_test "python print(any(\[not x.is_file for x in gdb.objfiles()\]))" \
274	    "True" \
275	    "at least one non-file objfile"
276	gdb_test "python print(any(\[x.is_file for x in gdb.objfiles()\]))" \
277	    "True" \
278	    "at least one file-based objfile"
279    }
280
281    with_test_prefix "test dwarf unwinder" {
282	# Check that the DWARF unwinder does not crash in presence of
283	# JIT objfiles.
284	gdb_test "up"
285	gdb_breakpoint "*function_add" temporary
286	gdb_test "cont" ".*Temporary breakpoint ${any} in jit_function_add .*"
287	gdb_test "bt" \
288	    [multi_line \
289		 "#0 ${any} in jit_function_add ${any}" \
290		 "#1 ${any} in main ${any}" \
291		]
292    }
293}
294
295jit_reader_test
296