aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2008-01-30 07:31:20 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:20 -0500
commita95d67f87e1a5f1b4429be3ba3bf7b4051657908 (patch)
tree4a67994b901c5dfbf3c2ee752efd53dbce938c36 /arch/x86
parente4811f2568c55e595a7bf15a3b9aba863b31fb94 (diff)
x86, ptrace: new ptrace BTS API
Here's the new ptrace BTS API that supports two different overflow handling mechanisms (wrap-around and buffer-full-signal) to support two different use cases (debugging and profiling). It further combines buffer allocation and configuration. Opens: - memory rlimit - overflow signal What would be the right signal to use? Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/ds.c56
-rw-r--r--arch/x86/kernel/ptrace.c221
2 files changed, 181 insertions, 96 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index e7855def97c3..6eb5d49a36bb 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -177,18 +177,20 @@ static inline void set_info_data(char *base, unsigned long value)
177} 177}
178 178
179 179
180int ds_allocate(void **dsp, size_t bts_size_in_records) 180int ds_allocate(void **dsp, size_t bts_size_in_bytes)
181{ 181{
182 size_t bts_size_in_bytes = 0; 182 size_t bts_size_in_records;
183 void *bts = 0; 183 void *bts;
184 void *ds = 0; 184 void *ds;
185 185
186 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts) 186 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
187 return -EOPNOTSUPP; 187 return -EOPNOTSUPP;
188 188
189 if (bts_size_in_records < 0) 189 if (bts_size_in_bytes < 0)
190 return -EINVAL; 190 return -EINVAL;
191 191
192 bts_size_in_records =
193 bts_size_in_bytes / ds_cfg.sizeof_bts;
192 bts_size_in_bytes = 194 bts_size_in_bytes =
193 bts_size_in_records * ds_cfg.sizeof_bts; 195 bts_size_in_records * ds_cfg.sizeof_bts;
194 196
@@ -233,9 +235,21 @@ int ds_get_bts_size(void *ds)
233 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts) 235 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
234 return -EOPNOTSUPP; 236 return -EOPNOTSUPP;
235 237
238 if (!ds)
239 return 0;
240
236 size_in_bytes = 241 size_in_bytes =
237 get_bts_absolute_maximum(ds) - 242 get_bts_absolute_maximum(ds) -
238 get_bts_buffer_base(ds); 243 get_bts_buffer_base(ds);
244 return size_in_bytes;
245}
246
247int ds_get_bts_end(void *ds)
248{
249 size_t size_in_bytes = ds_get_bts_size(ds);
250
251 if (size_in_bytes <= 0)
252 return size_in_bytes;
239 253
240 return size_in_bytes / ds_cfg.sizeof_bts; 254 return size_in_bytes / ds_cfg.sizeof_bts;
241} 255}
@@ -254,6 +268,38 @@ int ds_get_bts_index(void *ds)
254 return index_offset_in_bytes / ds_cfg.sizeof_bts; 268 return index_offset_in_bytes / ds_cfg.sizeof_bts;
255} 269}
256 270
271int ds_set_overflow(void *ds, int method)
272{
273 switch (method) {
274 case DS_O_SIGNAL:
275 return -EOPNOTSUPP;
276 case DS_O_WRAP:
277 return 0;
278 default:
279 return -EINVAL;
280 }
281}
282
283int ds_get_overflow(void *ds)
284{
285 return DS_O_WRAP;
286}
287
288int ds_clear(void *ds)
289{
290 int bts_size = ds_get_bts_size(ds);
291 void *bts_base;
292
293 if (bts_size <= 0)
294 return bts_size;
295
296 bts_base = get_bts_buffer_base(ds);
297 memset(bts_base, 0, bts_size);
298
299 set_bts_index(ds, bts_base);
300 return 0;
301}
302
257int ds_read_bts(void *ds, size_t index, struct bts_struct *out) 303int ds_read_bts(void *ds, size_t index, struct bts_struct *out)
258{ 304{
259 void *bts; 305 void *bts;
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 3e78c124e2d2..18972a305890 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -33,12 +33,6 @@
33 33
34 34
35/* 35/*
36 * The maximal size of a BTS buffer per traced task in number of BTS
37 * records.
38 */
39#define PTRACE_BTS_BUFFER_MAX 4000
40
41/*
42 * does not yet catch signals sent when the child dies. 36 * does not yet catch signals sent when the child dies.
43 * in exit.c or in signal.c. 37 * in exit.c or in signal.c.
44 */ 38 */
@@ -466,17 +460,12 @@ static int ptrace_set_debugreg(struct task_struct *child,
466 return 0; 460 return 0;
467} 461}
468 462
469static int ptrace_bts_max_buffer_size(void) 463static int ptrace_bts_get_size(struct task_struct *child)
470{
471 return PTRACE_BTS_BUFFER_MAX;
472}
473
474static int ptrace_bts_get_buffer_size(struct task_struct *child)
475{ 464{
476 if (!child->thread.ds_area_msr) 465 if (!child->thread.ds_area_msr)
477 return -ENXIO; 466 return -ENXIO;
478 467
479 return ds_get_bts_size((void *)child->thread.ds_area_msr); 468 return ds_get_bts_index((void *)child->thread.ds_area_msr);
480} 469}
481 470
482static int ptrace_bts_read_record(struct task_struct *child, 471static int ptrace_bts_read_record(struct task_struct *child,
@@ -485,7 +474,7 @@ static int ptrace_bts_read_record(struct task_struct *child,
485{ 474{
486 struct bts_struct ret; 475 struct bts_struct ret;
487 int retval; 476 int retval;
488 int bts_size; 477 int bts_end;
489 int bts_index; 478 int bts_index;
490 479
491 if (!child->thread.ds_area_msr) 480 if (!child->thread.ds_area_msr)
@@ -494,15 +483,15 @@ static int ptrace_bts_read_record(struct task_struct *child,
494 if (index < 0) 483 if (index < 0)
495 return -EINVAL; 484 return -EINVAL;
496 485
497 bts_size = ds_get_bts_size((void *)child->thread.ds_area_msr); 486 bts_end = ds_get_bts_end((void *)child->thread.ds_area_msr);
498 if (bts_size <= index) 487 if (bts_end <= index)
499 return -EINVAL; 488 return -EINVAL;
500 489
501 /* translate the ptrace bts index into the ds bts index */ 490 /* translate the ptrace bts index into the ds bts index */
502 bts_index = ds_get_bts_index((void *)child->thread.ds_area_msr); 491 bts_index = ds_get_bts_index((void *)child->thread.ds_area_msr);
503 bts_index -= (index + 1); 492 bts_index -= (index + 1);
504 if (bts_index < 0) 493 if (bts_index < 0)
505 bts_index += bts_size; 494 bts_index += bts_end;
506 495
507 retval = ds_read_bts((void *)child->thread.ds_area_msr, 496 retval = ds_read_bts((void *)child->thread.ds_area_msr,
508 bts_index, &ret); 497 bts_index, &ret);
@@ -530,19 +519,97 @@ static int ptrace_bts_write_record(struct task_struct *child,
530 return sizeof(*in); 519 return sizeof(*in);
531} 520}
532 521
533static int ptrace_bts_config(struct task_struct *child, 522static int ptrace_bts_clear(struct task_struct *child)
534 unsigned long options)
535{ 523{
536 unsigned long debugctl_mask = ds_debugctl_mask(); 524 if (!child->thread.ds_area_msr)
537 int retval; 525 return -ENXIO;
538 526
539 retval = ptrace_bts_get_buffer_size(child); 527 return ds_clear((void *)child->thread.ds_area_msr);
540 if (retval < 0) 528}
541 return retval; 529
542 if (retval == 0) 530static int ptrace_bts_drain(struct task_struct *child,
531 struct bts_struct __user *out)
532{
533 int end, i;
534 void *ds = (void *)child->thread.ds_area_msr;
535
536 if (!ds)
543 return -ENXIO; 537 return -ENXIO;
544 538
545 if (options & PTRACE_BTS_O_TRACE_TASK) { 539 end = ds_get_bts_index(ds);
540 if (end <= 0)
541 return end;
542
543 for (i = 0; i < end; i++, out++) {
544 struct bts_struct ret;
545 int retval;
546
547 retval = ds_read_bts(ds, i, &ret);
548 if (retval < 0)
549 return retval;
550
551 if (copy_to_user(out, &ret, sizeof(ret)))
552 return -EFAULT;
553 }
554
555 ds_clear(ds);
556
557 return i;
558}
559
560static int ptrace_bts_config(struct task_struct *child,
561 const struct ptrace_bts_config __user *ucfg)
562{
563 struct ptrace_bts_config cfg;
564 unsigned long debugctl_mask;
565 int bts_size, ret;
566 void *ds;
567
568 if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
569 return -EFAULT;
570
571 bts_size = 0;
572 ds = (void *)child->thread.ds_area_msr;
573 if (ds) {
574 bts_size = ds_get_bts_size(ds);
575 if (bts_size < 0)
576 return bts_size;
577 }
578
579 if (bts_size != cfg.size) {
580 ret = ds_free((void **)&child->thread.ds_area_msr);
581 if (ret < 0)
582 return ret;
583
584 if (cfg.size > 0)
585 ret = ds_allocate((void **)&child->thread.ds_area_msr,
586 cfg.size);
587 ds = (void *)child->thread.ds_area_msr;
588 if (ds)
589 set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
590 else
591 clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
592
593 if (ret < 0)
594 return ret;
595
596 bts_size = ds_get_bts_size(ds);
597 if (bts_size <= 0)
598 return bts_size;
599 }
600
601 if (ds) {
602 if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
603 ret = ds_set_overflow(ds, DS_O_SIGNAL);
604 } else {
605 ret = ds_set_overflow(ds, DS_O_WRAP);
606 }
607 if (ret < 0)
608 return ret;
609 }
610
611 debugctl_mask = ds_debugctl_mask();
612 if (ds && (cfg.flags & PTRACE_BTS_O_TRACE)) {
546 child->thread.debugctlmsr |= debugctl_mask; 613 child->thread.debugctlmsr |= debugctl_mask;
547 set_tsk_thread_flag(child, TIF_DEBUGCTLMSR); 614 set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
548 } else { 615 } else {
@@ -555,7 +622,7 @@ static int ptrace_bts_config(struct task_struct *child,
555 clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); 622 clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
556 } 623 }
557 624
558 if (options & PTRACE_BTS_O_TIMESTAMPS) 625 if (ds && (cfg.flags & PTRACE_BTS_O_SCHED))
559 set_tsk_thread_flag(child, TIF_BTS_TRACE_TS); 626 set_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
560 else 627 else
561 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); 628 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
@@ -563,59 +630,32 @@ static int ptrace_bts_config(struct task_struct *child,
563 return 0; 630 return 0;
564} 631}
565 632
566static int ptrace_bts_status(struct task_struct *child) 633static int ptrace_bts_status(struct task_struct *child,
634 struct ptrace_bts_config __user *ucfg)
567{ 635{
568 unsigned long debugctl_mask = ds_debugctl_mask(); 636 void *ds = (void *)child->thread.ds_area_msr;
569 int retval, status = 0; 637 struct ptrace_bts_config cfg;
570
571 retval = ptrace_bts_get_buffer_size(child);
572 if (retval < 0)
573 return retval;
574 if (retval == 0)
575 return -ENXIO;
576
577 if (ptrace_bts_get_buffer_size(child) <= 0)
578 return -ENXIO;
579 638
580 if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) && 639 memset(&cfg, 0, sizeof(cfg));
581 child->thread.debugctlmsr & debugctl_mask)
582 status |= PTRACE_BTS_O_TRACE_TASK;
583 if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS))
584 status |= PTRACE_BTS_O_TIMESTAMPS;
585 640
586 return status; 641 if (ds) {
587} 642 cfg.size = ds_get_bts_size(ds);
588 643
589static int ptrace_bts_allocate_bts(struct task_struct *child, 644 if (ds_get_overflow(ds) == DS_O_SIGNAL)
590 int size_in_records) 645 cfg.flags |= PTRACE_BTS_O_SIGNAL;
591{
592 int retval = 0;
593 void *ds;
594 646
595 if (size_in_records < 0) 647 if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) &&
596 return -EINVAL; 648 child->thread.debugctlmsr & ds_debugctl_mask())
649 cfg.flags |= PTRACE_BTS_O_TRACE;
597 650
598 if (size_in_records > ptrace_bts_max_buffer_size()) 651 if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS))
599 return -EINVAL; 652 cfg.flags |= PTRACE_BTS_O_SCHED;
600
601 if (size_in_records == 0) {
602 ptrace_bts_config(child, /* options = */ 0);
603 } else {
604 retval = ds_allocate(&ds, size_in_records);
605 if (retval)
606 return retval;
607 } 653 }
608 654
609 if (child->thread.ds_area_msr) 655 if (copy_to_user(ucfg, &cfg, sizeof(cfg)))
610 ds_free((void **)&child->thread.ds_area_msr); 656 return -EFAULT;
611
612 child->thread.ds_area_msr = (unsigned long)ds;
613 if (child->thread.ds_area_msr)
614 set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
615 else
616 clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
617 657
618 return retval; 658 return sizeof(cfg);
619} 659}
620 660
621void ptrace_bts_take_timestamp(struct task_struct *tsk, 661void ptrace_bts_take_timestamp(struct task_struct *tsk,
@@ -626,9 +666,6 @@ void ptrace_bts_take_timestamp(struct task_struct *tsk,
626 .variant.jiffies = jiffies 666 .variant.jiffies = jiffies
627 }; 667 };
628 668
629 if (ptrace_bts_get_buffer_size(tsk) <= 0)
630 return;
631
632 ptrace_bts_write_record(tsk, &rec); 669 ptrace_bts_write_record(tsk, &rec);
633} 670}
634 671
@@ -808,30 +845,32 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
808 break; 845 break;
809#endif 846#endif
810 847
811 case PTRACE_BTS_MAX_BUFFER_SIZE: 848 case PTRACE_BTS_CONFIG:
812 ret = ptrace_bts_max_buffer_size(); 849 ret = ptrace_bts_config
850 (child, (struct ptrace_bts_config __user *)addr);
813 break; 851 break;
814 852
815 case PTRACE_BTS_ALLOCATE_BUFFER: 853 case PTRACE_BTS_STATUS:
816 ret = ptrace_bts_allocate_bts(child, data); 854 ret = ptrace_bts_status
855 (child, (struct ptrace_bts_config __user *)addr);
817 break; 856 break;
818 857
819 case PTRACE_BTS_GET_BUFFER_SIZE: 858 case PTRACE_BTS_SIZE:
820 ret = ptrace_bts_get_buffer_size(child); 859 ret = ptrace_bts_get_size(child);
821 break; 860 break;
822 861
823 case PTRACE_BTS_READ_RECORD: 862 case PTRACE_BTS_GET:
824 ret = ptrace_bts_read_record 863 ret = ptrace_bts_read_record
825 (child, data, 864 (child, data, (struct bts_struct __user *) addr);
826 (struct bts_struct __user *) addr);
827 break; 865 break;
828 866
829 case PTRACE_BTS_CONFIG: 867 case PTRACE_BTS_CLEAR:
830 ret = ptrace_bts_config(child, data); 868 ret = ptrace_bts_clear(child);
831 break; 869 break;
832 870
833 case PTRACE_BTS_STATUS: 871 case PTRACE_BTS_DRAIN:
834 ret = ptrace_bts_status(child); 872 ret = ptrace_bts_drain
873 (child, (struct bts_struct __user *) addr);
835 break; 874 break;
836 875
837 default: 876 default:
@@ -1017,12 +1056,12 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
1017 case PTRACE_SETOPTIONS: 1056 case PTRACE_SETOPTIONS:
1018 case PTRACE_SET_THREAD_AREA: 1057 case PTRACE_SET_THREAD_AREA:
1019 case PTRACE_GET_THREAD_AREA: 1058 case PTRACE_GET_THREAD_AREA:
1020 case PTRACE_BTS_MAX_BUFFER_SIZE:
1021 case PTRACE_BTS_ALLOCATE_BUFFER:
1022 case PTRACE_BTS_GET_BUFFER_SIZE:
1023 case PTRACE_BTS_READ_RECORD:
1024 case PTRACE_BTS_CONFIG: 1059 case PTRACE_BTS_CONFIG:
1025 case PTRACE_BTS_STATUS: 1060 case PTRACE_BTS_STATUS:
1061 case PTRACE_BTS_SIZE:
1062 case PTRACE_BTS_GET:
1063 case PTRACE_BTS_CLEAR:
1064 case PTRACE_BTS_DRAIN:
1026 return sys_ptrace(request, pid, addr, data); 1065 return sys_ptrace(request, pid, addr, data);
1027 1066
1028 default: 1067 default: