| 1 | #include <stdbool.h> |
|---|---|
| 2 | #include <stdint.h> |
| 3 | |
| 4 | uint64_t get_tpidr(void) { |
| 5 | uint64_t tpidr = 0; |
| 6 | __asm__ volatile("mrs %0, tpidr_el0": "=r"(tpidr)); |
| 7 | return tpidr; |
| 8 | } |
| 9 | |
| 10 | uint64_t get_tpidr2(void) { |
| 11 | uint64_t tpidr2 = 0; |
| 12 | // S3_3_C13_C0_5 means tpidr2, and will work with older tools. |
| 13 | __asm__ volatile("mrs %0, S3_3_C13_C0_5": "=r"(tpidr2)); |
| 14 | return tpidr2; |
| 15 | } |
| 16 | |
| 17 | void set_tpidr(uint64_t value) { |
| 18 | __asm__ volatile("msr tpidr_el0, %0":: "r"(value)); |
| 19 | } |
| 20 | |
| 21 | void set_tpidr2(uint64_t value) { |
| 22 | __asm__ volatile("msr S3_3_C13_C0_5, %0":: "r"(value)); |
| 23 | } |
| 24 | |
| 25 | bool use_tpidr2 = false; |
| 26 | const uint64_t tpidr_pattern = 0x1122334455667788; |
| 27 | const uint64_t tpidr2_pattern = 0x8877665544332211; |
| 28 | |
| 29 | void expr_func() { |
| 30 | set_tpidr(~tpidr_pattern); |
| 31 | if (use_tpidr2) |
| 32 | set_tpidr2(~tpidr2_pattern); |
| 33 | } |
| 34 | |
| 35 | int main(int argc, char *argv[]) { |
| 36 | use_tpidr2 = argc > 1; |
| 37 | |
| 38 | uint64_t original_tpidr = get_tpidr(); |
| 39 | // Accessing this on a core without it produces SIGILL. Only do this if |
| 40 | // requested. |
| 41 | uint64_t original_tpidr2 = 0; |
| 42 | if (use_tpidr2) |
| 43 | original_tpidr2 = get_tpidr2(); |
| 44 | |
| 45 | set_tpidr(tpidr_pattern); |
| 46 | |
| 47 | if (use_tpidr2) |
| 48 | set_tpidr2(tpidr2_pattern); |
| 49 | |
| 50 | // Set break point at this line. |
| 51 | // lldb will now set its own pattern(s) for us to find. |
| 52 | |
| 53 | uint64_t new_tpidr = get_tpidr(); |
| 54 | volatile bool tpidr_was_set = new_tpidr == 0x1111222233334444; |
| 55 | |
| 56 | uint64_t new_tpidr2 = 0; |
| 57 | volatile bool tpidr2_was_set = false; |
| 58 | if (use_tpidr2) { |
| 59 | new_tpidr2 = get_tpidr2(); |
| 60 | tpidr2_was_set = new_tpidr2 == 0x4444333322221111; |
| 61 | } |
| 62 | |
| 63 | set_tpidr(original_tpidr); |
| 64 | if (use_tpidr2) |
| 65 | set_tpidr2(original_tpidr2); |
| 66 | |
| 67 | return 0; // Set break point 2 at this line. |
| 68 | } |
| 69 |
