| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  *  arch/s390/kernel/ptrace.c | 
 | 3 |  * | 
 | 4 |  *  S390 version | 
 | 5 |  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation | 
 | 6 |  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), | 
 | 7 |  *               Martin Schwidefsky (schwidefsky@de.ibm.com) | 
 | 8 |  * | 
 | 9 |  *  Based on PowerPC version  | 
 | 10 |  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | 
 | 11 |  * | 
 | 12 |  *  Derived from "arch/m68k/kernel/ptrace.c" | 
 | 13 |  *  Copyright (C) 1994 by Hamish Macdonald | 
 | 14 |  *  Taken from linux/kernel/ptrace.c and modified for M680x0. | 
 | 15 |  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds | 
 | 16 |  * | 
 | 17 |  * Modified by Cort Dougan (cort@cs.nmt.edu)  | 
 | 18 |  * | 
 | 19 |  * | 
 | 20 |  * This file is subject to the terms and conditions of the GNU General | 
 | 21 |  * Public License.  See the file README.legal in the main directory of | 
 | 22 |  * this archive for more details. | 
 | 23 |  */ | 
 | 24 |  | 
 | 25 | #include <linux/kernel.h> | 
 | 26 | #include <linux/sched.h> | 
 | 27 | #include <linux/mm.h> | 
 | 28 | #include <linux/smp.h> | 
 | 29 | #include <linux/smp_lock.h> | 
 | 30 | #include <linux/errno.h> | 
 | 31 | #include <linux/ptrace.h> | 
 | 32 | #include <linux/user.h> | 
 | 33 | #include <linux/security.h> | 
 | 34 | #include <linux/audit.h> | 
