ptrace.c 13.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1992 Ross Biro
 * Copyright (C) Linus Torvalds
 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
 * Copyright (C) 1996 David S. Miller
 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
 * Copyright (C) 1999 MIPS Technologies, Inc.
 * Copyright (C) 2000 Ulf Carlsson
 *
 * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
 * binaries.
 */
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/smp.h>
#include <linux/user.h>
#include <linux/security.h>
26 27
#include <linux/audit.h>
#include <linux/seccomp.h>
L
Linus Torvalds 已提交
28

29
#include <asm/byteorder.h>
L
Linus Torvalds 已提交
30
#include <asm/cpu.h>
31
#include <asm/dsp.h>
L
Linus Torvalds 已提交
32 33
#include <asm/fpu.h>
#include <asm/mipsregs.h>
34
#include <asm/mipsmtregs.h>
L
Linus Torvalds 已提交
35 36 37 38
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/uaccess.h>
#include <asm/bootinfo.h>
39
#include <asm/reg.h>
L
Linus Torvalds 已提交
40 41 42 43 44 45 46 47

/*
 * Called by kernel/ptrace.c when detaching..
 *
 * Make sure single step bits etc are not set.
 */
void ptrace_disable(struct task_struct *child)
{
48 49
	/* Don't load the watchpoint registers for the ex-child. */
	clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
L
Linus Torvalds 已提交
50 51
}

52 53 54 55 56
/*
 * Read a general register set.  We always use the 64-bit format, even
 * for 32-bit kernels and for 32-bit processes on a 64-bit kernel.
 * Registers are sign extended to fill the available space.
 */
57
int ptrace_getregs(struct task_struct *child, __s64 __user *data)
58 59 60 61 62 63 64
{
	struct pt_regs *regs;
	int i;

	if (!access_ok(VERIFY_WRITE, data, 38 * 8))
		return -EIO;

A
Al Viro 已提交
65
	regs = task_pt_regs(child);
66 67

	for (i = 0; i < 32; i++)
68 69 70 71 72 73 74
		__put_user((long)regs->regs[i], data + i);
	__put_user((long)regs->lo, data + EF_LO - EF_R0);
	__put_user((long)regs->hi, data + EF_HI - EF_R0);
	__put_user((long)regs->cp0_epc, data + EF_CP0_EPC - EF_R0);
	__put_user((long)regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0);
	__put_user((long)regs->cp0_status, data + EF_CP0_STATUS - EF_R0);
	__put_user((long)regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0);
75 76 77 78 79 80 81 82 83

	return 0;
}

/*
 * Write a general register set.  As for PTRACE_GETREGS, we always use
 * the 64-bit format.  On a 32-bit kernel only the lower order half
 * (according to endianness) will be used.
 */
84
int ptrace_setregs(struct task_struct *child, __s64 __user *data)
85 86 87 88 89 90 91
{
	struct pt_regs *regs;
	int i;

	if (!access_ok(VERIFY_READ, data, 38 * 8))
		return -EIO;

A
Al Viro 已提交
92
	regs = task_pt_regs(child);
93 94

	for (i = 0; i < 32; i++)
95 96 97 98
		__get_user(regs->regs[i], data + i);
	__get_user(regs->lo, data + EF_LO - EF_R0);
	__get_user(regs->hi, data + EF_HI - EF_R0);
	__get_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0);
99 100 101 102 103 104

	/* badvaddr, status, and cause may not be written.  */

	return 0;
}

