ptrace.c 11.3 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 39
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/bootinfo.h>
40
#include <asm/reg.h>
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49 50 51

/*
 * Called by kernel/ptrace.c when detaching..
 *
 * Make sure single step bits etc are not set.
 */
void ptrace_disable(struct task_struct *child)
{
	/* Nothing to do.. */
}

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(regs->regs[i], data + i);
	__put_user(regs->lo, data + EF_LO - EF_R0);
	__put_user(regs->hi, data + EF_HI - EF_R0);
	__put_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0);
	__put_user(regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0);
	__put_user(regs->cp0_status, data + EF_CP0_STATUS - EF_R0);
	__put_user(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
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
L
Linus Torvalds 已提交
171 172 173 174 175 176
{
	int ret;

	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 已提交
177 178
	case PTRACE_PEEKDATA:
		ret = generic_ptrace_peekdata(child, addr, data);
L
Linus Torvalds 已提交
179 180 181 182 183 184 185
		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 已提交
186
		regs = task_pt_regs(child);
L
Linus Torvalds 已提交
187 188 189 190 191 192 193 194 195 196
		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);

197
#ifdef CONFIG_32BIT
L
Linus Torvalds 已提交
198 199 200 201 202 203 204 205 206 207
				/*
				 * 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
208
#ifdef CONFIG_64BIT
L
Linus Torvalds 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
				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;
230 231 232 233 234
#ifdef CONFIG_CPU_HAS_SMARTMIPS
		case ACX:
			tmp = regs->acx;
			break;
#endif
L
Linus Torvalds 已提交
235
		case FPC_CSR:
236
			tmp = child->thread.fpu.fcr31;
L
Linus Torvalds 已提交
237 238 239
			break;
		case FPC_EIR: {	/* implementation / version register */
			unsigned int flags;
240 241 242 243
#ifdef CONFIG_MIPS_MT_SMTC
			unsigned int irqflags;
			unsigned int mtflags;
#endif /* CONFIG_MIPS_MT_SMTC */
L
Linus Torvalds 已提交
244

245 246 247
			preempt_disable();
			if (!cpu_has_fpu) {
				preempt_enable();
L
Linus Torvalds 已提交
248
				break;
249
			}
L
Linus Torvalds 已提交
250

251 252 253 254 255
#ifdef CONFIG_MIPS_MT_SMTC
			/* Read-modify-write of Status must be atomic */
			local_irq_save(irqflags);
			mtflags = dmt();
#endif /* CONFIG_MIPS_MT_SMTC */
256 257 258 259 260 261 262 263 264 265 266 267 268
			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);
			}
269 270 271 272
#ifdef CONFIG_MIPS_MT_SMTC
			emt(mtflags);
			local_irq_restore(irqflags);
#endif /* CONFIG_MIPS_MT_SMTC */
273
			preempt_enable();
L
Linus Torvalds 已提交
274 275
			break;
		}
276 277 278
		case DSP_BASE ... DSP_BASE + 5: {
			dspreg_t *dregs;

279 280 281
			if (!cpu_has_dsp) {
				tmp = 0;
				ret = -EIO;
282
				goto out;
283
			}
R
Ralf Baechle 已提交
284 285
			dregs = __get_dsp_regs(child);
			tmp = (unsigned long) (dregs[addr - DSP_BASE]);
286
			break;
287
		}
288 289 290 291
		case DSP_CONTROL:
			if (!cpu_has_dsp) {
				tmp = 0;
				ret = -EIO;
292
				goto out;
293 294 295
			}
			tmp = child->thread.dsp.dspcontrol;
			break;
L
Linus Torvalds 已提交
296 297 298
		default:
			tmp = 0;
			ret = -EIO;
299
			goto out;
L
Linus Torvalds 已提交
300
		}
R
Ralf Baechle 已提交
301
		ret = put_user(tmp, (unsigned long __user *) data);
L
Linus Torvalds 已提交
302 303 304 305 306 307
		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 已提交
308
		ret = generic_ptrace_pokedata(child, addr, data);
L
Linus Torvalds 已提交
309 310 311 312 313
		break;

	case PTRACE_POKEUSR: {
		struct pt_regs *regs;
		ret = 0;
A
Al Viro 已提交
314
		regs = task_pt_regs(child);
L
Linus Torvalds 已提交
315 316 317 318 319 320 321 322 323 324

		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  */
325 326 327
				memset(&child->thread.fpu, ~0,
				       sizeof(child->thread.fpu));
				child->thread.fpu.fcr31 = 0;
L
Linus Torvalds 已提交
328
			}
