Blame view

arch/x86/kernel/ptrace.c 35 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /* By Ross Biro 1/23/92 */
  /*
   * Pentium III FXSR, SSE support
   *	Gareth Hughes <gareth@valinux.com>, May 2000
   */
  
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/mm.h>
  #include <linux/smp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/errno.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/ptrace.h>
91e7b707a   Roland McGrath   x86: x86 user_reg...
14
  #include <linux/regset.h>
eeea3c3ff   Roland McGrath   x86: tracehook sy...
15
  #include <linux/tracehook.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/user.h>
070459d95   Roland McGrath   x86: x86 user_reg...
17
  #include <linux/elf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
  #include <linux/security.h>
  #include <linux/audit.h>
  #include <linux/seccomp.h>
7ed20e1ad   Jesper Juhl   [PATCH] convert t...
21
  #include <linux/signal.h>
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
22
23
  #include <linux/perf_event.h>
  #include <linux/hw_breakpoint.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
32
  
  #include <asm/uaccess.h>
  #include <asm/pgtable.h>
  #include <asm/system.h>
  #include <asm/processor.h>
  #include <asm/i387.h>
  #include <asm/debugreg.h>
  #include <asm/ldt.h>
  #include <asm/desc.h>
2047b08be   Roland McGrath   x86: x86 ptrace g...
33
34
  #include <asm/prctl.h>
  #include <asm/proto.h>
72f674d20   K.Prasad   hw-breakpoints: m...
35
  #include <asm/hw_breakpoint.h>
eee3af4a2   Markus Metzger   x86, ptrace: supp...
36

070459d95   Roland McGrath   x86: x86 user_reg...
37
  #include "tls.h"
1c569f026   Josh Stone   tracing: Create g...
38
39
  #define CREATE_TRACE_POINTS
  #include <trace/events/syscalls.h>
070459d95   Roland McGrath   x86: x86 user_reg...
40
41
42
43
  enum x86_regset {
  	REGSET_GENERAL,
  	REGSET_FP,
  	REGSET_XFP,
325af5fb1   Roland McGrath   x86: ioperm user_...
44
  	REGSET_IOPERM64 = REGSET_XFP,
5b3efd500   Suresh Siddha   x86, ptrace: regs...
45
  	REGSET_XSTATE,
070459d95   Roland McGrath   x86: x86 user_reg...
46
  	REGSET_TLS,
325af5fb1   Roland McGrath   x86: ioperm user_...
47
  	REGSET_IOPERM32,
070459d95   Roland McGrath   x86: x86 user_reg...
48
  };
eee3af4a2   Markus Metzger   x86, ptrace: supp...
49

b1cf540f0   Masami Hiramatsu   x86: Add pt_regs ...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  struct pt_regs_offset {
  	const char *name;
  	int offset;
  };
  
  #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
  #define REG_OFFSET_END {.name = NULL, .offset = 0}
  
  static const struct pt_regs_offset regoffset_table[] = {
  #ifdef CONFIG_X86_64
  	REG_OFFSET_NAME(r15),
  	REG_OFFSET_NAME(r14),
  	REG_OFFSET_NAME(r13),
  	REG_OFFSET_NAME(r12),
  	REG_OFFSET_NAME(r11),
  	REG_OFFSET_NAME(r10),
  	REG_OFFSET_NAME(r9),
  	REG_OFFSET_NAME(r8),
  #endif
  	REG_OFFSET_NAME(bx),
  	REG_OFFSET_NAME(cx),
  	REG_OFFSET_NAME(dx),
  	REG_OFFSET_NAME(si),
  	REG_OFFSET_NAME(di),
  	REG_OFFSET_NAME(bp),
  	REG_OFFSET_NAME(ax),
  #ifdef CONFIG_X86_32
  	REG_OFFSET_NAME(ds),
  	REG_OFFSET_NAME(es),
  	REG_OFFSET_NAME(fs),
  	REG_OFFSET_NAME(gs),
  #endif
  	REG_OFFSET_NAME(orig_ax),
  	REG_OFFSET_NAME(ip),
  	REG_OFFSET_NAME(cs),
  	REG_OFFSET_NAME(flags),
  	REG_OFFSET_NAME(sp),
  	REG_OFFSET_NAME(ss),
  	REG_OFFSET_END,
  };
  
  /**
   * regs_query_register_offset() - query register offset from its name
   * @name:	the name of a register
   *
   * regs_query_register_offset() returns the offset of a register in struct
   * pt_regs from its name. If the name is invalid, this returns -EINVAL;
   */
  int regs_query_register_offset(const char *name)
  {
  	const struct pt_regs_offset *roff;
  	for (roff = regoffset_table; roff->name != NULL; roff++)
  		if (!strcmp(roff->name, name))
  			return roff->offset;
  	return -EINVAL;
  }
  
  /**
   * regs_query_register_name() - query register name from its offset
   * @offset:	the offset of a register in struct pt_regs.
   *
   * regs_query_register_name() returns the name of a register from its
   * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
   */
  const char *regs_query_register_name(unsigned int offset)
  {
  	const struct pt_regs_offset *roff;
  	for (roff = regoffset_table; roff->name != NULL; roff++)
  		if (roff->offset == offset)
  			return roff->name;
  	return NULL;
  }
  
  static const int arg_offs_table[] = {
  #ifdef CONFIG_X86_32
  	[0] = offsetof(struct pt_regs, ax),
  	[1] = offsetof(struct pt_regs, dx),
  	[2] = offsetof(struct pt_regs, cx)
  #else /* CONFIG_X86_64 */
  	[0] = offsetof(struct pt_regs, di),
  	[1] = offsetof(struct pt_regs, si),
  	[2] = offsetof(struct pt_regs, dx),
  	[3] = offsetof(struct pt_regs, cx),
  	[4] = offsetof(struct pt_regs, r8),
  	[5] = offsetof(struct pt_regs, r9)
  #endif
  };
eee3af4a2   Markus Metzger   x86, ptrace: supp...
137
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
   * does not yet catch signals sent when the child dies.
   * in exit.c or in signal.c.
   */
9f155b980   Chuck Ebbert   [PATCH] i386: PTR...
141
142
  /*
   * Determines which flags the user has access to [1 = access, 0 = no access].
9f155b980   Chuck Ebbert   [PATCH] i386: PTR...
143
   */
e39c28914   Roland McGrath   x86: ptrace FLAG_...
144
145
146
147
148
149
  #define FLAG_MASK_32		((unsigned long)			\
  				 (X86_EFLAGS_CF | X86_EFLAGS_PF |	\
  				  X86_EFLAGS_AF | X86_EFLAGS_ZF |	\
  				  X86_EFLAGS_SF | X86_EFLAGS_TF |	\
  				  X86_EFLAGS_DF | X86_EFLAGS_OF |	\
  				  X86_EFLAGS_RF | X86_EFLAGS_AC))
2047b08be   Roland McGrath   x86: x86 ptrace g...
150
151
152
153
154
155
156
157
158
  /*
   * Determines whether a value may be installed in a segment register.
   */
  static inline bool invalid_selector(u16 value)
  {
  	return unlikely(value != 0 && (value & SEGMENT_RPL_MASK) != USER_RPL);
  }
  
  #ifdef CONFIG_X86_32
e39c28914   Roland McGrath   x86: ptrace FLAG_...
159
  #define FLAG_MASK		FLAG_MASK_32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

