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