| Jesper Juhl | 7ed20e1 | 2005-05-01 08:59:14 -0700 | [diff] [blame] | 35 | #include <linux/signal.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 |  | 
 | 37 | #include <asm/segment.h> | 
 | 38 | #include <asm/page.h> | 
 | 39 | #include <asm/pgtable.h> | 
 | 40 | #include <asm/pgalloc.h> | 
 | 41 | #include <asm/system.h> | 
 | 42 | #include <asm/uaccess.h> | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 43 | #include <asm/unistd.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 |  | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 45 | #ifdef CONFIG_COMPAT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 46 | #include "compat_ptrace.h" | 
 | 47 | #endif | 
 | 48 |  | 
 | 49 | static void | 
 | 50 | FixPerRegisters(struct task_struct *task) | 
 | 51 | { | 
 | 52 | 	struct pt_regs *regs; | 
 | 53 | 	per_struct *per_info; | 
 | 54 |  | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 55 | 	regs = task_pt_regs(task); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | 	per_info = (per_struct *) &task->thread.per_info; | 
 | 57 | 	per_info->control_regs.bits.em_instruction_fetch = | 
 | 58 | 		per_info->single_step | per_info->instruction_fetch; | 
 | 59 | 	 | 
 | 60 | 	if (per_info->single_step) { | 
 | 61 | 		per_info->control_regs.bits.starting_addr = 0; | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 62 | #ifdef CONFIG_COMPAT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | 		if (test_thread_flag(TIF_31BIT)) | 
 | 64 | 			per_info->control_regs.bits.ending_addr = 0x7fffffffUL; | 
 | 65 | 		else | 
 | 66 | #endif | 
 | 67 | 			per_info->control_regs.bits.ending_addr = PSW_ADDR_INSN; | 
 | 68 | 	} else { | 
 | 69 | 		per_info->control_regs.bits.starting_addr = | 
 | 70 | 			per_info->starting_addr; | 
 | 71 | 		per_info->control_regs.bits.ending_addr = | 
 | 72 | 			per_info->ending_addr; | 
 | 73 | 	} | 
 | 74 | 	/* | 
 | 75 | 	 * if any of the control reg tracing bits are on  | 
 | 76 | 	 * we switch on per in the psw | 
 | 77 | 	 */ | 
 | 78 | 	if (per_info->control_regs.words.cr[0] & PER_EM_MASK) | 
 | 79 | 		regs->psw.mask |= PSW_MASK_PER; | 
 | 80 | 	else | 
 | 81 | 		regs->psw.mask &= ~PSW_MASK_PER; | 
 | 82 |  | 
 | 83 | 	if (per_info->control_regs.bits.em_storage_alteration) | 
 | 84 | 		per_info->control_regs.bits.storage_alt_space_ctl = 1; | 
 | 85 | 	else | 
 | 86 | 		per_info->control_regs.bits.storage_alt_space_ctl = 0; | 
 | 87 | } | 
 | 88 |  | 
 | 89 | void | 
 | 90 | set_single_step(struct task_struct *task) | 
 | 91 | { | 
 | 92 | 	task->thread.per_info.single_step = 1; | 
 | 93 | 	FixPerRegisters(task); | 
 | 94 | } | 
 | 95 |  | 
 | 96 | void | 
 | 97 | clear_single_step(struct task_struct *task) | 
 | 98 | { | 
 | 99 | 	task->thread.per_info.single_step = 0; | 
 | 100 | 	FixPerRegisters(task); | 
 | 101 | } | 
 | 102 |  | 
 | 103 | /* | 
 | 104 |  * Called by kernel/ptrace.c when detaching.. | 
 | 105 |  * | 
 | 106 |  * Make sure single step bits etc are not set. | 
 | 107 |  */ | 
 | 108 | void | 
 | 109 | ptrace_disable(struct task_struct *child) | 
 | 110 | { | 
 | 111 | 	/* make sure the single step bit is not set. */ | 
 | 112 | 	clear_single_step(child); | 
 | 113 | } | 
 | 114 |  | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 115 | #ifndef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | # define __ADDR_MASK 3 | 
 | 117 | #else | 
 | 118 | # define __ADDR_MASK 7 | 
 | 119 | #endif | 
 | 120 |  | 
 | 121 | /* | 
 | 122 |  * Read the word at offset addr from the user area of a process. The | 
 | 123 |  * trouble here is that the information is littered over different | 
 | 124 |  * locations. The process registers are found on the kernel stack, | 
 | 125 |  * the floating point stuff and the trace settings are stored in | 
 | 126 |  * the task structure. In addition the different structures in | 
 | 127 |  * struct user contain pad bytes that should be read as zeroes. | 
 | 128 |  * Lovely... | 
 | 129 |  */ | 
 | 130 | static int | 
 | 131 | peek_user(struct task_struct *child, addr_t addr, addr_t data) | 
 | 132 | { | 
 | 133 | 	struct user *dummy = NULL; | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 134 | 	addr_t offset, tmp, mask; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 |  | 
 | 136 | 	/* | 
 | 137 | 	 * Stupid gdb peeks/pokes the access registers in 64 bit with | 
 | 138 | 	 * an alignment of 4. Programmers from hell... | 
 | 139 | 	 */ | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 140 | 	mask = __ADDR_MASK; | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 141 | #ifdef CONFIG_64BIT | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 142 | 	if (addr >= (addr_t) &dummy->regs.acrs && | 
 | 143 | 	    addr < (addr_t) &dummy->regs.orig_gpr2) | 
 | 144 | 		mask = 3; | 
 | 145 | #endif | 
 | 146 | 	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | 		return -EIO; | 
 | 148 |  | 
 | 149 | 	if (addr < (addr_t) &dummy->regs.acrs) { | 
 | 150 | 		/* | 
 | 151 | 		 * psw and gprs are stored on the stack | 
 | 152 | 		 */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 153 | 		tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 154 | 		if (addr == (addr_t) &dummy->regs.psw.mask) | 
 | 155 | 			/* Remove per bit from user psw. */ | 
 | 156 | 			tmp &= ~PSW_MASK_PER; | 
 | 157 |  | 
 | 158 | 	} else if (addr < (addr_t) &dummy->regs.orig_gpr2) { | 
 | 159 | 		/* | 
 | 160 | 		 * access registers are stored in the thread structure | 
 | 161 | 		 */ | 
 | 162 | 		offset = addr - (addr_t) &dummy->regs.acrs; | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 163 | #ifdef CONFIG_64BIT | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 164 | 		/* | 
 | 165 | 		 * Very special case: old & broken 64 bit gdb reading | 
 | 166 | 		 * from acrs[15]. Result is a 64 bit value. Read the | 
 | 167 | 		 * 32 bit acrs[15] value and shift it by 32. Sick... | 
 | 168 | 		 */ | 
 | 169 | 		if (addr == (addr_t) &dummy->regs.acrs[15]) | 
 | 170 | 			tmp = ((unsigned long) child->thread.acrs[15]) << 32; | 
 | 171 | 		else | 
 | 172 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 | 		tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset); | 
 | 174 |  | 
 | 175 | 	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) { | 
 | 176 | 		/* | 
 | 177 | 		 * orig_gpr2 is stored on the kernel stack | 
 | 178 | 		 */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 179 | 		tmp = (addr_t) task_pt_regs(child)->orig_gpr2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 |  | 
 | 181 | 	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 
 | 182 | 		/*  | 
 | 183 | 		 * floating point regs. are stored in the thread structure | 
 | 184 | 		 */ | 
 | 185 | 		offset = addr - (addr_t) &dummy->regs.fp_regs; | 
 | 186 | 		tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 187 | 		if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 
 | 188 | 			tmp &= (unsigned long) FPC_VALID_MASK | 
 | 189 | 				<< (BITS_PER_LONG - 32); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 190 |  | 
 | 191 | 	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 
 | 192 | 		/* | 
 | 193 | 		 * per_info is found in the thread structure | 
 | 194 | 		 */ | 
 | 195 | 		offset = addr - (addr_t) &dummy->regs.per_info; | 
 | 196 | 		tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset); | 
 | 197 |  | 
 | 198 | 	} else | 
 | 199 | 		tmp = 0; | 
 | 200 |  | 
 | 201 | 	return put_user(tmp, (addr_t __user *) data); | 
 | 202 | } | 
 | 203 |  | 
 | 204 | /* | 
 | 205 |  * Write a word to the user area of a process at location addr. This | 
 | 206 |  * operation does have an additional problem compared to peek_user. | 
 | 207 |  * Stores to the program status word and on the floating point | 
 | 208 |  * control register needs to get checked for validity. | 
 | 209 |  */ | 
 | 210 | static int | 
 | 211 | poke_user(struct task_struct *child, addr_t addr, addr_t data) | 
 | 212 | { | 
 | 213 | 	struct user *dummy = NULL; | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 214 | 	addr_t offset, mask; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 215 |  | 
 | 216 | 	/* | 
 | 217 | 	 * Stupid gdb peeks/pokes the access registers in 64 bit with | 
 | 218 | 	 * an alignment of 4. Programmers from hell indeed... | 
 | 219 | 	 */ | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 220 | 	mask = __ADDR_MASK; | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 221 | #ifdef CONFIG_64BIT | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 222 | 	if (addr >= (addr_t) &dummy->regs.acrs && | 
 | 223 | 	    addr < (addr_t) &dummy->regs.orig_gpr2) | 
 | 224 | 		mask = 3; | 
 | 225 | #endif | 
 | 226 | 	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 227 | 		return -EIO; | 
 | 228 |  | 
 | 229 | 	if (addr < (addr_t) &dummy->regs.acrs) { | 
 | 230 | 		/* | 
 | 231 | 		 * psw and gprs are stored on the stack | 
 | 232 | 		 */ | 
 | 233 | 		if (addr == (addr_t) &dummy->regs.psw.mask && | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 234 | #ifdef CONFIG_COMPAT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | 		    data != PSW_MASK_MERGE(PSW_USER32_BITS, data) && | 
 | 236 | #endif | 
 | 237 | 		    data != PSW_MASK_MERGE(PSW_USER_BITS, data)) | 
 | 238 | 			/* Invalid psw mask. */ | 
 | 239 | 			return -EINVAL; | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 240 | #ifndef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 241 | 		if (addr == (addr_t) &dummy->regs.psw.addr) | 
 | 242 | 			/* I'd like to reject addresses without the | 
 | 243 | 			   high order bit but older gdb's rely on it */ | 
 | 244 | 			data |= PSW_ADDR_AMODE; | 
 | 245 | #endif | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 246 | 		*(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 247 |  | 
 | 248 | 	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { | 
 | 249 | 		/* | 
 | 250 | 		 * access registers are stored in the thread structure | 
 | 251 | 		 */ | 
 | 252 | 		offset = addr - (addr_t) &dummy->regs.acrs; | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 253 | #ifdef CONFIG_64BIT | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 254 | 		/* | 
 | 255 | 		 * Very special case: old & broken 64 bit gdb writing | 
 | 256 | 		 * to acrs[15] with a 64 bit value. Ignore the lower | 
 | 257 | 		 * half of the value and write the upper 32 bit to | 
 | 258 | 		 * acrs[15]. Sick... | 
 | 259 | 		 */ | 
 | 260 | 		if (addr == (addr_t) &dummy->regs.acrs[15]) | 
 | 261 | 			child->thread.acrs[15] = (unsigned int) (data >> 32); | 
 | 262 | 		else | 
 | 263 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | 		*(addr_t *)((addr_t) &child->thread.acrs + offset) = data; | 
 | 265 |  | 
 | 266 | 	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) { | 
 | 267 | 		/* | 
 | 268 | 		 * orig_gpr2 is stored on the kernel stack | 
 | 269 | 		 */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 270 | 		task_pt_regs(child)->orig_gpr2 = data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 271 |  | 
 | 272 | 	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 
 | 273 | 		/* | 
 | 274 | 		 * floating point regs. are stored in the thread structure | 
 | 275 | 		 */ | 
 | 276 | 		if (addr == (addr_t) &dummy->regs.fp_regs.fpc && | 
| Martin Schwidefsky | 778959d | 2005-06-04 15:43:30 -0700 | [diff] [blame] | 277 | 		    (data & ~((unsigned long) FPC_VALID_MASK | 
 | 278 | 			      << (BITS_PER_LONG - 32))) != 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 279 | 			return -EINVAL; | 
 | 280 | 		offset = addr - (addr_t) &dummy->regs.fp_regs; | 
 | 281 | 		*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; | 
 | 282 |  | 
 | 283 | 	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 
 | 284 | 		/* | 
 | 285 | 		 * per_info is found in the thread structure  | 
 | 286 | 		 */ | 
 | 287 | 		offset = addr - (addr_t) &dummy->regs.per_info; | 
 | 288 | 		*(addr_t *)((addr_t) &child->thread.per_info + offset) = data; | 
 | 289 |  | 
 | 290 | 	} | 
 | 291 |  | 
 | 292 | 	FixPerRegisters(child); | 
 | 293 | 	return 0; | 
 | 294 | } | 
 | 295 |  | 
 | 296 | static int | 
 | 297 | do_ptrace_normal(struct task_struct *child, long request, long addr, long data) | 
 | 298 | { | 
 | 299 | 	unsigned long tmp; | 
 | 300 | 	ptrace_area parea;  | 
 | 301 | 	int copied, ret; | 
 | 302 |  | 
 | 303 | 	switch (request) { | 
 | 304 | 	case PTRACE_PEEKTEXT: | 
 | 305 | 	case PTRACE_PEEKDATA: | 
 | 306 | 		/* Remove high order bit from address (only for 31 bit). */ | 
 | 307 | 		addr &= PSW_ADDR_INSN; | 
 | 308 | 		/* read word at location addr. */ | 
 | 309 | 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | 
 | 310 | 		if (copied != sizeof(tmp)) | 
 | 311 | 			return -EIO; | 
 | 312 | 		return put_user(tmp, (unsigned long __user *) data); | 
 | 313 |  | 
 | 314 | 	case PTRACE_PEEKUSR: | 
 | 315 | 		/* read the word at location addr in the USER area. */ | 
 | 316 | 		return peek_user(child, addr, data); | 
 | 317 |  | 
 | 318 | 	case PTRACE_POKETEXT: | 
 | 319 | 	case PTRACE_POKEDATA: | 
 | 320 | 		/* Remove high order bit from address (only for 31 bit). */ | 
 | 321 | 		addr &= PSW_ADDR_INSN; | 
 | 322 | 		/* write the word at location addr. */ | 
 | 323 | 		copied = access_process_vm(child, addr, &data, sizeof(data),1); | 
 | 324 | 		if (copied != sizeof(data)) | 
 | 325 | 			return -EIO; | 
 | 326 | 		return 0; | 
 | 327 |  | 
 | 328 | 	case PTRACE_POKEUSR: | 
 | 329 | 		/* write the word at location addr in the USER area */ | 
 | 330 | 		return poke_user(child, addr, data); | 
 | 331 |  | 
 | 332 | 	case PTRACE_PEEKUSR_AREA: | 
 | 333 | 	case PTRACE_POKEUSR_AREA: | 
 | 334 | 		if (copy_from_user(&parea, (void __user *) addr, | 
 | 335 | 							sizeof(parea))) | 
 | 336 | 			return -EFAULT; | 
 | 337 | 		addr = parea.kernel_addr; | 
 | 338 | 		data = parea.process_addr; | 
 | 339 | 		copied = 0; | 
 | 340 | 		while (copied < parea.len) { | 
 | 341 | 			if (request == PTRACE_PEEKUSR_AREA) | 
 | 342 | 				ret = peek_user(child, addr, data); | 
 | 343 | 			else { | 
 | 344 | 				addr_t tmp; | 
 | 345 | 				if (get_user (tmp, (addr_t __user *) data)) | 
 | 346 | 					return -EFAULT; | 
 | 347 | 				ret = poke_user(child, addr, tmp); | 
 | 348 | 			} | 
 | 349 | 			if (ret) | 
 | 350 | 				return ret; | 
 | 351 | 			addr += sizeof(unsigned long); | 
 | 352 | 			data += sizeof(unsigned long); | 
 | 353 | 			copied += sizeof(unsigned long); | 
 | 354 | 		} | 
 | 355 | 		return 0; | 
 | 356 | 	} | 
 | 357 | 	return ptrace_request(child, request, addr, data); | 
 | 358 | } | 
 | 359 |  | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 360 | #ifdef CONFIG_COMPAT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 361 | /* | 
 | 362 |  * Now the fun part starts... a 31 bit program running in the | 
 | 363 |  * 31 bit emulation tracing another program. PTRACE_PEEKTEXT, | 
 | 364 |  * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy | 
 | 365 |  * to handle, the difference to the 64 bit versions of the requests | 
 | 366 |  * is that the access is done in multiples of 4 byte instead of | 
 | 367 |  * 8 bytes (sizeof(unsigned long) on 31/64 bit). | 
 | 368 |  * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA, | 
 | 369 |  * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program | 
 | 370 |  * is a 31 bit program too, the content of struct user can be | 
 | 371 |  * emulated. A 31 bit program peeking into the struct user of | 
 | 372 |  * a 64 bit program is a no-no. | 
 | 373 |  */ | 
 | 374 |  | 
 | 375 | /* | 
 | 376 |  * Same as peek_user but for a 31 bit program. | 
 | 377 |  */ | 
 | 378 | static int | 
 | 379 | peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) | 
 | 380 | { | 
 | 381 | 	struct user32 *dummy32 = NULL; | 
 | 382 | 	per_struct32 *dummy_per32 = NULL; | 
 | 383 | 	addr_t offset; | 
 | 384 | 	__u32 tmp; | 
 | 385 |  | 
 | 386 | 	if (!test_thread_flag(TIF_31BIT) || | 
 | 387 | 	    (addr & 3) || addr > sizeof(struct user) - 3) | 
 | 388 | 		return -EIO; | 
 | 389 |  | 
 | 390 | 	if (addr < (addr_t) &dummy32->regs.acrs) { | 
 | 391 | 		/* | 
 | 392 | 		 * psw and gprs are stored on the stack | 
 | 393 | 		 */ | 
 | 394 | 		if (addr == (addr_t) &dummy32->regs.psw.mask) { | 
 | 395 | 			/* Fake a 31 bit psw mask. */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 396 | 			tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 397 | 			tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp); | 
 | 398 | 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) { | 
 | 399 | 			/* Fake a 31 bit psw address. */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 400 | 			tmp = (__u32) task_pt_regs(child)->psw.addr | | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 401 | 				PSW32_ADDR_AMODE31; | 
 | 402 | 		} else { | 
 | 403 | 			/* gpr 0-15 */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 404 | 			tmp = *(__u32 *)((addr_t) &task_pt_regs(child)->psw + | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 405 | 					 addr*2 + 4); | 
 | 406 | 		} | 
 | 407 | 	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { | 
 | 408 | 		/* | 
 | 409 | 		 * access registers are stored in the thread structure | 
 | 410 | 		 */ | 
 | 411 | 		offset = addr - (addr_t) &dummy32->regs.acrs; | 
 | 412 | 		tmp = *(__u32*)((addr_t) &child->thread.acrs + offset); | 
 | 413 |  | 
 | 414 | 	} else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { | 
 | 415 | 		/* | 
 | 416 | 		 * orig_gpr2 is stored on the kernel stack | 
 | 417 | 		 */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 418 | 		tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 419 |  | 
 | 420 | 	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 
 | 421 | 		/* | 
 | 422 | 		 * floating point regs. are stored in the thread structure  | 
 | 423 | 		 */ | 
 | 424 | 	        offset = addr - (addr_t) &dummy32->regs.fp_regs; | 
 | 425 | 		tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset); | 
 | 426 |  | 
 | 427 | 	} else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 
 | 428 | 		/* | 
 | 429 | 		 * per_info is found in the thread structure | 
 | 430 | 		 */ | 
 | 431 | 		offset = addr - (addr_t) &dummy32->regs.per_info; | 
 | 432 | 		/* This is magic. See per_struct and per_struct32. */ | 
 | 433 | 		if ((offset >= (addr_t) &dummy_per32->control_regs && | 
 | 434 | 		     offset < (addr_t) (&dummy_per32->control_regs + 1)) || | 
 | 435 | 		    (offset >= (addr_t) &dummy_per32->starting_addr && | 
 | 436 | 		     offset <= (addr_t) &dummy_per32->ending_addr) || | 
 | 437 | 		    offset == (addr_t) &dummy_per32->lowcore.words.address) | 
 | 438 | 			offset = offset*2 + 4; | 
 | 439 | 		else | 
 | 440 | 			offset = offset*2; | 
 | 441 | 		tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset); | 
 | 442 |  | 
 | 443 | 	} else | 
 | 444 | 		tmp = 0; | 
 | 445 |  | 
 | 446 | 	return put_user(tmp, (__u32 __user *) data); | 
 | 447 | } | 
 | 448 |  | 
 | 449 | /* | 
 | 450 |  * Same as poke_user but for a 31 bit program. | 
 | 451 |  */ | 
 | 452 | static int | 
 | 453 | poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) | 
 | 454 | { | 
 | 455 | 	struct user32 *dummy32 = NULL; | 
 | 456 | 	per_struct32 *dummy_per32 = NULL; | 
 | 457 | 	addr_t offset; | 
 | 458 | 	__u32 tmp; | 
 | 459 |  | 
 | 460 | 	if (!test_thread_flag(TIF_31BIT) || | 
 | 461 | 	    (addr & 3) || addr > sizeof(struct user32) - 3) | 
 | 462 | 		return -EIO; | 
 | 463 |  | 
 | 464 | 	tmp = (__u32) data; | 
 | 465 |  | 
 | 466 | 	if (addr < (addr_t) &dummy32->regs.acrs) { | 
 | 467 | 		/* | 
 | 468 | 		 * psw, gprs, acrs and orig_gpr2 are stored on the stack | 
 | 469 | 		 */ | 
 | 470 | 		if (addr == (addr_t) &dummy32->regs.psw.mask) { | 
 | 471 | 			/* Build a 64 bit psw mask from 31 bit mask. */ | 
 | 472 | 			if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp)) | 
 | 473 | 				/* Invalid psw mask. */ | 
 | 474 | 				return -EINVAL; | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 475 | 			task_pt_regs(child)->psw.mask = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 476 | 				PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32); | 
 | 477 | 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) { | 
 | 478 | 			/* Build a 64 bit psw address from 31 bit address. */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 479 | 			task_pt_regs(child)->psw.addr = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 480 | 				(__u64) tmp & PSW32_ADDR_INSN; | 
 | 481 | 		} else { | 
 | 482 | 			/* gpr 0-15 */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 483 | 			*(__u32*)((addr_t) &task_pt_regs(child)->psw | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 484 | 				  + addr*2 + 4) = tmp; | 
 | 485 | 		} | 
 | 486 | 	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { | 
 | 487 | 		/* | 
 | 488 | 		 * access registers are stored in the thread structure | 
 | 489 | 		 */ | 
 | 490 | 		offset = addr - (addr_t) &dummy32->regs.acrs; | 
 | 491 | 		*(__u32*)((addr_t) &child->thread.acrs + offset) = tmp; | 
 | 492 |  | 
 | 493 | 	} else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { | 
 | 494 | 		/* | 
 | 495 | 		 * orig_gpr2 is stored on the kernel stack | 
 | 496 | 		 */ | 
| Al Viro | c7584fb | 2006-01-12 01:05:49 -0800 | [diff] [blame] | 497 | 		*(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 498 |  | 
 | 499 | 	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 
 | 500 | 		/* | 
 | 501 | 		 * floating point regs. are stored in the thread structure  | 
 | 502 | 		 */ | 
 | 503 | 		if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && | 
 | 504 | 		    (tmp & ~FPC_VALID_MASK) != 0) | 
 | 505 | 			/* Invalid floating point control. */ | 
 | 506 | 			return -EINVAL; | 
 | 507 | 	        offset = addr - (addr_t) &dummy32->regs.fp_regs; | 
 | 508 | 		*(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; | 
 | 509 |  | 
 | 510 | 	} else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 
 | 511 | 		/* | 
 | 512 | 		 * per_info is found in the thread structure. | 
 | 513 | 		 */ | 
 | 514 | 		offset = addr - (addr_t) &dummy32->regs.per_info; | 
 | 515 | 		/* | 
 | 516 | 		 * This is magic. See per_struct and per_struct32. | 
 | 517 | 		 * By incident the offsets in per_struct are exactly | 
 | 518 | 		 * twice the offsets in per_struct32 for all fields. | 
 | 519 | 		 * The 8 byte fields need special handling though, | 
 | 520 | 		 * because the second half (bytes 4-7) is needed and | 
 | 521 | 		 * not the first half. | 
 | 522 | 		 */ | 
 | 523 | 		if ((offset >= (addr_t) &dummy_per32->control_regs && | 
 | 524 | 		     offset < (addr_t) (&dummy_per32->control_regs + 1)) || | 
 | 525 | 		    (offset >= (addr_t) &dummy_per32->starting_addr && | 
 | 526 | 		     offset <= (addr_t) &dummy_per32->ending_addr) || | 
 | 527 | 		    offset == (addr_t) &dummy_per32->lowcore.words.address) | 
 | 528 | 			offset = offset*2 + 4; | 
 | 529 | 		else | 
 | 530 | 			offset = offset*2; | 
 | 531 | 		*(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp; | 
 | 532 |  | 
 | 533 | 	} | 
 | 534 |  | 
 | 535 | 	FixPerRegisters(child); | 
 | 536 | 	return 0; | 
 | 537 | } | 
 | 538 |  | 
 | 539 | static int | 
 | 540 | do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) | 
 | 541 | { | 
 | 542 | 	unsigned int tmp;  /* 4 bytes !! */ | 
 | 543 | 	ptrace_area_emu31 parea;  | 
 | 544 | 	int copied, ret; | 
 | 545 |  | 
 | 546 | 	switch (request) { | 
 | 547 | 	case PTRACE_PEEKTEXT: | 
 | 548 | 	case PTRACE_PEEKDATA: | 
 | 549 | 		/* read word at location addr. */ | 
 | 550 | 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | 
 | 551 | 		if (copied != sizeof(tmp)) | 
 | 552 | 			return -EIO; | 
 | 553 | 		return put_user(tmp, (unsigned int __user *) data); | 
 | 554 |  | 
 | 555 | 	case PTRACE_PEEKUSR: | 
 | 556 | 		/* read the word at location addr in the USER area. */ | 
 | 557 | 		return peek_user_emu31(child, addr, data); | 
 | 558 |  | 
 | 559 | 	case PTRACE_POKETEXT: | 
 | 560 | 	case PTRACE_POKEDATA: | 
 | 561 | 		/* write the word at location addr. */ | 
 | 562 | 		tmp = data; | 
 | 563 | 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1); | 
 | 564 | 		if (copied != sizeof(tmp)) | 
 | 565 | 			return -EIO; | 
 | 566 | 		return 0; | 
 | 567 |  | 
 | 568 | 	case PTRACE_POKEUSR: | 
 | 569 | 		/* write the word at location addr in the USER area */ | 
 | 570 | 		return poke_user_emu31(child, addr, data); | 
 | 571 |  | 
 | 572 | 	case PTRACE_PEEKUSR_AREA: | 
 | 573 | 	case PTRACE_POKEUSR_AREA: | 
 | 574 | 		if (copy_from_user(&parea, (void __user *) addr, | 
 | 575 | 							sizeof(parea))) | 
 | 576 | 			return -EFAULT; | 
 | 577 | 		addr = parea.kernel_addr; | 
 | 578 | 		data = parea.process_addr; | 
 | 579 | 		copied = 0; | 
 | 580 | 		while (copied < parea.len) { | 
 | 581 | 			if (request == PTRACE_PEEKUSR_AREA) | 
 | 582 | 				ret = peek_user_emu31(child, addr, data); | 
 | 583 | 			else { | 
 | 584 | 				__u32 tmp; | 
 | 585 | 				if (get_user (tmp, (__u32 __user *) data)) | 
 | 586 | 					return -EFAULT; | 
 | 587 | 				ret = poke_user_emu31(child, addr, tmp); | 
 | 588 | 			} | 
 | 589 | 			if (ret) | 
 | 590 | 				return ret; | 
 | 591 | 			addr += sizeof(unsigned int); | 
 | 592 | 			data += sizeof(unsigned int); | 
 | 593 | 			copied += sizeof(unsigned int); | 
 | 594 | 		} | 
 | 595 | 		return 0; | 
 | 596 | 	case PTRACE_GETEVENTMSG: | 
 | 597 | 		return put_user((__u32) child->ptrace_message, | 
 | 598 | 				(unsigned int __user *) data); | 
 | 599 | 	case PTRACE_GETSIGINFO: | 
 | 600 | 		if (child->last_siginfo == NULL) | 
 | 601 | 			return -EINVAL; | 
 | 602 | 		return copy_siginfo_to_user32((compat_siginfo_t __user *) data, | 
 | 603 | 					      child->last_siginfo); | 
 | 604 | 	case PTRACE_SETSIGINFO: | 
 | 605 | 		if (child->last_siginfo == NULL) | 
 | 606 | 			return -EINVAL; | 
 | 607 | 		return copy_siginfo_from_user32(child->last_siginfo, | 
 | 608 | 						(compat_siginfo_t __user *) data); | 
 | 609 | 	} | 
 | 610 | 	return ptrace_request(child, request, addr, data); | 
 | 611 | } | 
 | 612 | #endif | 
 | 613 |  | 
 | 614 | #define PT32_IEEE_IP 0x13c | 
 | 615 |  | 
 | 616 | static int | 
 | 617 | do_ptrace(struct task_struct *child, long request, long addr, long data) | 
 | 618 | { | 
 | 619 | 	int ret; | 
 | 620 |  | 
 | 621 | 	if (request == PTRACE_ATTACH) | 
 | 622 | 		return ptrace_attach(child); | 
 | 623 |  | 
 | 624 | 	/* | 
 | 625 | 	 * Special cases to get/store the ieee instructions pointer. | 
 | 626 | 	 */ | 
 | 627 | 	if (child == current) { | 
 | 628 | 		if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP) | 
 | 629 | 			return peek_user(child, addr, data); | 
 | 630 | 		if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP) | 
 | 631 | 			return poke_user(child, addr, data); | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 632 | #ifdef CONFIG_COMPAT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 633 | 		if (request == PTRACE_PEEKUSR && | 
 | 634 | 		    addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) | 
 | 635 | 			return peek_user_emu31(child, addr, data); | 
 | 636 | 		if (request == PTRACE_POKEUSR && | 
 | 637 | 		    addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) | 
 | 638 | 			return poke_user_emu31(child, addr, data); | 
 | 639 | #endif | 
 | 640 | 	} | 
 | 641 |  | 
 | 642 | 	ret = ptrace_check_attach(child, request == PTRACE_KILL); | 
 | 643 | 	if (ret < 0) | 
 | 644 | 		return ret; | 
 | 645 |  | 
 | 646 | 	switch (request) { | 
 | 647 | 	case PTRACE_SYSCALL: | 
 | 648 | 		/* continue and stop at next (return from) syscall */ | 
 | 649 | 	case PTRACE_CONT: | 
 | 650 | 		/* restart after signal. */ | 
| Jesper Juhl | 7ed20e1 | 2005-05-01 08:59:14 -0700 | [diff] [blame] | 651 | 		if (!valid_signal(data)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 652 | 			return -EIO; | 
 | 653 | 		if (request == PTRACE_SYSCALL) | 
 | 654 | 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 
 | 655 | 		else | 
 | 656 | 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 
 | 657 | 		child->exit_code = data; | 
 | 658 | 		/* make sure the single step bit is not set. */ | 
 | 659 | 		clear_single_step(child); | 
 | 660 | 		wake_up_process(child); | 
 | 661 | 		return 0; | 
 | 662 |  | 
 | 663 | 	case PTRACE_KILL: | 
 | 664 | 		/* | 
 | 665 | 		 * make the child exit.  Best I can do is send it a sigkill.  | 
 | 666 | 		 * perhaps it should be put in the status that it wants to  | 
 | 667 | 		 * exit. | 
 | 668 | 		 */ | 
 | 669 | 		if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | 
 | 670 | 			return 0; | 
 | 671 | 		child->exit_code = SIGKILL; | 
 | 672 | 		/* make sure the single step bit is not set. */ | 
 | 673 | 		clear_single_step(child); | 
 | 674 | 		wake_up_process(child); | 
 | 675 | 		return 0; | 
 | 676 |  | 
 | 677 | 	case PTRACE_SINGLESTEP: | 
 | 678 | 		/* set the trap flag. */ | 
| Jesper Juhl | 7ed20e1 | 2005-05-01 08:59:14 -0700 | [diff] [blame] | 679 | 		if (!valid_signal(data)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 680 | 			return -EIO; | 
 | 681 | 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 
 | 682 | 		child->exit_code = data; | 
 | 683 | 		if (data) | 
 | 684 | 			set_tsk_thread_flag(child, TIF_SINGLE_STEP); | 
 | 685 | 		else | 
 | 686 | 			set_single_step(child); | 
 | 687 | 		/* give it a chance to run. */ | 
 | 688 | 		wake_up_process(child); | 
 | 689 | 		return 0; | 
 | 690 |  | 
 | 691 | 	case PTRACE_DETACH: | 
 | 692 | 		/* detach a process that was attached. */ | 
 | 693 | 		return ptrace_detach(child, data); | 
 | 694 |  | 
 | 695 |  | 
 | 696 | 	/* Do requests that differ for 31/64 bit */ | 
 | 697 | 	default: | 
| Martin Schwidefsky | 347a8dc | 2006-01-06 00:19:28 -0800 | [diff] [blame] | 698 | #ifdef CONFIG_COMPAT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 699 | 		if (test_thread_flag(TIF_31BIT)) | 
 | 700 | 			return do_ptrace_emu31(child, request, addr, data); | 
 | 701 | #endif | 
 | 702 | 		return do_ptrace_normal(child, request, addr, data); | 
 | 703 | 	} | 
 | 704 | 	/* Not reached.  */ | 
 | 705 | 	return -EIO; | 
 | 706 | } | 
 | 707 |  | 
 | 708 | asmlinkage long | 
 | 709 | sys_ptrace(long request, long pid, long addr, long data) | 
 | 710 | { | 
 | 711 | 	struct task_struct *child; | 
 | 712 | 	int ret; | 
 | 713 |  | 
 | 714 | 	lock_kernel(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 715 | 	if (request == PTRACE_TRACEME) { | 
| Christoph Hellwig | 6b9c7ed | 2006-01-08 01:02:33 -0800 | [diff] [blame] | 716 | 		 ret = ptrace_traceme(); | 
 | 717 | 		 goto out; | 
 | 718 | 	} | 
 | 719 |  | 
 | 720 | 	child = ptrace_get_task_struct(pid); | 
 | 721 | 	if (IS_ERR(child)) { | 
 | 722 | 		ret = PTR_ERR(child); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 723 | 		goto out; | 
 | 724 | 	} | 
 | 725 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 726 | 	ret = do_ptrace(child, request, addr, data); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 727 | 	put_task_struct(child); | 
 | 728 | out: | 
 | 729 | 	unlock_kernel(); | 
 | 730 | 	return ret; | 
 | 731 | } | 
 | 732 |  | 
 | 733 | asmlinkage void | 
 | 734 | syscall_trace(struct pt_regs *regs, int entryexit) | 
 | 735 | { | 
 | 2fd6f58 | 2005-04-29 16:08:28 +0100 | [diff] [blame] | 736 | 	if (unlikely(current->audit_context) && entryexit) | 
| Al Viro | 5411be5 | 2006-03-29 20:23:36 -0500 | [diff] [blame] | 737 | 		audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); | 
 | 2fd6f58 | 2005-04-29 16:08:28 +0100 | [diff] [blame] | 738 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 739 | 	if (!test_thread_flag(TIF_SYSCALL_TRACE)) | 
 | 2fd6f58 | 2005-04-29 16:08:28 +0100 | [diff] [blame] | 740 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 741 | 	if (!(current->ptrace & PT_PTRACED)) | 
 | 2fd6f58 | 2005-04-29 16:08:28 +0100 | [diff] [blame] | 742 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 743 | 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | 
 | 744 | 				 ? 0x80 : 0)); | 
 | 745 |  | 
 | 746 | 	/* | 
| Bodo Stroesser | c5c3a6d | 2005-06-04 15:43:32 -0700 | [diff] [blame] | 747 | 	 * If the debuffer has set an invalid system call number, | 
 | 748 | 	 * we prepare to skip the system call restart handling. | 
 | 749 | 	 */ | 
 | 750 | 	if (!entryexit && regs->gprs[2] >= NR_syscalls) | 
 | 751 | 		regs->trap = -1; | 
 | 752 |  | 
 | 753 | 	/* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 754 | 	 * this isn't the same as continuing with a signal, but it will do | 
 | 755 | 	 * for normal use.  strace only continues with a signal if the | 
 | 756 | 	 * stopping signal is not SIGTRAP.  -brl | 
 | 757 | 	 */ | 
 | 758 | 	if (current->exit_code) { | 
 | 759 | 		send_sig(current->exit_code, current, 1); | 
 | 760 | 		current->exit_code = 0; | 
 | 761 | 	} | 
 | 2fd6f58 | 2005-04-29 16:08:28 +0100 | [diff] [blame] | 762 |  out: | 
 | 763 | 	if (unlikely(current->audit_context) && !entryexit) | 
| Al Viro | 5411be5 | 2006-03-29 20:23:36 -0500 | [diff] [blame] | 764 | 		audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, | 
 | 2fd6f58 | 2005-04-29 16:08:28 +0100 | [diff] [blame] | 765 | 				    regs->gprs[2], regs->orig_gpr2, regs->gprs[3], | 
 | 766 | 				    regs->gprs[4], regs->gprs[5]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 767 | } |