329
#ifdef CONFIG_32BIT
L
Linus Torvalds 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342
			/*
			 * 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
343
#ifdef CONFIG_64BIT
L
Linus Torvalds 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356
			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;
357 358 359 360 361
#ifdef CONFIG_CPU_HAS_SMARTMIPS
		case ACX:
			regs->acx = data;
			break;
#endif
L
Linus Torvalds 已提交
362
		case FPC_CSR:
363
			child->thread.fpu.fcr31 = data;
L
Linus Torvalds 已提交
364
			break;
365 366 367
		case DSP_BASE ... DSP_BASE + 5: {
			dspreg_t *dregs;

368 369 370 371 372
			if (!cpu_has_dsp) {
				ret = -EIO;
				break;
			}

373
			dregs = __get_dsp_regs(child);
374 375
			dregs[addr - DSP_BASE] = data;
			break;
376
		}
377 378 379 380 381 382 383
		case DSP_CONTROL:
			if (!cpu_has_dsp) {
				ret = -EIO;
				break;
			}
			child->thread.dsp.dspcontrol = data;
			break;
L
Linus Torvalds 已提交
384 385 386 387 388 389 390 391
		default:
			/* The rest are not allowed. */
			ret = -EIO;
			break;
		}
		break;
		}

392
	case PTRACE_GETREGS:
393
		ret = ptrace_getregs(child, (__u64 __user *) data);
394 395 396
		break;

	case PTRACE_SETREGS:
397
		ret = ptrace_setregs(child, (__u64 __user *) data);
398 399 400
		break;

	case PTRACE_GETFPREGS:
401
		ret = ptrace_getfpregs(child, (__u32 __user *) data);
402 403 404
		break;

	case PTRACE_SETFPREGS:
405
		ret = ptrace_setfpregs(child, (__u32 __user *) data);
406 407
		break;

L
Linus Torvalds 已提交
408 409 410
	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: { /* restart after signal. */
		ret = -EIO;
411
		if (!valid_signal(data))
L
Linus Torvalds 已提交
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
			break;
		if (request == PTRACE_SYSCALL) {
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}
		else {
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;
	}

	/*
	 * make the child exit.  Best I can do is send it a sigkill.
	 * perhaps it should be put in the status that it wants to
	 * exit.
	 */
	case PTRACE_KILL:
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		wake_up_process(child);
		break;

R
Ralf Baechle 已提交
438
	case PTRACE_GET_THREAD_AREA:
A
Al Viro 已提交
439
		ret = put_user(task_thread_info(child)->tp_value,
R
Ralf Baechle 已提交
440 441 442
				(unsigned long __user *) data);
		break;

L
Linus Torvalds 已提交
443 444 445 446
	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
447
 out:
L
Linus Torvalds 已提交
448 449 450
	return ret;
}

Y
Yoichi Yuasa 已提交
451
static inline int audit_arch(void)
452
{
453
	int arch = EM_MIPS;
454
#ifdef CONFIG_64BIT
455 456 457 458 459 460
	arch |=  __AUDIT_ARCH_64BIT;
#endif
#if defined(__LITTLE_ENDIAN)
	arch |=  __AUDIT_ARCH_LE;
#endif
	return arch;
461 462
}

L
Linus Torvalds 已提交
463 464 465 466 467 468
/*
 * Notification of system call entry/exit
 * - triggered by current->work.syscall_trace
 */
asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
{
469 470 471 472
	/* do the secure computing check first */
	if (!entryexit)
		secure_computing(regs->regs[0]);

473
	if (unlikely(current->audit_context) && entryexit)
474
		audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]),
475
		                   regs->regs[2]);
L
Linus Torvalds 已提交
476 477

	if (!(current->ptrace & PT_PTRACED))
478
		goto out;
479

480 481
	if (!test_thread_flag(TIF_SYSCALL_TRACE))
		goto out;
L
Linus Torvalds 已提交
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496

	/* 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;
	}
497 498

out:
499
	if (unlikely(current->audit_context) && !entryexit)
500
		audit_syscall_entry(audit_arch(), regs->regs[0],
501 502
				    regs->regs[4], regs->regs[5],
				    regs->regs[6], regs->regs[7]);
L
Linus Torvalds 已提交
503
}