4fe702c7e   Jaswinder Singh   X86_32: declare p...
161
  static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  {
65ea5b034   H. Peter Anvin   x86: rename the s...
163
  	BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
ccbeed3a0   Tejun Heo   x86: make lazy %g...
164
  	return &regs->bx + (regno >> 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
06ee1b687   Roland McGrath   x86: x86 ptrace g...
166
  static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  {
06ee1b687   Roland McGrath   x86: x86 ptrace g...
168
169
170
171
172
173
174
  	/*
  	 * Returning the value truncates it to 16 bits.
  	 */
  	unsigned int retval;
  	if (offset != offsetof(struct user_regs_struct, gs))
  		retval = *pt_regs_access(task_pt_regs(task), offset);
  	else {
06ee1b687   Roland McGrath   x86: x86 ptrace g...
175
  		if (task == current)
d9a89a26e   Tejun Heo   x86: add %gs acce...
176
177
178
  			retval = get_user_gs(task_pt_regs(task));
  		else
  			retval = task_user_gs(task);
06ee1b687   Roland McGrath   x86: x86 ptrace g...
179
180
181
182
183
184
185
186
187
188
  	}
  	return retval;
  }
  
  static int set_segment_reg(struct task_struct *task,
  			   unsigned long offset, u16 value)
  {
  	/*
  	 * The value argument was already truncated to 16 bits.
  	 */
2047b08be   Roland McGrath   x86: x86 ptrace g...
189
  	if (invalid_selector(value))
06ee1b687   Roland McGrath   x86: x86 ptrace g...
190
  		return -EIO;
c63855d04   Roland McGrath   x86 ptrace: disal...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	/*
  	 * For %cs and %ss we cannot permit a null selector.
  	 * We can permit a bogus selector as long as it has USER_RPL.
  	 * Null selectors are fine for other segment registers, but
  	 * we will never get back to user mode with invalid %cs or %ss
  	 * and will take the trap in iret instead.  Much code relies
  	 * on user_mode() to distinguish a user trap frame (which can
  	 * safely use invalid selectors) from a kernel trap frame.
  	 */
  	switch (offset) {
  	case offsetof(struct user_regs_struct, cs):
  	case offsetof(struct user_regs_struct, ss):
  		if (unlikely(value == 0))
  			return -EIO;
  
  	default:
06ee1b687   Roland McGrath   x86: x86 ptrace g...
207
  		*pt_regs_access(task_pt_regs(task), offset) = value;
c63855d04   Roland McGrath   x86 ptrace: disal...
208
209
210
  		break;
  
  	case offsetof(struct user_regs_struct, gs):
06ee1b687   Roland McGrath   x86: x86 ptrace g...
211
  		if (task == current)
d9a89a26e   Tejun Heo   x86: add %gs acce...
212
213
214
  			set_user_gs(task_pt_regs(task), value);
  		else
  			task_user_gs(task) = value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  	}
06ee1b687   Roland McGrath   x86: x86 ptrace g...
216

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
  	return 0;
  }
2047b08be   Roland McGrath   x86: x86 ptrace g...
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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  #else  /* CONFIG_X86_64 */
  
  #define FLAG_MASK		(FLAG_MASK_32 | X86_EFLAGS_NT)
  
  static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long offset)
  {
  	BUILD_BUG_ON(offsetof(struct pt_regs, r15) != 0);
  	return &regs->r15 + (offset / sizeof(regs->r15));
  }
  
  static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
  {
  	/*
  	 * Returning the value truncates it to 16 bits.
  	 */
  	unsigned int seg;
  
  	switch (offset) {
  	case offsetof(struct user_regs_struct, fs):
  		if (task == current) {
  			/* Older gas can't assemble movq %?s,%r?? */
  			asm("movl %%fs,%0" : "=r" (seg));
  			return seg;
  		}
  		return task->thread.fsindex;
  	case offsetof(struct user_regs_struct, gs):
  		if (task == current) {
  			asm("movl %%gs,%0" : "=r" (seg));
  			return seg;
  		}
  		return task->thread.gsindex;
  	case offsetof(struct user_regs_struct, ds):
  		if (task == current) {
  			asm("movl %%ds,%0" : "=r" (seg));
  			return seg;
  		}
  		return task->thread.ds;
  	case offsetof(struct user_regs_struct, es):
  		if (task == current) {
  			asm("movl %%es,%0" : "=r" (seg));
  			return seg;
  		}
  		return task->thread.es;
  
  	case offsetof(struct user_regs_struct, cs):
  	case offsetof(struct user_regs_struct, ss):
  		break;
  	}
  	return *pt_regs_access(task_pt_regs(task), offset);
  }
  
  static int set_segment_reg(struct task_struct *task,
  			   unsigned long offset, u16 value)
  {
  	/*
  	 * The value argument was already truncated to 16 bits.
  	 */
  	if (invalid_selector(value))
  		return -EIO;
  
  	switch (offset) {
  	case offsetof(struct user_regs_struct,fs):
  		/*
  		 * If this is setting fs as for normal 64-bit use but
  		 * setting fs_base has implicitly changed it, leave it.
  		 */
  		if ((value == FS_TLS_SEL && task->thread.fsindex == 0 &&
  		     task->thread.fs != 0) ||
  		    (value == 0 && task->thread.fsindex == FS_TLS_SEL &&
  		     task->thread.fs == 0))
  			break;
  		task->thread.fsindex = value;
  		if (task == current)
  			loadsegment(fs, task->thread.fsindex);
  		break;
  	case offsetof(struct user_regs_struct,gs):
  		/*
  		 * If this is setting gs as for normal 64-bit use but
  		 * setting gs_base has implicitly changed it, leave it.
  		 */
  		if ((value == GS_TLS_SEL && task->thread.gsindex == 0 &&
  		     task->thread.gs != 0) ||
  		    (value == 0 && task->thread.gsindex == GS_TLS_SEL &&
  		     task->thread.gs == 0))
  			break;
  		task->thread.gsindex = value;
  		if (task == current)
  			load_gs_index(task->thread.gsindex);
  		break;
  	case offsetof(struct user_regs_struct,ds):
  		task->thread.ds = value;
  		if (task == current)
  			loadsegment(ds, task->thread.ds);
  		break;
  	case offsetof(struct user_regs_struct,es):
  		task->thread.es = value;
  		if (task == current)
  			loadsegment(es, task->thread.es);
  		break;
  
  		/*
  		 * Can't actually change these in 64-bit mode.
  		 */
  	case offsetof(struct user_regs_struct,cs):
c63855d04   Roland McGrath   x86 ptrace: disal...
323
324
  		if (unlikely(value == 0))
  			return -EIO;
2047b08be   Roland McGrath   x86: x86 ptrace g...
325
326
327
  #ifdef CONFIG_IA32_EMULATION
  		if (test_tsk_thread_flag(task, TIF_IA32))
  			task_pt_regs(task)->cs = value;
2047b08be   Roland McGrath   x86: x86 ptrace g...
328
  #endif
cb757c41f   Roland McGrath   x86: x86 ia32 ptr...
329
  		break;
2047b08be   Roland McGrath   x86: x86 ptrace g...
330
  	case offsetof(struct user_regs_struct,ss):
c63855d04   Roland McGrath   x86 ptrace: disal...
331
332
  		if (unlikely(value == 0))
  			return -EIO;
2047b08be   Roland McGrath   x86: x86 ptrace g...
333
334
335
  #ifdef CONFIG_IA32_EMULATION
  		if (test_tsk_thread_flag(task, TIF_IA32))
  			task_pt_regs(task)->ss = value;
2047b08be   Roland McGrath   x86: x86 ptrace g...
336
  #endif
cb757c41f   Roland McGrath   x86: x86 ia32 ptr...
337
  		break;
2047b08be   Roland McGrath   x86: x86 ptrace g...
338
339
340
341
  	}
  
  	return 0;
  }
2047b08be   Roland McGrath   x86: x86 ptrace g...
342
  #endif	/* CONFIG_X86_32 */
06ee1b687   Roland McGrath   x86: x86 ptrace g...
343
  static unsigned long get_flags(struct task_struct *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  {
06ee1b687   Roland McGrath   x86: x86 ptrace g...
345
346
347
348
349
350
351
  	unsigned long retval = task_pt_regs(task)->flags;
  
  	/*
  	 * If the debugger set TF, hide it from the readout.
  	 */
  	if (test_tsk_thread_flag(task, TIF_FORCED_TF))
  		retval &= ~X86_EFLAGS_TF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  	return retval;
  }
06ee1b687   Roland McGrath   x86: x86 ptrace g...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  static int set_flags(struct task_struct *task, unsigned long value)
  {
  	struct pt_regs *regs = task_pt_regs(task);
  
  	/*
  	 * If the user value contains TF, mark that
  	 * it was not "us" (the debugger) that set it.
  	 * If not, make sure it stays set if we had.
  	 */
  	if (value & X86_EFLAGS_TF)
  		clear_tsk_thread_flag(task, TIF_FORCED_TF);
  	else if (test_tsk_thread_flag(task, TIF_FORCED_TF))
  		value |= X86_EFLAGS_TF;
  
  	regs->flags = (regs->flags & ~FLAG_MASK) | (value & FLAG_MASK);
  
  	return 0;
  }
  
  static int putreg(struct task_struct *child,
  		  unsigned long offset, unsigned long value)
  {
  	switch (offset) {
  	case offsetof(struct user_regs_struct, cs):
  	case offsetof(struct user_regs_struct, ds):
  	case offsetof(struct user_regs_struct, es):
  	case offsetof(struct user_regs_struct, fs):
  	case offsetof(struct user_regs_struct, gs):
  	case offsetof(struct user_regs_struct, ss):
  		return set_segment_reg(child, offset, value);
  
  	case offsetof(struct user_regs_struct, flags):
  		return set_flags(child, value);
2047b08be   Roland McGrath   x86: x86 ptrace g...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  
  #ifdef CONFIG_X86_64
  	case offsetof(struct user_regs_struct,fs_base):
  		if (value >= TASK_SIZE_OF(child))
  			return -EIO;
  		/*
  		 * When changing the segment base, use do_arch_prctl
  		 * to set either thread.fs or thread.fsindex and the
  		 * corresponding GDT slot.
  		 */
  		if (child->thread.fs != value)
  			return do_arch_prctl(child, ARCH_SET_FS, value);
  		return 0;
  	case offsetof(struct user_regs_struct,gs_base):
  		/*
  		 * Exactly the same here as the %fs handling above.
  		 */
  		if (value >= TASK_SIZE_OF(child))
  			return -EIO;
  		if (child->thread.gs != value)
  			return do_arch_prctl(child, ARCH_SET_GS, value);
  		return 0;
  #endif
06ee1b687   Roland McGrath   x86: x86 ptrace g...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  	}
  
  	*pt_regs_access(task_pt_regs(child), offset) = value;
  	return 0;
  }
  
  static unsigned long getreg(struct task_struct *task, unsigned long offset)
  {
  	switch (offset) {
  	case offsetof(struct user_regs_struct, cs):
  	case offsetof(struct user_regs_struct, ds):
  	case offsetof(struct user_regs_struct, es):
  	case offsetof(struct user_regs_struct, fs):
  	case offsetof(struct user_regs_struct, gs):
  	case offsetof(struct user_regs_struct, ss):
  		return get_segment_reg(task, offset);
  
  	case offsetof(struct user_regs_struct, flags):
  		return get_flags(task);
2047b08be   Roland McGrath   x86: x86 ptrace g...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  
  #ifdef CONFIG_X86_64
  	case offsetof(struct user_regs_struct, fs_base): {
  		/*
  		 * do_arch_prctl may have used a GDT slot instead of
  		 * the MSR.  To userland, it appears the same either
  		 * way, except the %fs segment selector might not be 0.
  		 */
  		unsigned int seg = task->thread.fsindex;
  		if (task->thread.fs != 0)
  			return task->thread.fs;
  		if (task == current)
  			asm("movl %%fs,%0" : "=r" (seg));
  		if (seg != FS_TLS_SEL)
  			return 0;
  		return get_desc_base(&task->thread.tls_array[FS_TLS]);
  	}
  	case offsetof(struct user_regs_struct, gs_base): {
  		/*
  		 * Exactly the same here as the %fs handling above.
  		 */
  		unsigned int seg = task->thread.gsindex;
  		if (task->thread.gs != 0)
  			return task->thread.gs;
  		if (task == current)
  			asm("movl %%gs,%0" : "=r" (seg));
  		if (seg != GS_TLS_SEL)
  			return 0;
  		return get_desc_base(&task->thread.tls_array[GS_TLS]);
  	}
  #endif
06ee1b687   Roland McGrath   x86: x86 ptrace g...
461
462
463
464
  	}
  
  	return *pt_regs_access(task_pt_regs(task), offset);
  }
91e7b707a   Roland McGrath   x86: x86 user_reg...
465
466
467
468
469
470
471
  static int genregs_get(struct task_struct *target,
  		       const struct user_regset *regset,
  		       unsigned int pos, unsigned int count,
  		       void *kbuf, void __user *ubuf)
  {
  	if (kbuf) {
  		unsigned long *k = kbuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
472
  		while (count >= sizeof(*k)) {
91e7b707a   Roland McGrath   x86: x86 user_reg...
473
474
475
476
477
478
  			*k++ = getreg(target, pos);
  			count -= sizeof(*k);
  			pos += sizeof(*k);
  		}
  	} else {
  		unsigned long __user *u = ubuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
479
  		while (count >= sizeof(*u)) {
91e7b707a   Roland McGrath   x86: x86 user_reg...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  			if (__put_user(getreg(target, pos), u++))
  				return -EFAULT;
  			count -= sizeof(*u);
  			pos += sizeof(*u);
  		}
  	}
  
  	return 0;
  }
  
  static int genregs_set(struct task_struct *target,
  		       const struct user_regset *regset,
  		       unsigned int pos, unsigned int count,
  		       const void *kbuf, const void __user *ubuf)
  {
  	int ret = 0;
  	if (kbuf) {
  		const unsigned long *k = kbuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
498
  		while (count >= sizeof(*k) && !ret) {
91e7b707a   Roland McGrath   x86: x86 user_reg...
499
500
501
502
503
504
  			ret = putreg(target, pos, *k++);
  			count -= sizeof(*k);
  			pos += sizeof(*k);
  		}
  	} else {
  		const unsigned long  __user *u = ubuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
505
  		while (count >= sizeof(*u) && !ret) {
91e7b707a   Roland McGrath   x86: x86 user_reg...
506
507
508
509
510
511
512
513
514
515
516
  			unsigned long word;
  			ret = __get_user(word, u++);
  			if (ret)
  				break;
  			ret = putreg(target, pos, word);
  			count -= sizeof(*u);
  			pos += sizeof(*u);
  		}
  	}
  	return ret;
  }
a8b0ca17b   Peter Zijlstra   perf: Remove the ...
517
  static void ptrace_triggered(struct perf_event *bp,
b326e9560   Frederic Weisbecker   hw-breakpoints: U...
518
519
  			     struct perf_sample_data *data,
  			     struct pt_regs *regs)
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
520
  {
0f5340933   Roland McGrath   x86: x86-32 threa...
521
  	int i;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
522
  	struct thread_struct *thread = &(current->thread);
0f5340933   Roland McGrath   x86: x86-32 threa...
523

72f674d20   K.Prasad   hw-breakpoints: m...
524
525
526
527
  	/*
  	 * Store in the virtual DR6 register the fact that the breakpoint
  	 * was hit so the thread's debugger will see it.
  	 */
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
528
529
  	for (i = 0; i < HBP_NUM; i++) {
  		if (thread->ptrace_bps[i] == bp)
72f674d20   K.Prasad   hw-breakpoints: m...
530
  			break;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
531
  	}
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
532

72f674d20   K.Prasad   hw-breakpoints: m...
533
534
  	thread->debugreg6 |= (DR_TRAP0 << i);
  }
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
535

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  /*
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
537
538
539
   * Walk through every ptrace breakpoints for this thread and
   * build the dr7 value on top of their attributes.
   *
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
540
   */
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
541
  static unsigned long ptrace_get_dr7(struct perf_event *bp[])
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
542
  {
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
543
544
545
546
547
548
549
550
551
  	int i;
  	int dr7 = 0;
  	struct arch_hw_breakpoint *info;
  
  	for (i = 0; i < HBP_NUM; i++) {
  		if (bp[i] && !bp[i]->attr.disabled) {
  			info = counter_arch_bp(bp[i]);
  			dr7 |= encode_dr7(i, info->len, info->type);
  		}
0f5340933   Roland McGrath   x86: x86-32 threa...
552
  	}
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
553
554
  
  	return dr7;
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
555
  }
44234adcd   Frederic Weisbecker   hw-breakpoints: M...
556
  static int
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
557
  ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
1cedae729   Frederic Weisbecker   hw-breakpoints: K...
558
  			 struct task_struct *tsk, int disabled)
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
559
560
561
  {
  	int err;
  	int gen_len, gen_type;
b326e9560   Frederic Weisbecker   hw-breakpoints: U...
562
  	struct perf_event_attr attr;
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
563
564
  
  	/*
c9404c9c3   Adam Buchbinder   Fix misspelling o...
565
  	 * We should have at least an inactive breakpoint at this
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
566
567
568
569
  	 * slot. It means the user is writing dr7 without having
  	 * written the address register first
  	 */
  	if (!bp)
44234adcd   Frederic Weisbecker   hw-breakpoints: M...
570
  		return -EINVAL;
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
571
572
573
  
  	err = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
  	if (err)
44234adcd   Frederic Weisbecker   hw-breakpoints: M...
574
  		return err;
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
575
576
577
578
  
  	attr = bp->attr;
  	attr.bp_len = gen_len;
  	attr.bp_type = gen_type;
1cedae729   Frederic Weisbecker   hw-breakpoints: K...
579
  	attr.disabled = disabled;
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
580

2f0993e0f   Frederic Weisbecker   hw-breakpoints: D...
581
  	return modify_user_hw_breakpoint(bp, &attr);
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
582
  }
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
583
  /*
72f674d20   K.Prasad   hw-breakpoints: m...
584
585
586
   * Handle ptrace writes to debug register 7.
   */
  static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
587
  {
72f674d20   K.Prasad   hw-breakpoints: m...
588
  	struct thread_struct *thread = &(tsk->thread);
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
589
  	unsigned long old_dr7;
72f674d20   K.Prasad   hw-breakpoints: m...
590
591
592
  	int i, orig_ret = 0, rc = 0;
  	int enabled, second_pass = 0;
  	unsigned len, type;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
593
  	struct perf_event *bp;
72f674d20   K.Prasad   hw-breakpoints: m...
594

87dc669ba   Frederic Weisbecker   x86, hw_breakpoin...
595
596
  	if (ptrace_get_breakpoints(tsk) < 0)
  		return -ESRCH;
72f674d20   K.Prasad   hw-breakpoints: m...
597
  	data &= ~DR_CONTROL_RESERVED;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
598
  	old_dr7 = ptrace_get_dr7(thread->ptrace_bps);
72f674d20   K.Prasad   hw-breakpoints: m...
599
600
601
602
603
604
605
  restore:
  	/*
  	 * Loop through all the hardware breakpoints, making the
  	 * appropriate changes to each.
  	 */
  	for (i = 0; i < HBP_NUM; i++) {
  		enabled = decode_dr7(data, i, &len, &type);
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
606
  		bp = thread->ptrace_bps[i];
72f674d20   K.Prasad   hw-breakpoints: m...
607
608
609
  
  		if (!enabled) {
  			if (bp) {
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
610
611
  				/*
  				 * Don't unregister the breakpoints right-away,
72f674d20   K.Prasad   hw-breakpoints: m...
612
613
614
615
616
617
618
  				 * unless all register_user_hw_breakpoint()
  				 * requests have succeeded. This prevents
  				 * any window of opportunity for debug
  				 * register grabbing by other users.
  				 */
  				if (!second_pass)
  					continue;
1cedae729   Frederic Weisbecker   hw-breakpoints: K...
619

44234adcd   Frederic Weisbecker   hw-breakpoints: M...
620
  				rc = ptrace_modify_breakpoint(bp, len, type,
1cedae729   Frederic Weisbecker   hw-breakpoints: K...
621
  							      tsk, 1);
44234adcd   Frederic Weisbecker   hw-breakpoints: M...
622
  				if (rc)
1cedae729   Frederic Weisbecker   hw-breakpoints: K...
623
  					break;
72f674d20   K.Prasad   hw-breakpoints: m...
624
625
626
  			}
  			continue;
  		}
0f5340933   Roland McGrath   x86: x86-32 threa...
627

44234adcd   Frederic Weisbecker   hw-breakpoints: M...
628
629
  		rc = ptrace_modify_breakpoint(bp, len, type, tsk, 0);
  		if (rc)
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
630
  			break;
72f674d20   K.Prasad   hw-breakpoints: m...
631
632
633
634
635
636
637
638
639
640
641
642
643
  	}
  	/*
  	 * Make a second pass to free the remaining unused breakpoints
  	 * or to restore the original breakpoints if an error occurred.
  	 */
  	if (!second_pass) {
  		second_pass = 1;
  		if (rc < 0) {
  			orig_ret = rc;
  			data = old_dr7;
  		}
  		goto restore;
  	}
87dc669ba   Frederic Weisbecker   x86, hw_breakpoin...
644
645
  
  	ptrace_put_breakpoints(tsk);
72f674d20   K.Prasad   hw-breakpoints: m...
646
647
  	return ((orig_ret < 0) ? orig_ret : rc);
  }
0f5340933   Roland McGrath   x86: x86-32 threa...
648

72f674d20   K.Prasad   hw-breakpoints: m...
649
650
651
  /*
   * Handle PTRACE_PEEKUSR calls for the debug register area.
   */
9d22b5366   Jaswinder Singh Rajput   x86: Mark ptrace_...
652
  static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
72f674d20   K.Prasad   hw-breakpoints: m...
653
654
655
  {
  	struct thread_struct *thread = &(tsk->thread);
  	unsigned long val = 0;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
656
657
  	if (n < HBP_NUM) {
  		struct perf_event *bp;
87dc669ba   Frederic Weisbecker   x86, hw_breakpoin...
658
659
660
  
  		if (ptrace_get_breakpoints(tsk) < 0)
  			return -ESRCH;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
661
662
  		bp = thread->ptrace_bps[n];
  		if (!bp)
87dc669ba   Frederic Weisbecker   x86, hw_breakpoin...
663
664
665
666
667
  			val = 0;
  		else
  			val = bp->hw.info.address;
  
  		ptrace_put_breakpoints(tsk);
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
668
  	} else if (n == 6) {
72f674d20   K.Prasad   hw-breakpoints: m...
669
  		val = thread->debugreg6;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
670
  	 } else if (n == 7) {
326264a02   Frederic Weisbecker   hw-breakpoint: Ke...
671
  		val = thread->ptrace_dr7;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
672
  	}
72f674d20   K.Prasad   hw-breakpoints: m...
673
674
  	return val;
  }
0f5340933   Roland McGrath   x86: x86-32 threa...
675

24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
676
677
678
679
680
  static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
  				      unsigned long addr)
  {
  	struct perf_event *bp;
  	struct thread_struct *t = &tsk->thread;
b326e9560   Frederic Weisbecker   hw-breakpoints: U...
681
  	struct perf_event_attr attr;
87dc669ba   Frederic Weisbecker   x86, hw_breakpoin...
682
683
684
685
  	int err = 0;
  
  	if (ptrace_get_breakpoints(tsk) < 0)
  		return -ESRCH;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
686
687
  
  	if (!t->ptrace_bps[nr]) {
73266fc1d   Frederic Weisbecker   hw-breakpoints: T...
688
  		ptrace_breakpoint_init(&attr);
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
689
  		/*
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
690
691
  		 * Put stub len and type to register (reserve) an inactive but
  		 * correct bp
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
692
  		 */
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
693
694
695
696
  		attr.bp_addr = addr;
  		attr.bp_len = HW_BREAKPOINT_LEN_1;
  		attr.bp_type = HW_BREAKPOINT_W;
  		attr.disabled = 1;
4dc0da869   Avi Kivity   perf: Add context...
697
698
  		bp = register_user_hw_breakpoint(&attr, ptrace_triggered,
  						 NULL, tsk);
44234adcd   Frederic Weisbecker   hw-breakpoints: M...
699
700
701
702
703
704
705
706
707
708
  
  		/*
  		 * CHECKME: the previous code returned -EIO if the addr wasn't
  		 * a valid task virtual addr. The new one will return -EINVAL in
  		 *  this case.
  		 * -EINVAL may be what we want for in-kernel breakpoints users,
  		 * but -EIO looks better for ptrace, since we refuse a register
  		 * writing for the user. And anyway this is the previous
  		 * behaviour.
  		 */
87dc669ba   Frederic Weisbecker   x86, hw_breakpoin...
709
710
711
712
  		if (IS_ERR(bp)) {
  			err = PTR_ERR(bp);
  			goto put;
  		}
44234adcd   Frederic Weisbecker   hw-breakpoints: M...
713
714
  
  		t->ptrace_bps[nr] = bp;
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
715
716
  	} else {
  		bp = t->ptrace_bps[nr];
5fa10b28e   Frederic Weisbecker   hw-breakpoints: U...
717
718
719
  
  		attr = bp->attr;
  		attr.bp_addr = addr;
44234adcd   Frederic Weisbecker   hw-breakpoints: M...
720
  		err = modify_user_hw_breakpoint(bp, &attr);
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
721
  	}
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
722

87dc669ba   Frederic Weisbecker   x86, hw_breakpoin...
723
724
725
  put:
  	ptrace_put_breakpoints(tsk);
  	return err;
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
726
  }