105
int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
106 107
{
	int i;
108
	unsigned int tmp;
109 110 111 112 113 114 115

	if (!access_ok(VERIFY_WRITE, data, 33 * 8))
		return -EIO;

	if (tsk_used_math(child)) {
		fpureg_t *fregs = get_fpu_regs(child);
		for (i = 0; i < 32; i++)
116
			__put_user(fregs[i], i + (__u64 __user *) data);
117 118
	} else {
		for (i = 0; i < 32; i++)
119
			__put_user((__u64) -1, i + (__u64 __user *) data);
120 121
	}

122
	__put_user(child->thread.fpu.fcr31, data + 64);
123

124
	preempt_disable();
125
	if (cpu_has_fpu) {
126
		unsigned int flags;
127

128 129 130 131 132 133 134 135 136 137 138 139 140
		if (cpu_has_mipsmt) {
			unsigned int vpflags = dvpe();
			flags = read_c0_status();
			__enable_fpu();
			__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
			write_c0_status(flags);
			evpe(vpflags);
		} else {
			flags = read_c0_status();
			__enable_fpu();
			__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
			write_c0_status(flags);
		}
141
	} else {
142
		tmp = 0;
143
	}
144
	preempt_enable();
145
	__put_user(tmp, data + 65);
146 147 148 149

	return 0;
}

150
int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
151 152 153 154 155 156 157 158 159 160
{
	fpureg_t *fregs;
	int i;

	if (!access_ok(VERIFY_READ, data, 33 * 8))
		return -EIO;

	fregs = get_fpu_regs(child);

	for (i = 0; i < 32; i++)
161
		__get_user(fregs[i], i + (__u64 __user *) data);
162

163
	__get_user(child->thread.fpu.fcr31, data + 64);
164 165 166 167 168 169

	/* FIR may not be written.  */

	return 0;
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
int ptrace_get_watch_regs(struct task_struct *child,
			  struct pt_watch_regs __user *addr)
{
	enum pt_watch_style style;
	int i;

	if (!cpu_has_watch || current_cpu_data.watch_reg_use_cnt == 0)
		return -EIO;
	if (!access_ok(VERIFY_WRITE, addr, sizeof(struct pt_watch_regs)))
		return -EIO;

#ifdef CONFIG_32BIT
	style = pt_watch_style_mips32;
#define WATCH_STYLE mips32
#else
	style = pt_watch_style_mips64;
#define WATCH_STYLE mips64
#endif

	__put_user(style, &addr->style);
	__put_user(current_cpu_data.watch_reg_use_cnt,
		   &addr->WATCH_STYLE.num_valid);
	for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
		__put_user(child->thread.watch.mips3264.watchlo[i],
			   &addr->WATCH_STYLE.watchlo[i]);
		__put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff,
			   &addr->WATCH_STYLE.watchhi[i]);
		__put_user(current_cpu_data.watch_reg_masks[i],
			   &addr->WATCH_STYLE.watch_masks[i]);
	}
	for (; i < 8; i++) {
		__put_user(0, &addr->WATCH_STYLE.watchlo[i]);
		__put_user(0, &addr->WATCH_STYLE.watchhi[i]);
		__put_user(0, &addr->WATCH_STYLE.watch_masks[i]);
	}

	return 0;
}

int ptrace_set_watch_regs(struct task_struct *child,
			  struct pt_watch_regs __user *addr)
{
	int i;
	int watch_active = 0;
	unsigned long lt[NUM_WATCH_REGS];
	u16 ht[NUM_WATCH_REGS];

	if (!cpu_has_watch || current_cpu_data.watch_reg_use_cnt == 0)
		return -EIO;
	if (!access_ok(VERIFY_READ, addr, sizeof(struct pt_watch_regs)))
		return -EIO;
	/* Check the values. */
	for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
		__get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
#ifdef CONFIG_32BIT
		if (lt[i] & __UA_LIMIT)
			return -EINVAL;
#else
		if (test_tsk_thread_flag(child, TIF_32BIT_ADDR)) {
			if (lt[i] & 0xffffffff80000000UL)
				return -EINVAL;
		} else {
			if (lt[i] & __UA_LIMIT)
				return -EINVAL;
		}
#endif
		__get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
		if (ht[i] & ~0xff8)
			return -EINVAL;
	}
	/* Install them. */
	for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
		if (lt[i] & 7)
			watch_active = 1;
		child->thread.watch.mips3264.watchlo[i] = lt[i];
		/* Set the G bit. */
		child->thread.watch.mips3264.watchhi[i] = ht[i];
	}

	if (watch_active)
		set_tsk_thread_flag(child, TIF_LOAD_WATCH);
	else
		clear_tsk_thread_flag(child, TIF_LOAD_WATCH);

	return 0;
}

