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