325af5fb1   Roland McGrath   x86: ioperm user_...
727
  /*
72f674d20   K.Prasad   hw-breakpoints: m...
728
729
   * Handle PTRACE_POKEUSR calls for the debug register area.
   */
98b8b99ae   H Hartley Sweeten   arch/x86/kernel/p...
730
731
  static int ptrace_set_debugreg(struct task_struct *tsk, int n,
  			       unsigned long val)
72f674d20   K.Prasad   hw-breakpoints: m...
732
733
734
735
736
737
738
739
740
  {
  	struct thread_struct *thread = &(tsk->thread);
  	int rc = 0;
  
  	/* There are no DR4 or DR5 registers */
  	if (n == 4 || n == 5)
  		return -EIO;
  
  	if (n == 6) {
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
741
  		thread->debugreg6 = val;
72f674d20   K.Prasad   hw-breakpoints: m...
742
  		goto ret_path;
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
743
  	}
72f674d20   K.Prasad   hw-breakpoints: m...
744
  	if (n < HBP_NUM) {
24f1e32c6   Frederic Weisbecker   hw-breakpoints: R...
745
746
747
  		rc = ptrace_set_breakpoint_addr(tsk, n, val);
  		if (rc)
  			return rc;
72f674d20   K.Prasad   hw-breakpoints: m...
748
749
  	}
  	/* All that's left is DR7 */
326264a02   Frederic Weisbecker   hw-breakpoint: Ke...
750
  	if (n == 7) {
72f674d20   K.Prasad   hw-breakpoints: m...
751
  		rc = ptrace_write_dr7(tsk, val);
326264a02   Frederic Weisbecker   hw-breakpoint: Ke...
752
753
754
  		if (!rc)
  			thread->ptrace_dr7 = val;
  	}
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
755

72f674d20   K.Prasad   hw-breakpoints: m...
756
757
  ret_path:
  	return rc;
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
758
  }