257 258
long arch_ptrace(struct task_struct *child, long request,
		 unsigned long addr, unsigned long data)
L
Linus Torvalds 已提交
259 260
{
	int ret;
261 262 263
	void __user *addrp = (void __user *) addr;
	void __user *datavp = (void __user *) data;
	unsigned long __user *datalp = (void __user *) data;
L
Linus Torvalds 已提交
264 265 266 267

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */
A
Alexey Dobriyan 已提交
268 269
	case PTRACE_PEEKDATA:
		ret = generic_ptrace_peekdata(child, addr, data);
L
Linus Torvalds 已提交
270 271 272 273 274 275 276
		break;

	/* Read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		struct pt_regs *regs;
		unsigned long tmp = 0;

A
Al Viro 已提交
277
		regs = task_pt_regs(child);
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285 286 287
		ret = 0;  /* Default return value. */

		switch (addr) {
		case 0 ... 31:
			tmp = regs->regs[addr];
			break;
		case FPR_BASE ... FPR_BASE + 31:
			if (tsk_used_math(child)) {
				fpureg_t *fregs = get_fpu_regs(child);

288
#ifdef CONFIG_32BIT
L
Linus Torvalds 已提交
289 290 291 292 293 294 295 296 297 298
				/*
				 * The odd registers are actually the high
				 * order bits of the values stored in the even
				 * registers - unless we're using r2k_switch.S.
				 */
				if (addr & 1)
					tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
				else
					tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
#endif
299
#ifdef CONFIG_64BIT
L
Linus Torvalds 已提交
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
				tmp = fregs[addr - FPR_BASE];
#endif
			} else {
				tmp = -1;	/* FP not yet used  */
			}
			break;
		case PC:
			tmp = regs->cp0_epc;
			break;
		case CAUSE:
			tmp = regs->cp0_cause;
			break;
		case BADVADDR:
			tmp = regs->cp0_badvaddr;
			break;
		case MMHI:
			tmp = regs->hi;
			break;
		case MMLO:
			tmp = regs->lo;
			break;
321 322 323 324 325
#ifdef CONFIG_CPU_HAS_SMARTMIPS
		case ACX:
			tmp = regs->acx;
			break;
#endif
L
Linus Torvalds 已提交
326
		case FPC_CSR:
327
			tmp = child->thread.fpu.fcr31;
L
Linus Torvalds 已提交
328 329 330
			break;
		case FPC_EIR: {	/* implementation / version register */
			unsigned int flags;
331
#ifdef CONFIG_MIPS_MT_SMTC
332
			unsigned long irqflags;
333 334
			unsigned int mtflags;
#endif /* CONFIG_MIPS_MT_SMTC */
L
Linus Torvalds 已提交
335

336 337 338
			preempt_disable();
			if (!cpu_has_fpu) {
				preempt_enable();
L
Linus Torvalds 已提交
339
				break;
340
			}
L
Linus Torvalds 已提交
341

342 343 344 345 346
#ifdef CONFIG_MIPS_MT_SMTC
			/* Read-modify-write of Status must be atomic */
			local_irq_save(irqflags);
			mtflags = dmt();
#endif /* CONFIG_MIPS_MT_SMTC */
347 348 349 350 351 352 353 354 355 356 357 358 359
			if (cpu_has_mipsmt) {
				unsigned int vpflags = dvpe();
				flags = read_c0_status();
				__enable_fpu();
				__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
				write_c0_status(flags);
				evpe(vpflags);
			} else {
				flags = read_c0_status();
				__enable_fpu();
				__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
				write_c0_status(flags);
			}
360 361 362 363
#ifdef CONFIG_MIPS_MT_SMTC
			emt(mtflags);
			local_irq_restore(irqflags);
#endif /* CONFIG_MIPS_MT_SMTC */
364
			preempt_enable();
L
Linus Torvalds 已提交
365 366
			break;
		}
367 368 369
		case DSP_BASE ... DSP_BASE + 5: {
			dspreg_t *dregs;

370 371 372
			if (!cpu_has_dsp) {
				tmp = 0;
				ret = -EIO;
373
				goto out;
374
			}
R
Ralf Baechle 已提交
375 376
			dregs = __get_dsp_regs(child);
			tmp = (unsigned long) (dregs[addr - DSP_BASE]);
377
			break;
378
		}
379 380 381 382
		case DSP_CONTROL:
			if (!cpu_has_dsp) {
				tmp = 0;
				ret = -EIO;
383
				goto out;
384 385 386
			}
			tmp = child->thread.dsp.dspcontrol;
			break;
L
Linus Torvalds 已提交
387 388 389
		default:
			tmp = 0;
			ret = -EIO;
390
			goto out;
L
Linus Torvalds 已提交
391
		}
392
		ret = put_user(tmp, datalp);
L
Linus Torvalds 已提交
393 394 395 396 397 398
		break;
	}

	/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
