Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/xtensa/kernel/ptrace.c
26424 views
1
/*
2
* This file is subject to the terms and conditions of the GNU General Public
3
* License. See the file "COPYING" in the main directory of this archive
4
* for more details.
5
*
6
* Copyright (C) 2001 - 2007 Tensilica Inc.
7
*
8
* Joe Taylor <[email protected], [email protected]>
9
* Chris Zankel <[email protected]>
10
* Scott Foehner<[email protected]>,
11
* Kevin Chea
12
* Marc Gauthier<[email protected]> <[email protected]>
13
*/
14
15
#include <linux/audit.h>
16
#include <linux/errno.h>
17
#include <linux/hw_breakpoint.h>
18
#include <linux/kernel.h>
19
#include <linux/mm.h>
20
#include <linux/perf_event.h>
21
#include <linux/ptrace.h>
22
#include <linux/regset.h>
23
#include <linux/sched.h>
24
#include <linux/sched/task_stack.h>
25
#include <linux/seccomp.h>
26
#include <linux/security.h>
27
#include <linux/signal.h>
28
#include <linux/smp.h>
29
#include <linux/uaccess.h>
30
31
#define CREATE_TRACE_POINTS
32
#include <trace/events/syscalls.h>
33
34
#include <asm/coprocessor.h>
35
#include <asm/elf.h>
36
#include <asm/page.h>
37
#include <asm/ptrace.h>
38
39
static int gpr_get(struct task_struct *target,
40
const struct user_regset *regset,
41
struct membuf to)
42
{
43
struct pt_regs *regs = task_pt_regs(target);
44
struct user_pt_regs newregs = {
45
.pc = regs->pc,
46
.ps = regs->ps & ~(1 << PS_EXCM_BIT),
47
.lbeg = regs->lbeg,
48
.lend = regs->lend,
49
.lcount = regs->lcount,
50
.sar = regs->sar,
51
.threadptr = regs->threadptr,
52
.windowbase = regs->windowbase,
53
.windowstart = regs->windowstart,
54
.syscall = regs->syscall,
55
};
56
57
memcpy(newregs.a,
58
regs->areg + XCHAL_NUM_AREGS - regs->windowbase * 4,
59
regs->windowbase * 16);
60
memcpy(newregs.a + regs->windowbase * 4,
61
regs->areg,
62
(WSBITS - regs->windowbase) * 16);
63
64
return membuf_write(&to, &newregs, sizeof(newregs));
65
}
66
67
static int gpr_set(struct task_struct *target,
68
const struct user_regset *regset,
69
unsigned int pos, unsigned int count,
70
const void *kbuf, const void __user *ubuf)
71
{
72
int ret;
73
struct user_pt_regs newregs = {0};
74
struct pt_regs *regs;
75
const u32 ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
76
77
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
78
if (ret)
79
return ret;
80
81
if (newregs.windowbase >= XCHAL_NUM_AREGS / 4)
82
return -EINVAL;
83
84
regs = task_pt_regs(target);
85
regs->pc = newregs.pc;
86
regs->ps = (regs->ps & ~ps_mask) | (newregs.ps & ps_mask);
87
regs->lbeg = newregs.lbeg;
88
regs->lend = newregs.lend;
89
regs->lcount = newregs.lcount;
90
regs->sar = newregs.sar;
91
regs->threadptr = newregs.threadptr;
92
93
if (newregs.syscall)
94
regs->syscall = newregs.syscall;
95
96
if (newregs.windowbase != regs->windowbase ||
97
newregs.windowstart != regs->windowstart) {
98
u32 rotws, wmask;
99
100
rotws = (((newregs.windowstart |
101
(newregs.windowstart << WSBITS)) >>
102
newregs.windowbase) &
103
((1 << WSBITS) - 1)) & ~1;
104
wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) |
105
(rotws & 0xF) | 1;
106
regs->windowbase = newregs.windowbase;
107
regs->windowstart = newregs.windowstart;
108
regs->wmask = wmask;
109
}
110
111
memcpy(regs->areg + XCHAL_NUM_AREGS - newregs.windowbase * 4,
112
newregs.a, newregs.windowbase * 16);
113
memcpy(regs->areg, newregs.a + newregs.windowbase * 4,
114
(WSBITS - newregs.windowbase) * 16);
115
116
return 0;
117
}
118
119
static int tie_get(struct task_struct *target,
120
const struct user_regset *regset,
121
struct membuf to)
122
{
123
int ret;
124
struct pt_regs *regs = task_pt_regs(target);
125
struct thread_info *ti = task_thread_info(target);
126
elf_xtregs_t *newregs = kzalloc(sizeof(elf_xtregs_t), GFP_KERNEL);
127
128
if (!newregs)
129
return -ENOMEM;
130
131
newregs->opt = regs->xtregs_opt;
132
newregs->user = ti->xtregs_user;
133
134
#if XTENSA_HAVE_COPROCESSORS
135
/* Flush all coprocessor registers to memory. */
136
coprocessor_flush_all(ti);
137
newregs->cp0 = ti->xtregs_cp.cp0;
138
newregs->cp1 = ti->xtregs_cp.cp1;
139
newregs->cp2 = ti->xtregs_cp.cp2;
140
newregs->cp3 = ti->xtregs_cp.cp3;
141
newregs->cp4 = ti->xtregs_cp.cp4;
142
newregs->cp5 = ti->xtregs_cp.cp5;
143
newregs->cp6 = ti->xtregs_cp.cp6;
144
newregs->cp7 = ti->xtregs_cp.cp7;
145
#endif
146
ret = membuf_write(&to, newregs, sizeof(*newregs));
147
kfree(newregs);
148
return ret;
149
}
150
151
static int tie_set(struct task_struct *target,
152
const struct user_regset *regset,
153
unsigned int pos, unsigned int count,
154
const void *kbuf, const void __user *ubuf)
155
{
156
int ret;
157
struct pt_regs *regs = task_pt_regs(target);
158
struct thread_info *ti = task_thread_info(target);
159
elf_xtregs_t *newregs = kzalloc(sizeof(elf_xtregs_t), GFP_KERNEL);
160
161
if (!newregs)
162
return -ENOMEM;
163
164
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
165
newregs, 0, -1);
166
167
if (ret)
168
goto exit;
169
regs->xtregs_opt = newregs->opt;
170
ti->xtregs_user = newregs->user;
171
172
#if XTENSA_HAVE_COPROCESSORS
173
/* Flush all coprocessors before we overwrite them. */
174
coprocessor_flush_release_all(ti);
175
ti->xtregs_cp.cp0 = newregs->cp0;
176
ti->xtregs_cp.cp1 = newregs->cp1;
177
ti->xtregs_cp.cp2 = newregs->cp2;
178
ti->xtregs_cp.cp3 = newregs->cp3;
179
ti->xtregs_cp.cp4 = newregs->cp4;
180
ti->xtregs_cp.cp5 = newregs->cp5;
181
ti->xtregs_cp.cp6 = newregs->cp6;
182
ti->xtregs_cp.cp7 = newregs->cp7;
183
#endif
184
exit:
185
kfree(newregs);
186
return ret;
187
}
188
189
enum xtensa_regset {
190
REGSET_GPR,
191
REGSET_TIE,
192
};
193
194
static const struct user_regset xtensa_regsets[] = {
195
[REGSET_GPR] = {
196
USER_REGSET_NOTE_TYPE(PRSTATUS),
197
.n = sizeof(struct user_pt_regs) / sizeof(u32),
198
.size = sizeof(u32),
199
.align = sizeof(u32),
200
.regset_get = gpr_get,
201
.set = gpr_set,
202
},
203
[REGSET_TIE] = {
204
USER_REGSET_NOTE_TYPE(PRFPREG),
205
.n = sizeof(elf_xtregs_t) / sizeof(u32),
206
.size = sizeof(u32),
207
.align = sizeof(u32),
208
.regset_get = tie_get,
209
.set = tie_set,
210
},
211
};
212
213
static const struct user_regset_view user_xtensa_view = {
214
.name = "xtensa",
215
.e_machine = EM_XTENSA,
216
.regsets = xtensa_regsets,
217
.n = ARRAY_SIZE(xtensa_regsets)
218
};
219
220
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
221
{
222
return &user_xtensa_view;
223
}
224
225
void user_enable_single_step(struct task_struct *child)
226
{
227
set_tsk_thread_flag(child, TIF_SINGLESTEP);
228
}
229
230
void user_disable_single_step(struct task_struct *child)
231
{
232
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
233
}
234
235
/*
236
* Called by kernel/ptrace.c when detaching to disable single stepping.
237
*/
238
239
void ptrace_disable(struct task_struct *child)
240
{
241
/* Nothing to do.. */
242
}
243
244
static int ptrace_getregs(struct task_struct *child, void __user *uregs)
245
{
246
return copy_regset_to_user(child, &user_xtensa_view, REGSET_GPR,
247
0, sizeof(xtensa_gregset_t), uregs);
248
}
249
250
static int ptrace_setregs(struct task_struct *child, void __user *uregs)
251
{
252
return copy_regset_from_user(child, &user_xtensa_view, REGSET_GPR,
253
0, sizeof(xtensa_gregset_t), uregs);
254
}
255
256
static int ptrace_getxregs(struct task_struct *child, void __user *uregs)
257
{
258
return copy_regset_to_user(child, &user_xtensa_view, REGSET_TIE,
259
0, sizeof(elf_xtregs_t), uregs);
260
}
261
262
static int ptrace_setxregs(struct task_struct *child, void __user *uregs)
263
{
264
return copy_regset_from_user(child, &user_xtensa_view, REGSET_TIE,
265
0, sizeof(elf_xtregs_t), uregs);
266
}
267
268
static int ptrace_peekusr(struct task_struct *child, long regno,
269
long __user *ret)
270
{
271
struct pt_regs *regs;
272
unsigned long tmp;
273
274
regs = task_pt_regs(child);
275
tmp = 0; /* Default return value. */
276
277
switch(regno) {
278
case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
279
tmp = regs->areg[regno - REG_AR_BASE];
280
break;
281
282
case REG_A_BASE ... REG_A_BASE + 15:
283
tmp = regs->areg[regno - REG_A_BASE];
284
break;
285
286
case REG_PC:
287
tmp = regs->pc;
288
break;
289
290
case REG_PS:
291
/* Note: PS.EXCM is not set while user task is running;
292
* its being set in regs is for exception handling
293
* convenience.
294
*/
295
tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
296
break;
297
298
case REG_WB:
299
break; /* tmp = 0 */
300
301
case REG_WS:
302
{
303
unsigned long wb = regs->windowbase;
304
unsigned long ws = regs->windowstart;
305
tmp = ((ws >> wb) | (ws << (WSBITS - wb))) &
306
((1 << WSBITS) - 1);
307
break;
308
}
309
case REG_LBEG:
310
tmp = regs->lbeg;
311
break;
312
313
case REG_LEND:
314
tmp = regs->lend;
315
break;
316
317
case REG_LCOUNT:
318
tmp = regs->lcount;
319
break;
320
321
case REG_SAR:
322
tmp = regs->sar;
323
break;
324
325
case SYSCALL_NR:
326
tmp = regs->syscall;
327
break;
328
329
default:
330
return -EIO;
331
}
332
return put_user(tmp, ret);
333
}
334
335
static int ptrace_pokeusr(struct task_struct *child, long regno, long val)
336
{
337
struct pt_regs *regs;
338
regs = task_pt_regs(child);
339
340
switch (regno) {
341
case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
342
regs->areg[regno - REG_AR_BASE] = val;
343
break;
344
345
case REG_A_BASE ... REG_A_BASE + 15:
346
regs->areg[regno - REG_A_BASE] = val;
347
break;
348
349
case REG_PC:
350
regs->pc = val;
351
break;
352
353
case SYSCALL_NR:
354
regs->syscall = val;
355
break;
356
357
default:
358
return -EIO;
359
}
360
return 0;
361
}
362
363
#ifdef CONFIG_HAVE_HW_BREAKPOINT
364
static void ptrace_hbptriggered(struct perf_event *bp,
365
struct perf_sample_data *data,
366
struct pt_regs *regs)
367
{
368
int i;
369
struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
370
371
if (bp->attr.bp_type & HW_BREAKPOINT_X) {
372
for (i = 0; i < XCHAL_NUM_IBREAK; ++i)
373
if (current->thread.ptrace_bp[i] == bp)
374
break;
375
i <<= 1;
376
} else {
377
for (i = 0; i < XCHAL_NUM_DBREAK; ++i)
378
if (current->thread.ptrace_wp[i] == bp)
379
break;
380
i = (i << 1) | 1;
381
}
382
383
force_sig_ptrace_errno_trap(i, (void __user *)bkpt->address);
384
}
385
386
static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
387
{
388
struct perf_event_attr attr;
389
390
ptrace_breakpoint_init(&attr);
391
392
/* Initialise fields to sane defaults. */
393
attr.bp_addr = 0;
394
attr.bp_len = 1;
395
attr.bp_type = type;
396
attr.disabled = 1;
397
398
return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL,
399
tsk);
400
}
401
402
/*
403
* Address bit 0 choose instruction (0) or data (1) break register, bits
404
* 31..1 are the register number.
405
* Both PTRACE_GETHBPREGS and PTRACE_SETHBPREGS transfer two 32-bit words:
406
* address (0) and control (1).
407
* Instruction breakpoint contorl word is 0 to clear breakpoint, 1 to set.
408
* Data breakpoint control word bit 31 is 'trigger on store', bit 30 is
409
* 'trigger on load, bits 29..0 are length. Length 0 is used to clear a
410
* breakpoint. To set a breakpoint length must be a power of 2 in the range
411
* 1..64 and the address must be length-aligned.
412
*/
413
414
static long ptrace_gethbpregs(struct task_struct *child, long addr,
415
long __user *datap)
416
{
417
struct perf_event *bp;
418
u32 user_data[2] = {0};
419
bool dbreak = addr & 1;
420
unsigned idx = addr >> 1;
421
422
if ((!dbreak && idx >= XCHAL_NUM_IBREAK) ||
423
(dbreak && idx >= XCHAL_NUM_DBREAK))
424
return -EINVAL;
425
426
if (dbreak)
427
bp = child->thread.ptrace_wp[idx];
428
else
429
bp = child->thread.ptrace_bp[idx];
430
431
if (bp) {
432
user_data[0] = bp->attr.bp_addr;
433
user_data[1] = bp->attr.disabled ? 0 : bp->attr.bp_len;
434
if (dbreak) {
435
if (bp->attr.bp_type & HW_BREAKPOINT_R)
436
user_data[1] |= DBREAKC_LOAD_MASK;
437
if (bp->attr.bp_type & HW_BREAKPOINT_W)
438
user_data[1] |= DBREAKC_STOR_MASK;
439
}
440
}
441
442
if (copy_to_user(datap, user_data, sizeof(user_data)))
443
return -EFAULT;
444
445
return 0;
446
}
447
448
static long ptrace_sethbpregs(struct task_struct *child, long addr,
449
long __user *datap)
450
{
451
struct perf_event *bp;
452
struct perf_event_attr attr;
453
u32 user_data[2];
454
bool dbreak = addr & 1;
455
unsigned idx = addr >> 1;
456
int bp_type = 0;
457
458
if ((!dbreak && idx >= XCHAL_NUM_IBREAK) ||
459
(dbreak && idx >= XCHAL_NUM_DBREAK))
460
return -EINVAL;
461
462
if (copy_from_user(user_data, datap, sizeof(user_data)))
463
return -EFAULT;
464
465
if (dbreak) {
466
bp = child->thread.ptrace_wp[idx];
467
if (user_data[1] & DBREAKC_LOAD_MASK)
468
bp_type |= HW_BREAKPOINT_R;
469
if (user_data[1] & DBREAKC_STOR_MASK)
470
bp_type |= HW_BREAKPOINT_W;
471
} else {
472
bp = child->thread.ptrace_bp[idx];
473
bp_type = HW_BREAKPOINT_X;
474
}
475
476
if (!bp) {
477
bp = ptrace_hbp_create(child,
478
bp_type ? bp_type : HW_BREAKPOINT_RW);
479
if (IS_ERR(bp))
480
return PTR_ERR(bp);
481
if (dbreak)
482
child->thread.ptrace_wp[idx] = bp;
483
else
484
child->thread.ptrace_bp[idx] = bp;
485
}
486
487
attr = bp->attr;
488
attr.bp_addr = user_data[0];
489
attr.bp_len = user_data[1] & ~(DBREAKC_LOAD_MASK | DBREAKC_STOR_MASK);
490
attr.bp_type = bp_type;
491
attr.disabled = !attr.bp_len;
492
493
return modify_user_hw_breakpoint(bp, &attr);
494
}
495
#endif
496
497
long arch_ptrace(struct task_struct *child, long request,
498
unsigned long addr, unsigned long data)
499
{
500
int ret = -EPERM;
501
void __user *datap = (void __user *) data;
502
503
switch (request) {
504
case PTRACE_PEEKUSR: /* read register specified by addr. */
505
ret = ptrace_peekusr(child, addr, datap);
506
break;
507
508
case PTRACE_POKEUSR: /* write register specified by addr. */
509
ret = ptrace_pokeusr(child, addr, data);
510
break;
511
512
case PTRACE_GETREGS:
513
ret = ptrace_getregs(child, datap);
514
break;
515
516
case PTRACE_SETREGS:
517
ret = ptrace_setregs(child, datap);
518
break;
519
520
case PTRACE_GETXTREGS:
521
ret = ptrace_getxregs(child, datap);
522
break;
523
524
case PTRACE_SETXTREGS:
525
ret = ptrace_setxregs(child, datap);
526
break;
527
#ifdef CONFIG_HAVE_HW_BREAKPOINT
528
case PTRACE_GETHBPREGS:
529
ret = ptrace_gethbpregs(child, addr, datap);
530
break;
531
532
case PTRACE_SETHBPREGS:
533
ret = ptrace_sethbpregs(child, addr, datap);
534
break;
535
#endif
536
default:
537
ret = ptrace_request(child, request, addr, data);
538
break;
539
}
540
541
return ret;
542
}
543
544
int do_syscall_trace_enter(struct pt_regs *regs)
545
{
546
if (regs->syscall == NO_SYSCALL)
547
regs->areg[2] = -ENOSYS;
548
549
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
550
ptrace_report_syscall_entry(regs)) {
551
regs->areg[2] = -ENOSYS;
552
regs->syscall = NO_SYSCALL;
553
return 0;
554
}
555
556
if (regs->syscall == NO_SYSCALL ||
557
secure_computing() == -1) {
558
do_syscall_trace_leave(regs);
559
return 0;
560
}
561
562
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
563
trace_sys_enter(regs, syscall_get_nr(current, regs));
564
565
audit_syscall_entry(regs->syscall, regs->areg[6],
566
regs->areg[3], regs->areg[4],
567
regs->areg[5]);
568
return 1;
569
}
570
571
void do_syscall_trace_leave(struct pt_regs *regs)
572
{
573
int step;
574
575
audit_syscall_exit(regs);
576
577
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
578
trace_sys_exit(regs, regs_return_value(regs));
579
580
step = test_thread_flag(TIF_SINGLESTEP);
581
582
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
583
ptrace_report_syscall_exit(regs, step);
584
}
585
586