This source file includes following definitions.
- get_dbginfo
- hwbreak_present
- dawr_present
- set_breakpoint_addr
- set_hwbreakpoint_addr
- del_hwbreakpoint_addr
- write_var
- read_var
- trigger_tests
- check_success
- launch_watchpoints
- launch_tests
- ptrace_hwbreak
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <sys/ptrace.h>
15 #include <unistd.h>
16 #include <stddef.h>
17 #include <sys/user.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <signal.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include "ptrace.h"
24
25
26 enum {
27 BP_X = 1,
28 BP_RW = 2,
29 BP_W = 4,
30 };
31
32 static pid_t child_pid;
33 static struct ppc_debug_info dbginfo;
34
35 static void get_dbginfo(void)
36 {
37 int ret;
38
39 ret = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
40 if (ret) {
41 perror("Can't get breakpoint info\n");
42 exit(-1);
43 }
44 }
45
46 static bool hwbreak_present(void)
47 {
48 return (dbginfo.num_data_bps != 0);
49 }
50
51 static bool dawr_present(void)
52 {
53 return !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
54 }
55
56 static void set_breakpoint_addr(void *addr)
57 {
58 int ret;
59
60 ret = ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, addr);
61 if (ret) {
62 perror("Can't set breakpoint addr\n");
63 exit(-1);
64 }
65 }
66
67 static int set_hwbreakpoint_addr(void *addr, int range)
68 {
69 int ret;
70
71 struct ppc_hw_breakpoint info;
72
73 info.version = 1;
74 info.trigger_type = PPC_BREAKPOINT_TRIGGER_RW;
75 info.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
76 if (range > 0)
77 info.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
78 info.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
79 info.addr = (__u64)addr;
80 info.addr2 = (__u64)addr + range;
81 info.condition_value = 0;
82
83 ret = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
84 if (ret < 0) {
85 perror("Can't set breakpoint\n");
86 exit(-1);
87 }
88 return ret;
89 }
90
91 static int del_hwbreakpoint_addr(int watchpoint_handle)
92 {
93 int ret;
94
95 ret = ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, watchpoint_handle);
96 if (ret < 0) {
97 perror("Can't delete hw breakpoint\n");
98 exit(-1);
99 }
100 return ret;
101 }
102
103 #define DAWR_LENGTH_MAX 512
104
105
106 static unsigned long long
107 dummy_array[DAWR_LENGTH_MAX / sizeof(unsigned long long)]
108 __attribute__((aligned(512)));
109 static unsigned long long *dummy_var = dummy_array;
110
111 static void write_var(int len)
112 {
113 long long *plval;
114 char *pcval;
115 short *psval;
116 int *pival;
117
118 switch (len) {
119 case 1:
120 pcval = (char *)dummy_var;
121 *pcval = 0xff;
122 break;
123 case 2:
124 psval = (short *)dummy_var;
125 *psval = 0xffff;
126 break;
127 case 4:
128 pival = (int *)dummy_var;
129 *pival = 0xffffffff;
130 break;
131 case 8:
132 plval = (long long *)dummy_var;
133 *plval = 0xffffffffffffffffLL;
134 break;
135 }
136 }
137
138 static void read_var(int len)
139 {
140 char cval __attribute__((unused));
141 short sval __attribute__((unused));
142 int ival __attribute__((unused));
143 long long lval __attribute__((unused));
144
145 switch (len) {
146 case 1:
147 cval = *(char *)dummy_var;
148 break;
149 case 2:
150 sval = *(short *)dummy_var;
151 break;
152 case 4:
153 ival = *(int *)dummy_var;
154 break;
155 case 8:
156 lval = *(long long *)dummy_var;
157 break;
158 }
159 }
160
161
162
163
164
165 static void trigger_tests(void)
166 {
167 int len, ret;
168
169 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
170 if (ret) {
171 perror("Can't be traced?\n");
172 return;
173 }
174
175
176 kill(getpid(), SIGUSR1);
177
178
179 for (len = 1; len <= sizeof(long); len <<= 1)
180 write_var(len);
181
182
183 for (len = 1; len <= sizeof(long); len <<= 1)
184 read_var(len);
185
186
187
188
189 for (len = 1; len <= sizeof(long); len <<= 1)
190 write_var(len);
191
192
193 for (len = 1; len <= sizeof(long); len <<= 1)
194 read_var(len);
195 }
196
197 static void check_success(const char *msg)
198 {
199 const char *msg2;
200 int status;
201
202
203 wait(&status);
204
205 msg2 = "Failed";
206
207 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
208 msg2 = "Child process hit the breakpoint";
209 }
210
211 printf("%s Result: [%s]\n", msg, msg2);
212 }
213
214 static void launch_watchpoints(char *buf, int mode, int len,
215 struct ppc_debug_info *dbginfo, bool dawr)
216 {
217 const char *mode_str;
218 unsigned long data = (unsigned long)(dummy_var);
219 int wh, range;
220
221 data &= ~0x7UL;
222
223 if (mode == BP_W) {
224 data |= (1UL << 1);
225 mode_str = "write";
226 } else {
227 data |= (1UL << 0);
228 data |= (1UL << 1);
229 mode_str = "read";
230 }
231
232
233 data |= (1UL << 2);
234
235
236 set_breakpoint_addr((void *)data);
237 ptrace(PTRACE_CONT, child_pid, NULL, 0);
238 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
239 check_success(buf);
240
241 set_breakpoint_addr(NULL);
242
243 data = (data & ~7);
244
245
246 if (!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
247 return;
248 wh = set_hwbreakpoint_addr((void *)data, 0);
249 ptrace(PTRACE_CONT, child_pid, NULL, 0);
250 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
251 check_success(buf);
252
253 del_hwbreakpoint_addr(wh);
254
255
256 range = 8;
257 if (dawr)
258 range = 512 - ((int)data & (DAWR_LENGTH_MAX - 1));
259 wh = set_hwbreakpoint_addr((void *)data, range);
260 ptrace(PTRACE_CONT, child_pid, NULL, 0);
261 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
262 check_success(buf);
263
264 del_hwbreakpoint_addr(wh);
265 }
266
267
268 static int launch_tests(bool dawr)
269 {
270 char buf[1024];
271 int len, i, status;
272
273 struct ppc_debug_info dbginfo;
274
275 i = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
276 if (i) {
277 perror("Can't set breakpoint info\n");
278 exit(-1);
279 }
280 if (!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
281 printf("WARNING: Kernel doesn't support PPC_PTRACE_SETHWDEBUG\n");
282
283
284 for (len = 1; len <= sizeof(long); len <<= 1)
285 launch_watchpoints(buf, BP_W, len, &dbginfo, dawr);
286
287
288 for (len = 1; len <= sizeof(long); len <<= 1)
289 launch_watchpoints(buf, BP_RW, len, &dbginfo, dawr);
290
291 ptrace(PTRACE_CONT, child_pid, NULL, 0);
292
293
294
295
296
297
298 wait(&status);
299
300 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
301 printf("FAIL: Child process hit the breakpoint, which is not expected\n");
302 ptrace(PTRACE_CONT, child_pid, NULL, 0);
303 return TEST_FAIL;
304 }
305
306 if (WIFEXITED(status))
307 printf("Child exited normally\n");
308
309 return TEST_PASS;
310 }
311
312 static int ptrace_hwbreak(void)
313 {
314 pid_t pid;
315 int ret;
316 bool dawr;
317
318 pid = fork();
319 if (!pid) {
320 trigger_tests();
321 return 0;
322 }
323
324 wait(NULL);
325
326 child_pid = pid;
327
328 get_dbginfo();
329 SKIP_IF(!hwbreak_present());
330 dawr = dawr_present();
331
332 ret = launch_tests(dawr);
333
334 wait(NULL);
335
336 return ret;
337 }
338
339 int main(int argc, char **argv, char **envp)
340 {
341 return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
342 }