aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorAlex Smith <alex@alex-smith.me.uk>2014-07-23 09:40:09 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-07-30 17:27:46 -0400
commitc23b3d1a53119849dc3c23c417124deb067aa33d (patch)
treeadec9f6c5adf5556df55619c7217b270ebf68eae /arch/mips/kernel
parentbcec7c8da6b092b1ff3327fd83c2193adb12f684 (diff)
MIPS: ptrace: Change GP regset to use correct core dump register layout
Commit 6a9c001b7ec3 ("MIPS: Switch ELF core dumper to use regsets.") switched the core dumper to use regsets, however the GP regset code simply makes a direct copy of the kernel's pt_regs, which does not match the original core dump register layout as defined in asm/reg.h. Furthermore, the definition of pt_regs can vary with certain Kconfig variables, therefore the GP regset can never be relied upon to return registers in the same layout. Therefore, this patch changes the GP regset to match the original core dump layout. The layout differs for 32- and 64-bit processes, so separate implementations of the get/set functions are added for the 32- and 64-bit regsets. Signed-off-by: Alex Smith <alex@alex-smith.me.uk> Cc: <stable@vger.kernel.org> # v3.13+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7452/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/ptrace.c189
1 files changed, 160 insertions, 29 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 8f2130a2bbd3..8bd13ed084d2 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -246,36 +246,160 @@ int ptrace_set_watch_regs(struct task_struct *child,
246 246
247/* regset get/set implementations */ 247/* regset get/set implementations */
248 248
249static int gpr_get(struct task_struct *target, 249#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
250 const struct user_regset *regset, 250
251 unsigned int pos, unsigned int count, 251static int gpr32_get(struct task_struct *target,
252 void *kbuf, void __user *ubuf) 252 const struct user_regset *regset,
253 unsigned int pos, unsigned int count,
254 void *kbuf, void __user *ubuf)
253{ 255{
254 struct pt_regs *regs = task_pt_regs(target); 256 struct pt_regs *regs = task_pt_regs(target);
257 u32 uregs[ELF_NGREG] = {};
258 unsigned i;
259
260 for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
261 /* k0/k1 are copied as zero. */
262 if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
263 continue;
264
265 uregs[i] = regs->regs[i - MIPS32_EF_R0];
266 }
255 267
256 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 268 uregs[MIPS32_EF_LO] = regs->lo;
257 regs, 0, sizeof(*regs)); 269 uregs[MIPS32_EF_HI] = regs->hi;
270 uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
271 uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
272 uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
273 uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
274
275 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
276 sizeof(uregs));
258} 277}
259 278
260static int gpr_set(struct task_struct *target, 279static int gpr32_set(struct task_struct *target,
261 const struct user_regset *regset, 280 const struct user_regset *regset,
262 unsigned int pos, unsigned int count, 281 unsigned int pos, unsigned int count,
263 const void *kbuf, const void __user *ubuf) 282 const void *kbuf, const void __user *ubuf)
264{ 283{
265 struct pt_regs newregs; 284 struct pt_regs *regs = task_pt_regs(target);
266 int ret; 285 u32 uregs[ELF_NGREG];
286 unsigned start, num_regs, i;
287 int err;
288
289 start = pos / sizeof(u32);
290 num_regs = count / sizeof(u32);
291
292 if (start + num_regs > ELF_NGREG)
293 return -EIO;
294
295 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
296 sizeof(uregs));
297 if (err)
298 return err;
299
300 for (i = start; i < num_regs; i++) {
301 /*
302 * Cast all values to signed here so that if this is a 64-bit
303 * kernel, the supplied 32-bit values will be sign extended.
304 */
305 switch (i) {
306 case MIPS32_EF_R1 ... MIPS32_EF_R25:
307 /* k0/k1 are ignored. */
308 case MIPS32_EF_R28 ... MIPS32_EF_R31:
309 regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
310 break;
311 case MIPS32_EF_LO:
312 regs->lo = (s32)uregs[i];
313 break;
314 case MIPS32_EF_HI:
315 regs->hi = (s32)uregs[i];
316 break;
317 case MIPS32_EF_CP0_EPC:
318 regs->cp0_epc = (s32)uregs[i];
319 break;
320 }
321 }
322
323 return 0;
324}
325
326#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
327
328#ifdef CONFIG_64BIT
329
330static int gpr64_get(struct task_struct *target,
331 const struct user_regset *regset,
332 unsigned int pos, unsigned int count,
333 void *kbuf, void __user *ubuf)
334{
335 struct pt_regs *regs = task_pt_regs(target);
336 u64 uregs[ELF_NGREG] = {};
337 unsigned i;
338
339 for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
340 /* k0/k1 are copied as zero. */
341 if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
342 continue;
343
344 uregs[i] = regs->regs[i - MIPS64_EF_R0];
345 }
346
347 uregs[MIPS64_EF_LO] = regs->lo;
348 uregs[MIPS64_EF_HI] = regs->hi;
349 uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
350 uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
351 uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
352 uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
353
354 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
355 sizeof(uregs));
356}
267 357
268 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 358static int gpr64_set(struct task_struct *target,
269 &newregs, 359 const struct user_regset *regset,
270 0, sizeof(newregs)); 360 unsigned int pos, unsigned int count,
271 if (ret) 361 const void *kbuf, const void __user *ubuf)
272 return ret; 362{
363 struct pt_regs *regs = task_pt_regs(target);
364 u64 uregs[ELF_NGREG];
365 unsigned start, num_regs, i;
366 int err;
367
368 start = pos / sizeof(u64);
369 num_regs = count / sizeof(u64);
273 370
274 *task_pt_regs(target) = newregs; 371 if (start + num_regs > ELF_NGREG)
372 return -EIO;
373
374 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
375 sizeof(uregs));
376 if (err)
377 return err;
378
379 for (i = start; i < num_regs; i++) {
380 switch (i) {
381 case MIPS64_EF_R1 ... MIPS64_EF_R25:
382 /* k0/k1 are ignored. */
383 case MIPS64_EF_R28 ... MIPS64_EF_R31:
384 regs->regs[i - MIPS64_EF_R0] = uregs[i];
385 break;
386 case MIPS64_EF_LO:
387 regs->lo = uregs[i];
388 break;
389 case MIPS64_EF_HI:
390 regs->hi = uregs[i];
391 break;
392 case MIPS64_EF_CP0_EPC:
393 regs->cp0_epc = uregs[i];
394 break;
395 }
396 }
275 397
276 return 0; 398 return 0;
277} 399}
278 400
401#endif /* CONFIG_64BIT */
402
279static int fpr_get(struct task_struct *target, 403static int fpr_get(struct task_struct *target,
280 const struct user_regset *regset, 404 const struct user_regset *regset,
281 unsigned int pos, unsigned int count, 405 unsigned int pos, unsigned int count,
@@ -337,14 +461,16 @@ enum mips_regset {
337 REGSET_FPR, 461 REGSET_FPR,
338}; 462};
339 463
464#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
465
340static const struct user_regset mips_regsets[] = { 466static const struct user_regset mips_regsets[] = {
341 [REGSET_GPR] = { 467 [REGSET_GPR] = {
342 .core_note_type = NT_PRSTATUS, 468 .core_note_type = NT_PRSTATUS,
343 .n = ELF_NGREG, 469 .n = ELF_NGREG,
344 .size = sizeof(unsigned int), 470 .size = sizeof(unsigned int),
345 .align = sizeof(unsigned int), 471 .align = sizeof(unsigned int),
346 .get = gpr_get, 472 .get = gpr32_get,
347 .set = gpr_set, 473 .set = gpr32_set,
348 }, 474 },
349 [REGSET_FPR] = { 475 [REGSET_FPR] = {
350 .core_note_type = NT_PRFPREG, 476 .core_note_type = NT_PRFPREG,
@@ -364,14 +490,18 @@ static const struct user_regset_view user_mips_view = {
364 .n = ARRAY_SIZE(mips_regsets), 490 .n = ARRAY_SIZE(mips_regsets),
365}; 491};
366 492
493#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
494
495#ifdef CONFIG_64BIT
496
367static const struct user_regset mips64_regsets[] = { 497static const struct user_regset mips64_regsets[] = {
368 [REGSET_GPR] = { 498 [REGSET_GPR] = {
369 .core_note_type = NT_PRSTATUS, 499 .core_note_type = NT_PRSTATUS,
370 .n = ELF_NGREG, 500 .n = ELF_NGREG,
371 .size = sizeof(unsigned long), 501 .size = sizeof(unsigned long),
372 .align = sizeof(unsigned long), 502 .align = sizeof(unsigned long),
373 .get = gpr_get, 503 .get = gpr64_get,
374 .set = gpr_set, 504 .set = gpr64_set,
375 }, 505 },
376 [REGSET_FPR] = { 506 [REGSET_FPR] = {
377 .core_note_type = NT_PRFPREG, 507 .core_note_type = NT_PRFPREG,
@@ -384,25 +514,26 @@ static const struct user_regset mips64_regsets[] = {
384}; 514};
385 515
386static const struct user_regset_view user_mips64_view = { 516static const struct user_regset_view user_mips64_view = {
387 .name = "mips", 517 .name = "mips64",
388 .e_machine = ELF_ARCH, 518 .e_machine = ELF_ARCH,
389 .ei_osabi = ELF_OSABI, 519 .ei_osabi = ELF_OSABI,
390 .regsets = mips64_regsets, 520 .regsets = mips64_regsets,
391 .n = ARRAY_SIZE(mips_regsets), 521 .n = ARRAY_SIZE(mips64_regsets),
392}; 522};
393 523
524#endif /* CONFIG_64BIT */
525
394const struct user_regset_view *task_user_regset_view(struct task_struct *task) 526const struct user_regset_view *task_user_regset_view(struct task_struct *task)
395{ 527{
396#ifdef CONFIG_32BIT 528#ifdef CONFIG_32BIT
397 return &user_mips_view; 529 return &user_mips_view;
398#endif 530#else
399
400#ifdef CONFIG_MIPS32_O32 531#ifdef CONFIG_MIPS32_O32
401 if (test_tsk_thread_flag(task, TIF_32BIT_REGS)) 532 if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
402 return &user_mips_view; 533 return &user_mips_view;
403#endif 534#endif
404
405 return &user_mips64_view; 535 return &user_mips64_view;
536#endif
406} 537}
407 538
408long arch_ptrace(struct task_struct *child, long request, 539long arch_ptrace(struct task_struct *child, long request,