325af5fb1   Roland McGrath   x86: ioperm user_...
759
760
761
762
763
764
765
766
767
  /*
   * These access the current or another (stopped) task's io permission
   * bitmap for debugging or core dump.
   */
  static int ioperm_active(struct task_struct *target,
  			 const struct user_regset *regset)
  {
  	return target->thread.io_bitmap_max / regset->size;
  }
b4ef95de0   Ingo Molnar   x86: disable BTS ...
768

325af5fb1   Roland McGrath   x86: ioperm user_...
769
770
771
772
  static int ioperm_get(struct task_struct *target,
  		      const struct user_regset *regset,
  		      unsigned int pos, unsigned int count,
  		      void *kbuf, void __user *ubuf)
eee3af4a2   Markus Metzger   x86, ptrace: supp...
773
  {
325af5fb1   Roland McGrath   x86: ioperm user_...
774
  	if (!target->thread.io_bitmap_ptr)
eee3af4a2   Markus Metzger   x86, ptrace: supp...
775
  		return -ENXIO;
325af5fb1   Roland McGrath   x86: ioperm user_...
776
777
778
779
  	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  				   target->thread.io_bitmap_ptr,
  				   0, IO_BITMAP_BYTES);
  }
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
780
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
785
   * Called by kernel/ptrace.c when detaching..
   *
   * Make sure the single step bit is not set.
   */
  void ptrace_disable(struct task_struct *child)
9e714bed6   Roland McGrath   x86: x86-32 ptrac...
786
  {
7f232343e   Roland McGrath   x86: arch_has_sin...
787
  	user_disable_single_step(child);
e9c86c789   Roland McGrath   x86: x86 ptrace a...
788
  #ifdef TIF_SYSCALL_EMU
ab1c23c24   Bodo Stroesser   [PATCH] SYSEMU: f...
789
  	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
e9c86c789   Roland McGrath   x86: x86 ptrace a...
790
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
  }
5a4646a4e   Roland McGrath   x86: x86 ptrace u...
792
793
794
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
  static const struct user_regset_view user_x86_32_view; /* Initialized below. */
  #endif
9b05a69e0   Namhyung Kim   ptrace: change si...
795
796
  long arch_ptrace(struct task_struct *child, long request,
  		 unsigned long addr, unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  {
5a4646a4e   Roland McGrath   x86: x86 ptrace u...
798
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  	unsigned long __user *datap = (unsigned long __user *)data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  	switch (request) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
803
804
805
  	/* read the word at location addr in the USER area. */
  	case PTRACE_PEEKUSR: {
  		unsigned long tmp;
  
  		ret = -EIO;
eb5a36993   Namhyung Kim   ptrace: cleanup a...
806
  		if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
  			break;
  
  		tmp = 0;  /* Default return condition */
e9c86c789   Roland McGrath   x86: x86 ptrace a...
810
  		if (addr < sizeof(struct user_regs_struct))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  			tmp = getreg(child, addr);
e9c86c789   Roland McGrath   x86: x86 ptrace a...
812
813
814
815
  		else if (addr >= offsetof(struct user, u_debugreg[0]) &&
  			 addr <= offsetof(struct user, u_debugreg[7])) {
  			addr -= offsetof(struct user, u_debugreg[0]);
  			tmp = ptrace_get_debugreg(child, addr / sizeof(data));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
  		}
  		ret = put_user(tmp, datap);
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
  	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
  		ret = -EIO;
eb5a36993   Namhyung Kim   ptrace: cleanup a...
822
  		if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
  			break;
e9c86c789   Roland McGrath   x86: x86 ptrace a...
824
  		if (addr < sizeof(struct user_regs_struct))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  			ret = putreg(child, addr, data);
e9c86c789   Roland McGrath   x86: x86 ptrace a...
826
827
828
829
830
  		else if (addr >= offsetof(struct user, u_debugreg[0]) &&
  			 addr <= offsetof(struct user, u_debugreg[7])) {
  			addr -= offsetof(struct user, u_debugreg[0]);
  			ret = ptrace_set_debugreg(child,
  						  addr / sizeof(data), data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  		}
e9c86c789   Roland McGrath   x86: x86 ptrace a...
832
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833

5a4646a4e   Roland McGrath   x86: x86 ptrace u...
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
  	case PTRACE_GETREGS:	/* Get all gp regs from the child. */
  		return copy_regset_to_user(child,
  					   task_user_regset_view(current),
  					   REGSET_GENERAL,
  					   0, sizeof(struct user_regs_struct),
  					   datap);
  
  	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
  		return copy_regset_from_user(child,
  					     task_user_regset_view(current),
  					     REGSET_GENERAL,
  					     0, sizeof(struct user_regs_struct),
  					     datap);
  
  	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
  		return copy_regset_to_user(child,
  					   task_user_regset_view(current),
  					   REGSET_FP,
  					   0, sizeof(struct user_i387_struct),
  					   datap);
  
  	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
  		return copy_regset_from_user(child,
  					     task_user_regset_view(current),
  					     REGSET_FP,
  					     0, sizeof(struct user_i387_struct),
  					     datap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861

e9c86c789   Roland McGrath   x86: x86 ptrace a...
862
  #ifdef CONFIG_X86_32
5a4646a4e   Roland McGrath   x86: x86 ptrace u...
863
864
865
866
  	case PTRACE_GETFPXREGS:	/* Get the child extended FPU state. */
  		return copy_regset_to_user(child, &user_x86_32_view,
  					   REGSET_XFP,
  					   0, sizeof(struct user_fxsr_struct),
45fdc3a76   Roland McGrath   x86 ptrace: fix P...
867
  					   datap) ? -EIO : 0;
5a4646a4e   Roland McGrath   x86: x86 ptrace u...
868
869
870
871
872
  
  	case PTRACE_SETFPXREGS:	/* Set the child extended FPU state. */
  		return copy_regset_from_user(child, &user_x86_32_view,
  					     REGSET_XFP,
  					     0, sizeof(struct user_fxsr_struct),
45fdc3a76   Roland McGrath   x86 ptrace: fix P...
873
  					     datap) ? -EIO : 0;
e9c86c789   Roland McGrath   x86: x86 ptrace a...
874
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875

e9c86c789   Roland McGrath   x86: x86 ptrace a...
876
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  	case PTRACE_GET_THREAD_AREA:
9b05a69e0   Namhyung Kim   ptrace: change si...
878
  		if ((int) addr < 0)
efd1ca52d   Roland McGrath   x86: TLS cleanup
879
880
  			return -EIO;
  		ret = do_get_thread_area(child, addr,
eb5a36993   Namhyung Kim   ptrace: cleanup a...
881
  					(struct user_desc __user *)data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
  		break;
  
  	case PTRACE_SET_THREAD_AREA:
9b05a69e0   Namhyung Kim   ptrace: change si...
885
  		if ((int) addr < 0)
efd1ca52d   Roland McGrath   x86: TLS cleanup
886
887
  			return -EIO;
  		ret = do_set_thread_area(child, addr,
eb5a36993   Namhyung Kim   ptrace: cleanup a...
888
  					(struct user_desc __user *)data, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  		break;
e9c86c789   Roland McGrath   x86: x86 ptrace a...
890
891
892
893
894
895
896
897
898
899
  #endif
  
  #ifdef CONFIG_X86_64
  		/* normal 64bit interface to access TLS data.
  		   Works just like arch_prctl, except that the arguments
  		   are reversed. */
  	case PTRACE_ARCH_PRCTL:
  		ret = do_arch_prctl(child, data, addr);
  		break;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
901
902
903
904
  
  	default:
  		ret = ptrace_request(child, request, addr, data);
  		break;
  	}
d9771e8c5   Roland McGrath   x86: x86-32 ptrac...
905

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
  	return ret;
  }
cb757c41f   Roland McGrath   x86: x86 ia32 ptr...
908
  #ifdef CONFIG_IA32_EMULATION
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
909
910
911
  #include <linux/compat.h>
  #include <linux/syscalls.h>
  #include <asm/ia32.h>
cb757c41f   Roland McGrath   x86: x86 ia32 ptr...
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
  #include <asm/user32.h>
  
  #define R32(l,q)							\
  	case offsetof(struct user32, regs.l):				\
  		regs->q = value; break
  
  #define SEG32(rs)							\
  	case offsetof(struct user32, regs.rs):				\
  		return set_segment_reg(child,				\
  				       offsetof(struct user_regs_struct, rs), \
  				       value);				\
  		break
  
  static int putreg32(struct task_struct *child, unsigned regno, u32 value)
  {
  	struct pt_regs *regs = task_pt_regs(child);
  
  	switch (regno) {
  
  	SEG32(cs);
  	SEG32(ds);
  	SEG32(es);
  	SEG32(fs);
  	SEG32(gs);
  	SEG32(ss);
  
  	R32(ebx, bx);
  	R32(ecx, cx);
  	R32(edx, dx);
  	R32(edi, di);
  	R32(esi, si);
  	R32(ebp, bp);
  	R32(eax, ax);
cb757c41f   Roland McGrath   x86: x86 ia32 ptr...
945
946
  	R32(eip, ip);
  	R32(esp, sp);
40f0933d5   Roland McGrath   x86: ia32 syscall...
947
948
  	case offsetof(struct user32, regs.orig_eax):
  		/*
8cb3ed139   Roland McGrath   x86: ptrace: set ...
949
950
951
952
953
  		 * A 32-bit debugger setting orig_eax means to restore
  		 * the state of the task restarting a 32-bit syscall.
  		 * Make sure we interpret the -ERESTART* codes correctly
  		 * in case the task is not actually still sitting at the
  		 * exit from a 32-bit syscall with TS_COMPAT still set.
40f0933d5   Roland McGrath   x86: ia32 syscall...
954
  		 */
8cb3ed139   Roland McGrath   x86: ptrace: set ...
955
956
957
  		regs->orig_ax = value;
  		if (syscall_get_nr(child, regs) >= 0)
  			task_thread_info(child)->status |= TS_COMPAT;
40f0933d5   Roland McGrath   x86: ia32 syscall...
958
  		break;
cb757c41f   Roland McGrath   x86: x86 ia32 ptr...
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
  	case offsetof(struct user32, regs.eflags):
  		return set_flags(child, value);
  
  	case offsetof(struct user32, u_debugreg[0]) ...
  		offsetof(struct user32, u_debugreg[7]):
  		regno -= offsetof(struct user32, u_debugreg[0]);
  		return ptrace_set_debugreg(child, regno / 4, value);
  
  	default:
  		if (regno > sizeof(struct user32) || (regno & 3))
  			return -EIO;
  
  		/*
  		 * Other dummy fields in the virtual user structure
  		 * are ignored
  		 */
  		break;
  	}
  	return 0;
  }
  
  #undef R32
  #undef SEG32
  
  #define R32(l,q)							\
  	case offsetof(struct user32, regs.l):				\
  		*val = regs->q; break
  
  #define SEG32(rs)							\
  	case offsetof(struct user32, regs.rs):				\
  		*val = get_segment_reg(child,				\
  				       offsetof(struct user_regs_struct, rs)); \
  		break
  
  static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
  {
  	struct pt_regs *regs = task_pt_regs(child);
  
  	switch (regno) {
  
  	SEG32(ds);
  	SEG32(es);
  	SEG32(fs);
  	SEG32(gs);
  
  	R32(cs, cs);
  	R32(ss, ss);
  	R32(ebx, bx);
  	R32(ecx, cx);
  	R32(edx, dx);
  	R32(edi, di);
  	R32(esi, si);
  	R32(ebp, bp);
  	R32(eax, ax);
  	R32(orig_eax, orig_ax);
  	R32(eip, ip);
  	R32(esp, sp);
  
  	case offsetof(struct user32, regs.eflags):
  		*val = get_flags(child);
  		break;
  
  	case offsetof(struct user32, u_debugreg[0]) ...
  		offsetof(struct user32, u_debugreg[7]):
  		regno -= offsetof(struct user32, u_debugreg[0]);
  		*val = ptrace_get_debugreg(child, regno / 4);
  		break;
  
  	default:
  		if (regno > sizeof(struct user32) || (regno & 3))
  			return -EIO;
  
  		/*
  		 * Other dummy fields in the virtual user structure
  		 * are ignored
  		 */
  		*val = 0;
  		break;
  	}
  	return 0;
  }
  
  #undef R32
  #undef SEG32
91e7b707a   Roland McGrath   x86: x86 user_reg...
1043
1044
1045
1046
1047
1048
1049
  static int genregs32_get(struct task_struct *target,
  			 const struct user_regset *regset,
  			 unsigned int pos, unsigned int count,
  			 void *kbuf, void __user *ubuf)
  {
  	if (kbuf) {
  		compat_ulong_t *k = kbuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
1050
  		while (count >= sizeof(*k)) {
91e7b707a   Roland McGrath   x86: x86 user_reg...
1051
1052
1053
1054
1055
1056
  			getreg32(target, pos, k++);
  			count -= sizeof(*k);
  			pos += sizeof(*k);
  		}
  	} else {
  		compat_ulong_t __user *u = ubuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
1057
  		while (count >= sizeof(*u)) {
91e7b707a   Roland McGrath   x86: x86 user_reg...
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
  			compat_ulong_t word;
  			getreg32(target, pos, &word);
  			if (__put_user(word, u++))
  				return -EFAULT;
  			count -= sizeof(*u);
  			pos += sizeof(*u);
  		}
  	}
  
  	return 0;
  }
  
  static int genregs32_set(struct task_struct *target,
  			 const struct user_regset *regset,
  			 unsigned int pos, unsigned int count,
  			 const void *kbuf, const void __user *ubuf)
  {
  	int ret = 0;
  	if (kbuf) {
  		const compat_ulong_t *k = kbuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
1078
  		while (count >= sizeof(*k) && !ret) {
f9cb02b0b   Roland McGrath   x86 ptrace: fix c...
1079
  			ret = putreg32(target, pos, *k++);
91e7b707a   Roland McGrath   x86: x86 user_reg...
1080
1081
1082
1083
1084
  			count -= sizeof(*k);
  			pos += sizeof(*k);
  		}
  	} else {
  		const compat_ulong_t __user *u = ubuf;
04a1e62c2   Linus Torvalds   x86/ptrace: make ...
1085
  		while (count >= sizeof(*u) && !ret) {
91e7b707a   Roland McGrath   x86: x86 user_reg...
1086
1087
1088
1089
  			compat_ulong_t word;
  			ret = __get_user(word, u++);
  			if (ret)
  				break;
f9cb02b0b   Roland McGrath   x86 ptrace: fix c...
1090
  			ret = putreg32(target, pos, word);
91e7b707a   Roland McGrath   x86: x86 user_reg...
1091
1092
1093
1094
1095
1096
  			count -= sizeof(*u);
  			pos += sizeof(*u);
  		}
  	}
  	return ret;
  }
562b80baf   Roland McGrath   x86_64 ia32 ptrac...
1097
1098
  long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
  			compat_ulong_t caddr, compat_ulong_t cdata)
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
1099
  {
562b80baf   Roland McGrath   x86_64 ia32 ptrac...
1100
1101
  	unsigned long addr = caddr;
  	unsigned long data = cdata;
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
1102
1103
1104
1105
1106
  	void __user *datap = compat_ptr(data);
  	int ret;
  	__u32 val;
  
  	switch (request) {
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
1107
1108
1109
1110
1111
1112
1113
1114
1115
  	case PTRACE_PEEKUSR:
  		ret = getreg32(child, addr, &val);
  		if (ret == 0)
  			ret = put_user(val, (__u32 __user *)datap);
  		break;
  
  	case PTRACE_POKEUSR:
  		ret = putreg32(child, addr, data);
  		break;
5a4646a4e   Roland McGrath   x86: x86 ptrace u...
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
  	case PTRACE_GETREGS:	/* Get all gp regs from the child. */
  		return copy_regset_to_user(child, &user_x86_32_view,
  					   REGSET_GENERAL,
  					   0, sizeof(struct user_regs_struct32),
  					   datap);
  
  	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
  		return copy_regset_from_user(child, &user_x86_32_view,
  					     REGSET_GENERAL, 0,
  					     sizeof(struct user_regs_struct32),
  					     datap);
  
  	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
  		return copy_regset_to_user(child, &user_x86_32_view,
  					   REGSET_FP, 0,
  					   sizeof(struct user_i387_ia32_struct),
  					   datap);
  
  	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
  		return copy_regset_from_user(
  			child, &user_x86_32_view, REGSET_FP,
  			0, sizeof(struct user_i387_ia32_struct), datap);
  
  	case PTRACE_GETFPXREGS:	/* Get the child extended FPU state. */
  		return copy_regset_to_user(child, &user_x86_32_view,
  					   REGSET_XFP, 0,
  					   sizeof(struct user32_fxsr_struct),
  					   datap);
  
  	case PTRACE_SETFPXREGS:	/* Set the child extended FPU state. */
  		return copy_regset_from_user(child, &user_x86_32_view,
  					     REGSET_XFP, 0,
  					     sizeof(struct user32_fxsr_struct),
  					     datap);
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
1150

562b80baf   Roland McGrath   x86_64 ia32 ptrac...
1151
1152
1153
  	case PTRACE_GET_THREAD_AREA:
  	case PTRACE_SET_THREAD_AREA:
  		return arch_ptrace(child, request, addr, data);
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
1154
  	default:
fdadd54db   Roland McGrath   x86: x86 ptrace g...
1155
  		return compat_ptrace_request(child, request, addr, data);
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
1156
  	}
099cd6e9d   Roland McGrath   x86: x86 ia32 ptr...
1157
1158
  	return ret;
  }
cb757c41f   Roland McGrath   x86: x86 ia32 ptr...
1159
  #endif	/* CONFIG_IA32_EMULATION */
070459d95   Roland McGrath   x86: x86 user_reg...
1160
  #ifdef CONFIG_X86_64
5b3efd500   Suresh Siddha   x86, ptrace: regs...
1161
  static struct user_regset x86_64_regsets[] __read_mostly = {
070459d95   Roland McGrath   x86: x86 user_reg...
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
  	[REGSET_GENERAL] = {
  		.core_note_type = NT_PRSTATUS,
  		.n = sizeof(struct user_regs_struct) / sizeof(long),
  		.size = sizeof(long), .align = sizeof(long),
  		.get = genregs_get, .set = genregs_set
  	},
  	[REGSET_FP] = {
  		.core_note_type = NT_PRFPREG,
  		.n = sizeof(struct user_i387_struct) / sizeof(long),
  		.size = sizeof(long), .align = sizeof(long),
  		.active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
  	},
5b3efd500   Suresh Siddha   x86, ptrace: regs...
1174
1175
1176
1177
1178
1179
  	[REGSET_XSTATE] = {
  		.core_note_type = NT_X86_XSTATE,
  		.size = sizeof(u64), .align = sizeof(u64),
  		.active = xstateregs_active, .get = xstateregs_get,
  		.set = xstateregs_set
  	},
325af5fb1   Roland McGrath   x86: ioperm user_...
1180
1181
1182
1183
1184
1185
  	[REGSET_IOPERM64] = {
  		.core_note_type = NT_386_IOPERM,
  		.n = IO_BITMAP_LONGS,
  		.size = sizeof(long), .align = sizeof(long),
  		.active = ioperm_active, .get = ioperm_get
  	},
070459d95   Roland McGrath   x86: x86 user_reg...
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
  };
  
  static const struct user_regset_view user_x86_64_view = {
  	.name = "x86_64", .e_machine = EM_X86_64,
  	.regsets = x86_64_regsets, .n = ARRAY_SIZE(x86_64_regsets)
  };
  
  #else  /* CONFIG_X86_32 */
  
  #define user_regs_struct32	user_regs_struct
  #define genregs32_get		genregs_get
  #define genregs32_set		genregs_set
1f465f4e4   Roland McGrath   x86: user_regset_...
1198
1199
  #define user_i387_ia32_struct	user_i387_struct
  #define user32_fxsr_struct	user_fxsr_struct
070459d95   Roland McGrath   x86: x86 user_reg...
1200
1201
1202
  #endif	/* CONFIG_X86_64 */
  
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
5b3efd500   Suresh Siddha   x86, ptrace: regs...
1203
  static struct user_regset x86_32_regsets[] __read_mostly = {
070459d95   Roland McGrath   x86: x86 user_reg...
1204
1205
1206
1207
1208
1209
1210
1211
  	[REGSET_GENERAL] = {
  		.core_note_type = NT_PRSTATUS,
  		.n = sizeof(struct user_regs_struct32) / sizeof(u32),
  		.size = sizeof(u32), .align = sizeof(u32),
  		.get = genregs32_get, .set = genregs32_set
  	},
  	[REGSET_FP] = {
  		.core_note_type = NT_PRFPREG,
1f465f4e4   Roland McGrath   x86: user_regset_...
1212
  		.n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),
070459d95   Roland McGrath   x86: x86 user_reg...
1213
1214
1215
1216
1217
  		.size = sizeof(u32), .align = sizeof(u32),
  		.active = fpregs_active, .get = fpregs_get, .set = fpregs_set
  	},
  	[REGSET_XFP] = {
  		.core_note_type = NT_PRXFPREG,
1f465f4e4   Roland McGrath   x86: user_regset_...
1218
  		.n = sizeof(struct user32_fxsr_struct) / sizeof(u32),
070459d95   Roland McGrath   x86: x86 user_reg...
1219
1220
1221
  		.size = sizeof(u32), .align = sizeof(u32),
  		.active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
  	},
5b3efd500   Suresh Siddha   x86, ptrace: regs...
1222
1223
1224
1225
1226
1227
  	[REGSET_XSTATE] = {
  		.core_note_type = NT_X86_XSTATE,
  		.size = sizeof(u64), .align = sizeof(u64),
  		.active = xstateregs_active, .get = xstateregs_get,
  		.set = xstateregs_set
  	},
070459d95   Roland McGrath   x86: x86 user_reg...
1228
  	[REGSET_TLS] = {
bb61682b3   Roland McGrath   x86: x86 core dum...
1229
  		.core_note_type = NT_386_TLS,
070459d95   Roland McGrath   x86: x86 user_reg...
1230
1231
1232
1233
1234
1235
  		.n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN,
  		.size = sizeof(struct user_desc),
  		.align = sizeof(struct user_desc),
  		.active = regset_tls_active,
  		.get = regset_tls_get, .set = regset_tls_set
  	},
325af5fb1   Roland McGrath   x86: ioperm user_...
1236
1237
1238
1239
1240
1241
  	[REGSET_IOPERM32] = {
  		.core_note_type = NT_386_IOPERM,
  		.n = IO_BITMAP_BYTES / sizeof(u32),
  		.size = sizeof(u32), .align = sizeof(u32),
  		.active = ioperm_active, .get = ioperm_get
  	},
070459d95   Roland McGrath   x86: x86 user_reg...
1242
1243
1244
1245
1246
1247
1248
  };
  
  static const struct user_regset_view user_x86_32_view = {
  	.name = "i386", .e_machine = EM_386,
  	.regsets = x86_32_regsets, .n = ARRAY_SIZE(x86_32_regsets)
  };
  #endif
5b3efd500   Suresh Siddha   x86, ptrace: regs...
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
  /*
   * This represents bytes 464..511 in the memory layout exported through
   * the REGSET_XSTATE interface.
   */
  u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
  
  void update_regset_xstate_info(unsigned int size, u64 xstate_mask)
  {
  #ifdef CONFIG_X86_64
  	x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64);
  #endif
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
  	x86_32_regsets[REGSET_XSTATE].n = size / sizeof(u64);
  #endif
  	xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask;
  }
070459d95   Roland McGrath   x86: x86 user_reg...
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
  const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  {
  #ifdef CONFIG_IA32_EMULATION
  	if (test_tsk_thread_flag(task, TIF_IA32))
  #endif
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
  		return &user_x86_32_view;
  #endif
  #ifdef CONFIG_X86_64
  	return &user_x86_64_view;
  #endif
  }
7f38551fc   Oleg Nesterov   ptrace: x86: impl...
1277
1278
1279
1280
  static void fill_sigtrap_info(struct task_struct *tsk,
  				struct pt_regs *regs,
  				int error_code, int si_code,
  				struct siginfo *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
  	tsk->thread.trap_no = 1;
  	tsk->thread.error_code = error_code;
7f38551fc   Oleg Nesterov   ptrace: x86: impl...
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
  	memset(info, 0, sizeof(*info));
  	info->si_signo = SIGTRAP;
  	info->si_code = si_code;
  	info->si_addr = user_mode_vm(regs) ? (void __user *)regs->ip : NULL;
  }
  
  void user_single_step_siginfo(struct task_struct *tsk,
  				struct pt_regs *regs,
  				struct siginfo *info)
  {
  	fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296

7f38551fc   Oleg Nesterov   ptrace: x86: impl...
1297
1298
1299
1300
  void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
  					 int error_code, int si_code)
  {
  	struct siginfo info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301

7f38551fc   Oleg Nesterov   ptrace: x86: impl...
1302
  	fill_sigtrap_info(tsk, regs, error_code, si_code, &info);
27b46d766   Simon Arlott   spelling fixes: a...
1303
  	/* Send us the fake SIGTRAP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
  	force_sig_info(SIGTRAP, &info, tsk);
  }
86976cd80   Roland McGrath   x86: x86 ptrace m...
1306

d4d671501   Roland McGrath   x86 ptrace: unify...
1307
1308
1309
  #ifdef CONFIG_X86_32
  # define IS_IA32	1
  #elif defined CONFIG_IA32_EMULATION
ccbe495ca   Roland McGrath   x86-64: syscall-a...
1310
  # define IS_IA32	is_compat_task()
d4d671501   Roland McGrath   x86 ptrace: unify...
1311
1312
1313
1314
1315
1316
1317
1318
  #else
  # define IS_IA32	0
  #endif
  
  /*
   * We must return the syscall number to actually look up in the table.
   * This can be -1L to skip running any syscall at all.
   */
1b4ac2a93   Richard Weinberger   x86: Get rid of a...
1319
  long syscall_trace_enter(struct pt_regs *regs)
86976cd80   Roland McGrath   x86: x86 ptrace m...
1320
  {
d4d671501   Roland McGrath   x86 ptrace: unify...
1321
  	long ret = 0;
380fdd758   Roland McGrath   x86 ptrace: user-...
1322
1323
1324
1325
1326
1327
1328
1329
1330
  	/*
  	 * If we stepped into a sysenter/syscall insn, it trapped in
  	 * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
  	 * If user-mode had set TF itself, then it's still clear from
  	 * do_debug() and we need to set it again to restore the user
  	 * state.  If we entered on the slow path, TF was already set.
  	 */
  	if (test_thread_flag(TIF_SINGLESTEP))
  		regs->flags |= X86_EFLAGS_TF;
86976cd80   Roland McGrath   x86: x86 ptrace m...
1331
1332
  	/* do the secure computing check first */
  	secure_computing(regs->orig_ax);
d4d671501   Roland McGrath   x86 ptrace: unify...
1333
1334
  	if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
  		ret = -1L;
eeea3c3ff   Roland McGrath   x86: tracehook sy...
1335
1336
1337
  	if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
  	    tracehook_report_syscall_entry(regs))
  		ret = -1L;
86976cd80   Roland McGrath   x86: x86 ptrace m...
1338

667000011   Josh Stone   tracing: Rename F...
1339
  	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1c569f026   Josh Stone   tracing: Create g...
1340
  		trace_sys_enter(regs, regs->orig_ax);
1b3fa2ce6   Frederic Weisbecker   tracing/x86: basi...
1341

86976cd80   Roland McGrath   x86: x86 ptrace m...
1342
  	if (unlikely(current->audit_context)) {
d4d671501   Roland McGrath   x86 ptrace: unify...
1343
  		if (IS_IA32)
86976cd80   Roland McGrath   x86: x86 ptrace m...
1344
1345
1346
1347
  			audit_syscall_entry(AUDIT_ARCH_I386,
  					    regs->orig_ax,
  					    regs->bx, regs->cx,
  					    regs->dx, regs->si);
d4d671501   Roland McGrath   x86 ptrace: unify...
1348
1349
  #ifdef CONFIG_X86_64
  		else
86976cd80   Roland McGrath   x86: x86 ptrace m...
1350
1351
1352
1353
  			audit_syscall_entry(AUDIT_ARCH_X86_64,
  					    regs->orig_ax,
  					    regs->di, regs->si,
  					    regs->dx, regs->r10);
d4d671501   Roland McGrath   x86 ptrace: unify...
1354
  #endif
86976cd80   Roland McGrath   x86: x86 ptrace m...
1355
  	}
d4d671501   Roland McGrath   x86 ptrace: unify...
1356
1357
  
  	return ret ?: regs->orig_ax;
86976cd80   Roland McGrath   x86: x86 ptrace m...
1358
  }
1b4ac2a93   Richard Weinberger   x86: Get rid of a...
1359
  void syscall_trace_leave(struct pt_regs *regs)
86976cd80   Roland McGrath   x86: x86 ptrace m...
1360
  {
d51965037   Oleg Nesterov   ptrace: x86: chan...
1361
  	bool step;
86976cd80   Roland McGrath   x86: x86 ptrace m...
1362
1363
  	if (unlikely(current->audit_context))
  		audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
667000011   Josh Stone   tracing: Rename F...
1364
  	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1c569f026   Josh Stone   tracing: Create g...
1365
  		trace_sys_exit(regs, regs->ax);
1b3fa2ce6   Frederic Weisbecker   tracing/x86: basi...
1366

d4d671501   Roland McGrath   x86 ptrace: unify...
1367
1368
1369
1370
  	/*
  	 * If TIF_SYSCALL_EMU is set, we only get here because of
  	 * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP).
  	 * We already reported this syscall instruction in
d51965037   Oleg Nesterov   ptrace: x86: chan...
1371
  	 * syscall_trace_enter().
d4d671501   Roland McGrath   x86 ptrace: unify...
1372
  	 */
d51965037   Oleg Nesterov   ptrace: x86: chan...
1373
1374
1375
1376
  	step = unlikely(test_thread_flag(TIF_SINGLESTEP)) &&
  			!test_thread_flag(TIF_SYSCALL_EMU);
  	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
  		tracehook_report_syscall_exit(regs, step);
d4d671501   Roland McGrath   x86 ptrace: unify...
1377
  }