Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2012
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 11.21 KB | None | 0 0
  1. --- /android/runnymede-gb-crc-2.6.35-1fcdb7b/arch/arm/kernel/ptrace.c   2011-12-22 23:38:37.000000000 -0800
  2. +++ /android/cm-kernel/arch/arm/kernel/ptrace.c 2012-01-16 15:24:36.000000000 -0800
  3. @@ -19,6 +19,8 @@
  4.  #include <linux/init.h>
  5.  #include <linux/signal.h>
  6.  #include <linux/uaccess.h>
  7. +#include <linux/perf_event.h>
  8. +#include <linux/hw_breakpoint.h>
  9.  
  10.  #include <asm/pgtable.h>
  11.  #include <asm/system.h>
  12. @@ -52,6 +54,102 @@
  13.  #define BREAKINST_THUMB    0xde01
  14.  #endif
  15.  
  16. +struct pt_regs_offset {
  17. +   const char *name;
  18. +   int offset;
  19. +};
  20. +
  21. +#define REG_OFFSET_NAME(r) \
  22. +   {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
  23. +#define REG_OFFSET_END {.name = NULL, .offset = 0}
  24. +
  25. +static const struct pt_regs_offset regoffset_table[] = {
  26. +   REG_OFFSET_NAME(r0),
  27. +   REG_OFFSET_NAME(r1),
  28. +   REG_OFFSET_NAME(r2),
  29. +   REG_OFFSET_NAME(r3),
  30. +   REG_OFFSET_NAME(r4),
  31. +   REG_OFFSET_NAME(r5),
  32. +   REG_OFFSET_NAME(r6),
  33. +   REG_OFFSET_NAME(r7),
  34. +   REG_OFFSET_NAME(r8),
  35. +   REG_OFFSET_NAME(r9),
  36. +   REG_OFFSET_NAME(r10),
  37. +   REG_OFFSET_NAME(fp),
  38. +   REG_OFFSET_NAME(ip),
  39. +   REG_OFFSET_NAME(sp),
  40. +   REG_OFFSET_NAME(lr),
  41. +   REG_OFFSET_NAME(pc),
  42. +   REG_OFFSET_NAME(cpsr),
  43. +   REG_OFFSET_NAME(ORIG_r0),
  44. +   REG_OFFSET_END,
  45. +};
  46. +
  47. +/**
  48. + * regs_query_register_offset() - query register offset from its name
  49. + * @name:  the name of a register
  50. + *
  51. + * regs_query_register_offset() returns the offset of a register in struct
  52. + * pt_regs from its name. If the name is invalid, this returns -EINVAL;
  53. + */
  54. +int regs_query_register_offset(const char *name)
  55. +{
  56. +   const struct pt_regs_offset *roff;
  57. +   for (roff = regoffset_table; roff->name != NULL; roff++)
  58. +       if (!strcmp(roff->name, name))
  59. +           return roff->offset;
  60. +   return -EINVAL;
  61. +}
  62. +
  63. +/**
  64. + * regs_query_register_name() - query register name from its offset
  65. + * @offset:    the offset of a register in struct pt_regs.
  66. + *
  67. + * regs_query_register_name() returns the name of a register from its
  68. + * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
  69. + */
  70. +const char *regs_query_register_name(unsigned int offset)
  71. +{
  72. +   const struct pt_regs_offset *roff;
  73. +   for (roff = regoffset_table; roff->name != NULL; roff++)
  74. +       if (roff->offset == offset)
  75. +           return roff->name;
  76. +   return NULL;
  77. +}
  78. +
  79. +/**
  80. + * regs_within_kernel_stack() - check the address in the stack
  81. + * @regs:      pt_regs which contains kernel stack pointer.
  82. + * @addr:      address which is checked.
  83. + *
  84. + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
  85. + * If @addr is within the kernel stack, it returns true. If not, returns false.
  86. + */
  87. +bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
  88. +{
  89. +   return ((addr & ~(THREAD_SIZE - 1))  ==
  90. +       (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
  91. +}
  92. +
  93. +/**
  94. + * regs_get_kernel_stack_nth() - get Nth entry of the stack
  95. + * @regs:  pt_regs which contains kernel stack pointer.
  96. + * @n:     stack entry number.
  97. + *
  98. + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
  99. + * is specified by @regs. If the @n th entry is NOT in the kernel stack,
  100. + * this returns 0.
  101. + */
  102. +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
  103. +{
  104. +   unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
  105. +   addr += n;
  106. +   if (regs_within_kernel_stack(regs, (unsigned long)addr))
  107. +       return *addr;
  108. +   else
  109. +       return 0;
  110. +}
  111. +
  112.  /*
  113.   * this routine will get a word off of the processes privileged stack.
  114.   * the offset is how far from the base addr as stored in the THREAD.
  115. @@ -751,13 +849,241 @@
  116.  }
  117.  #endif
  118.  
  119. -long arch_ptrace(struct task_struct *child, long request, long addr, long data)
  120. +#ifdef CONFIG_HAVE_HW_BREAKPOINT
  121. +/*
  122. + * Convert a virtual register number into an index for a thread_info
  123. + * breakpoint array. Breakpoints are identified using positive numbers
  124. + * whilst watchpoints are negative. The registers are laid out as pairs
  125. + * of (address, control), each pair mapping to a unique hw_breakpoint struct.
  126. + * Register 0 is reserved for describing resource information.
  127. + */
  128. +static int ptrace_hbp_num_to_idx(long num)
  129. +{
  130. +   if (num < 0)
  131. +       num = (ARM_MAX_BRP << 1) - num;
  132. +   return (num - 1) >> 1;
  133. +}
  134. +
  135. +/*
  136. + * Returns the virtual register number for the address of the
  137. + * breakpoint at index idx.
  138. + */
  139. +static long ptrace_hbp_idx_to_num(int idx)
  140. +{
  141. +   long mid = ARM_MAX_BRP << 1;
  142. +   long num = (idx << 1) + 1;
  143. +   return num > mid ? mid - num : num;
  144. +}
  145. +
  146. +/*
  147. + * Handle hitting a HW-breakpoint.
  148. + */
  149. +static void ptrace_hbptriggered(struct perf_event *bp, int unused,
  150. +                    struct perf_sample_data *data,
  151. +                    struct pt_regs *regs)
  152. +{
  153. +   struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
  154. +   long num;
  155. +   int i;
  156. +   siginfo_t info;
  157. +
  158. +   for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i)
  159. +       if (current->thread.debug.hbp[i] == bp)
  160. +           break;
  161. +
  162. +   num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i);
  163. +
  164. +   info.si_signo   = SIGTRAP;
  165. +   info.si_errno   = (int)num;
  166. +   info.si_code    = TRAP_HWBKPT;
  167. +   info.si_addr    = (void __user *)(bkpt->trigger);
  168. +
  169. +   force_sig_info(SIGTRAP, &info, current);
  170. +}
  171. +
  172. +/*
  173. + * Set ptrace breakpoint pointers to zero for this task.
  174. + * This is required in order to prevent child processes from unregistering
  175. + * breakpoints held by their parent.
  176. + */
  177. +void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
  178. +{
  179. +   memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp));
  180. +}
  181. +
  182. +/*
  183. + * Unregister breakpoints from this task and reset the pointers in
  184. + * the thread_struct.
  185. + */
  186. +void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
  187. +{
  188. +   int i;
  189. +   struct thread_struct *t = &tsk->thread;
  190. +
  191. +   for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) {
  192. +       if (t->debug.hbp[i]) {
  193. +           unregister_hw_breakpoint(t->debug.hbp[i]);
  194. +           t->debug.hbp[i] = NULL;
  195. +       }
  196. +   }
  197. +}
  198. +
  199. +static u32 ptrace_get_hbp_resource_info(void)
  200. +{
  201. +   u8 num_brps, num_wrps, debug_arch, wp_len;
  202. +   u32 reg = 0;
  203. +
  204. +   num_brps    = hw_breakpoint_slots(TYPE_INST);
  205. +   num_wrps    = hw_breakpoint_slots(TYPE_DATA);
  206. +   debug_arch  = arch_get_debug_arch();
  207. +   wp_len      = arch_get_max_wp_len();
  208. +
  209. +   reg     |= debug_arch;
  210. +   reg     <<= 8;
  211. +   reg     |= wp_len;
  212. +   reg     <<= 8;
  213. +   reg     |= num_wrps;
  214. +   reg     <<= 8;
  215. +   reg     |= num_brps;
  216. +
  217. +   return reg;
  218. +}
  219. +
  220. +static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
  221. +{
  222. +   struct perf_event_attr attr;
  223. +
  224. +   ptrace_breakpoint_init(&attr);
  225. +
  226. +   /* Initialise fields to sane defaults. */
  227. +   attr.bp_addr    = 0;
  228. +   attr.bp_len = HW_BREAKPOINT_LEN_4;
  229. +   attr.bp_type    = type;
  230. +   attr.disabled   = 1;
  231. +
  232. +   return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk);
  233. +}
  234. +
  235. +static int ptrace_gethbpregs(struct task_struct *tsk, long num,
  236. +                unsigned long  __user *data)
  237. +{
  238. +   u32 reg;
  239. +   int idx, ret = 0;
  240. +   struct perf_event *bp;
  241. +   struct arch_hw_breakpoint_ctrl arch_ctrl;
  242. +
  243. +   if (num == 0) {
  244. +       reg = ptrace_get_hbp_resource_info();
  245. +   } else {
  246. +       idx = ptrace_hbp_num_to_idx(num);
  247. +       if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
  248. +           ret = -EINVAL;
  249. +           goto out;
  250. +       }
  251. +
  252. +       bp = tsk->thread.debug.hbp[idx];
  253. +       if (!bp) {
  254. +           reg = 0;
  255. +           goto put;
  256. +       }
  257. +
  258. +       arch_ctrl = counter_arch_bp(bp)->ctrl;
  259. +
  260. +       /*
  261. +        * Fix up the len because we may have adjusted it
  262. +        * to compensate for an unaligned address.
  263. +        */
  264. +       while (!(arch_ctrl.len & 0x1))
  265. +           arch_ctrl.len >>= 1;
  266. +
  267. +       if (idx & 0x1)
  268. +           reg = encode_ctrl_reg(arch_ctrl);
  269. +       else
  270. +           reg = bp->attr.bp_addr;
  271. +   }
  272. +
  273. +put:
  274. +   if (put_user(reg, data))
  275. +       ret = -EFAULT;
  276. +
  277. +out:
  278. +   return ret;
  279. +}
  280. +
  281. +static int ptrace_sethbpregs(struct task_struct *tsk, long num,
  282. +                unsigned long __user *data)
  283. +{
  284. +   int idx, gen_len, gen_type, implied_type, ret = 0;
  285. +   u32 user_val;
  286. +   struct perf_event *bp;
  287. +   struct arch_hw_breakpoint_ctrl ctrl;
  288. +   struct perf_event_attr attr;
  289. +
  290. +   if (num == 0)
  291. +       goto out;
  292. +   else if (num < 0)
  293. +       implied_type = HW_BREAKPOINT_RW;
  294. +   else
  295. +       implied_type = HW_BREAKPOINT_X;
  296. +
  297. +   idx = ptrace_hbp_num_to_idx(num);
  298. +   if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
  299. +       ret = -EINVAL;
  300. +       goto out;
  301. +   }
  302. +
  303. +   if (get_user(user_val, data)) {
  304. +       ret = -EFAULT;
  305. +       goto out;
  306. +   }
  307. +
  308. +   bp = tsk->thread.debug.hbp[idx];
  309. +   if (!bp) {
  310. +       bp = ptrace_hbp_create(tsk, implied_type);
  311. +       if (IS_ERR(bp)) {
  312. +           ret = PTR_ERR(bp);
  313. +           goto out;
  314. +       }
  315. +       tsk->thread.debug.hbp[idx] = bp;
  316. +   }
  317. +
  318. +   attr = bp->attr;
  319. +
  320. +   if (num & 0x1) {
  321. +       /* Address */
  322. +       attr.bp_addr    = user_val;
  323. +   } else {
  324. +       /* Control */
  325. +       decode_ctrl_reg(user_val, &ctrl);
  326. +       ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type);
  327. +       if (ret)
  328. +           goto out;
  329. +
  330. +       if ((gen_type & implied_type) != gen_type) {
  331. +               ret = -EINVAL;
  332. +               goto out;
  333. +       }
  334. +
  335. +       attr.bp_len = gen_len;
  336. +       attr.bp_type    = gen_type;
  337. +       attr.disabled   = !ctrl.enabled;
  338. +   }
  339. +
  340. +   ret = modify_user_hw_breakpoint(bp, &attr);
  341. +out:
  342. +   return ret;
  343. +}
  344. +#endif
  345. +
  346. +long arch_ptrace(struct task_struct *child, long request,
  347. +        unsigned long addr, unsigned long data)
  348.  {
  349.     int ret;
  350. +   unsigned long __user *datap = (unsigned long __user *) data;
  351.  
  352.     switch (request) {
  353.         case PTRACE_PEEKUSR:
  354. -           ret = ptrace_read_user(child, addr, (unsigned long __user *)data);
  355. +           ret = ptrace_read_user(child, addr, datap);
  356.             break;
  357.  
  358.         case PTRACE_POKEUSR:
  359. @@ -765,34 +1091,34 @@
  360.             break;
  361.  
  362.         case PTRACE_GETREGS:
  363. -           ret = ptrace_getregs(child, (void __user *)data);
  364. +           ret = ptrace_getregs(child, datap);
  365.             break;
  366.  
  367.         case PTRACE_SETREGS:
  368. -           ret = ptrace_setregs(child, (void __user *)data);
  369. +           ret = ptrace_setregs(child, datap);
  370.             break;
  371.  
  372.         case PTRACE_GETFPREGS:
  373. -           ret = ptrace_getfpregs(child, (void __user *)data);
  374. +           ret = ptrace_getfpregs(child, datap);
  375.             break;
  376.        
  377.         case PTRACE_SETFPREGS:
  378. -           ret = ptrace_setfpregs(child, (void __user *)data);
  379. +           ret = ptrace_setfpregs(child, datap);
  380.             break;
  381.  
  382.  #ifdef CONFIG_IWMMXT
  383.         case PTRACE_GETWMMXREGS:
  384. -           ret = ptrace_getwmmxregs(child, (void __user *)data);
  385. +           ret = ptrace_getwmmxregs(child, datap);
  386.             break;
  387.  
  388.         case PTRACE_SETWMMXREGS:
  389. -           ret = ptrace_setwmmxregs(child, (void __user *)data);
  390. +           ret = ptrace_setwmmxregs(child, datap);
  391.             break;
  392.  #endif
  393.  
  394.         case PTRACE_GET_THREAD_AREA:
  395.             ret = put_user(task_thread_info(child)->tp_value,
  396. -                      (unsigned long __user *) data);
  397. +                      datap);
  398.             break;
  399.  
  400.         case PTRACE_SET_SYSCALL:
  401. @@ -802,21 +1128,32 @@
  402.  
  403.  #ifdef CONFIG_CRUNCH
  404.         case PTRACE_GETCRUNCHREGS:
  405. -           ret = ptrace_getcrunchregs(child, (void __user *)data);
  406. +           ret = ptrace_getcrunchregs(child, datap);
  407.             break;
  408.  
  409.         case PTRACE_SETCRUNCHREGS:
  410. -           ret = ptrace_setcrunchregs(child, (void __user *)data);
  411. +           ret = ptrace_setcrunchregs(child, datap);
  412.             break;
  413.  #endif
  414.  
  415.  #ifdef CONFIG_VFP
  416.         case PTRACE_GETVFPREGS:
  417. -           ret = ptrace_getvfpregs(child, (void __user *)data);
  418. +           ret = ptrace_getvfpregs(child, datap);
  419.             break;
  420.  
  421.         case PTRACE_SETVFPREGS:
  422. -           ret = ptrace_setvfpregs(child, (void __user *)data);
  423. +           ret = ptrace_setvfpregs(child, datap);
  424. +           break;
  425. +#endif
  426. +
  427. +#ifdef CONFIG_HAVE_HW_BREAKPOINT
  428. +       case PTRACE_GETHBPREGS:
  429. +           ret = ptrace_gethbpregs(child, addr,
  430. +                       (unsigned long __user *)data);
  431. +           break;
  432. +       case PTRACE_SETHBPREGS:
  433. +           ret = ptrace_sethbpregs(child, addr,
  434. +                       (unsigned long __user *)data);
  435.             break;
  436.  #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement