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 |