A
Alexey Dobriyan 已提交
399
		ret = generic_ptrace_pokedata(child, addr, data);
L
Linus Torvalds 已提交
400 401 402 403 404
		break;

	case PTRACE_POKEUSR: {
		struct pt_regs *regs;
		ret = 0;
A
Al Viro 已提交
405
		regs = task_pt_regs(child);
L
Linus Torvalds 已提交
406 407 408 409 410 411 412 413 414 415

		switch (addr) {
		case 0 ... 31:
			regs->regs[addr] = data;
			break;
		case FPR_BASE ... FPR_BASE + 31: {
			fpureg_t *fregs = get_fpu_regs(child);

			if (!tsk_used_math(child)) {
				/* FP not yet used  */
416 417 418
				memset(&child->thread.fpu, ~0,
				       sizeof(child->thread.fpu));
				child->thread.fpu.fcr31 = 0;
L
Linus Torvalds 已提交
419
			}
420
#ifdef CONFIG_32BIT
L
Linus Torvalds 已提交
421 422 423 424 425 426 427 428 429 430 431 432 433
			/*
			 * The odd registers are actually the high order bits
			 * of the values stored in the even registers - unless
			 * we're using r2k_switch.S.
			 */
			if (addr & 1) {
				fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
				fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
			} else {
				fregs[addr - FPR_BASE] &= ~0xffffffffLL;
				fregs[addr - FPR_BASE] |= data;
			}
#endif
434
#ifdef CONFIG_64BIT
L
Linus Torvalds 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447
			fregs[addr - FPR_BASE] = data;
#endif
			break;
		}
		case PC:
			regs->cp0_epc = data;
			break;
		case MMHI:
			regs->hi = data;
			break;
		case MMLO:
			regs->lo = data;
			break;
448 449 450 451 452
#ifdef CONFIG_CPU_HAS_SMARTMIPS
		case ACX:
			regs->acx = data;
			break;
#endif
L
Linus Torvalds 已提交
453
		case FPC_CSR:
454
			child->thread.fpu.fcr31 = data;
L
Linus Torvalds 已提交
455
			break;
456 457 458
		case DSP_BASE ... DSP_BASE + 5: {
			dspreg_t *dregs;

459 460 461 462 463
			if (!cpu_has_dsp) {
				ret = -EIO;
				break;
			}

464
			dregs = __get_dsp_regs(child);
465 466
			dregs[addr - DSP_BASE] = data;
			break;
467
		}
468 469 470 471 472 473 474
		case DSP_CONTROL:
			if (!cpu_has_dsp) {
				ret = -EIO;
				break;
			}
			child->thread.dsp.dspcontrol = data;
			break;
L
Linus Torvalds 已提交
475 476 477 478 479 480 481 482
		default:
			/* The rest are not allowed. */
			ret = -EIO;
			break;
		}
		break;
		}

