ptrace-hwbreak.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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 "ptrace.h"
  22. /* Breakpoint access modes */
  23. enum {
  24. BP_X = 1,
  25. BP_RW = 2,
  26. BP_W = 4,
  27. };
  28. static pid_t child_pid;
  29. static struct ppc_debug_info dbginfo;
  30. static void get_dbginfo(void)
  31. {
  32. int ret;
  33. ret = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
  34. if (ret) {
  35. perror("Can't get breakpoint info\n");
  36. exit(-1);
  37. }
  38. }
  39. static bool hwbreak_present(void)
  40. {
  41. return (dbginfo.num_data_bps != 0);
  42. }
  43. static bool dawr_present(void)
  44. {
  45. return !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
  46. }
  47. static void set_breakpoint_addr(void *addr)
  48. {
  49. int ret;
  50. ret = ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, addr);
  51. if (ret) {
  52. perror("Can't set breakpoint addr\n");
  53. exit(-1);
  54. }
  55. }
  56. static int set_hwbreakpoint_addr(void *addr, int range)
  57. {
  58. int ret;
  59. struct ppc_hw_breakpoint info;
  60. info.version = 1;
  61. info.trigger_type = PPC_BREAKPOINT_TRIGGER_RW;
  62. info.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
  63. if (range > 0)
  64. info.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
  65. info.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
  66. info.addr = (__u64)addr;
  67. info.addr2 = (__u64)addr + range;
  68. info.condition_value = 0;
  69. ret = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
  70. if (ret < 0) {
  71. perror("Can't set breakpoint\n");
  72. exit(-1);
  73. }
  74. return ret;
  75. }
  76. static int del_hwbreakpoint_addr(int watchpoint_handle)
  77. {
  78. int ret;
  79. ret = ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, watchpoint_handle);
  80. if (ret < 0) {
  81. perror("Can't delete hw breakpoint\n");
  82. exit(-1);
  83. }
  84. return ret;
  85. }
  86. #define DAWR_LENGTH_MAX 512
  87. /* Dummy variables to test read/write accesses */
  88. static unsigned long long
  89. dummy_array[DAWR_LENGTH_MAX / sizeof(unsigned long long)]
  90. __attribute__((aligned(512)));
  91. static unsigned long long *dummy_var = dummy_array;
  92. static void write_var(int len)
  93. {
  94. long long *plval;
  95. char *pcval;
  96. short *psval;
  97. int *pival;
  98. switch (len) {
  99. case 1:
  100. pcval = (char *)dummy_var;
  101. *pcval = 0xff;
  102. break;
  103. case 2:
  104. psval = (short *)dummy_var;
  105. *psval = 0xffff;
  106. break;
  107. case 4:
  108. pival = (int *)dummy_var;
  109. *pival = 0xffffffff;
  110. break;
  111. case 8:
  112. plval = (long long *)dummy_var;
  113. *plval = 0xffffffffffffffffLL;
  114. break;
  115. }
  116. }
  117. static void read_var(int len)
  118. {
  119. char cval __attribute__((unused));
  120. short sval __attribute__((unused));
  121. int ival __attribute__((unused));
  122. long long lval __attribute__((unused));
  123. switch (len) {
  124. case 1:
  125. cval = *(char *)dummy_var;
  126. break;
  127. case 2:
  128. sval = *(short *)dummy_var;
  129. break;
  130. case 4:
  131. ival = *(int *)dummy_var;
  132. break;
  133. case 8:
  134. lval = *(long long *)dummy_var;
  135. break;
  136. }
  137. }
  138. /*
  139. * Do the r/w accesses to trigger the breakpoints. And run
  140. * the usual traps.
  141. */
  142. static void trigger_tests(void)
  143. {
  144. int len, ret;
  145. ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
  146. if (ret) {
  147. perror("Can't be traced?\n");
  148. return;
  149. }
  150. /* Wake up father so that it sets up the first test */
  151. kill(getpid(), SIGUSR1);
  152. /* Test write watchpoints */
  153. for (len = 1; len <= sizeof(long); len <<= 1)
  154. write_var(len);
  155. /* Test read/write watchpoints (on read accesses) */
  156. for (len = 1; len <= sizeof(long); len <<= 1)
  157. read_var(len);
  158. /* Test when breakpoint is unset */
  159. /* Test write watchpoints */
  160. for (len = 1; len <= sizeof(long); len <<= 1)
  161. write_var(len);
  162. /* Test read/write watchpoints (on read accesses) */
  163. for (len = 1; len <= sizeof(long); len <<= 1)
  164. read_var(len);
  165. }
  166. static void check_success(const char *msg)
  167. {
  168. const char *msg2;
  169. int status;
  170. /* Wait for the child to SIGTRAP */
  171. wait(&status);
  172. msg2 = "Failed";
  173. if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
  174. msg2 = "Child process hit the breakpoint";
  175. }
  176. printf("%s Result: [%s]\n", msg, msg2);
  177. }
  178. static void launch_watchpoints(char *buf, int mode, int len,
  179. struct ppc_debug_info *dbginfo, bool dawr)
  180. {
  181. const char *mode_str;
  182. unsigned long data = (unsigned long)(dummy_var);
  183. int wh, range;
  184. data &= ~0x7UL;
  185. if (mode == BP_W) {
  186. data |= (1UL << 1);
  187. mode_str = "write";
  188. } else {
  189. data |= (1UL << 0);
  190. data |= (1UL << 1);
  191. mode_str = "read";
  192. }
  193. /* Set DABR_TRANSLATION bit */
  194. data |= (1UL << 2);
  195. /* use PTRACE_SET_DEBUGREG breakpoints */
  196. set_breakpoint_addr((void *)data);
  197. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  198. sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
  199. check_success(buf);
  200. /* Unregister hw brkpoint */
  201. set_breakpoint_addr(NULL);
  202. data = (data & ~7); /* remove dabr control bits */
  203. /* use PPC_PTRACE_SETHWDEBUG breakpoint */
  204. if (!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
  205. return; /* not supported */
  206. wh = set_hwbreakpoint_addr((void *)data, 0);
  207. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  208. sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
  209. check_success(buf);
  210. /* Unregister hw brkpoint */
  211. del_hwbreakpoint_addr(wh);
  212. /* try a wider range */
  213. range = 8;
  214. if (dawr)
  215. range = 512 - ((int)data & (DAWR_LENGTH_MAX - 1));
  216. wh = set_hwbreakpoint_addr((void *)data, range);
  217. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  218. sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
  219. check_success(buf);
  220. /* Unregister hw brkpoint */
  221. del_hwbreakpoint_addr(wh);
  222. }
  223. /* Set the breakpoints and check the child successfully trigger them */
  224. static int launch_tests(bool dawr)
  225. {
  226. char buf[1024];
  227. int len, i, status;
  228. struct ppc_debug_info dbginfo;
  229. i = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
  230. if (i) {
  231. perror("Can't set breakpoint info\n");
  232. exit(-1);
  233. }
  234. if (!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
  235. printf("WARNING: Kernel doesn't support PPC_PTRACE_SETHWDEBUG\n");
  236. /* Write watchpoint */
  237. for (len = 1; len <= sizeof(long); len <<= 1)
  238. launch_watchpoints(buf, BP_W, len, &dbginfo, dawr);
  239. /* Read-Write watchpoint */
  240. for (len = 1; len <= sizeof(long); len <<= 1)
  241. launch_watchpoints(buf, BP_RW, len, &dbginfo, dawr);
  242. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  243. /*
  244. * Now we have unregistered the breakpoint, access by child
  245. * should not cause SIGTRAP.
  246. */
  247. wait(&status);
  248. if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
  249. printf("FAIL: Child process hit the breakpoint, which is not expected\n");
  250. ptrace(PTRACE_CONT, child_pid, NULL, 0);
  251. return TEST_FAIL;
  252. }
  253. if (WIFEXITED(status))
  254. printf("Child exited normally\n");
  255. return TEST_PASS;
  256. }
  257. static int ptrace_hwbreak(void)
  258. {
  259. pid_t pid;
  260. int ret;
  261. bool dawr;
  262. pid = fork();
  263. if (!pid) {
  264. trigger_tests();
  265. return 0;
  266. }
  267. wait(NULL);
  268. child_pid = pid;
  269. get_dbginfo();
  270. SKIP_IF(!hwbreak_present());
  271. dawr = dawr_present();
  272. ret = launch_tests(dawr);
  273. wait(NULL);
  274. return ret;
  275. }
  276. int main(int argc, char **argv, char **envp)
  277. {
  278. return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
  279. }