ptrace-hwbreak.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Ptrace test for hw breakpoints
  4. *
  5. * Based on tools/testing/selftests/breakpoints/breakpoint_test.c
  6. *
  7. * This test forks and the parent then traces the child doing various
  8. * types of ptrace enabled breakpoints
  9. *
  10. * Copyright (C) 2018 Michael Neuling, IBM Corporation.
  11. */
  12. #include <sys/ptrace.h>
  13. #include <unistd.h>
  14. #include <stddef.h>
  15. #include <sys/user.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <signal.h>
  19. #include <sys/types.h>
  20. #include <sys/wait.h>
  21. #include <sys/syscall.h>
  22. #include <linux/limits.h>
  23. #include "ptrace.h"
  24. #define SPRN_PVR 0x11F
  25. #define PVR_8xx 0x00500000
  26. bool is_8xx;
  27. /*
  28. * Use volatile on all global var so that compiler doesn't
  29. * optimise their load/stores. Otherwise selftest can fail.
  30. */
  31. static volatile __u64 glvar;
  32. #define DAWR_MAX_LEN 512
  33. static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));
  34. #define A_LEN 6
  35. #define B_LEN 6
  36. struct gstruct {
  37. __u8 a[A_LEN]; /* double word aligned */
  38. __u8 b[B_LEN]; /* double word unaligned */
  39. };
  40. static volatile struct gstruct gstruct __attribute__((aligned(512)));
  41. static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));
  42. static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
  43. {
  44. if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
  45. perror("Can't get breakpoint info");
  46. exit(-1);
  47. }
  48. }
  49. static bool dawr_present(struct ppc_debug_info *dbginfo)
  50. {
  51. return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
  52. }
  53. static void write_var(int len)
  54. {
  55. __u8 *pcvar;
  56. __u16 *psvar;
  57. __u32 *pivar;
  58. __u64 *plvar;
  59. switch (len) {
  60. case 1:
  61. pcvar = (__u8 *)&glvar;
  62. *pcvar = 0xff;
  63. break;
  64. case 2:
  65. psvar = (__u16 *)&glvar;
  66. *psvar = 0xffff;
  67. break;
  68. case 4:
  69. pivar = (__u32 *)&glvar;
  70. *pivar = 0xffffffff;
  71. break;
  72. case 8:
  73. plvar = (__u64 *)&glvar;
  74. *plvar = 0xffffffffffffffffLL;
  75. break;
  76. }
  77. }
  78. static void read_var(int len)
  79. {
  80. __u8 cvar __attribute__((unused));
  81. __u16 svar __attribute__((unused));
  82. __u32 ivar __attribute__((unused));
  83. __u64 lvar __attribute__((unused));
  84. switch (len) {
  85. case 1:
  86. cvar = (__u8)glvar;
  87. break;
  88. case 2:
  89. svar = (__u16)glvar;
  90. break;
  91. case 4:
  92. ivar = (__u32)glvar;
  93. break;
  94. case 8:
  95. lvar = (__u64)glvar;
  96. break;
  97. }
  98. }
  99. static void test_workload(void)
  100. {
  101. __u8 cvar __attribute__((unused));
  102. __u32 ivar __attribute__((unused));
  103. int len = 0;
  104. if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) {
  105. perror("Child can't be traced?");
  106. exit(-1);
  107. }
  108. /* Wake up father so that it sets up the first test */
  109. kill(getpid(), SIGUSR1);
  110. /* PTRACE_SET_DEBUGREG, WO test */
  111. for (len = 1; len <= sizeof(glvar); len <<= 1)
  112. write_var(len);
  113. /* PTRACE_SET_DEBUGREG, RO test */
  114. for (len = 1; len <= sizeof(glvar); len <<= 1)
  115. read_var(len);
  116. /* PTRACE_SET_DEBUGREG, RW test */
  117. for (len = 1; len <= sizeof(glvar); len <<= 1) {
  118. if (rand() % 2)
  119. read_var(len);
  120. else
  121. write_var(len);
  122. }
  123. /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
  124. syscall(__NR_getcwd, &cwd, PATH_MAX);
  125. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
  126. write_var(1);
  127. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
  128. read_var(1);
  129. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
  130. if (rand() % 2)
  131. write_var(1);
  132. else
  133. read_var(1);
  134. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
  135. syscall(__NR_getcwd, &cwd, PATH_MAX);
  136. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
  137. gstruct.a[rand() % A_LEN] = 'a';
  138. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
  139. cvar = gstruct.a[rand() % A_LEN];
  140. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
  141. if (rand() % 2)
  142. gstruct.a[rand() % A_LEN] = 'a';
  143. else
  144. cvar = gstruct.a[rand() % A_LEN];
  145. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
  146. gstruct.b[rand() % B_LEN] = 'b';
  147. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
  148. cvar = gstruct.b[rand() % B_LEN];
  149. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
  150. if (rand() % 2)
  151. gstruct.b[rand() % B_LEN] = 'b';
  152. else
  153. cvar = gstruct.b[rand() % B_LEN];
  154. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
  155. if (rand() % 2)
  156. *((int *)(gstruct.a + 4)) = 10;
  157. else
  158. ivar = *((int *)(gstruct.a + 4));
  159. /* PPC_PTRACE_SETHWDEBUG. DAWR_MAX_LEN. RW test */
  160. if (rand() % 2)
  161. big_var[rand() % DAWR_MAX_LEN] = 'a';
  162. else
  163. cvar = big_var[rand() % DAWR_MAX_LEN];
  164. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
  165. gstruct.a[rand() % A_LEN] = 'a';
  166. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
  167. cvar = gstruct.b[rand() % B_LEN];
  168. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
  169. gstruct.a[rand() % A_LEN] = 'a';
  170. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
  171. cvar = gstruct.a[rand() % A_LEN];
  172. }
  173. static void check_success(pid_t child_pid, const char *name, const char *type,
  174. unsigned long saddr, int len)
  175. {
  176. int status;
  177. siginfo_t siginfo;
  178. unsigned long eaddr = (saddr + len - 1) | 0x7;
  179. saddr &= ~0x7;
  180. /* Wait for the child to SIGTRAP */
  181. wait(&status);
  182. ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo);
  183. if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
  184. (unsigned long)siginfo.si_addr < saddr ||
  185. (unsigned long)siginfo.si_addr > eaddr) {
  186. printf("%s, %s, len: %d: Fail\n", name, type, len);
  187. exit(-1);
  188. }
  189. printf("%s, %s, len: %d: Ok\n", name, type, len);
  190. if (!is_8xx) {
  191. /*
  192. * For ptrace registered watchpoint, signal is generated
  193. * before executing load/store. Singlestep the instruction
  194. * and then continue the test.
  195. */
  196. ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);
  197. wait(NULL);
  198. }
  199. }
  200. static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr)
  201. {
  202. if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) {
  203. perror("PTRACE_SET_DEBUGREG failed");
  204. exit(-1);
  205. }
  206. }
  207. static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info)
  208. {
  209. int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info);
  210. if (wh <= 0) {
  211. perror("PPC_PTRACE_SETHWDEBUG failed");
  212. exit(-1);
  213. }
  214. return wh;
  215. }
  216. static void ptrace_delhwdebug(pid_t child_pid, int wh)
  217. {
  218. if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) {
  219. perror("PPC_PTRACE_DELHWDEBUG failed");
  220. exit(-1);
  221. }
  222. }
  223. #define DABR_READ_SHIFT 0
  224. #define DABR_WRITE_SHIFT 1
  225. #define DABR_TRANSLATION_SHIFT 2
  226. static int test_set_debugreg(pid_t child_pid)
  227. {
  228. unsigned long wp_addr = (unsigned long)&glvar;
  229. char *name = "PTRACE_SET_DEBUGREG";
  230. int len;
  231. /* PTRACE_SET_DEBUGREG, WO test*/
  232. wp_addr &= ~0x7UL;
  233. wp_addr |= (1UL << DABR_WRITE_SHIFT);
  234. wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
  235. for (len = 1; len <= sizeof(glvar); len <<= 1) {
  236. ptrace_set_debugreg(child_pid, wp_addr);
  237. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  238. check_success(child_pid, name, "WO", wp_addr, len);
  239. }
  240. /* PTRACE_SET_DEBUGREG, RO test */
  241. wp_addr &= ~0x7UL;
  242. wp_addr |= (1UL << DABR_READ_SHIFT);
  243. wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
  244. for (len = 1; len <= sizeof(glvar); len <<= 1) {
  245. ptrace_set_debugreg(child_pid, wp_addr);
  246. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  247. check_success(child_pid, name, "RO", wp_addr, len);
  248. }
  249. /* PTRACE_SET_DEBUGREG, RW test */
  250. wp_addr &= ~0x7UL;
  251. wp_addr |= (1Ul << DABR_READ_SHIFT);
  252. wp_addr |= (1UL << DABR_WRITE_SHIFT);
  253. wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
  254. for (len = 1; len <= sizeof(glvar); len <<= 1) {
  255. ptrace_set_debugreg(child_pid, wp_addr);
  256. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  257. check_success(child_pid, name, "RW", wp_addr, len);
  258. }
  259. ptrace_set_debugreg(child_pid, 0);
  260. return 0;
  261. }
  262. static int test_set_debugreg_kernel_userspace(pid_t child_pid)
  263. {
  264. unsigned long wp_addr = (unsigned long)cwd;
  265. char *name = "PTRACE_SET_DEBUGREG";
  266. /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
  267. wp_addr &= ~0x7UL;
  268. wp_addr |= (1Ul << DABR_READ_SHIFT);
  269. wp_addr |= (1UL << DABR_WRITE_SHIFT);
  270. wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
  271. ptrace_set_debugreg(child_pid, wp_addr);
  272. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  273. check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8);
  274. ptrace_set_debugreg(child_pid, 0);
  275. return 0;
  276. }
  277. static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
  278. unsigned long addr, int len)
  279. {
  280. info->version = 1;
  281. info->trigger_type = type;
  282. info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
  283. info->addr = (__u64)addr;
  284. info->addr2 = (__u64)addr + len;
  285. info->condition_value = 0;
  286. if (!len)
  287. info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
  288. else
  289. info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
  290. }
  291. static void test_sethwdebug_exact(pid_t child_pid)
  292. {
  293. struct ppc_hw_breakpoint info;
  294. unsigned long wp_addr = (unsigned long)&glvar;
  295. char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
  296. int len = 1; /* hardcoded in kernel */
  297. int wh;
  298. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
  299. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
  300. wh = ptrace_sethwdebug(child_pid, &info);
  301. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  302. check_success(child_pid, name, "WO", wp_addr, len);
  303. ptrace_delhwdebug(child_pid, wh);
  304. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
  305. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0);
  306. wh = ptrace_sethwdebug(child_pid, &info);
  307. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  308. check_success(child_pid, name, "RO", wp_addr, len);
  309. ptrace_delhwdebug(child_pid, wh);
  310. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
  311. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0);
  312. wh = ptrace_sethwdebug(child_pid, &info);
  313. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  314. check_success(child_pid, name, "RW", wp_addr, len);
  315. ptrace_delhwdebug(child_pid, wh);
  316. }
  317. static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid)
  318. {
  319. struct ppc_hw_breakpoint info;
  320. unsigned long wp_addr = (unsigned long)&cwd;
  321. char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
  322. int len = 1; /* hardcoded in kernel */
  323. int wh;
  324. /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
  325. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
  326. wh = ptrace_sethwdebug(child_pid, &info);
  327. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  328. check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len);
  329. ptrace_delhwdebug(child_pid, wh);
  330. }
  331. static void test_sethwdebug_range_aligned(pid_t child_pid)
  332. {
  333. struct ppc_hw_breakpoint info;
  334. unsigned long wp_addr;
  335. char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED";
  336. int len;
  337. int wh;
  338. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
  339. wp_addr = (unsigned long)&gstruct.a;
  340. len = A_LEN;
  341. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
  342. wh = ptrace_sethwdebug(child_pid, &info);
  343. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  344. check_success(child_pid, name, "WO", wp_addr, len);
  345. ptrace_delhwdebug(child_pid, wh);
  346. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
  347. wp_addr = (unsigned long)&gstruct.a;
  348. len = A_LEN;
  349. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
  350. wh = ptrace_sethwdebug(child_pid, &info);
  351. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  352. check_success(child_pid, name, "RO", wp_addr, len);
  353. ptrace_delhwdebug(child_pid, wh);
  354. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
  355. wp_addr = (unsigned long)&gstruct.a;
  356. len = A_LEN;
  357. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
  358. wh = ptrace_sethwdebug(child_pid, &info);
  359. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  360. check_success(child_pid, name, "RW", wp_addr, len);
  361. ptrace_delhwdebug(child_pid, wh);
  362. }
  363. static void test_multi_sethwdebug_range(pid_t child_pid)
  364. {
  365. struct ppc_hw_breakpoint info1, info2;
  366. unsigned long wp_addr1, wp_addr2;
  367. char *name1 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED";
  368. char *name2 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED";
  369. int len1, len2;
  370. int wh1, wh2;
  371. wp_addr1 = (unsigned long)&gstruct.a;
  372. wp_addr2 = (unsigned long)&gstruct.b;
  373. len1 = A_LEN;
  374. len2 = B_LEN;
  375. get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
  376. get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
  377. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
  378. wh1 = ptrace_sethwdebug(child_pid, &info1);
  379. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
  380. wh2 = ptrace_sethwdebug(child_pid, &info2);
  381. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  382. check_success(child_pid, name1, "WO", wp_addr1, len1);
  383. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  384. check_success(child_pid, name2, "RO", wp_addr2, len2);
  385. ptrace_delhwdebug(child_pid, wh1);
  386. ptrace_delhwdebug(child_pid, wh2);
  387. }
  388. static void test_multi_sethwdebug_range_dawr_overlap(pid_t child_pid)
  389. {
  390. struct ppc_hw_breakpoint info1, info2;
  391. unsigned long wp_addr1, wp_addr2;
  392. char *name = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap";
  393. int len1, len2;
  394. int wh1, wh2;
  395. wp_addr1 = (unsigned long)&gstruct.a;
  396. wp_addr2 = (unsigned long)&gstruct.a;
  397. len1 = A_LEN;
  398. len2 = A_LEN;
  399. get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
  400. get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
  401. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
  402. wh1 = ptrace_sethwdebug(child_pid, &info1);
  403. /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
  404. wh2 = ptrace_sethwdebug(child_pid, &info2);
  405. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  406. check_success(child_pid, name, "WO", wp_addr1, len1);
  407. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  408. check_success(child_pid, name, "RO", wp_addr2, len2);
  409. ptrace_delhwdebug(child_pid, wh1);
  410. ptrace_delhwdebug(child_pid, wh2);
  411. }
  412. static void test_sethwdebug_range_unaligned(pid_t child_pid)
  413. {
  414. struct ppc_hw_breakpoint info;
  415. unsigned long wp_addr;
  416. char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED";
  417. int len;
  418. int wh;
  419. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
  420. wp_addr = (unsigned long)&gstruct.b;
  421. len = B_LEN;
  422. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
  423. wh = ptrace_sethwdebug(child_pid, &info);
  424. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  425. check_success(child_pid, name, "WO", wp_addr, len);
  426. ptrace_delhwdebug(child_pid, wh);
  427. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
  428. wp_addr = (unsigned long)&gstruct.b;
  429. len = B_LEN;
  430. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
  431. wh = ptrace_sethwdebug(child_pid, &info);
  432. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  433. check_success(child_pid, name, "RO", wp_addr, len);
  434. ptrace_delhwdebug(child_pid, wh);
  435. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
  436. wp_addr = (unsigned long)&gstruct.b;
  437. len = B_LEN;
  438. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
  439. wh = ptrace_sethwdebug(child_pid, &info);
  440. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  441. check_success(child_pid, name, "RW", wp_addr, len);
  442. ptrace_delhwdebug(child_pid, wh);
  443. }
  444. static void test_sethwdebug_range_unaligned_dar(pid_t child_pid)
  445. {
  446. struct ppc_hw_breakpoint info;
  447. unsigned long wp_addr;
  448. char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE";
  449. int len;
  450. int wh;
  451. /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
  452. wp_addr = (unsigned long)&gstruct.b;
  453. len = B_LEN;
  454. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
  455. wh = ptrace_sethwdebug(child_pid, &info);
  456. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  457. check_success(child_pid, name, "RW", wp_addr, len);
  458. ptrace_delhwdebug(child_pid, wh);
  459. }
  460. static void test_sethwdebug_dawr_max_range(pid_t child_pid)
  461. {
  462. struct ppc_hw_breakpoint info;
  463. unsigned long wp_addr;
  464. char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN";
  465. int len;
  466. int wh;
  467. /* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */
  468. wp_addr = (unsigned long)big_var;
  469. len = DAWR_MAX_LEN;
  470. get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
  471. wh = ptrace_sethwdebug(child_pid, &info);
  472. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  473. check_success(child_pid, name, "RW", wp_addr, len);
  474. ptrace_delhwdebug(child_pid, wh);
  475. }
  476. /* Set the breakpoints and check the child successfully trigger them */
  477. static void
  478. run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr)
  479. {
  480. test_set_debugreg(child_pid);
  481. test_set_debugreg_kernel_userspace(child_pid);
  482. test_sethwdebug_exact(child_pid);
  483. test_sethwdebug_exact_kernel_userspace(child_pid);
  484. if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) {
  485. test_sethwdebug_range_aligned(child_pid);
  486. if (dawr || is_8xx) {
  487. test_sethwdebug_range_unaligned(child_pid);
  488. test_sethwdebug_range_unaligned_dar(child_pid);
  489. test_sethwdebug_dawr_max_range(child_pid);
  490. if (dbginfo->num_data_bps > 1) {
  491. test_multi_sethwdebug_range(child_pid);
  492. test_multi_sethwdebug_range_dawr_overlap(child_pid);
  493. }
  494. }
  495. }
  496. }
  497. static int ptrace_hwbreak(void)
  498. {
  499. pid_t child_pid;
  500. struct ppc_debug_info dbginfo;
  501. bool dawr;
  502. child_pid = fork();
  503. if (!child_pid) {
  504. test_workload();
  505. return 0;
  506. }
  507. wait(NULL);
  508. get_dbginfo(child_pid, &dbginfo);
  509. SKIP_IF(dbginfo.num_data_bps == 0);
  510. dawr = dawr_present(&dbginfo);
  511. run_tests(child_pid, &dbginfo, dawr);
  512. /* Let the child exit first. */
  513. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  514. wait(NULL);
  515. /*
  516. * Testcases exits immediately with -1 on any failure. If
  517. * it has reached here, it means all tests were successful.
  518. */
  519. return TEST_PASS;
  520. }
  521. int main(int argc, char **argv, char **envp)
  522. {
  523. int pvr = 0;
  524. asm __volatile__ ("mfspr %0,%1" : "=r"(pvr) : "i"(SPRN_PVR));
  525. if (pvr == PVR_8xx)
  526. is_8xx = true;
  527. return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
  528. }