xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.arch/insn-reloc.c (revision aef5eb5f59cdfe8314f1b5f78ac04eb144e44010)
1 /* This testcase is part of GDB, the GNU debugger.
2 
3    Copyright 2015-2019 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 #endif
516 
517 /* Functions testing relocations need to be placed here.  GDB will read
518    n_testcases to know how many fast tracepoints to place.  It will look
519    for symbols in the form of 'set_point\[0-9\]+' so each functions
520    needs one, starting at 0.  */
521 
522 static testcase_ftype testcases[] = {
523 #if (defined __x86_64__ || defined __i386__)
524   can_relocate_call,
525   can_relocate_jump
526 #elif (defined __aarch64__)
527   can_relocate_b,
528   can_relocate_bcond_true,
529   can_relocate_cbz,
530   can_relocate_cbnz,
531   can_relocate_tbz,
532   can_relocate_tbnz,
533   can_relocate_adr_forward,
534   can_relocate_adr_backward,
535   can_relocate_adrp,
536   can_relocate_ldr,
537   can_relocate_bcond_false,
538   can_relocate_bl,
539 #endif
540 };
541 
542 static size_t n_testcases = (sizeof (testcases) / sizeof (testcase_ftype));
543 
544 int
545 main ()
546 {
547   int i = 0;
548 
549   for (i = 0; i < n_testcases; i++)
550     testcases[i] ();
551 
552   return 0;
553 }
554