xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.arch/insn-reloc.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1 /* This testcase is part of GDB, the GNU debugger.
2 
3    Copyright 2015-2023 Free Software Foundation, Inc.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17 
18 #include <stddef.h>
19 #include <stdint.h>
20 
21 typedef void (*testcase_ftype)(void);
22 
23 /* Each function checks the correctness of the instruction being
24    relocated due to a fast tracepoint.  Call function pass if it is
25    correct, otherwise call function fail.  GDB sets a breakpoints on
26    pass and fail in order to check the correctness.  */
27 
28 static void
29 pass (void)
30 {
31 }
32 
33 static void
34 fail (void)
35 {
36 }
37 
38 #if (defined __x86_64__ || defined __i386__)
39 
40 #ifdef SYMBOL_PREFIX
41 #define SYMBOL(str)     SYMBOL_PREFIX #str
42 #else
43 #define SYMBOL(str)     #str
44 #endif
45 
46 /* Make sure we can relocate a CALL instruction.  CALL instructions are
47    5 bytes long so we can always set a fast tracepoints on them.
48 
49      JMP set_point0
50    f:
51      MOV $1, %[ok]
52      JMP end
53    set_point0:
54      CALL f ; tracepoint here.
55    end:
56 
57    */
58 
59 static void
60 can_relocate_call (void)
61 {
62   int ok = 0;
63 
64   asm ("    .global " SYMBOL (set_point0) "\n"
65        "  jmp " SYMBOL (set_point0) "\n"
66        "0:\n"
67        "  mov $1, %[ok]\n"
68        "  jmp 1f\n"
69        SYMBOL (set_point0) ":\n"
70        "  call 0b\n"
71        "1:\n"
72        : [ok] "=r" (ok));
73 
74   if (ok == 1)
75     pass ();
76   else
77     fail ();
78 }
79 
80 /* Make sure we can relocate a JMP instruction.  We need the JMP
81    instruction to be 5 bytes long in order to set a fast tracepoint on
82    it.  To do this, we emit the opcode directly.
83 
84      JMP next ; tracepoint here.
85    next:
86      MOV $1, %[ok]
87 
88    */
89 
90 static void
91 can_relocate_jump (void)
92 {
93   int ok = 0;
94 
95   asm ("    .global " SYMBOL (set_point1) "\n"
96        SYMBOL (set_point1) ":\n"
97        ".byte 0xe9\n"  /* jmp  */
98        ".byte 0x00\n"
99        ".byte 0x00\n"
100        ".byte 0x00\n"
101        ".byte 0x00\n"
102        "  mov $1, %[ok]\n"
103        : [ok] "=r" (ok));
104 
105   if (ok == 1)
106     pass ();
107   else
108     fail ();
109 }
110 #elif (defined __aarch64__)
111 
112 /* Make sure we can relocate a B instruction.
113 
114      B set_point0
115    set_ok:
116      MOV %[ok], #1
117      B end
118    set_point0:
119      B set_ok ; tracepoint here.
120      MOV %[ok], #0
121    end
122 
123    */
124 
125 static void
126 can_relocate_b (void)
127 {
128   int ok = 0;
129 
130   asm ("  b set_point0\n"
131        "0:\n"
132        "  mov %[ok], #1\n"
133        "  b 1f\n"
134        "set_point0:\n"
135        "  b 0b\n"
136        "  mov %[ok], #0\n"
137        "1:\n"
138        : [ok] "=r" (ok));
139 
140   if (ok == 1)
141     pass ();
142   else
143     fail ();
144 }
145 
146 /* Make sure we can relocate a B.cond instruction.
147 
148      MOV x0, #8
149      TST x0, #8 ; Clear the Z flag.
150      B set_point1
151    set_ok:
152      MOV %[ok], #1
153      B end
154    set_point1:
155      B.NE set_ok ; tracepoint here.
156      MOV %[ok], #0
157    end
158 
159    */
160 
161 static void
162 can_relocate_bcond_true (void)
163 {
164   int ok = 0;
165 
166   asm ("  mov x0, #8\n"
167        "  tst x0, #8\n"
168        "  b set_point1\n"
169        "0:\n"
170        "  mov %[ok], #1\n"
171        "  b 1f\n"
172        "set_point1:\n"
173        "  b.ne 0b\n"
174        "  mov %[ok], #0\n"
175        "1:\n"
176        : [ok] "=r" (ok)
177        :
178        : "0", "cc");
179 
180   if (ok == 1)
181     pass ();
182   else
183     fail ();
184 }
185 
186 /* Make sure we can relocate a CBZ instruction.
187 
188      MOV x0, #0
189      B set_point2
190    set_ok:
191      MOV %[ok], #1
192      B end
193    set_point2:
194      CBZ x0, set_ok ; tracepoint here.
195      MOV %[ok], #0
196    end
197 
198    */
199 
200 static void
201 can_relocate_cbz (void)
202 {
203   int ok = 0;
204 
205   asm ("  mov x0, #0\n"
206        "  b set_point2\n"
207        "0:\n"
208        "  mov %[ok], #1\n"
209        "  b 1f\n"
210        "set_point2:\n"
211        "  cbz x0, 0b\n"
212        "  mov %[ok], #0\n"
213        "1:\n"
214        : [ok] "=r" (ok)
215        :
216        : "0");
217 
218   if (ok == 1)
219     pass ();
220   else
221     fail ();
222 }
223 
224 /* Make sure we can relocate a CBNZ instruction.
225 
226      MOV x0, #8
227      B set_point3
228    set_ok:
229      MOV %[ok], #1
230      B end
231    set_point3:
232      CBNZ x0, set_ok ; tracepoint here.
233      MOV %[ok], #0
234    end
235 
236    */
237 
238 static void
239 can_relocate_cbnz (void)
240 {
241   int ok = 0;
242 
243   asm ("  mov x0, #8\n"
244        "  b set_point3\n"
245        "0:\n"
246        "  mov %[ok], #1\n"
247        "  b 1f\n"
248        "set_point3:\n"
249        "  cbnz x0, 0b\n"
250        "  mov %[ok], #0\n"
251        "1:\n"
252        : [ok] "=r" (ok)
253        :
254        : "0");
255 
256   if (ok == 1)
257     pass ();
258   else
259     fail ();
260 }
261 
262 /* Make sure we can relocate a TBZ instruction.
263 
264      MOV x0, #8
265      MVN x0, x0 ; Clear bit 3.
266      B set_point4
267    set_ok:
268      MOV %[ok], #1
269      B end
270    set_point4:
271      TBZ x0, #3, set_ok ; tracepoint here.
272      MOV %[ok], #0
273    end
274 
275    */
276 
277 static void
278 can_relocate_tbz (void)
279 {
280   int ok = 0;
281 
282   asm ("  mov x0, #8\n"
283        "  mvn x0, x0\n"
284        "  b set_point4\n"
285        "0:\n"
286        "  mov %[ok], #1\n"
287        "  b 1f\n"
288        "set_point4:\n"
289        "  tbz x0, #3, 0b\n"
290        "  mov %[ok], #0\n"
291        "1:\n"
292        : [ok] "=r" (ok)
293        :
294        : "0");
295 
296   if (ok == 1)
297     pass ();
298   else
299     fail ();
300 }
301 
302 /* Make sure we can relocate a TBNZ instruction.
303 
304      MOV x0, #8 ; Set bit 3.
305      B set_point5
306    set_ok:
307      MOV %[ok], #1
308      B end
309    set_point5:
310      TBNZ x0, #3, set_ok ; tracepoint here.
311      MOV %[ok], #0
312    end
313 
314    */
315 
316 static void
317 can_relocate_tbnz (void)
318 {
319   int ok = 0;
320 
321   asm ("  mov x0, #8\n"
322        "  b set_point5\n"
323        "0:\n"
324        "  mov %[ok], #1\n"
325        "  b 1f\n"
326        "set_point5:\n"
327        "  tbnz x0, #3, 0b\n"
328        "  mov %[ok], #0\n"
329        "1:\n"
330        : [ok] "=r" (ok)
331        :
332        : "0");
333 
334   if (ok == 1)
335     pass ();
336   else
337     fail ();
338 }
339 
340 /* Make sure we can relocate an ADR instruction with a positive offset.
341 
342    set_point6:
343      ADR x0, target ; tracepoint here.
344      BR x0 ; jump to target
345      MOV %[ok], #0
346      B end
347    target:
348      MOV %[ok], #1
349    end
350 
351    */
352 
353 static void
354 can_relocate_adr_forward (void)
355 {
356   int ok = 0;
357 
358   asm ("set_point6:\n"
359        "  adr x0, 0f\n"
360        "  br x0\n"
361        "  mov %[ok], #0\n"
362        "  b 1f\n"
363        "0:\n"
364        "  mov %[ok], #1\n"
365        "1:\n"
366        : [ok] "=r" (ok)
367        :
368        : "0");
369 
370   if (ok == 1)
371     pass ();
372   else
373     fail ();
374 }
375 
376 /* Make sure we can relocate an ADR instruction with a negative offset.
377 
378      B set_point7
379    target:
380      MOV %[ok], #1
381      B end
382    set_point7:
383      ADR x0, target ; tracepoint here.
384      BR x0 ; jump to target
385      MOV %[ok], #0
386    end
387 
388    */
389 
390 static void
391 can_relocate_adr_backward (void)
392 {
393   int ok = 0;
394 
395   asm ("b set_point7\n"
396        "0:\n"
397        "  mov %[ok], #1\n"
398        "  b 1f\n"
399        "set_point7:\n"
400        "  adr x0, 0b\n"
401        "  br x0\n"
402        "  mov %[ok], #0\n"
403        "1:\n"
404        : [ok] "=r" (ok)
405        :
406        : "0");
407 
408   if (ok == 1)
409     pass ();
410   else
411     fail ();
412 }
413 
414 /* Make sure we can relocate an ADRP instruction.
415 
416    set_point8:
417      ADRP %[addr], set_point8 ; tracepoint here.
418      ADR %[pc], set_point8
419 
420    ADR computes the address of the given label.  While ADRP gives us its
421    page, on a 4K boundary.  We can check ADRP executed normally by
422    making sure the result of ADR and ADRP are equivalent, except for the
423    12 lowest bits which should be cleared.
424 
425    */
426 
427 static void
428 can_relocate_adrp (void)
429 {
430   uintptr_t page;
431   uintptr_t pc;
432 
433   asm ("set_point8:\n"
434        "  adrp %[page], set_point8\n"
435        "  adr %[pc], set_point8\n"
436        : [page] "=r" (page), [pc] "=r" (pc));
437 
438   if (page == (pc & ~0xfff))
439     pass ();
440   else
441     fail ();
442 }
443 
444 /* Make sure we can relocate an LDR instruction, where the memory to
445    read is an offset from the current PC.
446 
447      B set_point9
448    data:
449      .word 0x0cabba9e
450    set_point9:
451      LDR %[result], data ; tracepoint here.
452 
453    */
454 
455 static void
456 can_relocate_ldr (void)
457 {
458   uint32_t result = 0;
459 
460   asm ("b set_point9\n"
461        "0:\n"
462        "  .word 0x0cabba9e\n"
463        "set_point9:\n"
464        "  ldr %w[result], 0b\n"
465        : [result] "=r" (result));
466 
467   if (result == 0x0cabba9e)
468     pass ();
469   else
470     fail ();
471 }
472 
473 /* Make sure we can relocate a B.cond instruction and condition is false.  */
474 
475 static void
476 can_relocate_bcond_false (void)
477 {
478   int ok = 0;
479 
480   asm ("  mov x0, #8\n"
481        "  tst x0, #8\n" /* Clear the Z flag.  */
482        "set_point10:\n" /* Set tracepoint here.  */
483        "  b.eq 0b\n"    /* Condition is false.  */
484        "  mov %[ok], #1\n"
485        "  b 1f\n"
486        "0:\n"
487        "  mov %[ok], #0\n"
488        "1:\n"
489        : [ok] "=r" (ok)
490        :
491        : "0", "cc");
492 
493   if (ok == 1)
494     pass ();
495   else
496     fail ();
497 }
498 
499 static void
500 foo (void)
501 {
502 }
503 
504 /* Make sure we can relocate a BL instruction.  */
505 
506 static void
507 can_relocate_bl (void)
508 {
509   asm ("set_point11:\n"
510        "  bl foo\n"
511        "  bl pass\n"
512        : : : "x30"); /* Test that LR is updated correctly.  */
513 }
514 
515 /* Make sure we can relocate a BR instruction.
516 
517      ... Set x0 to target
518    set_point12:
519      BR x0 ; jump to target (tracepoint here).
520      fail()
521      return
522    target:
523      pass()
524    end
525 
526    */
527 
528 static void
529 can_relocate_br (void)
530 {
531   int ok = 0;
532 
533   asm goto ("  adr x0, %l0\n"
534             "set_point12:\n"
535             "  br x0\n"
536             :
537             :
538             : "x0"
539             : madejump);
540 
541   fail ();
542   return;
543 madejump:
544   pass ();
545 }
546 
547 /* Make sure we can relocate a BLR instruction.
548 
549    We use two different functions since the test runner expects one breakpoint
550    per function and we want to test two different things.
551    For BLR we want to test that the BLR actually jumps to the relevant
552    function, *and* that it sets the LR register correctly.
553 
554    Hence we create one testcase that jumps to `pass` using BLR, and one
555    testcase that jumps to `pass` if BLR has set the LR correctly.
556 
557   -- can_relocate_blr_jumps
558      ... Set x0 to pass
559    set_point13:
560      BLR x0        ; jump to pass (tracepoint here).
561 
562   -- can_relocate_blr_sets_lr
563      ... Set x0 to foo
564    set_point14:
565      BLR x0        ; jumps somewhere else (tracepoint here).
566      BL pass       ; ensures the LR was set correctly by the BLR.
567 
568    */
569 
570 static void
571 can_relocate_blr_jumps (void)
572 {
573   int ok = 0;
574 
575   /* Test BLR indeed jumps to the target.  */
576   asm ("set_point13:\n"
577        "  blr %[address]\n"
578        : : [address] "r" (&pass) : "x30");
579 }
580 
581 static void
582 can_relocate_blr_sets_lr (void)
583 {
584   int ok = 0;
585 
586   /* Test BLR sets the LR correctly.  */
587   asm ("set_point14:\n"
588        "  blr %[address]\n"
589        "  bl pass\n"
590        : : [address] "r" (&foo) : "x30");
591 }
592 
593 #endif
594 
595 /* Functions testing relocations need to be placed here.  GDB will read
596    n_testcases to know how many fast tracepoints to place.  It will look
597    for symbols in the form of 'set_point\[0-9\]+' so each functions
598    needs one, starting at 0.  */
599 
600 static testcase_ftype testcases[] = {
601 #if (defined __x86_64__ || defined __i386__)
602   can_relocate_call,
603   can_relocate_jump
604 #elif (defined __aarch64__)
605   can_relocate_b,
606   can_relocate_bcond_true,
607   can_relocate_cbz,
608   can_relocate_cbnz,
609   can_relocate_tbz,
610   can_relocate_tbnz,
611   can_relocate_adr_forward,
612   can_relocate_adr_backward,
613   can_relocate_adrp,
614   can_relocate_ldr,
615   can_relocate_bcond_false,
616   can_relocate_bl,
617   can_relocate_br,
618   can_relocate_blr_jumps,
619   can_relocate_blr_sets_lr,
620 #endif
621 };
622 
623 static size_t n_testcases = (sizeof (testcases) / sizeof (testcase_ftype));
624 
625 int
626 main ()
627 {
628   int i = 0;
629 
630   for (i = 0; i < n_testcases; i++)
631     testcases[i] ();
632 
633   return 0;
634 }
635