483
	case PTRACE_GETREGS:
484
		ret = ptrace_getregs(child, datavp);
485 486 487
		break;

	case PTRACE_SETREGS:
488
		ret = ptrace_setregs(child, datavp);
489 490 491
		break;

	case PTRACE_GETFPREGS:
492
		ret = ptrace_getfpregs(child, datavp);
493 494 495
		break;

	case PTRACE_SETFPREGS:
496
		ret = ptrace_setfpregs(child, datavp);
497 498
		break;

R
Ralf Baechle 已提交
499
	case PTRACE_GET_THREAD_AREA:
500
		ret = put_user(task_thread_info(child)->tp_value, datalp);
R
Ralf Baechle 已提交
501 502
		break;

503
	case PTRACE_GET_WATCH_REGS:
504
		ret = ptrace_get_watch_regs(child, addrp);
505 506 507
		break;

	case PTRACE_SET_WATCH_REGS:
508
		ret = ptrace_set_watch_regs(child, addrp);
509 510
		break;

L
Linus Torvalds 已提交
511 512 513 514
	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
515
 out:
L
Linus Torvalds 已提交
516 517 518
	return ret;
}

Y
Yoichi Yuasa 已提交
519
static inline int audit_arch(void)
520
{
521
	int arch = EM_MIPS;
522
#ifdef CONFIG_64BIT
523 524 525 526 527 528
	arch |=  __AUDIT_ARCH_64BIT;
#endif
#if defined(__LITTLE_ENDIAN)
	arch |=  __AUDIT_ARCH_LE;
#endif
	return arch;
529 530
}

L
Linus Torvalds 已提交
531 532 533 534
/*
 * Notification of system call entry/exit
 * - triggered by current->work.syscall_trace
 */
535
asmlinkage void syscall_trace_enter(struct pt_regs *regs)
L
Linus Torvalds 已提交
536
{
537
	/* do the secure computing check first */
538
	secure_computing(regs->regs[2]);
L
Linus Torvalds 已提交
539 540

	if (!(current->ptrace & PT_PTRACED))
541
		goto out;
542

543 544
	if (!test_thread_flag(TIF_SYSCALL_TRACE))
		goto out;
L
Linus Torvalds 已提交
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559

	/* The 0x80 provides a way for the tracing parent to distinguish
	   between a syscall stop and SIGTRAP delivery */
	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
	                         0x80 : 0));

	/*
	 * this isn't the same as continuing with a signal, but it will do
	 * for normal use.  strace only continues with a signal if the
	 * stopping signal is not SIGTRAP.  -brl
	 */
	if (current->exit_code) {
		send_sig(current->exit_code, current, 1);
		current->exit_code = 0;
	}
560 561

out:
562 563 564
	audit_syscall_entry(audit_arch(), regs->regs[2],
			    regs->regs[4], regs->regs[5],
			    regs->regs[6], regs->regs[7]);
L
Linus Torvalds 已提交
565
}
566 567 568 569 570 571 572

/*
 * Notification of system call entry/exit
 * - triggered by current->work.syscall_trace
 */
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{
573
	audit_syscall_exit(regs);
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595

	if (!(current->ptrace & PT_PTRACED))
		return;

	if (!test_thread_flag(TIF_SYSCALL_TRACE))
		return;

	/* The 0x80 provides a way for the tracing parent to distinguish
	   between a syscall stop and SIGTRAP delivery */
	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
	                         0x80 : 0));

	/*
	 * this isn't the same as continuing with a signal, but it will do
	 * for normal use.  strace only continues with a signal if the
	 * stopping signal is not SIGTRAP.  -brl
	 */
	if (current->exit_code) {
		send_sig(current->exit_code, current, 1);
		current->exit_code = 0;
	}
}