diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 121 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_amd.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_p6.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/rtc.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/trace_clock.c | 21 | ||||
-rw-r--r-- | arch/x86/kernel/tsc.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/uprobes.c | 54 |
10 files changed, 193 insertions, 42 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 91ce48f05f9f..34e923a53762 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -9,7 +9,6 @@ CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE) | |||
9 | ifdef CONFIG_FUNCTION_TRACER | 9 | ifdef CONFIG_FUNCTION_TRACER |
10 | # Do not profile debug and lowlevel utilities | 10 | # Do not profile debug and lowlevel utilities |
11 | CFLAGS_REMOVE_tsc.o = -pg | 11 | CFLAGS_REMOVE_tsc.o = -pg |
12 | CFLAGS_REMOVE_rtc.o = -pg | ||
13 | CFLAGS_REMOVE_paravirt-spinlocks.o = -pg | 12 | CFLAGS_REMOVE_paravirt-spinlocks.o = -pg |
14 | CFLAGS_REMOVE_pvclock.o = -pg | 13 | CFLAGS_REMOVE_pvclock.o = -pg |
15 | CFLAGS_REMOVE_kvmclock.o = -pg | 14 | CFLAGS_REMOVE_kvmclock.o = -pg |
@@ -62,6 +61,7 @@ obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o | |||
62 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 61 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
63 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 62 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
64 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o | 63 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o |
64 | obj-$(CONFIG_X86_TSC) += trace_clock.o | ||
65 | obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o | 65 | obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o |
66 | obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o | 66 | obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o |
67 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o | 67 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 4a3374e61a93..4428fd178bce 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1316,6 +1316,121 @@ static struct attribute_group x86_pmu_format_group = { | |||
1316 | .attrs = NULL, | 1316 | .attrs = NULL, |
1317 | }; | 1317 | }; |
1318 | 1318 | ||
1319 | struct perf_pmu_events_attr { | ||
1320 | struct device_attribute attr; | ||
1321 | u64 id; | ||
1322 | }; | ||
1323 | |||
1324 | /* | ||
1325 | * Remove all undefined events (x86_pmu.event_map(id) == 0) | ||
1326 | * out of events_attr attributes. | ||
1327 | */ | ||
1328 | static void __init filter_events(struct attribute **attrs) | ||
1329 | { | ||
1330 | int i, j; | ||
1331 | |||
1332 | for (i = 0; attrs[i]; i++) { | ||
1333 | if (x86_pmu.event_map(i)) | ||
1334 | continue; | ||
1335 | |||
1336 | for (j = i; attrs[j]; j++) | ||
1337 | attrs[j] = attrs[j + 1]; | ||
1338 | |||
1339 | /* Check the shifted attr. */ | ||
1340 | i--; | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | static ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, | ||
1345 | char *page) | ||
1346 | { | ||
1347 | struct perf_pmu_events_attr *pmu_attr = \ | ||
1348 | container_of(attr, struct perf_pmu_events_attr, attr); | ||
1349 | |||
1350 | u64 config = x86_pmu.event_map(pmu_attr->id); | ||
1351 | return x86_pmu.events_sysfs_show(page, config); | ||
1352 | } | ||
1353 | |||
1354 | #define EVENT_VAR(_id) event_attr_##_id | ||
1355 | #define EVENT_PTR(_id) &event_attr_##_id.attr.attr | ||
1356 | |||
1357 | #define EVENT_ATTR(_name, _id) \ | ||
1358 | static struct perf_pmu_events_attr EVENT_VAR(_id) = { \ | ||
1359 | .attr = __ATTR(_name, 0444, events_sysfs_show, NULL), \ | ||
1360 | .id = PERF_COUNT_HW_##_id, \ | ||
1361 | }; | ||
1362 | |||
1363 | EVENT_ATTR(cpu-cycles, CPU_CYCLES ); | ||
1364 | EVENT_ATTR(instructions, INSTRUCTIONS ); | ||
1365 | EVENT_ATTR(cache-references, CACHE_REFERENCES ); | ||
1366 | EVENT_ATTR(cache-misses, CACHE_MISSES ); | ||
1367 | EVENT_ATTR(branch-instructions, BRANCH_INSTRUCTIONS ); | ||
1368 | EVENT_ATTR(branch-misses, BRANCH_MISSES ); | ||
1369 | EVENT_ATTR(bus-cycles, BUS_CYCLES ); | ||
1370 | EVENT_ATTR(stalled-cycles-frontend, STALLED_CYCLES_FRONTEND ); | ||
1371 | EVENT_ATTR(stalled-cycles-backend, STALLED_CYCLES_BACKEND ); | ||
1372 | EVENT_ATTR(ref-cycles, REF_CPU_CYCLES ); | ||
1373 | |||
1374 | static struct attribute *empty_attrs; | ||
1375 | |||
1376 | static struct attribute *events_attr[] = { | ||
1377 | EVENT_PTR(CPU_CYCLES), | ||
1378 | EVENT_PTR(INSTRUCTIONS), | ||
1379 | EVENT_PTR(CACHE_REFERENCES), | ||
1380 | EVENT_PTR(CACHE_MISSES), | ||
1381 | EVENT_PTR(BRANCH_INSTRUCTIONS), | ||
1382 | EVENT_PTR(BRANCH_MISSES), | ||
1383 | EVENT_PTR(BUS_CYCLES), | ||
1384 | EVENT_PTR(STALLED_CYCLES_FRONTEND), | ||
1385 | EVENT_PTR(STALLED_CYCLES_BACKEND), | ||
1386 | EVENT_PTR(REF_CPU_CYCLES), | ||
1387 | NULL, | ||
1388 | }; | ||
1389 | |||
1390 | static struct attribute_group x86_pmu_events_group = { | ||
1391 | .name = "events", | ||
1392 | .attrs = events_attr, | ||
1393 | }; | ||
1394 | |||
1395 | ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event) | ||
1396 | { | ||
1397 | u64 umask = (config & ARCH_PERFMON_EVENTSEL_UMASK) >> 8; | ||
1398 | u64 cmask = (config & ARCH_PERFMON_EVENTSEL_CMASK) >> 24; | ||
1399 | bool edge = (config & ARCH_PERFMON_EVENTSEL_EDGE); | ||
1400 | bool pc = (config & ARCH_PERFMON_EVENTSEL_PIN_CONTROL); | ||
1401 | bool any = (config & ARCH_PERFMON_EVENTSEL_ANY); | ||
1402 | bool inv = (config & ARCH_PERFMON_EVENTSEL_INV); | ||
1403 | ssize_t ret; | ||
1404 | |||
1405 | /* | ||
1406 | * We have whole page size to spend and just little data | ||
1407 | * to write, so we can safely use sprintf. | ||
1408 | */ | ||
1409 | ret = sprintf(page, "event=0x%02llx", event); | ||
1410 | |||
1411 | if (umask) | ||
1412 | ret += sprintf(page + ret, ",umask=0x%02llx", umask); | ||
1413 | |||
1414 | if (edge) | ||
1415 | ret += sprintf(page + ret, ",edge"); | ||
1416 | |||
1417 | if (pc) | ||
1418 | ret += sprintf(page + ret, ",pc"); | ||
1419 | |||
1420 | if (any) | ||
1421 | ret += sprintf(page + ret, ",any"); | ||
1422 | |||
1423 | if (inv) | ||
1424 | ret += sprintf(page + ret, ",inv"); | ||
1425 | |||
1426 | if (cmask) | ||
1427 | ret += sprintf(page + ret, ",cmask=0x%02llx", cmask); | ||
1428 | |||
1429 | ret += sprintf(page + ret, "\n"); | ||
1430 | |||
1431 | return ret; | ||
1432 | } | ||
1433 | |||
1319 | static int __init init_hw_perf_events(void) | 1434 | static int __init init_hw_perf_events(void) |
1320 | { | 1435 | { |
1321 | struct x86_pmu_quirk *quirk; | 1436 | struct x86_pmu_quirk *quirk; |
@@ -1362,6 +1477,11 @@ static int __init init_hw_perf_events(void) | |||
1362 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ | 1477 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ |
1363 | x86_pmu_format_group.attrs = x86_pmu.format_attrs; | 1478 | x86_pmu_format_group.attrs = x86_pmu.format_attrs; |
1364 | 1479 | ||
1480 | if (!x86_pmu.events_sysfs_show) | ||
1481 | x86_pmu_events_group.attrs = &empty_attrs; | ||
1482 | else | ||
1483 | filter_events(x86_pmu_events_group.attrs); | ||
1484 | |||
1365 | pr_info("... version: %d\n", x86_pmu.version); | 1485 | pr_info("... version: %d\n", x86_pmu.version); |
1366 | pr_info("... bit width: %d\n", x86_pmu.cntval_bits); | 1486 | pr_info("... bit width: %d\n", x86_pmu.cntval_bits); |
1367 | pr_info("... generic registers: %d\n", x86_pmu.num_counters); | 1487 | pr_info("... generic registers: %d\n", x86_pmu.num_counters); |
@@ -1651,6 +1771,7 @@ static struct attribute_group x86_pmu_attr_group = { | |||
1651 | static const struct attribute_group *x86_pmu_attr_groups[] = { | 1771 | static const struct attribute_group *x86_pmu_attr_groups[] = { |
1652 | &x86_pmu_attr_group, | 1772 | &x86_pmu_attr_group, |
1653 | &x86_pmu_format_group, | 1773 | &x86_pmu_format_group, |
1774 | &x86_pmu_events_group, | ||
1654 | NULL, | 1775 | NULL, |
1655 | }; | 1776 | }; |
1656 | 1777 | ||
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 271d25700297..115c1ea97746 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -354,6 +354,8 @@ struct x86_pmu { | |||
354 | int attr_rdpmc; | 354 | int attr_rdpmc; |
355 | struct attribute **format_attrs; | 355 | struct attribute **format_attrs; |
356 | 356 | ||
357 | ssize_t (*events_sysfs_show)(char *page, u64 config); | ||
358 | |||
357 | /* | 359 | /* |
358 | * CPU Hotplug hooks | 360 | * CPU Hotplug hooks |
359 | */ | 361 | */ |
@@ -536,6 +538,9 @@ static inline void set_linear_ip(struct pt_regs *regs, unsigned long ip) | |||
536 | regs->ip = ip; | 538 | regs->ip = ip; |
537 | } | 539 | } |
538 | 540 | ||
541 | ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event); | ||
542 | ssize_t intel_event_sysfs_show(char *page, u64 config); | ||
543 | |||
539 | #ifdef CONFIG_CPU_SUP_AMD | 544 | #ifdef CONFIG_CPU_SUP_AMD |
540 | 545 | ||
541 | int amd_pmu_init(void); | 546 | int amd_pmu_init(void); |
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 4528ae7b6ec4..c93bc4e813a0 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c | |||
@@ -568,6 +568,14 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev | |||
568 | } | 568 | } |
569 | } | 569 | } |
570 | 570 | ||
571 | static ssize_t amd_event_sysfs_show(char *page, u64 config) | ||
572 | { | ||
573 | u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT) | | ||
574 | (config & AMD64_EVENTSEL_EVENT) >> 24; | ||
575 | |||
576 | return x86_event_sysfs_show(page, config, event); | ||
577 | } | ||
578 | |||
571 | static __initconst const struct x86_pmu amd_pmu = { | 579 | static __initconst const struct x86_pmu amd_pmu = { |
572 | .name = "AMD", | 580 | .name = "AMD", |
573 | .handle_irq = x86_pmu_handle_irq, | 581 | .handle_irq = x86_pmu_handle_irq, |
@@ -591,6 +599,7 @@ static __initconst const struct x86_pmu amd_pmu = { | |||
591 | .put_event_constraints = amd_put_event_constraints, | 599 | .put_event_constraints = amd_put_event_constraints, |
592 | 600 | ||
593 | .format_attrs = amd_format_attr, | 601 | .format_attrs = amd_format_attr, |
602 | .events_sysfs_show = amd_event_sysfs_show, | ||
594 | 603 | ||
595 | .cpu_prepare = amd_pmu_cpu_prepare, | 604 | .cpu_prepare = amd_pmu_cpu_prepare, |
596 | .cpu_starting = amd_pmu_cpu_starting, | 605 | .cpu_starting = amd_pmu_cpu_starting, |
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 324bb523d9d9..93b9e1181f83 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
@@ -1603,6 +1603,13 @@ static struct attribute *intel_arch_formats_attr[] = { | |||
1603 | NULL, | 1603 | NULL, |
1604 | }; | 1604 | }; |
1605 | 1605 | ||
1606 | ssize_t intel_event_sysfs_show(char *page, u64 config) | ||
1607 | { | ||
1608 | u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT); | ||
1609 | |||
1610 | return x86_event_sysfs_show(page, config, event); | ||
1611 | } | ||
1612 | |||
1606 | static __initconst const struct x86_pmu core_pmu = { | 1613 | static __initconst const struct x86_pmu core_pmu = { |
1607 | .name = "core", | 1614 | .name = "core", |
1608 | .handle_irq = x86_pmu_handle_irq, | 1615 | .handle_irq = x86_pmu_handle_irq, |
@@ -1628,6 +1635,7 @@ static __initconst const struct x86_pmu core_pmu = { | |||
1628 | .event_constraints = intel_core_event_constraints, | 1635 | .event_constraints = intel_core_event_constraints, |
1629 | .guest_get_msrs = core_guest_get_msrs, | 1636 | .guest_get_msrs = core_guest_get_msrs, |
1630 | .format_attrs = intel_arch_formats_attr, | 1637 | .format_attrs = intel_arch_formats_attr, |
1638 | .events_sysfs_show = intel_event_sysfs_show, | ||
1631 | }; | 1639 | }; |
1632 | 1640 | ||
1633 | struct intel_shared_regs *allocate_shared_regs(int cpu) | 1641 | struct intel_shared_regs *allocate_shared_regs(int cpu) |
@@ -1766,6 +1774,7 @@ static __initconst const struct x86_pmu intel_pmu = { | |||
1766 | .pebs_aliases = intel_pebs_aliases_core2, | 1774 | .pebs_aliases = intel_pebs_aliases_core2, |
1767 | 1775 | ||
1768 | .format_attrs = intel_arch3_formats_attr, | 1776 | .format_attrs = intel_arch3_formats_attr, |
1777 | .events_sysfs_show = intel_event_sysfs_show, | ||
1769 | 1778 | ||
1770 | .cpu_prepare = intel_pmu_cpu_prepare, | 1779 | .cpu_prepare = intel_pmu_cpu_prepare, |
1771 | .cpu_starting = intel_pmu_cpu_starting, | 1780 | .cpu_starting = intel_pmu_cpu_starting, |
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c index 7d0270bd793e..f2af39f5dc3d 100644 --- a/arch/x86/kernel/cpu/perf_event_p6.c +++ b/arch/x86/kernel/cpu/perf_event_p6.c | |||
@@ -227,6 +227,8 @@ static __initconst const struct x86_pmu p6_pmu = { | |||
227 | .event_constraints = p6_event_constraints, | 227 | .event_constraints = p6_event_constraints, |
228 | 228 | ||
229 | .format_attrs = intel_p6_formats_attr, | 229 | .format_attrs = intel_p6_formats_attr, |
230 | .events_sysfs_show = intel_event_sysfs_show, | ||
231 | |||
230 | }; | 232 | }; |
231 | 233 | ||
232 | __init int p6_pmu_init(void) | 234 | __init int p6_pmu_init(void) |
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 4929c1be0ac0..801602b5d745 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c | |||
@@ -195,12 +195,6 @@ void read_persistent_clock(struct timespec *ts) | |||
195 | ts->tv_nsec = 0; | 195 | ts->tv_nsec = 0; |
196 | } | 196 | } |
197 | 197 | ||
198 | unsigned long long native_read_tsc(void) | ||
199 | { | ||
200 | return __native_read_tsc(); | ||
201 | } | ||
202 | EXPORT_SYMBOL(native_read_tsc); | ||
203 | |||
204 | 198 | ||
205 | static struct resource rtc_resources[] = { | 199 | static struct resource rtc_resources[] = { |
206 | [0] = { | 200 | [0] = { |
diff --git a/arch/x86/kernel/trace_clock.c b/arch/x86/kernel/trace_clock.c new file mode 100644 index 000000000000..25b993729f9b --- /dev/null +++ b/arch/x86/kernel/trace_clock.c | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * X86 trace clocks | ||
3 | */ | ||
4 | #include <asm/trace_clock.h> | ||
5 | #include <asm/barrier.h> | ||
6 | #include <asm/msr.h> | ||
7 | |||
8 | /* | ||
9 | * trace_clock_x86_tsc(): A clock that is just the cycle counter. | ||
10 | * | ||
11 | * Unlike the other clocks, this is not in nanoseconds. | ||
12 | */ | ||
13 | u64 notrace trace_clock_x86_tsc(void) | ||
14 | { | ||
15 | u64 ret; | ||
16 | |||
17 | rdtsc_barrier(); | ||
18 | rdtscll(ret); | ||
19 | |||
20 | return ret; | ||
21 | } | ||
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index cfa5d4f7ca56..06ccb5073a3f 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
@@ -77,6 +77,12 @@ unsigned long long | |||
77 | sched_clock(void) __attribute__((alias("native_sched_clock"))); | 77 | sched_clock(void) __attribute__((alias("native_sched_clock"))); |
78 | #endif | 78 | #endif |
79 | 79 | ||
80 | unsigned long long native_read_tsc(void) | ||
81 | { | ||
82 | return __native_read_tsc(); | ||
83 | } | ||
84 | EXPORT_SYMBOL(native_read_tsc); | ||
85 | |||
80 | int check_tsc_unstable(void) | 86 | int check_tsc_unstable(void) |
81 | { | 87 | { |
82 | return tsc_unstable; | 88 | return tsc_unstable; |
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index aafa5557b396..c71025b67462 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -478,6 +478,11 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
478 | regs->ip = current->utask->xol_vaddr; | 478 | regs->ip = current->utask->xol_vaddr; |
479 | pre_xol_rip_insn(auprobe, regs, autask); | 479 | pre_xol_rip_insn(auprobe, regs, autask); |
480 | 480 | ||
481 | autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); | ||
482 | regs->flags |= X86_EFLAGS_TF; | ||
483 | if (test_tsk_thread_flag(current, TIF_BLOCKSTEP)) | ||
484 | set_task_blockstep(current, false); | ||
485 | |||
481 | return 0; | 486 | return 0; |
482 | } | 487 | } |
483 | 488 | ||
@@ -603,6 +608,16 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
603 | if (auprobe->fixups & UPROBE_FIX_CALL) | 608 | if (auprobe->fixups & UPROBE_FIX_CALL) |
604 | result = adjust_ret_addr(regs->sp, correction); | 609 | result = adjust_ret_addr(regs->sp, correction); |
605 | 610 | ||
611 | /* | ||
612 | * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP | ||
613 | * so we can get an extra SIGTRAP if we do not clear TF. We need | ||
614 | * to examine the opcode to make it right. | ||
615 | */ | ||
616 | if (utask->autask.saved_tf) | ||
617 | send_sig(SIGTRAP, current, 0); | ||
618 | else if (!(auprobe->fixups & UPROBE_FIX_SETF)) | ||
619 | regs->flags &= ~X86_EFLAGS_TF; | ||
620 | |||
606 | return result; | 621 | return result; |
607 | } | 622 | } |
608 | 623 | ||
@@ -647,6 +662,10 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
647 | current->thread.trap_nr = utask->autask.saved_trap_nr; | 662 | current->thread.trap_nr = utask->autask.saved_trap_nr; |
648 | handle_riprel_post_xol(auprobe, regs, NULL); | 663 | handle_riprel_post_xol(auprobe, regs, NULL); |
649 | instruction_pointer_set(regs, utask->vaddr); | 664 | instruction_pointer_set(regs, utask->vaddr); |
665 | |||
666 | /* clear TF if it was set by us in arch_uprobe_pre_xol() */ | ||
667 | if (!utask->autask.saved_tf) | ||
668 | regs->flags &= ~X86_EFLAGS_TF; | ||
650 | } | 669 | } |
651 | 670 | ||
652 | /* | 671 | /* |
@@ -676,38 +695,3 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
676 | send_sig(SIGTRAP, current, 0); | 695 | send_sig(SIGTRAP, current, 0); |
677 | return ret; | 696 | return ret; |
678 | } | 697 | } |
679 | |||
680 | void arch_uprobe_enable_step(struct arch_uprobe *auprobe) | ||
681 | { | ||
682 | struct task_struct *task = current; | ||
683 | struct arch_uprobe_task *autask = &task->utask->autask; | ||
684 | struct pt_regs *regs = task_pt_regs(task); | ||
685 | |||
686 | autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); | ||
687 | |||
688 | regs->flags |= X86_EFLAGS_TF; | ||
689 | if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) | ||
690 | set_task_blockstep(task, false); | ||
691 | } | ||
692 | |||
693 | void arch_uprobe_disable_step(struct arch_uprobe *auprobe) | ||
694 | { | ||
695 | struct task_struct *task = current; | ||
696 | struct arch_uprobe_task *autask = &task->utask->autask; | ||
697 | bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED); | ||
698 | struct pt_regs *regs = task_pt_regs(task); | ||
699 | /* | ||
700 | * The state of TIF_BLOCKSTEP was not saved so we can get an extra | ||
701 | * SIGTRAP if we do not clear TF. We need to examine the opcode to | ||
702 | * make it right. | ||
703 | */ | ||
704 | if (unlikely(trapped)) { | ||
705 | if (!autask->saved_tf) | ||
706 | regs->flags &= ~X86_EFLAGS_TF; | ||
707 | } else { | ||
708 | if (autask->saved_tf) | ||
709 | send_sig(SIGTRAP, task, 0); | ||
710 | else if (!(auprobe->fixups & UPROBE_FIX_SETF)) | ||
711 | regs->flags &= ~X86_EFLAGS_TF; | ||
712 | } | ||
713 | } | ||