diff options
Diffstat (limited to 'tools')
286 files changed, 12011 insertions, 3309 deletions
diff --git a/tools/Makefile b/tools/Makefile index c8a90d01dd8e..221e1ce78b06 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -19,6 +19,7 @@ help: | |||
19 | @echo ' kvm_stat - top-like utility for displaying kvm statistics' | 19 | @echo ' kvm_stat - top-like utility for displaying kvm statistics' |
20 | @echo ' leds - LEDs tools' | 20 | @echo ' leds - LEDs tools' |
21 | @echo ' lguest - a minimal 32-bit x86 hypervisor' | 21 | @echo ' lguest - a minimal 32-bit x86 hypervisor' |
22 | @echo ' liblockdep - user-space wrapper for kernel locking-validator' | ||
22 | @echo ' net - misc networking tools' | 23 | @echo ' net - misc networking tools' |
23 | @echo ' perf - Linux performance measurement and analysis tool' | 24 | @echo ' perf - Linux performance measurement and analysis tool' |
24 | @echo ' selftests - various kernel selftests' | 25 | @echo ' selftests - various kernel selftests' |
@@ -89,7 +90,7 @@ freefall: FORCE | |||
89 | kvm_stat: FORCE | 90 | kvm_stat: FORCE |
90 | $(call descend,kvm/$@) | 91 | $(call descend,kvm/$@) |
91 | 92 | ||
92 | all: acpi cgroup cpupower gpio hv firewire lguest \ | 93 | all: acpi cgroup cpupower gpio hv firewire lguest liblockdep \ |
93 | perf selftests turbostat usb \ | 94 | perf selftests turbostat usb \ |
94 | virtio vm net x86_energy_perf_policy \ | 95 | virtio vm net x86_energy_perf_policy \ |
95 | tmon freefall objtool kvm_stat | 96 | tmon freefall objtool kvm_stat |
@@ -103,6 +104,9 @@ cpupower_install: | |||
103 | cgroup_install firewire_install gpio_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install: | 104 | cgroup_install firewire_install gpio_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install: |
104 | $(call descend,$(@:_install=),install) | 105 | $(call descend,$(@:_install=),install) |
105 | 106 | ||
107 | liblockdep_install: | ||
108 | $(call descend,lib/lockdep,install) | ||
109 | |||
106 | selftests_install: | 110 | selftests_install: |
107 | $(call descend,testing/$(@:_install=),install) | 111 | $(call descend,testing/$(@:_install=),install) |
108 | 112 | ||
@@ -119,7 +123,7 @@ kvm_stat_install: | |||
119 | $(call descend,kvm/$(@:_install=),install) | 123 | $(call descend,kvm/$(@:_install=),install) |
120 | 124 | ||
121 | install: acpi_install cgroup_install cpupower_install gpio_install \ | 125 | install: acpi_install cgroup_install cpupower_install gpio_install \ |
122 | hv_install firewire_install lguest_install \ | 126 | hv_install firewire_install lguest_install liblockdep_install \ |
123 | perf_install selftests_install turbostat_install usb_install \ | 127 | perf_install selftests_install turbostat_install usb_install \ |
124 | virtio_install vm_install net_install x86_energy_perf_policy_install \ | 128 | virtio_install vm_install net_install x86_energy_perf_policy_install \ |
125 | tmon_install freefall_install objtool_install kvm_stat_install | 129 | tmon_install freefall_install objtool_install kvm_stat_install |
diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h index 6ebd3e6a1fd1..5e3c673fa3f4 100644 --- a/tools/arch/arm/include/uapi/asm/kvm.h +++ b/tools/arch/arm/include/uapi/asm/kvm.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #define __KVM_HAVE_IRQ_LINE | 27 | #define __KVM_HAVE_IRQ_LINE |
28 | #define __KVM_HAVE_READONLY_MEM | 28 | #define __KVM_HAVE_READONLY_MEM |
29 | 29 | ||
30 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 | ||
31 | |||
30 | #define KVM_REG_SIZE(id) \ | 32 | #define KVM_REG_SIZE(id) \ |
31 | (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) | 33 | (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) |
32 | 34 | ||
@@ -114,6 +116,8 @@ struct kvm_debug_exit_arch { | |||
114 | }; | 116 | }; |
115 | 117 | ||
116 | struct kvm_sync_regs { | 118 | struct kvm_sync_regs { |
119 | /* Used with KVM_CAP_ARM_USER_IRQ */ | ||
120 | __u64 device_irq_level; | ||
117 | }; | 121 | }; |
118 | 122 | ||
119 | struct kvm_arch_memory_slot { | 123 | struct kvm_arch_memory_slot { |
@@ -192,13 +196,17 @@ struct kvm_arch_memory_slot { | |||
192 | #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 | 196 | #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 |
193 | #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 | 197 | #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 |
194 | #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 | 198 | #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 |
199 | #define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 | ||
195 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 | 200 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 |
196 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ | 201 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ |
197 | (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) | 202 | (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) |
198 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff | 203 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff |
199 | #define VGIC_LEVEL_INFO_LINE_LEVEL 0 | 204 | #define VGIC_LEVEL_INFO_LINE_LEVEL 0 |
200 | 205 | ||
201 | #define KVM_DEV_ARM_VGIC_CTRL_INIT 0 | 206 | #define KVM_DEV_ARM_VGIC_CTRL_INIT 0 |
207 | #define KVM_DEV_ARM_ITS_SAVE_TABLES 1 | ||
208 | #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 | ||
209 | #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 | ||
202 | 210 | ||
203 | /* KVM_IRQ_LINE irq field index values */ | 211 | /* KVM_IRQ_LINE irq field index values */ |
204 | #define KVM_ARM_IRQ_TYPE_SHIFT 24 | 212 | #define KVM_ARM_IRQ_TYPE_SHIFT 24 |
diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h index c2860358ae3e..70eea2ecc663 100644 --- a/tools/arch/arm64/include/uapi/asm/kvm.h +++ b/tools/arch/arm64/include/uapi/asm/kvm.h | |||
@@ -39,6 +39,8 @@ | |||
39 | #define __KVM_HAVE_IRQ_LINE | 39 | #define __KVM_HAVE_IRQ_LINE |
40 | #define __KVM_HAVE_READONLY_MEM | 40 | #define __KVM_HAVE_READONLY_MEM |
41 | 41 | ||
42 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 | ||
43 | |||
42 | #define KVM_REG_SIZE(id) \ | 44 | #define KVM_REG_SIZE(id) \ |
43 | (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) | 45 | (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) |
44 | 46 | ||
@@ -143,6 +145,8 @@ struct kvm_debug_exit_arch { | |||
143 | #define KVM_GUESTDBG_USE_HW (1 << 17) | 145 | #define KVM_GUESTDBG_USE_HW (1 << 17) |
144 | 146 | ||
145 | struct kvm_sync_regs { | 147 | struct kvm_sync_regs { |
148 | /* Used with KVM_CAP_ARM_USER_IRQ */ | ||
149 | __u64 device_irq_level; | ||
146 | }; | 150 | }; |
147 | 151 | ||
148 | struct kvm_arch_memory_slot { | 152 | struct kvm_arch_memory_slot { |
@@ -212,13 +216,17 @@ struct kvm_arch_memory_slot { | |||
212 | #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 | 216 | #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 |
213 | #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 | 217 | #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 |
214 | #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 | 218 | #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 |
219 | #define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 | ||
215 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 | 220 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 |
216 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ | 221 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ |
217 | (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) | 222 | (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) |
218 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff | 223 | #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff |
219 | #define VGIC_LEVEL_INFO_LINE_LEVEL 0 | 224 | #define VGIC_LEVEL_INFO_LINE_LEVEL 0 |
220 | 225 | ||
221 | #define KVM_DEV_ARM_VGIC_CTRL_INIT 0 | 226 | #define KVM_DEV_ARM_VGIC_CTRL_INIT 0 |
227 | #define KVM_DEV_ARM_ITS_SAVE_TABLES 1 | ||
228 | #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 | ||
229 | #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 | ||
222 | 230 | ||
223 | /* Device Control API on vcpu fd */ | 231 | /* Device Control API on vcpu fd */ |
224 | #define KVM_ARM_VCPU_PMU_V3_CTRL 0 | 232 | #define KVM_ARM_VCPU_PMU_V3_CTRL 0 |
diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h index 4edbe4bb0e8b..07fbeb927834 100644 --- a/tools/arch/powerpc/include/uapi/asm/kvm.h +++ b/tools/arch/powerpc/include/uapi/asm/kvm.h | |||
@@ -29,6 +29,9 @@ | |||
29 | #define __KVM_HAVE_IRQ_LINE | 29 | #define __KVM_HAVE_IRQ_LINE |
30 | #define __KVM_HAVE_GUEST_DEBUG | 30 | #define __KVM_HAVE_GUEST_DEBUG |
31 | 31 | ||
32 | /* Not always available, but if it is, this is the correct offset. */ | ||
33 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 | ||
34 | |||
32 | struct kvm_regs { | 35 | struct kvm_regs { |
33 | __u64 pc; | 36 | __u64 pc; |
34 | __u64 cr; | 37 | __u64 cr; |
diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h index 7f4fd65e9208..3dd2a1d308dd 100644 --- a/tools/arch/s390/include/uapi/asm/kvm.h +++ b/tools/arch/s390/include/uapi/asm/kvm.h | |||
@@ -26,6 +26,8 @@ | |||
26 | #define KVM_DEV_FLIC_ADAPTER_REGISTER 6 | 26 | #define KVM_DEV_FLIC_ADAPTER_REGISTER 6 |
27 | #define KVM_DEV_FLIC_ADAPTER_MODIFY 7 | 27 | #define KVM_DEV_FLIC_ADAPTER_MODIFY 7 |
28 | #define KVM_DEV_FLIC_CLEAR_IO_IRQ 8 | 28 | #define KVM_DEV_FLIC_CLEAR_IO_IRQ 8 |
29 | #define KVM_DEV_FLIC_AISM 9 | ||
30 | #define KVM_DEV_FLIC_AIRQ_INJECT 10 | ||
29 | /* | 31 | /* |
30 | * We can have up to 4*64k pending subchannels + 8 adapter interrupts, | 32 | * We can have up to 4*64k pending subchannels + 8 adapter interrupts, |
31 | * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. | 33 | * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. |
@@ -41,7 +43,14 @@ struct kvm_s390_io_adapter { | |||
41 | __u8 isc; | 43 | __u8 isc; |
42 | __u8 maskable; | 44 | __u8 maskable; |
43 | __u8 swap; | 45 | __u8 swap; |
44 | __u8 pad; | 46 | __u8 flags; |
47 | }; | ||
48 | |||
49 | #define KVM_S390_ADAPTER_SUPPRESSIBLE 0x01 | ||
50 | |||
51 | struct kvm_s390_ais_req { | ||
52 | __u8 isc; | ||
53 | __u16 mode; | ||
45 | }; | 54 | }; |
46 | 55 | ||
47 | #define KVM_S390_IO_ADAPTER_MASK 1 | 56 | #define KVM_S390_IO_ADAPTER_MASK 1 |
@@ -110,6 +119,7 @@ struct kvm_s390_vm_cpu_machine { | |||
110 | #define KVM_S390_VM_CPU_FEAT_CMMA 10 | 119 | #define KVM_S390_VM_CPU_FEAT_CMMA 10 |
111 | #define KVM_S390_VM_CPU_FEAT_PFMFI 11 | 120 | #define KVM_S390_VM_CPU_FEAT_PFMFI 11 |
112 | #define KVM_S390_VM_CPU_FEAT_SIGPIF 12 | 121 | #define KVM_S390_VM_CPU_FEAT_SIGPIF 12 |
122 | #define KVM_S390_VM_CPU_FEAT_KSS 13 | ||
113 | struct kvm_s390_vm_cpu_feat { | 123 | struct kvm_s390_vm_cpu_feat { |
114 | __u64 feat[16]; | 124 | __u64 feat[16]; |
115 | }; | 125 | }; |
@@ -198,6 +208,10 @@ struct kvm_guest_debug_arch { | |||
198 | #define KVM_SYNC_VRS (1UL << 6) | 208 | #define KVM_SYNC_VRS (1UL << 6) |
199 | #define KVM_SYNC_RICCB (1UL << 7) | 209 | #define KVM_SYNC_RICCB (1UL << 7) |
200 | #define KVM_SYNC_FPRS (1UL << 8) | 210 | #define KVM_SYNC_FPRS (1UL << 8) |
211 | #define KVM_SYNC_GSCB (1UL << 9) | ||
212 | /* length and alignment of the sdnx as a power of two */ | ||
213 | #define SDNXC 8 | ||
214 | #define SDNXL (1UL << SDNXC) | ||
201 | /* definition of registers in kvm_run */ | 215 | /* definition of registers in kvm_run */ |
202 | struct kvm_sync_regs { | 216 | struct kvm_sync_regs { |
203 | __u64 prefix; /* prefix register */ | 217 | __u64 prefix; /* prefix register */ |
@@ -218,8 +232,16 @@ struct kvm_sync_regs { | |||
218 | }; | 232 | }; |
219 | __u8 reserved[512]; /* for future vector expansion */ | 233 | __u8 reserved[512]; /* for future vector expansion */ |
220 | __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ | 234 | __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ |
221 | __u8 padding[52]; /* riccb needs to be 64byte aligned */ | 235 | __u8 padding1[52]; /* riccb needs to be 64byte aligned */ |
222 | __u8 riccb[64]; /* runtime instrumentation controls block */ | 236 | __u8 riccb[64]; /* runtime instrumentation controls block */ |
237 | __u8 padding2[192]; /* sdnx needs to be 256byte aligned */ | ||
238 | union { | ||
239 | __u8 sdnx[SDNXL]; /* state description annex */ | ||
240 | struct { | ||
241 | __u64 reserved1[2]; | ||
242 | __u64 gscb[4]; | ||
243 | }; | ||
244 | }; | ||
223 | }; | 245 | }; |
224 | 246 | ||
225 | #define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1) | 247 | #define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1) |
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 0fe00446f9ca..2701e5f8145b 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h | |||
@@ -202,6 +202,8 @@ | |||
202 | #define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ | 202 | #define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ |
203 | #define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ | 203 | #define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ |
204 | 204 | ||
205 | #define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ | ||
206 | |||
205 | /* Virtualization flags: Linux defined, word 8 */ | 207 | /* Virtualization flags: Linux defined, word 8 */ |
206 | #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ | 208 | #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ |
207 | #define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ | 209 | #define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ |
diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h index 85599ad4d024..5dff775af7cd 100644 --- a/tools/arch/x86/include/asm/disabled-features.h +++ b/tools/arch/x86/include/asm/disabled-features.h | |||
@@ -36,6 +36,12 @@ | |||
36 | # define DISABLE_OSPKE (1<<(X86_FEATURE_OSPKE & 31)) | 36 | # define DISABLE_OSPKE (1<<(X86_FEATURE_OSPKE & 31)) |
37 | #endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ | 37 | #endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ |
38 | 38 | ||
39 | #ifdef CONFIG_X86_5LEVEL | ||
40 | # define DISABLE_LA57 0 | ||
41 | #else | ||
42 | # define DISABLE_LA57 (1<<(X86_FEATURE_LA57 & 31)) | ||
43 | #endif | ||
44 | |||
39 | /* | 45 | /* |
40 | * Make sure to add features to the correct mask | 46 | * Make sure to add features to the correct mask |
41 | */ | 47 | */ |
@@ -55,7 +61,7 @@ | |||
55 | #define DISABLED_MASK13 0 | 61 | #define DISABLED_MASK13 0 |
56 | #define DISABLED_MASK14 0 | 62 | #define DISABLED_MASK14 0 |
57 | #define DISABLED_MASK15 0 | 63 | #define DISABLED_MASK15 0 |
58 | #define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE) | 64 | #define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57) |
59 | #define DISABLED_MASK17 0 | 65 | #define DISABLED_MASK17 0 |
60 | #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) | 66 | #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) |
61 | 67 | ||
diff --git a/tools/arch/x86/include/asm/required-features.h b/tools/arch/x86/include/asm/required-features.h index fac9a5c0abe9..d91ba04dd007 100644 --- a/tools/arch/x86/include/asm/required-features.h +++ b/tools/arch/x86/include/asm/required-features.h | |||
@@ -53,6 +53,12 @@ | |||
53 | # define NEED_MOVBE 0 | 53 | # define NEED_MOVBE 0 |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | #ifdef CONFIG_X86_5LEVEL | ||
57 | # define NEED_LA57 (1<<(X86_FEATURE_LA57 & 31)) | ||
58 | #else | ||
59 | # define NEED_LA57 0 | ||
60 | #endif | ||
61 | |||
56 | #ifdef CONFIG_X86_64 | 62 | #ifdef CONFIG_X86_64 |
57 | #ifdef CONFIG_PARAVIRT | 63 | #ifdef CONFIG_PARAVIRT |
58 | /* Paravirtualized systems may not have PSE or PGE available */ | 64 | /* Paravirtualized systems may not have PSE or PGE available */ |
@@ -98,7 +104,7 @@ | |||
98 | #define REQUIRED_MASK13 0 | 104 | #define REQUIRED_MASK13 0 |
99 | #define REQUIRED_MASK14 0 | 105 | #define REQUIRED_MASK14 0 |
100 | #define REQUIRED_MASK15 0 | 106 | #define REQUIRED_MASK15 0 |
101 | #define REQUIRED_MASK16 0 | 107 | #define REQUIRED_MASK16 (NEED_LA57) |
102 | #define REQUIRED_MASK17 0 | 108 | #define REQUIRED_MASK17 0 |
103 | #define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) | 109 | #define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) |
104 | 110 | ||
diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index 739c0c594022..c2824d02ba37 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h | |||
@@ -9,6 +9,9 @@ | |||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/ioctl.h> | 10 | #include <linux/ioctl.h> |
11 | 11 | ||
12 | #define KVM_PIO_PAGE_OFFSET 1 | ||
13 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 2 | ||
14 | |||
12 | #define DE_VECTOR 0 | 15 | #define DE_VECTOR 0 |
13 | #define DB_VECTOR 1 | 16 | #define DB_VECTOR 1 |
14 | #define BP_VECTOR 3 | 17 | #define BP_VECTOR 3 |
diff --git a/tools/arch/x86/include/uapi/asm/vmx.h b/tools/arch/x86/include/uapi/asm/vmx.h index 14458658e988..690a2dcf4078 100644 --- a/tools/arch/x86/include/uapi/asm/vmx.h +++ b/tools/arch/x86/include/uapi/asm/vmx.h | |||
@@ -76,7 +76,11 @@ | |||
76 | #define EXIT_REASON_WBINVD 54 | 76 | #define EXIT_REASON_WBINVD 54 |
77 | #define EXIT_REASON_XSETBV 55 | 77 | #define EXIT_REASON_XSETBV 55 |
78 | #define EXIT_REASON_APIC_WRITE 56 | 78 | #define EXIT_REASON_APIC_WRITE 56 |
79 | #define EXIT_REASON_RDRAND 57 | ||
79 | #define EXIT_REASON_INVPCID 58 | 80 | #define EXIT_REASON_INVPCID 58 |
81 | #define EXIT_REASON_VMFUNC 59 | ||
82 | #define EXIT_REASON_ENCLS 60 | ||
83 | #define EXIT_REASON_RDSEED 61 | ||
80 | #define EXIT_REASON_PML_FULL 62 | 84 | #define EXIT_REASON_PML_FULL 62 |
81 | #define EXIT_REASON_XSAVES 63 | 85 | #define EXIT_REASON_XSAVES 63 |
82 | #define EXIT_REASON_XRSTORS 64 | 86 | #define EXIT_REASON_XRSTORS 64 |
@@ -90,6 +94,7 @@ | |||
90 | { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ | 94 | { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ |
91 | { EXIT_REASON_CPUID, "CPUID" }, \ | 95 | { EXIT_REASON_CPUID, "CPUID" }, \ |
92 | { EXIT_REASON_HLT, "HLT" }, \ | 96 | { EXIT_REASON_HLT, "HLT" }, \ |
97 | { EXIT_REASON_INVD, "INVD" }, \ | ||
93 | { EXIT_REASON_INVLPG, "INVLPG" }, \ | 98 | { EXIT_REASON_INVLPG, "INVLPG" }, \ |
94 | { EXIT_REASON_RDPMC, "RDPMC" }, \ | 99 | { EXIT_REASON_RDPMC, "RDPMC" }, \ |
95 | { EXIT_REASON_RDTSC, "RDTSC" }, \ | 100 | { EXIT_REASON_RDTSC, "RDTSC" }, \ |
@@ -108,6 +113,8 @@ | |||
108 | { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ | 113 | { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ |
109 | { EXIT_REASON_MSR_READ, "MSR_READ" }, \ | 114 | { EXIT_REASON_MSR_READ, "MSR_READ" }, \ |
110 | { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ | 115 | { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ |
116 | { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \ | ||
117 | { EXIT_REASON_MSR_LOAD_FAIL, "MSR_LOAD_FAIL" }, \ | ||
111 | { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ | 118 | { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ |
112 | { EXIT_REASON_MONITOR_TRAP_FLAG, "MONITOR_TRAP_FLAG" }, \ | 119 | { EXIT_REASON_MONITOR_TRAP_FLAG, "MONITOR_TRAP_FLAG" }, \ |
113 | { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ | 120 | { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ |
@@ -115,20 +122,24 @@ | |||
115 | { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ | 122 | { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ |
116 | { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ | 123 | { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ |
117 | { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ | 124 | { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ |
118 | { EXIT_REASON_GDTR_IDTR, "GDTR_IDTR" }, \ | 125 | { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \ |
119 | { EXIT_REASON_LDTR_TR, "LDTR_TR" }, \ | 126 | { EXIT_REASON_GDTR_IDTR, "GDTR_IDTR" }, \ |
127 | { EXIT_REASON_LDTR_TR, "LDTR_TR" }, \ | ||
120 | { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ | 128 | { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ |
121 | { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ | 129 | { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ |
122 | { EXIT_REASON_INVEPT, "INVEPT" }, \ | 130 | { EXIT_REASON_INVEPT, "INVEPT" }, \ |
131 | { EXIT_REASON_RDTSCP, "RDTSCP" }, \ | ||
123 | { EXIT_REASON_PREEMPTION_TIMER, "PREEMPTION_TIMER" }, \ | 132 | { EXIT_REASON_PREEMPTION_TIMER, "PREEMPTION_TIMER" }, \ |
133 | { EXIT_REASON_INVVPID, "INVVPID" }, \ | ||
124 | { EXIT_REASON_WBINVD, "WBINVD" }, \ | 134 | { EXIT_REASON_WBINVD, "WBINVD" }, \ |
135 | { EXIT_REASON_XSETBV, "XSETBV" }, \ | ||
125 | { EXIT_REASON_APIC_WRITE, "APIC_WRITE" }, \ | 136 | { EXIT_REASON_APIC_WRITE, "APIC_WRITE" }, \ |
126 | { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \ | 137 | { EXIT_REASON_RDRAND, "RDRAND" }, \ |
127 | { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \ | ||
128 | { EXIT_REASON_MSR_LOAD_FAIL, "MSR_LOAD_FAIL" }, \ | ||
129 | { EXIT_REASON_INVD, "INVD" }, \ | ||
130 | { EXIT_REASON_INVVPID, "INVVPID" }, \ | ||
131 | { EXIT_REASON_INVPCID, "INVPCID" }, \ | 138 | { EXIT_REASON_INVPCID, "INVPCID" }, \ |
139 | { EXIT_REASON_VMFUNC, "VMFUNC" }, \ | ||
140 | { EXIT_REASON_ENCLS, "ENCLS" }, \ | ||
141 | { EXIT_REASON_RDSEED, "RDSEED" }, \ | ||
142 | { EXIT_REASON_PML_FULL, "PML_FULL" }, \ | ||
132 | { EXIT_REASON_XSAVES, "XSAVES" }, \ | 143 | { EXIT_REASON_XSAVES, "XSAVES" }, \ |
133 | { EXIT_REASON_XRSTORS, "XRSTORS" } | 144 | { EXIT_REASON_XRSTORS, "XRSTORS" } |
134 | 145 | ||
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c index ebc6dceddb58..7598361ef1f1 100644 --- a/tools/build/feature/test-bpf.c +++ b/tools/build/feature/test-bpf.c | |||
@@ -29,6 +29,7 @@ int main(void) | |||
29 | attr.log_size = 0; | 29 | attr.log_size = 0; |
30 | attr.log_level = 0; | 30 | attr.log_level = 0; |
31 | attr.kern_version = 0; | 31 | attr.kern_version = 0; |
32 | attr.prog_flags = 0; | ||
32 | 33 | ||
33 | /* | 34 | /* |
34 | * Test existence of __NR_bpf and BPF_PROG_LOAD. | 35 | * Test existence of __NR_bpf and BPF_PROG_LOAD. |
diff --git a/tools/hv/bondvf.sh b/tools/hv/bondvf.sh index d85968cb1bf2..89b25068cd98 100755 --- a/tools/hv/bondvf.sh +++ b/tools/hv/bondvf.sh | |||
@@ -102,15 +102,30 @@ function create_bond_cfg_redhat { | |||
102 | } | 102 | } |
103 | 103 | ||
104 | function del_eth_cfg_ubuntu { | 104 | function del_eth_cfg_ubuntu { |
105 | local fn=$cfgdir/interfaces | 105 | local mainfn=$cfgdir/interfaces |
106 | local fnlist=( $mainfn ) | ||
107 | |||
108 | local dirlist=(`awk '/^[ \t]*source/{print $2}' $mainfn`) | ||
109 | |||
110 | local i | ||
111 | for i in "${dirlist[@]}" | ||
112 | do | ||
113 | fnlist+=(`ls $i 2>/dev/null`) | ||
114 | done | ||
115 | |||
106 | local tmpfl=$(mktemp) | 116 | local tmpfl=$(mktemp) |
107 | 117 | ||
108 | local nic_start='^[ \t]*(auto|iface|mapping|allow-.*)[ \t]+'$1 | 118 | local nic_start='^[ \t]*(auto|iface|mapping|allow-.*)[ \t]+'$1 |
109 | local nic_end='^[ \t]*(auto|iface|mapping|allow-.*|source)' | 119 | local nic_end='^[ \t]*(auto|iface|mapping|allow-.*|source)' |
110 | 120 | ||
111 | awk "/$nic_end/{x=0} x{next} /$nic_start/{x=1;next} 1" $fn >$tmpfl | 121 | local fn |
122 | for fn in "${fnlist[@]}" | ||
123 | do | ||
124 | awk "/$nic_end/{x=0} x{next} /$nic_start/{x=1;next} 1" \ | ||
125 | $fn >$tmpfl | ||
112 | 126 | ||
113 | cp $tmpfl $fn | 127 | cp $tmpfl $fn |
128 | done | ||
114 | 129 | ||
115 | rm $tmpfl | 130 | rm $tmpfl |
116 | } | 131 | } |
@@ -119,7 +134,6 @@ function create_eth_cfg_ubuntu { | |||
119 | local fn=$cfgdir/interfaces | 134 | local fn=$cfgdir/interfaces |
120 | 135 | ||
121 | del_eth_cfg_ubuntu $1 | 136 | del_eth_cfg_ubuntu $1 |
122 | |||
123 | echo $'\n'auto $1 >>$fn | 137 | echo $'\n'auto $1 >>$fn |
124 | echo iface $1 inet manual >>$fn | 138 | echo iface $1 inet manual >>$fn |
125 | echo bond-master $2 >>$fn | 139 | echo bond-master $2 >>$fn |
@@ -128,7 +142,10 @@ function create_eth_cfg_ubuntu { | |||
128 | function create_eth_cfg_pri_ubuntu { | 142 | function create_eth_cfg_pri_ubuntu { |
129 | local fn=$cfgdir/interfaces | 143 | local fn=$cfgdir/interfaces |
130 | 144 | ||
131 | create_eth_cfg_ubuntu $1 $2 | 145 | del_eth_cfg_ubuntu $1 |
146 | echo $'\n'allow-hotplug $1 >>$fn | ||
147 | echo iface $1 inet manual >>$fn | ||
148 | echo bond-master $2 >>$fn | ||
132 | echo bond-primary $1 >>$fn | 149 | echo bond-primary $1 >>$fn |
133 | } | 150 | } |
134 | 151 | ||
@@ -153,7 +170,11 @@ function create_eth_cfg_suse { | |||
153 | } | 170 | } |
154 | 171 | ||
155 | function create_eth_cfg_pri_suse { | 172 | function create_eth_cfg_pri_suse { |
156 | create_eth_cfg_suse $1 | 173 | local fn=$cfgdir/ifcfg-$1 |
174 | |||
175 | rm -f $fn | ||
176 | echo BOOTPROTO=none >>$fn | ||
177 | echo STARTMODE=hotplug >>$fn | ||
157 | } | 178 | } |
158 | 179 | ||
159 | function create_bond_cfg_suse { | 180 | function create_bond_cfg_suse { |
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index f1758fcbc37d..88b20e007c05 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <fcntl.h> | 39 | #include <fcntl.h> |
40 | #include <dirent.h> | 40 | #include <dirent.h> |
41 | #include <net/if.h> | 41 | #include <net/if.h> |
42 | #include <limits.h> | ||
42 | #include <getopt.h> | 43 | #include <getopt.h> |
43 | 44 | ||
44 | /* | 45 | /* |
@@ -97,6 +98,8 @@ static struct utsname uts_buf; | |||
97 | #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/" | 98 | #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/" |
98 | #endif | 99 | #endif |
99 | 100 | ||
101 | #define KVP_NET_DIR "/sys/class/net/" | ||
102 | |||
100 | #define MAX_FILE_NAME 100 | 103 | #define MAX_FILE_NAME 100 |
101 | #define ENTRIES_PER_BLOCK 50 | 104 | #define ENTRIES_PER_BLOCK 50 |
102 | 105 | ||
@@ -596,26 +599,21 @@ static char *kvp_get_if_name(char *guid) | |||
596 | DIR *dir; | 599 | DIR *dir; |
597 | struct dirent *entry; | 600 | struct dirent *entry; |
598 | FILE *file; | 601 | FILE *file; |
599 | char *p, *q, *x; | 602 | char *p, *x; |
600 | char *if_name = NULL; | 603 | char *if_name = NULL; |
601 | char buf[256]; | 604 | char buf[256]; |
602 | char *kvp_net_dir = "/sys/class/net/"; | 605 | char dev_id[PATH_MAX]; |
603 | char dev_id[256]; | ||
604 | 606 | ||
605 | dir = opendir(kvp_net_dir); | 607 | dir = opendir(KVP_NET_DIR); |
606 | if (dir == NULL) | 608 | if (dir == NULL) |
607 | return NULL; | 609 | return NULL; |
608 | 610 | ||
609 | snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir); | ||
610 | q = dev_id + strlen(kvp_net_dir); | ||
611 | |||
612 | while ((entry = readdir(dir)) != NULL) { | 611 | while ((entry = readdir(dir)) != NULL) { |
613 | /* | 612 | /* |
614 | * Set the state for the next pass. | 613 | * Set the state for the next pass. |
615 | */ | 614 | */ |
616 | *q = '\0'; | 615 | snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id", |
617 | strcat(dev_id, entry->d_name); | 616 | KVP_NET_DIR, entry->d_name); |
618 | strcat(dev_id, "/device/device_id"); | ||
619 | 617 | ||
620 | file = fopen(dev_id, "r"); | 618 | file = fopen(dev_id, "r"); |
621 | if (file == NULL) | 619 | if (file == NULL) |
@@ -653,12 +651,12 @@ static char *kvp_if_name_to_mac(char *if_name) | |||
653 | FILE *file; | 651 | FILE *file; |
654 | char *p, *x; | 652 | char *p, *x; |
655 | char buf[256]; | 653 | char buf[256]; |
656 | char addr_file[256]; | 654 | char addr_file[PATH_MAX]; |
657 | unsigned int i; | 655 | unsigned int i; |
658 | char *mac_addr = NULL; | 656 | char *mac_addr = NULL; |
659 | 657 | ||
660 | snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/", | 658 | snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR, |
661 | if_name, "/address"); | 659 | if_name, "/address"); |
662 | 660 | ||
663 | file = fopen(addr_file, "r"); | 661 | file = fopen(addr_file, "r"); |
664 | if (file == NULL) | 662 | if (file == NULL) |
@@ -688,28 +686,22 @@ static char *kvp_mac_to_if_name(char *mac) | |||
688 | DIR *dir; | 686 | DIR *dir; |
689 | struct dirent *entry; | 687 | struct dirent *entry; |
690 | FILE *file; | 688 | FILE *file; |
691 | char *p, *q, *x; | 689 | char *p, *x; |
692 | char *if_name = NULL; | 690 | char *if_name = NULL; |
693 | char buf[256]; | 691 | char buf[256]; |
694 | char *kvp_net_dir = "/sys/class/net/"; | 692 | char dev_id[PATH_MAX]; |
695 | char dev_id[256]; | ||
696 | unsigned int i; | 693 | unsigned int i; |
697 | 694 | ||
698 | dir = opendir(kvp_net_dir); | 695 | dir = opendir(KVP_NET_DIR); |
699 | if (dir == NULL) | 696 | if (dir == NULL) |
700 | return NULL; | 697 | return NULL; |
701 | 698 | ||
702 | snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir); | ||
703 | q = dev_id + strlen(kvp_net_dir); | ||
704 | |||
705 | while ((entry = readdir(dir)) != NULL) { | 699 | while ((entry = readdir(dir)) != NULL) { |
706 | /* | 700 | /* |
707 | * Set the state for the next pass. | 701 | * Set the state for the next pass. |
708 | */ | 702 | */ |
709 | *q = '\0'; | 703 | snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR, |
710 | 704 | entry->d_name); | |
711 | strcat(dev_id, entry->d_name); | ||
712 | strcat(dev_id, "/address"); | ||
713 | 705 | ||
714 | file = fopen(dev_id, "r"); | 706 | file = fopen(dev_id, "r"); |
715 | if (file == NULL) | 707 | if (file == NULL) |
@@ -1218,9 +1210,9 @@ static int process_ip_string(FILE *f, char *ip_string, int type) | |||
1218 | static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) | 1210 | static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) |
1219 | { | 1211 | { |
1220 | int error = 0; | 1212 | int error = 0; |
1221 | char if_file[128]; | 1213 | char if_file[PATH_MAX]; |
1222 | FILE *file; | 1214 | FILE *file; |
1223 | char cmd[512]; | 1215 | char cmd[PATH_MAX]; |
1224 | char *mac_addr; | 1216 | char *mac_addr; |
1225 | 1217 | ||
1226 | /* | 1218 | /* |
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index e0829809c897..7ba54195934c 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c | |||
@@ -261,7 +261,9 @@ int main(int argc, char *argv[]) | |||
261 | if (len != sizeof(struct hv_vss_msg)) { | 261 | if (len != sizeof(struct hv_vss_msg)) { |
262 | syslog(LOG_ERR, "write failed; error: %d %s", errno, | 262 | syslog(LOG_ERR, "write failed; error: %d %s", errno, |
263 | strerror(errno)); | 263 | strerror(errno)); |
264 | exit(EXIT_FAILURE); | 264 | |
265 | if (op == VSS_OP_FREEZE) | ||
266 | vss_operate(VSS_OP_THAW); | ||
265 | } | 267 | } |
266 | } | 268 | } |
267 | 269 | ||
diff --git a/tools/iio/Makefile b/tools/iio/Makefile index 5446d625e17d..8f08e03a9a5e 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | CC = $(CROSS_COMPILE)gcc | 1 | CC = $(CROSS_COMPILE)gcc |
2 | CFLAGS += -Wall -g -D_GNU_SOURCE | 2 | CFLAGS += -Wall -g -D_GNU_SOURCE -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include |
3 | 3 | ||
4 | BINDIR=usr/bin | 4 | BINDIR=usr/bin |
5 | INSTALL_PROGRAM=install -m 755 -p | 5 | INSTALL_PROGRAM=install -m 755 -p |
diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index 780f2014f8fa..8b379da26e35 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <stdint.h> | 13 | #include <stdint.h> |
14 | 14 | ||
15 | /* Made up value to limit allocation sizes */ | 15 | /* Made up value to limit allocation sizes */ |
16 | #define IIO_MAX_NAME_LENGTH 30 | 16 | #define IIO_MAX_NAME_LENGTH 64 |
17 | 17 | ||
18 | #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" | 18 | #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" |
19 | #define FORMAT_TYPE_FILE "%s_type" | 19 | #define FORMAT_TYPE_FILE "%s_type" |
diff --git a/tools/include/asm/sections.h b/tools/include/asm/sections.h new file mode 100644 index 000000000000..a80643d7a7f1 --- /dev/null +++ b/tools/include/asm/sections.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef __TOOLS_INCLUDE_LINUX_ASM_SECTIONS_H | ||
2 | #define __TOOLS_INCLUDE_LINUX_ASM_SECTIONS_H | ||
3 | |||
4 | #endif /* __TOOLS_INCLUDE_LINUX_ASM_SECTIONS_H */ | ||
diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h index 1aecad369af5..969db1981868 100644 --- a/tools/include/linux/bitops.h +++ b/tools/include/linux/bitops.h | |||
@@ -61,4 +61,14 @@ static inline unsigned fls_long(unsigned long l) | |||
61 | return fls64(l); | 61 | return fls64(l); |
62 | } | 62 | } |
63 | 63 | ||
64 | /** | ||
65 | * rol32 - rotate a 32-bit value left | ||
66 | * @word: value to rotate | ||
67 | * @shift: bits to roll | ||
68 | */ | ||
69 | static inline __u32 rol32(__u32 word, unsigned int shift) | ||
70 | { | ||
71 | return (word << shift) | (word >> ((-shift) & 31)); | ||
72 | } | ||
73 | |||
64 | #endif | 74 | #endif |
diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index 825d44f89a29..bd39b2090ad1 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h | |||
@@ -19,3 +19,13 @@ | |||
19 | 19 | ||
20 | /* &a[0] degrades to a pointer: a different type from an array */ | 20 | /* &a[0] degrades to a pointer: a different type from an array */ |
21 | #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) | 21 | #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) |
22 | |||
23 | #define noinline __attribute__((noinline)) | ||
24 | |||
25 | #define __packed __attribute__((packed)) | ||
26 | |||
27 | #define __noreturn __attribute__((noreturn)) | ||
28 | |||
29 | #define __aligned(x) __attribute__((aligned(x))) | ||
30 | #define __printf(a, b) __attribute__((format(printf, a, b))) | ||
31 | #define __scanf(a, b) __attribute__((format(scanf, a, b))) | ||
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 23299d7e7160..d7a5604c38d7 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h | |||
@@ -17,6 +17,10 @@ | |||
17 | # define __always_inline inline __attribute__((always_inline)) | 17 | # define __always_inline inline __attribute__((always_inline)) |
18 | #endif | 18 | #endif |
19 | 19 | ||
20 | #ifndef noinline | ||
21 | #define noinline | ||
22 | #endif | ||
23 | |||
20 | /* Are two types/vars the same type (ignoring qualifiers)? */ | 24 | /* Are two types/vars the same type (ignoring qualifiers)? */ |
21 | #ifndef __same_type | 25 | #ifndef __same_type |
22 | # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) | 26 | # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) |
@@ -45,6 +49,10 @@ | |||
45 | # define __maybe_unused __attribute__((unused)) | 49 | # define __maybe_unused __attribute__((unused)) |
46 | #endif | 50 | #endif |
47 | 51 | ||
52 | #ifndef __used | ||
53 | # define __used __attribute__((__unused__)) | ||
54 | #endif | ||
55 | |||
48 | #ifndef __packed | 56 | #ifndef __packed |
49 | # define __packed __attribute__((__packed__)) | 57 | # define __packed __attribute__((__packed__)) |
50 | #endif | 58 | #endif |
@@ -65,6 +73,14 @@ | |||
65 | # define unlikely(x) __builtin_expect(!!(x), 0) | 73 | # define unlikely(x) __builtin_expect(!!(x), 0) |
66 | #endif | 74 | #endif |
67 | 75 | ||
76 | #ifndef __init | ||
77 | # define __init | ||
78 | #endif | ||
79 | |||
80 | #ifndef noinline | ||
81 | # define noinline | ||
82 | #endif | ||
83 | |||
68 | #define uninitialized_var(x) x = *(&(x)) | 84 | #define uninitialized_var(x) x = *(&(x)) |
69 | 85 | ||
70 | #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) | 86 | #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) |
diff --git a/tools/lib/lockdep/uinclude/linux/debug_locks.h b/tools/include/linux/debug_locks.h index f38eb64df794..61cc7f501168 100644 --- a/tools/lib/lockdep/uinclude/linux/debug_locks.h +++ b/tools/include/linux/debug_locks.h | |||
@@ -3,8 +3,9 @@ | |||
3 | 3 | ||
4 | #include <stddef.h> | 4 | #include <stddef.h> |
5 | #include <linux/compiler.h> | 5 | #include <linux/compiler.h> |
6 | #include <asm/bug.h> | ||
6 | 7 | ||
7 | #define DEBUG_LOCKS_WARN_ON(x) (x) | 8 | #define DEBUG_LOCKS_WARN_ON(x) WARN_ON(x) |
8 | 9 | ||
9 | extern bool debug_locks; | 10 | extern bool debug_locks; |
10 | extern bool debug_locks_silent; | 11 | extern bool debug_locks_silent; |
diff --git a/tools/include/linux/delay.h b/tools/include/linux/delay.h new file mode 100644 index 000000000000..55aa4173af1f --- /dev/null +++ b/tools/include/linux/delay.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_DELAY_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_DELAY_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_DELAY_H */ | ||
diff --git a/tools/include/linux/err.h b/tools/include/linux/err.h index bdc3dd8131d4..abf0478a8fb2 100644 --- a/tools/include/linux/err.h +++ b/tools/include/linux/err.h | |||
@@ -46,4 +46,9 @@ static inline bool __must_check IS_ERR(__force const void *ptr) | |||
46 | return IS_ERR_VALUE((unsigned long)ptr); | 46 | return IS_ERR_VALUE((unsigned long)ptr); |
47 | } | 47 | } |
48 | 48 | ||
49 | static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr) | ||
50 | { | ||
51 | return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr); | ||
52 | } | ||
53 | |||
49 | #endif /* _LINUX_ERR_H */ | 54 | #endif /* _LINUX_ERR_H */ |
diff --git a/tools/include/linux/filter.h b/tools/include/linux/filter.h index 390d7c9685fd..4ce25d43e8e3 100644 --- a/tools/include/linux/filter.h +++ b/tools/include/linux/filter.h | |||
@@ -208,6 +208,16 @@ | |||
208 | .off = OFF, \ | 208 | .off = OFF, \ |
209 | .imm = IMM }) | 209 | .imm = IMM }) |
210 | 210 | ||
211 | /* Unconditional jumps, goto pc + off16 */ | ||
212 | |||
213 | #define BPF_JMP_A(OFF) \ | ||
214 | ((struct bpf_insn) { \ | ||
215 | .code = BPF_JMP | BPF_JA, \ | ||
216 | .dst_reg = 0, \ | ||
217 | .src_reg = 0, \ | ||
218 | .off = OFF, \ | ||
219 | .imm = 0 }) | ||
220 | |||
211 | /* Function call */ | 221 | /* Function call */ |
212 | 222 | ||
213 | #define BPF_EMIT_CALL(FUNC) \ | 223 | #define BPF_EMIT_CALL(FUNC) \ |
diff --git a/tools/include/linux/ftrace.h b/tools/include/linux/ftrace.h new file mode 100644 index 000000000000..949f541ce11e --- /dev/null +++ b/tools/include/linux/ftrace.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_FTRACE_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_FTRACE_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_FTRACE_H */ | ||
diff --git a/tools/include/linux/gfp.h b/tools/include/linux/gfp.h new file mode 100644 index 000000000000..22030756fbc0 --- /dev/null +++ b/tools/include/linux/gfp.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_GFP_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_GFP_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_GFP_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/linux/hardirq.h b/tools/include/linux/hardirq.h index c8f3f8f58729..c8f3f8f58729 100644 --- a/tools/lib/lockdep/uinclude/linux/hardirq.h +++ b/tools/include/linux/hardirq.h | |||
diff --git a/tools/include/linux/interrupt.h b/tools/include/linux/interrupt.h new file mode 100644 index 000000000000..6be25bbdca9e --- /dev/null +++ b/tools/include/linux/interrupt.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_INTERRUPT_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_INTERRUPT_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_INTERRUPT_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/linux/irqflags.h b/tools/include/linux/irqflags.h index 6cc296f0fad0..df77669cfe1c 100644 --- a/tools/lib/lockdep/uinclude/linux/irqflags.h +++ b/tools/include/linux/irqflags.h | |||
@@ -17,19 +17,19 @@ | |||
17 | #define raw_local_irq_disable() do { } while (0) | 17 | #define raw_local_irq_disable() do { } while (0) |
18 | #define raw_local_irq_enable() do { } while (0) | 18 | #define raw_local_irq_enable() do { } while (0) |
19 | #define raw_local_irq_save(flags) ((flags) = 0) | 19 | #define raw_local_irq_save(flags) ((flags) = 0) |
20 | #define raw_local_irq_restore(flags) do { } while (0) | 20 | #define raw_local_irq_restore(flags) ((void)(flags)) |
21 | #define raw_local_save_flags(flags) ((flags) = 0) | 21 | #define raw_local_save_flags(flags) ((flags) = 0) |
22 | #define raw_irqs_disabled_flags(flags) do { } while (0) | 22 | #define raw_irqs_disabled_flags(flags) ((void)(flags)) |
23 | #define raw_irqs_disabled() 0 | 23 | #define raw_irqs_disabled() 0 |
24 | #define raw_safe_halt() | 24 | #define raw_safe_halt() |
25 | 25 | ||
26 | #define local_irq_enable() do { } while (0) | 26 | #define local_irq_enable() do { } while (0) |
27 | #define local_irq_disable() do { } while (0) | 27 | #define local_irq_disable() do { } while (0) |
28 | #define local_irq_save(flags) ((flags) = 0) | 28 | #define local_irq_save(flags) ((flags) = 0) |
29 | #define local_irq_restore(flags) do { } while (0) | 29 | #define local_irq_restore(flags) ((void)(flags)) |
30 | #define local_save_flags(flags) ((flags) = 0) | 30 | #define local_save_flags(flags) ((flags) = 0) |
31 | #define irqs_disabled() (1) | 31 | #define irqs_disabled() (1) |
32 | #define irqs_disabled_flags(flags) (0) | 32 | #define irqs_disabled_flags(flags) ((void)(flags), 0) |
33 | #define safe_halt() do { } while (0) | 33 | #define safe_halt() do { } while (0) |
34 | 34 | ||
35 | #define trace_lock_release(x, y) | 35 | #define trace_lock_release(x, y) |
diff --git a/tools/include/linux/jhash.h b/tools/include/linux/jhash.h new file mode 100644 index 000000000000..348c6f47e4cc --- /dev/null +++ b/tools/include/linux/jhash.h | |||
@@ -0,0 +1,175 @@ | |||
1 | #ifndef _LINUX_JHASH_H | ||
2 | #define _LINUX_JHASH_H | ||
3 | |||
4 | /* jhash.h: Jenkins hash support. | ||
5 | * | ||
6 | * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) | ||
7 | * | ||
8 | * http://burtleburtle.net/bob/hash/ | ||
9 | * | ||
10 | * These are the credits from Bob's sources: | ||
11 | * | ||
12 | * lookup3.c, by Bob Jenkins, May 2006, Public Domain. | ||
13 | * | ||
14 | * These are functions for producing 32-bit hashes for hash table lookup. | ||
15 | * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() | ||
16 | * are externally useful functions. Routines to test the hash are included | ||
17 | * if SELF_TEST is defined. You can use this free for any purpose. It's in | ||
18 | * the public domain. It has no warranty. | ||
19 | * | ||
20 | * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) | ||
21 | * | ||
22 | * I've modified Bob's hash to be useful in the Linux kernel, and | ||
23 | * any bugs present are my fault. | ||
24 | * Jozsef | ||
25 | */ | ||
26 | #include <linux/bitops.h> | ||
27 | #include <linux/unaligned/packed_struct.h> | ||
28 | |||
29 | /* Best hash sizes are of power of two */ | ||
30 | #define jhash_size(n) ((u32)1<<(n)) | ||
31 | /* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */ | ||
32 | #define jhash_mask(n) (jhash_size(n)-1) | ||
33 | |||
34 | /* __jhash_mix -- mix 3 32-bit values reversibly. */ | ||
35 | #define __jhash_mix(a, b, c) \ | ||
36 | { \ | ||
37 | a -= c; a ^= rol32(c, 4); c += b; \ | ||
38 | b -= a; b ^= rol32(a, 6); a += c; \ | ||
39 | c -= b; c ^= rol32(b, 8); b += a; \ | ||
40 | a -= c; a ^= rol32(c, 16); c += b; \ | ||
41 | b -= a; b ^= rol32(a, 19); a += c; \ | ||
42 | c -= b; c ^= rol32(b, 4); b += a; \ | ||
43 | } | ||
44 | |||
45 | /* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */ | ||
46 | #define __jhash_final(a, b, c) \ | ||
47 | { \ | ||
48 | c ^= b; c -= rol32(b, 14); \ | ||
49 | a ^= c; a -= rol32(c, 11); \ | ||
50 | b ^= a; b -= rol32(a, 25); \ | ||
51 | c ^= b; c -= rol32(b, 16); \ | ||
52 | a ^= c; a -= rol32(c, 4); \ | ||
53 | b ^= a; b -= rol32(a, 14); \ | ||
54 | c ^= b; c -= rol32(b, 24); \ | ||
55 | } | ||
56 | |||
57 | /* An arbitrary initial parameter */ | ||
58 | #define JHASH_INITVAL 0xdeadbeef | ||
59 | |||
60 | /* jhash - hash an arbitrary key | ||
61 | * @k: sequence of bytes as key | ||
62 | * @length: the length of the key | ||
63 | * @initval: the previous hash, or an arbitray value | ||
64 | * | ||
65 | * The generic version, hashes an arbitrary sequence of bytes. | ||
66 | * No alignment or length assumptions are made about the input key. | ||
67 | * | ||
68 | * Returns the hash value of the key. The result depends on endianness. | ||
69 | */ | ||
70 | static inline u32 jhash(const void *key, u32 length, u32 initval) | ||
71 | { | ||
72 | u32 a, b, c; | ||
73 | const u8 *k = key; | ||
74 | |||
75 | /* Set up the internal state */ | ||
76 | a = b = c = JHASH_INITVAL + length + initval; | ||
77 | |||
78 | /* All but the last block: affect some 32 bits of (a,b,c) */ | ||
79 | while (length > 12) { | ||
80 | a += __get_unaligned_cpu32(k); | ||
81 | b += __get_unaligned_cpu32(k + 4); | ||
82 | c += __get_unaligned_cpu32(k + 8); | ||
83 | __jhash_mix(a, b, c); | ||
84 | length -= 12; | ||
85 | k += 12; | ||
86 | } | ||
87 | /* Last block: affect all 32 bits of (c) */ | ||
88 | /* All the case statements fall through */ | ||
89 | switch (length) { | ||
90 | case 12: c += (u32)k[11]<<24; | ||
91 | case 11: c += (u32)k[10]<<16; | ||
92 | case 10: c += (u32)k[9]<<8; | ||
93 | case 9: c += k[8]; | ||
94 | case 8: b += (u32)k[7]<<24; | ||
95 | case 7: b += (u32)k[6]<<16; | ||
96 | case 6: b += (u32)k[5]<<8; | ||
97 | case 5: b += k[4]; | ||
98 | case 4: a += (u32)k[3]<<24; | ||
99 | case 3: a += (u32)k[2]<<16; | ||
100 | case 2: a += (u32)k[1]<<8; | ||
101 | case 1: a += k[0]; | ||
102 | __jhash_final(a, b, c); | ||
103 | case 0: /* Nothing left to add */ | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | return c; | ||
108 | } | ||
109 | |||
110 | /* jhash2 - hash an array of u32's | ||
111 | * @k: the key which must be an array of u32's | ||
112 | * @length: the number of u32's in the key | ||
113 | * @initval: the previous hash, or an arbitray value | ||
114 | * | ||
115 | * Returns the hash value of the key. | ||
116 | */ | ||
117 | static inline u32 jhash2(const u32 *k, u32 length, u32 initval) | ||
118 | { | ||
119 | u32 a, b, c; | ||
120 | |||
121 | /* Set up the internal state */ | ||
122 | a = b = c = JHASH_INITVAL + (length<<2) + initval; | ||
123 | |||
124 | /* Handle most of the key */ | ||
125 | while (length > 3) { | ||
126 | a += k[0]; | ||
127 | b += k[1]; | ||
128 | c += k[2]; | ||
129 | __jhash_mix(a, b, c); | ||
130 | length -= 3; | ||
131 | k += 3; | ||
132 | } | ||
133 | |||
134 | /* Handle the last 3 u32's: all the case statements fall through */ | ||
135 | switch (length) { | ||
136 | case 3: c += k[2]; | ||
137 | case 2: b += k[1]; | ||
138 | case 1: a += k[0]; | ||
139 | __jhash_final(a, b, c); | ||
140 | case 0: /* Nothing left to add */ | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | return c; | ||
145 | } | ||
146 | |||
147 | |||
148 | /* __jhash_nwords - hash exactly 3, 2 or 1 word(s) */ | ||
149 | static inline u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) | ||
150 | { | ||
151 | a += initval; | ||
152 | b += initval; | ||
153 | c += initval; | ||
154 | |||
155 | __jhash_final(a, b, c); | ||
156 | |||
157 | return c; | ||
158 | } | ||
159 | |||
160 | static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) | ||
161 | { | ||
162 | return __jhash_nwords(a, b, c, initval + JHASH_INITVAL + (3 << 2)); | ||
163 | } | ||
164 | |||
165 | static inline u32 jhash_2words(u32 a, u32 b, u32 initval) | ||
166 | { | ||
167 | return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); | ||
168 | } | ||
169 | |||
170 | static inline u32 jhash_1word(u32 a, u32 initval) | ||
171 | { | ||
172 | return __jhash_nwords(a, 0, 0, initval + JHASH_INITVAL + (1 << 2)); | ||
173 | } | ||
174 | |||
175 | #endif /* _LINUX_JHASH_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kallsyms.h b/tools/include/linux/kallsyms.h index b0f2dbdf1a15..582cc1e5f3a4 100644 --- a/tools/lib/lockdep/uinclude/linux/kallsyms.h +++ b/tools/include/linux/kallsyms.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
5 | #include <stdio.h> | 5 | #include <stdio.h> |
6 | #include <unistd.h> | ||
6 | 7 | ||
7 | #define KSYM_NAME_LEN 128 | 8 | #define KSYM_NAME_LEN 128 |
8 | 9 | ||
@@ -24,7 +25,7 @@ static inline void print_ip_sym(unsigned long ip) | |||
24 | 25 | ||
25 | name = backtrace_symbols((void **)&ip, 1); | 26 | name = backtrace_symbols((void **)&ip, 1); |
26 | 27 | ||
27 | printf("%s\n", *name); | 28 | dprintf(STDOUT_FILENO, "%s\n", *name); |
28 | 29 | ||
29 | free(name); | 30 | free(name); |
30 | } | 31 | } |
diff --git a/tools/lib/lockdep/uinclude/linux/kern_levels.h b/tools/include/linux/kern_levels.h index 3b9bade28698..3b9bade28698 100644 --- a/tools/lib/lockdep/uinclude/linux/kern_levels.h +++ b/tools/include/linux/kern_levels.h | |||
diff --git a/tools/include/linux/kernel.h b/tools/include/linux/kernel.h index 73ccc48126bb..77d2e94ca5df 100644 --- a/tools/include/linux/kernel.h +++ b/tools/include/linux/kernel.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <stddef.h> | 5 | #include <stddef.h> |
6 | #include <assert.h> | 6 | #include <assert.h> |
7 | #include <linux/compiler.h> | 7 | #include <linux/compiler.h> |
8 | #include <endian.h> | ||
9 | #include <byteswap.h> | ||
8 | 10 | ||
9 | #ifndef UINT_MAX | 11 | #ifndef UINT_MAX |
10 | #define UINT_MAX (~0U) | 12 | #define UINT_MAX (~0U) |
@@ -32,6 +34,7 @@ | |||
32 | (type *)((char *)__mptr - offsetof(type, member)); }) | 34 | (type *)((char *)__mptr - offsetof(type, member)); }) |
33 | #endif | 35 | #endif |
34 | 36 | ||
37 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | ||
35 | #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) | 38 | #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) |
36 | 39 | ||
37 | #ifndef max | 40 | #ifndef max |
@@ -67,12 +70,33 @@ | |||
67 | #endif | 70 | #endif |
68 | #endif | 71 | #endif |
69 | 72 | ||
70 | /* | 73 | #if __BYTE_ORDER == __BIG_ENDIAN |
71 | * Both need more care to handle endianness | 74 | #define cpu_to_le16 bswap_16 |
72 | * (Don't use bitmap_copy_le() for now) | 75 | #define cpu_to_le32 bswap_32 |
73 | */ | 76 | #define cpu_to_le64 bswap_64 |
74 | #define cpu_to_le64(x) (x) | 77 | #define le16_to_cpu bswap_16 |
75 | #define cpu_to_le32(x) (x) | 78 | #define le32_to_cpu bswap_32 |
79 | #define le64_to_cpu bswap_64 | ||
80 | #define cpu_to_be16 | ||
81 | #define cpu_to_be32 | ||
82 | #define cpu_to_be64 | ||
83 | #define be16_to_cpu | ||
84 | #define be32_to_cpu | ||
85 | #define be64_to_cpu | ||
86 | #else | ||
87 | #define cpu_to_le16 | ||
88 | #define cpu_to_le32 | ||
89 | #define cpu_to_le64 | ||
90 | #define le16_to_cpu | ||
91 | #define le32_to_cpu | ||
92 | #define le64_to_cpu | ||
93 | #define cpu_to_be16 bswap_16 | ||
94 | #define cpu_to_be32 bswap_32 | ||
95 | #define cpu_to_be64 bswap_64 | ||
96 | #define be16_to_cpu bswap_16 | ||
97 | #define be32_to_cpu bswap_32 | ||
98 | #define be64_to_cpu bswap_64 | ||
99 | #endif | ||
76 | 100 | ||
77 | int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); | 101 | int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); |
78 | int scnprintf(char * buf, size_t size, const char * fmt, ...); | 102 | int scnprintf(char * buf, size_t size, const char * fmt, ...); |
@@ -89,4 +113,7 @@ int scnprintf(char * buf, size_t size, const char * fmt, ...); | |||
89 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) | 113 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) |
90 | #define round_down(x, y) ((x) & ~__round_mask(x, y)) | 114 | #define round_down(x, y) ((x) & ~__round_mask(x, y)) |
91 | 115 | ||
116 | #define current_gfp_context(k) 0 | ||
117 | #define synchronize_sched() | ||
118 | |||
92 | #endif | 119 | #endif |
diff --git a/tools/lib/lockdep/uinclude/linux/kmemcheck.h b/tools/include/linux/kmemcheck.h index 94d598bc6abe..94d598bc6abe 100644 --- a/tools/lib/lockdep/uinclude/linux/kmemcheck.h +++ b/tools/include/linux/kmemcheck.h | |||
diff --git a/tools/include/linux/linkage.h b/tools/include/linux/linkage.h new file mode 100644 index 000000000000..bc763d500262 --- /dev/null +++ b/tools/include/linux/linkage.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_LINKAGE_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_LINKAGE_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_LINKAGE_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/include/linux/lockdep.h index c808c7d02d21..8da3e8effafa 100644 --- a/tools/lib/lockdep/uinclude/linux/lockdep.h +++ b/tools/include/linux/lockdep.h | |||
@@ -7,8 +7,15 @@ | |||
7 | #include <limits.h> | 7 | #include <limits.h> |
8 | #include <linux/utsname.h> | 8 | #include <linux/utsname.h> |
9 | #include <linux/compiler.h> | 9 | #include <linux/compiler.h> |
10 | #include <linux/export.h> | ||
11 | #include <linux/kern_levels.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/rcu.h> | ||
14 | #include <linux/list.h> | ||
15 | #include <linux/hardirq.h> | ||
16 | #include <unistd.h> | ||
10 | 17 | ||
11 | #define MAX_LOCK_DEPTH 2000UL | 18 | #define MAX_LOCK_DEPTH 63UL |
12 | 19 | ||
13 | #define asmlinkage | 20 | #define asmlinkage |
14 | #define __visible | 21 | #define __visible |
@@ -29,31 +36,32 @@ extern struct task_struct *__curr(void); | |||
29 | 36 | ||
30 | #define current (__curr()) | 37 | #define current (__curr()) |
31 | 38 | ||
32 | #define debug_locks_off() 1 | 39 | static inline int debug_locks_off(void) |
40 | { | ||
41 | return 1; | ||
42 | } | ||
43 | |||
33 | #define task_pid_nr(tsk) ((tsk)->pid) | 44 | #define task_pid_nr(tsk) ((tsk)->pid) |
34 | 45 | ||
35 | #define KSYM_NAME_LEN 128 | 46 | #define KSYM_NAME_LEN 128 |
36 | #define printk printf | 47 | #define printk(...) dprintf(STDOUT_FILENO, __VA_ARGS__) |
48 | #define pr_err(format, ...) fprintf (stderr, format, ## __VA_ARGS__) | ||
49 | #define pr_warn pr_err | ||
37 | 50 | ||
38 | #define list_del_rcu list_del | 51 | #define list_del_rcu list_del |
39 | 52 | ||
40 | #define atomic_t unsigned long | 53 | #define atomic_t unsigned long |
41 | #define atomic_inc(x) ((*(x))++) | 54 | #define atomic_inc(x) ((*(x))++) |
42 | 55 | ||
43 | static struct new_utsname *init_utsname(void) | ||
44 | { | ||
45 | static struct new_utsname n = (struct new_utsname) { | ||
46 | .release = "liblockdep", | ||
47 | .version = LIBLOCKDEP_VERSION, | ||
48 | }; | ||
49 | |||
50 | return &n; | ||
51 | } | ||
52 | |||
53 | #define print_tainted() "" | 56 | #define print_tainted() "" |
54 | #define static_obj(x) 1 | 57 | #define static_obj(x) 1 |
55 | 58 | ||
56 | #define debug_show_all_locks() | 59 | #define debug_show_all_locks() |
57 | extern void debug_check_no_locks_held(void); | 60 | extern void debug_check_no_locks_held(void); |
58 | 61 | ||
62 | static __used bool __is_kernel_percpu_address(unsigned long addr, void *can_addr) | ||
63 | { | ||
64 | return false; | ||
65 | } | ||
66 | |||
59 | #endif | 67 | #endif |
diff --git a/tools/lib/lockdep/uinclude/linux/module.h b/tools/include/linux/module.h index 09c7a7be8ccc..07055db296f3 100644 --- a/tools/lib/lockdep/uinclude/linux/module.h +++ b/tools/include/linux/module.h | |||
@@ -3,4 +3,9 @@ | |||
3 | 3 | ||
4 | #define module_param(name, type, perm) | 4 | #define module_param(name, type, perm) |
5 | 5 | ||
6 | static inline bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr) | ||
7 | { | ||
8 | return false; | ||
9 | } | ||
10 | |||
6 | #endif | 11 | #endif |
diff --git a/tools/include/linux/mutex.h b/tools/include/linux/mutex.h new file mode 100644 index 000000000000..a8180d25f2fc --- /dev/null +++ b/tools/include/linux/mutex.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_MUTEX_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_MUTEX_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_MUTEX_H */ | ||
diff --git a/tools/include/linux/proc_fs.h b/tools/include/linux/proc_fs.h new file mode 100644 index 000000000000..8b3b03b64fda --- /dev/null +++ b/tools/include/linux/proc_fs.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_PROC_FS_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_PROC_FS_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_PROC_FS_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/linux/rcu.h b/tools/include/linux/rcu.h index 042ee8e463c9..5080649dad04 100644 --- a/tools/lib/lockdep/uinclude/linux/rcu.h +++ b/tools/include/linux/rcu.h | |||
@@ -18,4 +18,7 @@ static inline bool rcu_is_watching(void) | |||
18 | return false; | 18 | return false; |
19 | } | 19 | } |
20 | 20 | ||
21 | #define rcu_assign_pointer(p, v) ((p) = (v)) | ||
22 | #define RCU_INIT_POINTER(p, v) p=(v) | ||
23 | |||
21 | #endif | 24 | #endif |
diff --git a/tools/include/linux/sched/clock.h b/tools/include/linux/sched/clock.h new file mode 100644 index 000000000000..5837d17c4182 --- /dev/null +++ b/tools/include/linux/sched/clock.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_PERF_LINUX_SCHED_CLOCK_H | ||
2 | #define _TOOLS_PERF_LINUX_SCHED_CLOCK_H | ||
3 | |||
4 | #endif /* _TOOLS_PERF_LINUX_SCHED_CLOCK_H */ | ||
diff --git a/tools/include/linux/sched/mm.h b/tools/include/linux/sched/mm.h new file mode 100644 index 000000000000..c8d9f19c1f35 --- /dev/null +++ b/tools/include/linux/sched/mm.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_PERF_LINUX_SCHED_MM_H | ||
2 | #define _TOOLS_PERF_LINUX_SCHED_MM_H | ||
3 | |||
4 | #endif /* _TOOLS_PERF_LINUX_SCHED_MM_H */ | ||
diff --git a/tools/include/linux/sched/task.h b/tools/include/linux/sched/task.h new file mode 100644 index 000000000000..a97890eca110 --- /dev/null +++ b/tools/include/linux/sched/task.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_PERF_LINUX_SCHED_TASK_H | ||
2 | #define _TOOLS_PERF_LINUX_SCHED_TASK_H | ||
3 | |||
4 | #endif /* _TOOLS_PERF_LINUX_SCHED_TASK_H */ | ||
diff --git a/tools/include/linux/seq_file.h b/tools/include/linux/seq_file.h new file mode 100644 index 000000000000..102fd9217f1f --- /dev/null +++ b/tools/include/linux/seq_file.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_LINUX_SEQ_FILE_H | ||
2 | #define _TOOLS_INCLUDE_LINUX_SEQ_FILE_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_LINUX_SEQ_FILE_H */ | ||
diff --git a/tools/include/linux/spinlock.h b/tools/include/linux/spinlock.h index 58397dcb19d6..417cda4f793f 100644 --- a/tools/include/linux/spinlock.h +++ b/tools/include/linux/spinlock.h | |||
@@ -1,5 +1,31 @@ | |||
1 | #ifndef __LINUX_SPINLOCK_H_ | ||
2 | #define __LINUX_SPINLOCK_H_ | ||
3 | |||
4 | #include <pthread.h> | ||
5 | #include <stdbool.h> | ||
6 | |||
1 | #define spinlock_t pthread_mutex_t | 7 | #define spinlock_t pthread_mutex_t |
2 | #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; | 8 | #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; |
3 | 9 | ||
4 | #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) | 10 | #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) |
5 | #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) | 11 | #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) |
12 | |||
13 | #define arch_spinlock_t pthread_mutex_t | ||
14 | #define __ARCH_SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER | ||
15 | |||
16 | static inline void arch_spin_lock(arch_spinlock_t *mutex) | ||
17 | { | ||
18 | pthread_mutex_lock(mutex); | ||
19 | } | ||
20 | |||
21 | static inline void arch_spin_unlock(arch_spinlock_t *mutex) | ||
22 | { | ||
23 | pthread_mutex_unlock(mutex); | ||
24 | } | ||
25 | |||
26 | static inline bool arch_spin_is_locked(arch_spinlock_t *mutex) | ||
27 | { | ||
28 | return true; | ||
29 | } | ||
30 | |||
31 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/stacktrace.h b/tools/include/linux/stacktrace.h index 39aecc6b19d1..39aecc6b19d1 100644 --- a/tools/lib/lockdep/uinclude/linux/stacktrace.h +++ b/tools/include/linux/stacktrace.h | |||
diff --git a/tools/include/linux/unaligned/packed_struct.h b/tools/include/linux/unaligned/packed_struct.h new file mode 100644 index 000000000000..c0d817de4df2 --- /dev/null +++ b/tools/include/linux/unaligned/packed_struct.h | |||
@@ -0,0 +1,46 @@ | |||
1 | #ifndef _LINUX_UNALIGNED_PACKED_STRUCT_H | ||
2 | #define _LINUX_UNALIGNED_PACKED_STRUCT_H | ||
3 | |||
4 | #include <linux/kernel.h> | ||
5 | |||
6 | struct __una_u16 { u16 x; } __packed; | ||
7 | struct __una_u32 { u32 x; } __packed; | ||
8 | struct __una_u64 { u64 x; } __packed; | ||
9 | |||
10 | static inline u16 __get_unaligned_cpu16(const void *p) | ||
11 | { | ||
12 | const struct __una_u16 *ptr = (const struct __una_u16 *)p; | ||
13 | return ptr->x; | ||
14 | } | ||
15 | |||
16 | static inline u32 __get_unaligned_cpu32(const void *p) | ||
17 | { | ||
18 | const struct __una_u32 *ptr = (const struct __una_u32 *)p; | ||
19 | return ptr->x; | ||
20 | } | ||
21 | |||
22 | static inline u64 __get_unaligned_cpu64(const void *p) | ||
23 | { | ||
24 | const struct __una_u64 *ptr = (const struct __una_u64 *)p; | ||
25 | return ptr->x; | ||
26 | } | ||
27 | |||
28 | static inline void __put_unaligned_cpu16(u16 val, void *p) | ||
29 | { | ||
30 | struct __una_u16 *ptr = (struct __una_u16 *)p; | ||
31 | ptr->x = val; | ||
32 | } | ||
33 | |||
34 | static inline void __put_unaligned_cpu32(u32 val, void *p) | ||
35 | { | ||
36 | struct __una_u32 *ptr = (struct __una_u32 *)p; | ||
37 | ptr->x = val; | ||
38 | } | ||
39 | |||
40 | static inline void __put_unaligned_cpu64(u64 val, void *p) | ||
41 | { | ||
42 | struct __una_u64 *ptr = (struct __una_u64 *)p; | ||
43 | ptr->x = val; | ||
44 | } | ||
45 | |||
46 | #endif /* _LINUX_UNALIGNED_PACKED_STRUCT_H */ | ||
diff --git a/tools/include/trace/events/lock.h b/tools/include/trace/events/lock.h new file mode 100644 index 000000000000..5b15fd5ee1af --- /dev/null +++ b/tools/include/trace/events/lock.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _TOOLS_INCLUDE_TRACE_EVENTS_LOCK_H | ||
2 | #define _TOOLS_INCLUDE_TRACE_EVENTS_LOCK_H | ||
3 | |||
4 | #endif /* _TOOLS_INCLUDE_TRACE_EVENTS_LOCK_H */ | ||
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e553529929f6..ce2988be4f0e 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -82,6 +82,11 @@ enum bpf_cmd { | |||
82 | BPF_PROG_ATTACH, | 82 | BPF_PROG_ATTACH, |
83 | BPF_PROG_DETACH, | 83 | BPF_PROG_DETACH, |
84 | BPF_PROG_TEST_RUN, | 84 | BPF_PROG_TEST_RUN, |
85 | BPF_PROG_GET_NEXT_ID, | ||
86 | BPF_MAP_GET_NEXT_ID, | ||
87 | BPF_PROG_GET_FD_BY_ID, | ||
88 | BPF_MAP_GET_FD_BY_ID, | ||
89 | BPF_OBJ_GET_INFO_BY_FD, | ||
85 | }; | 90 | }; |
86 | 91 | ||
87 | enum bpf_map_type { | 92 | enum bpf_map_type { |
@@ -115,12 +120,14 @@ enum bpf_prog_type { | |||
115 | BPF_PROG_TYPE_LWT_IN, | 120 | BPF_PROG_TYPE_LWT_IN, |
116 | BPF_PROG_TYPE_LWT_OUT, | 121 | BPF_PROG_TYPE_LWT_OUT, |
117 | BPF_PROG_TYPE_LWT_XMIT, | 122 | BPF_PROG_TYPE_LWT_XMIT, |
123 | BPF_PROG_TYPE_SOCK_OPS, | ||
118 | }; | 124 | }; |
119 | 125 | ||
120 | enum bpf_attach_type { | 126 | enum bpf_attach_type { |
121 | BPF_CGROUP_INET_INGRESS, | 127 | BPF_CGROUP_INET_INGRESS, |
122 | BPF_CGROUP_INET_EGRESS, | 128 | BPF_CGROUP_INET_EGRESS, |
123 | BPF_CGROUP_INET_SOCK_CREATE, | 129 | BPF_CGROUP_INET_SOCK_CREATE, |
130 | BPF_CGROUP_SOCK_OPS, | ||
124 | __MAX_BPF_ATTACH_TYPE | 131 | __MAX_BPF_ATTACH_TYPE |
125 | }; | 132 | }; |
126 | 133 | ||
@@ -132,6 +139,13 @@ enum bpf_attach_type { | |||
132 | */ | 139 | */ |
133 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) | 140 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) |
134 | 141 | ||
142 | /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the | ||
143 | * verifier will perform strict alignment checking as if the kernel | ||
144 | * has been built with CONFIG_EFFICIENT_UNALIGNED_ACCESS not set, | ||
145 | * and NET_IP_ALIGN defined to 2. | ||
146 | */ | ||
147 | #define BPF_F_STRICT_ALIGNMENT (1U << 0) | ||
148 | |||
135 | #define BPF_PSEUDO_MAP_FD 1 | 149 | #define BPF_PSEUDO_MAP_FD 1 |
136 | 150 | ||
137 | /* flags for BPF_MAP_UPDATE_ELEM command */ | 151 | /* flags for BPF_MAP_UPDATE_ELEM command */ |
@@ -177,6 +191,7 @@ union bpf_attr { | |||
177 | __u32 log_size; /* size of user buffer */ | 191 | __u32 log_size; /* size of user buffer */ |
178 | __aligned_u64 log_buf; /* user supplied buffer */ | 192 | __aligned_u64 log_buf; /* user supplied buffer */ |
179 | __u32 kern_version; /* checked when prog_type=kprobe */ | 193 | __u32 kern_version; /* checked when prog_type=kprobe */ |
194 | __u32 prog_flags; | ||
180 | }; | 195 | }; |
181 | 196 | ||
182 | struct { /* anonymous struct used by BPF_OBJ_* commands */ | 197 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
@@ -201,6 +216,21 @@ union bpf_attr { | |||
201 | __u32 repeat; | 216 | __u32 repeat; |
202 | __u32 duration; | 217 | __u32 duration; |
203 | } test; | 218 | } test; |
219 | |||
220 | struct { /* anonymous struct used by BPF_*_GET_*_ID */ | ||
221 | union { | ||
222 | __u32 start_id; | ||
223 | __u32 prog_id; | ||
224 | __u32 map_id; | ||
225 | }; | ||
226 | __u32 next_id; | ||
227 | }; | ||
228 | |||
229 | struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */ | ||
230 | __u32 bpf_fd; | ||
231 | __u32 info_len; | ||
232 | __aligned_u64 info; | ||
233 | } info; | ||
204 | } __attribute__((aligned(8))); | 234 | } __attribute__((aligned(8))); |
205 | 235 | ||
206 | /* BPF helper function descriptions: | 236 | /* BPF helper function descriptions: |
@@ -305,8 +335,11 @@ union bpf_attr { | |||
305 | * @flags: room for future extensions | 335 | * @flags: room for future extensions |
306 | * Return: 0 on success or negative error | 336 | * Return: 0 on success or negative error |
307 | * | 337 | * |
308 | * u64 bpf_perf_event_read(&map, index) | 338 | * u64 bpf_perf_event_read(map, flags) |
309 | * Return: Number events read or error code | 339 | * read perf event counter value |
340 | * @map: pointer to perf_event_array map | ||
341 | * @flags: index of event in the map or bitmask flags | ||
342 | * Return: value of perf event counter read or error code | ||
310 | * | 343 | * |
311 | * int bpf_redirect(ifindex, flags) | 344 | * int bpf_redirect(ifindex, flags) |
312 | * redirect to another netdev | 345 | * redirect to another netdev |
@@ -320,11 +353,11 @@ union bpf_attr { | |||
320 | * @skb: pointer to skb | 353 | * @skb: pointer to skb |
321 | * Return: realm if != 0 | 354 | * Return: realm if != 0 |
322 | * | 355 | * |
323 | * int bpf_perf_event_output(ctx, map, index, data, size) | 356 | * int bpf_perf_event_output(ctx, map, flags, data, size) |
324 | * output perf raw sample | 357 | * output perf raw sample |
325 | * @ctx: struct pt_regs* | 358 | * @ctx: struct pt_regs* |
326 | * @map: pointer to perf_event_array map | 359 | * @map: pointer to perf_event_array map |
327 | * @index: index of event in the map | 360 | * @flags: index of event in the map or bitmask flags |
328 | * @data: data on stack to be output as raw data | 361 | * @data: data on stack to be output as raw data |
329 | * @size: size of data | 362 | * @size: size of data |
330 | * Return: 0 on success or negative error | 363 | * Return: 0 on success or negative error |
@@ -481,8 +514,31 @@ union bpf_attr { | |||
481 | * u32 bpf_get_socket_uid(skb) | 514 | * u32 bpf_get_socket_uid(skb) |
482 | * Get the owner uid of the socket stored inside sk_buff. | 515 | * Get the owner uid of the socket stored inside sk_buff. |
483 | * @skb: pointer to skb | 516 | * @skb: pointer to skb |
484 | * Return: uid of the socket owner on success or 0 if the socket pointer | 517 | * Return: uid of the socket owner on success or overflowuid if failed. |
485 | * inside sk_buff is NULL | 518 | * |
519 | * u32 bpf_set_hash(skb, hash) | ||
520 | * Set full skb->hash. | ||
521 | * @skb: pointer to skb | ||
522 | * @hash: hash to set | ||
523 | * | ||
524 | * int bpf_setsockopt(bpf_socket, level, optname, optval, optlen) | ||
525 | * Calls setsockopt. Not all opts are available, only those with | ||
526 | * integer optvals plus TCP_CONGESTION. | ||
527 | * Supported levels: SOL_SOCKET and IPROTO_TCP | ||
528 | * @bpf_socket: pointer to bpf_socket | ||
529 | * @level: SOL_SOCKET or IPROTO_TCP | ||
530 | * @optname: option name | ||
531 | * @optval: pointer to option value | ||
532 | * @optlen: length of optval in byes | ||
533 | * Return: 0 or negative error | ||
534 | * | ||
535 | * int bpf_skb_adjust_room(skb, len_diff, mode, flags) | ||
536 | * Grow or shrink room in sk_buff. | ||
537 | * @skb: pointer to skb | ||
538 | * @len_diff: (signed) amount of room to grow/shrink | ||
539 | * @mode: operation mode (enum bpf_adj_room_mode) | ||
540 | * @flags: reserved for future use | ||
541 | * Return: 0 on success or negative error code | ||
486 | */ | 542 | */ |
487 | #define __BPF_FUNC_MAPPER(FN) \ | 543 | #define __BPF_FUNC_MAPPER(FN) \ |
488 | FN(unspec), \ | 544 | FN(unspec), \ |
@@ -532,7 +588,10 @@ union bpf_attr { | |||
532 | FN(xdp_adjust_head), \ | 588 | FN(xdp_adjust_head), \ |
533 | FN(probe_read_str), \ | 589 | FN(probe_read_str), \ |
534 | FN(get_socket_cookie), \ | 590 | FN(get_socket_cookie), \ |
535 | FN(get_socket_uid), | 591 | FN(get_socket_uid), \ |
592 | FN(set_hash), \ | ||
593 | FN(setsockopt), \ | ||
594 | FN(skb_adjust_room), | ||
536 | 595 | ||
537 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 596 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
538 | * function eBPF program intends to call | 597 | * function eBPF program intends to call |
@@ -582,6 +641,11 @@ enum bpf_func_id { | |||
582 | /* BPF_FUNC_perf_event_output for sk_buff input context. */ | 641 | /* BPF_FUNC_perf_event_output for sk_buff input context. */ |
583 | #define BPF_F_CTXLEN_MASK (0xfffffULL << 32) | 642 | #define BPF_F_CTXLEN_MASK (0xfffffULL << 32) |
584 | 643 | ||
644 | /* Mode for BPF_FUNC_skb_adjust_room helper. */ | ||
645 | enum bpf_adj_room_mode { | ||
646 | BPF_ADJ_ROOM_NET_OPTS, | ||
647 | }; | ||
648 | |||
585 | /* user accessible mirror of in-kernel sk_buff. | 649 | /* user accessible mirror of in-kernel sk_buff. |
586 | * new fields can only be added to the end of this structure | 650 | * new fields can only be added to the end of this structure |
587 | */ | 651 | */ |
@@ -663,4 +727,75 @@ struct xdp_md { | |||
663 | __u32 data_end; | 727 | __u32 data_end; |
664 | }; | 728 | }; |
665 | 729 | ||
730 | #define BPF_TAG_SIZE 8 | ||
731 | |||
732 | struct bpf_prog_info { | ||
733 | __u32 type; | ||
734 | __u32 id; | ||
735 | __u8 tag[BPF_TAG_SIZE]; | ||
736 | __u32 jited_prog_len; | ||
737 | __u32 xlated_prog_len; | ||
738 | __aligned_u64 jited_prog_insns; | ||
739 | __aligned_u64 xlated_prog_insns; | ||
740 | } __attribute__((aligned(8))); | ||
741 | |||
742 | struct bpf_map_info { | ||
743 | __u32 type; | ||
744 | __u32 id; | ||
745 | __u32 key_size; | ||
746 | __u32 value_size; | ||
747 | __u32 max_entries; | ||
748 | __u32 map_flags; | ||
749 | } __attribute__((aligned(8))); | ||
750 | |||
751 | /* User bpf_sock_ops struct to access socket values and specify request ops | ||
752 | * and their replies. | ||
753 | * New fields can only be added at the end of this structure | ||
754 | */ | ||
755 | struct bpf_sock_ops { | ||
756 | __u32 op; | ||
757 | union { | ||
758 | __u32 reply; | ||
759 | __u32 replylong[4]; | ||
760 | }; | ||
761 | __u32 family; | ||
762 | __u32 remote_ip4; | ||
763 | __u32 local_ip4; | ||
764 | __u32 remote_ip6[4]; | ||
765 | __u32 local_ip6[4]; | ||
766 | __u32 remote_port; | ||
767 | __u32 local_port; | ||
768 | }; | ||
769 | |||
770 | /* List of known BPF sock_ops operators. | ||
771 | * New entries can only be added at the end | ||
772 | */ | ||
773 | enum { | ||
774 | BPF_SOCK_OPS_VOID, | ||
775 | BPF_SOCK_OPS_TIMEOUT_INIT, /* Should return SYN-RTO value to use or | ||
776 | * -1 if default value should be used | ||
777 | */ | ||
778 | BPF_SOCK_OPS_RWND_INIT, /* Should return initial advertized | ||
779 | * window (in packets) or -1 if default | ||
780 | * value should be used | ||
781 | */ | ||
782 | BPF_SOCK_OPS_TCP_CONNECT_CB, /* Calls BPF program right before an | ||
783 | * active connection is initialized | ||
784 | */ | ||
785 | BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB, /* Calls BPF program when an | ||
786 | * active connection is | ||
787 | * established | ||
788 | */ | ||
789 | BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, /* Calls BPF program when a | ||
790 | * passive connection is | ||
791 | * established | ||
792 | */ | ||
793 | BPF_SOCK_OPS_NEEDS_ECN, /* If connection's congestion control | ||
794 | * needs ECN | ||
795 | */ | ||
796 | }; | ||
797 | |||
798 | #define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ | ||
799 | #define TCP_BPF_SNDCWND_CLAMP 1002 /* Set sndcwnd_clamp */ | ||
800 | |||
666 | #endif /* _UAPI__LINUX_BPF_H__ */ | 801 | #endif /* _UAPI__LINUX_BPF_H__ */ |
diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h index d538897b8e08..17b10304c393 100644 --- a/tools/include/uapi/linux/stat.h +++ b/tools/include/uapi/linux/stat.h | |||
@@ -48,17 +48,13 @@ | |||
48 | * tv_sec holds the number of seconds before (negative) or after (positive) | 48 | * tv_sec holds the number of seconds before (negative) or after (positive) |
49 | * 00:00:00 1st January 1970 UTC. | 49 | * 00:00:00 1st January 1970 UTC. |
50 | * | 50 | * |
51 | * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is | 51 | * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time. |
52 | * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time. | ||
53 | * | ||
54 | * Note that if both tv_sec and tv_nsec are non-zero, then the two values must | ||
55 | * either be both positive or both negative. | ||
56 | * | 52 | * |
57 | * __reserved is held in case we need a yet finer resolution. | 53 | * __reserved is held in case we need a yet finer resolution. |
58 | */ | 54 | */ |
59 | struct statx_timestamp { | 55 | struct statx_timestamp { |
60 | __s64 tv_sec; | 56 | __s64 tv_sec; |
61 | __s32 tv_nsec; | 57 | __u32 tv_nsec; |
62 | __s32 __reserved; | 58 | __s32 __reserved; |
63 | }; | 59 | }; |
64 | 60 | ||
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 8f74ed8e7237..dd8f00cfb8b4 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat | |||
@@ -295,114 +295,6 @@ class ArchS390(Arch): | |||
295 | ARCH = Arch.get_arch() | 295 | ARCH = Arch.get_arch() |
296 | 296 | ||
297 | 297 | ||
298 | def walkdir(path): | ||
299 | """Returns os.walk() data for specified directory. | ||
300 | |||
301 | As it is only a wrapper it returns the same 3-tuple of (dirpath, | ||
302 | dirnames, filenames). | ||
303 | """ | ||
304 | return next(os.walk(path)) | ||
305 | |||
306 | |||
307 | def parse_int_list(list_string): | ||
308 | """Returns an int list from a string of comma separated integers and | ||
309 | integer ranges.""" | ||
310 | integers = [] | ||
311 | members = list_string.split(',') | ||
312 | |||
313 | for member in members: | ||
314 | if '-' not in member: | ||
315 | integers.append(int(member)) | ||
316 | else: | ||
317 | int_range = member.split('-') | ||
318 | integers.extend(range(int(int_range[0]), | ||
319 | int(int_range[1]) + 1)) | ||
320 | |||
321 | return integers | ||
322 | |||
323 | |||
324 | def get_pid_from_gname(gname): | ||
325 | """Fuzzy function to convert guest name to QEMU process pid. | ||
326 | |||
327 | Returns a list of potential pids, can be empty if no match found. | ||
328 | Throws an exception on processing errors. | ||
329 | |||
330 | """ | ||
331 | pids = [] | ||
332 | try: | ||
333 | child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'], | ||
334 | stdout=subprocess.PIPE) | ||
335 | except: | ||
336 | raise Exception | ||
337 | for line in child.stdout: | ||
338 | line = line.lstrip().split(' ', 1) | ||
339 | # perform a sanity check before calling the more expensive | ||
340 | # function to possibly extract the guest name | ||
341 | if ' -name ' in line[1] and gname == get_gname_from_pid(line[0]): | ||
342 | pids.append(int(line[0])) | ||
343 | child.stdout.close() | ||
344 | |||
345 | return pids | ||
346 | |||
347 | |||
348 | def get_gname_from_pid(pid): | ||
349 | """Returns the guest name for a QEMU process pid. | ||
350 | |||
351 | Extracts the guest name from the QEMU comma line by processing the '-name' | ||
352 | option. Will also handle names specified out of sequence. | ||
353 | |||
354 | """ | ||
355 | name = '' | ||
356 | try: | ||
357 | line = open('/proc/{}/cmdline'.format(pid), 'rb').read().split('\0') | ||
358 | parms = line[line.index('-name') + 1].split(',') | ||
359 | while '' in parms: | ||
360 | # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results in | ||
361 | # ['foo', '', 'bar'], which we revert here | ||
362 | idx = parms.index('') | ||
363 | parms[idx - 1] += ',' + parms[idx + 1] | ||
364 | del parms[idx:idx+2] | ||
365 | # the '-name' switch allows for two ways to specify the guest name, | ||
366 | # where the plain name overrides the name specified via 'guest=' | ||
367 | for arg in parms: | ||
368 | if '=' not in arg: | ||
369 | name = arg | ||
370 | break | ||
371 | if arg[:6] == 'guest=': | ||
372 | name = arg[6:] | ||
373 | except (ValueError, IOError, IndexError): | ||
374 | pass | ||
375 | |||
376 | return name | ||
377 | |||
378 | |||
379 | def get_online_cpus(): | ||
380 | """Returns a list of cpu id integers.""" | ||
381 | with open('/sys/devices/system/cpu/online') as cpu_list: | ||
382 | cpu_string = cpu_list.readline() | ||
383 | return parse_int_list(cpu_string) | ||
384 | |||
385 | |||
386 | def get_filters(): | ||
387 | """Returns a dict of trace events, their filter ids and | ||
388 | the values that can be filtered. | ||
389 | |||
390 | Trace events can be filtered for special values by setting a | ||
391 | filter string via an ioctl. The string normally has the format | ||
392 | identifier==value. For each filter a new event will be created, to | ||
393 | be able to distinguish the events. | ||
394 | |||
395 | """ | ||
396 | filters = {} | ||
397 | filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) | ||
398 | if ARCH.exit_reasons: | ||
399 | filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) | ||
400 | return filters | ||
401 | |||
402 | libc = ctypes.CDLL('libc.so.6', use_errno=True) | ||
403 | syscall = libc.syscall | ||
404 | |||
405 | |||
406 | class perf_event_attr(ctypes.Structure): | 298 | class perf_event_attr(ctypes.Structure): |
407 | """Struct that holds the necessary data to set up a trace event. | 299 | """Struct that holds the necessary data to set up a trace event. |
408 | 300 | ||
@@ -432,25 +324,6 @@ class perf_event_attr(ctypes.Structure): | |||
432 | self.read_format = PERF_FORMAT_GROUP | 324 | self.read_format = PERF_FORMAT_GROUP |
433 | 325 | ||
434 | 326 | ||
435 | def perf_event_open(attr, pid, cpu, group_fd, flags): | ||
436 | """Wrapper for the sys_perf_evt_open() syscall. | ||
437 | |||
438 | Used to set up performance events, returns a file descriptor or -1 | ||
439 | on error. | ||
440 | |||
441 | Attributes are: | ||
442 | - syscall number | ||
443 | - struct perf_event_attr * | ||
444 | - pid or -1 to monitor all pids | ||
445 | - cpu number or -1 to monitor all cpus | ||
446 | - The file descriptor of the group leader or -1 to create a group. | ||
447 | - flags | ||
448 | |||
449 | """ | ||
450 | return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), | ||
451 | ctypes.c_int(pid), ctypes.c_int(cpu), | ||
452 | ctypes.c_int(group_fd), ctypes.c_long(flags)) | ||
453 | |||
454 | PERF_TYPE_TRACEPOINT = 2 | 327 | PERF_TYPE_TRACEPOINT = 2 |
455 | PERF_FORMAT_GROUP = 1 << 3 | 328 | PERF_FORMAT_GROUP = 1 << 3 |
456 | 329 | ||
@@ -495,6 +368,8 @@ class Event(object): | |||
495 | """Represents a performance event and manages its life cycle.""" | 368 | """Represents a performance event and manages its life cycle.""" |
496 | def __init__(self, name, group, trace_cpu, trace_pid, trace_point, | 369 | def __init__(self, name, group, trace_cpu, trace_pid, trace_point, |
497 | trace_filter, trace_set='kvm'): | 370 | trace_filter, trace_set='kvm'): |
371 | self.libc = ctypes.CDLL('libc.so.6', use_errno=True) | ||
372 | self.syscall = self.libc.syscall | ||
498 | self.name = name | 373 | self.name = name |
499 | self.fd = None | 374 | self.fd = None |
500 | self.setup_event(group, trace_cpu, trace_pid, trace_point, | 375 | self.setup_event(group, trace_cpu, trace_pid, trace_point, |
@@ -511,6 +386,25 @@ class Event(object): | |||
511 | if self.fd: | 386 | if self.fd: |
512 | os.close(self.fd) | 387 | os.close(self.fd) |
513 | 388 | ||
389 | def perf_event_open(self, attr, pid, cpu, group_fd, flags): | ||
390 | """Wrapper for the sys_perf_evt_open() syscall. | ||
391 | |||
392 | Used to set up performance events, returns a file descriptor or -1 | ||
393 | on error. | ||
394 | |||
395 | Attributes are: | ||
396 | - syscall number | ||
397 | - struct perf_event_attr * | ||
398 | - pid or -1 to monitor all pids | ||
399 | - cpu number or -1 to monitor all cpus | ||
400 | - The file descriptor of the group leader or -1 to create a group. | ||
401 | - flags | ||
402 | |||
403 | """ | ||
404 | return self.syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), | ||
405 | ctypes.c_int(pid), ctypes.c_int(cpu), | ||
406 | ctypes.c_int(group_fd), ctypes.c_long(flags)) | ||
407 | |||
514 | def setup_event_attribute(self, trace_set, trace_point): | 408 | def setup_event_attribute(self, trace_set, trace_point): |
515 | """Returns an initialized ctype perf_event_attr struct.""" | 409 | """Returns an initialized ctype perf_event_attr struct.""" |
516 | 410 | ||
@@ -539,8 +433,8 @@ class Event(object): | |||
539 | if group.events: | 433 | if group.events: |
540 | group_leader = group.events[0].fd | 434 | group_leader = group.events[0].fd |
541 | 435 | ||
542 | fd = perf_event_open(event_attr, trace_pid, | 436 | fd = self.perf_event_open(event_attr, trace_pid, |
543 | trace_cpu, group_leader, 0) | 437 | trace_cpu, group_leader, 0) |
544 | if fd == -1: | 438 | if fd == -1: |
545 | err = ctypes.get_errno() | 439 | err = ctypes.get_errno() |
546 | raise OSError(err, os.strerror(err), | 440 | raise OSError(err, os.strerror(err), |
@@ -575,17 +469,53 @@ class Event(object): | |||
575 | fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) | 469 | fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) |
576 | 470 | ||
577 | 471 | ||
578 | class TracepointProvider(object): | 472 | class Provider(object): |
473 | """Encapsulates functionalities used by all providers.""" | ||
474 | @staticmethod | ||
475 | def is_field_wanted(fields_filter, field): | ||
476 | """Indicate whether field is valid according to fields_filter.""" | ||
477 | if not fields_filter: | ||
478 | return True | ||
479 | return re.match(fields_filter, field) is not None | ||
480 | |||
481 | @staticmethod | ||
482 | def walkdir(path): | ||
483 | """Returns os.walk() data for specified directory. | ||
484 | |||
485 | As it is only a wrapper it returns the same 3-tuple of (dirpath, | ||
486 | dirnames, filenames). | ||
487 | """ | ||
488 | return next(os.walk(path)) | ||
489 | |||
490 | |||
491 | class TracepointProvider(Provider): | ||
579 | """Data provider for the stats class. | 492 | """Data provider for the stats class. |
580 | 493 | ||
581 | Manages the events/groups from which it acquires its data. | 494 | Manages the events/groups from which it acquires its data. |
582 | 495 | ||
583 | """ | 496 | """ |
584 | def __init__(self): | 497 | def __init__(self, pid, fields_filter): |
585 | self.group_leaders = [] | 498 | self.group_leaders = [] |
586 | self.filters = get_filters() | 499 | self.filters = self.get_filters() |
587 | self._fields = self.get_available_fields() | 500 | self.update_fields(fields_filter) |
588 | self._pid = 0 | 501 | self.pid = pid |
502 | |||
503 | @staticmethod | ||
504 | def get_filters(): | ||
505 | """Returns a dict of trace events, their filter ids and | ||
506 | the values that can be filtered. | ||
507 | |||
508 | Trace events can be filtered for special values by setting a | ||
509 | filter string via an ioctl. The string normally has the format | ||
510 | identifier==value. For each filter a new event will be created, to | ||
511 | be able to distinguish the events. | ||
512 | |||
513 | """ | ||
514 | filters = {} | ||
515 | filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) | ||
516 | if ARCH.exit_reasons: | ||
517 | filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) | ||
518 | return filters | ||
589 | 519 | ||
590 | def get_available_fields(self): | 520 | def get_available_fields(self): |
591 | """Returns a list of available event's of format 'event name(filter | 521 | """Returns a list of available event's of format 'event name(filter |
@@ -603,7 +533,7 @@ class TracepointProvider(object): | |||
603 | 533 | ||
604 | """ | 534 | """ |
605 | path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') | 535 | path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') |
606 | fields = walkdir(path)[1] | 536 | fields = self.walkdir(path)[1] |
607 | extra = [] | 537 | extra = [] |
608 | for field in fields: | 538 | for field in fields: |
609 | if field in self.filters: | 539 | if field in self.filters: |
@@ -613,6 +543,34 @@ class TracepointProvider(object): | |||
613 | fields += extra | 543 | fields += extra |
614 | return fields | 544 | return fields |
615 | 545 | ||
546 | def update_fields(self, fields_filter): | ||
547 | """Refresh fields, applying fields_filter""" | ||
548 | self._fields = [field for field in self.get_available_fields() | ||
549 | if self.is_field_wanted(fields_filter, field)] | ||
550 | |||
551 | @staticmethod | ||
552 | def get_online_cpus(): | ||
553 | """Returns a list of cpu id integers.""" | ||
554 | def parse_int_list(list_string): | ||
555 | """Returns an int list from a string of comma separated integers and | ||
556 | integer ranges.""" | ||
557 | integers = [] | ||
558 | members = list_string.split(',') | ||
559 | |||
560 | for member in members: | ||
561 | if '-' not in member: | ||
562 | integers.append(int(member)) | ||
563 | else: | ||
564 | int_range = member.split('-') | ||
565 | integers.extend(range(int(int_range[0]), | ||
566 | int(int_range[1]) + 1)) | ||
567 | |||
568 | return integers | ||
569 | |||
570 | with open('/sys/devices/system/cpu/online') as cpu_list: | ||
571 | cpu_string = cpu_list.readline() | ||
572 | return parse_int_list(cpu_string) | ||
573 | |||
616 | def setup_traces(self): | 574 | def setup_traces(self): |
617 | """Creates all event and group objects needed to be able to retrieve | 575 | """Creates all event and group objects needed to be able to retrieve |
618 | data.""" | 576 | data.""" |
@@ -621,9 +579,9 @@ class TracepointProvider(object): | |||
621 | # Fetch list of all threads of the monitored pid, as qemu | 579 | # Fetch list of all threads of the monitored pid, as qemu |
622 | # starts a thread for each vcpu. | 580 | # starts a thread for each vcpu. |
623 | path = os.path.join('/proc', str(self._pid), 'task') | 581 | path = os.path.join('/proc', str(self._pid), 'task') |
624 | groupids = walkdir(path)[1] | 582 | groupids = self.walkdir(path)[1] |
625 | else: | 583 | else: |
626 | groupids = get_online_cpus() | 584 | groupids = self.get_online_cpus() |
627 | 585 | ||
628 | # The constant is needed as a buffer for python libs, std | 586 | # The constant is needed as a buffer for python libs, std |
629 | # streams and other files that the script opens. | 587 | # streams and other files that the script opens. |
@@ -671,9 +629,6 @@ class TracepointProvider(object): | |||
671 | 629 | ||
672 | self.group_leaders.append(group) | 630 | self.group_leaders.append(group) |
673 | 631 | ||
674 | def available_fields(self): | ||
675 | return self.get_available_fields() | ||
676 | |||
677 | @property | 632 | @property |
678 | def fields(self): | 633 | def fields(self): |
679 | return self._fields | 634 | return self._fields |
@@ -707,7 +662,7 @@ class TracepointProvider(object): | |||
707 | self.setup_traces() | 662 | self.setup_traces() |
708 | self.fields = self._fields | 663 | self.fields = self._fields |
709 | 664 | ||
710 | def read(self): | 665 | def read(self, by_guest=0): |
711 | """Returns 'event name: current value' for all enabled events.""" | 666 | """Returns 'event name: current value' for all enabled events.""" |
712 | ret = defaultdict(int) | 667 | ret = defaultdict(int) |
713 | for group in self.group_leaders: | 668 | for group in self.group_leaders: |
@@ -723,16 +678,17 @@ class TracepointProvider(object): | |||
723 | event.reset() | 678 | event.reset() |
724 | 679 | ||
725 | 680 | ||
726 | class DebugfsProvider(object): | 681 | class DebugfsProvider(Provider): |
727 | """Provides data from the files that KVM creates in the kvm debugfs | 682 | """Provides data from the files that KVM creates in the kvm debugfs |
728 | folder.""" | 683 | folder.""" |
729 | def __init__(self): | 684 | def __init__(self, pid, fields_filter, include_past): |
730 | self._fields = self.get_available_fields() | 685 | self.update_fields(fields_filter) |
731 | self._baseline = {} | 686 | self._baseline = {} |
732 | self._pid = 0 | ||
733 | self.do_read = True | 687 | self.do_read = True |
734 | self.paths = [] | 688 | self.paths = [] |
735 | self.reset() | 689 | self.pid = pid |
690 | if include_past: | ||
691 | self.restore() | ||
736 | 692 | ||
737 | def get_available_fields(self): | 693 | def get_available_fields(self): |
738 | """"Returns a list of available fields. | 694 | """"Returns a list of available fields. |
@@ -740,7 +696,12 @@ class DebugfsProvider(object): | |||
740 | The fields are all available KVM debugfs files | 696 | The fields are all available KVM debugfs files |
741 | 697 | ||
742 | """ | 698 | """ |
743 | return walkdir(PATH_DEBUGFS_KVM)[2] | 699 | return self.walkdir(PATH_DEBUGFS_KVM)[2] |
700 | |||
701 | def update_fields(self, fields_filter): | ||
702 | """Refresh fields, applying fields_filter""" | ||
703 | self._fields = [field for field in self.get_available_fields() | ||
704 | if self.is_field_wanted(fields_filter, field)] | ||
744 | 705 | ||
745 | @property | 706 | @property |
746 | def fields(self): | 707 | def fields(self): |
@@ -757,10 +718,9 @@ class DebugfsProvider(object): | |||
757 | 718 | ||
758 | @pid.setter | 719 | @pid.setter |
759 | def pid(self, pid): | 720 | def pid(self, pid): |
721 | self._pid = pid | ||
760 | if pid != 0: | 722 | if pid != 0: |
761 | self._pid = pid | 723 | vms = self.walkdir(PATH_DEBUGFS_KVM)[1] |
762 | |||
763 | vms = walkdir(PATH_DEBUGFS_KVM)[1] | ||
764 | if len(vms) == 0: | 724 | if len(vms) == 0: |
765 | self.do_read = False | 725 | self.do_read = False |
766 | 726 | ||
@@ -771,8 +731,15 @@ class DebugfsProvider(object): | |||
771 | self.do_read = True | 731 | self.do_read = True |
772 | self.reset() | 732 | self.reset() |
773 | 733 | ||
774 | def read(self, reset=0): | 734 | def read(self, reset=0, by_guest=0): |
775 | """Returns a dict with format:'file name / field -> current value'.""" | 735 | """Returns a dict with format:'file name / field -> current value'. |
736 | |||
737 | Parameter 'reset': | ||
738 | 0 plain read | ||
739 | 1 reset field counts to 0 | ||
740 | 2 restore the original field counts | ||
741 | |||
742 | """ | ||
776 | results = {} | 743 | results = {} |
777 | 744 | ||
778 | # If no debugfs filtering support is available, then don't read. | 745 | # If no debugfs filtering support is available, then don't read. |
@@ -789,12 +756,22 @@ class DebugfsProvider(object): | |||
789 | for field in self._fields: | 756 | for field in self._fields: |
790 | value = self.read_field(field, path) | 757 | value = self.read_field(field, path) |
791 | key = path + field | 758 | key = path + field |
792 | if reset: | 759 | if reset == 1: |
793 | self._baseline[key] = value | 760 | self._baseline[key] = value |
761 | if reset == 2: | ||
762 | self._baseline[key] = 0 | ||
794 | if self._baseline.get(key, -1) == -1: | 763 | if self._baseline.get(key, -1) == -1: |
795 | self._baseline[key] = value | 764 | self._baseline[key] = value |
796 | results[field] = (results.get(field, 0) + value - | 765 | increment = (results.get(field, 0) + value - |
797 | self._baseline.get(key, 0)) | 766 | self._baseline.get(key, 0)) |
767 | if by_guest: | ||
768 | pid = key.split('-')[0] | ||
769 | if pid in results: | ||
770 | results[pid] += increment | ||
771 | else: | ||
772 | results[pid] = increment | ||
773 | else: | ||
774 | results[field] = increment | ||
798 | 775 | ||
799 | return results | 776 | return results |
800 | 777 | ||
@@ -813,6 +790,11 @@ class DebugfsProvider(object): | |||
813 | self._baseline = {} | 790 | self._baseline = {} |
814 | self.read(1) | 791 | self.read(1) |
815 | 792 | ||
793 | def restore(self): | ||
794 | """Reset field counters""" | ||
795 | self._baseline = {} | ||
796 | self.read(2) | ||
797 | |||
816 | 798 | ||
817 | class Stats(object): | 799 | class Stats(object): |
818 | """Manages the data providers and the data they provide. | 800 | """Manages the data providers and the data they provide. |
@@ -821,33 +803,32 @@ class Stats(object): | |||
821 | provider data. | 803 | provider data. |
822 | 804 | ||
823 | """ | 805 | """ |
824 | def __init__(self, providers, pid, fields=None): | 806 | def __init__(self, options): |
825 | self.providers = providers | 807 | self.providers = self.get_providers(options) |
826 | self._pid_filter = pid | 808 | self._pid_filter = options.pid |
827 | self._fields_filter = fields | 809 | self._fields_filter = options.fields |
828 | self.values = {} | 810 | self.values = {} |
829 | self.update_provider_pid() | 811 | |
830 | self.update_provider_filters() | 812 | @staticmethod |
813 | def get_providers(options): | ||
814 | """Returns a list of data providers depending on the passed options.""" | ||
815 | providers = [] | ||
816 | |||
817 | if options.debugfs: | ||
818 | providers.append(DebugfsProvider(options.pid, options.fields, | ||
819 | options.dbgfs_include_past)) | ||
820 | if options.tracepoints or not providers: | ||
821 | providers.append(TracepointProvider(options.pid, options.fields)) | ||
822 | |||
823 | return providers | ||
831 | 824 | ||
832 | def update_provider_filters(self): | 825 | def update_provider_filters(self): |
833 | """Propagates fields filters to providers.""" | 826 | """Propagates fields filters to providers.""" |
834 | def wanted(key): | ||
835 | if not self._fields_filter: | ||
836 | return True | ||
837 | return re.match(self._fields_filter, key) is not None | ||
838 | |||
839 | # As we reset the counters when updating the fields we can | 827 | # As we reset the counters when updating the fields we can |
840 | # also clear the cache of old values. | 828 | # also clear the cache of old values. |
841 | self.values = {} | 829 | self.values = {} |
842 | for provider in self.providers: | 830 | for provider in self.providers: |
843 | provider_fields = [key for key in provider.get_available_fields() | 831 | provider.update_fields(self._fields_filter) |
844 | if wanted(key)] | ||
845 | provider.fields = provider_fields | ||
846 | |||
847 | def update_provider_pid(self): | ||
848 | """Propagates pid filters to providers.""" | ||
849 | for provider in self.providers: | ||
850 | provider.pid = self._pid_filter | ||
851 | 832 | ||
852 | def reset(self): | 833 | def reset(self): |
853 | self.values = {} | 834 | self.values = {} |
@@ -873,27 +854,52 @@ class Stats(object): | |||
873 | if pid != self._pid_filter: | 854 | if pid != self._pid_filter: |
874 | self._pid_filter = pid | 855 | self._pid_filter = pid |
875 | self.values = {} | 856 | self.values = {} |
876 | self.update_provider_pid() | 857 | for provider in self.providers: |
858 | provider.pid = self._pid_filter | ||
877 | 859 | ||
878 | def get(self): | 860 | def get(self, by_guest=0): |
879 | """Returns a dict with field -> (value, delta to last value) of all | 861 | """Returns a dict with field -> (value, delta to last value) of all |
880 | provider data.""" | 862 | provider data.""" |
881 | for provider in self.providers: | 863 | for provider in self.providers: |
882 | new = provider.read() | 864 | new = provider.read(by_guest=by_guest) |
883 | for key in provider.fields: | 865 | for key in new if by_guest else provider.fields: |
884 | oldval = self.values.get(key, (0, 0))[0] | 866 | oldval = self.values.get(key, (0, 0))[0] |
885 | newval = new.get(key, 0) | 867 | newval = new.get(key, 0) |
886 | newdelta = newval - oldval | 868 | newdelta = newval - oldval |
887 | self.values[key] = (newval, newdelta) | 869 | self.values[key] = (newval, newdelta) |
888 | return self.values | 870 | return self.values |
889 | 871 | ||
890 | LABEL_WIDTH = 40 | 872 | def toggle_display_guests(self, to_pid): |
891 | NUMBER_WIDTH = 10 | 873 | """Toggle between collection of stats by individual event and by |
892 | DELAY_INITIAL = 0.25 | 874 | guest pid |
893 | DELAY_REGULAR = 3.0 | 875 | |
876 | Events reported by DebugfsProvider change when switching to/from | ||
877 | reading by guest values. Hence we have to remove the excess event | ||
878 | names from self.values. | ||
879 | |||
880 | """ | ||
881 | if any(isinstance(ins, TracepointProvider) for ins in self.providers): | ||
882 | return 1 | ||
883 | if to_pid: | ||
884 | for provider in self.providers: | ||
885 | if isinstance(provider, DebugfsProvider): | ||
886 | for key in provider.fields: | ||
887 | if key in self.values.keys(): | ||
888 | del self.values[key] | ||
889 | else: | ||
890 | oldvals = self.values.copy() | ||
891 | for key in oldvals: | ||
892 | if key.isdigit(): | ||
893 | del self.values[key] | ||
894 | # Update oldval (see get()) | ||
895 | self.get(to_pid) | ||
896 | return 0 | ||
897 | |||
898 | DELAY_DEFAULT = 3.0 | ||
894 | MAX_GUEST_NAME_LEN = 48 | 899 | MAX_GUEST_NAME_LEN = 48 |
895 | MAX_REGEX_LEN = 44 | 900 | MAX_REGEX_LEN = 44 |
896 | DEFAULT_REGEX = r'^[^\(]*$' | 901 | DEFAULT_REGEX = r'^[^\(]*$' |
902 | SORT_DEFAULT = 0 | ||
897 | 903 | ||
898 | 904 | ||
899 | class Tui(object): | 905 | class Tui(object): |
@@ -901,7 +907,10 @@ class Tui(object): | |||
901 | def __init__(self, stats): | 907 | def __init__(self, stats): |
902 | self.stats = stats | 908 | self.stats = stats |
903 | self.screen = None | 909 | self.screen = None |
904 | self.update_drilldown() | 910 | self._delay_initial = 0.25 |
911 | self._delay_regular = DELAY_DEFAULT | ||
912 | self._sorting = SORT_DEFAULT | ||
913 | self._display_guests = 0 | ||
905 | 914 | ||
906 | def __enter__(self): | 915 | def __enter__(self): |
907 | """Initialises curses for later use. Based on curses.wrapper | 916 | """Initialises curses for later use. Based on curses.wrapper |
@@ -929,7 +938,7 @@ class Tui(object): | |||
929 | return self | 938 | return self |
930 | 939 | ||
931 | def __exit__(self, *exception): | 940 | def __exit__(self, *exception): |
932 | """Resets the terminal to its normal state. Based on curses.wrappre | 941 | """Resets the terminal to its normal state. Based on curses.wrapper |
933 | implementation from the Python standard library.""" | 942 | implementation from the Python standard library.""" |
934 | if self.screen: | 943 | if self.screen: |
935 | self.screen.keypad(0) | 944 | self.screen.keypad(0) |
@@ -937,6 +946,86 @@ class Tui(object): | |||
937 | curses.nocbreak() | 946 | curses.nocbreak() |
938 | curses.endwin() | 947 | curses.endwin() |
939 | 948 | ||
949 | def get_all_gnames(self): | ||
950 | """Returns a list of (pid, gname) tuples of all running guests""" | ||
951 | res = [] | ||
952 | try: | ||
953 | child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'], | ||
954 | stdout=subprocess.PIPE) | ||
955 | except: | ||
956 | raise Exception | ||
957 | for line in child.stdout: | ||
958 | line = line.lstrip().split(' ', 1) | ||
959 | # perform a sanity check before calling the more expensive | ||
960 | # function to possibly extract the guest name | ||
961 | if ' -name ' in line[1]: | ||
962 | res.append((line[0], self.get_gname_from_pid(line[0]))) | ||
963 | child.stdout.close() | ||
964 | |||
965 | return res | ||
966 | |||
967 | def print_all_gnames(self, row): | ||
968 | """Print a list of all running guests along with their pids.""" | ||
969 | self.screen.addstr(row, 2, '%8s %-60s' % | ||
970 | ('Pid', 'Guest Name (fuzzy list, might be ' | ||
971 | 'inaccurate!)'), | ||
972 | curses.A_UNDERLINE) | ||
973 | row += 1 | ||
974 | try: | ||
975 | for line in self.get_all_gnames(): | ||
976 | self.screen.addstr(row, 2, '%8s %-60s' % (line[0], line[1])) | ||
977 | row += 1 | ||
978 | if row >= self.screen.getmaxyx()[0]: | ||
979 | break | ||
980 | except Exception: | ||
981 | self.screen.addstr(row + 1, 2, 'Not available') | ||
982 | |||
983 | def get_pid_from_gname(self, gname): | ||
984 | """Fuzzy function to convert guest name to QEMU process pid. | ||
985 | |||
986 | Returns a list of potential pids, can be empty if no match found. | ||
987 | Throws an exception on processing errors. | ||
988 | |||
989 | """ | ||
990 | pids = [] | ||
991 | for line in self.get_all_gnames(): | ||
992 | if gname == line[1]: | ||
993 | pids.append(int(line[0])) | ||
994 | |||
995 | return pids | ||
996 | |||
997 | @staticmethod | ||
998 | def get_gname_from_pid(pid): | ||
999 | """Returns the guest name for a QEMU process pid. | ||
1000 | |||
1001 | Extracts the guest name from the QEMU comma line by processing the | ||
1002 | '-name' option. Will also handle names specified out of sequence. | ||
1003 | |||
1004 | """ | ||
1005 | name = '' | ||
1006 | try: | ||
1007 | line = open('/proc/{}/cmdline' | ||
1008 | .format(pid), 'rb').read().split('\0') | ||
1009 | parms = line[line.index('-name') + 1].split(',') | ||
1010 | while '' in parms: | ||
1011 | # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results | ||
1012 | # in # ['foo', '', 'bar'], which we revert here | ||
1013 | idx = parms.index('') | ||
1014 | parms[idx - 1] += ',' + parms[idx + 1] | ||
1015 | del parms[idx:idx+2] | ||
1016 | # the '-name' switch allows for two ways to specify the guest name, | ||
1017 | # where the plain name overrides the name specified via 'guest=' | ||
1018 | for arg in parms: | ||
1019 | if '=' not in arg: | ||
1020 | name = arg | ||
1021 | break | ||
1022 | if arg[:6] == 'guest=': | ||
1023 | name = arg[6:] | ||
1024 | except (ValueError, IOError, IndexError): | ||
1025 | pass | ||
1026 | |||
1027 | return name | ||
1028 | |||
940 | def update_drilldown(self): | 1029 | def update_drilldown(self): |
941 | """Sets or removes a filter that only allows fields without braces.""" | 1030 | """Sets or removes a filter that only allows fields without braces.""" |
942 | if not self.stats.fields_filter: | 1031 | if not self.stats.fields_filter: |
@@ -954,7 +1043,7 @@ class Tui(object): | |||
954 | if pid is None: | 1043 | if pid is None: |
955 | pid = self.stats.pid_filter | 1044 | pid = self.stats.pid_filter |
956 | self.screen.erase() | 1045 | self.screen.erase() |
957 | gname = get_gname_from_pid(pid) | 1046 | gname = self.get_gname_from_pid(pid) |
958 | if gname: | 1047 | if gname: |
959 | gname = ('({})'.format(gname[:MAX_GUEST_NAME_LEN] + '...' | 1048 | gname = ('({})'.format(gname[:MAX_GUEST_NAME_LEN] + '...' |
960 | if len(gname) > MAX_GUEST_NAME_LEN | 1049 | if len(gname) > MAX_GUEST_NAME_LEN |
@@ -970,13 +1059,13 @@ class Tui(object): | |||
970 | if len(regex) > MAX_REGEX_LEN: | 1059 | if len(regex) > MAX_REGEX_LEN: |
971 | regex = regex[:MAX_REGEX_LEN] + '...' | 1060 | regex = regex[:MAX_REGEX_LEN] + '...' |
972 | self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) | 1061 | self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) |
973 | self.screen.addstr(2, 1, 'Event') | 1062 | if self._display_guests: |
974 | self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - | 1063 | col_name = 'Guest Name' |
975 | len('Total'), 'Total') | 1064 | else: |
976 | self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 - | 1065 | col_name = 'Event' |
977 | len('%Total'), '%Total') | 1066 | self.screen.addstr(2, 1, '%-40s %10s%7s %8s' % |
978 | self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 + 8 - | 1067 | (col_name, 'Total', '%Total', 'CurAvg/s'), |
979 | len('Current'), 'Current') | 1068 | curses.A_STANDOUT) |
980 | self.screen.addstr(4, 1, 'Collecting data...') | 1069 | self.screen.addstr(4, 1, 'Collecting data...') |
981 | self.screen.refresh() | 1070 | self.screen.refresh() |
982 | 1071 | ||
@@ -984,16 +1073,25 @@ class Tui(object): | |||
984 | row = 3 | 1073 | row = 3 |
985 | self.screen.move(row, 0) | 1074 | self.screen.move(row, 0) |
986 | self.screen.clrtobot() | 1075 | self.screen.clrtobot() |
987 | stats = self.stats.get() | 1076 | stats = self.stats.get(self._display_guests) |
988 | 1077 | ||
989 | def sortkey(x): | 1078 | def sortCurAvg(x): |
1079 | # sort by current events if available | ||
990 | if stats[x][1]: | 1080 | if stats[x][1]: |
991 | return (-stats[x][1], -stats[x][0]) | 1081 | return (-stats[x][1], -stats[x][0]) |
992 | else: | 1082 | else: |
993 | return (0, -stats[x][0]) | 1083 | return (0, -stats[x][0]) |
1084 | |||
1085 | def sortTotal(x): | ||
1086 | # sort by totals | ||
1087 | return (0, -stats[x][0]) | ||
994 | total = 0. | 1088 | total = 0. |
995 | for val in stats.values(): | 1089 | for val in stats.values(): |
996 | total += val[0] | 1090 | total += val[0] |
1091 | if self._sorting == SORT_DEFAULT: | ||
1092 | sortkey = sortCurAvg | ||
1093 | else: | ||
1094 | sortkey = sortTotal | ||
997 | for key in sorted(stats.keys(), key=sortkey): | 1095 | for key in sorted(stats.keys(), key=sortkey): |
998 | 1096 | ||
999 | if row >= self.screen.getmaxyx()[0]: | 1097 | if row >= self.screen.getmaxyx()[0]: |
@@ -1001,18 +1099,61 @@ class Tui(object): | |||
1001 | values = stats[key] | 1099 | values = stats[key] |
1002 | if not values[0] and not values[1]: | 1100 | if not values[0] and not values[1]: |
1003 | break | 1101 | break |
1004 | col = 1 | 1102 | if values[0] is not None: |
1005 | self.screen.addstr(row, col, key) | 1103 | cur = int(round(values[1] / sleeptime)) if values[1] else '' |
1006 | col += LABEL_WIDTH | 1104 | if self._display_guests: |
1007 | self.screen.addstr(row, col, '%10d' % (values[0],)) | 1105 | key = self.get_gname_from_pid(key) |
1008 | col += NUMBER_WIDTH | 1106 | self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % |
1009 | self.screen.addstr(row, col, '%7.1f' % (values[0] * 100 / total,)) | 1107 | (key, values[0], values[0] * 100 / total, |
1010 | col += 7 | 1108 | cur)) |
1011 | if values[1] is not None: | ||
1012 | self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) | ||
1013 | row += 1 | 1109 | row += 1 |
1110 | if row == 3: | ||
1111 | self.screen.addstr(4, 1, 'No matching events reported yet') | ||
1014 | self.screen.refresh() | 1112 | self.screen.refresh() |
1015 | 1113 | ||
1114 | def show_msg(self, text): | ||
1115 | """Display message centered text and exit on key press""" | ||
1116 | hint = 'Press any key to continue' | ||
1117 | curses.cbreak() | ||
1118 | self.screen.erase() | ||
1119 | (x, term_width) = self.screen.getmaxyx() | ||
1120 | row = 2 | ||
1121 | for line in text: | ||
1122 | start = (term_width - len(line)) / 2 | ||
1123 | self.screen.addstr(row, start, line) | ||
1124 | row += 1 | ||
1125 | self.screen.addstr(row + 1, (term_width - len(hint)) / 2, hint, | ||
1126 | curses.A_STANDOUT) | ||
1127 | self.screen.getkey() | ||
1128 | |||
1129 | def show_help_interactive(self): | ||
1130 | """Display help with list of interactive commands""" | ||
1131 | msg = (' b toggle events by guests (debugfs only, honors' | ||
1132 | ' filters)', | ||
1133 | ' c clear filter', | ||
1134 | ' f filter by regular expression', | ||
1135 | ' g filter by guest name', | ||
1136 | ' h display interactive commands reference', | ||
1137 | ' o toggle sorting order (Total vs CurAvg/s)', | ||
1138 | ' p filter by PID', | ||
1139 | ' q quit', | ||
1140 | ' r reset stats', | ||
1141 | ' s set update interval', | ||
1142 | ' x toggle reporting of stats for individual child trace' | ||
1143 | ' events', | ||
1144 | 'Any other key refreshes statistics immediately') | ||
1145 | curses.cbreak() | ||
1146 | self.screen.erase() | ||
1147 | self.screen.addstr(0, 0, "Interactive commands reference", | ||
1148 | curses.A_BOLD) | ||
1149 | self.screen.addstr(2, 0, "Press any key to exit", curses.A_STANDOUT) | ||
1150 | row = 4 | ||
1151 | for line in msg: | ||
1152 | self.screen.addstr(row, 0, line) | ||
1153 | row += 1 | ||
1154 | self.screen.getkey() | ||
1155 | self.refresh_header() | ||
1156 | |||
1016 | def show_filter_selection(self): | 1157 | def show_filter_selection(self): |
1017 | """Draws filter selection mask. | 1158 | """Draws filter selection mask. |
1018 | 1159 | ||
@@ -1059,6 +1200,7 @@ class Tui(object): | |||
1059 | 'This might limit the shown data to the trace ' | 1200 | 'This might limit the shown data to the trace ' |
1060 | 'statistics.') | 1201 | 'statistics.') |
1061 | self.screen.addstr(5, 0, msg) | 1202 | self.screen.addstr(5, 0, msg) |
1203 | self.print_all_gnames(7) | ||
1062 | 1204 | ||
1063 | curses.echo() | 1205 | curses.echo() |
1064 | self.screen.addstr(3, 0, "Pid [0 or pid]: ") | 1206 | self.screen.addstr(3, 0, "Pid [0 or pid]: ") |
@@ -1077,10 +1219,40 @@ class Tui(object): | |||
1077 | self.refresh_header(pid) | 1219 | self.refresh_header(pid) |
1078 | self.update_pid(pid) | 1220 | self.update_pid(pid) |
1079 | break | 1221 | break |
1080 | |||
1081 | except ValueError: | 1222 | except ValueError: |
1082 | msg = '"' + str(pid) + '": Not a valid pid' | 1223 | msg = '"' + str(pid) + '": Not a valid pid' |
1083 | continue | 1224 | |
1225 | def show_set_update_interval(self): | ||
1226 | """Draws update interval selection mask.""" | ||
1227 | msg = '' | ||
1228 | while True: | ||
1229 | self.screen.erase() | ||
1230 | self.screen.addstr(0, 0, 'Set update interval (defaults to %fs).' % | ||
1231 | DELAY_DEFAULT, curses.A_BOLD) | ||
1232 | self.screen.addstr(4, 0, msg) | ||
1233 | self.screen.addstr(2, 0, 'Change delay from %.1fs to ' % | ||
1234 | self._delay_regular) | ||
1235 | curses.echo() | ||
1236 | val = self.screen.getstr() | ||
1237 | curses.noecho() | ||
1238 | |||
1239 | try: | ||
1240 | if len(val) > 0: | ||
1241 | delay = float(val) | ||
1242 | if delay < 0.1: | ||
1243 | msg = '"' + str(val) + '": Value must be >=0.1' | ||
1244 | continue | ||
1245 | if delay > 25.5: | ||
1246 | msg = '"' + str(val) + '": Value must be <=25.5' | ||
1247 | continue | ||
1248 | else: | ||
1249 | delay = DELAY_DEFAULT | ||
1250 | self._delay_regular = delay | ||
1251 | break | ||
1252 | |||
1253 | except ValueError: | ||
1254 | msg = '"' + str(val) + '": Invalid value' | ||
1255 | self.refresh_header() | ||
1084 | 1256 | ||
1085 | def show_vm_selection_by_guest_name(self): | 1257 | def show_vm_selection_by_guest_name(self): |
1086 | """Draws guest selection mask. | 1258 | """Draws guest selection mask. |
@@ -1098,6 +1270,7 @@ class Tui(object): | |||
1098 | 'This might limit the shown data to the trace ' | 1270 | 'This might limit the shown data to the trace ' |
1099 | 'statistics.') | 1271 | 'statistics.') |
1100 | self.screen.addstr(5, 0, msg) | 1272 | self.screen.addstr(5, 0, msg) |
1273 | self.print_all_gnames(7) | ||
1101 | curses.echo() | 1274 | curses.echo() |
1102 | self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") | 1275 | self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") |
1103 | gname = self.screen.getstr() | 1276 | gname = self.screen.getstr() |
@@ -1110,7 +1283,7 @@ class Tui(object): | |||
1110 | else: | 1283 | else: |
1111 | pids = [] | 1284 | pids = [] |
1112 | try: | 1285 | try: |
1113 | pids = get_pid_from_gname(gname) | 1286 | pids = self.get_pid_from_gname(gname) |
1114 | except: | 1287 | except: |
1115 | msg = '"' + gname + '": Internal error while searching, ' \ | 1288 | msg = '"' + gname + '": Internal error while searching, ' \ |
1116 | 'use pid filter instead' | 1289 | 'use pid filter instead' |
@@ -1128,38 +1301,60 @@ class Tui(object): | |||
1128 | 1301 | ||
1129 | def show_stats(self): | 1302 | def show_stats(self): |
1130 | """Refreshes the screen and processes user input.""" | 1303 | """Refreshes the screen and processes user input.""" |
1131 | sleeptime = DELAY_INITIAL | 1304 | sleeptime = self._delay_initial |
1132 | self.refresh_header() | 1305 | self.refresh_header() |
1306 | start = 0.0 # result based on init value never appears on screen | ||
1133 | while True: | 1307 | while True: |
1134 | self.refresh_body(sleeptime) | 1308 | self.refresh_body(time.time() - start) |
1135 | curses.halfdelay(int(sleeptime * 10)) | 1309 | curses.halfdelay(int(sleeptime * 10)) |
1136 | sleeptime = DELAY_REGULAR | 1310 | start = time.time() |
1311 | sleeptime = self._delay_regular | ||
1137 | try: | 1312 | try: |
1138 | char = self.screen.getkey() | 1313 | char = self.screen.getkey() |
1139 | if char == 'x': | 1314 | if char == 'b': |
1315 | self._display_guests = not self._display_guests | ||
1316 | if self.stats.toggle_display_guests(self._display_guests): | ||
1317 | self.show_msg(['Command not available with tracepoints' | ||
1318 | ' enabled', 'Restart with debugfs only ' | ||
1319 | '(see option \'-d\') and try again!']) | ||
1320 | self._display_guests = not self._display_guests | ||
1140 | self.refresh_header() | 1321 | self.refresh_header() |
1141 | self.update_drilldown() | ||
1142 | sleeptime = DELAY_INITIAL | ||
1143 | if char == 'q': | ||
1144 | break | ||
1145 | if char == 'c': | 1322 | if char == 'c': |
1146 | self.stats.fields_filter = DEFAULT_REGEX | 1323 | self.stats.fields_filter = DEFAULT_REGEX |
1147 | self.refresh_header(0) | 1324 | self.refresh_header(0) |
1148 | self.update_pid(0) | 1325 | self.update_pid(0) |
1149 | sleeptime = DELAY_INITIAL | ||
1150 | if char == 'f': | 1326 | if char == 'f': |
1327 | curses.curs_set(1) | ||
1151 | self.show_filter_selection() | 1328 | self.show_filter_selection() |
1152 | sleeptime = DELAY_INITIAL | 1329 | curses.curs_set(0) |
1330 | sleeptime = self._delay_initial | ||
1153 | if char == 'g': | 1331 | if char == 'g': |
1332 | curses.curs_set(1) | ||
1154 | self.show_vm_selection_by_guest_name() | 1333 | self.show_vm_selection_by_guest_name() |
1155 | sleeptime = DELAY_INITIAL | 1334 | curses.curs_set(0) |
1335 | sleeptime = self._delay_initial | ||
1336 | if char == 'h': | ||
1337 | self.show_help_interactive() | ||
1338 | if char == 'o': | ||
1339 | self._sorting = not self._sorting | ||
1156 | if char == 'p': | 1340 | if char == 'p': |
1341 | curses.curs_set(1) | ||
1157 | self.show_vm_selection_by_pid() | 1342 | self.show_vm_selection_by_pid() |
1158 | sleeptime = DELAY_INITIAL | 1343 | curses.curs_set(0) |
1344 | sleeptime = self._delay_initial | ||
1345 | if char == 'q': | ||
1346 | break | ||
1159 | if char == 'r': | 1347 | if char == 'r': |
1160 | self.refresh_header() | ||
1161 | self.stats.reset() | 1348 | self.stats.reset() |
1162 | sleeptime = DELAY_INITIAL | 1349 | if char == 's': |
1350 | curses.curs_set(1) | ||
1351 | self.show_set_update_interval() | ||
1352 | curses.curs_set(0) | ||
1353 | sleeptime = self._delay_initial | ||
1354 | if char == 'x': | ||
1355 | self.update_drilldown() | ||
1356 | # prevents display of current values on next refresh | ||
1357 | self.stats.get() | ||
1163 | except KeyboardInterrupt: | 1358 | except KeyboardInterrupt: |
1164 | break | 1359 | break |
1165 | except curses.error: | 1360 | except curses.error: |
@@ -1227,13 +1422,17 @@ Requirements: | |||
1227 | the large number of files that are possibly opened. | 1422 | the large number of files that are possibly opened. |
1228 | 1423 | ||
1229 | Interactive Commands: | 1424 | Interactive Commands: |
1425 | b toggle events by guests (debugfs only, honors filters) | ||
1230 | c clear filter | 1426 | c clear filter |
1231 | f filter by regular expression | 1427 | f filter by regular expression |
1232 | g filter by guest name | 1428 | g filter by guest name |
1429 | h display interactive commands reference | ||
1430 | o toggle sorting order (Total vs CurAvg/s) | ||
1233 | p filter by PID | 1431 | p filter by PID |
1234 | q quit | 1432 | q quit |
1235 | x toggle reporting of stats for individual child trace events | ||
1236 | r reset stats | 1433 | r reset stats |
1434 | s set update interval | ||
1435 | x toggle reporting of stats for individual child trace events | ||
1237 | Press any other key to refresh statistics immediately. | 1436 | Press any other key to refresh statistics immediately. |
1238 | """ | 1437 | """ |
1239 | 1438 | ||
@@ -1246,7 +1445,7 @@ Press any other key to refresh statistics immediately. | |||
1246 | 1445 | ||
1247 | def cb_guest_to_pid(option, opt, val, parser): | 1446 | def cb_guest_to_pid(option, opt, val, parser): |
1248 | try: | 1447 | try: |
1249 | pids = get_pid_from_gname(val) | 1448 | pids = Tui.get_pid_from_gname(val) |
1250 | except: | 1449 | except: |
1251 | raise optparse.OptionValueError('Error while searching for guest ' | 1450 | raise optparse.OptionValueError('Error while searching for guest ' |
1252 | '"{}", use "-p" to specify a pid ' | 1451 | '"{}", use "-p" to specify a pid ' |
@@ -1268,6 +1467,13 @@ Press any other key to refresh statistics immediately. | |||
1268 | dest='once', | 1467 | dest='once', |
1269 | help='run in batch mode for one second', | 1468 | help='run in batch mode for one second', |
1270 | ) | 1469 | ) |
1470 | optparser.add_option('-i', '--debugfs-include-past', | ||
1471 | action='store_true', | ||
1472 | default=False, | ||
1473 | dest='dbgfs_include_past', | ||
1474 | help='include all available data on past events for ' | ||
1475 | 'debugfs', | ||
1476 | ) | ||
1271 | optparser.add_option('-l', '--log', | 1477 | optparser.add_option('-l', '--log', |
1272 | action='store_true', | 1478 | action='store_true', |
1273 | default=False, | 1479 | default=False, |
@@ -1288,7 +1494,7 @@ Press any other key to refresh statistics immediately. | |||
1288 | ) | 1494 | ) |
1289 | optparser.add_option('-f', '--fields', | 1495 | optparser.add_option('-f', '--fields', |
1290 | action='store', | 1496 | action='store', |
1291 | default=None, | 1497 | default=DEFAULT_REGEX, |
1292 | dest='fields', | 1498 | dest='fields', |
1293 | help='fields to display (regex)', | 1499 | help='fields to display (regex)', |
1294 | ) | 1500 | ) |
@@ -1311,20 +1517,6 @@ Press any other key to refresh statistics immediately. | |||
1311 | return options | 1517 | return options |
1312 | 1518 | ||
1313 | 1519 | ||
1314 | def get_providers(options): | ||
1315 | """Returns a list of data providers depending on the passed options.""" | ||
1316 | providers = [] | ||
1317 | |||
1318 | if options.tracepoints: | ||
1319 | providers.append(TracepointProvider()) | ||
1320 | if options.debugfs: | ||
1321 | providers.append(DebugfsProvider()) | ||
1322 | if len(providers) == 0: | ||
1323 | providers.append(TracepointProvider()) | ||
1324 | |||
1325 | return providers | ||
1326 | |||
1327 | |||
1328 | def check_access(options): | 1520 | def check_access(options): |
1329 | """Exits if the current user can't access all needed directories.""" | 1521 | """Exits if the current user can't access all needed directories.""" |
1330 | if not os.path.exists('/sys/kernel/debug'): | 1522 | if not os.path.exists('/sys/kernel/debug'): |
@@ -1365,8 +1557,7 @@ def main(): | |||
1365 | sys.stderr.write('Did you use a (unsupported) tid instead of a pid?\n') | 1557 | sys.stderr.write('Did you use a (unsupported) tid instead of a pid?\n') |
1366 | sys.exit('Specified pid does not exist.') | 1558 | sys.exit('Specified pid does not exist.') |
1367 | 1559 | ||
1368 | providers = get_providers(options) | 1560 | stats = Stats(options) |
1369 | stats = Stats(providers, options.pid, fields=options.fields) | ||
1370 | 1561 | ||
1371 | if options.log: | 1562 | if options.log: |
1372 | log(stats) | 1563 | log(stats) |
diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt index 109431bdc63c..e5cf836be8a1 100644 --- a/tools/kvm/kvm_stat/kvm_stat.txt +++ b/tools/kvm/kvm_stat/kvm_stat.txt | |||
@@ -29,18 +29,26 @@ meaning of events. | |||
29 | INTERACTIVE COMMANDS | 29 | INTERACTIVE COMMANDS |
30 | -------------------- | 30 | -------------------- |
31 | [horizontal] | 31 | [horizontal] |
32 | *b*:: toggle events by guests (debugfs only, honors filters) | ||
33 | |||
32 | *c*:: clear filter | 34 | *c*:: clear filter |
33 | 35 | ||
34 | *f*:: filter by regular expression | 36 | *f*:: filter by regular expression |
35 | 37 | ||
36 | *g*:: filter by guest name | 38 | *g*:: filter by guest name |
37 | 39 | ||
40 | *h*:: display interactive commands reference | ||
41 | |||
42 | *o*:: toggle sorting order (Total vs CurAvg/s) | ||
43 | |||
38 | *p*:: filter by PID | 44 | *p*:: filter by PID |
39 | 45 | ||
40 | *q*:: quit | 46 | *q*:: quit |
41 | 47 | ||
42 | *r*:: reset stats | 48 | *r*:: reset stats |
43 | 49 | ||
50 | *s*:: set update interval | ||
51 | |||
44 | *x*:: toggle reporting of stats for child trace events | 52 | *x*:: toggle reporting of stats for child trace events |
45 | 53 | ||
46 | Press any other key to refresh statistics immediately. | 54 | Press any other key to refresh statistics immediately. |
@@ -64,6 +72,10 @@ OPTIONS | |||
64 | --debugfs:: | 72 | --debugfs:: |
65 | retrieve statistics from debugfs | 73 | retrieve statistics from debugfs |
66 | 74 | ||
75 | -i:: | ||
76 | --debugfs-include-past:: | ||
77 | include all available data on past events for debugfs | ||
78 | |||
67 | -p<pid>:: | 79 | -p<pid>:: |
68 | --pid=<pid>:: | 80 | --pid=<pid>:: |
69 | limit statistics to one virtual machine (pid) | 81 | limit statistics to one virtual machine (pid) |
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 809c7721cd24..a7ecf8f469f4 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c | |||
@@ -387,6 +387,22 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) | |||
387 | return err; | 387 | return err; |
388 | } | 388 | } |
389 | 389 | ||
390 | int filename__write_int(const char *filename, int value) | ||
391 | { | ||
392 | int fd = open(filename, O_WRONLY), err = -1; | ||
393 | char buf[64]; | ||
394 | |||
395 | if (fd < 0) | ||
396 | return err; | ||
397 | |||
398 | sprintf(buf, "%d", value); | ||
399 | if (write(fd, buf, sizeof(buf)) == sizeof(buf)) | ||
400 | err = 0; | ||
401 | |||
402 | close(fd); | ||
403 | return err; | ||
404 | } | ||
405 | |||
390 | int procfs__read_str(const char *entry, char **buf, size_t *sizep) | 406 | int procfs__read_str(const char *entry, char **buf, size_t *sizep) |
391 | { | 407 | { |
392 | char path[PATH_MAX]; | 408 | char path[PATH_MAX]; |
@@ -480,3 +496,17 @@ int sysctl__read_int(const char *sysctl, int *value) | |||
480 | 496 | ||
481 | return filename__read_int(path, value); | 497 | return filename__read_int(path, value); |
482 | } | 498 | } |
499 | |||
500 | int sysfs__write_int(const char *entry, int value) | ||
501 | { | ||
502 | char path[PATH_MAX]; | ||
503 | const char *sysfs = sysfs__mountpoint(); | ||
504 | |||
505 | if (!sysfs) | ||
506 | return -1; | ||
507 | |||
508 | if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX) | ||
509 | return -1; | ||
510 | |||
511 | return filename__write_int(path, value); | ||
512 | } | ||
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 956c21127d1e..45605348461e 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h | |||
@@ -31,6 +31,8 @@ int filename__read_int(const char *filename, int *value); | |||
31 | int filename__read_ull(const char *filename, unsigned long long *value); | 31 | int filename__read_ull(const char *filename, unsigned long long *value); |
32 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | 32 | int filename__read_str(const char *filename, char **buf, size_t *sizep); |
33 | 33 | ||
34 | int filename__write_int(const char *filename, int value); | ||
35 | |||
34 | int procfs__read_str(const char *entry, char **buf, size_t *sizep); | 36 | int procfs__read_str(const char *entry, char **buf, size_t *sizep); |
35 | 37 | ||
36 | int sysctl__read_int(const char *sysctl, int *value); | 38 | int sysctl__read_int(const char *sysctl, int *value); |
@@ -38,4 +40,6 @@ int sysfs__read_int(const char *entry, int *value); | |||
38 | int sysfs__read_ull(const char *entry, unsigned long long *value); | 40 | int sysfs__read_ull(const char *entry, unsigned long long *value); |
39 | int sysfs__read_str(const char *entry, char **buf, size_t *sizep); | 41 | int sysfs__read_str(const char *entry, char **buf, size_t *sizep); |
40 | int sysfs__read_bool(const char *entry, bool *value); | 42 | int sysfs__read_bool(const char *entry, bool *value); |
43 | |||
44 | int sysfs__write_int(const char *entry, int value); | ||
41 | #endif /* __API_FS__ */ | 45 | #endif /* __API_FS__ */ |
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 4fe444b8092e..7e0405e1651d 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c | |||
@@ -117,6 +117,28 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | |||
117 | return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | 117 | return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); |
118 | } | 118 | } |
119 | 119 | ||
120 | int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, | ||
121 | size_t insns_cnt, int strict_alignment, | ||
122 | const char *license, __u32 kern_version, | ||
123 | char *log_buf, size_t log_buf_sz) | ||
124 | { | ||
125 | union bpf_attr attr; | ||
126 | |||
127 | bzero(&attr, sizeof(attr)); | ||
128 | attr.prog_type = type; | ||
129 | attr.insn_cnt = (__u32)insns_cnt; | ||
130 | attr.insns = ptr_to_u64(insns); | ||
131 | attr.license = ptr_to_u64(license); | ||
132 | attr.log_buf = ptr_to_u64(log_buf); | ||
133 | attr.log_size = log_buf_sz; | ||
134 | attr.log_level = 2; | ||
135 | log_buf[0] = 0; | ||
136 | attr.kern_version = kern_version; | ||
137 | attr.prog_flags = strict_alignment ? BPF_F_STRICT_ALIGNMENT : 0; | ||
138 | |||
139 | return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | ||
140 | } | ||
141 | |||
120 | int bpf_map_update_elem(int fd, const void *key, const void *value, | 142 | int bpf_map_update_elem(int fd, const void *key, const void *value, |
121 | __u64 flags) | 143 | __u64 flags) |
122 | { | 144 | { |
@@ -235,3 +257,71 @@ int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, | |||
235 | *duration = attr.test.duration; | 257 | *duration = attr.test.duration; |
236 | return ret; | 258 | return ret; |
237 | } | 259 | } |
260 | |||
261 | int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id) | ||
262 | { | ||
263 | union bpf_attr attr; | ||
264 | int err; | ||
265 | |||
266 | bzero(&attr, sizeof(attr)); | ||
267 | attr.start_id = start_id; | ||
268 | |||
269 | err = sys_bpf(BPF_PROG_GET_NEXT_ID, &attr, sizeof(attr)); | ||
270 | if (!err) | ||
271 | *next_id = attr.next_id; | ||
272 | |||
273 | return err; | ||
274 | } | ||
275 | |||
276 | int bpf_map_get_next_id(__u32 start_id, __u32 *next_id) | ||
277 | { | ||
278 | union bpf_attr attr; | ||
279 | int err; | ||
280 | |||
281 | bzero(&attr, sizeof(attr)); | ||
282 | attr.start_id = start_id; | ||
283 | |||
284 | err = sys_bpf(BPF_MAP_GET_NEXT_ID, &attr, sizeof(attr)); | ||
285 | if (!err) | ||
286 | *next_id = attr.next_id; | ||
287 | |||
288 | return err; | ||
289 | } | ||
290 | |||
291 | int bpf_prog_get_fd_by_id(__u32 id) | ||
292 | { | ||
293 | union bpf_attr attr; | ||
294 | |||
295 | bzero(&attr, sizeof(attr)); | ||
296 | attr.prog_id = id; | ||
297 | |||
298 | return sys_bpf(BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr)); | ||
299 | } | ||
300 | |||
301 | int bpf_map_get_fd_by_id(__u32 id) | ||
302 | { | ||
303 | union bpf_attr attr; | ||
304 | |||
305 | bzero(&attr, sizeof(attr)); | ||
306 | attr.map_id = id; | ||
307 | |||
308 | return sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr)); | ||
309 | } | ||
310 | |||
311 | int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len) | ||
312 | { | ||
313 | union bpf_attr attr; | ||
314 | int err; | ||
315 | |||
316 | bzero(&attr, sizeof(attr)); | ||
317 | bzero(info, *info_len); | ||
318 | attr.info.bpf_fd = prog_fd; | ||
319 | attr.info.info_len = *info_len; | ||
320 | attr.info.info = ptr_to_u64(info); | ||
321 | |||
322 | err = sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr)); | ||
323 | if (!err) | ||
324 | *info_len = attr.info.info_len; | ||
325 | |||
326 | return err; | ||
327 | } | ||
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index edb4daeff7a5..16de44a14b48 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h | |||
@@ -35,6 +35,10 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | |||
35 | size_t insns_cnt, const char *license, | 35 | size_t insns_cnt, const char *license, |
36 | __u32 kern_version, char *log_buf, | 36 | __u32 kern_version, char *log_buf, |
37 | size_t log_buf_sz); | 37 | size_t log_buf_sz); |
38 | int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, | ||
39 | size_t insns_cnt, int strict_alignment, | ||
40 | const char *license, __u32 kern_version, | ||
41 | char *log_buf, size_t log_buf_sz); | ||
38 | 42 | ||
39 | int bpf_map_update_elem(int fd, const void *key, const void *value, | 43 | int bpf_map_update_elem(int fd, const void *key, const void *value, |
40 | __u64 flags); | 44 | __u64 flags); |
@@ -50,5 +54,10 @@ int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); | |||
50 | int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, | 54 | int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, |
51 | void *data_out, __u32 *size_out, __u32 *retval, | 55 | void *data_out, __u32 *size_out, __u32 *retval, |
52 | __u32 *duration); | 56 | __u32 *duration); |
57 | int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); | ||
58 | int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); | ||
59 | int bpf_prog_get_fd_by_id(__u32 id); | ||
60 | int bpf_map_get_fd_by_id(__u32 id); | ||
61 | int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); | ||
53 | 62 | ||
54 | #endif | 63 | #endif |
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 3bc0ef9f8923..ed9ace59d112 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile | |||
@@ -79,6 +79,7 @@ INCLUDES = -I. -I./uinclude -I./include -I../../include $(CONFIG_INCLUDES) | |||
79 | # Set compile option CFLAGS if not set elsewhere | 79 | # Set compile option CFLAGS if not set elsewhere |
80 | CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g | 80 | CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g |
81 | CFLAGS += -fPIC | 81 | CFLAGS += -fPIC |
82 | CFLAGS += -Wall | ||
82 | 83 | ||
83 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) | 84 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) |
84 | 85 | ||
@@ -100,7 +101,7 @@ include $(srctree)/tools/build/Makefile.include | |||
100 | 101 | ||
101 | do_compile_shared_library = \ | 102 | do_compile_shared_library = \ |
102 | ($(print_shared_lib_compile) \ | 103 | ($(print_shared_lib_compile) \ |
103 | $(CC) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='"$@"';$(shell ln -sf $@ liblockdep.so)) | 104 | $(CC) $(LDFLAGS) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='$(@F)';$(shell ln -sf $(@F) $(@D)/liblockdep.so)) |
104 | 105 | ||
105 | do_build_static_lib = \ | 106 | do_build_static_lib = \ |
106 | ($(print_static_lib_build) \ | 107 | ($(print_static_lib_build) \ |
@@ -118,10 +119,10 @@ all_cmd: $(CMD_TARGETS) | |||
118 | $(LIB_IN): force | 119 | $(LIB_IN): force |
119 | $(Q)$(MAKE) $(build)=liblockdep | 120 | $(Q)$(MAKE) $(build)=liblockdep |
120 | 121 | ||
121 | liblockdep.so.$(LIBLOCKDEP_VERSION): $(LIB_IN) | 122 | $(OUTPUT)liblockdep.so.$(LIBLOCKDEP_VERSION): $(LIB_IN) |
122 | $(Q)$(do_compile_shared_library) | 123 | $(Q)$(do_compile_shared_library) |
123 | 124 | ||
124 | liblockdep.a: $(LIB_IN) | 125 | $(OUTPUT)liblockdep.a: $(LIB_IN) |
125 | $(Q)$(do_build_static_lib) | 126 | $(Q)$(do_build_static_lib) |
126 | 127 | ||
127 | tags: force | 128 | tags: force |
@@ -149,7 +150,7 @@ install_lib: all_cmd | |||
149 | install: install_lib | 150 | install: install_lib |
150 | 151 | ||
151 | clean: | 152 | clean: |
152 | $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d .*.cmd | 153 | $(RM) $(OUTPUT)*.o *~ $(TARGETS) $(OUTPUT)*.a $(OUTPUT)*liblockdep*.so* $(VERSION_FILES) $(OUTPUT).*.d $(OUTPUT).*.cmd |
153 | $(RM) tags TAGS | 154 | $(RM) tags TAGS |
154 | 155 | ||
155 | PHONY += force | 156 | PHONY += force |
diff --git a/tools/lib/lockdep/lockdep.c b/tools/lib/lockdep/lockdep.c index a0a2e3a266af..ced6d7443cea 100644 --- a/tools/lib/lockdep/lockdep.c +++ b/tools/lib/lockdep/lockdep.c | |||
@@ -1,8 +1,27 @@ | |||
1 | #include <linux/lockdep.h> | 1 | #include <linux/lockdep.h> |
2 | #include <stdlib.h> | ||
2 | 3 | ||
3 | /* Trivial API wrappers, we don't (yet) have RCU in user-space: */ | 4 | /* Trivial API wrappers, we don't (yet) have RCU in user-space: */ |
4 | #define hlist_for_each_entry_rcu hlist_for_each_entry | 5 | #define hlist_for_each_entry_rcu hlist_for_each_entry |
5 | #define hlist_add_head_rcu hlist_add_head | 6 | #define hlist_add_head_rcu hlist_add_head |
6 | #define hlist_del_rcu hlist_del | 7 | #define hlist_del_rcu hlist_del |
8 | #define list_for_each_entry_rcu list_for_each_entry | ||
9 | #define list_add_tail_rcu list_add_tail | ||
10 | |||
11 | u32 prandom_u32(void) | ||
12 | { | ||
13 | /* Used only by lock_pin_lock() which is dead code */ | ||
14 | abort(); | ||
15 | } | ||
16 | |||
17 | static struct new_utsname *init_utsname(void) | ||
18 | { | ||
19 | static struct new_utsname n = (struct new_utsname) { | ||
20 | .release = "liblockdep", | ||
21 | .version = LIBLOCKDEP_VERSION, | ||
22 | }; | ||
23 | |||
24 | return &n; | ||
25 | } | ||
7 | 26 | ||
8 | #include "../../../kernel/locking/lockdep.c" | 27 | #include "../../../kernel/locking/lockdep.c" |
diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c index 52844847569c..6a2d3c5d4e92 100644 --- a/tools/lib/lockdep/preload.c +++ b/tools/lib/lockdep/preload.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <dlfcn.h> | 4 | #include <dlfcn.h> |
5 | #include <stdlib.h> | 5 | #include <stdlib.h> |
6 | #include <sysexits.h> | 6 | #include <sysexits.h> |
7 | #include <unistd.h> | ||
7 | #include "include/liblockdep/mutex.h" | 8 | #include "include/liblockdep/mutex.h" |
8 | #include "../../include/linux/rbtree.h" | 9 | #include "../../include/linux/rbtree.h" |
9 | 10 | ||
@@ -122,8 +123,6 @@ static struct rb_node **__get_lock_node(void *lock, struct rb_node **parent) | |||
122 | #define LIBLOCKDEP_STATIC_ENTRIES 1024 | 123 | #define LIBLOCKDEP_STATIC_ENTRIES 1024 |
123 | #endif | 124 | #endif |
124 | 125 | ||
125 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
126 | |||
127 | static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES]; | 126 | static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES]; |
128 | static int __locks_nr; | 127 | static int __locks_nr; |
129 | 128 | ||
@@ -149,7 +148,7 @@ static struct lock_lookup *alloc_lock(void) | |||
149 | 148 | ||
150 | int idx = __locks_nr++; | 149 | int idx = __locks_nr++; |
151 | if (idx >= ARRAY_SIZE(__locks)) { | 150 | if (idx >= ARRAY_SIZE(__locks)) { |
152 | fprintf(stderr, | 151 | dprintf(STDERR_FILENO, |
153 | "LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n"); | 152 | "LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n"); |
154 | exit(EX_UNAVAILABLE); | 153 | exit(EX_UNAVAILABLE); |
155 | } | 154 | } |
diff --git a/tools/lib/lockdep/rbtree.c b/tools/lib/lockdep/rbtree.c index f7f43033c8b7..297c304571f8 100644 --- a/tools/lib/lockdep/rbtree.c +++ b/tools/lib/lockdep/rbtree.c | |||
@@ -1 +1 @@ | |||
#include "../../../lib/rbtree.c" | #include "../../lib/rbtree.c" | ||
diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh index 1069d96248c1..f9b94098fc98 100755 --- a/tools/lib/lockdep/run_tests.sh +++ b/tools/lib/lockdep/run_tests.sh | |||
@@ -4,9 +4,9 @@ make &> /dev/null | |||
4 | 4 | ||
5 | for i in `ls tests/*.c`; do | 5 | for i in `ls tests/*.c`; do |
6 | testname=$(basename "$i" .c) | 6 | testname=$(basename "$i" .c) |
7 | gcc -o tests/$testname -pthread -lpthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null | 7 | gcc -o tests/$testname -pthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null |
8 | echo -ne "$testname... " | 8 | echo -ne "$testname... " |
9 | if [ $(timeout 1 ./tests/$testname | wc -l) -gt 0 ]; then | 9 | if [ $(timeout 1 ./tests/$testname 2>&1 | wc -l) -gt 0 ]; then |
10 | echo "PASSED!" | 10 | echo "PASSED!" |
11 | else | 11 | else |
12 | echo "FAILED!" | 12 | echo "FAILED!" |
@@ -18,9 +18,9 @@ done | |||
18 | 18 | ||
19 | for i in `ls tests/*.c`; do | 19 | for i in `ls tests/*.c`; do |
20 | testname=$(basename "$i" .c) | 20 | testname=$(basename "$i" .c) |
21 | gcc -o tests/$testname -pthread -lpthread -Iinclude $i &> /dev/null | 21 | gcc -o tests/$testname -pthread -Iinclude $i &> /dev/null |
22 | echo -ne "(PRELOAD) $testname... " | 22 | echo -ne "(PRELOAD) $testname... " |
23 | if [ $(timeout 1 ./lockdep ./tests/$testname | wc -l) -gt 0 ]; then | 23 | if [ $(timeout 1 ./lockdep ./tests/$testname 2>&1 | wc -l) -gt 0 ]; then |
24 | echo "PASSED!" | 24 | echo "PASSED!" |
25 | else | 25 | else |
26 | echo "FAILED!" | 26 | echo "FAILED!" |
diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h deleted file mode 100644 index d82b170bb216..000000000000 --- a/tools/lib/lockdep/uinclude/asm/hash.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef __ASM_GENERIC_HASH_H | ||
2 | #define __ASM_GENERIC_HASH_H | ||
3 | |||
4 | /* Stub */ | ||
5 | |||
6 | #endif /* __ASM_GENERIC_HASH_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/asm/hweight.h b/tools/lib/lockdep/uinclude/asm/hweight.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/asm/hweight.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/asm/sections.h b/tools/lib/lockdep/uinclude/asm/sections.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/asm/sections.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/bitops.h b/tools/lib/lockdep/uinclude/linux/bitops.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/bitops.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h deleted file mode 100644 index fd3e56a83fc2..000000000000 --- a/tools/lib/lockdep/uinclude/linux/compiler.h +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_COMPILER_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_COMPILER_H_ | ||
3 | |||
4 | #define __used __attribute__((__unused__)) | ||
5 | #define unlikely | ||
6 | #define READ_ONCE(x) (x) | ||
7 | #define WRITE_ONCE(x, val) x=(val) | ||
8 | #define RCU_INIT_POINTER(p, v) p=(v) | ||
9 | |||
10 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/delay.h b/tools/lib/lockdep/uinclude/linux/delay.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/delay.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/ftrace.h b/tools/lib/lockdep/uinclude/linux/ftrace.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/ftrace.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/gfp.h b/tools/lib/lockdep/uinclude/linux/gfp.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/gfp.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/hash.h b/tools/lib/lockdep/uinclude/linux/hash.h deleted file mode 100644 index 0f8479858dc0..000000000000 --- a/tools/lib/lockdep/uinclude/linux/hash.h +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | #include "../../../include/linux/hash.h" | ||
diff --git a/tools/lib/lockdep/uinclude/linux/interrupt.h b/tools/lib/lockdep/uinclude/linux/interrupt.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/interrupt.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/kernel.h b/tools/lib/lockdep/uinclude/linux/kernel.h deleted file mode 100644 index 276c7a8b2ed1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/kernel.h +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_KERNEL_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_KERNEL_H_ | ||
3 | |||
4 | #include <linux/export.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <linux/rcu.h> | ||
7 | #include <linux/hardirq.h> | ||
8 | #include <linux/kern_levels.h> | ||
9 | |||
10 | #ifndef container_of | ||
11 | #define container_of(ptr, type, member) ({ \ | ||
12 | const typeof(((type *)0)->member) * __mptr = (ptr); \ | ||
13 | (type *)((char *)__mptr - offsetof(type, member)); }) | ||
14 | #endif | ||
15 | |||
16 | #define max(x, y) ({ \ | ||
17 | typeof(x) _max1 = (x); \ | ||
18 | typeof(y) _max2 = (y); \ | ||
19 | (void) (&_max1 == &_max2); \ | ||
20 | _max1 > _max2 ? _max1 : _max2; }) | ||
21 | |||
22 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | ||
23 | #define WARN_ON(x) (x) | ||
24 | #define WARN_ON_ONCE(x) (x) | ||
25 | #define likely(x) (x) | ||
26 | #define WARN(x, y...) (x) | ||
27 | #define uninitialized_var(x) x | ||
28 | #define __init | ||
29 | #define noinline | ||
30 | #define list_add_tail_rcu list_add_tail | ||
31 | #define list_for_each_entry_rcu list_for_each_entry | ||
32 | #define barrier() | ||
33 | #define synchronize_sched() | ||
34 | |||
35 | #ifndef CALLER_ADDR0 | ||
36 | #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) | ||
37 | #endif | ||
38 | |||
39 | #ifndef _RET_IP_ | ||
40 | #define _RET_IP_ CALLER_ADDR0 | ||
41 | #endif | ||
42 | |||
43 | #ifndef _THIS_IP_ | ||
44 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) | ||
45 | #endif | ||
46 | |||
47 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/linkage.h b/tools/lib/lockdep/uinclude/linux/linkage.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/linkage.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/list.h b/tools/lib/lockdep/uinclude/linux/list.h deleted file mode 100644 index 6e9ef31ed82e..000000000000 --- a/tools/lib/lockdep/uinclude/linux/list.h +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | #include "../../../include/linux/list.h" | ||
diff --git a/tools/lib/lockdep/uinclude/linux/mutex.h b/tools/lib/lockdep/uinclude/linux/mutex.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/mutex.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/poison.h b/tools/lib/lockdep/uinclude/linux/poison.h deleted file mode 100644 index 0c27bdf14233..000000000000 --- a/tools/lib/lockdep/uinclude/linux/poison.h +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | #include "../../../include/linux/poison.h" | ||
diff --git a/tools/lib/lockdep/uinclude/linux/prefetch.h b/tools/lib/lockdep/uinclude/linux/prefetch.h deleted file mode 100644 index d73fe6f850ac..000000000000 --- a/tools/lib/lockdep/uinclude/linux/prefetch.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_PREFETCH_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_PREFETCH_H | ||
3 | |||
4 | static inline void prefetch(void *a __attribute__((unused))) { } | ||
5 | |||
6 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/proc_fs.h b/tools/lib/lockdep/uinclude/linux/proc_fs.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/proc_fs.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h deleted file mode 100644 index c3759477379c..000000000000 --- a/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | #define __always_inline | ||
2 | #include "../../../include/linux/rbtree_augmented.h" | ||
diff --git a/tools/lib/lockdep/uinclude/linux/seq_file.h b/tools/lib/lockdep/uinclude/linux/seq_file.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/linux/seq_file.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/spinlock.h b/tools/lib/lockdep/uinclude/linux/spinlock.h deleted file mode 100644 index 68c1aa2bcba5..000000000000 --- a/tools/lib/lockdep/uinclude/linux/spinlock.h +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | #ifndef _LIBLOCKDEP_SPINLOCK_H_ | ||
2 | #define _LIBLOCKDEP_SPINLOCK_H_ | ||
3 | |||
4 | #include <pthread.h> | ||
5 | #include <stdbool.h> | ||
6 | |||
7 | #define arch_spinlock_t pthread_mutex_t | ||
8 | #define __ARCH_SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER | ||
9 | |||
10 | static inline void arch_spin_lock(arch_spinlock_t *mutex) | ||
11 | { | ||
12 | pthread_mutex_lock(mutex); | ||
13 | } | ||
14 | |||
15 | static inline void arch_spin_unlock(arch_spinlock_t *mutex) | ||
16 | { | ||
17 | pthread_mutex_unlock(mutex); | ||
18 | } | ||
19 | |||
20 | static inline bool arch_spin_is_locked(arch_spinlock_t *mutex) | ||
21 | { | ||
22 | return true; | ||
23 | } | ||
24 | |||
25 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/stringify.h b/tools/lib/lockdep/uinclude/linux/stringify.h deleted file mode 100644 index 05dfcd1ac118..000000000000 --- a/tools/lib/lockdep/uinclude/linux/stringify.h +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_STRINGIFY_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_STRINGIFY_H_ | ||
3 | |||
4 | #define __stringify_1(x...) #x | ||
5 | #define __stringify(x...) __stringify_1(x) | ||
6 | |||
7 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/trace/events/lock.h b/tools/lib/lockdep/uinclude/trace/events/lock.h deleted file mode 100644 index fab00ff936d1..000000000000 --- a/tools/lib/lockdep/uinclude/trace/events/lock.h +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/net/bpf_jit_disasm.c b/tools/net/bpf_jit_disasm.c index ad572e6cdbd0..422d9abd666a 100644 --- a/tools/net/bpf_jit_disasm.c +++ b/tools/net/bpf_jit_disasm.c | |||
@@ -159,8 +159,8 @@ static void put_log_buff(char *buff) | |||
159 | free(buff); | 159 | free(buff); |
160 | } | 160 | } |
161 | 161 | ||
162 | static unsigned int get_last_jit_image(char *haystack, size_t hlen, | 162 | static uint8_t *get_last_jit_image(char *haystack, size_t hlen, |
163 | uint8_t *image, size_t ilen) | 163 | unsigned int *ilen) |
164 | { | 164 | { |
165 | char *ptr, *pptr, *tmp; | 165 | char *ptr, *pptr, *tmp; |
166 | off_t off = 0; | 166 | off_t off = 0; |
@@ -168,9 +168,10 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, | |||
168 | regmatch_t pmatch[1]; | 168 | regmatch_t pmatch[1]; |
169 | unsigned long base; | 169 | unsigned long base; |
170 | regex_t regex; | 170 | regex_t regex; |
171 | uint8_t *image; | ||
171 | 172 | ||
172 | if (hlen == 0) | 173 | if (hlen == 0) |
173 | return 0; | 174 | return NULL; |
174 | 175 | ||
175 | ret = regcomp(®ex, "flen=[[:alnum:]]+ proglen=[[:digit:]]+ " | 176 | ret = regcomp(®ex, "flen=[[:alnum:]]+ proglen=[[:digit:]]+ " |
176 | "pass=[[:digit:]]+ image=[[:xdigit:]]+", REG_EXTENDED); | 177 | "pass=[[:digit:]]+ image=[[:xdigit:]]+", REG_EXTENDED); |
@@ -194,11 +195,22 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, | |||
194 | &flen, &proglen, &pass, &base); | 195 | &flen, &proglen, &pass, &base); |
195 | if (ret != 4) { | 196 | if (ret != 4) { |
196 | regfree(®ex); | 197 | regfree(®ex); |
197 | return 0; | 198 | return NULL; |
199 | } | ||
200 | if (proglen > 1000000) { | ||
201 | printf("proglen of %d too big, stopping\n", proglen); | ||
202 | return NULL; | ||
198 | } | 203 | } |
199 | 204 | ||
205 | image = malloc(proglen); | ||
206 | if (!image) { | ||
207 | printf("Out of memory\n"); | ||
208 | return NULL; | ||
209 | } | ||
210 | memset(image, 0, proglen); | ||
211 | |||
200 | tmp = ptr = haystack + off; | 212 | tmp = ptr = haystack + off; |
201 | while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) { | 213 | while ((ptr = strtok(tmp, "\n")) != NULL && ulen < proglen) { |
202 | tmp = NULL; | 214 | tmp = NULL; |
203 | if (!strstr(ptr, "JIT code")) | 215 | if (!strstr(ptr, "JIT code")) |
204 | continue; | 216 | continue; |
@@ -208,10 +220,12 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, | |||
208 | ptr = pptr; | 220 | ptr = pptr; |
209 | do { | 221 | do { |
210 | image[ulen++] = (uint8_t) strtoul(pptr, &pptr, 16); | 222 | image[ulen++] = (uint8_t) strtoul(pptr, &pptr, 16); |
211 | if (ptr == pptr || ulen >= ilen) { | 223 | if (ptr == pptr) { |
212 | ulen--; | 224 | ulen--; |
213 | break; | 225 | break; |
214 | } | 226 | } |
227 | if (ulen >= proglen) | ||
228 | break; | ||
215 | ptr = pptr; | 229 | ptr = pptr; |
216 | } while (1); | 230 | } while (1); |
217 | } | 231 | } |
@@ -222,7 +236,8 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, | |||
222 | printf("%lx + <x>:\n", base); | 236 | printf("%lx + <x>:\n", base); |
223 | 237 | ||
224 | regfree(®ex); | 238 | regfree(®ex); |
225 | return ulen; | 239 | *ilen = ulen; |
240 | return image; | ||
226 | } | 241 | } |
227 | 242 | ||
228 | static void usage(void) | 243 | static void usage(void) |
@@ -237,12 +252,12 @@ static void usage(void) | |||
237 | int main(int argc, char **argv) | 252 | int main(int argc, char **argv) |
238 | { | 253 | { |
239 | unsigned int len, klen, opt, opcodes = 0; | 254 | unsigned int len, klen, opt, opcodes = 0; |
240 | static uint8_t image[32768]; | ||
241 | char *kbuff, *file = NULL; | 255 | char *kbuff, *file = NULL; |
242 | char *ofile = NULL; | 256 | char *ofile = NULL; |
243 | int ofd; | 257 | int ofd; |
244 | ssize_t nr; | 258 | ssize_t nr; |
245 | uint8_t *pos; | 259 | uint8_t *pos; |
260 | uint8_t *image = NULL; | ||
246 | 261 | ||
247 | while ((opt = getopt(argc, argv, "of:O:")) != -1) { | 262 | while ((opt = getopt(argc, argv, "of:O:")) != -1) { |
248 | switch (opt) { | 263 | switch (opt) { |
@@ -262,7 +277,6 @@ int main(int argc, char **argv) | |||
262 | } | 277 | } |
263 | 278 | ||
264 | bfd_init(); | 279 | bfd_init(); |
265 | memset(image, 0, sizeof(image)); | ||
266 | 280 | ||
267 | kbuff = get_log_buff(file, &klen); | 281 | kbuff = get_log_buff(file, &klen); |
268 | if (!kbuff) { | 282 | if (!kbuff) { |
@@ -270,8 +284,8 @@ int main(int argc, char **argv) | |||
270 | return -1; | 284 | return -1; |
271 | } | 285 | } |
272 | 286 | ||
273 | len = get_last_jit_image(kbuff, klen, image, sizeof(image)); | 287 | image = get_last_jit_image(kbuff, klen, &len); |
274 | if (len <= 0) { | 288 | if (!image) { |
275 | fprintf(stderr, "No JIT image found!\n"); | 289 | fprintf(stderr, "No JIT image found!\n"); |
276 | goto done; | 290 | goto done; |
277 | } | 291 | } |
@@ -301,5 +315,6 @@ int main(int argc, char **argv) | |||
301 | 315 | ||
302 | done: | 316 | done: |
303 | put_log_buff(kbuff); | 317 | put_log_buff(kbuff); |
318 | free(image); | ||
304 | return 0; | 319 | return 0; |
305 | } | 320 | } |
diff --git a/tools/objtool/Build b/tools/objtool/Build index d6cdece5e58b..6f2e1987c4d9 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build | |||
@@ -1,5 +1,6 @@ | |||
1 | objtool-y += arch/$(SRCARCH)/ | 1 | objtool-y += arch/$(SRCARCH)/ |
2 | objtool-y += builtin-check.o | 2 | objtool-y += builtin-check.o |
3 | objtool-y += check.o | ||
3 | objtool-y += elf.o | 4 | objtool-y += elf.o |
4 | objtool-y += special.o | 5 | objtool-y += special.o |
5 | objtool-y += objtool.o | 6 | objtool-y += objtool.o |
diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt index 55a60d331f47..17c1195f11f4 100644 --- a/tools/objtool/Documentation/stack-validation.txt +++ b/tools/objtool/Documentation/stack-validation.txt | |||
@@ -127,28 +127,13 @@ b) 100% reliable stack traces for DWARF enabled kernels | |||
127 | 127 | ||
128 | c) Higher live patching compatibility rate | 128 | c) Higher live patching compatibility rate |
129 | 129 | ||
130 | (NOTE: This is not yet implemented) | 130 | Livepatch has an optional "consistency model", which is needed for |
131 | 131 | more complex patches. In order for the consistency model to work, | |
132 | Currently with CONFIG_LIVEPATCH there's a basic live patching | 132 | stack traces need to be reliable (or an unreliable condition needs to |
133 | framework which is safe for roughly 85-90% of "security" fixes. But | 133 | be detectable). Objtool makes that possible. |
134 | patches can't have complex features like function dependency or | ||
135 | prototype changes, or data structure changes. | ||
136 | |||
137 | There's a strong need to support patches which have the more complex | ||
138 | features so that the patch compatibility rate for security fixes can | ||
139 | eventually approach something resembling 100%. To achieve that, a | ||
140 | "consistency model" is needed, which allows tasks to be safely | ||
141 | transitioned from an unpatched state to a patched state. | ||
142 | |||
143 | One of the key requirements of the currently proposed livepatch | ||
144 | consistency model [*] is that it needs to walk the stack of each | ||
145 | sleeping task to determine if it can be transitioned to the patched | ||
146 | state. If objtool can ensure that stack traces are reliable, this | ||
147 | consistency model can be used and the live patching compatibility | ||
148 | rate can be improved significantly. | ||
149 | |||
150 | [*] https://lkml.kernel.org/r/cover.1423499826.git.jpoimboe@redhat.com | ||
151 | 134 | ||
135 | For more details, see the livepatch documentation in the Linux kernel | ||
136 | source tree at Documentation/livepatch/livepatch.txt. | ||
152 | 137 | ||
153 | Rules | 138 | Rules |
154 | ----- | 139 | ----- |
@@ -201,80 +186,84 @@ To achieve the validation, objtool enforces the following rules: | |||
201 | return normally. | 186 | return normally. |
202 | 187 | ||
203 | 188 | ||
204 | Errors in .S files | 189 | Objtool warnings |
205 | ------------------ | 190 | ---------------- |
206 | 191 | ||
207 | If you're getting an error in a compiled .S file which you don't | 192 | For asm files, if you're getting an error which doesn't make sense, |
208 | understand, first make sure that the affected code follows the above | 193 | first make sure that the affected code follows the above rules. |
209 | rules. | 194 | |
195 | For C files, the common culprits are inline asm statements and calls to | ||
196 | "noreturn" functions. See below for more details. | ||
197 | |||
198 | Another possible cause for errors in C code is if the Makefile removes | ||
199 | -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. | ||
210 | 200 | ||
211 | Here are some examples of common warnings reported by objtool, what | 201 | Here are some examples of common warnings reported by objtool, what |
212 | they mean, and suggestions for how to fix them. | 202 | they mean, and suggestions for how to fix them. |
213 | 203 | ||
214 | 204 | ||
215 | 1. asm_file.o: warning: objtool: func()+0x128: call without frame pointer save/setup | 205 | 1. file.o: warning: objtool: func()+0x128: call without frame pointer save/setup |
216 | 206 | ||
217 | The func() function made a function call without first saving and/or | 207 | The func() function made a function call without first saving and/or |
218 | updating the frame pointer. | 208 | updating the frame pointer, and CONFIG_FRAME_POINTER is enabled. |
219 | |||
220 | If func() is indeed a callable function, add proper frame pointer | ||
221 | logic using the FRAME_BEGIN and FRAME_END macros. Otherwise, remove | ||
222 | its ELF function annotation by changing ENDPROC to END. | ||
223 | 209 | ||
224 | If you're getting this error in a .c file, see the "Errors in .c | 210 | If the error is for an asm file, and func() is indeed a callable |
225 | files" section. | 211 | function, add proper frame pointer logic using the FRAME_BEGIN and |
212 | FRAME_END macros. Otherwise, if it's not a callable function, remove | ||
213 | its ELF function annotation by changing ENDPROC to END, and instead | ||
214 | use the manual CFI hint macros in asm/undwarf.h. | ||
226 | 215 | ||
216 | If it's a GCC-compiled .c file, the error may be because the function | ||
217 | uses an inline asm() statement which has a "call" instruction. An | ||
218 | asm() statement with a call instruction must declare the use of the | ||
219 | stack pointer in its output operand. For example, on x86_64: | ||
227 | 220 | ||
228 | 2. asm_file.o: warning: objtool: .text+0x53: return instruction outside of a callable function | 221 | register void *__sp asm("rsp"); |
229 | 222 | asm volatile("call func" : "+r" (__sp)); | |
230 | A return instruction was detected, but objtool couldn't find a way | ||
231 | for a callable function to reach the instruction. | ||
232 | 223 | ||
233 | If the return instruction is inside (or reachable from) a callable | 224 | Otherwise the stack frame may not get created before the call. |
234 | function, the function needs to be annotated with the ENTRY/ENDPROC | ||
235 | macros. | ||
236 | 225 | ||
237 | If you _really_ need a return instruction outside of a function, and | ||
238 | are 100% sure that it won't affect stack traces, you can tell | ||
239 | objtool to ignore it. See the "Adding exceptions" section below. | ||
240 | 226 | ||
227 | 2. file.o: warning: objtool: .text+0x53: unreachable instruction | ||
241 | 228 | ||
242 | 3. asm_file.o: warning: objtool: func()+0x9: function has unreachable instruction | 229 | Objtool couldn't find a code path to reach the instruction. |
243 | 230 | ||
244 | The instruction lives inside of a callable function, but there's no | 231 | If the error is for an asm file, and the instruction is inside (or |
245 | possible control flow path from the beginning of the function to the | 232 | reachable from) a callable function, the function should be annotated |
246 | instruction. | 233 | with the ENTRY/ENDPROC macros (ENDPROC is the important one). |
234 | Otherwise, the code should probably be annotated with the CFI hint | ||
235 | macros in asm/undwarf.h so objtool and the unwinder can know the | ||
236 | stack state associated with the code. | ||
247 | 237 | ||
248 | If the instruction is actually needed, and it's actually in a | 238 | If you're 100% sure the code won't affect stack traces, or if you're |
249 | callable function, ensure that its function is properly annotated | 239 | a just a bad person, you can tell objtool to ignore it. See the |
250 | with ENTRY/ENDPROC. | 240 | "Adding exceptions" section below. |
251 | 241 | ||
252 | If it's not actually in a callable function (e.g. kernel entry code), | 242 | If it's not actually in a callable function (e.g. kernel entry code), |
253 | change ENDPROC to END. | 243 | change ENDPROC to END. |
254 | 244 | ||
255 | 245 | ||
256 | 4. asm_file.o: warning: objtool: func(): can't find starting instruction | 246 | 4. file.o: warning: objtool: func(): can't find starting instruction |
257 | or | 247 | or |
258 | asm_file.o: warning: objtool: func()+0x11dd: can't decode instruction | 248 | file.o: warning: objtool: func()+0x11dd: can't decode instruction |
259 | 249 | ||
260 | Did you put data in a text section? If so, that can confuse | 250 | Does the file have data in a text section? If so, that can confuse |
261 | objtool's instruction decoder. Move the data to a more appropriate | 251 | objtool's instruction decoder. Move the data to a more appropriate |
262 | section like .data or .rodata. | 252 | section like .data or .rodata. |
263 | 253 | ||
264 | 254 | ||
265 | 5. asm_file.o: warning: objtool: func()+0x6: kernel entry/exit from callable instruction | 255 | 5. file.o: warning: objtool: func()+0x6: unsupported instruction in callable function |
266 | |||
267 | This is a kernel entry/exit instruction like sysenter or sysret. | ||
268 | Such instructions aren't allowed in a callable function, and are most | ||
269 | likely part of the kernel entry code. | ||
270 | 256 | ||
271 | If the instruction isn't actually in a callable function, change | 257 | This is a kernel entry/exit instruction like sysenter or iret. Such |
272 | ENDPROC to END. | 258 | instructions aren't allowed in a callable function, and are most |
259 | likely part of the kernel entry code. They should usually not have | ||
260 | the callable function annotation (ENDPROC) and should always be | ||
261 | annotated with the CFI hint macros in asm/undwarf.h. | ||
273 | 262 | ||
274 | 263 | ||
275 | 6. asm_file.o: warning: objtool: func()+0x26: sibling call from callable instruction with changed frame pointer | 264 | 6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame |
276 | 265 | ||
277 | This is a dynamic jump or a jump to an undefined symbol. Stacktool | 266 | This is a dynamic jump or a jump to an undefined symbol. Objtool |
278 | assumed it's a sibling call and detected that the frame pointer | 267 | assumed it's a sibling call and detected that the frame pointer |
279 | wasn't first restored to its original state. | 268 | wasn't first restored to its original state. |
280 | 269 | ||
@@ -282,24 +271,28 @@ they mean, and suggestions for how to fix them. | |||
282 | destination code to the local file. | 271 | destination code to the local file. |
283 | 272 | ||
284 | If the instruction is not actually in a callable function (e.g. | 273 | If the instruction is not actually in a callable function (e.g. |
285 | kernel entry code), change ENDPROC to END. | 274 | kernel entry code), change ENDPROC to END and annotate manually with |
275 | the CFI hint macros in asm/undwarf.h. | ||
286 | 276 | ||
287 | 277 | ||
288 | 7. asm_file: warning: objtool: func()+0x5c: frame pointer state mismatch | 278 | 7. file: warning: objtool: func()+0x5c: stack state mismatch |
289 | 279 | ||
290 | The instruction's frame pointer state is inconsistent, depending on | 280 | The instruction's frame pointer state is inconsistent, depending on |
291 | which execution path was taken to reach the instruction. | 281 | which execution path was taken to reach the instruction. |
292 | 282 | ||
293 | Make sure the function pushes and sets up the frame pointer (for | 283 | Make sure that, when CONFIG_FRAME_POINTER is enabled, the function |
294 | x86_64, this means rbp) at the beginning of the function and pops it | 284 | pushes and sets up the frame pointer (for x86_64, this means rbp) at |
295 | at the end of the function. Also make sure that no other code in the | 285 | the beginning of the function and pops it at the end of the function. |
296 | function touches the frame pointer. | 286 | Also make sure that no other code in the function touches the frame |
287 | pointer. | ||
297 | 288 | ||
289 | Another possibility is that the code has some asm or inline asm which | ||
290 | does some unusual things to the stack or the frame pointer. In such | ||
291 | cases it's probably appropriate to use the CFI hint macros in | ||
292 | asm/undwarf.h. | ||
298 | 293 | ||
299 | Errors in .c files | ||
300 | ------------------ | ||
301 | 294 | ||
302 | 1. c_file.o: warning: objtool: funcA() falls through to next function funcB() | 295 | 8. file.o: warning: objtool: funcA() falls through to next function funcB() |
303 | 296 | ||
304 | This means that funcA() doesn't end with a return instruction or an | 297 | This means that funcA() doesn't end with a return instruction or an |
305 | unconditional jump, and that objtool has determined that the function | 298 | unconditional jump, and that objtool has determined that the function |
@@ -318,22 +311,6 @@ Errors in .c files | |||
318 | might be corrupt due to a gcc bug. For more details, see: | 311 | might be corrupt due to a gcc bug. For more details, see: |
319 | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 | 312 | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 |
320 | 313 | ||
321 | 2. If you're getting any other objtool error in a compiled .c file, it | ||
322 | may be because the file uses an asm() statement which has a "call" | ||
323 | instruction. An asm() statement with a call instruction must declare | ||
324 | the use of the stack pointer in its output operand. For example, on | ||
325 | x86_64: | ||
326 | |||
327 | register void *__sp asm("rsp"); | ||
328 | asm volatile("call func" : "+r" (__sp)); | ||
329 | |||
330 | Otherwise the stack frame may not get created before the call. | ||
331 | |||
332 | 3. Another possible cause for errors in C code is if the Makefile removes | ||
333 | -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. | ||
334 | |||
335 | Also see the above section for .S file errors for more information what | ||
336 | the individual error messages mean. | ||
337 | 314 | ||
338 | If the error doesn't seem to make sense, it could be a bug in objtool. | 315 | If the error doesn't seem to make sense, it could be a bug in objtool. |
339 | Feel free to ask the objtool maintainer for help. | 316 | Feel free to ask the objtool maintainer for help. |
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 27e019c09bd2..0e2765e243c0 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
@@ -25,7 +25,7 @@ OBJTOOL_IN := $(OBJTOOL)-in.o | |||
25 | all: $(OBJTOOL) | 25 | all: $(OBJTOOL) |
26 | 26 | ||
27 | INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi | 27 | INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi |
28 | CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) | 28 | CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -fomit-frame-pointer -O2 -g $(INCLUDES) |
29 | LDFLAGS += -lelf $(LIBSUBCMD) | 29 | LDFLAGS += -lelf $(LIBSUBCMD) |
30 | 30 | ||
31 | # Allow old libelf to be used: | 31 | # Allow old libelf to be used: |
diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index a59e061c0b4a..21aeca874edb 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h | |||
@@ -19,25 +19,63 @@ | |||
19 | #define _ARCH_H | 19 | #define _ARCH_H |
20 | 20 | ||
21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
22 | #include <linux/list.h> | ||
22 | #include "elf.h" | 23 | #include "elf.h" |
24 | #include "cfi.h" | ||
23 | 25 | ||
24 | #define INSN_FP_SAVE 1 | 26 | #define INSN_JUMP_CONDITIONAL 1 |
25 | #define INSN_FP_SETUP 2 | 27 | #define INSN_JUMP_UNCONDITIONAL 2 |
26 | #define INSN_FP_RESTORE 3 | 28 | #define INSN_JUMP_DYNAMIC 3 |
27 | #define INSN_JUMP_CONDITIONAL 4 | 29 | #define INSN_CALL 4 |
28 | #define INSN_JUMP_UNCONDITIONAL 5 | 30 | #define INSN_CALL_DYNAMIC 5 |
29 | #define INSN_JUMP_DYNAMIC 6 | 31 | #define INSN_RETURN 6 |
30 | #define INSN_CALL 7 | 32 | #define INSN_CONTEXT_SWITCH 7 |
31 | #define INSN_CALL_DYNAMIC 8 | 33 | #define INSN_STACK 8 |
32 | #define INSN_RETURN 9 | 34 | #define INSN_NOP 9 |
33 | #define INSN_CONTEXT_SWITCH 10 | 35 | #define INSN_OTHER 10 |
34 | #define INSN_NOP 11 | ||
35 | #define INSN_OTHER 12 | ||
36 | #define INSN_LAST INSN_OTHER | 36 | #define INSN_LAST INSN_OTHER |
37 | 37 | ||
38 | enum op_dest_type { | ||
39 | OP_DEST_REG, | ||
40 | OP_DEST_REG_INDIRECT, | ||
41 | OP_DEST_MEM, | ||
42 | OP_DEST_PUSH, | ||
43 | OP_DEST_LEAVE, | ||
44 | }; | ||
45 | |||
46 | struct op_dest { | ||
47 | enum op_dest_type type; | ||
48 | unsigned char reg; | ||
49 | int offset; | ||
50 | }; | ||
51 | |||
52 | enum op_src_type { | ||
53 | OP_SRC_REG, | ||
54 | OP_SRC_REG_INDIRECT, | ||
55 | OP_SRC_CONST, | ||
56 | OP_SRC_POP, | ||
57 | OP_SRC_ADD, | ||
58 | OP_SRC_AND, | ||
59 | }; | ||
60 | |||
61 | struct op_src { | ||
62 | enum op_src_type type; | ||
63 | unsigned char reg; | ||
64 | int offset; | ||
65 | }; | ||
66 | |||
67 | struct stack_op { | ||
68 | struct op_dest dest; | ||
69 | struct op_src src; | ||
70 | }; | ||
71 | |||
72 | void arch_initial_func_cfi_state(struct cfi_state *state); | ||
73 | |||
38 | int arch_decode_instruction(struct elf *elf, struct section *sec, | 74 | int arch_decode_instruction(struct elf *elf, struct section *sec, |
39 | unsigned long offset, unsigned int maxlen, | 75 | unsigned long offset, unsigned int maxlen, |
40 | unsigned int *len, unsigned char *type, | 76 | unsigned int *len, unsigned char *type, |
41 | unsigned long *displacement); | 77 | unsigned long *immediate, struct stack_op *op); |
78 | |||
79 | bool arch_callee_saved_reg(unsigned char reg); | ||
42 | 80 | ||
43 | #endif /* _ARCH_H */ | 81 | #endif /* _ARCH_H */ |
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 6ac99e3266eb..a36c2eba64e7 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c | |||
@@ -27,6 +27,17 @@ | |||
27 | #include "../../arch.h" | 27 | #include "../../arch.h" |
28 | #include "../../warn.h" | 28 | #include "../../warn.h" |
29 | 29 | ||
30 | static unsigned char op_to_cfi_reg[][2] = { | ||
31 | {CFI_AX, CFI_R8}, | ||
32 | {CFI_CX, CFI_R9}, | ||
33 | {CFI_DX, CFI_R10}, | ||
34 | {CFI_BX, CFI_R11}, | ||
35 | {CFI_SP, CFI_R12}, | ||
36 | {CFI_BP, CFI_R13}, | ||
37 | {CFI_SI, CFI_R14}, | ||
38 | {CFI_DI, CFI_R15}, | ||
39 | }; | ||
40 | |||
30 | static int is_x86_64(struct elf *elf) | 41 | static int is_x86_64(struct elf *elf) |
31 | { | 42 | { |
32 | switch (elf->ehdr.e_machine) { | 43 | switch (elf->ehdr.e_machine) { |
@@ -40,24 +51,50 @@ static int is_x86_64(struct elf *elf) | |||
40 | } | 51 | } |
41 | } | 52 | } |
42 | 53 | ||
54 | bool arch_callee_saved_reg(unsigned char reg) | ||
55 | { | ||
56 | switch (reg) { | ||
57 | case CFI_BP: | ||
58 | case CFI_BX: | ||
59 | case CFI_R12: | ||
60 | case CFI_R13: | ||
61 | case CFI_R14: | ||
62 | case CFI_R15: | ||
63 | return true; | ||
64 | |||
65 | case CFI_AX: | ||
66 | case CFI_CX: | ||
67 | case CFI_DX: | ||
68 | case CFI_SI: | ||
69 | case CFI_DI: | ||
70 | case CFI_SP: | ||
71 | case CFI_R8: | ||
72 | case CFI_R9: | ||
73 | case CFI_R10: | ||
74 | case CFI_R11: | ||
75 | case CFI_RA: | ||
76 | default: | ||
77 | return false; | ||
78 | } | ||
79 | } | ||
80 | |||
43 | int arch_decode_instruction(struct elf *elf, struct section *sec, | 81 | int arch_decode_instruction(struct elf *elf, struct section *sec, |
44 | unsigned long offset, unsigned int maxlen, | 82 | unsigned long offset, unsigned int maxlen, |
45 | unsigned int *len, unsigned char *type, | 83 | unsigned int *len, unsigned char *type, |
46 | unsigned long *immediate) | 84 | unsigned long *immediate, struct stack_op *op) |
47 | { | 85 | { |
48 | struct insn insn; | 86 | struct insn insn; |
49 | int x86_64; | 87 | int x86_64, sign; |
50 | unsigned char op1, op2, ext; | 88 | unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, |
89 | modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0, | ||
90 | sib = 0; | ||
51 | 91 | ||
52 | x86_64 = is_x86_64(elf); | 92 | x86_64 = is_x86_64(elf); |
53 | if (x86_64 == -1) | 93 | if (x86_64 == -1) |
54 | return -1; | 94 | return -1; |
55 | 95 | ||
56 | insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64); | 96 | insn_init(&insn, sec->data->d_buf + offset, maxlen, x86_64); |
57 | insn_get_length(&insn); | 97 | insn_get_length(&insn); |
58 | insn_get_opcode(&insn); | ||
59 | insn_get_modrm(&insn); | ||
60 | insn_get_immediate(&insn); | ||
61 | 98 | ||
62 | if (!insn_complete(&insn)) { | 99 | if (!insn_complete(&insn)) { |
63 | WARN_FUNC("can't decode instruction", sec, offset); | 100 | WARN_FUNC("can't decode instruction", sec, offset); |
@@ -73,67 +110,323 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
73 | op1 = insn.opcode.bytes[0]; | 110 | op1 = insn.opcode.bytes[0]; |
74 | op2 = insn.opcode.bytes[1]; | 111 | op2 = insn.opcode.bytes[1]; |
75 | 112 | ||
113 | if (insn.rex_prefix.nbytes) { | ||
114 | rex = insn.rex_prefix.bytes[0]; | ||
115 | rex_w = X86_REX_W(rex) >> 3; | ||
116 | rex_r = X86_REX_R(rex) >> 2; | ||
117 | rex_b = X86_REX_B(rex); | ||
118 | } | ||
119 | |||
120 | if (insn.modrm.nbytes) { | ||
121 | modrm = insn.modrm.bytes[0]; | ||
122 | modrm_mod = X86_MODRM_MOD(modrm); | ||
123 | modrm_reg = X86_MODRM_REG(modrm); | ||
124 | modrm_rm = X86_MODRM_RM(modrm); | ||
125 | } | ||
126 | |||
127 | if (insn.sib.nbytes) | ||
128 | sib = insn.sib.bytes[0]; | ||
129 | |||
76 | switch (op1) { | 130 | switch (op1) { |
77 | case 0x55: | 131 | |
78 | if (!insn.rex_prefix.nbytes) | 132 | case 0x1: |
79 | /* push rbp */ | 133 | case 0x29: |
80 | *type = INSN_FP_SAVE; | 134 | if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { |
135 | |||
136 | /* add/sub reg, %rsp */ | ||
137 | *type = INSN_STACK; | ||
138 | op->src.type = OP_SRC_ADD; | ||
139 | op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
140 | op->dest.type = OP_SRC_REG; | ||
141 | op->dest.reg = CFI_SP; | ||
142 | } | ||
143 | break; | ||
144 | |||
145 | case 0x50 ... 0x57: | ||
146 | |||
147 | /* push reg */ | ||
148 | *type = INSN_STACK; | ||
149 | op->src.type = OP_SRC_REG; | ||
150 | op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; | ||
151 | op->dest.type = OP_DEST_PUSH; | ||
152 | |||
81 | break; | 153 | break; |
82 | 154 | ||
83 | case 0x5d: | 155 | case 0x58 ... 0x5f: |
84 | if (!insn.rex_prefix.nbytes) | 156 | |
85 | /* pop rbp */ | 157 | /* pop reg */ |
86 | *type = INSN_FP_RESTORE; | 158 | *type = INSN_STACK; |
159 | op->src.type = OP_SRC_POP; | ||
160 | op->dest.type = OP_DEST_REG; | ||
161 | op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; | ||
162 | |||
163 | break; | ||
164 | |||
165 | case 0x68: | ||
166 | case 0x6a: | ||
167 | /* push immediate */ | ||
168 | *type = INSN_STACK; | ||
169 | op->src.type = OP_SRC_CONST; | ||
170 | op->dest.type = OP_DEST_PUSH; | ||
87 | break; | 171 | break; |
88 | 172 | ||
89 | case 0x70 ... 0x7f: | 173 | case 0x70 ... 0x7f: |
90 | *type = INSN_JUMP_CONDITIONAL; | 174 | *type = INSN_JUMP_CONDITIONAL; |
91 | break; | 175 | break; |
92 | 176 | ||
177 | case 0x81: | ||
178 | case 0x83: | ||
179 | if (rex != 0x48) | ||
180 | break; | ||
181 | |||
182 | if (modrm == 0xe4) { | ||
183 | /* and imm, %rsp */ | ||
184 | *type = INSN_STACK; | ||
185 | op->src.type = OP_SRC_AND; | ||
186 | op->src.reg = CFI_SP; | ||
187 | op->src.offset = insn.immediate.value; | ||
188 | op->dest.type = OP_DEST_REG; | ||
189 | op->dest.reg = CFI_SP; | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | if (modrm == 0xc4) | ||
194 | sign = 1; | ||
195 | else if (modrm == 0xec) | ||
196 | sign = -1; | ||
197 | else | ||
198 | break; | ||
199 | |||
200 | /* add/sub imm, %rsp */ | ||
201 | *type = INSN_STACK; | ||
202 | op->src.type = OP_SRC_ADD; | ||
203 | op->src.reg = CFI_SP; | ||
204 | op->src.offset = insn.immediate.value * sign; | ||
205 | op->dest.type = OP_DEST_REG; | ||
206 | op->dest.reg = CFI_SP; | ||
207 | break; | ||
208 | |||
93 | case 0x89: | 209 | case 0x89: |
94 | if (insn.rex_prefix.nbytes == 1 && | 210 | if (rex == 0x48 && modrm == 0xe5) { |
95 | insn.rex_prefix.bytes[0] == 0x48 && | 211 | |
96 | insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5) | 212 | /* mov %rsp, %rbp */ |
97 | /* mov rsp, rbp */ | 213 | *type = INSN_STACK; |
98 | *type = INSN_FP_SETUP; | 214 | op->src.type = OP_SRC_REG; |
215 | op->src.reg = CFI_SP; | ||
216 | op->dest.type = OP_DEST_REG; | ||
217 | op->dest.reg = CFI_BP; | ||
218 | break; | ||
219 | } | ||
220 | /* fallthrough */ | ||
221 | case 0x88: | ||
222 | if (!rex_b && | ||
223 | (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { | ||
224 | |||
225 | /* mov reg, disp(%rbp) */ | ||
226 | *type = INSN_STACK; | ||
227 | op->src.type = OP_SRC_REG; | ||
228 | op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
229 | op->dest.type = OP_DEST_REG_INDIRECT; | ||
230 | op->dest.reg = CFI_BP; | ||
231 | op->dest.offset = insn.displacement.value; | ||
232 | |||
233 | } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { | ||
234 | |||
235 | /* mov reg, disp(%rsp) */ | ||
236 | *type = INSN_STACK; | ||
237 | op->src.type = OP_SRC_REG; | ||
238 | op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
239 | op->dest.type = OP_DEST_REG_INDIRECT; | ||
240 | op->dest.reg = CFI_SP; | ||
241 | op->dest.offset = insn.displacement.value; | ||
242 | } | ||
243 | |||
244 | break; | ||
245 | |||
246 | case 0x8b: | ||
247 | if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) { | ||
248 | |||
249 | /* mov disp(%rbp), reg */ | ||
250 | *type = INSN_STACK; | ||
251 | op->src.type = OP_SRC_REG_INDIRECT; | ||
252 | op->src.reg = CFI_BP; | ||
253 | op->src.offset = insn.displacement.value; | ||
254 | op->dest.type = OP_DEST_REG; | ||
255 | op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
256 | |||
257 | } else if (rex_w && !rex_b && sib == 0x24 && | ||
258 | modrm_mod != 3 && modrm_rm == 4) { | ||
259 | |||
260 | /* mov disp(%rsp), reg */ | ||
261 | *type = INSN_STACK; | ||
262 | op->src.type = OP_SRC_REG_INDIRECT; | ||
263 | op->src.reg = CFI_SP; | ||
264 | op->src.offset = insn.displacement.value; | ||
265 | op->dest.type = OP_DEST_REG; | ||
266 | op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
267 | } | ||
268 | |||
99 | break; | 269 | break; |
100 | 270 | ||
101 | case 0x8d: | 271 | case 0x8d: |
102 | if (insn.rex_prefix.nbytes && | 272 | if (rex == 0x48 && modrm == 0x65) { |
103 | insn.rex_prefix.bytes[0] == 0x48 && | 273 | |
104 | insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c && | 274 | /* lea -disp(%rbp), %rsp */ |
105 | insn.sib.nbytes && insn.sib.bytes[0] == 0x24) | 275 | *type = INSN_STACK; |
106 | /* lea %(rsp), %rbp */ | 276 | op->src.type = OP_SRC_ADD; |
107 | *type = INSN_FP_SETUP; | 277 | op->src.reg = CFI_BP; |
278 | op->src.offset = insn.displacement.value; | ||
279 | op->dest.type = OP_DEST_REG; | ||
280 | op->dest.reg = CFI_SP; | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | if (rex == 0x4c && modrm == 0x54 && sib == 0x24 && | ||
285 | insn.displacement.value == 8) { | ||
286 | |||
287 | /* | ||
288 | * lea 0x8(%rsp), %r10 | ||
289 | * | ||
290 | * Here r10 is the "drap" pointer, used as a stack | ||
291 | * pointer helper when the stack gets realigned. | ||
292 | */ | ||
293 | *type = INSN_STACK; | ||
294 | op->src.type = OP_SRC_ADD; | ||
295 | op->src.reg = CFI_SP; | ||
296 | op->src.offset = 8; | ||
297 | op->dest.type = OP_DEST_REG; | ||
298 | op->dest.reg = CFI_R10; | ||
299 | break; | ||
300 | } | ||
301 | |||
302 | if (rex == 0x4c && modrm == 0x6c && sib == 0x24 && | ||
303 | insn.displacement.value == 16) { | ||
304 | |||
305 | /* | ||
306 | * lea 0x10(%rsp), %r13 | ||
307 | * | ||
308 | * Here r13 is the "drap" pointer, used as a stack | ||
309 | * pointer helper when the stack gets realigned. | ||
310 | */ | ||
311 | *type = INSN_STACK; | ||
312 | op->src.type = OP_SRC_ADD; | ||
313 | op->src.reg = CFI_SP; | ||
314 | op->src.offset = 16; | ||
315 | op->dest.type = OP_DEST_REG; | ||
316 | op->dest.reg = CFI_R13; | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | if (rex == 0x49 && modrm == 0x62 && | ||
321 | insn.displacement.value == -8) { | ||
322 | |||
323 | /* | ||
324 | * lea -0x8(%r10), %rsp | ||
325 | * | ||
326 | * Restoring rsp back to its original value after a | ||
327 | * stack realignment. | ||
328 | */ | ||
329 | *type = INSN_STACK; | ||
330 | op->src.type = OP_SRC_ADD; | ||
331 | op->src.reg = CFI_R10; | ||
332 | op->src.offset = -8; | ||
333 | op->dest.type = OP_DEST_REG; | ||
334 | op->dest.reg = CFI_SP; | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | if (rex == 0x49 && modrm == 0x65 && | ||
339 | insn.displacement.value == -16) { | ||
340 | |||
341 | /* | ||
342 | * lea -0x10(%r13), %rsp | ||
343 | * | ||
344 | * Restoring rsp back to its original value after a | ||
345 | * stack realignment. | ||
346 | */ | ||
347 | *type = INSN_STACK; | ||
348 | op->src.type = OP_SRC_ADD; | ||
349 | op->src.reg = CFI_R13; | ||
350 | op->src.offset = -16; | ||
351 | op->dest.type = OP_DEST_REG; | ||
352 | op->dest.reg = CFI_SP; | ||
353 | break; | ||
354 | } | ||
355 | |||
356 | break; | ||
357 | |||
358 | case 0x8f: | ||
359 | /* pop to mem */ | ||
360 | *type = INSN_STACK; | ||
361 | op->src.type = OP_SRC_POP; | ||
362 | op->dest.type = OP_DEST_MEM; | ||
108 | break; | 363 | break; |
109 | 364 | ||
110 | case 0x90: | 365 | case 0x90: |
111 | *type = INSN_NOP; | 366 | *type = INSN_NOP; |
112 | break; | 367 | break; |
113 | 368 | ||
369 | case 0x9c: | ||
370 | /* pushf */ | ||
371 | *type = INSN_STACK; | ||
372 | op->src.type = OP_SRC_CONST; | ||
373 | op->dest.type = OP_DEST_PUSH; | ||
374 | break; | ||
375 | |||
376 | case 0x9d: | ||
377 | /* popf */ | ||
378 | *type = INSN_STACK; | ||
379 | op->src.type = OP_SRC_POP; | ||
380 | op->dest.type = OP_DEST_MEM; | ||
381 | break; | ||
382 | |||
114 | case 0x0f: | 383 | case 0x0f: |
384 | |||
115 | if (op2 >= 0x80 && op2 <= 0x8f) | 385 | if (op2 >= 0x80 && op2 <= 0x8f) |
116 | *type = INSN_JUMP_CONDITIONAL; | 386 | *type = INSN_JUMP_CONDITIONAL; |
117 | else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || | 387 | else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || |
118 | op2 == 0x35) | 388 | op2 == 0x35) |
389 | |||
119 | /* sysenter, sysret */ | 390 | /* sysenter, sysret */ |
120 | *type = INSN_CONTEXT_SWITCH; | 391 | *type = INSN_CONTEXT_SWITCH; |
392 | |||
121 | else if (op2 == 0x0d || op2 == 0x1f) | 393 | else if (op2 == 0x0d || op2 == 0x1f) |
394 | |||
122 | /* nopl/nopw */ | 395 | /* nopl/nopw */ |
123 | *type = INSN_NOP; | 396 | *type = INSN_NOP; |
124 | else if (op2 == 0x01 && insn.modrm.nbytes && | 397 | |
125 | (insn.modrm.bytes[0] == 0xc2 || | 398 | else if (op2 == 0xa0 || op2 == 0xa8) { |
126 | insn.modrm.bytes[0] == 0xd8)) | 399 | |
127 | /* vmlaunch, vmrun */ | 400 | /* push fs/gs */ |
128 | *type = INSN_CONTEXT_SWITCH; | 401 | *type = INSN_STACK; |
402 | op->src.type = OP_SRC_CONST; | ||
403 | op->dest.type = OP_DEST_PUSH; | ||
404 | |||
405 | } else if (op2 == 0xa1 || op2 == 0xa9) { | ||
406 | |||
407 | /* pop fs/gs */ | ||
408 | *type = INSN_STACK; | ||
409 | op->src.type = OP_SRC_POP; | ||
410 | op->dest.type = OP_DEST_MEM; | ||
411 | } | ||
129 | 412 | ||
130 | break; | 413 | break; |
131 | 414 | ||
132 | case 0xc9: /* leave */ | 415 | case 0xc9: |
133 | *type = INSN_FP_RESTORE; | 416 | /* |
417 | * leave | ||
418 | * | ||
419 | * equivalent to: | ||
420 | * mov bp, sp | ||
421 | * pop bp | ||
422 | */ | ||
423 | *type = INSN_STACK; | ||
424 | op->dest.type = OP_DEST_LEAVE; | ||
425 | |||
134 | break; | 426 | break; |
135 | 427 | ||
136 | case 0xe3: /* jecxz/jrcxz */ | 428 | case 0xe3: |
429 | /* jecxz/jrcxz */ | ||
137 | *type = INSN_JUMP_CONDITIONAL; | 430 | *type = INSN_JUMP_CONDITIONAL; |
138 | break; | 431 | break; |
139 | 432 | ||
@@ -158,14 +451,27 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
158 | break; | 451 | break; |
159 | 452 | ||
160 | case 0xff: | 453 | case 0xff: |
161 | ext = X86_MODRM_REG(insn.modrm.bytes[0]); | 454 | if (modrm_reg == 2 || modrm_reg == 3) |
162 | if (ext == 2 || ext == 3) | 455 | |
163 | *type = INSN_CALL_DYNAMIC; | 456 | *type = INSN_CALL_DYNAMIC; |
164 | else if (ext == 4) | 457 | |
458 | else if (modrm_reg == 4) | ||
459 | |||
165 | *type = INSN_JUMP_DYNAMIC; | 460 | *type = INSN_JUMP_DYNAMIC; |
166 | else if (ext == 5) /*jmpf */ | 461 | |
462 | else if (modrm_reg == 5) | ||
463 | |||
464 | /* jmpf */ | ||
167 | *type = INSN_CONTEXT_SWITCH; | 465 | *type = INSN_CONTEXT_SWITCH; |
168 | 466 | ||
467 | else if (modrm_reg == 6) { | ||
468 | |||
469 | /* push from mem */ | ||
470 | *type = INSN_STACK; | ||
471 | op->src.type = OP_SRC_CONST; | ||
472 | op->dest.type = OP_DEST_PUSH; | ||
473 | } | ||
474 | |||
169 | break; | 475 | break; |
170 | 476 | ||
171 | default: | 477 | default: |
@@ -176,3 +482,21 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
176 | 482 | ||
177 | return 0; | 483 | return 0; |
178 | } | 484 | } |
485 | |||
486 | void arch_initial_func_cfi_state(struct cfi_state *state) | ||
487 | { | ||
488 | int i; | ||
489 | |||
490 | for (i = 0; i < CFI_NUM_REGS; i++) { | ||
491 | state->regs[i].base = CFI_UNDEFINED; | ||
492 | state->regs[i].offset = 0; | ||
493 | } | ||
494 | |||
495 | /* initial CFA (call frame address) */ | ||
496 | state->cfa.base = CFI_SP; | ||
497 | state->cfa.offset = 8; | ||
498 | |||
499 | /* initial RA (return address) */ | ||
500 | state->regs[16].base = CFI_CFA; | ||
501 | state->regs[16].offset = -8; | ||
502 | } | ||
diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/insn/x86-opcode-map.txt index 767be7c76034..12e377184ee4 100644 --- a/tools/objtool/arch/x86/insn/x86-opcode-map.txt +++ b/tools/objtool/arch/x86/insn/x86-opcode-map.txt | |||
@@ -1009,7 +1009,7 @@ GrpTable: Grp15 | |||
1009 | 1: fxstor | RDGSBASE Ry (F3),(11B) | 1009 | 1: fxstor | RDGSBASE Ry (F3),(11B) |
1010 | 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) | 1010 | 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) |
1011 | 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) | 1011 | 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) |
1012 | 4: XSAVE | 1012 | 4: XSAVE | ptwrite Ey (F3),(11B) |
1013 | 5: XRSTOR | lfence (11B) | 1013 | 5: XRSTOR | lfence (11B) |
1014 | 6: XSAVEOPT | clwb (66) | mfence (11B) | 1014 | 6: XSAVEOPT | clwb (66) | mfence (11B) |
1015 | 7: clflush | clflushopt (66) | sfence (11B) | 1015 | 7: clflush | clflushopt (66) | sfence (11B) |
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 282a60368b14..365c34ecab26 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> | 2 | * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License | 5 | * modify it under the terms of the GNU General Public License |
@@ -25,1286 +25,32 @@ | |||
25 | * For more information, see tools/objtool/Documentation/stack-validation.txt. | 25 | * For more information, see tools/objtool/Documentation/stack-validation.txt. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <string.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <subcmd/parse-options.h> | 28 | #include <subcmd/parse-options.h> |
31 | |||
32 | #include "builtin.h" | 29 | #include "builtin.h" |
33 | #include "elf.h" | 30 | #include "check.h" |
34 | #include "special.h" | ||
35 | #include "arch.h" | ||
36 | #include "warn.h" | ||
37 | |||
38 | #include <linux/hashtable.h> | ||
39 | #include <linux/kernel.h> | ||
40 | |||
41 | #define STATE_FP_SAVED 0x1 | ||
42 | #define STATE_FP_SETUP 0x2 | ||
43 | #define STATE_FENTRY 0x4 | ||
44 | |||
45 | struct instruction { | ||
46 | struct list_head list; | ||
47 | struct hlist_node hash; | ||
48 | struct section *sec; | ||
49 | unsigned long offset; | ||
50 | unsigned int len, state; | ||
51 | unsigned char type; | ||
52 | unsigned long immediate; | ||
53 | bool alt_group, visited, dead_end; | ||
54 | struct symbol *call_dest; | ||
55 | struct instruction *jump_dest; | ||
56 | struct list_head alts; | ||
57 | struct symbol *func; | ||
58 | }; | ||
59 | |||
60 | struct alternative { | ||
61 | struct list_head list; | ||
62 | struct instruction *insn; | ||
63 | }; | ||
64 | |||
65 | struct objtool_file { | ||
66 | struct elf *elf; | ||
67 | struct list_head insn_list; | ||
68 | DECLARE_HASHTABLE(insn_hash, 16); | ||
69 | struct section *rodata, *whitelist; | ||
70 | bool ignore_unreachables, c_file; | ||
71 | }; | ||
72 | |||
73 | const char *objname; | ||
74 | static bool nofp; | ||
75 | |||
76 | static struct instruction *find_insn(struct objtool_file *file, | ||
77 | struct section *sec, unsigned long offset) | ||
78 | { | ||
79 | struct instruction *insn; | ||
80 | |||
81 | hash_for_each_possible(file->insn_hash, insn, hash, offset) | ||
82 | if (insn->sec == sec && insn->offset == offset) | ||
83 | return insn; | ||
84 | |||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | static struct instruction *next_insn_same_sec(struct objtool_file *file, | ||
89 | struct instruction *insn) | ||
90 | { | ||
91 | struct instruction *next = list_next_entry(insn, list); | ||
92 | |||
93 | if (&next->list == &file->insn_list || next->sec != insn->sec) | ||
94 | return NULL; | ||
95 | |||
96 | return next; | ||
97 | } | ||
98 | |||
99 | static bool gcov_enabled(struct objtool_file *file) | ||
100 | { | ||
101 | struct section *sec; | ||
102 | struct symbol *sym; | ||
103 | |||
104 | list_for_each_entry(sec, &file->elf->sections, list) | ||
105 | list_for_each_entry(sym, &sec->symbol_list, list) | ||
106 | if (!strncmp(sym->name, "__gcov_.", 8)) | ||
107 | return true; | ||
108 | |||
109 | return false; | ||
110 | } | ||
111 | |||
112 | #define for_each_insn(file, insn) \ | ||
113 | list_for_each_entry(insn, &file->insn_list, list) | ||
114 | |||
115 | #define func_for_each_insn(file, func, insn) \ | ||
116 | for (insn = find_insn(file, func->sec, func->offset); \ | ||
117 | insn && &insn->list != &file->insn_list && \ | ||
118 | insn->sec == func->sec && \ | ||
119 | insn->offset < func->offset + func->len; \ | ||
120 | insn = list_next_entry(insn, list)) | ||
121 | |||
122 | #define func_for_each_insn_continue_reverse(file, func, insn) \ | ||
123 | for (insn = list_prev_entry(insn, list); \ | ||
124 | &insn->list != &file->insn_list && \ | ||
125 | insn->sec == func->sec && insn->offset >= func->offset; \ | ||
126 | insn = list_prev_entry(insn, list)) | ||
127 | |||
128 | #define sec_for_each_insn_from(file, insn) \ | ||
129 | for (; insn; insn = next_insn_same_sec(file, insn)) | ||
130 | |||
131 | |||
132 | /* | ||
133 | * Check if the function has been manually whitelisted with the | ||
134 | * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted | ||
135 | * due to its use of a context switching instruction. | ||
136 | */ | ||
137 | static bool ignore_func(struct objtool_file *file, struct symbol *func) | ||
138 | { | ||
139 | struct rela *rela; | ||
140 | struct instruction *insn; | ||
141 | |||
142 | /* check for STACK_FRAME_NON_STANDARD */ | ||
143 | if (file->whitelist && file->whitelist->rela) | ||
144 | list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) { | ||
145 | if (rela->sym->type == STT_SECTION && | ||
146 | rela->sym->sec == func->sec && | ||
147 | rela->addend == func->offset) | ||
148 | return true; | ||
149 | if (rela->sym->type == STT_FUNC && rela->sym == func) | ||
150 | return true; | ||
151 | } | ||
152 | |||
153 | /* check if it has a context switching instruction */ | ||
154 | func_for_each_insn(file, func, insn) | ||
155 | if (insn->type == INSN_CONTEXT_SWITCH) | ||
156 | return true; | ||
157 | |||
158 | return false; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * This checks to see if the given function is a "noreturn" function. | ||
163 | * | ||
164 | * For global functions which are outside the scope of this object file, we | ||
165 | * have to keep a manual list of them. | ||
166 | * | ||
167 | * For local functions, we have to detect them manually by simply looking for | ||
168 | * the lack of a return instruction. | ||
169 | * | ||
170 | * Returns: | ||
171 | * -1: error | ||
172 | * 0: no dead end | ||
173 | * 1: dead end | ||
174 | */ | ||
175 | static int __dead_end_function(struct objtool_file *file, struct symbol *func, | ||
176 | int recursion) | ||
177 | { | ||
178 | int i; | ||
179 | struct instruction *insn; | ||
180 | bool empty = true; | ||
181 | |||
182 | /* | ||
183 | * Unfortunately these have to be hard coded because the noreturn | ||
184 | * attribute isn't provided in ELF data. | ||
185 | */ | ||
186 | static const char * const global_noreturns[] = { | ||
187 | "__stack_chk_fail", | ||
188 | "panic", | ||
189 | "do_exit", | ||
190 | "do_task_dead", | ||
191 | "__module_put_and_exit", | ||
192 | "complete_and_exit", | ||
193 | "kvm_spurious_fault", | ||
194 | "__reiserfs_panic", | ||
195 | "lbug_with_loc" | ||
196 | }; | ||
197 | |||
198 | if (func->bind == STB_WEAK) | ||
199 | return 0; | ||
200 | |||
201 | if (func->bind == STB_GLOBAL) | ||
202 | for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) | ||
203 | if (!strcmp(func->name, global_noreturns[i])) | ||
204 | return 1; | ||
205 | |||
206 | if (!func->sec) | ||
207 | return 0; | ||
208 | |||
209 | func_for_each_insn(file, func, insn) { | ||
210 | empty = false; | ||
211 | |||
212 | if (insn->type == INSN_RETURN) | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | if (empty) | ||
217 | return 0; | ||
218 | |||
219 | /* | ||
220 | * A function can have a sibling call instead of a return. In that | ||
221 | * case, the function's dead-end status depends on whether the target | ||
222 | * of the sibling call returns. | ||
223 | */ | ||
224 | func_for_each_insn(file, func, insn) { | ||
225 | if (insn->sec != func->sec || | ||
226 | insn->offset >= func->offset + func->len) | ||
227 | break; | ||
228 | |||
229 | if (insn->type == INSN_JUMP_UNCONDITIONAL) { | ||
230 | struct instruction *dest = insn->jump_dest; | ||
231 | struct symbol *dest_func; | ||
232 | |||
233 | if (!dest) | ||
234 | /* sibling call to another file */ | ||
235 | return 0; | ||
236 | |||
237 | if (dest->sec != func->sec || | ||
238 | dest->offset < func->offset || | ||
239 | dest->offset >= func->offset + func->len) { | ||
240 | /* local sibling call */ | ||
241 | dest_func = find_symbol_by_offset(dest->sec, | ||
242 | dest->offset); | ||
243 | if (!dest_func) | ||
244 | continue; | ||
245 | |||
246 | if (recursion == 5) { | ||
247 | WARN_FUNC("infinite recursion (objtool bug!)", | ||
248 | dest->sec, dest->offset); | ||
249 | return -1; | ||
250 | } | ||
251 | |||
252 | return __dead_end_function(file, dest_func, | ||
253 | recursion + 1); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) | ||
258 | /* sibling call */ | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | return 1; | ||
263 | } | ||
264 | |||
265 | static int dead_end_function(struct objtool_file *file, struct symbol *func) | ||
266 | { | ||
267 | return __dead_end_function(file, func, 0); | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Call the arch-specific instruction decoder for all the instructions and add | ||
272 | * them to the global instruction list. | ||
273 | */ | ||
274 | static int decode_instructions(struct objtool_file *file) | ||
275 | { | ||
276 | struct section *sec; | ||
277 | struct symbol *func; | ||
278 | unsigned long offset; | ||
279 | struct instruction *insn; | ||
280 | int ret; | ||
281 | |||
282 | list_for_each_entry(sec, &file->elf->sections, list) { | ||
283 | |||
284 | if (!(sec->sh.sh_flags & SHF_EXECINSTR)) | ||
285 | continue; | ||
286 | |||
287 | for (offset = 0; offset < sec->len; offset += insn->len) { | ||
288 | insn = malloc(sizeof(*insn)); | ||
289 | memset(insn, 0, sizeof(*insn)); | ||
290 | |||
291 | INIT_LIST_HEAD(&insn->alts); | ||
292 | insn->sec = sec; | ||
293 | insn->offset = offset; | ||
294 | |||
295 | ret = arch_decode_instruction(file->elf, sec, offset, | ||
296 | sec->len - offset, | ||
297 | &insn->len, &insn->type, | ||
298 | &insn->immediate); | ||
299 | if (ret) | ||
300 | return ret; | ||
301 | |||
302 | if (!insn->type || insn->type > INSN_LAST) { | ||
303 | WARN_FUNC("invalid instruction type %d", | ||
304 | insn->sec, insn->offset, insn->type); | ||
305 | return -1; | ||
306 | } | ||
307 | |||
308 | hash_add(file->insn_hash, &insn->hash, insn->offset); | ||
309 | list_add_tail(&insn->list, &file->insn_list); | ||
310 | } | ||
311 | |||
312 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
313 | if (func->type != STT_FUNC) | ||
314 | continue; | ||
315 | |||
316 | if (!find_insn(file, sec, func->offset)) { | ||
317 | WARN("%s(): can't find starting instruction", | ||
318 | func->name); | ||
319 | return -1; | ||
320 | } | ||
321 | |||
322 | func_for_each_insn(file, func, insn) | ||
323 | if (!insn->func) | ||
324 | insn->func = func; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Find all uses of the unreachable() macro, which are code path dead ends. | ||
333 | */ | ||
334 | static int add_dead_ends(struct objtool_file *file) | ||
335 | { | ||
336 | struct section *sec; | ||
337 | struct rela *rela; | ||
338 | struct instruction *insn; | ||
339 | bool found; | ||
340 | |||
341 | sec = find_section_by_name(file->elf, ".rela.discard.unreachable"); | ||
342 | if (!sec) | ||
343 | return 0; | ||
344 | |||
345 | list_for_each_entry(rela, &sec->rela_list, list) { | ||
346 | if (rela->sym->type != STT_SECTION) { | ||
347 | WARN("unexpected relocation symbol type in %s", sec->name); | ||
348 | return -1; | ||
349 | } | ||
350 | insn = find_insn(file, rela->sym->sec, rela->addend); | ||
351 | if (insn) | ||
352 | insn = list_prev_entry(insn, list); | ||
353 | else if (rela->addend == rela->sym->sec->len) { | ||
354 | found = false; | ||
355 | list_for_each_entry_reverse(insn, &file->insn_list, list) { | ||
356 | if (insn->sec == rela->sym->sec) { | ||
357 | found = true; | ||
358 | break; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | if (!found) { | ||
363 | WARN("can't find unreachable insn at %s+0x%x", | ||
364 | rela->sym->sec->name, rela->addend); | ||
365 | return -1; | ||
366 | } | ||
367 | } else { | ||
368 | WARN("can't find unreachable insn at %s+0x%x", | ||
369 | rela->sym->sec->name, rela->addend); | ||
370 | return -1; | ||
371 | } | ||
372 | |||
373 | insn->dead_end = true; | ||
374 | } | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * Warnings shouldn't be reported for ignored functions. | ||
381 | */ | ||
382 | static void add_ignores(struct objtool_file *file) | ||
383 | { | ||
384 | struct instruction *insn; | ||
385 | struct section *sec; | ||
386 | struct symbol *func; | ||
387 | |||
388 | list_for_each_entry(sec, &file->elf->sections, list) { | ||
389 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
390 | if (func->type != STT_FUNC) | ||
391 | continue; | ||
392 | |||
393 | if (!ignore_func(file, func)) | ||
394 | continue; | ||
395 | |||
396 | func_for_each_insn(file, func, insn) | ||
397 | insn->visited = true; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Find the destination instructions for all jumps. | ||
404 | */ | ||
405 | static int add_jump_destinations(struct objtool_file *file) | ||
406 | { | ||
407 | struct instruction *insn; | ||
408 | struct rela *rela; | ||
409 | struct section *dest_sec; | ||
410 | unsigned long dest_off; | ||
411 | |||
412 | for_each_insn(file, insn) { | ||
413 | if (insn->type != INSN_JUMP_CONDITIONAL && | ||
414 | insn->type != INSN_JUMP_UNCONDITIONAL) | ||
415 | continue; | ||
416 | |||
417 | /* skip ignores */ | ||
418 | if (insn->visited) | ||
419 | continue; | ||
420 | |||
421 | rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
422 | insn->len); | ||
423 | if (!rela) { | ||
424 | dest_sec = insn->sec; | ||
425 | dest_off = insn->offset + insn->len + insn->immediate; | ||
426 | } else if (rela->sym->type == STT_SECTION) { | ||
427 | dest_sec = rela->sym->sec; | ||
428 | dest_off = rela->addend + 4; | ||
429 | } else if (rela->sym->sec->idx) { | ||
430 | dest_sec = rela->sym->sec; | ||
431 | dest_off = rela->sym->sym.st_value + rela->addend + 4; | ||
432 | } else { | ||
433 | /* sibling call */ | ||
434 | insn->jump_dest = 0; | ||
435 | continue; | ||
436 | } | ||
437 | |||
438 | insn->jump_dest = find_insn(file, dest_sec, dest_off); | ||
439 | if (!insn->jump_dest) { | ||
440 | |||
441 | /* | ||
442 | * This is a special case where an alt instruction | ||
443 | * jumps past the end of the section. These are | ||
444 | * handled later in handle_group_alt(). | ||
445 | */ | ||
446 | if (!strcmp(insn->sec->name, ".altinstr_replacement")) | ||
447 | continue; | ||
448 | |||
449 | WARN_FUNC("can't find jump dest instruction at %s+0x%lx", | ||
450 | insn->sec, insn->offset, dest_sec->name, | ||
451 | dest_off); | ||
452 | return -1; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * Find the destination instructions for all calls. | ||
461 | */ | ||
462 | static int add_call_destinations(struct objtool_file *file) | ||
463 | { | ||
464 | struct instruction *insn; | ||
465 | unsigned long dest_off; | ||
466 | struct rela *rela; | ||
467 | |||
468 | for_each_insn(file, insn) { | ||
469 | if (insn->type != INSN_CALL) | ||
470 | continue; | ||
471 | |||
472 | rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
473 | insn->len); | ||
474 | if (!rela) { | ||
475 | dest_off = insn->offset + insn->len + insn->immediate; | ||
476 | insn->call_dest = find_symbol_by_offset(insn->sec, | ||
477 | dest_off); | ||
478 | if (!insn->call_dest) { | ||
479 | WARN_FUNC("can't find call dest symbol at offset 0x%lx", | ||
480 | insn->sec, insn->offset, dest_off); | ||
481 | return -1; | ||
482 | } | ||
483 | } else if (rela->sym->type == STT_SECTION) { | ||
484 | insn->call_dest = find_symbol_by_offset(rela->sym->sec, | ||
485 | rela->addend+4); | ||
486 | if (!insn->call_dest || | ||
487 | insn->call_dest->type != STT_FUNC) { | ||
488 | WARN_FUNC("can't find call dest symbol at %s+0x%x", | ||
489 | insn->sec, insn->offset, | ||
490 | rela->sym->sec->name, | ||
491 | rela->addend + 4); | ||
492 | return -1; | ||
493 | } | ||
494 | } else | ||
495 | insn->call_dest = rela->sym; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | * The .alternatives section requires some extra special care, over and above | ||
503 | * what other special sections require: | ||
504 | * | ||
505 | * 1. Because alternatives are patched in-place, we need to insert a fake jump | ||
506 | * instruction at the end so that validate_branch() skips all the original | ||
507 | * replaced instructions when validating the new instruction path. | ||
508 | * | ||
509 | * 2. An added wrinkle is that the new instruction length might be zero. In | ||
510 | * that case the old instructions are replaced with noops. We simulate that | ||
511 | * by creating a fake jump as the only new instruction. | ||
512 | * | ||
513 | * 3. In some cases, the alternative section includes an instruction which | ||
514 | * conditionally jumps to the _end_ of the entry. We have to modify these | ||
515 | * jumps' destinations to point back to .text rather than the end of the | ||
516 | * entry in .altinstr_replacement. | ||
517 | * | ||
518 | * 4. It has been requested that we don't validate the !POPCNT feature path | ||
519 | * which is a "very very small percentage of machines". | ||
520 | */ | ||
521 | static int handle_group_alt(struct objtool_file *file, | ||
522 | struct special_alt *special_alt, | ||
523 | struct instruction *orig_insn, | ||
524 | struct instruction **new_insn) | ||
525 | { | ||
526 | struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; | ||
527 | unsigned long dest_off; | ||
528 | |||
529 | last_orig_insn = NULL; | ||
530 | insn = orig_insn; | ||
531 | sec_for_each_insn_from(file, insn) { | ||
532 | if (insn->offset >= special_alt->orig_off + special_alt->orig_len) | ||
533 | break; | ||
534 | |||
535 | if (special_alt->skip_orig) | ||
536 | insn->type = INSN_NOP; | ||
537 | |||
538 | insn->alt_group = true; | ||
539 | last_orig_insn = insn; | ||
540 | } | ||
541 | |||
542 | if (!next_insn_same_sec(file, last_orig_insn)) { | ||
543 | WARN("%s: don't know how to handle alternatives at end of section", | ||
544 | special_alt->orig_sec->name); | ||
545 | return -1; | ||
546 | } | ||
547 | |||
548 | fake_jump = malloc(sizeof(*fake_jump)); | ||
549 | if (!fake_jump) { | ||
550 | WARN("malloc failed"); | ||
551 | return -1; | ||
552 | } | ||
553 | memset(fake_jump, 0, sizeof(*fake_jump)); | ||
554 | INIT_LIST_HEAD(&fake_jump->alts); | ||
555 | fake_jump->sec = special_alt->new_sec; | ||
556 | fake_jump->offset = -1; | ||
557 | fake_jump->type = INSN_JUMP_UNCONDITIONAL; | ||
558 | fake_jump->jump_dest = list_next_entry(last_orig_insn, list); | ||
559 | |||
560 | if (!special_alt->new_len) { | ||
561 | *new_insn = fake_jump; | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | last_new_insn = NULL; | ||
566 | insn = *new_insn; | ||
567 | sec_for_each_insn_from(file, insn) { | ||
568 | if (insn->offset >= special_alt->new_off + special_alt->new_len) | ||
569 | break; | ||
570 | |||
571 | last_new_insn = insn; | ||
572 | |||
573 | if (insn->type != INSN_JUMP_CONDITIONAL && | ||
574 | insn->type != INSN_JUMP_UNCONDITIONAL) | ||
575 | continue; | ||
576 | |||
577 | if (!insn->immediate) | ||
578 | continue; | ||
579 | |||
580 | dest_off = insn->offset + insn->len + insn->immediate; | ||
581 | if (dest_off == special_alt->new_off + special_alt->new_len) | ||
582 | insn->jump_dest = fake_jump; | ||
583 | |||
584 | if (!insn->jump_dest) { | ||
585 | WARN_FUNC("can't find alternative jump destination", | ||
586 | insn->sec, insn->offset); | ||
587 | return -1; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | if (!last_new_insn) { | ||
592 | WARN_FUNC("can't find last new alternative instruction", | ||
593 | special_alt->new_sec, special_alt->new_off); | ||
594 | return -1; | ||
595 | } | ||
596 | |||
597 | list_add(&fake_jump->list, &last_new_insn->list); | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * A jump table entry can either convert a nop to a jump or a jump to a nop. | ||
604 | * If the original instruction is a jump, make the alt entry an effective nop | ||
605 | * by just skipping the original instruction. | ||
606 | */ | ||
607 | static int handle_jump_alt(struct objtool_file *file, | ||
608 | struct special_alt *special_alt, | ||
609 | struct instruction *orig_insn, | ||
610 | struct instruction **new_insn) | ||
611 | { | ||
612 | if (orig_insn->type == INSN_NOP) | ||
613 | return 0; | ||
614 | |||
615 | if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { | ||
616 | WARN_FUNC("unsupported instruction at jump label", | ||
617 | orig_insn->sec, orig_insn->offset); | ||
618 | return -1; | ||
619 | } | ||
620 | |||
621 | *new_insn = list_next_entry(orig_insn, list); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | /* | ||
626 | * Read all the special sections which have alternate instructions which can be | ||
627 | * patched in or redirected to at runtime. Each instruction having alternate | ||
628 | * instruction(s) has them added to its insn->alts list, which will be | ||
629 | * traversed in validate_branch(). | ||
630 | */ | ||
631 | static int add_special_section_alts(struct objtool_file *file) | ||
632 | { | ||
633 | struct list_head special_alts; | ||
634 | struct instruction *orig_insn, *new_insn; | ||
635 | struct special_alt *special_alt, *tmp; | ||
636 | struct alternative *alt; | ||
637 | int ret; | ||
638 | |||
639 | ret = special_get_alts(file->elf, &special_alts); | ||
640 | if (ret) | ||
641 | return ret; | ||
642 | |||
643 | list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { | ||
644 | alt = malloc(sizeof(*alt)); | ||
645 | if (!alt) { | ||
646 | WARN("malloc failed"); | ||
647 | ret = -1; | ||
648 | goto out; | ||
649 | } | ||
650 | |||
651 | orig_insn = find_insn(file, special_alt->orig_sec, | ||
652 | special_alt->orig_off); | ||
653 | if (!orig_insn) { | ||
654 | WARN_FUNC("special: can't find orig instruction", | ||
655 | special_alt->orig_sec, special_alt->orig_off); | ||
656 | ret = -1; | ||
657 | goto out; | ||
658 | } | ||
659 | 31 | ||
660 | new_insn = NULL; | 32 | bool nofp; |
661 | if (!special_alt->group || special_alt->new_len) { | ||
662 | new_insn = find_insn(file, special_alt->new_sec, | ||
663 | special_alt->new_off); | ||
664 | if (!new_insn) { | ||
665 | WARN_FUNC("special: can't find new instruction", | ||
666 | special_alt->new_sec, | ||
667 | special_alt->new_off); | ||
668 | ret = -1; | ||
669 | goto out; | ||
670 | } | ||
671 | } | ||
672 | 33 | ||
673 | if (special_alt->group) { | 34 | static const char * const check_usage[] = { |
674 | ret = handle_group_alt(file, special_alt, orig_insn, | ||
675 | &new_insn); | ||
676 | if (ret) | ||
677 | goto out; | ||
678 | } else if (special_alt->jump_or_nop) { | ||
679 | ret = handle_jump_alt(file, special_alt, orig_insn, | ||
680 | &new_insn); | ||
681 | if (ret) | ||
682 | goto out; | ||
683 | } | ||
684 | |||
685 | alt->insn = new_insn; | ||
686 | list_add_tail(&alt->list, &orig_insn->alts); | ||
687 | |||
688 | list_del(&special_alt->list); | ||
689 | free(special_alt); | ||
690 | } | ||
691 | |||
692 | out: | ||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | static int add_switch_table(struct objtool_file *file, struct symbol *func, | ||
697 | struct instruction *insn, struct rela *table, | ||
698 | struct rela *next_table) | ||
699 | { | ||
700 | struct rela *rela = table; | ||
701 | struct instruction *alt_insn; | ||
702 | struct alternative *alt; | ||
703 | |||
704 | list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { | ||
705 | if (rela == next_table) | ||
706 | break; | ||
707 | |||
708 | if (rela->sym->sec != insn->sec || | ||
709 | rela->addend <= func->offset || | ||
710 | rela->addend >= func->offset + func->len) | ||
711 | break; | ||
712 | |||
713 | alt_insn = find_insn(file, insn->sec, rela->addend); | ||
714 | if (!alt_insn) { | ||
715 | WARN("%s: can't find instruction at %s+0x%x", | ||
716 | file->rodata->rela->name, insn->sec->name, | ||
717 | rela->addend); | ||
718 | return -1; | ||
719 | } | ||
720 | |||
721 | alt = malloc(sizeof(*alt)); | ||
722 | if (!alt) { | ||
723 | WARN("malloc failed"); | ||
724 | return -1; | ||
725 | } | ||
726 | |||
727 | alt->insn = alt_insn; | ||
728 | list_add_tail(&alt->list, &insn->alts); | ||
729 | } | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | /* | ||
735 | * find_switch_table() - Given a dynamic jump, find the switch jump table in | ||
736 | * .rodata associated with it. | ||
737 | * | ||
738 | * There are 3 basic patterns: | ||
739 | * | ||
740 | * 1. jmpq *[rodata addr](,%reg,8) | ||
741 | * | ||
742 | * This is the most common case by far. It jumps to an address in a simple | ||
743 | * jump table which is stored in .rodata. | ||
744 | * | ||
745 | * 2. jmpq *[rodata addr](%rip) | ||
746 | * | ||
747 | * This is caused by a rare GCC quirk, currently only seen in three driver | ||
748 | * functions in the kernel, only with certain obscure non-distro configs. | ||
749 | * | ||
750 | * As part of an optimization, GCC makes a copy of an existing switch jump | ||
751 | * table, modifies it, and then hard-codes the jump (albeit with an indirect | ||
752 | * jump) to use a single entry in the table. The rest of the jump table and | ||
753 | * some of its jump targets remain as dead code. | ||
754 | * | ||
755 | * In such a case we can just crudely ignore all unreachable instruction | ||
756 | * warnings for the entire object file. Ideally we would just ignore them | ||
757 | * for the function, but that would require redesigning the code quite a | ||
758 | * bit. And honestly that's just not worth doing: unreachable instruction | ||
759 | * warnings are of questionable value anyway, and this is such a rare issue. | ||
760 | * | ||
761 | * 3. mov [rodata addr],%reg1 | ||
762 | * ... some instructions ... | ||
763 | * jmpq *(%reg1,%reg2,8) | ||
764 | * | ||
765 | * This is a fairly uncommon pattern which is new for GCC 6. As of this | ||
766 | * writing, there are 11 occurrences of it in the allmodconfig kernel. | ||
767 | * | ||
768 | * TODO: Once we have DWARF CFI and smarter instruction decoding logic, | ||
769 | * ensure the same register is used in the mov and jump instructions. | ||
770 | */ | ||
771 | static struct rela *find_switch_table(struct objtool_file *file, | ||
772 | struct symbol *func, | ||
773 | struct instruction *insn) | ||
774 | { | ||
775 | struct rela *text_rela, *rodata_rela; | ||
776 | struct instruction *orig_insn = insn; | ||
777 | |||
778 | text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); | ||
779 | if (text_rela && text_rela->sym == file->rodata->sym) { | ||
780 | /* case 1 */ | ||
781 | rodata_rela = find_rela_by_dest(file->rodata, | ||
782 | text_rela->addend); | ||
783 | if (rodata_rela) | ||
784 | return rodata_rela; | ||
785 | |||
786 | /* case 2 */ | ||
787 | rodata_rela = find_rela_by_dest(file->rodata, | ||
788 | text_rela->addend + 4); | ||
789 | if (!rodata_rela) | ||
790 | return NULL; | ||
791 | file->ignore_unreachables = true; | ||
792 | return rodata_rela; | ||
793 | } | ||
794 | |||
795 | /* case 3 */ | ||
796 | func_for_each_insn_continue_reverse(file, func, insn) { | ||
797 | if (insn->type == INSN_JUMP_DYNAMIC) | ||
798 | break; | ||
799 | |||
800 | /* allow small jumps within the range */ | ||
801 | if (insn->type == INSN_JUMP_UNCONDITIONAL && | ||
802 | insn->jump_dest && | ||
803 | (insn->jump_dest->offset <= insn->offset || | ||
804 | insn->jump_dest->offset > orig_insn->offset)) | ||
805 | break; | ||
806 | |||
807 | /* look for a relocation which references .rodata */ | ||
808 | text_rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
809 | insn->len); | ||
810 | if (!text_rela || text_rela->sym != file->rodata->sym) | ||
811 | continue; | ||
812 | |||
813 | /* | ||
814 | * Make sure the .rodata address isn't associated with a | ||
815 | * symbol. gcc jump tables are anonymous data. | ||
816 | */ | ||
817 | if (find_symbol_containing(file->rodata, text_rela->addend)) | ||
818 | continue; | ||
819 | |||
820 | return find_rela_by_dest(file->rodata, text_rela->addend); | ||
821 | } | ||
822 | |||
823 | return NULL; | ||
824 | } | ||
825 | |||
826 | static int add_func_switch_tables(struct objtool_file *file, | ||
827 | struct symbol *func) | ||
828 | { | ||
829 | struct instruction *insn, *prev_jump = NULL; | ||
830 | struct rela *rela, *prev_rela = NULL; | ||
831 | int ret; | ||
832 | |||
833 | func_for_each_insn(file, func, insn) { | ||
834 | if (insn->type != INSN_JUMP_DYNAMIC) | ||
835 | continue; | ||
836 | |||
837 | rela = find_switch_table(file, func, insn); | ||
838 | if (!rela) | ||
839 | continue; | ||
840 | |||
841 | /* | ||
842 | * We found a switch table, but we don't know yet how big it | ||
843 | * is. Don't add it until we reach the end of the function or | ||
844 | * the beginning of another switch table in the same function. | ||
845 | */ | ||
846 | if (prev_jump) { | ||
847 | ret = add_switch_table(file, func, prev_jump, prev_rela, | ||
848 | rela); | ||
849 | if (ret) | ||
850 | return ret; | ||
851 | } | ||
852 | |||
853 | prev_jump = insn; | ||
854 | prev_rela = rela; | ||
855 | } | ||
856 | |||
857 | if (prev_jump) { | ||
858 | ret = add_switch_table(file, func, prev_jump, prev_rela, NULL); | ||
859 | if (ret) | ||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | /* | ||
867 | * For some switch statements, gcc generates a jump table in the .rodata | ||
868 | * section which contains a list of addresses within the function to jump to. | ||
869 | * This finds these jump tables and adds them to the insn->alts lists. | ||
870 | */ | ||
871 | static int add_switch_table_alts(struct objtool_file *file) | ||
872 | { | ||
873 | struct section *sec; | ||
874 | struct symbol *func; | ||
875 | int ret; | ||
876 | |||
877 | if (!file->rodata || !file->rodata->rela) | ||
878 | return 0; | ||
879 | |||
880 | list_for_each_entry(sec, &file->elf->sections, list) { | ||
881 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
882 | if (func->type != STT_FUNC) | ||
883 | continue; | ||
884 | |||
885 | ret = add_func_switch_tables(file, func); | ||
886 | if (ret) | ||
887 | return ret; | ||
888 | } | ||
889 | } | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int decode_sections(struct objtool_file *file) | ||
895 | { | ||
896 | int ret; | ||
897 | |||
898 | ret = decode_instructions(file); | ||
899 | if (ret) | ||
900 | return ret; | ||
901 | |||
902 | ret = add_dead_ends(file); | ||
903 | if (ret) | ||
904 | return ret; | ||
905 | |||
906 | add_ignores(file); | ||
907 | |||
908 | ret = add_jump_destinations(file); | ||
909 | if (ret) | ||
910 | return ret; | ||
911 | |||
912 | ret = add_call_destinations(file); | ||
913 | if (ret) | ||
914 | return ret; | ||
915 | |||
916 | ret = add_special_section_alts(file); | ||
917 | if (ret) | ||
918 | return ret; | ||
919 | |||
920 | ret = add_switch_table_alts(file); | ||
921 | if (ret) | ||
922 | return ret; | ||
923 | |||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static bool is_fentry_call(struct instruction *insn) | ||
928 | { | ||
929 | if (insn->type == INSN_CALL && | ||
930 | insn->call_dest->type == STT_NOTYPE && | ||
931 | !strcmp(insn->call_dest->name, "__fentry__")) | ||
932 | return true; | ||
933 | |||
934 | return false; | ||
935 | } | ||
936 | |||
937 | static bool has_modified_stack_frame(struct instruction *insn) | ||
938 | { | ||
939 | return (insn->state & STATE_FP_SAVED) || | ||
940 | (insn->state & STATE_FP_SETUP); | ||
941 | } | ||
942 | |||
943 | static bool has_valid_stack_frame(struct instruction *insn) | ||
944 | { | ||
945 | return (insn->state & STATE_FP_SAVED) && | ||
946 | (insn->state & STATE_FP_SETUP); | ||
947 | } | ||
948 | |||
949 | static unsigned int frame_state(unsigned long state) | ||
950 | { | ||
951 | return (state & (STATE_FP_SAVED | STATE_FP_SETUP)); | ||
952 | } | ||
953 | |||
954 | /* | ||
955 | * Follow the branch starting at the given instruction, and recursively follow | ||
956 | * any other branches (jumps). Meanwhile, track the frame pointer state at | ||
957 | * each instruction and validate all the rules described in | ||
958 | * tools/objtool/Documentation/stack-validation.txt. | ||
959 | */ | ||
960 | static int validate_branch(struct objtool_file *file, | ||
961 | struct instruction *first, unsigned char first_state) | ||
962 | { | ||
963 | struct alternative *alt; | ||
964 | struct instruction *insn; | ||
965 | struct section *sec; | ||
966 | struct symbol *func = NULL; | ||
967 | unsigned char state; | ||
968 | int ret; | ||
969 | |||
970 | insn = first; | ||
971 | sec = insn->sec; | ||
972 | state = first_state; | ||
973 | |||
974 | if (insn->alt_group && list_empty(&insn->alts)) { | ||
975 | WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", | ||
976 | sec, insn->offset); | ||
977 | return 1; | ||
978 | } | ||
979 | |||
980 | while (1) { | ||
981 | if (file->c_file && insn->func) { | ||
982 | if (func && func != insn->func) { | ||
983 | WARN("%s() falls through to next function %s()", | ||
984 | func->name, insn->func->name); | ||
985 | return 1; | ||
986 | } | ||
987 | |||
988 | func = insn->func; | ||
989 | } | ||
990 | |||
991 | if (insn->visited) { | ||
992 | if (frame_state(insn->state) != frame_state(state)) { | ||
993 | WARN_FUNC("frame pointer state mismatch", | ||
994 | sec, insn->offset); | ||
995 | return 1; | ||
996 | } | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | insn->visited = true; | ||
1002 | insn->state = state; | ||
1003 | |||
1004 | list_for_each_entry(alt, &insn->alts, list) { | ||
1005 | ret = validate_branch(file, alt->insn, state); | ||
1006 | if (ret) | ||
1007 | return 1; | ||
1008 | } | ||
1009 | |||
1010 | switch (insn->type) { | ||
1011 | |||
1012 | case INSN_FP_SAVE: | ||
1013 | if (!nofp) { | ||
1014 | if (state & STATE_FP_SAVED) { | ||
1015 | WARN_FUNC("duplicate frame pointer save", | ||
1016 | sec, insn->offset); | ||
1017 | return 1; | ||
1018 | } | ||
1019 | state |= STATE_FP_SAVED; | ||
1020 | } | ||
1021 | break; | ||
1022 | |||
1023 | case INSN_FP_SETUP: | ||
1024 | if (!nofp) { | ||
1025 | if (state & STATE_FP_SETUP) { | ||
1026 | WARN_FUNC("duplicate frame pointer setup", | ||
1027 | sec, insn->offset); | ||
1028 | return 1; | ||
1029 | } | ||
1030 | state |= STATE_FP_SETUP; | ||
1031 | } | ||
1032 | break; | ||
1033 | |||
1034 | case INSN_FP_RESTORE: | ||
1035 | if (!nofp) { | ||
1036 | if (has_valid_stack_frame(insn)) | ||
1037 | state &= ~STATE_FP_SETUP; | ||
1038 | |||
1039 | state &= ~STATE_FP_SAVED; | ||
1040 | } | ||
1041 | break; | ||
1042 | |||
1043 | case INSN_RETURN: | ||
1044 | if (!nofp && has_modified_stack_frame(insn)) { | ||
1045 | WARN_FUNC("return without frame pointer restore", | ||
1046 | sec, insn->offset); | ||
1047 | return 1; | ||
1048 | } | ||
1049 | return 0; | ||
1050 | |||
1051 | case INSN_CALL: | ||
1052 | if (is_fentry_call(insn)) { | ||
1053 | state |= STATE_FENTRY; | ||
1054 | break; | ||
1055 | } | ||
1056 | |||
1057 | ret = dead_end_function(file, insn->call_dest); | ||
1058 | if (ret == 1) | ||
1059 | return 0; | ||
1060 | if (ret == -1) | ||
1061 | return 1; | ||
1062 | |||
1063 | /* fallthrough */ | ||
1064 | case INSN_CALL_DYNAMIC: | ||
1065 | if (!nofp && !has_valid_stack_frame(insn)) { | ||
1066 | WARN_FUNC("call without frame pointer save/setup", | ||
1067 | sec, insn->offset); | ||
1068 | return 1; | ||
1069 | } | ||
1070 | break; | ||
1071 | |||
1072 | case INSN_JUMP_CONDITIONAL: | ||
1073 | case INSN_JUMP_UNCONDITIONAL: | ||
1074 | if (insn->jump_dest) { | ||
1075 | ret = validate_branch(file, insn->jump_dest, | ||
1076 | state); | ||
1077 | if (ret) | ||
1078 | return 1; | ||
1079 | } else if (has_modified_stack_frame(insn)) { | ||
1080 | WARN_FUNC("sibling call from callable instruction with changed frame pointer", | ||
1081 | sec, insn->offset); | ||
1082 | return 1; | ||
1083 | } /* else it's a sibling call */ | ||
1084 | |||
1085 | if (insn->type == INSN_JUMP_UNCONDITIONAL) | ||
1086 | return 0; | ||
1087 | |||
1088 | break; | ||
1089 | |||
1090 | case INSN_JUMP_DYNAMIC: | ||
1091 | if (list_empty(&insn->alts) && | ||
1092 | has_modified_stack_frame(insn)) { | ||
1093 | WARN_FUNC("sibling call from callable instruction with changed frame pointer", | ||
1094 | sec, insn->offset); | ||
1095 | return 1; | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1099 | |||
1100 | default: | ||
1101 | break; | ||
1102 | } | ||
1103 | |||
1104 | if (insn->dead_end) | ||
1105 | return 0; | ||
1106 | |||
1107 | insn = next_insn_same_sec(file, insn); | ||
1108 | if (!insn) { | ||
1109 | WARN("%s: unexpected end of section", sec->name); | ||
1110 | return 1; | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | static bool is_kasan_insn(struct instruction *insn) | ||
1118 | { | ||
1119 | return (insn->type == INSN_CALL && | ||
1120 | !strcmp(insn->call_dest->name, "__asan_handle_no_return")); | ||
1121 | } | ||
1122 | |||
1123 | static bool is_ubsan_insn(struct instruction *insn) | ||
1124 | { | ||
1125 | return (insn->type == INSN_CALL && | ||
1126 | !strcmp(insn->call_dest->name, | ||
1127 | "__ubsan_handle_builtin_unreachable")); | ||
1128 | } | ||
1129 | |||
1130 | static bool ignore_unreachable_insn(struct symbol *func, | ||
1131 | struct instruction *insn) | ||
1132 | { | ||
1133 | int i; | ||
1134 | |||
1135 | if (insn->type == INSN_NOP) | ||
1136 | return true; | ||
1137 | |||
1138 | /* | ||
1139 | * Check if this (or a subsequent) instruction is related to | ||
1140 | * CONFIG_UBSAN or CONFIG_KASAN. | ||
1141 | * | ||
1142 | * End the search at 5 instructions to avoid going into the weeds. | ||
1143 | */ | ||
1144 | for (i = 0; i < 5; i++) { | ||
1145 | |||
1146 | if (is_kasan_insn(insn) || is_ubsan_insn(insn)) | ||
1147 | return true; | ||
1148 | |||
1149 | if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { | ||
1150 | insn = insn->jump_dest; | ||
1151 | continue; | ||
1152 | } | ||
1153 | |||
1154 | if (insn->offset + insn->len >= func->offset + func->len) | ||
1155 | break; | ||
1156 | insn = list_next_entry(insn, list); | ||
1157 | } | ||
1158 | |||
1159 | return false; | ||
1160 | } | ||
1161 | |||
1162 | static int validate_functions(struct objtool_file *file) | ||
1163 | { | ||
1164 | struct section *sec; | ||
1165 | struct symbol *func; | ||
1166 | struct instruction *insn; | ||
1167 | int ret, warnings = 0; | ||
1168 | |||
1169 | list_for_each_entry(sec, &file->elf->sections, list) { | ||
1170 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
1171 | if (func->type != STT_FUNC) | ||
1172 | continue; | ||
1173 | |||
1174 | insn = find_insn(file, sec, func->offset); | ||
1175 | if (!insn) | ||
1176 | continue; | ||
1177 | |||
1178 | ret = validate_branch(file, insn, 0); | ||
1179 | warnings += ret; | ||
1180 | } | ||
1181 | } | ||
1182 | |||
1183 | list_for_each_entry(sec, &file->elf->sections, list) { | ||
1184 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
1185 | if (func->type != STT_FUNC) | ||
1186 | continue; | ||
1187 | |||
1188 | func_for_each_insn(file, func, insn) { | ||
1189 | if (insn->visited) | ||
1190 | continue; | ||
1191 | |||
1192 | insn->visited = true; | ||
1193 | |||
1194 | if (file->ignore_unreachables || warnings || | ||
1195 | ignore_unreachable_insn(func, insn)) | ||
1196 | continue; | ||
1197 | |||
1198 | /* | ||
1199 | * gcov produces a lot of unreachable | ||
1200 | * instructions. If we get an unreachable | ||
1201 | * warning and the file has gcov enabled, just | ||
1202 | * ignore it, and all other such warnings for | ||
1203 | * the file. | ||
1204 | */ | ||
1205 | if (!file->ignore_unreachables && | ||
1206 | gcov_enabled(file)) { | ||
1207 | file->ignore_unreachables = true; | ||
1208 | continue; | ||
1209 | } | ||
1210 | |||
1211 | WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); | ||
1212 | warnings++; | ||
1213 | } | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | return warnings; | ||
1218 | } | ||
1219 | |||
1220 | static int validate_uncallable_instructions(struct objtool_file *file) | ||
1221 | { | ||
1222 | struct instruction *insn; | ||
1223 | int warnings = 0; | ||
1224 | |||
1225 | for_each_insn(file, insn) { | ||
1226 | if (!insn->visited && insn->type == INSN_RETURN) { | ||
1227 | WARN_FUNC("return instruction outside of a callable function", | ||
1228 | insn->sec, insn->offset); | ||
1229 | warnings++; | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | return warnings; | ||
1234 | } | ||
1235 | |||
1236 | static void cleanup(struct objtool_file *file) | ||
1237 | { | ||
1238 | struct instruction *insn, *tmpinsn; | ||
1239 | struct alternative *alt, *tmpalt; | ||
1240 | |||
1241 | list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { | ||
1242 | list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { | ||
1243 | list_del(&alt->list); | ||
1244 | free(alt); | ||
1245 | } | ||
1246 | list_del(&insn->list); | ||
1247 | hash_del(&insn->hash); | ||
1248 | free(insn); | ||
1249 | } | ||
1250 | elf_close(file->elf); | ||
1251 | } | ||
1252 | |||
1253 | const char * const check_usage[] = { | ||
1254 | "objtool check [<options>] file.o", | 35 | "objtool check [<options>] file.o", |
1255 | NULL, | 36 | NULL, |
1256 | }; | 37 | }; |
1257 | 38 | ||
39 | const struct option check_options[] = { | ||
40 | OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), | ||
41 | OPT_END(), | ||
42 | }; | ||
43 | |||
1258 | int cmd_check(int argc, const char **argv) | 44 | int cmd_check(int argc, const char **argv) |
1259 | { | 45 | { |
1260 | struct objtool_file file; | 46 | const char *objname; |
1261 | int ret, warnings = 0; | ||
1262 | |||
1263 | const struct option options[] = { | ||
1264 | OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), | ||
1265 | OPT_END(), | ||
1266 | }; | ||
1267 | 47 | ||
1268 | argc = parse_options(argc, argv, options, check_usage, 0); | 48 | argc = parse_options(argc, argv, check_options, check_usage, 0); |
1269 | 49 | ||
1270 | if (argc != 1) | 50 | if (argc != 1) |
1271 | usage_with_options(check_usage, options); | 51 | usage_with_options(check_usage, check_options); |
1272 | 52 | ||
1273 | objname = argv[0]; | 53 | objname = argv[0]; |
1274 | 54 | ||
1275 | file.elf = elf_open(objname); | 55 | return check(objname, nofp); |
1276 | if (!file.elf) { | ||
1277 | fprintf(stderr, "error reading elf file %s\n", objname); | ||
1278 | return 1; | ||
1279 | } | ||
1280 | |||
1281 | INIT_LIST_HEAD(&file.insn_list); | ||
1282 | hash_init(file.insn_hash); | ||
1283 | file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); | ||
1284 | file.rodata = find_section_by_name(file.elf, ".rodata"); | ||
1285 | file.ignore_unreachables = false; | ||
1286 | file.c_file = find_section_by_name(file.elf, ".comment"); | ||
1287 | |||
1288 | ret = decode_sections(&file); | ||
1289 | if (ret < 0) | ||
1290 | goto out; | ||
1291 | warnings += ret; | ||
1292 | |||
1293 | ret = validate_functions(&file); | ||
1294 | if (ret < 0) | ||
1295 | goto out; | ||
1296 | warnings += ret; | ||
1297 | |||
1298 | ret = validate_uncallable_instructions(&file); | ||
1299 | if (ret < 0) | ||
1300 | goto out; | ||
1301 | warnings += ret; | ||
1302 | |||
1303 | out: | ||
1304 | cleanup(&file); | ||
1305 | |||
1306 | /* ignore warnings for now until we get all the code cleaned up */ | ||
1307 | if (ret || warnings) | ||
1308 | return 0; | ||
1309 | return 0; | ||
1310 | } | 56 | } |
diff --git a/tools/objtool/cfi.h b/tools/objtool/cfi.h new file mode 100644 index 000000000000..443ab2c69992 --- /dev/null +++ b/tools/objtool/cfi.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _OBJTOOL_CFI_H | ||
19 | #define _OBJTOOL_CFI_H | ||
20 | |||
21 | #define CFI_UNDEFINED -1 | ||
22 | #define CFI_CFA -2 | ||
23 | #define CFI_SP_INDIRECT -3 | ||
24 | #define CFI_BP_INDIRECT -4 | ||
25 | |||
26 | #define CFI_AX 0 | ||
27 | #define CFI_DX 1 | ||
28 | #define CFI_CX 2 | ||
29 | #define CFI_BX 3 | ||
30 | #define CFI_SI 4 | ||
31 | #define CFI_DI 5 | ||
32 | #define CFI_BP 6 | ||
33 | #define CFI_SP 7 | ||
34 | #define CFI_R8 8 | ||
35 | #define CFI_R9 9 | ||
36 | #define CFI_R10 10 | ||
37 | #define CFI_R11 11 | ||
38 | #define CFI_R12 12 | ||
39 | #define CFI_R13 13 | ||
40 | #define CFI_R14 14 | ||
41 | #define CFI_R15 15 | ||
42 | #define CFI_RA 16 | ||
43 | #define CFI_NUM_REGS 17 | ||
44 | |||
45 | struct cfi_reg { | ||
46 | int base; | ||
47 | int offset; | ||
48 | }; | ||
49 | |||
50 | struct cfi_state { | ||
51 | struct cfi_reg cfa; | ||
52 | struct cfi_reg regs[CFI_NUM_REGS]; | ||
53 | }; | ||
54 | |||
55 | #endif /* _OBJTOOL_CFI_H */ | ||
diff --git a/tools/objtool/check.c b/tools/objtool/check.c new file mode 100644 index 000000000000..fea222192c57 --- /dev/null +++ b/tools/objtool/check.c | |||
@@ -0,0 +1,1655 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <string.h> | ||
19 | #include <stdlib.h> | ||
20 | |||
21 | #include "check.h" | ||
22 | #include "elf.h" | ||
23 | #include "special.h" | ||
24 | #include "arch.h" | ||
25 | #include "warn.h" | ||
26 | |||
27 | #include <linux/hashtable.h> | ||
28 | #include <linux/kernel.h> | ||
29 | |||
30 | struct alternative { | ||
31 | struct list_head list; | ||
32 | struct instruction *insn; | ||
33 | }; | ||
34 | |||
35 | const char *objname; | ||
36 | static bool nofp; | ||
37 | struct cfi_state initial_func_cfi; | ||
38 | |||
39 | static struct instruction *find_insn(struct objtool_file *file, | ||
40 | struct section *sec, unsigned long offset) | ||
41 | { | ||
42 | struct instruction *insn; | ||
43 | |||
44 | hash_for_each_possible(file->insn_hash, insn, hash, offset) | ||
45 | if (insn->sec == sec && insn->offset == offset) | ||
46 | return insn; | ||
47 | |||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | static struct instruction *next_insn_same_sec(struct objtool_file *file, | ||
52 | struct instruction *insn) | ||
53 | { | ||
54 | struct instruction *next = list_next_entry(insn, list); | ||
55 | |||
56 | if (!next || &next->list == &file->insn_list || next->sec != insn->sec) | ||
57 | return NULL; | ||
58 | |||
59 | return next; | ||
60 | } | ||
61 | |||
62 | static bool gcov_enabled(struct objtool_file *file) | ||
63 | { | ||
64 | struct section *sec; | ||
65 | struct symbol *sym; | ||
66 | |||
67 | for_each_sec(file, sec) | ||
68 | list_for_each_entry(sym, &sec->symbol_list, list) | ||
69 | if (!strncmp(sym->name, "__gcov_.", 8)) | ||
70 | return true; | ||
71 | |||
72 | return false; | ||
73 | } | ||
74 | |||
75 | #define func_for_each_insn(file, func, insn) \ | ||
76 | for (insn = find_insn(file, func->sec, func->offset); \ | ||
77 | insn && &insn->list != &file->insn_list && \ | ||
78 | insn->sec == func->sec && \ | ||
79 | insn->offset < func->offset + func->len; \ | ||
80 | insn = list_next_entry(insn, list)) | ||
81 | |||
82 | #define func_for_each_insn_continue_reverse(file, func, insn) \ | ||
83 | for (insn = list_prev_entry(insn, list); \ | ||
84 | &insn->list != &file->insn_list && \ | ||
85 | insn->sec == func->sec && insn->offset >= func->offset; \ | ||
86 | insn = list_prev_entry(insn, list)) | ||
87 | |||
88 | #define sec_for_each_insn_from(file, insn) \ | ||
89 | for (; insn; insn = next_insn_same_sec(file, insn)) | ||
90 | |||
91 | #define sec_for_each_insn_continue(file, insn) \ | ||
92 | for (insn = next_insn_same_sec(file, insn); insn; \ | ||
93 | insn = next_insn_same_sec(file, insn)) | ||
94 | |||
95 | /* | ||
96 | * Check if the function has been manually whitelisted with the | ||
97 | * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted | ||
98 | * due to its use of a context switching instruction. | ||
99 | */ | ||
100 | static bool ignore_func(struct objtool_file *file, struct symbol *func) | ||
101 | { | ||
102 | struct rela *rela; | ||
103 | struct instruction *insn; | ||
104 | |||
105 | /* check for STACK_FRAME_NON_STANDARD */ | ||
106 | if (file->whitelist && file->whitelist->rela) | ||
107 | list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) { | ||
108 | if (rela->sym->type == STT_SECTION && | ||
109 | rela->sym->sec == func->sec && | ||
110 | rela->addend == func->offset) | ||
111 | return true; | ||
112 | if (rela->sym->type == STT_FUNC && rela->sym == func) | ||
113 | return true; | ||
114 | } | ||
115 | |||
116 | /* check if it has a context switching instruction */ | ||
117 | func_for_each_insn(file, func, insn) | ||
118 | if (insn->type == INSN_CONTEXT_SWITCH) | ||
119 | return true; | ||
120 | |||
121 | return false; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * This checks to see if the given function is a "noreturn" function. | ||
126 | * | ||
127 | * For global functions which are outside the scope of this object file, we | ||
128 | * have to keep a manual list of them. | ||
129 | * | ||
130 | * For local functions, we have to detect them manually by simply looking for | ||
131 | * the lack of a return instruction. | ||
132 | * | ||
133 | * Returns: | ||
134 | * -1: error | ||
135 | * 0: no dead end | ||
136 | * 1: dead end | ||
137 | */ | ||
138 | static int __dead_end_function(struct objtool_file *file, struct symbol *func, | ||
139 | int recursion) | ||
140 | { | ||
141 | int i; | ||
142 | struct instruction *insn; | ||
143 | bool empty = true; | ||
144 | |||
145 | /* | ||
146 | * Unfortunately these have to be hard coded because the noreturn | ||
147 | * attribute isn't provided in ELF data. | ||
148 | */ | ||
149 | static const char * const global_noreturns[] = { | ||
150 | "__stack_chk_fail", | ||
151 | "panic", | ||
152 | "do_exit", | ||
153 | "do_task_dead", | ||
154 | "__module_put_and_exit", | ||
155 | "complete_and_exit", | ||
156 | "kvm_spurious_fault", | ||
157 | "__reiserfs_panic", | ||
158 | "lbug_with_loc", | ||
159 | "fortify_panic", | ||
160 | }; | ||
161 | |||
162 | if (func->bind == STB_WEAK) | ||
163 | return 0; | ||
164 | |||
165 | if (func->bind == STB_GLOBAL) | ||
166 | for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) | ||
167 | if (!strcmp(func->name, global_noreturns[i])) | ||
168 | return 1; | ||
169 | |||
170 | if (!func->sec) | ||
171 | return 0; | ||
172 | |||
173 | func_for_each_insn(file, func, insn) { | ||
174 | empty = false; | ||
175 | |||
176 | if (insn->type == INSN_RETURN) | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | if (empty) | ||
181 | return 0; | ||
182 | |||
183 | /* | ||
184 | * A function can have a sibling call instead of a return. In that | ||
185 | * case, the function's dead-end status depends on whether the target | ||
186 | * of the sibling call returns. | ||
187 | */ | ||
188 | func_for_each_insn(file, func, insn) { | ||
189 | if (insn->sec != func->sec || | ||
190 | insn->offset >= func->offset + func->len) | ||
191 | break; | ||
192 | |||
193 | if (insn->type == INSN_JUMP_UNCONDITIONAL) { | ||
194 | struct instruction *dest = insn->jump_dest; | ||
195 | struct symbol *dest_func; | ||
196 | |||
197 | if (!dest) | ||
198 | /* sibling call to another file */ | ||
199 | return 0; | ||
200 | |||
201 | if (dest->sec != func->sec || | ||
202 | dest->offset < func->offset || | ||
203 | dest->offset >= func->offset + func->len) { | ||
204 | /* local sibling call */ | ||
205 | dest_func = find_symbol_by_offset(dest->sec, | ||
206 | dest->offset); | ||
207 | if (!dest_func) | ||
208 | continue; | ||
209 | |||
210 | if (recursion == 5) { | ||
211 | WARN_FUNC("infinite recursion (objtool bug!)", | ||
212 | dest->sec, dest->offset); | ||
213 | return -1; | ||
214 | } | ||
215 | |||
216 | return __dead_end_function(file, dest_func, | ||
217 | recursion + 1); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) | ||
222 | /* sibling call */ | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | return 1; | ||
227 | } | ||
228 | |||
229 | static int dead_end_function(struct objtool_file *file, struct symbol *func) | ||
230 | { | ||
231 | return __dead_end_function(file, func, 0); | ||
232 | } | ||
233 | |||
234 | static void clear_insn_state(struct insn_state *state) | ||
235 | { | ||
236 | int i; | ||
237 | |||
238 | memset(state, 0, sizeof(*state)); | ||
239 | state->cfa.base = CFI_UNDEFINED; | ||
240 | for (i = 0; i < CFI_NUM_REGS; i++) | ||
241 | state->regs[i].base = CFI_UNDEFINED; | ||
242 | state->drap_reg = CFI_UNDEFINED; | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * Call the arch-specific instruction decoder for all the instructions and add | ||
247 | * them to the global instruction list. | ||
248 | */ | ||
249 | static int decode_instructions(struct objtool_file *file) | ||
250 | { | ||
251 | struct section *sec; | ||
252 | struct symbol *func; | ||
253 | unsigned long offset; | ||
254 | struct instruction *insn; | ||
255 | int ret; | ||
256 | |||
257 | for_each_sec(file, sec) { | ||
258 | |||
259 | if (!(sec->sh.sh_flags & SHF_EXECINSTR)) | ||
260 | continue; | ||
261 | |||
262 | for (offset = 0; offset < sec->len; offset += insn->len) { | ||
263 | insn = malloc(sizeof(*insn)); | ||
264 | if (!insn) { | ||
265 | WARN("malloc failed"); | ||
266 | return -1; | ||
267 | } | ||
268 | memset(insn, 0, sizeof(*insn)); | ||
269 | INIT_LIST_HEAD(&insn->alts); | ||
270 | clear_insn_state(&insn->state); | ||
271 | |||
272 | insn->sec = sec; | ||
273 | insn->offset = offset; | ||
274 | |||
275 | ret = arch_decode_instruction(file->elf, sec, offset, | ||
276 | sec->len - offset, | ||
277 | &insn->len, &insn->type, | ||
278 | &insn->immediate, | ||
279 | &insn->stack_op); | ||
280 | if (ret) | ||
281 | return ret; | ||
282 | |||
283 | if (!insn->type || insn->type > INSN_LAST) { | ||
284 | WARN_FUNC("invalid instruction type %d", | ||
285 | insn->sec, insn->offset, insn->type); | ||
286 | return -1; | ||
287 | } | ||
288 | |||
289 | hash_add(file->insn_hash, &insn->hash, insn->offset); | ||
290 | list_add_tail(&insn->list, &file->insn_list); | ||
291 | } | ||
292 | |||
293 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
294 | if (func->type != STT_FUNC) | ||
295 | continue; | ||
296 | |||
297 | if (!find_insn(file, sec, func->offset)) { | ||
298 | WARN("%s(): can't find starting instruction", | ||
299 | func->name); | ||
300 | return -1; | ||
301 | } | ||
302 | |||
303 | func_for_each_insn(file, func, insn) | ||
304 | if (!insn->func) | ||
305 | insn->func = func; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Find all uses of the unreachable() macro, which are code path dead ends. | ||
314 | */ | ||
315 | static int add_dead_ends(struct objtool_file *file) | ||
316 | { | ||
317 | struct section *sec; | ||
318 | struct rela *rela; | ||
319 | struct instruction *insn; | ||
320 | bool found; | ||
321 | |||
322 | sec = find_section_by_name(file->elf, ".rela.discard.unreachable"); | ||
323 | if (!sec) | ||
324 | return 0; | ||
325 | |||
326 | list_for_each_entry(rela, &sec->rela_list, list) { | ||
327 | if (rela->sym->type != STT_SECTION) { | ||
328 | WARN("unexpected relocation symbol type in %s", sec->name); | ||
329 | return -1; | ||
330 | } | ||
331 | insn = find_insn(file, rela->sym->sec, rela->addend); | ||
332 | if (insn) | ||
333 | insn = list_prev_entry(insn, list); | ||
334 | else if (rela->addend == rela->sym->sec->len) { | ||
335 | found = false; | ||
336 | list_for_each_entry_reverse(insn, &file->insn_list, list) { | ||
337 | if (insn->sec == rela->sym->sec) { | ||
338 | found = true; | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | if (!found) { | ||
344 | WARN("can't find unreachable insn at %s+0x%x", | ||
345 | rela->sym->sec->name, rela->addend); | ||
346 | return -1; | ||
347 | } | ||
348 | } else { | ||
349 | WARN("can't find unreachable insn at %s+0x%x", | ||
350 | rela->sym->sec->name, rela->addend); | ||
351 | return -1; | ||
352 | } | ||
353 | |||
354 | insn->dead_end = true; | ||
355 | } | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * Warnings shouldn't be reported for ignored functions. | ||
362 | */ | ||
363 | static void add_ignores(struct objtool_file *file) | ||
364 | { | ||
365 | struct instruction *insn; | ||
366 | struct section *sec; | ||
367 | struct symbol *func; | ||
368 | |||
369 | for_each_sec(file, sec) { | ||
370 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
371 | if (func->type != STT_FUNC) | ||
372 | continue; | ||
373 | |||
374 | if (!ignore_func(file, func)) | ||
375 | continue; | ||
376 | |||
377 | func_for_each_insn(file, func, insn) | ||
378 | insn->ignore = true; | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * Find the destination instructions for all jumps. | ||
385 | */ | ||
386 | static int add_jump_destinations(struct objtool_file *file) | ||
387 | { | ||
388 | struct instruction *insn; | ||
389 | struct rela *rela; | ||
390 | struct section *dest_sec; | ||
391 | unsigned long dest_off; | ||
392 | |||
393 | for_each_insn(file, insn) { | ||
394 | if (insn->type != INSN_JUMP_CONDITIONAL && | ||
395 | insn->type != INSN_JUMP_UNCONDITIONAL) | ||
396 | continue; | ||
397 | |||
398 | if (insn->ignore) | ||
399 | continue; | ||
400 | |||
401 | rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
402 | insn->len); | ||
403 | if (!rela) { | ||
404 | dest_sec = insn->sec; | ||
405 | dest_off = insn->offset + insn->len + insn->immediate; | ||
406 | } else if (rela->sym->type == STT_SECTION) { | ||
407 | dest_sec = rela->sym->sec; | ||
408 | dest_off = rela->addend + 4; | ||
409 | } else if (rela->sym->sec->idx) { | ||
410 | dest_sec = rela->sym->sec; | ||
411 | dest_off = rela->sym->sym.st_value + rela->addend + 4; | ||
412 | } else { | ||
413 | /* sibling call */ | ||
414 | insn->jump_dest = 0; | ||
415 | continue; | ||
416 | } | ||
417 | |||
418 | insn->jump_dest = find_insn(file, dest_sec, dest_off); | ||
419 | if (!insn->jump_dest) { | ||
420 | |||
421 | /* | ||
422 | * This is a special case where an alt instruction | ||
423 | * jumps past the end of the section. These are | ||
424 | * handled later in handle_group_alt(). | ||
425 | */ | ||
426 | if (!strcmp(insn->sec->name, ".altinstr_replacement")) | ||
427 | continue; | ||
428 | |||
429 | WARN_FUNC("can't find jump dest instruction at %s+0x%lx", | ||
430 | insn->sec, insn->offset, dest_sec->name, | ||
431 | dest_off); | ||
432 | return -1; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * Find the destination instructions for all calls. | ||
441 | */ | ||
442 | static int add_call_destinations(struct objtool_file *file) | ||
443 | { | ||
444 | struct instruction *insn; | ||
445 | unsigned long dest_off; | ||
446 | struct rela *rela; | ||
447 | |||
448 | for_each_insn(file, insn) { | ||
449 | if (insn->type != INSN_CALL) | ||
450 | continue; | ||
451 | |||
452 | rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
453 | insn->len); | ||
454 | if (!rela) { | ||
455 | dest_off = insn->offset + insn->len + insn->immediate; | ||
456 | insn->call_dest = find_symbol_by_offset(insn->sec, | ||
457 | dest_off); | ||
458 | if (!insn->call_dest) { | ||
459 | WARN_FUNC("can't find call dest symbol at offset 0x%lx", | ||
460 | insn->sec, insn->offset, dest_off); | ||
461 | return -1; | ||
462 | } | ||
463 | } else if (rela->sym->type == STT_SECTION) { | ||
464 | insn->call_dest = find_symbol_by_offset(rela->sym->sec, | ||
465 | rela->addend+4); | ||
466 | if (!insn->call_dest || | ||
467 | insn->call_dest->type != STT_FUNC) { | ||
468 | WARN_FUNC("can't find call dest symbol at %s+0x%x", | ||
469 | insn->sec, insn->offset, | ||
470 | rela->sym->sec->name, | ||
471 | rela->addend + 4); | ||
472 | return -1; | ||
473 | } | ||
474 | } else | ||
475 | insn->call_dest = rela->sym; | ||
476 | } | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * The .alternatives section requires some extra special care, over and above | ||
483 | * what other special sections require: | ||
484 | * | ||
485 | * 1. Because alternatives are patched in-place, we need to insert a fake jump | ||
486 | * instruction at the end so that validate_branch() skips all the original | ||
487 | * replaced instructions when validating the new instruction path. | ||
488 | * | ||
489 | * 2. An added wrinkle is that the new instruction length might be zero. In | ||
490 | * that case the old instructions are replaced with noops. We simulate that | ||
491 | * by creating a fake jump as the only new instruction. | ||
492 | * | ||
493 | * 3. In some cases, the alternative section includes an instruction which | ||
494 | * conditionally jumps to the _end_ of the entry. We have to modify these | ||
495 | * jumps' destinations to point back to .text rather than the end of the | ||
496 | * entry in .altinstr_replacement. | ||
497 | * | ||
498 | * 4. It has been requested that we don't validate the !POPCNT feature path | ||
499 | * which is a "very very small percentage of machines". | ||
500 | */ | ||
501 | static int handle_group_alt(struct objtool_file *file, | ||
502 | struct special_alt *special_alt, | ||
503 | struct instruction *orig_insn, | ||
504 | struct instruction **new_insn) | ||
505 | { | ||
506 | struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; | ||
507 | unsigned long dest_off; | ||
508 | |||
509 | last_orig_insn = NULL; | ||
510 | insn = orig_insn; | ||
511 | sec_for_each_insn_from(file, insn) { | ||
512 | if (insn->offset >= special_alt->orig_off + special_alt->orig_len) | ||
513 | break; | ||
514 | |||
515 | if (special_alt->skip_orig) | ||
516 | insn->type = INSN_NOP; | ||
517 | |||
518 | insn->alt_group = true; | ||
519 | last_orig_insn = insn; | ||
520 | } | ||
521 | |||
522 | if (!next_insn_same_sec(file, last_orig_insn)) { | ||
523 | WARN("%s: don't know how to handle alternatives at end of section", | ||
524 | special_alt->orig_sec->name); | ||
525 | return -1; | ||
526 | } | ||
527 | |||
528 | fake_jump = malloc(sizeof(*fake_jump)); | ||
529 | if (!fake_jump) { | ||
530 | WARN("malloc failed"); | ||
531 | return -1; | ||
532 | } | ||
533 | memset(fake_jump, 0, sizeof(*fake_jump)); | ||
534 | INIT_LIST_HEAD(&fake_jump->alts); | ||
535 | clear_insn_state(&fake_jump->state); | ||
536 | |||
537 | fake_jump->sec = special_alt->new_sec; | ||
538 | fake_jump->offset = -1; | ||
539 | fake_jump->type = INSN_JUMP_UNCONDITIONAL; | ||
540 | fake_jump->jump_dest = list_next_entry(last_orig_insn, list); | ||
541 | fake_jump->ignore = true; | ||
542 | |||
543 | if (!special_alt->new_len) { | ||
544 | *new_insn = fake_jump; | ||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | last_new_insn = NULL; | ||
549 | insn = *new_insn; | ||
550 | sec_for_each_insn_from(file, insn) { | ||
551 | if (insn->offset >= special_alt->new_off + special_alt->new_len) | ||
552 | break; | ||
553 | |||
554 | last_new_insn = insn; | ||
555 | |||
556 | if (insn->type != INSN_JUMP_CONDITIONAL && | ||
557 | insn->type != INSN_JUMP_UNCONDITIONAL) | ||
558 | continue; | ||
559 | |||
560 | if (!insn->immediate) | ||
561 | continue; | ||
562 | |||
563 | dest_off = insn->offset + insn->len + insn->immediate; | ||
564 | if (dest_off == special_alt->new_off + special_alt->new_len) | ||
565 | insn->jump_dest = fake_jump; | ||
566 | |||
567 | if (!insn->jump_dest) { | ||
568 | WARN_FUNC("can't find alternative jump destination", | ||
569 | insn->sec, insn->offset); | ||
570 | return -1; | ||
571 | } | ||
572 | } | ||
573 | |||
574 | if (!last_new_insn) { | ||
575 | WARN_FUNC("can't find last new alternative instruction", | ||
576 | special_alt->new_sec, special_alt->new_off); | ||
577 | return -1; | ||
578 | } | ||
579 | |||
580 | list_add(&fake_jump->list, &last_new_insn->list); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | /* | ||
586 | * A jump table entry can either convert a nop to a jump or a jump to a nop. | ||
587 | * If the original instruction is a jump, make the alt entry an effective nop | ||
588 | * by just skipping the original instruction. | ||
589 | */ | ||
590 | static int handle_jump_alt(struct objtool_file *file, | ||
591 | struct special_alt *special_alt, | ||
592 | struct instruction *orig_insn, | ||
593 | struct instruction **new_insn) | ||
594 | { | ||
595 | if (orig_insn->type == INSN_NOP) | ||
596 | return 0; | ||
597 | |||
598 | if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { | ||
599 | WARN_FUNC("unsupported instruction at jump label", | ||
600 | orig_insn->sec, orig_insn->offset); | ||
601 | return -1; | ||
602 | } | ||
603 | |||
604 | *new_insn = list_next_entry(orig_insn, list); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * Read all the special sections which have alternate instructions which can be | ||
610 | * patched in or redirected to at runtime. Each instruction having alternate | ||
611 | * instruction(s) has them added to its insn->alts list, which will be | ||
612 | * traversed in validate_branch(). | ||
613 | */ | ||
614 | static int add_special_section_alts(struct objtool_file *file) | ||
615 | { | ||
616 | struct list_head special_alts; | ||
617 | struct instruction *orig_insn, *new_insn; | ||
618 | struct special_alt *special_alt, *tmp; | ||
619 | struct alternative *alt; | ||
620 | int ret; | ||
621 | |||
622 | ret = special_get_alts(file->elf, &special_alts); | ||
623 | if (ret) | ||
624 | return ret; | ||
625 | |||
626 | list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { | ||
627 | alt = malloc(sizeof(*alt)); | ||
628 | if (!alt) { | ||
629 | WARN("malloc failed"); | ||
630 | ret = -1; | ||
631 | goto out; | ||
632 | } | ||
633 | |||
634 | orig_insn = find_insn(file, special_alt->orig_sec, | ||
635 | special_alt->orig_off); | ||
636 | if (!orig_insn) { | ||
637 | WARN_FUNC("special: can't find orig instruction", | ||
638 | special_alt->orig_sec, special_alt->orig_off); | ||
639 | ret = -1; | ||
640 | goto out; | ||
641 | } | ||
642 | |||
643 | new_insn = NULL; | ||
644 | if (!special_alt->group || special_alt->new_len) { | ||
645 | new_insn = find_insn(file, special_alt->new_sec, | ||
646 | special_alt->new_off); | ||
647 | if (!new_insn) { | ||
648 | WARN_FUNC("special: can't find new instruction", | ||
649 | special_alt->new_sec, | ||
650 | special_alt->new_off); | ||
651 | ret = -1; | ||
652 | goto out; | ||
653 | } | ||
654 | } | ||
655 | |||
656 | if (special_alt->group) { | ||
657 | ret = handle_group_alt(file, special_alt, orig_insn, | ||
658 | &new_insn); | ||
659 | if (ret) | ||
660 | goto out; | ||
661 | } else if (special_alt->jump_or_nop) { | ||
662 | ret = handle_jump_alt(file, special_alt, orig_insn, | ||
663 | &new_insn); | ||
664 | if (ret) | ||
665 | goto out; | ||
666 | } | ||
667 | |||
668 | alt->insn = new_insn; | ||
669 | list_add_tail(&alt->list, &orig_insn->alts); | ||
670 | |||
671 | list_del(&special_alt->list); | ||
672 | free(special_alt); | ||
673 | } | ||
674 | |||
675 | out: | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | static int add_switch_table(struct objtool_file *file, struct symbol *func, | ||
680 | struct instruction *insn, struct rela *table, | ||
681 | struct rela *next_table) | ||
682 | { | ||
683 | struct rela *rela = table; | ||
684 | struct instruction *alt_insn; | ||
685 | struct alternative *alt; | ||
686 | |||
687 | list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { | ||
688 | if (rela == next_table) | ||
689 | break; | ||
690 | |||
691 | if (rela->sym->sec != insn->sec || | ||
692 | rela->addend <= func->offset || | ||
693 | rela->addend >= func->offset + func->len) | ||
694 | break; | ||
695 | |||
696 | alt_insn = find_insn(file, insn->sec, rela->addend); | ||
697 | if (!alt_insn) { | ||
698 | WARN("%s: can't find instruction at %s+0x%x", | ||
699 | file->rodata->rela->name, insn->sec->name, | ||
700 | rela->addend); | ||
701 | return -1; | ||
702 | } | ||
703 | |||
704 | alt = malloc(sizeof(*alt)); | ||
705 | if (!alt) { | ||
706 | WARN("malloc failed"); | ||
707 | return -1; | ||
708 | } | ||
709 | |||
710 | alt->insn = alt_insn; | ||
711 | list_add_tail(&alt->list, &insn->alts); | ||
712 | } | ||
713 | |||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | /* | ||
718 | * find_switch_table() - Given a dynamic jump, find the switch jump table in | ||
719 | * .rodata associated with it. | ||
720 | * | ||
721 | * There are 3 basic patterns: | ||
722 | * | ||
723 | * 1. jmpq *[rodata addr](,%reg,8) | ||
724 | * | ||
725 | * This is the most common case by far. It jumps to an address in a simple | ||
726 | * jump table which is stored in .rodata. | ||
727 | * | ||
728 | * 2. jmpq *[rodata addr](%rip) | ||
729 | * | ||
730 | * This is caused by a rare GCC quirk, currently only seen in three driver | ||
731 | * functions in the kernel, only with certain obscure non-distro configs. | ||
732 | * | ||
733 | * As part of an optimization, GCC makes a copy of an existing switch jump | ||
734 | * table, modifies it, and then hard-codes the jump (albeit with an indirect | ||
735 | * jump) to use a single entry in the table. The rest of the jump table and | ||
736 | * some of its jump targets remain as dead code. | ||
737 | * | ||
738 | * In such a case we can just crudely ignore all unreachable instruction | ||
739 | * warnings for the entire object file. Ideally we would just ignore them | ||
740 | * for the function, but that would require redesigning the code quite a | ||
741 | * bit. And honestly that's just not worth doing: unreachable instruction | ||
742 | * warnings are of questionable value anyway, and this is such a rare issue. | ||
743 | * | ||
744 | * 3. mov [rodata addr],%reg1 | ||
745 | * ... some instructions ... | ||
746 | * jmpq *(%reg1,%reg2,8) | ||
747 | * | ||
748 | * This is a fairly uncommon pattern which is new for GCC 6. As of this | ||
749 | * writing, there are 11 occurrences of it in the allmodconfig kernel. | ||
750 | * | ||
751 | * TODO: Once we have DWARF CFI and smarter instruction decoding logic, | ||
752 | * ensure the same register is used in the mov and jump instructions. | ||
753 | */ | ||
754 | static struct rela *find_switch_table(struct objtool_file *file, | ||
755 | struct symbol *func, | ||
756 | struct instruction *insn) | ||
757 | { | ||
758 | struct rela *text_rela, *rodata_rela; | ||
759 | struct instruction *orig_insn = insn; | ||
760 | |||
761 | text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); | ||
762 | if (text_rela && text_rela->sym == file->rodata->sym) { | ||
763 | /* case 1 */ | ||
764 | rodata_rela = find_rela_by_dest(file->rodata, | ||
765 | text_rela->addend); | ||
766 | if (rodata_rela) | ||
767 | return rodata_rela; | ||
768 | |||
769 | /* case 2 */ | ||
770 | rodata_rela = find_rela_by_dest(file->rodata, | ||
771 | text_rela->addend + 4); | ||
772 | if (!rodata_rela) | ||
773 | return NULL; | ||
774 | file->ignore_unreachables = true; | ||
775 | return rodata_rela; | ||
776 | } | ||
777 | |||
778 | /* case 3 */ | ||
779 | func_for_each_insn_continue_reverse(file, func, insn) { | ||
780 | if (insn->type == INSN_JUMP_DYNAMIC) | ||
781 | break; | ||
782 | |||
783 | /* allow small jumps within the range */ | ||
784 | if (insn->type == INSN_JUMP_UNCONDITIONAL && | ||
785 | insn->jump_dest && | ||
786 | (insn->jump_dest->offset <= insn->offset || | ||
787 | insn->jump_dest->offset > orig_insn->offset)) | ||
788 | break; | ||
789 | |||
790 | /* look for a relocation which references .rodata */ | ||
791 | text_rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
792 | insn->len); | ||
793 | if (!text_rela || text_rela->sym != file->rodata->sym) | ||
794 | continue; | ||
795 | |||
796 | /* | ||
797 | * Make sure the .rodata address isn't associated with a | ||
798 | * symbol. gcc jump tables are anonymous data. | ||
799 | */ | ||
800 | if (find_symbol_containing(file->rodata, text_rela->addend)) | ||
801 | continue; | ||
802 | |||
803 | return find_rela_by_dest(file->rodata, text_rela->addend); | ||
804 | } | ||
805 | |||
806 | return NULL; | ||
807 | } | ||
808 | |||
809 | static int add_func_switch_tables(struct objtool_file *file, | ||
810 | struct symbol *func) | ||
811 | { | ||
812 | struct instruction *insn, *prev_jump = NULL; | ||
813 | struct rela *rela, *prev_rela = NULL; | ||
814 | int ret; | ||
815 | |||
816 | func_for_each_insn(file, func, insn) { | ||
817 | if (insn->type != INSN_JUMP_DYNAMIC) | ||
818 | continue; | ||
819 | |||
820 | rela = find_switch_table(file, func, insn); | ||
821 | if (!rela) | ||
822 | continue; | ||
823 | |||
824 | /* | ||
825 | * We found a switch table, but we don't know yet how big it | ||
826 | * is. Don't add it until we reach the end of the function or | ||
827 | * the beginning of another switch table in the same function. | ||
828 | */ | ||
829 | if (prev_jump) { | ||
830 | ret = add_switch_table(file, func, prev_jump, prev_rela, | ||
831 | rela); | ||
832 | if (ret) | ||
833 | return ret; | ||
834 | } | ||
835 | |||
836 | prev_jump = insn; | ||
837 | prev_rela = rela; | ||
838 | } | ||
839 | |||
840 | if (prev_jump) { | ||
841 | ret = add_switch_table(file, func, prev_jump, prev_rela, NULL); | ||
842 | if (ret) | ||
843 | return ret; | ||
844 | } | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | /* | ||
850 | * For some switch statements, gcc generates a jump table in the .rodata | ||
851 | * section which contains a list of addresses within the function to jump to. | ||
852 | * This finds these jump tables and adds them to the insn->alts lists. | ||
853 | */ | ||
854 | static int add_switch_table_alts(struct objtool_file *file) | ||
855 | { | ||
856 | struct section *sec; | ||
857 | struct symbol *func; | ||
858 | int ret; | ||
859 | |||
860 | if (!file->rodata || !file->rodata->rela) | ||
861 | return 0; | ||
862 | |||
863 | for_each_sec(file, sec) { | ||
864 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
865 | if (func->type != STT_FUNC) | ||
866 | continue; | ||
867 | |||
868 | ret = add_func_switch_tables(file, func); | ||
869 | if (ret) | ||
870 | return ret; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static int decode_sections(struct objtool_file *file) | ||
878 | { | ||
879 | int ret; | ||
880 | |||
881 | ret = decode_instructions(file); | ||
882 | if (ret) | ||
883 | return ret; | ||
884 | |||
885 | ret = add_dead_ends(file); | ||
886 | if (ret) | ||
887 | return ret; | ||
888 | |||
889 | add_ignores(file); | ||
890 | |||
891 | ret = add_jump_destinations(file); | ||
892 | if (ret) | ||
893 | return ret; | ||
894 | |||
895 | ret = add_call_destinations(file); | ||
896 | if (ret) | ||
897 | return ret; | ||
898 | |||
899 | ret = add_special_section_alts(file); | ||
900 | if (ret) | ||
901 | return ret; | ||
902 | |||
903 | ret = add_switch_table_alts(file); | ||
904 | if (ret) | ||
905 | return ret; | ||
906 | |||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static bool is_fentry_call(struct instruction *insn) | ||
911 | { | ||
912 | if (insn->type == INSN_CALL && | ||
913 | insn->call_dest->type == STT_NOTYPE && | ||
914 | !strcmp(insn->call_dest->name, "__fentry__")) | ||
915 | return true; | ||
916 | |||
917 | return false; | ||
918 | } | ||
919 | |||
920 | static bool has_modified_stack_frame(struct insn_state *state) | ||
921 | { | ||
922 | int i; | ||
923 | |||
924 | if (state->cfa.base != initial_func_cfi.cfa.base || | ||
925 | state->cfa.offset != initial_func_cfi.cfa.offset || | ||
926 | state->stack_size != initial_func_cfi.cfa.offset || | ||
927 | state->drap) | ||
928 | return true; | ||
929 | |||
930 | for (i = 0; i < CFI_NUM_REGS; i++) | ||
931 | if (state->regs[i].base != initial_func_cfi.regs[i].base || | ||
932 | state->regs[i].offset != initial_func_cfi.regs[i].offset) | ||
933 | return true; | ||
934 | |||
935 | return false; | ||
936 | } | ||
937 | |||
938 | static bool has_valid_stack_frame(struct insn_state *state) | ||
939 | { | ||
940 | if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA && | ||
941 | state->regs[CFI_BP].offset == -16) | ||
942 | return true; | ||
943 | |||
944 | if (state->drap && state->regs[CFI_BP].base == CFI_BP) | ||
945 | return true; | ||
946 | |||
947 | return false; | ||
948 | } | ||
949 | |||
950 | static void save_reg(struct insn_state *state, unsigned char reg, int base, | ||
951 | int offset) | ||
952 | { | ||
953 | if ((arch_callee_saved_reg(reg) || | ||
954 | (state->drap && reg == state->drap_reg)) && | ||
955 | state->regs[reg].base == CFI_UNDEFINED) { | ||
956 | state->regs[reg].base = base; | ||
957 | state->regs[reg].offset = offset; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | static void restore_reg(struct insn_state *state, unsigned char reg) | ||
962 | { | ||
963 | state->regs[reg].base = CFI_UNDEFINED; | ||
964 | state->regs[reg].offset = 0; | ||
965 | } | ||
966 | |||
967 | /* | ||
968 | * A note about DRAP stack alignment: | ||
969 | * | ||
970 | * GCC has the concept of a DRAP register, which is used to help keep track of | ||
971 | * the stack pointer when aligning the stack. r10 or r13 is used as the DRAP | ||
972 | * register. The typical DRAP pattern is: | ||
973 | * | ||
974 | * 4c 8d 54 24 08 lea 0x8(%rsp),%r10 | ||
975 | * 48 83 e4 c0 and $0xffffffffffffffc0,%rsp | ||
976 | * 41 ff 72 f8 pushq -0x8(%r10) | ||
977 | * 55 push %rbp | ||
978 | * 48 89 e5 mov %rsp,%rbp | ||
979 | * (more pushes) | ||
980 | * 41 52 push %r10 | ||
981 | * ... | ||
982 | * 41 5a pop %r10 | ||
983 | * (more pops) | ||
984 | * 5d pop %rbp | ||
985 | * 49 8d 62 f8 lea -0x8(%r10),%rsp | ||
986 | * c3 retq | ||
987 | * | ||
988 | * There are some variations in the epilogues, like: | ||
989 | * | ||
990 | * 5b pop %rbx | ||
991 | * 41 5a pop %r10 | ||
992 | * 41 5c pop %r12 | ||
993 | * 41 5d pop %r13 | ||
994 | * 41 5e pop %r14 | ||
995 | * c9 leaveq | ||
996 | * 49 8d 62 f8 lea -0x8(%r10),%rsp | ||
997 | * c3 retq | ||
998 | * | ||
999 | * and: | ||
1000 | * | ||
1001 | * 4c 8b 55 e8 mov -0x18(%rbp),%r10 | ||
1002 | * 48 8b 5d e0 mov -0x20(%rbp),%rbx | ||
1003 | * 4c 8b 65 f0 mov -0x10(%rbp),%r12 | ||
1004 | * 4c 8b 6d f8 mov -0x8(%rbp),%r13 | ||
1005 | * c9 leaveq | ||
1006 | * 49 8d 62 f8 lea -0x8(%r10),%rsp | ||
1007 | * c3 retq | ||
1008 | * | ||
1009 | * Sometimes r13 is used as the DRAP register, in which case it's saved and | ||
1010 | * restored beforehand: | ||
1011 | * | ||
1012 | * 41 55 push %r13 | ||
1013 | * 4c 8d 6c 24 10 lea 0x10(%rsp),%r13 | ||
1014 | * 48 83 e4 f0 and $0xfffffffffffffff0,%rsp | ||
1015 | * ... | ||
1016 | * 49 8d 65 f0 lea -0x10(%r13),%rsp | ||
1017 | * 41 5d pop %r13 | ||
1018 | * c3 retq | ||
1019 | */ | ||
1020 | static int update_insn_state(struct instruction *insn, struct insn_state *state) | ||
1021 | { | ||
1022 | struct stack_op *op = &insn->stack_op; | ||
1023 | struct cfi_reg *cfa = &state->cfa; | ||
1024 | struct cfi_reg *regs = state->regs; | ||
1025 | |||
1026 | /* stack operations don't make sense with an undefined CFA */ | ||
1027 | if (cfa->base == CFI_UNDEFINED) { | ||
1028 | if (insn->func) { | ||
1029 | WARN_FUNC("undefined stack state", insn->sec, insn->offset); | ||
1030 | return -1; | ||
1031 | } | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | switch (op->dest.type) { | ||
1036 | |||
1037 | case OP_DEST_REG: | ||
1038 | switch (op->src.type) { | ||
1039 | |||
1040 | case OP_SRC_REG: | ||
1041 | if (cfa->base == op->src.reg && cfa->base == CFI_SP && | ||
1042 | op->dest.reg == CFI_BP && regs[CFI_BP].base == CFI_CFA && | ||
1043 | regs[CFI_BP].offset == -cfa->offset) { | ||
1044 | |||
1045 | /* mov %rsp, %rbp */ | ||
1046 | cfa->base = op->dest.reg; | ||
1047 | state->bp_scratch = false; | ||
1048 | } else if (state->drap) { | ||
1049 | |||
1050 | /* drap: mov %rsp, %rbp */ | ||
1051 | regs[CFI_BP].base = CFI_BP; | ||
1052 | regs[CFI_BP].offset = -state->stack_size; | ||
1053 | state->bp_scratch = false; | ||
1054 | } else if (!nofp) { | ||
1055 | |||
1056 | WARN_FUNC("unknown stack-related register move", | ||
1057 | insn->sec, insn->offset); | ||
1058 | return -1; | ||
1059 | } | ||
1060 | |||
1061 | break; | ||
1062 | |||
1063 | case OP_SRC_ADD: | ||
1064 | if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { | ||
1065 | |||
1066 | /* add imm, %rsp */ | ||
1067 | state->stack_size -= op->src.offset; | ||
1068 | if (cfa->base == CFI_SP) | ||
1069 | cfa->offset -= op->src.offset; | ||
1070 | break; | ||
1071 | } | ||
1072 | |||
1073 | if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { | ||
1074 | |||
1075 | /* lea disp(%rbp), %rsp */ | ||
1076 | state->stack_size = -(op->src.offset + regs[CFI_BP].offset); | ||
1077 | break; | ||
1078 | } | ||
1079 | |||
1080 | if (op->dest.reg != CFI_BP && op->src.reg == CFI_SP && | ||
1081 | cfa->base == CFI_SP) { | ||
1082 | |||
1083 | /* drap: lea disp(%rsp), %drap */ | ||
1084 | state->drap_reg = op->dest.reg; | ||
1085 | break; | ||
1086 | } | ||
1087 | |||
1088 | if (state->drap && op->dest.reg == CFI_SP && | ||
1089 | op->src.reg == state->drap_reg) { | ||
1090 | |||
1091 | /* drap: lea disp(%drap), %rsp */ | ||
1092 | cfa->base = CFI_SP; | ||
1093 | cfa->offset = state->stack_size = -op->src.offset; | ||
1094 | state->drap_reg = CFI_UNDEFINED; | ||
1095 | state->drap = false; | ||
1096 | break; | ||
1097 | } | ||
1098 | |||
1099 | if (op->dest.reg == state->cfa.base) { | ||
1100 | WARN_FUNC("unsupported stack register modification", | ||
1101 | insn->sec, insn->offset); | ||
1102 | return -1; | ||
1103 | } | ||
1104 | |||
1105 | break; | ||
1106 | |||
1107 | case OP_SRC_AND: | ||
1108 | if (op->dest.reg != CFI_SP || | ||
1109 | (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || | ||
1110 | (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { | ||
1111 | WARN_FUNC("unsupported stack pointer realignment", | ||
1112 | insn->sec, insn->offset); | ||
1113 | return -1; | ||
1114 | } | ||
1115 | |||
1116 | if (state->drap_reg != CFI_UNDEFINED) { | ||
1117 | /* drap: and imm, %rsp */ | ||
1118 | cfa->base = state->drap_reg; | ||
1119 | cfa->offset = state->stack_size = 0; | ||
1120 | state->drap = true; | ||
1121 | |||
1122 | } | ||
1123 | |||
1124 | /* | ||
1125 | * Older versions of GCC (4.8ish) realign the stack | ||
1126 | * without DRAP, with a frame pointer. | ||
1127 | */ | ||
1128 | |||
1129 | break; | ||
1130 | |||
1131 | case OP_SRC_POP: | ||
1132 | if (!state->drap && op->dest.type == OP_DEST_REG && | ||
1133 | op->dest.reg == cfa->base) { | ||
1134 | |||
1135 | /* pop %rbp */ | ||
1136 | cfa->base = CFI_SP; | ||
1137 | } | ||
1138 | |||
1139 | if (regs[op->dest.reg].offset == -state->stack_size) { | ||
1140 | |||
1141 | if (state->drap && cfa->base == CFI_BP_INDIRECT && | ||
1142 | op->dest.type == OP_DEST_REG && | ||
1143 | op->dest.reg == state->drap_reg) { | ||
1144 | |||
1145 | /* drap: pop %drap */ | ||
1146 | cfa->base = state->drap_reg; | ||
1147 | cfa->offset = 0; | ||
1148 | } | ||
1149 | |||
1150 | restore_reg(state, op->dest.reg); | ||
1151 | } | ||
1152 | |||
1153 | state->stack_size -= 8; | ||
1154 | if (cfa->base == CFI_SP) | ||
1155 | cfa->offset -= 8; | ||
1156 | |||
1157 | break; | ||
1158 | |||
1159 | case OP_SRC_REG_INDIRECT: | ||
1160 | if (state->drap && op->src.reg == CFI_BP && | ||
1161 | op->src.offset == regs[op->dest.reg].offset) { | ||
1162 | |||
1163 | /* drap: mov disp(%rbp), %reg */ | ||
1164 | if (op->dest.reg == state->drap_reg) { | ||
1165 | cfa->base = state->drap_reg; | ||
1166 | cfa->offset = 0; | ||
1167 | } | ||
1168 | |||
1169 | restore_reg(state, op->dest.reg); | ||
1170 | |||
1171 | } else if (op->src.reg == cfa->base && | ||
1172 | op->src.offset == regs[op->dest.reg].offset + cfa->offset) { | ||
1173 | |||
1174 | /* mov disp(%rbp), %reg */ | ||
1175 | /* mov disp(%rsp), %reg */ | ||
1176 | restore_reg(state, op->dest.reg); | ||
1177 | } | ||
1178 | |||
1179 | break; | ||
1180 | |||
1181 | default: | ||
1182 | WARN_FUNC("unknown stack-related instruction", | ||
1183 | insn->sec, insn->offset); | ||
1184 | return -1; | ||
1185 | } | ||
1186 | |||
1187 | break; | ||
1188 | |||
1189 | case OP_DEST_PUSH: | ||
1190 | state->stack_size += 8; | ||
1191 | if (cfa->base == CFI_SP) | ||
1192 | cfa->offset += 8; | ||
1193 | |||
1194 | if (op->src.type != OP_SRC_REG) | ||
1195 | break; | ||
1196 | |||
1197 | if (state->drap) { | ||
1198 | if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { | ||
1199 | |||
1200 | /* drap: push %drap */ | ||
1201 | cfa->base = CFI_BP_INDIRECT; | ||
1202 | cfa->offset = -state->stack_size; | ||
1203 | |||
1204 | /* save drap so we know when to undefine it */ | ||
1205 | save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); | ||
1206 | |||
1207 | } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) { | ||
1208 | |||
1209 | /* drap: push %rbp */ | ||
1210 | state->stack_size = 0; | ||
1211 | |||
1212 | } else if (regs[op->src.reg].base == CFI_UNDEFINED) { | ||
1213 | |||
1214 | /* drap: push %reg */ | ||
1215 | save_reg(state, op->src.reg, CFI_BP, -state->stack_size); | ||
1216 | } | ||
1217 | |||
1218 | } else { | ||
1219 | |||
1220 | /* push %reg */ | ||
1221 | save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); | ||
1222 | } | ||
1223 | |||
1224 | /* detect when asm code uses rbp as a scratch register */ | ||
1225 | if (!nofp && insn->func && op->src.reg == CFI_BP && | ||
1226 | cfa->base != CFI_BP) | ||
1227 | state->bp_scratch = true; | ||
1228 | break; | ||
1229 | |||
1230 | case OP_DEST_REG_INDIRECT: | ||
1231 | |||
1232 | if (state->drap) { | ||
1233 | if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { | ||
1234 | |||
1235 | /* drap: mov %drap, disp(%rbp) */ | ||
1236 | cfa->base = CFI_BP_INDIRECT; | ||
1237 | cfa->offset = op->dest.offset; | ||
1238 | |||
1239 | /* save drap so we know when to undefine it */ | ||
1240 | save_reg(state, op->src.reg, CFI_CFA, op->dest.offset); | ||
1241 | } | ||
1242 | |||
1243 | else if (regs[op->src.reg].base == CFI_UNDEFINED) { | ||
1244 | |||
1245 | /* drap: mov reg, disp(%rbp) */ | ||
1246 | save_reg(state, op->src.reg, CFI_BP, op->dest.offset); | ||
1247 | } | ||
1248 | |||
1249 | } else if (op->dest.reg == cfa->base) { | ||
1250 | |||
1251 | /* mov reg, disp(%rbp) */ | ||
1252 | /* mov reg, disp(%rsp) */ | ||
1253 | save_reg(state, op->src.reg, CFI_CFA, | ||
1254 | op->dest.offset - state->cfa.offset); | ||
1255 | } | ||
1256 | |||
1257 | break; | ||
1258 | |||
1259 | case OP_DEST_LEAVE: | ||
1260 | if ((!state->drap && cfa->base != CFI_BP) || | ||
1261 | (state->drap && cfa->base != state->drap_reg)) { | ||
1262 | WARN_FUNC("leave instruction with modified stack frame", | ||
1263 | insn->sec, insn->offset); | ||
1264 | return -1; | ||
1265 | } | ||
1266 | |||
1267 | /* leave (mov %rbp, %rsp; pop %rbp) */ | ||
1268 | |||
1269 | state->stack_size = -state->regs[CFI_BP].offset - 8; | ||
1270 | restore_reg(state, CFI_BP); | ||
1271 | |||
1272 | if (!state->drap) { | ||
1273 | cfa->base = CFI_SP; | ||
1274 | cfa->offset -= 8; | ||
1275 | } | ||
1276 | |||
1277 | break; | ||
1278 | |||
1279 | case OP_DEST_MEM: | ||
1280 | if (op->src.type != OP_SRC_POP) { | ||
1281 | WARN_FUNC("unknown stack-related memory operation", | ||
1282 | insn->sec, insn->offset); | ||
1283 | return -1; | ||
1284 | } | ||
1285 | |||
1286 | /* pop mem */ | ||
1287 | state->stack_size -= 8; | ||
1288 | if (cfa->base == CFI_SP) | ||
1289 | cfa->offset -= 8; | ||
1290 | |||
1291 | break; | ||
1292 | |||
1293 | default: | ||
1294 | WARN_FUNC("unknown stack-related instruction", | ||
1295 | insn->sec, insn->offset); | ||
1296 | return -1; | ||
1297 | } | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | static bool insn_state_match(struct instruction *insn, struct insn_state *state) | ||
1303 | { | ||
1304 | struct insn_state *state1 = &insn->state, *state2 = state; | ||
1305 | int i; | ||
1306 | |||
1307 | if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) { | ||
1308 | WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d", | ||
1309 | insn->sec, insn->offset, | ||
1310 | state1->cfa.base, state1->cfa.offset, | ||
1311 | state2->cfa.base, state2->cfa.offset); | ||
1312 | |||
1313 | } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) { | ||
1314 | for (i = 0; i < CFI_NUM_REGS; i++) { | ||
1315 | if (!memcmp(&state1->regs[i], &state2->regs[i], | ||
1316 | sizeof(struct cfi_reg))) | ||
1317 | continue; | ||
1318 | |||
1319 | WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", | ||
1320 | insn->sec, insn->offset, | ||
1321 | i, state1->regs[i].base, state1->regs[i].offset, | ||
1322 | i, state2->regs[i].base, state2->regs[i].offset); | ||
1323 | break; | ||
1324 | } | ||
1325 | |||
1326 | } else if (state1->drap != state2->drap || | ||
1327 | (state1->drap && state1->drap_reg != state2->drap_reg)) { | ||
1328 | WARN_FUNC("stack state mismatch: drap1=%d(%d) drap2=%d(%d)", | ||
1329 | insn->sec, insn->offset, | ||
1330 | state1->drap, state1->drap_reg, | ||
1331 | state2->drap, state2->drap_reg); | ||
1332 | |||
1333 | } else | ||
1334 | return true; | ||
1335 | |||
1336 | return false; | ||
1337 | } | ||
1338 | |||
1339 | /* | ||
1340 | * Follow the branch starting at the given instruction, and recursively follow | ||
1341 | * any other branches (jumps). Meanwhile, track the frame pointer state at | ||
1342 | * each instruction and validate all the rules described in | ||
1343 | * tools/objtool/Documentation/stack-validation.txt. | ||
1344 | */ | ||
1345 | static int validate_branch(struct objtool_file *file, struct instruction *first, | ||
1346 | struct insn_state state) | ||
1347 | { | ||
1348 | struct alternative *alt; | ||
1349 | struct instruction *insn; | ||
1350 | struct section *sec; | ||
1351 | struct symbol *func = NULL; | ||
1352 | int ret; | ||
1353 | |||
1354 | insn = first; | ||
1355 | sec = insn->sec; | ||
1356 | |||
1357 | if (insn->alt_group && list_empty(&insn->alts)) { | ||
1358 | WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", | ||
1359 | sec, insn->offset); | ||
1360 | return -1; | ||
1361 | } | ||
1362 | |||
1363 | while (1) { | ||
1364 | if (file->c_file && insn->func) { | ||
1365 | if (func && func != insn->func) { | ||
1366 | WARN("%s() falls through to next function %s()", | ||
1367 | func->name, insn->func->name); | ||
1368 | return 1; | ||
1369 | } | ||
1370 | } | ||
1371 | |||
1372 | func = insn->func; | ||
1373 | |||
1374 | if (insn->visited) { | ||
1375 | if (!!insn_state_match(insn, &state)) | ||
1376 | return 1; | ||
1377 | |||
1378 | return 0; | ||
1379 | } | ||
1380 | |||
1381 | insn->state = state; | ||
1382 | |||
1383 | insn->visited = true; | ||
1384 | |||
1385 | list_for_each_entry(alt, &insn->alts, list) { | ||
1386 | ret = validate_branch(file, alt->insn, state); | ||
1387 | if (ret) | ||
1388 | return 1; | ||
1389 | } | ||
1390 | |||
1391 | switch (insn->type) { | ||
1392 | |||
1393 | case INSN_RETURN: | ||
1394 | if (func && has_modified_stack_frame(&state)) { | ||
1395 | WARN_FUNC("return with modified stack frame", | ||
1396 | sec, insn->offset); | ||
1397 | return 1; | ||
1398 | } | ||
1399 | |||
1400 | if (state.bp_scratch) { | ||
1401 | WARN("%s uses BP as a scratch register", | ||
1402 | insn->func->name); | ||
1403 | return 1; | ||
1404 | } | ||
1405 | |||
1406 | return 0; | ||
1407 | |||
1408 | case INSN_CALL: | ||
1409 | if (is_fentry_call(insn)) | ||
1410 | break; | ||
1411 | |||
1412 | ret = dead_end_function(file, insn->call_dest); | ||
1413 | if (ret == 1) | ||
1414 | return 0; | ||
1415 | if (ret == -1) | ||
1416 | return 1; | ||
1417 | |||
1418 | /* fallthrough */ | ||
1419 | case INSN_CALL_DYNAMIC: | ||
1420 | if (!nofp && func && !has_valid_stack_frame(&state)) { | ||
1421 | WARN_FUNC("call without frame pointer save/setup", | ||
1422 | sec, insn->offset); | ||
1423 | return 1; | ||
1424 | } | ||
1425 | break; | ||
1426 | |||
1427 | case INSN_JUMP_CONDITIONAL: | ||
1428 | case INSN_JUMP_UNCONDITIONAL: | ||
1429 | if (insn->jump_dest) { | ||
1430 | ret = validate_branch(file, insn->jump_dest, | ||
1431 | state); | ||
1432 | if (ret) | ||
1433 | return 1; | ||
1434 | } else if (func && has_modified_stack_frame(&state)) { | ||
1435 | WARN_FUNC("sibling call from callable instruction with modified stack frame", | ||
1436 | sec, insn->offset); | ||
1437 | return 1; | ||
1438 | } /* else it's a sibling call */ | ||
1439 | |||
1440 | if (insn->type == INSN_JUMP_UNCONDITIONAL) | ||
1441 | return 0; | ||
1442 | |||
1443 | break; | ||
1444 | |||
1445 | case INSN_JUMP_DYNAMIC: | ||
1446 | if (func && list_empty(&insn->alts) && | ||
1447 | has_modified_stack_frame(&state)) { | ||
1448 | WARN_FUNC("sibling call from callable instruction with modified stack frame", | ||
1449 | sec, insn->offset); | ||
1450 | return 1; | ||
1451 | } | ||
1452 | |||
1453 | return 0; | ||
1454 | |||
1455 | case INSN_STACK: | ||
1456 | if (update_insn_state(insn, &state)) | ||
1457 | return -1; | ||
1458 | |||
1459 | break; | ||
1460 | |||
1461 | default: | ||
1462 | break; | ||
1463 | } | ||
1464 | |||
1465 | if (insn->dead_end) | ||
1466 | return 0; | ||
1467 | |||
1468 | insn = next_insn_same_sec(file, insn); | ||
1469 | if (!insn) { | ||
1470 | WARN("%s: unexpected end of section", sec->name); | ||
1471 | return 1; | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1475 | return 0; | ||
1476 | } | ||
1477 | |||
1478 | static bool is_kasan_insn(struct instruction *insn) | ||
1479 | { | ||
1480 | return (insn->type == INSN_CALL && | ||
1481 | !strcmp(insn->call_dest->name, "__asan_handle_no_return")); | ||
1482 | } | ||
1483 | |||
1484 | static bool is_ubsan_insn(struct instruction *insn) | ||
1485 | { | ||
1486 | return (insn->type == INSN_CALL && | ||
1487 | !strcmp(insn->call_dest->name, | ||
1488 | "__ubsan_handle_builtin_unreachable")); | ||
1489 | } | ||
1490 | |||
1491 | static bool ignore_unreachable_insn(struct instruction *insn) | ||
1492 | { | ||
1493 | int i; | ||
1494 | |||
1495 | if (insn->ignore || insn->type == INSN_NOP) | ||
1496 | return true; | ||
1497 | |||
1498 | /* | ||
1499 | * Ignore any unused exceptions. This can happen when a whitelisted | ||
1500 | * function has an exception table entry. | ||
1501 | */ | ||
1502 | if (!strcmp(insn->sec->name, ".fixup")) | ||
1503 | return true; | ||
1504 | |||
1505 | /* | ||
1506 | * Check if this (or a subsequent) instruction is related to | ||
1507 | * CONFIG_UBSAN or CONFIG_KASAN. | ||
1508 | * | ||
1509 | * End the search at 5 instructions to avoid going into the weeds. | ||
1510 | */ | ||
1511 | if (!insn->func) | ||
1512 | return false; | ||
1513 | for (i = 0; i < 5; i++) { | ||
1514 | |||
1515 | if (is_kasan_insn(insn) || is_ubsan_insn(insn)) | ||
1516 | return true; | ||
1517 | |||
1518 | if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { | ||
1519 | insn = insn->jump_dest; | ||
1520 | continue; | ||
1521 | } | ||
1522 | |||
1523 | if (insn->offset + insn->len >= insn->func->offset + insn->func->len) | ||
1524 | break; | ||
1525 | insn = list_next_entry(insn, list); | ||
1526 | } | ||
1527 | |||
1528 | return false; | ||
1529 | } | ||
1530 | |||
1531 | static int validate_functions(struct objtool_file *file) | ||
1532 | { | ||
1533 | struct section *sec; | ||
1534 | struct symbol *func; | ||
1535 | struct instruction *insn; | ||
1536 | struct insn_state state; | ||
1537 | int ret, warnings = 0; | ||
1538 | |||
1539 | clear_insn_state(&state); | ||
1540 | |||
1541 | state.cfa = initial_func_cfi.cfa; | ||
1542 | memcpy(&state.regs, &initial_func_cfi.regs, | ||
1543 | CFI_NUM_REGS * sizeof(struct cfi_reg)); | ||
1544 | state.stack_size = initial_func_cfi.cfa.offset; | ||
1545 | |||
1546 | for_each_sec(file, sec) { | ||
1547 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
1548 | if (func->type != STT_FUNC) | ||
1549 | continue; | ||
1550 | |||
1551 | insn = find_insn(file, sec, func->offset); | ||
1552 | if (!insn || insn->ignore) | ||
1553 | continue; | ||
1554 | |||
1555 | ret = validate_branch(file, insn, state); | ||
1556 | warnings += ret; | ||
1557 | } | ||
1558 | } | ||
1559 | |||
1560 | return warnings; | ||
1561 | } | ||
1562 | |||
1563 | static int validate_reachable_instructions(struct objtool_file *file) | ||
1564 | { | ||
1565 | struct instruction *insn; | ||
1566 | |||
1567 | if (file->ignore_unreachables) | ||
1568 | return 0; | ||
1569 | |||
1570 | for_each_insn(file, insn) { | ||
1571 | if (insn->visited || ignore_unreachable_insn(insn)) | ||
1572 | continue; | ||
1573 | |||
1574 | /* | ||
1575 | * gcov produces a lot of unreachable instructions. If we get | ||
1576 | * an unreachable warning and the file has gcov enabled, just | ||
1577 | * ignore it, and all other such warnings for the file. Do | ||
1578 | * this here because this is an expensive function. | ||
1579 | */ | ||
1580 | if (gcov_enabled(file)) | ||
1581 | return 0; | ||
1582 | |||
1583 | WARN_FUNC("unreachable instruction", insn->sec, insn->offset); | ||
1584 | return 1; | ||
1585 | } | ||
1586 | |||
1587 | return 0; | ||
1588 | } | ||
1589 | |||
1590 | static void cleanup(struct objtool_file *file) | ||
1591 | { | ||
1592 | struct instruction *insn, *tmpinsn; | ||
1593 | struct alternative *alt, *tmpalt; | ||
1594 | |||
1595 | list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { | ||
1596 | list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { | ||
1597 | list_del(&alt->list); | ||
1598 | free(alt); | ||
1599 | } | ||
1600 | list_del(&insn->list); | ||
1601 | hash_del(&insn->hash); | ||
1602 | free(insn); | ||
1603 | } | ||
1604 | elf_close(file->elf); | ||
1605 | } | ||
1606 | |||
1607 | int check(const char *_objname, bool _nofp) | ||
1608 | { | ||
1609 | struct objtool_file file; | ||
1610 | int ret, warnings = 0; | ||
1611 | |||
1612 | objname = _objname; | ||
1613 | nofp = _nofp; | ||
1614 | |||
1615 | file.elf = elf_open(objname); | ||
1616 | if (!file.elf) | ||
1617 | return 1; | ||
1618 | |||
1619 | INIT_LIST_HEAD(&file.insn_list); | ||
1620 | hash_init(file.insn_hash); | ||
1621 | file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); | ||
1622 | file.rodata = find_section_by_name(file.elf, ".rodata"); | ||
1623 | file.ignore_unreachables = false; | ||
1624 | file.c_file = find_section_by_name(file.elf, ".comment"); | ||
1625 | |||
1626 | arch_initial_func_cfi_state(&initial_func_cfi); | ||
1627 | |||
1628 | ret = decode_sections(&file); | ||
1629 | if (ret < 0) | ||
1630 | goto out; | ||
1631 | warnings += ret; | ||
1632 | |||
1633 | if (list_empty(&file.insn_list)) | ||
1634 | goto out; | ||
1635 | |||
1636 | ret = validate_functions(&file); | ||
1637 | if (ret < 0) | ||
1638 | goto out; | ||
1639 | warnings += ret; | ||
1640 | |||
1641 | if (!warnings) { | ||
1642 | ret = validate_reachable_instructions(&file); | ||
1643 | if (ret < 0) | ||
1644 | goto out; | ||
1645 | warnings += ret; | ||
1646 | } | ||
1647 | |||
1648 | out: | ||
1649 | cleanup(&file); | ||
1650 | |||
1651 | /* ignore warnings for now until we get all the code cleaned up */ | ||
1652 | if (ret || warnings) | ||
1653 | return 0; | ||
1654 | return 0; | ||
1655 | } | ||
diff --git a/tools/objtool/check.h b/tools/objtool/check.h new file mode 100644 index 000000000000..da85f5b00ec6 --- /dev/null +++ b/tools/objtool/check.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _CHECK_H | ||
19 | #define _CHECK_H | ||
20 | |||
21 | #include <stdbool.h> | ||
22 | #include "elf.h" | ||
23 | #include "cfi.h" | ||
24 | #include "arch.h" | ||
25 | #include <linux/hashtable.h> | ||
26 | |||
27 | struct insn_state { | ||
28 | struct cfi_reg cfa; | ||
29 | struct cfi_reg regs[CFI_NUM_REGS]; | ||
30 | int stack_size; | ||
31 | bool bp_scratch; | ||
32 | bool drap; | ||
33 | int drap_reg; | ||
34 | }; | ||
35 | |||
36 | struct instruction { | ||
37 | struct list_head list; | ||
38 | struct hlist_node hash; | ||
39 | struct section *sec; | ||
40 | unsigned long offset; | ||
41 | unsigned int len; | ||
42 | unsigned char type; | ||
43 | unsigned long immediate; | ||
44 | bool alt_group, visited, dead_end, ignore; | ||
45 | struct symbol *call_dest; | ||
46 | struct instruction *jump_dest; | ||
47 | struct list_head alts; | ||
48 | struct symbol *func; | ||
49 | struct stack_op stack_op; | ||
50 | struct insn_state state; | ||
51 | }; | ||
52 | |||
53 | struct objtool_file { | ||
54 | struct elf *elf; | ||
55 | struct list_head insn_list; | ||
56 | DECLARE_HASHTABLE(insn_hash, 16); | ||
57 | struct section *rodata, *whitelist; | ||
58 | bool ignore_unreachables, c_file; | ||
59 | }; | ||
60 | |||
61 | int check(const char *objname, bool nofp); | ||
62 | |||
63 | #define for_each_insn(file, insn) \ | ||
64 | list_for_each_entry(insn, &file->insn_list, list) | ||
65 | |||
66 | #endif /* _CHECK_H */ | ||
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index d897702ce742..1a7e8aa2af58 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c | |||
@@ -37,6 +37,9 @@ | |||
37 | #define ELF_C_READ_MMAP ELF_C_READ | 37 | #define ELF_C_READ_MMAP ELF_C_READ |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | #define WARN_ELF(format, ...) \ | ||
41 | WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) | ||
42 | |||
40 | struct section *find_section_by_name(struct elf *elf, const char *name) | 43 | struct section *find_section_by_name(struct elf *elf, const char *name) |
41 | { | 44 | { |
42 | struct section *sec; | 45 | struct section *sec; |
@@ -139,12 +142,12 @@ static int read_sections(struct elf *elf) | |||
139 | int i; | 142 | int i; |
140 | 143 | ||
141 | if (elf_getshdrnum(elf->elf, §ions_nr)) { | 144 | if (elf_getshdrnum(elf->elf, §ions_nr)) { |
142 | perror("elf_getshdrnum"); | 145 | WARN_ELF("elf_getshdrnum"); |
143 | return -1; | 146 | return -1; |
144 | } | 147 | } |
145 | 148 | ||
146 | if (elf_getshdrstrndx(elf->elf, &shstrndx)) { | 149 | if (elf_getshdrstrndx(elf->elf, &shstrndx)) { |
147 | perror("elf_getshdrstrndx"); | 150 | WARN_ELF("elf_getshdrstrndx"); |
148 | return -1; | 151 | return -1; |
149 | } | 152 | } |
150 | 153 | ||
@@ -165,37 +168,36 @@ static int read_sections(struct elf *elf) | |||
165 | 168 | ||
166 | s = elf_getscn(elf->elf, i); | 169 | s = elf_getscn(elf->elf, i); |
167 | if (!s) { | 170 | if (!s) { |
168 | perror("elf_getscn"); | 171 | WARN_ELF("elf_getscn"); |
169 | return -1; | 172 | return -1; |
170 | } | 173 | } |
171 | 174 | ||
172 | sec->idx = elf_ndxscn(s); | 175 | sec->idx = elf_ndxscn(s); |
173 | 176 | ||
174 | if (!gelf_getshdr(s, &sec->sh)) { | 177 | if (!gelf_getshdr(s, &sec->sh)) { |
175 | perror("gelf_getshdr"); | 178 | WARN_ELF("gelf_getshdr"); |
176 | return -1; | 179 | return -1; |
177 | } | 180 | } |
178 | 181 | ||
179 | sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); | 182 | sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); |
180 | if (!sec->name) { | 183 | if (!sec->name) { |
181 | perror("elf_strptr"); | 184 | WARN_ELF("elf_strptr"); |
182 | return -1; | 185 | return -1; |
183 | } | 186 | } |
184 | 187 | ||
185 | sec->elf_data = elf_getdata(s, NULL); | 188 | sec->data = elf_getdata(s, NULL); |
186 | if (!sec->elf_data) { | 189 | if (!sec->data) { |
187 | perror("elf_getdata"); | 190 | WARN_ELF("elf_getdata"); |
188 | return -1; | 191 | return -1; |
189 | } | 192 | } |
190 | 193 | ||
191 | if (sec->elf_data->d_off != 0 || | 194 | if (sec->data->d_off != 0 || |
192 | sec->elf_data->d_size != sec->sh.sh_size) { | 195 | sec->data->d_size != sec->sh.sh_size) { |
193 | WARN("unexpected data attributes for %s", sec->name); | 196 | WARN("unexpected data attributes for %s", sec->name); |
194 | return -1; | 197 | return -1; |
195 | } | 198 | } |
196 | 199 | ||
197 | sec->data = (unsigned long)sec->elf_data->d_buf; | 200 | sec->len = sec->data->d_size; |
198 | sec->len = sec->elf_data->d_size; | ||
199 | } | 201 | } |
200 | 202 | ||
201 | /* sanity check, one more call to elf_nextscn() should return NULL */ | 203 | /* sanity check, one more call to elf_nextscn() should return NULL */ |
@@ -232,15 +234,15 @@ static int read_symbols(struct elf *elf) | |||
232 | 234 | ||
233 | sym->idx = i; | 235 | sym->idx = i; |
234 | 236 | ||
235 | if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { | 237 | if (!gelf_getsym(symtab->data, i, &sym->sym)) { |
236 | perror("gelf_getsym"); | 238 | WARN_ELF("gelf_getsym"); |
237 | goto err; | 239 | goto err; |
238 | } | 240 | } |
239 | 241 | ||
240 | sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, | 242 | sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, |
241 | sym->sym.st_name); | 243 | sym->sym.st_name); |
242 | if (!sym->name) { | 244 | if (!sym->name) { |
243 | perror("elf_strptr"); | 245 | WARN_ELF("elf_strptr"); |
244 | goto err; | 246 | goto err; |
245 | } | 247 | } |
246 | 248 | ||
@@ -322,8 +324,8 @@ static int read_relas(struct elf *elf) | |||
322 | } | 324 | } |
323 | memset(rela, 0, sizeof(*rela)); | 325 | memset(rela, 0, sizeof(*rela)); |
324 | 326 | ||
325 | if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { | 327 | if (!gelf_getrela(sec->data, i, &rela->rela)) { |
326 | perror("gelf_getrela"); | 328 | WARN_ELF("gelf_getrela"); |
327 | return -1; | 329 | return -1; |
328 | } | 330 | } |
329 | 331 | ||
@@ -362,12 +364,6 @@ struct elf *elf_open(const char *name) | |||
362 | 364 | ||
363 | INIT_LIST_HEAD(&elf->sections); | 365 | INIT_LIST_HEAD(&elf->sections); |
364 | 366 | ||
365 | elf->name = strdup(name); | ||
366 | if (!elf->name) { | ||
367 | perror("strdup"); | ||
368 | goto err; | ||
369 | } | ||
370 | |||
371 | elf->fd = open(name, O_RDONLY); | 367 | elf->fd = open(name, O_RDONLY); |
372 | if (elf->fd == -1) { | 368 | if (elf->fd == -1) { |
373 | perror("open"); | 369 | perror("open"); |
@@ -376,12 +372,12 @@ struct elf *elf_open(const char *name) | |||
376 | 372 | ||
377 | elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); | 373 | elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); |
378 | if (!elf->elf) { | 374 | if (!elf->elf) { |
379 | perror("elf_begin"); | 375 | WARN_ELF("elf_begin"); |
380 | goto err; | 376 | goto err; |
381 | } | 377 | } |
382 | 378 | ||
383 | if (!gelf_getehdr(elf->elf, &elf->ehdr)) { | 379 | if (!gelf_getehdr(elf->elf, &elf->ehdr)) { |
384 | perror("gelf_getehdr"); | 380 | WARN_ELF("gelf_getehdr"); |
385 | goto err; | 381 | goto err; |
386 | } | 382 | } |
387 | 383 | ||
@@ -407,6 +403,12 @@ void elf_close(struct elf *elf) | |||
407 | struct symbol *sym, *tmpsym; | 403 | struct symbol *sym, *tmpsym; |
408 | struct rela *rela, *tmprela; | 404 | struct rela *rela, *tmprela; |
409 | 405 | ||
406 | if (elf->elf) | ||
407 | elf_end(elf->elf); | ||
408 | |||
409 | if (elf->fd > 0) | ||
410 | close(elf->fd); | ||
411 | |||
410 | list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { | 412 | list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { |
411 | list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { | 413 | list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { |
412 | list_del(&sym->list); | 414 | list_del(&sym->list); |
@@ -421,11 +423,6 @@ void elf_close(struct elf *elf) | |||
421 | list_del(&sec->list); | 423 | list_del(&sec->list); |
422 | free(sec); | 424 | free(sec); |
423 | } | 425 | } |
424 | if (elf->name) | 426 | |
425 | free(elf->name); | ||
426 | if (elf->fd > 0) | ||
427 | close(elf->fd); | ||
428 | if (elf->elf) | ||
429 | elf_end(elf->elf); | ||
430 | free(elf); | 427 | free(elf); |
431 | } | 428 | } |
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 731973e1a3f5..343968b778cb 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h | |||
@@ -37,10 +37,9 @@ struct section { | |||
37 | DECLARE_HASHTABLE(rela_hash, 16); | 37 | DECLARE_HASHTABLE(rela_hash, 16); |
38 | struct section *base, *rela; | 38 | struct section *base, *rela; |
39 | struct symbol *sym; | 39 | struct symbol *sym; |
40 | Elf_Data *elf_data; | 40 | Elf_Data *data; |
41 | char *name; | 41 | char *name; |
42 | int idx; | 42 | int idx; |
43 | unsigned long data; | ||
44 | unsigned int len; | 43 | unsigned int len; |
45 | }; | 44 | }; |
46 | 45 | ||
@@ -86,6 +85,7 @@ struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, | |||
86 | struct symbol *find_containing_func(struct section *sec, unsigned long offset); | 85 | struct symbol *find_containing_func(struct section *sec, unsigned long offset); |
87 | void elf_close(struct elf *elf); | 86 | void elf_close(struct elf *elf); |
88 | 87 | ||
89 | 88 | #define for_each_sec(file, sec) \ | |
89 | list_for_each_entry(sec, &file->elf->sections, list) | ||
90 | 90 | ||
91 | #endif /* _OBJTOOL_ELF_H */ | 91 | #endif /* _OBJTOOL_ELF_H */ |
diff --git a/tools/objtool/special.c b/tools/objtool/special.c index bff8abb3a4aa..84f001d52322 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c | |||
@@ -91,16 +91,16 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, | |||
91 | alt->jump_or_nop = entry->jump_or_nop; | 91 | alt->jump_or_nop = entry->jump_or_nop; |
92 | 92 | ||
93 | if (alt->group) { | 93 | if (alt->group) { |
94 | alt->orig_len = *(unsigned char *)(sec->data + offset + | 94 | alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset + |
95 | entry->orig_len); | 95 | entry->orig_len); |
96 | alt->new_len = *(unsigned char *)(sec->data + offset + | 96 | alt->new_len = *(unsigned char *)(sec->data->d_buf + offset + |
97 | entry->new_len); | 97 | entry->new_len); |
98 | } | 98 | } |
99 | 99 | ||
100 | if (entry->feature) { | 100 | if (entry->feature) { |
101 | unsigned short feature; | 101 | unsigned short feature; |
102 | 102 | ||
103 | feature = *(unsigned short *)(sec->data + offset + | 103 | feature = *(unsigned short *)(sec->data->d_buf + offset + |
104 | entry->feature); | 104 | entry->feature); |
105 | 105 | ||
106 | /* | 106 | /* |
diff --git a/tools/objtool/warn.h b/tools/objtool/warn.h index ac7e07523e84..afd9f7a05f6d 100644 --- a/tools/objtool/warn.h +++ b/tools/objtool/warn.h | |||
@@ -18,6 +18,13 @@ | |||
18 | #ifndef _WARN_H | 18 | #ifndef _WARN_H |
19 | #define _WARN_H | 19 | #define _WARN_H |
20 | 20 | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <fcntl.h> | ||
26 | #include "elf.h" | ||
27 | |||
21 | extern const char *objname; | 28 | extern const char *objname; |
22 | 29 | ||
23 | static inline char *offstr(struct section *sec, unsigned long offset) | 30 | static inline char *offstr(struct section *sec, unsigned long offset) |
@@ -57,4 +64,7 @@ static inline char *offstr(struct section *sec, unsigned long offset) | |||
57 | free(_str); \ | 64 | free(_str); \ |
58 | }) | 65 | }) |
59 | 66 | ||
67 | #define WARN_ELF(format, ...) \ | ||
68 | WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) | ||
69 | |||
60 | #endif /* _WARN_H */ | 70 | #endif /* _WARN_H */ |
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index b0b3007d3c9c..4b6cdbf8f935 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt | |||
@@ -108,6 +108,9 @@ approach is available to export the data to a postgresql database. Refer to | |||
108 | script export-to-postgresql.py for more details, and to script | 108 | script export-to-postgresql.py for more details, and to script |
109 | call-graph-from-postgresql.py for an example of using the database. | 109 | call-graph-from-postgresql.py for an example of using the database. |
110 | 110 | ||
111 | There is also script intel-pt-events.py which provides an example of how to | ||
112 | unpack the raw data for power events and PTWRITE. | ||
113 | |||
111 | As mentioned above, it is easy to capture too much data. One way to limit the | 114 | As mentioned above, it is easy to capture too much data. One way to limit the |
112 | data captured is to use 'snapshot' mode which is explained further below. | 115 | data captured is to use 'snapshot' mode which is explained further below. |
113 | Refer to 'new snapshot option' and 'Intel PT modes of operation' further below. | 116 | Refer to 'new snapshot option' and 'Intel PT modes of operation' further below. |
@@ -364,6 +367,42 @@ cyc_thresh Specifies how frequently CYC packets are produced - see cyc | |||
364 | 367 | ||
365 | CYC packets are not requested by default. | 368 | CYC packets are not requested by default. |
366 | 369 | ||
370 | pt Specifies pass-through which enables the 'branch' config term. | ||
371 | |||
372 | The default config selects 'pt' if it is available, so a user will | ||
373 | never need to specify this term. | ||
374 | |||
375 | branch Enable branch tracing. Branch tracing is enabled by default so to | ||
376 | disable branch tracing use 'branch=0'. | ||
377 | |||
378 | The default config selects 'branch' if it is available. | ||
379 | |||
380 | ptw Enable PTWRITE packets which are produced when a ptwrite instruction | ||
381 | is executed. | ||
382 | |||
383 | Support for this feature is indicated by: | ||
384 | |||
385 | /sys/bus/event_source/devices/intel_pt/caps/ptwrite | ||
386 | |||
387 | which contains "1" if the feature is supported and | ||
388 | "0" otherwise. | ||
389 | |||
390 | fup_on_ptw Enable a FUP packet to follow the PTWRITE packet. The FUP packet | ||
391 | provides the address of the ptwrite instruction. In the absence of | ||
392 | fup_on_ptw, the decoder will use the address of the previous branch | ||
393 | if branch tracing is enabled, otherwise the address will be zero. | ||
394 | Note that fup_on_ptw will work even when branch tracing is disabled. | ||
395 | |||
396 | pwr_evt Enable power events. The power events provide information about | ||
397 | changes to the CPU C-state. | ||
398 | |||
399 | Support for this feature is indicated by: | ||
400 | |||
401 | /sys/bus/event_source/devices/intel_pt/caps/power_event_trace | ||
402 | |||
403 | which contains "1" if the feature is supported and | ||
404 | "0" otherwise. | ||
405 | |||
367 | 406 | ||
368 | new snapshot option | 407 | new snapshot option |
369 | ------------------- | 408 | ------------------- |
@@ -674,13 +713,15 @@ Having no option is the same as | |||
674 | 713 | ||
675 | which, in turn, is the same as | 714 | which, in turn, is the same as |
676 | 715 | ||
677 | --itrace=ibxe | 716 | --itrace=ibxwpe |
678 | 717 | ||
679 | The letters are: | 718 | The letters are: |
680 | 719 | ||
681 | i synthesize "instructions" events | 720 | i synthesize "instructions" events |
682 | b synthesize "branches" events | 721 | b synthesize "branches" events |
683 | x synthesize "transactions" events | 722 | x synthesize "transactions" events |
723 | w synthesize "ptwrite" events | ||
724 | p synthesize "power" events | ||
684 | c synthesize branches events (calls only) | 725 | c synthesize branches events (calls only) |
685 | r synthesize branches events (returns only) | 726 | r synthesize branches events (returns only) |
686 | e synthesize tracing error events | 727 | e synthesize tracing error events |
@@ -699,7 +740,40 @@ and "r" can be combined to get calls and returns. | |||
699 | 'flags' field can be used in perf script to determine whether the event is a | 740 | 'flags' field can be used in perf script to determine whether the event is a |
700 | tranasaction start, commit or abort. | 741 | tranasaction start, commit or abort. |
701 | 742 | ||
702 | Error events are new. They show where the decoder lost the trace. Error events | 743 | Note that "instructions", "branches" and "transactions" events depend on code |
744 | flow packets which can be disabled by using the config term "branch=0". Refer | ||
745 | to the config terms section above. | ||
746 | |||
747 | "ptwrite" events record the payload of the ptwrite instruction and whether | ||
748 | "fup_on_ptw" was used. "ptwrite" events depend on PTWRITE packets which are | ||
749 | recorded only if the "ptw" config term was used. Refer to the config terms | ||
750 | section above. perf script "synth" field displays "ptwrite" information like | ||
751 | this: "ip: 0 payload: 0x123456789abcdef0" where "ip" is 1 if "fup_on_ptw" was | ||
752 | used. | ||
753 | |||
754 | "Power" events correspond to power event packets and CBR (core-to-bus ratio) | ||
755 | packets. While CBR packets are always recorded when tracing is enabled, power | ||
756 | event packets are recorded only if the "pwr_evt" config term was used. Refer to | ||
757 | the config terms section above. The power events record information about | ||
758 | C-state changes, whereas CBR is indicative of CPU frequency. perf script | ||
759 | "event,synth" fields display information like this: | ||
760 | cbr: cbr: 22 freq: 2189 MHz (200%) | ||
761 | mwait: hints: 0x60 extensions: 0x1 | ||
762 | pwre: hw: 0 cstate: 2 sub-cstate: 0 | ||
763 | exstop: ip: 1 | ||
764 | pwrx: deepest cstate: 2 last cstate: 2 wake reason: 0x4 | ||
765 | Where: | ||
766 | "cbr" includes the frequency and the percentage of maximum non-turbo | ||
767 | "mwait" shows mwait hints and extensions | ||
768 | "pwre" shows C-state transitions (to a C-state deeper than C0) and | ||
769 | whether initiated by hardware | ||
770 | "exstop" indicates execution stopped and whether the IP was recorded | ||
771 | exactly, | ||
772 | "pwrx" indicates return to C0 | ||
773 | For more details refer to the Intel 64 and IA-32 Architectures Software | ||
774 | Developer Manuals. | ||
775 | |||
776 | Error events show where the decoder lost the trace. Error events | ||
703 | are quite important. Users must know if what they are seeing is a complete | 777 | are quite important. Users must know if what they are seeing is a complete |
704 | picture or not. | 778 | picture or not. |
705 | 779 | ||
diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index e2a4c5e0dbe5..a3abe04c779d 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt | |||
@@ -3,13 +3,15 @@ | |||
3 | c synthesize branches events (calls only) | 3 | c synthesize branches events (calls only) |
4 | r synthesize branches events (returns only) | 4 | r synthesize branches events (returns only) |
5 | x synthesize transactions events | 5 | x synthesize transactions events |
6 | w synthesize ptwrite events | ||
7 | p synthesize power events | ||
6 | e synthesize error events | 8 | e synthesize error events |
7 | d create a debug log | 9 | d create a debug log |
8 | g synthesize a call chain (use with i or x) | 10 | g synthesize a call chain (use with i or x) |
9 | l synthesize last branch entries (use with i or x) | 11 | l synthesize last branch entries (use with i or x) |
10 | s skip initial number of events | 12 | s skip initial number of events |
11 | 13 | ||
12 | The default is all events i.e. the same as --itrace=ibxe | 14 | The default is all events i.e. the same as --itrace=ibxwpe |
13 | 15 | ||
14 | In addition, the period (default 100000) for instructions events | 16 | In addition, the period (default 100000) for instructions events |
15 | can be specified in units of: | 17 | can be specified in units of: |
@@ -26,8 +28,8 @@ | |||
26 | Also the number of last branch entries (default 64, max. 1024) for | 28 | Also the number of last branch entries (default 64, max. 1024) for |
27 | instructions or transactions events can be specified. | 29 | instructions or transactions events can be specified. |
28 | 30 | ||
29 | It is also possible to skip events generated (instructions, branches, transactions) | 31 | It is also possible to skip events generated (instructions, branches, transactions, |
30 | at the beginning. This is useful to ignore initialization code. | 32 | ptwrite, power) at the beginning. This is useful to ignore initialization code. |
31 | 33 | ||
32 | --itrace=i0nss1000000 | 34 | --itrace=i0nss1000000 |
33 | 35 | ||
diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt index 6e6a8b22c859..721a447f046e 100644 --- a/tools/perf/Documentation/perf-ftrace.txt +++ b/tools/perf/Documentation/perf-ftrace.txt | |||
@@ -48,6 +48,39 @@ OPTIONS | |||
48 | Ranges of CPUs are specified with -: 0-2. | 48 | Ranges of CPUs are specified with -: 0-2. |
49 | Default is to trace on all online CPUs. | 49 | Default is to trace on all online CPUs. |
50 | 50 | ||
51 | -T:: | ||
52 | --trace-funcs=:: | ||
53 | Only trace functions given by the argument. Multiple functions | ||
54 | can be given by using this option more than once. The function | ||
55 | argument also can be a glob pattern. It will be passed to | ||
56 | 'set_ftrace_filter' in tracefs. | ||
57 | |||
58 | -N:: | ||
59 | --notrace-funcs=:: | ||
60 | Do not trace functions given by the argument. Like -T option, | ||
61 | this can be used more than once to specify multiple functions | ||
62 | (or glob patterns). It will be passed to 'set_ftrace_notrace' | ||
63 | in tracefs. | ||
64 | |||
65 | -G:: | ||
66 | --graph-funcs=:: | ||
67 | Set graph filter on the given function (or a glob pattern). | ||
68 | This is useful for the function_graph tracer only and enables | ||
69 | tracing for functions executed from the given function. | ||
70 | This can be used more than once to specify multiple functions. | ||
71 | It will be passed to 'set_graph_function' in tracefs. | ||
72 | |||
73 | -g:: | ||
74 | --nograph-funcs=:: | ||
75 | Set graph notrace filter on the given function (or a glob pattern). | ||
76 | Like -G option, this is useful for the function_graph tracer only | ||
77 | and disables tracing for function executed from the given function. | ||
78 | This can be used more than once to specify multiple functions. | ||
79 | It will be passed to 'set_graph_notrace' in tracefs. | ||
80 | |||
81 | -D:: | ||
82 | --graph-depth=:: | ||
83 | Set max depth for function graph tracer to follow | ||
51 | 84 | ||
52 | SEE ALSO | 85 | SEE ALSO |
53 | -------- | 86 | -------- |
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index e6c9902c6d82..165c2b1d4317 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -240,9 +240,13 @@ Add a probe on schedule() function 12th line with recording cpu local variable: | |||
240 | or | 240 | or |
241 | ./perf probe --add='schedule:12 cpu' | 241 | ./perf probe --add='schedule:12 cpu' |
242 | 242 | ||
243 | this will add one or more probes which has the name start with "schedule". | 243 | Add one or more probes which has the name start with "schedule". |
244 | 244 | ||
245 | Add probes on lines in schedule() function which calls update_rq_clock(). | 245 | ./perf probe schedule* |
246 | or | ||
247 | ./perf probe --add='schedule*' | ||
248 | |||
249 | Add probes on lines in schedule() function which calls update_rq_clock(). | ||
246 | 250 | ||
247 | ./perf probe 'schedule;update_rq_clock*' | 251 | ./perf probe 'schedule;update_rq_clock*' |
248 | or | 252 | or |
diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt index dfbb506d2c34..142606c0ec9c 100644 --- a/tools/perf/Documentation/perf-script-perl.txt +++ b/tools/perf/Documentation/perf-script-perl.txt | |||
@@ -39,7 +39,7 @@ EVENT HANDLERS | |||
39 | When perf script is invoked using a trace script, a user-defined | 39 | When perf script is invoked using a trace script, a user-defined |
40 | 'handler function' is called for each event in the trace. If there's | 40 | 'handler function' is called for each event in the trace. If there's |
41 | no handler function defined for a given event type, the event is | 41 | no handler function defined for a given event type, the event is |
42 | ignored (or passed to a 'trace_handled' function, see below) and the | 42 | ignored (or passed to a 'trace_unhandled' function, see below) and the |
43 | next event is processed. | 43 | next event is processed. |
44 | 44 | ||
45 | Most of the event's field values are passed as arguments to the | 45 | Most of the event's field values are passed as arguments to the |
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt index 54acba221558..51ec2d20068a 100644 --- a/tools/perf/Documentation/perf-script-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt | |||
@@ -149,10 +149,8 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu, | |||
149 | print "id=%d, args=%s\n" % \ | 149 | print "id=%d, args=%s\n" % \ |
150 | (id, args), | 150 | (id, args), |
151 | 151 | ||
152 | def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, | 152 | def trace_unhandled(event_name, context, event_fields_dict): |
153 | common_pid, common_comm): | 153 | print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) |
154 | print_header(event_name, common_cpu, common_secs, common_nsecs, | ||
155 | common_pid, common_comm) | ||
156 | 154 | ||
157 | def print_header(event_name, cpu, secs, nsecs, pid, comm): | 155 | def print_header(event_name, cpu, secs, nsecs, pid, comm): |
158 | print "%-20s %5u %05u.%09u %8u %-20s " % \ | 156 | print "%-20s %5u %05u.%09u %8u %-20s " % \ |
@@ -321,7 +319,7 @@ So those are the essential steps in writing and running a script. The | |||
321 | process can be generalized to any tracepoint or set of tracepoints | 319 | process can be generalized to any tracepoint or set of tracepoints |
322 | you're interested in - basically find the tracepoint(s) you're | 320 | you're interested in - basically find the tracepoint(s) you're |
323 | interested in by looking at the list of available events shown by | 321 | interested in by looking at the list of available events shown by |
324 | 'perf list' and/or look in /sys/kernel/debug/tracing events for | 322 | 'perf list' and/or look in /sys/kernel/debug/tracing/events/ for |
325 | detailed event and field info, record the corresponding trace data | 323 | detailed event and field info, record the corresponding trace data |
326 | using 'perf record', passing it the list of interesting events, | 324 | using 'perf record', passing it the list of interesting events, |
327 | generate a skeleton script using 'perf script -g python' and modify the | 325 | generate a skeleton script using 'perf script -g python' and modify the |
@@ -334,7 +332,7 @@ right place, you can have your script listed alongside the other | |||
334 | scripts listed by the 'perf script -l' command e.g.: | 332 | scripts listed by the 'perf script -l' command e.g.: |
335 | 333 | ||
336 | ---- | 334 | ---- |
337 | root@tropicana:~# perf script -l | 335 | # perf script -l |
338 | List of available trace scripts: | 336 | List of available trace scripts: |
339 | wakeup-latency system-wide min/max/avg wakeup latency | 337 | wakeup-latency system-wide min/max/avg wakeup latency |
340 | rw-by-file <comm> r/w activity for a program, by file | 338 | rw-by-file <comm> r/w activity for a program, by file |
@@ -383,8 +381,6 @@ source tree: | |||
383 | 381 | ||
384 | ---- | 382 | ---- |
385 | # ls -al kernel-source/tools/perf/scripts/python | 383 | # ls -al kernel-source/tools/perf/scripts/python |
386 | |||
387 | root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python | ||
388 | total 32 | 384 | total 32 |
389 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 . | 385 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 . |
390 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. | 386 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. |
@@ -399,7 +395,7 @@ otherwise your script won't show up at run-time), 'perf script -l' | |||
399 | should show a new entry for your script: | 395 | should show a new entry for your script: |
400 | 396 | ||
401 | ---- | 397 | ---- |
402 | root@tropicana:~# perf script -l | 398 | # perf script -l |
403 | List of available trace scripts: | 399 | List of available trace scripts: |
404 | wakeup-latency system-wide min/max/avg wakeup latency | 400 | wakeup-latency system-wide min/max/avg wakeup latency |
405 | rw-by-file <comm> r/w activity for a program, by file | 401 | rw-by-file <comm> r/w activity for a program, by file |
@@ -437,7 +433,7 @@ EVENT HANDLERS | |||
437 | When perf script is invoked using a trace script, a user-defined | 433 | When perf script is invoked using a trace script, a user-defined |
438 | 'handler function' is called for each event in the trace. If there's | 434 | 'handler function' is called for each event in the trace. If there's |
439 | no handler function defined for a given event type, the event is | 435 | no handler function defined for a given event type, the event is |
440 | ignored (or passed to a 'trace_handled' function, see below) and the | 436 | ignored (or passed to a 'trace_unhandled' function, see below) and the |
441 | next event is processed. | 437 | next event is processed. |
442 | 438 | ||
443 | Most of the event's field values are passed as arguments to the | 439 | Most of the event's field values are passed as arguments to the |
@@ -532,7 +528,7 @@ can implement a set of optional functions: | |||
532 | gives scripts a chance to do setup tasks: | 528 | gives scripts a chance to do setup tasks: |
533 | 529 | ||
534 | ---- | 530 | ---- |
535 | def trace_begin: | 531 | def trace_begin(): |
536 | pass | 532 | pass |
537 | ---- | 533 | ---- |
538 | 534 | ||
@@ -541,7 +537,7 @@ def trace_begin: | |||
541 | as display results: | 537 | as display results: |
542 | 538 | ||
543 | ---- | 539 | ---- |
544 | def trace_end: | 540 | def trace_end(): |
545 | pass | 541 | pass |
546 | ---- | 542 | ---- |
547 | 543 | ||
@@ -550,8 +546,7 @@ def trace_end: | |||
550 | of common arguments are passed into it: | 546 | of common arguments are passed into it: |
551 | 547 | ||
552 | ---- | 548 | ---- |
553 | def trace_unhandled(event_name, context, common_cpu, common_secs, | 549 | def trace_unhandled(event_name, context, event_fields_dict): |
554 | common_nsecs, common_pid, common_comm): | ||
555 | pass | 550 | pass |
556 | ---- | 551 | ---- |
557 | 552 | ||
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index cb0eda3925e6..5ee8796be96e 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -116,8 +116,9 @@ OPTIONS | |||
116 | --fields:: | 116 | --fields:: |
117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, | 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, |
119 | srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, | 119 | srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, |
120 | callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw, | 120 | callindent, insn, insnlen, synth. |
121 | Field list can be prepended with the type, trace, sw or hw, | ||
121 | to indicate to which event type the field list applies. | 122 | to indicate to which event type the field list applies. |
122 | e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace | 123 | e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace |
123 | 124 | ||
@@ -130,6 +131,14 @@ OPTIONS | |||
130 | i.e., the specified fields apply to all event types if the type string | 131 | i.e., the specified fields apply to all event types if the type string |
131 | is not given. | 132 | is not given. |
132 | 133 | ||
134 | In addition to overriding fields, it is also possible to add or remove | ||
135 | fields from the defaults. For example | ||
136 | |||
137 | -F -cpu,+insn | ||
138 | |||
139 | removes the cpu field and adds the insn field. Adding/removing fields | ||
140 | cannot be mixed with normal overriding. | ||
141 | |||
133 | The arguments are processed in the order received. A later usage can | 142 | The arguments are processed in the order received. A later usage can |
134 | reset a prior request. e.g.: | 143 | reset a prior request. e.g.: |
135 | 144 | ||
@@ -185,6 +194,9 @@ OPTIONS | |||
185 | instruction bytes and the instruction length of the current | 194 | instruction bytes and the instruction length of the current |
186 | instruction. | 195 | instruction. |
187 | 196 | ||
197 | The synth field is used by synthesized events which may be created when | ||
198 | Instruction Trace decoding. | ||
199 | |||
188 | Finally, a user may not set fields to none for all event types. | 200 | Finally, a user may not set fields to none for all event types. |
189 | i.e., -F "" is not allowed. | 201 | i.e., -F "" is not allowed. |
190 | 202 | ||
@@ -203,6 +215,8 @@ OPTIONS | |||
203 | is printed. This is the full execution path leading to the sample. This is only supported when the | 215 | is printed. This is the full execution path leading to the sample. This is only supported when the |
204 | sample was recorded with perf record -b or -j any. | 216 | sample was recorded with perf record -b or -j any. |
205 | 217 | ||
218 | The brstackoff field will print an offset into a specific dso/binary. | ||
219 | |||
206 | -k:: | 220 | -k:: |
207 | --vmlinux=<file>:: | 221 | --vmlinux=<file>:: |
208 | vmlinux pathname | 222 | vmlinux pathname |
@@ -311,6 +325,10 @@ include::itrace.txt[] | |||
311 | Set the maximum number of program blocks to print with brstackasm for | 325 | Set the maximum number of program blocks to print with brstackasm for |
312 | each sample. | 326 | each sample. |
313 | 327 | ||
328 | --inline:: | ||
329 | If a callgraph address belongs to an inlined function, the inline stack | ||
330 | will be printed. Each entry has function name and file/line. | ||
331 | |||
314 | SEE ALSO | 332 | SEE ALSO |
315 | -------- | 333 | -------- |
316 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 334 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index bd0e4417f2be..698076313606 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -239,6 +239,20 @@ taskset. | |||
239 | --no-merge:: | 239 | --no-merge:: |
240 | Do not merge results from same PMUs. | 240 | Do not merge results from same PMUs. |
241 | 241 | ||
242 | --smi-cost:: | ||
243 | Measure SMI cost if msr/aperf/ and msr/smi/ events are supported. | ||
244 | |||
245 | During the measurement, the /sys/device/cpu/freeze_on_smi will be set to | ||
246 | freeze core counters on SMI. | ||
247 | The aperf counter will not be effected by the setting. | ||
248 | The cost of SMI can be measured by (aperf - unhalted core cycles). | ||
249 | |||
250 | In practice, the percentages of SMI cycles is very useful for performance | ||
251 | oriented analysis. --metric_only will be applied by default. | ||
252 | The output is SMI cycles%, equals to (aperf - unhalted core cycles) / aperf | ||
253 | |||
254 | Users who wants to get the actual value can apply --no-metric-only. | ||
255 | |||
242 | EXAMPLES | 256 | EXAMPLES |
243 | -------- | 257 | -------- |
244 | 258 | ||
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 8354d04b392f..bdf0e87f9b29 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -19,18 +19,18 @@ CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) | |||
19 | 19 | ||
20 | include $(srctree)/tools/scripts/Makefile.arch | 20 | include $(srctree)/tools/scripts/Makefile.arch |
21 | 21 | ||
22 | $(call detected_var,ARCH) | 22 | $(call detected_var,SRCARCH) |
23 | 23 | ||
24 | NO_PERF_REGS := 1 | 24 | NO_PERF_REGS := 1 |
25 | 25 | ||
26 | # Additional ARCH settings for ppc | 26 | # Additional ARCH settings for ppc |
27 | ifeq ($(ARCH),powerpc) | 27 | ifeq ($(SRCARCH),powerpc) |
28 | NO_PERF_REGS := 0 | 28 | NO_PERF_REGS := 0 |
29 | LIBUNWIND_LIBS := -lunwind -lunwind-ppc64 | 29 | LIBUNWIND_LIBS := -lunwind -lunwind-ppc64 |
30 | endif | 30 | endif |
31 | 31 | ||
32 | # Additional ARCH settings for x86 | 32 | # Additional ARCH settings for x86 |
33 | ifeq ($(ARCH),x86) | 33 | ifeq ($(SRCARCH),x86) |
34 | $(call detected,CONFIG_X86) | 34 | $(call detected,CONFIG_X86) |
35 | ifeq (${IS_64_BIT}, 1) | 35 | ifeq (${IS_64_BIT}, 1) |
36 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated | 36 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated |
@@ -43,12 +43,12 @@ ifeq ($(ARCH),x86) | |||
43 | NO_PERF_REGS := 0 | 43 | NO_PERF_REGS := 0 |
44 | endif | 44 | endif |
45 | 45 | ||
46 | ifeq ($(ARCH),arm) | 46 | ifeq ($(SRCARCH),arm) |
47 | NO_PERF_REGS := 0 | 47 | NO_PERF_REGS := 0 |
48 | LIBUNWIND_LIBS = -lunwind -lunwind-arm | 48 | LIBUNWIND_LIBS = -lunwind -lunwind-arm |
49 | endif | 49 | endif |
50 | 50 | ||
51 | ifeq ($(ARCH),arm64) | 51 | ifeq ($(SRCARCH),arm64) |
52 | NO_PERF_REGS := 0 | 52 | NO_PERF_REGS := 0 |
53 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 | 53 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 |
54 | endif | 54 | endif |
@@ -61,7 +61,7 @@ endif | |||
61 | # Disable it on all other architectures in case libdw unwind | 61 | # Disable it on all other architectures in case libdw unwind |
62 | # support is detected in system. Add supported architectures | 62 | # support is detected in system. Add supported architectures |
63 | # to the check. | 63 | # to the check. |
64 | ifneq ($(ARCH),$(filter $(ARCH),x86 arm)) | 64 | ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc)) |
65 | NO_LIBDW_DWARF_UNWIND := 1 | 65 | NO_LIBDW_DWARF_UNWIND := 1 |
66 | endif | 66 | endif |
67 | 67 | ||
@@ -115,9 +115,9 @@ endif | |||
115 | FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS) | 115 | FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS) |
116 | FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf | 116 | FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf |
117 | 117 | ||
118 | FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi | 118 | FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi -I$(srctree)/tools/include/uapi |
119 | # include ARCH specific config | 119 | # include ARCH specific config |
120 | -include $(src-perf)/arch/$(ARCH)/Makefile | 120 | -include $(src-perf)/arch/$(SRCARCH)/Makefile |
121 | 121 | ||
122 | ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET | 122 | ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET |
123 | CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET | 123 | CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET |
@@ -228,12 +228,12 @@ ifeq ($(DEBUG),0) | |||
228 | endif | 228 | endif |
229 | 229 | ||
230 | INC_FLAGS += -I$(src-perf)/util/include | 230 | INC_FLAGS += -I$(src-perf)/util/include |
231 | INC_FLAGS += -I$(src-perf)/arch/$(ARCH)/include | 231 | INC_FLAGS += -I$(src-perf)/arch/$(SRCARCH)/include |
232 | INC_FLAGS += -I$(srctree)/tools/include/uapi | 232 | INC_FLAGS += -I$(srctree)/tools/include/uapi |
233 | INC_FLAGS += -I$(srctree)/tools/include/ | 233 | INC_FLAGS += -I$(srctree)/tools/include/ |
234 | INC_FLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi | 234 | INC_FLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi |
235 | INC_FLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/ | 235 | INC_FLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/ |
236 | INC_FLAGS += -I$(srctree)/tools/arch/$(ARCH)/ | 236 | INC_FLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/ |
237 | 237 | ||
238 | # $(obj-perf) for generated common-cmds.h | 238 | # $(obj-perf) for generated common-cmds.h |
239 | # $(obj-perf)/util for generated bison/flex headers | 239 | # $(obj-perf)/util for generated bison/flex headers |
@@ -355,7 +355,7 @@ ifndef NO_LIBELF | |||
355 | 355 | ||
356 | ifndef NO_DWARF | 356 | ifndef NO_DWARF |
357 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | 357 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) |
358 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | 358 | msg := $(warning DWARF register mappings have not been defined for architecture $(SRCARCH), DWARF support disabled); |
359 | NO_DWARF := 1 | 359 | NO_DWARF := 1 |
360 | else | 360 | else |
361 | CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS) | 361 | CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS) |
@@ -380,7 +380,7 @@ ifndef NO_LIBELF | |||
380 | CFLAGS += -DHAVE_BPF_PROLOGUE | 380 | CFLAGS += -DHAVE_BPF_PROLOGUE |
381 | $(call detected,CONFIG_BPF_PROLOGUE) | 381 | $(call detected,CONFIG_BPF_PROLOGUE) |
382 | else | 382 | else |
383 | msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset()); | 383 | msg := $(warning BPF prologue is not supported by architecture $(SRCARCH), missing regs_query_register_offset()); |
384 | endif | 384 | endif |
385 | else | 385 | else |
386 | msg := $(warning DWARF support is off, BPF prologue is disabled); | 386 | msg := $(warning DWARF support is off, BPF prologue is disabled); |
@@ -406,7 +406,7 @@ ifdef PERF_HAVE_JITDUMP | |||
406 | endif | 406 | endif |
407 | endif | 407 | endif |
408 | 408 | ||
409 | ifeq ($(ARCH),powerpc) | 409 | ifeq ($(SRCARCH),powerpc) |
410 | ifndef NO_DWARF | 410 | ifndef NO_DWARF |
411 | CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX | 411 | CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX |
412 | endif | 412 | endif |
@@ -487,7 +487,7 @@ else | |||
487 | endif | 487 | endif |
488 | 488 | ||
489 | ifndef NO_LOCAL_LIBUNWIND | 489 | ifndef NO_LOCAL_LIBUNWIND |
490 | ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) | 490 | ifeq ($(SRCARCH),$(filter $(SRCARCH),arm arm64)) |
491 | $(call feature_check,libunwind-debug-frame) | 491 | $(call feature_check,libunwind-debug-frame) |
492 | ifneq ($(feature-libunwind-debug-frame), 1) | 492 | ifneq ($(feature-libunwind-debug-frame), 1) |
493 | msg := $(warning No debug_frame support found in libunwind); | 493 | msg := $(warning No debug_frame support found in libunwind); |
@@ -740,7 +740,7 @@ ifeq (${IS_64_BIT}, 1) | |||
740 | NO_PERF_READ_VDSO32 := 1 | 740 | NO_PERF_READ_VDSO32 := 1 |
741 | endif | 741 | endif |
742 | endif | 742 | endif |
743 | ifneq ($(ARCH), x86) | 743 | ifneq ($(SRCARCH), x86) |
744 | NO_PERF_READ_VDSOX32 := 1 | 744 | NO_PERF_READ_VDSOX32 := 1 |
745 | endif | 745 | endif |
746 | ifndef NO_PERF_READ_VDSOX32 | 746 | ifndef NO_PERF_READ_VDSOX32 |
@@ -769,7 +769,7 @@ ifdef LIBBABELTRACE | |||
769 | endif | 769 | endif |
770 | 770 | ||
771 | ifndef NO_AUXTRACE | 771 | ifndef NO_AUXTRACE |
772 | ifeq ($(ARCH),x86) | 772 | ifeq ($(SRCARCH),x86) |
773 | ifeq ($(feature-get_cpuid), 0) | 773 | ifeq ($(feature-get_cpuid), 0) |
774 | msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc); | 774 | msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc); |
775 | NO_AUXTRACE := 1 | 775 | NO_AUXTRACE := 1 |
@@ -872,7 +872,7 @@ sysconfdir = $(prefix)/etc | |||
872 | ETC_PERFCONFIG = etc/perfconfig | 872 | ETC_PERFCONFIG = etc/perfconfig |
873 | endif | 873 | endif |
874 | ifndef lib | 874 | ifndef lib |
875 | ifeq ($(ARCH)$(IS_64_BIT), x861) | 875 | ifeq ($(SRCARCH)$(IS_64_BIT), x861) |
876 | lib = lib64 | 876 | lib = lib64 |
877 | else | 877 | else |
878 | lib = lib | 878 | lib = lib |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 79fe31f20a17..5008f51a08a2 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -226,7 +226,7 @@ endif | |||
226 | 226 | ||
227 | ifeq ($(config),0) | 227 | ifeq ($(config),0) |
228 | include $(srctree)/tools/scripts/Makefile.arch | 228 | include $(srctree)/tools/scripts/Makefile.arch |
229 | -include arch/$(ARCH)/Makefile | 229 | -include arch/$(SRCARCH)/Makefile |
230 | endif | 230 | endif |
231 | 231 | ||
232 | # The FEATURE_DUMP_EXPORT holds location of the actual | 232 | # The FEATURE_DUMP_EXPORT holds location of the actual |
diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build index 109eb75cf7de..d9b6af837c7d 100644 --- a/tools/perf/arch/Build +++ b/tools/perf/arch/Build | |||
@@ -1,2 +1,2 @@ | |||
1 | libperf-y += common.o | 1 | libperf-y += common.o |
2 | libperf-y += $(ARCH)/ | 2 | libperf-y += $(SRCARCH)/ |
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 29361d9b635a..7ce3d1a25133 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <api/fs/fs.h> | 18 | #include <api/fs/fs.h> |
19 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
20 | #include <linux/compiler.h> | ||
20 | #include <linux/coresight-pmu.h> | 21 | #include <linux/coresight-pmu.h> |
21 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
22 | #include <linux/log2.h> | 23 | #include <linux/log2.h> |
@@ -202,19 +203,18 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, | |||
202 | pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, | 203 | pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, |
203 | opts->auxtrace_snapshot_size); | 204 | opts->auxtrace_snapshot_size); |
204 | 205 | ||
205 | if (cs_etm_evsel) { | 206 | /* |
206 | /* | 207 | * To obtain the auxtrace buffer file descriptor, the auxtrace |
207 | * To obtain the auxtrace buffer file descriptor, the auxtrace | 208 | * event must come first. |
208 | * event must come first. | 209 | */ |
209 | */ | 210 | perf_evlist__to_front(evlist, cs_etm_evsel); |
210 | perf_evlist__to_front(evlist, cs_etm_evsel); | 211 | |
211 | /* | 212 | /* |
212 | * In the case of per-cpu mmaps, we need the CPU on the | 213 | * In the case of per-cpu mmaps, we need the CPU on the |
213 | * AUX event. | 214 | * AUX event. |
214 | */ | 215 | */ |
215 | if (!cpu_map__empty(cpus)) | 216 | if (!cpu_map__empty(cpus)) |
216 | perf_evsel__set_sample_bit(cs_etm_evsel, CPU); | 217 | perf_evsel__set_sample_bit(cs_etm_evsel, CPU); |
217 | } | ||
218 | 218 | ||
219 | /* Add dummy event to keep tracking */ | 219 | /* Add dummy event to keep tracking */ |
220 | if (opts->full_auxtrace) { | 220 | if (opts->full_auxtrace) { |
@@ -583,8 +583,7 @@ static FILE *cs_device__open_file(const char *name) | |||
583 | 583 | ||
584 | } | 584 | } |
585 | 585 | ||
586 | static __attribute__((format(printf, 2, 3))) | 586 | static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...) |
587 | int cs_device__print_file(const char *name, const char *fmt, ...) | ||
588 | { | 587 | { |
589 | va_list args; | 588 | va_list args; |
590 | FILE *file; | 589 | FILE *file; |
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 837067f48a4c..6b40e9f01740 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c | |||
@@ -26,6 +26,7 @@ const char *const arm64_triplets[] = { | |||
26 | 26 | ||
27 | const char *const powerpc_triplets[] = { | 27 | const char *const powerpc_triplets[] = { |
28 | "powerpc-unknown-linux-gnu-", | 28 | "powerpc-unknown-linux-gnu-", |
29 | "powerpc-linux-gnu-", | ||
29 | "powerpc64-unknown-linux-gnu-", | 30 | "powerpc64-unknown-linux-gnu-", |
30 | "powerpc64-linux-gnu-", | 31 | "powerpc64-linux-gnu-", |
31 | "powerpc64le-linux-gnu-", | 32 | "powerpc64le-linux-gnu-", |
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build index 90ad64b231cd..2e6595310420 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build | |||
@@ -5,4 +5,6 @@ libperf-y += perf_regs.o | |||
5 | 5 | ||
6 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 6 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
7 | libperf-$(CONFIG_DWARF) += skip-callchain-idx.o | 7 | libperf-$(CONFIG_DWARF) += skip-callchain-idx.o |
8 | |||
8 | libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o | 9 | libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o |
10 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o | ||
diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/arch/powerpc/util/unwind-libdw.c new file mode 100644 index 000000000000..3a24b3c43273 --- /dev/null +++ b/tools/perf/arch/powerpc/util/unwind-libdw.c | |||
@@ -0,0 +1,73 @@ | |||
1 | #include <elfutils/libdwfl.h> | ||
2 | #include "../../util/unwind-libdw.h" | ||
3 | #include "../../util/perf_regs.h" | ||
4 | #include "../../util/event.h" | ||
5 | |||
6 | /* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */ | ||
7 | static const int special_regs[3][2] = { | ||
8 | { 65, PERF_REG_POWERPC_LINK }, | ||
9 | { 101, PERF_REG_POWERPC_XER }, | ||
10 | { 109, PERF_REG_POWERPC_CTR }, | ||
11 | }; | ||
12 | |||
13 | bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) | ||
14 | { | ||
15 | struct unwind_info *ui = arg; | ||
16 | struct regs_dump *user_regs = &ui->sample->user_regs; | ||
17 | Dwarf_Word dwarf_regs[32], dwarf_nip; | ||
18 | size_t i; | ||
19 | |||
20 | #define REG(r) ({ \ | ||
21 | Dwarf_Word val = 0; \ | ||
22 | perf_reg_value(&val, user_regs, PERF_REG_POWERPC_##r); \ | ||
23 | val; \ | ||
24 | }) | ||
25 | |||
26 | dwarf_regs[0] = REG(R0); | ||
27 | dwarf_regs[1] = REG(R1); | ||
28 | dwarf_regs[2] = REG(R2); | ||
29 | dwarf_regs[3] = REG(R3); | ||
30 | dwarf_regs[4] = REG(R4); | ||
31 | dwarf_regs[5] = REG(R5); | ||
32 | dwarf_regs[6] = REG(R6); | ||
33 | dwarf_regs[7] = REG(R7); | ||
34 | dwarf_regs[8] = REG(R8); | ||
35 | dwarf_regs[9] = REG(R9); | ||
36 | dwarf_regs[10] = REG(R10); | ||
37 | dwarf_regs[11] = REG(R11); | ||
38 | dwarf_regs[12] = REG(R12); | ||
39 | dwarf_regs[13] = REG(R13); | ||
40 | dwarf_regs[14] = REG(R14); | ||
41 | dwarf_regs[15] = REG(R15); | ||
42 | dwarf_regs[16] = REG(R16); | ||
43 | dwarf_regs[17] = REG(R17); | ||
44 | dwarf_regs[18] = REG(R18); | ||
45 | dwarf_regs[19] = REG(R19); | ||
46 | dwarf_regs[20] = REG(R20); | ||
47 | dwarf_regs[21] = REG(R21); | ||
48 | dwarf_regs[22] = REG(R22); | ||
49 | dwarf_regs[23] = REG(R23); | ||
50 | dwarf_regs[24] = REG(R24); | ||
51 | dwarf_regs[25] = REG(R25); | ||
52 | dwarf_regs[26] = REG(R26); | ||
53 | dwarf_regs[27] = REG(R27); | ||
54 | dwarf_regs[28] = REG(R28); | ||
55 | dwarf_regs[29] = REG(R29); | ||
56 | dwarf_regs[30] = REG(R30); | ||
57 | dwarf_regs[31] = REG(R31); | ||
58 | if (!dwfl_thread_state_registers(thread, 0, 32, dwarf_regs)) | ||
59 | return false; | ||
60 | |||
61 | dwarf_nip = REG(NIP); | ||
62 | dwfl_thread_state_register_pc(thread, dwarf_nip); | ||
63 | for (i = 0; i < ARRAY_SIZE(special_regs); i++) { | ||
64 | Dwarf_Word val = 0; | ||
65 | perf_reg_value(&val, user_regs, special_regs[i][1]); | ||
66 | if (!dwfl_thread_state_registers(thread, | ||
67 | special_regs[i][0], 1, | ||
68 | &val)) | ||
69 | return false; | ||
70 | } | ||
71 | |||
72 | return true; | ||
73 | } | ||
diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-32.c b/tools/perf/arch/x86/tests/insn-x86-dat-32.c index 0f196eec9f48..3cbf6fad169f 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-32.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-32.c | |||
@@ -1664,3 +1664,15 @@ | |||
1664 | "0f c7 1d 78 56 34 12 \txrstors 0x12345678",}, | 1664 | "0f c7 1d 78 56 34 12 \txrstors 0x12345678",}, |
1665 | {{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", | 1665 | {{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", |
1666 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",}, | 1666 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",}, |
1667 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
1668 | "f3 0f ae 20 \tptwritel (%eax)",}, | ||
1669 | {{0xf3, 0x0f, 0xae, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", | ||
1670 | "f3 0f ae 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
1671 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
1672 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%eax,%ecx,8)",}, | ||
1673 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
1674 | "f3 0f ae 20 \tptwritel (%eax)",}, | ||
1675 | {{0xf3, 0x0f, 0xae, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", | ||
1676 | "f3 0f ae 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
1677 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
1678 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%eax,%ecx,8)",}, | ||
diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-64.c b/tools/perf/arch/x86/tests/insn-x86-dat-64.c index af25bc8240d0..aa512fa944dd 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-64.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-64.c | |||
@@ -1696,3 +1696,33 @@ | |||
1696 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",}, | 1696 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",}, |
1697 | {{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | 1697 | {{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", |
1698 | "41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",}, | 1698 | "41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",}, |
1699 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
1700 | "f3 0f ae 20 \tptwritel (%rax)",}, | ||
1701 | {{0xf3, 0x41, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
1702 | "f3 41 0f ae 20 \tptwritel (%r8)",}, | ||
1703 | {{0xf3, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
1704 | "f3 0f ae 24 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
1705 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
1706 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%rax,%rcx,8)",}, | ||
1707 | {{0xf3, 0x41, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
1708 | "f3 41 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%r8,%rcx,8)",}, | ||
1709 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
1710 | "f3 0f ae 20 \tptwritel (%rax)",}, | ||
1711 | {{0xf3, 0x41, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
1712 | "f3 41 0f ae 20 \tptwritel (%r8)",}, | ||
1713 | {{0xf3, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
1714 | "f3 0f ae 24 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
1715 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
1716 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%rax,%rcx,8)",}, | ||
1717 | {{0xf3, 0x41, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
1718 | "f3 41 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%r8,%rcx,8)",}, | ||
1719 | {{0xf3, 0x48, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
1720 | "f3 48 0f ae 20 \tptwriteq (%rax)",}, | ||
1721 | {{0xf3, 0x49, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
1722 | "f3 49 0f ae 20 \tptwriteq (%r8)",}, | ||
1723 | {{0xf3, 0x48, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
1724 | "f3 48 0f ae 24 25 78 56 34 12 \tptwriteq 0x12345678",}, | ||
1725 | {{0xf3, 0x48, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
1726 | "f3 48 0f ae a4 c8 78 56 34 12 \tptwriteq 0x12345678(%rax,%rcx,8)",}, | ||
1727 | {{0xf3, 0x49, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
1728 | "f3 49 0f ae a4 c8 78 56 34 12 \tptwriteq 0x12345678(%r8,%rcx,8)",}, | ||
diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-src.c b/tools/perf/arch/x86/tests/insn-x86-dat-src.c index 979487dae8d4..6cdb65d25b79 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-src.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-src.c | |||
@@ -1343,6 +1343,26 @@ int main(void) | |||
1343 | asm volatile("xrstors 0x12345678(%rax,%rcx,8)"); | 1343 | asm volatile("xrstors 0x12345678(%rax,%rcx,8)"); |
1344 | asm volatile("xrstors 0x12345678(%r8,%rcx,8)"); | 1344 | asm volatile("xrstors 0x12345678(%r8,%rcx,8)"); |
1345 | 1345 | ||
1346 | /* ptwrite */ | ||
1347 | |||
1348 | asm volatile("ptwrite (%rax)"); | ||
1349 | asm volatile("ptwrite (%r8)"); | ||
1350 | asm volatile("ptwrite (0x12345678)"); | ||
1351 | asm volatile("ptwrite 0x12345678(%rax,%rcx,8)"); | ||
1352 | asm volatile("ptwrite 0x12345678(%r8,%rcx,8)"); | ||
1353 | |||
1354 | asm volatile("ptwritel (%rax)"); | ||
1355 | asm volatile("ptwritel (%r8)"); | ||
1356 | asm volatile("ptwritel (0x12345678)"); | ||
1357 | asm volatile("ptwritel 0x12345678(%rax,%rcx,8)"); | ||
1358 | asm volatile("ptwritel 0x12345678(%r8,%rcx,8)"); | ||
1359 | |||
1360 | asm volatile("ptwriteq (%rax)"); | ||
1361 | asm volatile("ptwriteq (%r8)"); | ||
1362 | asm volatile("ptwriteq (0x12345678)"); | ||
1363 | asm volatile("ptwriteq 0x12345678(%rax,%rcx,8)"); | ||
1364 | asm volatile("ptwriteq 0x12345678(%r8,%rcx,8)"); | ||
1365 | |||
1346 | #else /* #ifdef __x86_64__ */ | 1366 | #else /* #ifdef __x86_64__ */ |
1347 | 1367 | ||
1348 | /* bound r32, mem (same op code as EVEX prefix) */ | 1368 | /* bound r32, mem (same op code as EVEX prefix) */ |
@@ -2653,6 +2673,16 @@ int main(void) | |||
2653 | asm volatile("xrstors (0x12345678)"); | 2673 | asm volatile("xrstors (0x12345678)"); |
2654 | asm volatile("xrstors 0x12345678(%eax,%ecx,8)"); | 2674 | asm volatile("xrstors 0x12345678(%eax,%ecx,8)"); |
2655 | 2675 | ||
2676 | /* ptwrite */ | ||
2677 | |||
2678 | asm volatile("ptwrite (%eax)"); | ||
2679 | asm volatile("ptwrite (0x12345678)"); | ||
2680 | asm volatile("ptwrite 0x12345678(%eax,%ecx,8)"); | ||
2681 | |||
2682 | asm volatile("ptwritel (%eax)"); | ||
2683 | asm volatile("ptwritel (0x12345678)"); | ||
2684 | asm volatile("ptwritel 0x12345678(%eax,%ecx,8)"); | ||
2685 | |||
2656 | #endif /* #ifndef __x86_64__ */ | 2686 | #endif /* #ifndef __x86_64__ */ |
2657 | 2687 | ||
2658 | /* Following line is a marker for the awk script - do not change */ | 2688 | /* Following line is a marker for the awk script - do not change */ |
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index af2bce7a2cd6..781df40b2966 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c | |||
@@ -35,10 +35,6 @@ | |||
35 | #define KiB_MASK(x) (KiB(x) - 1) | 35 | #define KiB_MASK(x) (KiB(x) - 1) |
36 | #define MiB_MASK(x) (MiB(x) - 1) | 36 | #define MiB_MASK(x) (MiB(x) - 1) |
37 | 37 | ||
38 | #define INTEL_BTS_DFLT_SAMPLE_SIZE KiB(4) | ||
39 | |||
40 | #define INTEL_BTS_MAX_SAMPLE_SIZE KiB(60) | ||
41 | |||
42 | struct intel_bts_snapshot_ref { | 38 | struct intel_bts_snapshot_ref { |
43 | void *ref_buf; | 39 | void *ref_buf; |
44 | size_t ref_offset; | 40 | size_t ref_offset; |
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index f630de0206a1..9535be57033f 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c | |||
@@ -40,10 +40,6 @@ | |||
40 | #define KiB_MASK(x) (KiB(x) - 1) | 40 | #define KiB_MASK(x) (KiB(x) - 1) |
41 | #define MiB_MASK(x) (MiB(x) - 1) | 41 | #define MiB_MASK(x) (MiB(x) - 1) |
42 | 42 | ||
43 | #define INTEL_PT_DEFAULT_SAMPLE_SIZE KiB(4) | ||
44 | |||
45 | #define INTEL_PT_MAX_SAMPLE_SIZE KiB(60) | ||
46 | |||
47 | #define INTEL_PT_PSB_PERIOD_NEAR 256 | 43 | #define INTEL_PT_PSB_PERIOD_NEAR 256 |
48 | 44 | ||
49 | struct intel_pt_snapshot_ref { | 45 | struct intel_pt_snapshot_ref { |
@@ -196,6 +192,7 @@ static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) | |||
196 | int psb_cyc, psb_periods, psb_period; | 192 | int psb_cyc, psb_periods, psb_period; |
197 | int pos = 0; | 193 | int pos = 0; |
198 | u64 config; | 194 | u64 config; |
195 | char c; | ||
199 | 196 | ||
200 | pos += scnprintf(buf + pos, sizeof(buf) - pos, "tsc"); | 197 | pos += scnprintf(buf + pos, sizeof(buf) - pos, "tsc"); |
201 | 198 | ||
@@ -229,6 +226,10 @@ static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) | |||
229 | } | 226 | } |
230 | } | 227 | } |
231 | 228 | ||
229 | if (perf_pmu__scan_file(intel_pt_pmu, "format/pt", "%c", &c) == 1 && | ||
230 | perf_pmu__scan_file(intel_pt_pmu, "format/branch", "%c", &c) == 1) | ||
231 | pos += scnprintf(buf + pos, sizeof(buf) - pos, ",pt,branch"); | ||
232 | |||
232 | pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf); | 233 | pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf); |
233 | 234 | ||
234 | intel_pt_parse_terms(&intel_pt_pmu->format, buf, &config); | 235 | intel_pt_parse_terms(&intel_pt_pmu->format, buf, &config); |
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 27de0c8c5c19..469d65b21122 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c | |||
@@ -700,7 +700,7 @@ static inline uint32_t lfsr_32(uint32_t lfsr) | |||
700 | * kernel (KSM, zero page, etc.) cannot optimize away RAM | 700 | * kernel (KSM, zero page, etc.) cannot optimize away RAM |
701 | * accesses: | 701 | * accesses: |
702 | */ | 702 | */ |
703 | static inline u64 access_data(u64 *data __attribute__((unused)), u64 val) | 703 | static inline u64 access_data(u64 *data, u64 val) |
704 | { | 704 | { |
705 | if (g->p.data_reads) | 705 | if (g->p.data_reads) |
706 | val += *data; | 706 | val += *data; |
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 620a467ee304..475999e48f66 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c | |||
@@ -1725,10 +1725,10 @@ static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name) | |||
1725 | tok; tok = strtok_r(NULL, ", ", &tmp)) { \ | 1725 | tok; tok = strtok_r(NULL, ", ", &tmp)) { \ |
1726 | ret = _fn(hpp_list, tok); \ | 1726 | ret = _fn(hpp_list, tok); \ |
1727 | if (ret == -EINVAL) { \ | 1727 | if (ret == -EINVAL) { \ |
1728 | error("Invalid --fields key: `%s'", tok); \ | 1728 | pr_err("Invalid --fields key: `%s'", tok); \ |
1729 | break; \ | 1729 | break; \ |
1730 | } else if (ret == -ESRCH) { \ | 1730 | } else if (ret == -ESRCH) { \ |
1731 | error("Unknown --fields key: `%s'", tok); \ | 1731 | pr_err("Unknown --fields key: `%s'", tok); \ |
1732 | break; \ | 1732 | break; \ |
1733 | } \ | 1733 | } \ |
1734 | } \ | 1734 | } \ |
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 80668fa7556e..ece45582a48d 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c | |||
@@ -156,7 +156,7 @@ static int parse_config_arg(char *arg, char **var, char **value) | |||
156 | 156 | ||
157 | int cmd_config(int argc, const char **argv) | 157 | int cmd_config(int argc, const char **argv) |
158 | { | 158 | { |
159 | int i, ret = 0; | 159 | int i, ret = -1; |
160 | struct perf_config_set *set; | 160 | struct perf_config_set *set; |
161 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); | 161 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); |
162 | const char *config_filename; | 162 | const char *config_filename; |
@@ -186,10 +186,8 @@ int cmd_config(int argc, const char **argv) | |||
186 | * because of reinitializing with options config file location. | 186 | * because of reinitializing with options config file location. |
187 | */ | 187 | */ |
188 | set = perf_config_set__new(); | 188 | set = perf_config_set__new(); |
189 | if (!set) { | 189 | if (!set) |
190 | ret = -1; | ||
191 | goto out_err; | 190 | goto out_err; |
192 | } | ||
193 | 191 | ||
194 | switch (actions) { | 192 | switch (actions) { |
195 | case ACTION_LIST: | 193 | case ACTION_LIST: |
@@ -197,41 +195,54 @@ int cmd_config(int argc, const char **argv) | |||
197 | pr_err("Error: takes no arguments\n"); | 195 | pr_err("Error: takes no arguments\n"); |
198 | parse_options_usage(config_usage, config_options, "l", 1); | 196 | parse_options_usage(config_usage, config_options, "l", 1); |
199 | } else { | 197 | } else { |
200 | ret = show_config(set); | 198 | if (show_config(set) < 0) { |
201 | if (ret < 0) | ||
202 | pr_err("Nothing configured, " | 199 | pr_err("Nothing configured, " |
203 | "please check your %s \n", config_filename); | 200 | "please check your %s \n", config_filename); |
201 | goto out_err; | ||
202 | } | ||
204 | } | 203 | } |
205 | break; | 204 | break; |
206 | default: | 205 | default: |
207 | if (argc) { | 206 | if (!argc) { |
208 | for (i = 0; argv[i]; i++) { | 207 | usage_with_options(config_usage, config_options); |
209 | char *var, *value; | 208 | break; |
210 | char *arg = strdup(argv[i]); | 209 | } |
211 | |||
212 | if (!arg) { | ||
213 | pr_err("%s: strdup failed\n", __func__); | ||
214 | ret = -1; | ||
215 | break; | ||
216 | } | ||
217 | 210 | ||
218 | if (parse_config_arg(arg, &var, &value) < 0) { | 211 | for (i = 0; argv[i]; i++) { |
219 | free(arg); | 212 | char *var, *value; |
220 | ret = -1; | 213 | char *arg = strdup(argv[i]); |
221 | break; | 214 | |
222 | } | 215 | if (!arg) { |
216 | pr_err("%s: strdup failed\n", __func__); | ||
217 | goto out_err; | ||
218 | } | ||
223 | 219 | ||
224 | if (value == NULL) | 220 | if (parse_config_arg(arg, &var, &value) < 0) { |
225 | ret = show_spec_config(set, var); | ||
226 | else | ||
227 | ret = set_config(set, config_filename, var, value); | ||
228 | free(arg); | 221 | free(arg); |
222 | goto out_err; | ||
229 | } | 223 | } |
230 | } else | 224 | |
231 | usage_with_options(config_usage, config_options); | 225 | if (value == NULL) { |
226 | if (show_spec_config(set, var) < 0) { | ||
227 | pr_err("%s is not configured: %s\n", | ||
228 | var, config_filename); | ||
229 | free(arg); | ||
230 | goto out_err; | ||
231 | } | ||
232 | } else { | ||
233 | if (set_config(set, config_filename, var, value) < 0) { | ||
234 | pr_err("Failed to set '%s=%s' on %s\n", | ||
235 | var, value, config_filename); | ||
236 | free(arg); | ||
237 | goto out_err; | ||
238 | } | ||
239 | } | ||
240 | free(arg); | ||
241 | } | ||
232 | } | 242 | } |
233 | 243 | ||
234 | perf_config_set__delete(set); | 244 | ret = 0; |
235 | out_err: | 245 | out_err: |
246 | perf_config_set__delete(set); | ||
236 | return ret; | 247 | return ret; |
237 | } | 248 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index eec5df80f5a3..0cd4cf6a344b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -1302,7 +1302,10 @@ static int diff__config(const char *var, const char *value, | |||
1302 | void *cb __maybe_unused) | 1302 | void *cb __maybe_unused) |
1303 | { | 1303 | { |
1304 | if (!strcmp(var, "diff.order")) { | 1304 | if (!strcmp(var, "diff.order")) { |
1305 | sort_compute = perf_config_int(var, value); | 1305 | int ret; |
1306 | if (perf_config_int(&ret, var, value) < 0) | ||
1307 | return -1; | ||
1308 | sort_compute = ret; | ||
1306 | return 0; | 1309 | return 0; |
1307 | } | 1310 | } |
1308 | if (!strcmp(var, "diff.compute")) { | 1311 | if (!strcmp(var, "diff.compute")) { |
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 9e0b35cd0eea..dd26c62c9893 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c | |||
@@ -28,9 +28,19 @@ | |||
28 | #define DEFAULT_TRACER "function_graph" | 28 | #define DEFAULT_TRACER "function_graph" |
29 | 29 | ||
30 | struct perf_ftrace { | 30 | struct perf_ftrace { |
31 | struct perf_evlist *evlist; | 31 | struct perf_evlist *evlist; |
32 | struct target target; | 32 | struct target target; |
33 | const char *tracer; | 33 | const char *tracer; |
34 | struct list_head filters; | ||
35 | struct list_head notrace; | ||
36 | struct list_head graph_funcs; | ||
37 | struct list_head nograph_funcs; | ||
38 | int graph_depth; | ||
39 | }; | ||
40 | |||
41 | struct filter_entry { | ||
42 | struct list_head list; | ||
43 | char name[]; | ||
34 | }; | 44 | }; |
35 | 45 | ||
36 | static bool done; | 46 | static bool done; |
@@ -61,6 +71,7 @@ static int __write_tracing_file(const char *name, const char *val, bool append) | |||
61 | int fd, ret = -1; | 71 | int fd, ret = -1; |
62 | ssize_t size = strlen(val); | 72 | ssize_t size = strlen(val); |
63 | int flags = O_WRONLY; | 73 | int flags = O_WRONLY; |
74 | char errbuf[512]; | ||
64 | 75 | ||
65 | file = get_tracing_file(name); | 76 | file = get_tracing_file(name); |
66 | if (!file) { | 77 | if (!file) { |
@@ -75,14 +86,16 @@ static int __write_tracing_file(const char *name, const char *val, bool append) | |||
75 | 86 | ||
76 | fd = open(file, flags); | 87 | fd = open(file, flags); |
77 | if (fd < 0) { | 88 | if (fd < 0) { |
78 | pr_debug("cannot open tracing file: %s\n", name); | 89 | pr_debug("cannot open tracing file: %s: %s\n", |
90 | name, str_error_r(errno, errbuf, sizeof(errbuf))); | ||
79 | goto out; | 91 | goto out; |
80 | } | 92 | } |
81 | 93 | ||
82 | if (write(fd, val, size) == size) | 94 | if (write(fd, val, size) == size) |
83 | ret = 0; | 95 | ret = 0; |
84 | else | 96 | else |
85 | pr_debug("write '%s' to tracing/%s failed\n", val, name); | 97 | pr_debug("write '%s' to tracing/%s failed: %s\n", |
98 | val, name, str_error_r(errno, errbuf, sizeof(errbuf))); | ||
86 | 99 | ||
87 | close(fd); | 100 | close(fd); |
88 | out: | 101 | out: |
@@ -101,6 +114,7 @@ static int append_tracing_file(const char *name, const char *val) | |||
101 | } | 114 | } |
102 | 115 | ||
103 | static int reset_tracing_cpu(void); | 116 | static int reset_tracing_cpu(void); |
117 | static void reset_tracing_filters(void); | ||
104 | 118 | ||
105 | static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) | 119 | static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) |
106 | { | 120 | { |
@@ -116,6 +130,10 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) | |||
116 | if (reset_tracing_cpu() < 0) | 130 | if (reset_tracing_cpu() < 0) |
117 | return -1; | 131 | return -1; |
118 | 132 | ||
133 | if (write_tracing_file("max_graph_depth", "0") < 0) | ||
134 | return -1; | ||
135 | |||
136 | reset_tracing_filters(); | ||
119 | return 0; | 137 | return 0; |
120 | } | 138 | } |
121 | 139 | ||
@@ -181,6 +199,68 @@ static int reset_tracing_cpu(void) | |||
181 | return ret; | 199 | return ret; |
182 | } | 200 | } |
183 | 201 | ||
202 | static int __set_tracing_filter(const char *filter_file, struct list_head *funcs) | ||
203 | { | ||
204 | struct filter_entry *pos; | ||
205 | |||
206 | list_for_each_entry(pos, funcs, list) { | ||
207 | if (append_tracing_file(filter_file, pos->name) < 0) | ||
208 | return -1; | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int set_tracing_filters(struct perf_ftrace *ftrace) | ||
215 | { | ||
216 | int ret; | ||
217 | |||
218 | ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters); | ||
219 | if (ret < 0) | ||
220 | return ret; | ||
221 | |||
222 | ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace); | ||
223 | if (ret < 0) | ||
224 | return ret; | ||
225 | |||
226 | ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs); | ||
227 | if (ret < 0) | ||
228 | return ret; | ||
229 | |||
230 | /* old kernels do not have this filter */ | ||
231 | __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs); | ||
232 | |||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static void reset_tracing_filters(void) | ||
237 | { | ||
238 | write_tracing_file("set_ftrace_filter", " "); | ||
239 | write_tracing_file("set_ftrace_notrace", " "); | ||
240 | write_tracing_file("set_graph_function", " "); | ||
241 | write_tracing_file("set_graph_notrace", " "); | ||
242 | } | ||
243 | |||
244 | static int set_tracing_depth(struct perf_ftrace *ftrace) | ||
245 | { | ||
246 | char buf[16]; | ||
247 | |||
248 | if (ftrace->graph_depth == 0) | ||
249 | return 0; | ||
250 | |||
251 | if (ftrace->graph_depth < 0) { | ||
252 | pr_err("invalid graph depth: %d\n", ftrace->graph_depth); | ||
253 | return -1; | ||
254 | } | ||
255 | |||
256 | snprintf(buf, sizeof(buf), "%d", ftrace->graph_depth); | ||
257 | |||
258 | if (write_tracing_file("max_graph_depth", buf) < 0) | ||
259 | return -1; | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
184 | static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) | 264 | static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) |
185 | { | 265 | { |
186 | char *trace_file; | 266 | char *trace_file; |
@@ -223,11 +303,23 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) | |||
223 | goto out_reset; | 303 | goto out_reset; |
224 | } | 304 | } |
225 | 305 | ||
306 | if (set_tracing_filters(ftrace) < 0) { | ||
307 | pr_err("failed to set tracing filters\n"); | ||
308 | goto out_reset; | ||
309 | } | ||
310 | |||
311 | if (set_tracing_depth(ftrace) < 0) { | ||
312 | pr_err("failed to set graph depth\n"); | ||
313 | goto out_reset; | ||
314 | } | ||
315 | |||
226 | if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { | 316 | if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { |
227 | pr_err("failed to set current_tracer to %s\n", ftrace->tracer); | 317 | pr_err("failed to set current_tracer to %s\n", ftrace->tracer); |
228 | goto out_reset; | 318 | goto out_reset; |
229 | } | 319 | } |
230 | 320 | ||
321 | setup_pager(); | ||
322 | |||
231 | trace_file = get_tracing_file("trace_pipe"); | 323 | trace_file = get_tracing_file("trace_pipe"); |
232 | if (!trace_file) { | 324 | if (!trace_file) { |
233 | pr_err("failed to open trace_pipe\n"); | 325 | pr_err("failed to open trace_pipe\n"); |
@@ -251,8 +343,6 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) | |||
251 | goto out_close_fd; | 343 | goto out_close_fd; |
252 | } | 344 | } |
253 | 345 | ||
254 | setup_pager(); | ||
255 | |||
256 | perf_evlist__start_workload(ftrace->evlist); | 346 | perf_evlist__start_workload(ftrace->evlist); |
257 | 347 | ||
258 | while (!done) { | 348 | while (!done) { |
@@ -307,6 +397,32 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb) | |||
307 | return -1; | 397 | return -1; |
308 | } | 398 | } |
309 | 399 | ||
400 | static int parse_filter_func(const struct option *opt, const char *str, | ||
401 | int unset __maybe_unused) | ||
402 | { | ||
403 | struct list_head *head = opt->value; | ||
404 | struct filter_entry *entry; | ||
405 | |||
406 | entry = malloc(sizeof(*entry) + strlen(str) + 1); | ||
407 | if (entry == NULL) | ||
408 | return -ENOMEM; | ||
409 | |||
410 | strcpy(entry->name, str); | ||
411 | list_add_tail(&entry->list, head); | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static void delete_filter_func(struct list_head *head) | ||
417 | { | ||
418 | struct filter_entry *pos, *tmp; | ||
419 | |||
420 | list_for_each_entry_safe(pos, tmp, head, list) { | ||
421 | list_del(&pos->list); | ||
422 | free(pos); | ||
423 | } | ||
424 | } | ||
425 | |||
310 | int cmd_ftrace(int argc, const char **argv) | 426 | int cmd_ftrace(int argc, const char **argv) |
311 | { | 427 | { |
312 | int ret; | 428 | int ret; |
@@ -330,9 +446,24 @@ int cmd_ftrace(int argc, const char **argv) | |||
330 | "system-wide collection from all CPUs"), | 446 | "system-wide collection from all CPUs"), |
331 | OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", | 447 | OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", |
332 | "list of cpus to monitor"), | 448 | "list of cpus to monitor"), |
449 | OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", | ||
450 | "trace given functions only", parse_filter_func), | ||
451 | OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", | ||
452 | "do not trace given functions", parse_filter_func), | ||
453 | OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", | ||
454 | "Set graph filter on given functions", parse_filter_func), | ||
455 | OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", | ||
456 | "Set nograph filter on given functions", parse_filter_func), | ||
457 | OPT_INTEGER('D', "graph-depth", &ftrace.graph_depth, | ||
458 | "Max depth for function graph tracer"), | ||
333 | OPT_END() | 459 | OPT_END() |
334 | }; | 460 | }; |
335 | 461 | ||
462 | INIT_LIST_HEAD(&ftrace.filters); | ||
463 | INIT_LIST_HEAD(&ftrace.notrace); | ||
464 | INIT_LIST_HEAD(&ftrace.graph_funcs); | ||
465 | INIT_LIST_HEAD(&ftrace.nograph_funcs); | ||
466 | |||
336 | ret = perf_config(perf_ftrace_config, &ftrace); | 467 | ret = perf_config(perf_ftrace_config, &ftrace); |
337 | if (ret < 0) | 468 | if (ret < 0) |
338 | return -1; | 469 | return -1; |
@@ -348,12 +479,14 @@ int cmd_ftrace(int argc, const char **argv) | |||
348 | 479 | ||
349 | target__strerror(&ftrace.target, ret, errbuf, 512); | 480 | target__strerror(&ftrace.target, ret, errbuf, 512); |
350 | pr_err("%s\n", errbuf); | 481 | pr_err("%s\n", errbuf); |
351 | return -EINVAL; | 482 | goto out_delete_filters; |
352 | } | 483 | } |
353 | 484 | ||
354 | ftrace.evlist = perf_evlist__new(); | 485 | ftrace.evlist = perf_evlist__new(); |
355 | if (ftrace.evlist == NULL) | 486 | if (ftrace.evlist == NULL) { |
356 | return -ENOMEM; | 487 | ret = -ENOMEM; |
488 | goto out_delete_filters; | ||
489 | } | ||
357 | 490 | ||
358 | ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); | 491 | ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); |
359 | if (ret < 0) | 492 | if (ret < 0) |
@@ -364,5 +497,11 @@ int cmd_ftrace(int argc, const char **argv) | |||
364 | out_delete_evlist: | 497 | out_delete_evlist: |
365 | perf_evlist__delete(ftrace.evlist); | 498 | perf_evlist__delete(ftrace.evlist); |
366 | 499 | ||
500 | out_delete_filters: | ||
501 | delete_filter_func(&ftrace.filters); | ||
502 | delete_filter_func(&ftrace.notrace); | ||
503 | delete_filter_func(&ftrace.graph_funcs); | ||
504 | delete_filter_func(&ftrace.nograph_funcs); | ||
505 | |||
367 | return ret; | 506 | return ret; |
368 | } | 507 | } |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 492f8e14ab09..530a7f2fa0f3 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
@@ -108,10 +108,14 @@ out: | |||
108 | return ret; | 108 | return ret; |
109 | } | 109 | } |
110 | 110 | ||
111 | static void exec_woman_emacs(const char *path, const char *page) | 111 | static void exec_failed(const char *cmd) |
112 | { | 112 | { |
113 | char sbuf[STRERR_BUFSIZE]; | 113 | char sbuf[STRERR_BUFSIZE]; |
114 | pr_warning("failed to exec '%s': %s", cmd, str_error_r(errno, sbuf, sizeof(sbuf))); | ||
115 | } | ||
114 | 116 | ||
117 | static void exec_woman_emacs(const char *path, const char *page) | ||
118 | { | ||
115 | if (!check_emacsclient_version()) { | 119 | if (!check_emacsclient_version()) { |
116 | /* This works only with emacsclient version >= 22. */ | 120 | /* This works only with emacsclient version >= 22. */ |
117 | char *man_page; | 121 | char *man_page; |
@@ -122,8 +126,7 @@ static void exec_woman_emacs(const char *path, const char *page) | |||
122 | execlp(path, "emacsclient", "-e", man_page, NULL); | 126 | execlp(path, "emacsclient", "-e", man_page, NULL); |
123 | free(man_page); | 127 | free(man_page); |
124 | } | 128 | } |
125 | warning("failed to exec '%s': %s", path, | 129 | exec_failed(path); |
126 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
127 | } | 130 | } |
128 | } | 131 | } |
129 | 132 | ||
@@ -134,7 +137,6 @@ static void exec_man_konqueror(const char *path, const char *page) | |||
134 | if (display && *display) { | 137 | if (display && *display) { |
135 | char *man_page; | 138 | char *man_page; |
136 | const char *filename = "kfmclient"; | 139 | const char *filename = "kfmclient"; |
137 | char sbuf[STRERR_BUFSIZE]; | ||
138 | 140 | ||
139 | /* It's simpler to launch konqueror using kfmclient. */ | 141 | /* It's simpler to launch konqueror using kfmclient. */ |
140 | if (path) { | 142 | if (path) { |
@@ -155,33 +157,27 @@ static void exec_man_konqueror(const char *path, const char *page) | |||
155 | execlp(path, filename, "newTab", man_page, NULL); | 157 | execlp(path, filename, "newTab", man_page, NULL); |
156 | free(man_page); | 158 | free(man_page); |
157 | } | 159 | } |
158 | warning("failed to exec '%s': %s", path, | 160 | exec_failed(path); |
159 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
160 | } | 161 | } |
161 | } | 162 | } |
162 | 163 | ||
163 | static void exec_man_man(const char *path, const char *page) | 164 | static void exec_man_man(const char *path, const char *page) |
164 | { | 165 | { |
165 | char sbuf[STRERR_BUFSIZE]; | ||
166 | |||
167 | if (!path) | 166 | if (!path) |
168 | path = "man"; | 167 | path = "man"; |
169 | execlp(path, "man", page, NULL); | 168 | execlp(path, "man", page, NULL); |
170 | warning("failed to exec '%s': %s", path, | 169 | exec_failed(path); |
171 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
172 | } | 170 | } |
173 | 171 | ||
174 | static void exec_man_cmd(const char *cmd, const char *page) | 172 | static void exec_man_cmd(const char *cmd, const char *page) |
175 | { | 173 | { |
176 | char sbuf[STRERR_BUFSIZE]; | ||
177 | char *shell_cmd; | 174 | char *shell_cmd; |
178 | 175 | ||
179 | if (asprintf(&shell_cmd, "%s %s", cmd, page) > 0) { | 176 | if (asprintf(&shell_cmd, "%s %s", cmd, page) > 0) { |
180 | execl("/bin/sh", "sh", "-c", shell_cmd, NULL); | 177 | execl("/bin/sh", "sh", "-c", shell_cmd, NULL); |
181 | free(shell_cmd); | 178 | free(shell_cmd); |
182 | } | 179 | } |
183 | warning("failed to exec '%s': %s", cmd, | 180 | exec_failed(cmd); |
184 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
185 | } | 181 | } |
186 | 182 | ||
187 | static void add_man_viewer(const char *name) | 183 | static void add_man_viewer(const char *name) |
@@ -214,6 +210,12 @@ static void do_add_man_viewer_info(const char *name, | |||
214 | man_viewer_info_list = new; | 210 | man_viewer_info_list = new; |
215 | } | 211 | } |
216 | 212 | ||
213 | static void unsupported_man_viewer(const char *name, const char *var) | ||
214 | { | ||
215 | pr_warning("'%s': path for unsupported man viewer.\n" | ||
216 | "Please consider using 'man.<tool>.%s' instead.", name, var); | ||
217 | } | ||
218 | |||
217 | static int add_man_viewer_path(const char *name, | 219 | static int add_man_viewer_path(const char *name, |
218 | size_t len, | 220 | size_t len, |
219 | const char *value) | 221 | const char *value) |
@@ -221,9 +223,7 @@ static int add_man_viewer_path(const char *name, | |||
221 | if (supported_man_viewer(name, len)) | 223 | if (supported_man_viewer(name, len)) |
222 | do_add_man_viewer_info(name, len, value); | 224 | do_add_man_viewer_info(name, len, value); |
223 | else | 225 | else |
224 | warning("'%s': path for unsupported man viewer.\n" | 226 | unsupported_man_viewer(name, "cmd"); |
225 | "Please consider using 'man.<tool>.cmd' instead.", | ||
226 | name); | ||
227 | 227 | ||
228 | return 0; | 228 | return 0; |
229 | } | 229 | } |
@@ -233,9 +233,7 @@ static int add_man_viewer_cmd(const char *name, | |||
233 | const char *value) | 233 | const char *value) |
234 | { | 234 | { |
235 | if (supported_man_viewer(name, len)) | 235 | if (supported_man_viewer(name, len)) |
236 | warning("'%s': cmd for supported man viewer.\n" | 236 | unsupported_man_viewer(name, "path"); |
237 | "Please consider using 'man.<tool>.path' instead.", | ||
238 | name); | ||
239 | else | 237 | else |
240 | do_add_man_viewer_info(name, len, value); | 238 | do_add_man_viewer_info(name, len, value); |
241 | 239 | ||
@@ -247,8 +245,10 @@ static int add_man_viewer_info(const char *var, const char *value) | |||
247 | const char *name = var + 4; | 245 | const char *name = var + 4; |
248 | const char *subkey = strrchr(name, '.'); | 246 | const char *subkey = strrchr(name, '.'); |
249 | 247 | ||
250 | if (!subkey) | 248 | if (!subkey) { |
251 | return error("Config with no key for man viewer: %s", name); | 249 | pr_err("Config with no key for man viewer: %s", name); |
250 | return -1; | ||
251 | } | ||
252 | 252 | ||
253 | if (!strcmp(subkey, ".path")) { | 253 | if (!strcmp(subkey, ".path")) { |
254 | if (!value) | 254 | if (!value) |
@@ -261,7 +261,7 @@ static int add_man_viewer_info(const char *var, const char *value) | |||
261 | return add_man_viewer_cmd(name, subkey - name, value); | 261 | return add_man_viewer_cmd(name, subkey - name, value); |
262 | } | 262 | } |
263 | 263 | ||
264 | warning("'%s': unsupported man viewer sub key.", subkey); | 264 | pr_warning("'%s': unsupported man viewer sub key.", subkey); |
265 | return 0; | 265 | return 0; |
266 | } | 266 | } |
267 | 267 | ||
@@ -332,7 +332,7 @@ static void setup_man_path(void) | |||
332 | setenv("MANPATH", new_path, 1); | 332 | setenv("MANPATH", new_path, 1); |
333 | free(new_path); | 333 | free(new_path); |
334 | } else { | 334 | } else { |
335 | error("Unable to setup man path"); | 335 | pr_err("Unable to setup man path"); |
336 | } | 336 | } |
337 | } | 337 | } |
338 | 338 | ||
@@ -349,7 +349,7 @@ static void exec_viewer(const char *name, const char *page) | |||
349 | else if (info) | 349 | else if (info) |
350 | exec_man_cmd(info, page); | 350 | exec_man_cmd(info, page); |
351 | else | 351 | else |
352 | warning("'%s': unknown man viewer.", name); | 352 | pr_warning("'%s': unknown man viewer.", name); |
353 | } | 353 | } |
354 | 354 | ||
355 | static int show_man_page(const char *perf_cmd) | 355 | static int show_man_page(const char *perf_cmd) |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 9409c9464667..0a8a1c45af87 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -1715,7 +1715,7 @@ static int setup_slab_sorting(struct list_head *sort_list, const char *arg) | |||
1715 | if (!tok) | 1715 | if (!tok) |
1716 | break; | 1716 | break; |
1717 | if (slab_sort_dimension__add(tok, sort_list) < 0) { | 1717 | if (slab_sort_dimension__add(tok, sort_list) < 0) { |
1718 | error("Unknown slab --sort key: '%s'", tok); | 1718 | pr_err("Unknown slab --sort key: '%s'", tok); |
1719 | free(str); | 1719 | free(str); |
1720 | return -1; | 1720 | return -1; |
1721 | } | 1721 | } |
@@ -1741,7 +1741,7 @@ static int setup_page_sorting(struct list_head *sort_list, const char *arg) | |||
1741 | if (!tok) | 1741 | if (!tok) |
1742 | break; | 1742 | break; |
1743 | if (page_sort_dimension__add(tok, sort_list) < 0) { | 1743 | if (page_sort_dimension__add(tok, sort_list) < 0) { |
1744 | error("Unknown page --sort key: '%s'", tok); | 1744 | pr_err("Unknown page --sort key: '%s'", tok); |
1745 | free(str); | 1745 | free(str); |
1746 | return -1; | 1746 | return -1; |
1747 | } | 1747 | } |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ee7d0a82ccd0..17a14bcce34a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -453,7 +453,7 @@ try_again: | |||
453 | } | 453 | } |
454 | 454 | ||
455 | if (perf_evlist__apply_filters(evlist, &pos)) { | 455 | if (perf_evlist__apply_filters(evlist, &pos)) { |
456 | error("failed to set filter \"%s\" on event %s with %d (%s)\n", | 456 | pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", |
457 | pos->filter, perf_evsel__name(pos), errno, | 457 | pos->filter, perf_evsel__name(pos), errno, |
458 | str_error_r(errno, msg, sizeof(msg))); | 458 | str_error_r(errno, msg, sizeof(msg))); |
459 | rc = -1; | 459 | rc = -1; |
@@ -461,7 +461,7 @@ try_again: | |||
461 | } | 461 | } |
462 | 462 | ||
463 | if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) { | 463 | if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) { |
464 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | 464 | pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", |
465 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, | 465 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, |
466 | str_error_r(errno, msg, sizeof(msg))); | 466 | str_error_r(errno, msg, sizeof(msg))); |
467 | rc = -1; | 467 | rc = -1; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 22478ff2b706..79a33eb1a10d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -94,10 +94,9 @@ static int report__config(const char *var, const char *value, void *cb) | |||
94 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); | 94 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); |
95 | return 0; | 95 | return 0; |
96 | } | 96 | } |
97 | if (!strcmp(var, "report.queue-size")) { | 97 | if (!strcmp(var, "report.queue-size")) |
98 | rep->queue_size = perf_config_u64(var, value); | 98 | return perf_config_u64(&rep->queue_size, var, value); |
99 | return 0; | 99 | |
100 | } | ||
101 | if (!strcmp(var, "report.sort_order")) { | 100 | if (!strcmp(var, "report.sort_order")) { |
102 | default_sort_order = strdup(value); | 101 | default_sort_order = strdup(value); |
103 | return 0; | 102 | return 0; |
@@ -558,6 +557,7 @@ static int __cmd_report(struct report *rep) | |||
558 | ui__error("failed to set cpu bitmap\n"); | 557 | ui__error("failed to set cpu bitmap\n"); |
559 | return ret; | 558 | return ret; |
560 | } | 559 | } |
560 | session->itrace_synth_opts->cpu_bitmap = rep->cpu_bitmap; | ||
561 | } | 561 | } |
562 | 562 | ||
563 | if (rep->show_threads) { | 563 | if (rep->show_threads) { |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 39996c53995a..322b4def8411 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -2066,7 +2066,7 @@ static void save_task_callchain(struct perf_sched *sched, | |||
2066 | if (thread__resolve_callchain(thread, cursor, evsel, sample, | 2066 | if (thread__resolve_callchain(thread, cursor, evsel, sample, |
2067 | NULL, NULL, sched->max_stack + 2) != 0) { | 2067 | NULL, NULL, sched->max_stack + 2) != 0) { |
2068 | if (verbose > 0) | 2068 | if (verbose > 0) |
2069 | error("Failed to resolve callchain. Skipping\n"); | 2069 | pr_err("Failed to resolve callchain. Skipping\n"); |
2070 | 2070 | ||
2071 | return; | 2071 | return; |
2072 | } | 2072 | } |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index d05aec491cff..83cdc0a61fd6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -85,6 +85,8 @@ enum perf_output_field { | |||
85 | PERF_OUTPUT_INSN = 1U << 21, | 85 | PERF_OUTPUT_INSN = 1U << 21, |
86 | PERF_OUTPUT_INSNLEN = 1U << 22, | 86 | PERF_OUTPUT_INSNLEN = 1U << 22, |
87 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, | 87 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, |
88 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, | ||
89 | PERF_OUTPUT_SYNTH = 1U << 25, | ||
88 | }; | 90 | }; |
89 | 91 | ||
90 | struct output_option { | 92 | struct output_option { |
@@ -115,6 +117,13 @@ struct output_option { | |||
115 | {.str = "insn", .field = PERF_OUTPUT_INSN}, | 117 | {.str = "insn", .field = PERF_OUTPUT_INSN}, |
116 | {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN}, | 118 | {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN}, |
117 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, | 119 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, |
120 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, | ||
121 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, | ||
122 | }; | ||
123 | |||
124 | enum { | ||
125 | OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX, | ||
126 | OUTPUT_TYPE_MAX | ||
118 | }; | 127 | }; |
119 | 128 | ||
120 | /* default set to maintain compatibility with current format */ | 129 | /* default set to maintain compatibility with current format */ |
@@ -124,7 +133,7 @@ static struct { | |||
124 | unsigned int print_ip_opts; | 133 | unsigned int print_ip_opts; |
125 | u64 fields; | 134 | u64 fields; |
126 | u64 invalid_fields; | 135 | u64 invalid_fields; |
127 | } output[PERF_TYPE_MAX] = { | 136 | } output[OUTPUT_TYPE_MAX] = { |
128 | 137 | ||
129 | [PERF_TYPE_HARDWARE] = { | 138 | [PERF_TYPE_HARDWARE] = { |
130 | .user_set = false, | 139 | .user_set = false, |
@@ -182,12 +191,44 @@ static struct { | |||
182 | 191 | ||
183 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | 192 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
184 | }, | 193 | }, |
194 | |||
195 | [OUTPUT_TYPE_SYNTH] = { | ||
196 | .user_set = false, | ||
197 | |||
198 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | ||
199 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | ||
200 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | ||
201 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | ||
202 | PERF_OUTPUT_SYNTH, | ||
203 | |||
204 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | ||
205 | }, | ||
185 | }; | 206 | }; |
186 | 207 | ||
208 | static inline int output_type(unsigned int type) | ||
209 | { | ||
210 | switch (type) { | ||
211 | case PERF_TYPE_SYNTH: | ||
212 | return OUTPUT_TYPE_SYNTH; | ||
213 | default: | ||
214 | return type; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | static inline unsigned int attr_type(unsigned int type) | ||
219 | { | ||
220 | switch (type) { | ||
221 | case OUTPUT_TYPE_SYNTH: | ||
222 | return PERF_TYPE_SYNTH; | ||
223 | default: | ||
224 | return type; | ||
225 | } | ||
226 | } | ||
227 | |||
187 | static bool output_set_by_user(void) | 228 | static bool output_set_by_user(void) |
188 | { | 229 | { |
189 | int j; | 230 | int j; |
190 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 231 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
191 | if (output[j].user_set) | 232 | if (output[j].user_set) |
192 | return true; | 233 | return true; |
193 | } | 234 | } |
@@ -208,7 +249,7 @@ static const char *output_field2str(enum perf_output_field field) | |||
208 | return str; | 249 | return str; |
209 | } | 250 | } |
210 | 251 | ||
211 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) | 252 | #define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) |
212 | 253 | ||
213 | static int perf_evsel__do_check_stype(struct perf_evsel *evsel, | 254 | static int perf_evsel__do_check_stype(struct perf_evsel *evsel, |
214 | u64 sample_type, const char *sample_msg, | 255 | u64 sample_type, const char *sample_msg, |
@@ -216,7 +257,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel, | |||
216 | bool allow_user_set) | 257 | bool allow_user_set) |
217 | { | 258 | { |
218 | struct perf_event_attr *attr = &evsel->attr; | 259 | struct perf_event_attr *attr = &evsel->attr; |
219 | int type = attr->type; | 260 | int type = output_type(attr->type); |
220 | const char *evname; | 261 | const char *evname; |
221 | 262 | ||
222 | if (attr->sample_type & sample_type) | 263 | if (attr->sample_type & sample_type) |
@@ -298,10 +339,10 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
298 | "selected.\n"); | 339 | "selected.\n"); |
299 | return -EINVAL; | 340 | return -EINVAL; |
300 | } | 341 | } |
301 | if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { | 342 | if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) && |
302 | pr_err("Display of DSO requested but neither sample IP nor " | 343 | !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM) && !PRINT_FIELD(BRSTACKOFF)) { |
303 | "sample address\nis selected. Hence, no addresses to convert " | 344 | pr_err("Display of DSO requested but no address to convert. Select\n" |
304 | "to DSO.\n"); | 345 | "sample IP, sample address, brstack, brstacksym, or brstackoff.\n"); |
305 | return -EINVAL; | 346 | return -EINVAL; |
306 | } | 347 | } |
307 | if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { | 348 | if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { |
@@ -346,7 +387,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
346 | 387 | ||
347 | static void set_print_ip_opts(struct perf_event_attr *attr) | 388 | static void set_print_ip_opts(struct perf_event_attr *attr) |
348 | { | 389 | { |
349 | unsigned int type = attr->type; | 390 | unsigned int type = output_type(attr->type); |
350 | 391 | ||
351 | output[type].print_ip_opts = 0; | 392 | output[type].print_ip_opts = 0; |
352 | if (PRINT_FIELD(IP)) | 393 | if (PRINT_FIELD(IP)) |
@@ -374,16 +415,17 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
374 | unsigned int j; | 415 | unsigned int j; |
375 | struct perf_evsel *evsel; | 416 | struct perf_evsel *evsel; |
376 | 417 | ||
377 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 418 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
378 | evsel = perf_session__find_first_evtype(session, j); | 419 | evsel = perf_session__find_first_evtype(session, attr_type(j)); |
379 | 420 | ||
380 | /* | 421 | /* |
381 | * even if fields is set to 0 (ie., show nothing) event must | 422 | * even if fields is set to 0 (ie., show nothing) event must |
382 | * exist if user explicitly includes it on the command line | 423 | * exist if user explicitly includes it on the command line |
383 | */ | 424 | */ |
384 | if (!evsel && output[j].user_set && !output[j].wildcard_set) { | 425 | if (!evsel && output[j].user_set && !output[j].wildcard_set && |
426 | j != OUTPUT_TYPE_SYNTH) { | ||
385 | pr_err("%s events do not exist. " | 427 | pr_err("%s events do not exist. " |
386 | "Remove corresponding -f option to proceed.\n", | 428 | "Remove corresponding -F option to proceed.\n", |
387 | event_type(j)); | 429 | event_type(j)); |
388 | return -1; | 430 | return -1; |
389 | } | 431 | } |
@@ -514,18 +556,43 @@ mispred_str(struct branch_entry *br) | |||
514 | return br->flags.predicted ? 'P' : 'M'; | 556 | return br->flags.predicted ? 'P' : 'M'; |
515 | } | 557 | } |
516 | 558 | ||
517 | static void print_sample_brstack(struct perf_sample *sample) | 559 | static void print_sample_brstack(struct perf_sample *sample, |
560 | struct thread *thread, | ||
561 | struct perf_event_attr *attr) | ||
518 | { | 562 | { |
519 | struct branch_stack *br = sample->branch_stack; | 563 | struct branch_stack *br = sample->branch_stack; |
520 | u64 i; | 564 | struct addr_location alf, alt; |
565 | u64 i, from, to; | ||
521 | 566 | ||
522 | if (!(br && br->nr)) | 567 | if (!(br && br->nr)) |
523 | return; | 568 | return; |
524 | 569 | ||
525 | for (i = 0; i < br->nr; i++) { | 570 | for (i = 0; i < br->nr; i++) { |
526 | printf(" 0x%"PRIx64"/0x%"PRIx64"/%c/%c/%c/%d ", | 571 | from = br->entries[i].from; |
527 | br->entries[i].from, | 572 | to = br->entries[i].to; |
528 | br->entries[i].to, | 573 | |
574 | if (PRINT_FIELD(DSO)) { | ||
575 | memset(&alf, 0, sizeof(alf)); | ||
576 | memset(&alt, 0, sizeof(alt)); | ||
577 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); | ||
578 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); | ||
579 | } | ||
580 | |||
581 | printf("0x%"PRIx64, from); | ||
582 | if (PRINT_FIELD(DSO)) { | ||
583 | printf("("); | ||
584 | map__fprintf_dsoname(alf.map, stdout); | ||
585 | printf(")"); | ||
586 | } | ||
587 | |||
588 | printf("/0x%"PRIx64, to); | ||
589 | if (PRINT_FIELD(DSO)) { | ||
590 | printf("("); | ||
591 | map__fprintf_dsoname(alt.map, stdout); | ||
592 | printf(")"); | ||
593 | } | ||
594 | |||
595 | printf("/%c/%c/%c/%d ", | ||
529 | mispred_str( br->entries + i), | 596 | mispred_str( br->entries + i), |
530 | br->entries[i].flags.in_tx? 'X' : '-', | 597 | br->entries[i].flags.in_tx? 'X' : '-', |
531 | br->entries[i].flags.abort? 'A' : '-', | 598 | br->entries[i].flags.abort? 'A' : '-', |
@@ -534,7 +601,8 @@ static void print_sample_brstack(struct perf_sample *sample) | |||
534 | } | 601 | } |
535 | 602 | ||
536 | static void print_sample_brstacksym(struct perf_sample *sample, | 603 | static void print_sample_brstacksym(struct perf_sample *sample, |
537 | struct thread *thread) | 604 | struct thread *thread, |
605 | struct perf_event_attr *attr) | ||
538 | { | 606 | { |
539 | struct branch_stack *br = sample->branch_stack; | 607 | struct branch_stack *br = sample->branch_stack; |
540 | struct addr_location alf, alt; | 608 | struct addr_location alf, alt; |
@@ -559,8 +627,18 @@ static void print_sample_brstacksym(struct perf_sample *sample, | |||
559 | alt.sym = map__find_symbol(alt.map, alt.addr); | 627 | alt.sym = map__find_symbol(alt.map, alt.addr); |
560 | 628 | ||
561 | symbol__fprintf_symname_offs(alf.sym, &alf, stdout); | 629 | symbol__fprintf_symname_offs(alf.sym, &alf, stdout); |
630 | if (PRINT_FIELD(DSO)) { | ||
631 | printf("("); | ||
632 | map__fprintf_dsoname(alf.map, stdout); | ||
633 | printf(")"); | ||
634 | } | ||
562 | putchar('/'); | 635 | putchar('/'); |
563 | symbol__fprintf_symname_offs(alt.sym, &alt, stdout); | 636 | symbol__fprintf_symname_offs(alt.sym, &alt, stdout); |
637 | if (PRINT_FIELD(DSO)) { | ||
638 | printf("("); | ||
639 | map__fprintf_dsoname(alt.map, stdout); | ||
640 | printf(")"); | ||
641 | } | ||
564 | printf("/%c/%c/%c/%d ", | 642 | printf("/%c/%c/%c/%d ", |
565 | mispred_str( br->entries + i), | 643 | mispred_str( br->entries + i), |
566 | br->entries[i].flags.in_tx? 'X' : '-', | 644 | br->entries[i].flags.in_tx? 'X' : '-', |
@@ -569,6 +647,51 @@ static void print_sample_brstacksym(struct perf_sample *sample, | |||
569 | } | 647 | } |
570 | } | 648 | } |
571 | 649 | ||
650 | static void print_sample_brstackoff(struct perf_sample *sample, | ||
651 | struct thread *thread, | ||
652 | struct perf_event_attr *attr) | ||
653 | { | ||
654 | struct branch_stack *br = sample->branch_stack; | ||
655 | struct addr_location alf, alt; | ||
656 | u64 i, from, to; | ||
657 | |||
658 | if (!(br && br->nr)) | ||
659 | return; | ||
660 | |||
661 | for (i = 0; i < br->nr; i++) { | ||
662 | |||
663 | memset(&alf, 0, sizeof(alf)); | ||
664 | memset(&alt, 0, sizeof(alt)); | ||
665 | from = br->entries[i].from; | ||
666 | to = br->entries[i].to; | ||
667 | |||
668 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); | ||
669 | if (alf.map && !alf.map->dso->adjust_symbols) | ||
670 | from = map__map_ip(alf.map, from); | ||
671 | |||
672 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); | ||
673 | if (alt.map && !alt.map->dso->adjust_symbols) | ||
674 | to = map__map_ip(alt.map, to); | ||
675 | |||
676 | printf("0x%"PRIx64, from); | ||
677 | if (PRINT_FIELD(DSO)) { | ||
678 | printf("("); | ||
679 | map__fprintf_dsoname(alf.map, stdout); | ||
680 | printf(")"); | ||
681 | } | ||
682 | printf("/0x%"PRIx64, to); | ||
683 | if (PRINT_FIELD(DSO)) { | ||
684 | printf("("); | ||
685 | map__fprintf_dsoname(alt.map, stdout); | ||
686 | printf(")"); | ||
687 | } | ||
688 | printf("/%c/%c/%c/%d ", | ||
689 | mispred_str(br->entries + i), | ||
690 | br->entries[i].flags.in_tx ? 'X' : '-', | ||
691 | br->entries[i].flags.abort ? 'A' : '-', | ||
692 | br->entries[i].flags.cycles); | ||
693 | } | ||
694 | } | ||
572 | #define MAXBB 16384UL | 695 | #define MAXBB 16384UL |
573 | 696 | ||
574 | static int grab_bb(u8 *buffer, u64 start, u64 end, | 697 | static int grab_bb(u8 *buffer, u64 start, u64 end, |
@@ -906,6 +1029,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
906 | struct machine *machine) | 1029 | struct machine *machine) |
907 | { | 1030 | { |
908 | struct perf_event_attr *attr = &evsel->attr; | 1031 | struct perf_event_attr *attr = &evsel->attr; |
1032 | unsigned int type = output_type(attr->type); | ||
909 | bool print_srcline_last = false; | 1033 | bool print_srcline_last = false; |
910 | 1034 | ||
911 | if (PRINT_FIELD(CALLINDENT)) | 1035 | if (PRINT_FIELD(CALLINDENT)) |
@@ -913,7 +1037,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
913 | 1037 | ||
914 | /* print branch_from information */ | 1038 | /* print branch_from information */ |
915 | if (PRINT_FIELD(IP)) { | 1039 | if (PRINT_FIELD(IP)) { |
916 | unsigned int print_opts = output[attr->type].print_ip_opts; | 1040 | unsigned int print_opts = output[type].print_ip_opts; |
917 | struct callchain_cursor *cursor = NULL; | 1041 | struct callchain_cursor *cursor = NULL; |
918 | 1042 | ||
919 | if (symbol_conf.use_callchain && sample->callchain && | 1043 | if (symbol_conf.use_callchain && sample->callchain && |
@@ -936,7 +1060,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
936 | /* print branch_to information */ | 1060 | /* print branch_to information */ |
937 | if (PRINT_FIELD(ADDR) || | 1061 | if (PRINT_FIELD(ADDR) || |
938 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 1062 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
939 | !output[attr->type].user_set)) { | 1063 | !output[type].user_set)) { |
940 | printf(" => "); | 1064 | printf(" => "); |
941 | print_sample_addr(sample, thread, attr); | 1065 | print_sample_addr(sample, thread, attr); |
942 | } | 1066 | } |
@@ -1079,6 +1203,127 @@ static void print_sample_bpf_output(struct perf_sample *sample) | |||
1079 | (char *)(sample->raw_data)); | 1203 | (char *)(sample->raw_data)); |
1080 | } | 1204 | } |
1081 | 1205 | ||
1206 | static void print_sample_spacing(int len, int spacing) | ||
1207 | { | ||
1208 | if (len > 0 && len < spacing) | ||
1209 | printf("%*s", spacing - len, ""); | ||
1210 | } | ||
1211 | |||
1212 | static void print_sample_pt_spacing(int len) | ||
1213 | { | ||
1214 | print_sample_spacing(len, 34); | ||
1215 | } | ||
1216 | |||
1217 | static void print_sample_synth_ptwrite(struct perf_sample *sample) | ||
1218 | { | ||
1219 | struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample); | ||
1220 | int len; | ||
1221 | |||
1222 | if (perf_sample__bad_synth_size(sample, *data)) | ||
1223 | return; | ||
1224 | |||
1225 | len = printf(" IP: %u payload: %#" PRIx64 " ", | ||
1226 | data->ip, le64_to_cpu(data->payload)); | ||
1227 | print_sample_pt_spacing(len); | ||
1228 | } | ||
1229 | |||
1230 | static void print_sample_synth_mwait(struct perf_sample *sample) | ||
1231 | { | ||
1232 | struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample); | ||
1233 | int len; | ||
1234 | |||
1235 | if (perf_sample__bad_synth_size(sample, *data)) | ||
1236 | return; | ||
1237 | |||
1238 | len = printf(" hints: %#x extensions: %#x ", | ||
1239 | data->hints, data->extensions); | ||
1240 | print_sample_pt_spacing(len); | ||
1241 | } | ||
1242 | |||
1243 | static void print_sample_synth_pwre(struct perf_sample *sample) | ||
1244 | { | ||
1245 | struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample); | ||
1246 | int len; | ||
1247 | |||
1248 | if (perf_sample__bad_synth_size(sample, *data)) | ||
1249 | return; | ||
1250 | |||
1251 | len = printf(" hw: %u cstate: %u sub-cstate: %u ", | ||
1252 | data->hw, data->cstate, data->subcstate); | ||
1253 | print_sample_pt_spacing(len); | ||
1254 | } | ||
1255 | |||
1256 | static void print_sample_synth_exstop(struct perf_sample *sample) | ||
1257 | { | ||
1258 | struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample); | ||
1259 | int len; | ||
1260 | |||
1261 | if (perf_sample__bad_synth_size(sample, *data)) | ||
1262 | return; | ||
1263 | |||
1264 | len = printf(" IP: %u ", data->ip); | ||
1265 | print_sample_pt_spacing(len); | ||
1266 | } | ||
1267 | |||
1268 | static void print_sample_synth_pwrx(struct perf_sample *sample) | ||
1269 | { | ||
1270 | struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample); | ||
1271 | int len; | ||
1272 | |||
1273 | if (perf_sample__bad_synth_size(sample, *data)) | ||
1274 | return; | ||
1275 | |||
1276 | len = printf(" deepest cstate: %u last cstate: %u wake reason: %#x ", | ||
1277 | data->deepest_cstate, data->last_cstate, | ||
1278 | data->wake_reason); | ||
1279 | print_sample_pt_spacing(len); | ||
1280 | } | ||
1281 | |||
1282 | static void print_sample_synth_cbr(struct perf_sample *sample) | ||
1283 | { | ||
1284 | struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample); | ||
1285 | unsigned int percent, freq; | ||
1286 | int len; | ||
1287 | |||
1288 | if (perf_sample__bad_synth_size(sample, *data)) | ||
1289 | return; | ||
1290 | |||
1291 | freq = (le32_to_cpu(data->freq) + 500) / 1000; | ||
1292 | len = printf(" cbr: %2u freq: %4u MHz ", data->cbr, freq); | ||
1293 | if (data->max_nonturbo) { | ||
1294 | percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10; | ||
1295 | len += printf("(%3u%%) ", percent); | ||
1296 | } | ||
1297 | print_sample_pt_spacing(len); | ||
1298 | } | ||
1299 | |||
1300 | static void print_sample_synth(struct perf_sample *sample, | ||
1301 | struct perf_evsel *evsel) | ||
1302 | { | ||
1303 | switch (evsel->attr.config) { | ||
1304 | case PERF_SYNTH_INTEL_PTWRITE: | ||
1305 | print_sample_synth_ptwrite(sample); | ||
1306 | break; | ||
1307 | case PERF_SYNTH_INTEL_MWAIT: | ||
1308 | print_sample_synth_mwait(sample); | ||
1309 | break; | ||
1310 | case PERF_SYNTH_INTEL_PWRE: | ||
1311 | print_sample_synth_pwre(sample); | ||
1312 | break; | ||
1313 | case PERF_SYNTH_INTEL_EXSTOP: | ||
1314 | print_sample_synth_exstop(sample); | ||
1315 | break; | ||
1316 | case PERF_SYNTH_INTEL_PWRX: | ||
1317 | print_sample_synth_pwrx(sample); | ||
1318 | break; | ||
1319 | case PERF_SYNTH_INTEL_CBR: | ||
1320 | print_sample_synth_cbr(sample); | ||
1321 | break; | ||
1322 | default: | ||
1323 | break; | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1082 | struct perf_script { | 1327 | struct perf_script { |
1083 | struct perf_tool tool; | 1328 | struct perf_tool tool; |
1084 | struct perf_session *session; | 1329 | struct perf_session *session; |
@@ -1132,8 +1377,9 @@ static void process_event(struct perf_script *script, | |||
1132 | { | 1377 | { |
1133 | struct thread *thread = al->thread; | 1378 | struct thread *thread = al->thread; |
1134 | struct perf_event_attr *attr = &evsel->attr; | 1379 | struct perf_event_attr *attr = &evsel->attr; |
1380 | unsigned int type = output_type(attr->type); | ||
1135 | 1381 | ||
1136 | if (output[attr->type].fields == 0) | 1382 | if (output[type].fields == 0) |
1137 | return; | 1383 | return; |
1138 | 1384 | ||
1139 | print_sample_start(sample, thread, evsel); | 1385 | print_sample_start(sample, thread, evsel); |
@@ -1162,6 +1408,10 @@ static void process_event(struct perf_script *script, | |||
1162 | if (PRINT_FIELD(TRACE)) | 1408 | if (PRINT_FIELD(TRACE)) |
1163 | event_format__print(evsel->tp_format, sample->cpu, | 1409 | event_format__print(evsel->tp_format, sample->cpu, |
1164 | sample->raw_data, sample->raw_size); | 1410 | sample->raw_data, sample->raw_size); |
1411 | |||
1412 | if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH)) | ||
1413 | print_sample_synth(sample, evsel); | ||
1414 | |||
1165 | if (PRINT_FIELD(ADDR)) | 1415 | if (PRINT_FIELD(ADDR)) |
1166 | print_sample_addr(sample, thread, attr); | 1416 | print_sample_addr(sample, thread, attr); |
1167 | 1417 | ||
@@ -1180,16 +1430,18 @@ static void process_event(struct perf_script *script, | |||
1180 | cursor = &callchain_cursor; | 1430 | cursor = &callchain_cursor; |
1181 | 1431 | ||
1182 | putchar(cursor ? '\n' : ' '); | 1432 | putchar(cursor ? '\n' : ' '); |
1183 | sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); | 1433 | sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout); |
1184 | } | 1434 | } |
1185 | 1435 | ||
1186 | if (PRINT_FIELD(IREGS)) | 1436 | if (PRINT_FIELD(IREGS)) |
1187 | print_sample_iregs(sample, attr); | 1437 | print_sample_iregs(sample, attr); |
1188 | 1438 | ||
1189 | if (PRINT_FIELD(BRSTACK)) | 1439 | if (PRINT_FIELD(BRSTACK)) |
1190 | print_sample_brstack(sample); | 1440 | print_sample_brstack(sample, thread, attr); |
1191 | else if (PRINT_FIELD(BRSTACKSYM)) | 1441 | else if (PRINT_FIELD(BRSTACKSYM)) |
1192 | print_sample_brstacksym(sample, thread); | 1442 | print_sample_brstacksym(sample, thread, attr); |
1443 | else if (PRINT_FIELD(BRSTACKOFF)) | ||
1444 | print_sample_brstackoff(sample, thread, attr); | ||
1193 | 1445 | ||
1194 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) | 1446 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) |
1195 | print_sample_bpf_output(sample); | 1447 | print_sample_bpf_output(sample); |
@@ -1325,7 +1577,8 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, | |||
1325 | evlist = *pevlist; | 1577 | evlist = *pevlist; |
1326 | evsel = perf_evlist__last(*pevlist); | 1578 | evsel = perf_evlist__last(*pevlist); |
1327 | 1579 | ||
1328 | if (evsel->attr.type >= PERF_TYPE_MAX) | 1580 | if (evsel->attr.type >= PERF_TYPE_MAX && |
1581 | evsel->attr.type != PERF_TYPE_SYNTH) | ||
1329 | return 0; | 1582 | return 0; |
1330 | 1583 | ||
1331 | evlist__for_each_entry(evlist, pos) { | 1584 | evlist__for_each_entry(evlist, pos) { |
@@ -1727,6 +1980,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1727 | int rc = 0; | 1980 | int rc = 0; |
1728 | char *str = strdup(arg); | 1981 | char *str = strdup(arg); |
1729 | int type = -1; | 1982 | int type = -1; |
1983 | enum { DEFAULT, SET, ADD, REMOVE } change = DEFAULT; | ||
1730 | 1984 | ||
1731 | if (!str) | 1985 | if (!str) |
1732 | return -ENOMEM; | 1986 | return -ENOMEM; |
@@ -1749,6 +2003,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1749 | type = PERF_TYPE_RAW; | 2003 | type = PERF_TYPE_RAW; |
1750 | else if (!strcmp(str, "break")) | 2004 | else if (!strcmp(str, "break")) |
1751 | type = PERF_TYPE_BREAKPOINT; | 2005 | type = PERF_TYPE_BREAKPOINT; |
2006 | else if (!strcmp(str, "synth")) | ||
2007 | type = OUTPUT_TYPE_SYNTH; | ||
1752 | else { | 2008 | else { |
1753 | fprintf(stderr, "Invalid event type in field string.\n"); | 2009 | fprintf(stderr, "Invalid event type in field string.\n"); |
1754 | rc = -EINVAL; | 2010 | rc = -EINVAL; |
@@ -1772,23 +2028,44 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1772 | goto out; | 2028 | goto out; |
1773 | } | 2029 | } |
1774 | 2030 | ||
2031 | /* Don't override defaults for +- */ | ||
2032 | if (strchr(str, '+') || strchr(str, '-')) | ||
2033 | goto parse; | ||
2034 | |||
1775 | if (output_set_by_user()) | 2035 | if (output_set_by_user()) |
1776 | pr_warning("Overriding previous field request for all events.\n"); | 2036 | pr_warning("Overriding previous field request for all events.\n"); |
1777 | 2037 | ||
1778 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 2038 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
1779 | output[j].fields = 0; | 2039 | output[j].fields = 0; |
1780 | output[j].user_set = true; | 2040 | output[j].user_set = true; |
1781 | output[j].wildcard_set = true; | 2041 | output[j].wildcard_set = true; |
1782 | } | 2042 | } |
1783 | } | 2043 | } |
1784 | 2044 | ||
2045 | parse: | ||
1785 | for (tok = strtok_r(tok, ",", &strtok_saveptr); tok; tok = strtok_r(NULL, ",", &strtok_saveptr)) { | 2046 | for (tok = strtok_r(tok, ",", &strtok_saveptr); tok; tok = strtok_r(NULL, ",", &strtok_saveptr)) { |
2047 | if (*tok == '+') { | ||
2048 | if (change == SET) | ||
2049 | goto out_badmix; | ||
2050 | change = ADD; | ||
2051 | tok++; | ||
2052 | } else if (*tok == '-') { | ||
2053 | if (change == SET) | ||
2054 | goto out_badmix; | ||
2055 | change = REMOVE; | ||
2056 | tok++; | ||
2057 | } else { | ||
2058 | if (change != SET && change != DEFAULT) | ||
2059 | goto out_badmix; | ||
2060 | change = SET; | ||
2061 | } | ||
2062 | |||
1786 | for (i = 0; i < imax; ++i) { | 2063 | for (i = 0; i < imax; ++i) { |
1787 | if (strcmp(tok, all_output_options[i].str) == 0) | 2064 | if (strcmp(tok, all_output_options[i].str) == 0) |
1788 | break; | 2065 | break; |
1789 | } | 2066 | } |
1790 | if (i == imax && strcmp(tok, "flags") == 0) { | 2067 | if (i == imax && strcmp(tok, "flags") == 0) { |
1791 | print_flags = true; | 2068 | print_flags = change == REMOVE ? false : true; |
1792 | continue; | 2069 | continue; |
1793 | } | 2070 | } |
1794 | if (i == imax) { | 2071 | if (i == imax) { |
@@ -1801,12 +2078,16 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1801 | /* add user option to all events types for | 2078 | /* add user option to all events types for |
1802 | * which it is valid | 2079 | * which it is valid |
1803 | */ | 2080 | */ |
1804 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 2081 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
1805 | if (output[j].invalid_fields & all_output_options[i].field) { | 2082 | if (output[j].invalid_fields & all_output_options[i].field) { |
1806 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", | 2083 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", |
1807 | all_output_options[i].str, event_type(j)); | 2084 | all_output_options[i].str, event_type(j)); |
1808 | } else | 2085 | } else { |
1809 | output[j].fields |= all_output_options[i].field; | 2086 | if (change == REMOVE) |
2087 | output[j].fields &= ~all_output_options[i].field; | ||
2088 | else | ||
2089 | output[j].fields |= all_output_options[i].field; | ||
2090 | } | ||
1810 | } | 2091 | } |
1811 | } else { | 2092 | } else { |
1812 | if (output[type].invalid_fields & all_output_options[i].field) { | 2093 | if (output[type].invalid_fields & all_output_options[i].field) { |
@@ -1826,7 +2107,11 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1826 | "Events will not be displayed.\n", event_type(type)); | 2107 | "Events will not be displayed.\n", event_type(type)); |
1827 | } | 2108 | } |
1828 | } | 2109 | } |
2110 | goto out; | ||
1829 | 2111 | ||
2112 | out_badmix: | ||
2113 | fprintf(stderr, "Cannot mix +-field with overridden fields\n"); | ||
2114 | rc = -EINVAL; | ||
1830 | out: | 2115 | out: |
1831 | free(str); | 2116 | free(str); |
1832 | return rc; | 2117 | return rc; |
@@ -2444,10 +2729,11 @@ int cmd_script(int argc, const char **argv) | |||
2444 | symbol__config_symfs), | 2729 | symbol__config_symfs), |
2445 | OPT_CALLBACK('F', "fields", NULL, "str", | 2730 | OPT_CALLBACK('F', "fields", NULL, "str", |
2446 | "comma separated output fields prepend with 'type:'. " | 2731 | "comma separated output fields prepend with 'type:'. " |
2447 | "Valid types: hw,sw,trace,raw. " | 2732 | "+field to add and -field to remove." |
2733 | "Valid types: hw,sw,trace,raw,synth. " | ||
2448 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 2734 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
2449 | "addr,symoff,period,iregs,brstack,brstacksym,flags," | 2735 | "addr,symoff,period,iregs,brstack,brstacksym,flags," |
2450 | "bpf-output,callindent,insn,insnlen,brstackinsn", | 2736 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth", |
2451 | parse_output_fields), | 2737 | parse_output_fields), |
2452 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 2738 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
2453 | "system-wide collection from all CPUs"), | 2739 | "system-wide collection from all CPUs"), |
@@ -2494,6 +2780,8 @@ int cmd_script(int argc, const char **argv) | |||
2494 | "Enable kernel symbol demangling"), | 2780 | "Enable kernel symbol demangling"), |
2495 | OPT_STRING(0, "time", &script.time_str, "str", | 2781 | OPT_STRING(0, "time", &script.time_str, "str", |
2496 | "Time span of interest (start,stop)"), | 2782 | "Time span of interest (start,stop)"), |
2783 | OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, | ||
2784 | "Show inline function"), | ||
2497 | OPT_END() | 2785 | OPT_END() |
2498 | }; | 2786 | }; |
2499 | const char * const script_subcommands[] = { "record", "report", NULL }; | 2787 | const char * const script_subcommands[] = { "record", "report", NULL }; |
@@ -2704,6 +2992,7 @@ int cmd_script(int argc, const char **argv) | |||
2704 | err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); | 2992 | err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); |
2705 | if (err < 0) | 2993 | if (err < 0) |
2706 | goto out_delete; | 2994 | goto out_delete; |
2995 | itrace_synth_opts.cpu_bitmap = cpu_bitmap; | ||
2707 | } | 2996 | } |
2708 | 2997 | ||
2709 | if (!no_callchain) | 2998 | if (!no_callchain) |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a935b5023732..48ac53b199fc 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -86,6 +86,7 @@ | |||
86 | #define DEFAULT_SEPARATOR " " | 86 | #define DEFAULT_SEPARATOR " " |
87 | #define CNTR_NOT_SUPPORTED "<not supported>" | 87 | #define CNTR_NOT_SUPPORTED "<not supported>" |
88 | #define CNTR_NOT_COUNTED "<not counted>" | 88 | #define CNTR_NOT_COUNTED "<not counted>" |
89 | #define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" | ||
89 | 90 | ||
90 | static void print_counters(struct timespec *ts, int argc, const char **argv); | 91 | static void print_counters(struct timespec *ts, int argc, const char **argv); |
91 | 92 | ||
@@ -122,6 +123,14 @@ static const char * topdown_attrs[] = { | |||
122 | NULL, | 123 | NULL, |
123 | }; | 124 | }; |
124 | 125 | ||
126 | static const char *smi_cost_attrs = { | ||
127 | "{" | ||
128 | "msr/aperf/," | ||
129 | "msr/smi/," | ||
130 | "cycles" | ||
131 | "}" | ||
132 | }; | ||
133 | |||
125 | static struct perf_evlist *evsel_list; | 134 | static struct perf_evlist *evsel_list; |
126 | 135 | ||
127 | static struct target target = { | 136 | static struct target target = { |
@@ -137,6 +146,8 @@ static bool null_run = false; | |||
137 | static int detailed_run = 0; | 146 | static int detailed_run = 0; |
138 | static bool transaction_run; | 147 | static bool transaction_run; |
139 | static bool topdown_run = false; | 148 | static bool topdown_run = false; |
149 | static bool smi_cost = false; | ||
150 | static bool smi_reset = false; | ||
140 | static bool big_num = true; | 151 | static bool big_num = true; |
141 | static int big_num_opt = -1; | 152 | static int big_num_opt = -1; |
142 | static const char *csv_sep = NULL; | 153 | static const char *csv_sep = NULL; |
@@ -625,14 +636,14 @@ try_again: | |||
625 | } | 636 | } |
626 | 637 | ||
627 | if (perf_evlist__apply_filters(evsel_list, &counter)) { | 638 | if (perf_evlist__apply_filters(evsel_list, &counter)) { |
628 | error("failed to set filter \"%s\" on event %s with %d (%s)\n", | 639 | pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", |
629 | counter->filter, perf_evsel__name(counter), errno, | 640 | counter->filter, perf_evsel__name(counter), errno, |
630 | str_error_r(errno, msg, sizeof(msg))); | 641 | str_error_r(errno, msg, sizeof(msg))); |
631 | return -1; | 642 | return -1; |
632 | } | 643 | } |
633 | 644 | ||
634 | if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) { | 645 | if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) { |
635 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | 646 | pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", |
636 | err_term->val.drv_cfg, perf_evsel__name(counter), errno, | 647 | err_term->val.drv_cfg, perf_evsel__name(counter), errno, |
637 | str_error_r(errno, msg, sizeof(msg))); | 648 | str_error_r(errno, msg, sizeof(msg))); |
638 | return -1; | 649 | return -1; |
@@ -1578,6 +1589,7 @@ static void print_header(int argc, const char **argv) | |||
1578 | static void print_footer(void) | 1589 | static void print_footer(void) |
1579 | { | 1590 | { |
1580 | FILE *output = stat_config.output; | 1591 | FILE *output = stat_config.output; |
1592 | int n; | ||
1581 | 1593 | ||
1582 | if (!null_run) | 1594 | if (!null_run) |
1583 | fprintf(output, "\n"); | 1595 | fprintf(output, "\n"); |
@@ -1590,7 +1602,9 @@ static void print_footer(void) | |||
1590 | } | 1602 | } |
1591 | fprintf(output, "\n\n"); | 1603 | fprintf(output, "\n\n"); |
1592 | 1604 | ||
1593 | if (print_free_counters_hint) | 1605 | if (print_free_counters_hint && |
1606 | sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 && | ||
1607 | n > 0) | ||
1594 | fprintf(output, | 1608 | fprintf(output, |
1595 | "Some events weren't counted. Try disabling the NMI watchdog:\n" | 1609 | "Some events weren't counted. Try disabling the NMI watchdog:\n" |
1596 | " echo 0 > /proc/sys/kernel/nmi_watchdog\n" | 1610 | " echo 0 > /proc/sys/kernel/nmi_watchdog\n" |
@@ -1779,6 +1793,8 @@ static const struct option stat_options[] = { | |||
1779 | "Only print computed metrics. No raw values", enable_metric_only), | 1793 | "Only print computed metrics. No raw values", enable_metric_only), |
1780 | OPT_BOOLEAN(0, "topdown", &topdown_run, | 1794 | OPT_BOOLEAN(0, "topdown", &topdown_run, |
1781 | "measure topdown level 1 statistics"), | 1795 | "measure topdown level 1 statistics"), |
1796 | OPT_BOOLEAN(0, "smi-cost", &smi_cost, | ||
1797 | "measure SMI cost"), | ||
1782 | OPT_END() | 1798 | OPT_END() |
1783 | }; | 1799 | }; |
1784 | 1800 | ||
@@ -2157,6 +2173,39 @@ static int add_default_attributes(void) | |||
2157 | return 0; | 2173 | return 0; |
2158 | } | 2174 | } |
2159 | 2175 | ||
2176 | if (smi_cost) { | ||
2177 | int smi; | ||
2178 | |||
2179 | if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { | ||
2180 | fprintf(stderr, "freeze_on_smi is not supported.\n"); | ||
2181 | return -1; | ||
2182 | } | ||
2183 | |||
2184 | if (!smi) { | ||
2185 | if (sysfs__write_int(FREEZE_ON_SMI_PATH, 1) < 0) { | ||
2186 | fprintf(stderr, "Failed to set freeze_on_smi.\n"); | ||
2187 | return -1; | ||
2188 | } | ||
2189 | smi_reset = true; | ||
2190 | } | ||
2191 | |||
2192 | if (pmu_have_event("msr", "aperf") && | ||
2193 | pmu_have_event("msr", "smi")) { | ||
2194 | if (!force_metric_only) | ||
2195 | metric_only = true; | ||
2196 | err = parse_events(evsel_list, smi_cost_attrs, NULL); | ||
2197 | } else { | ||
2198 | fprintf(stderr, "To measure SMI cost, it needs " | ||
2199 | "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); | ||
2200 | return -1; | ||
2201 | } | ||
2202 | if (err) { | ||
2203 | fprintf(stderr, "Cannot set up SMI cost events\n"); | ||
2204 | return -1; | ||
2205 | } | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2160 | if (topdown_run) { | 2209 | if (topdown_run) { |
2161 | char *str = NULL; | 2210 | char *str = NULL; |
2162 | bool warn = false; | 2211 | bool warn = false; |
@@ -2739,6 +2788,9 @@ int cmd_stat(int argc, const char **argv) | |||
2739 | perf_stat__exit_aggr_mode(); | 2788 | perf_stat__exit_aggr_mode(); |
2740 | perf_evlist__free_stats(evsel_list); | 2789 | perf_evlist__free_stats(evsel_list); |
2741 | out: | 2790 | out: |
2791 | if (smi_cost && smi_reset) | ||
2792 | sysfs__write_int(FREEZE_ON_SMI_PATH, 0); | ||
2793 | |||
2742 | perf_evlist__delete(evsel_list); | 2794 | perf_evlist__delete(evsel_list); |
2743 | return status; | 2795 | return status; |
2744 | } | 2796 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 10b6362ca0bf..6052376634c0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -134,7 +134,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) | |||
134 | return err; | 134 | return err; |
135 | } | 135 | } |
136 | 136 | ||
137 | err = symbol__disassemble(sym, map, NULL, 0); | 137 | err = symbol__disassemble(sym, map, NULL, 0, NULL); |
138 | if (err == 0) { | 138 | if (err == 0) { |
139 | out_assign: | 139 | out_assign: |
140 | top->sym_filter_entry = he; | 140 | top->sym_filter_entry = he; |
@@ -958,7 +958,7 @@ static int __cmd_top(struct perf_top *top) | |||
958 | 958 | ||
959 | ret = perf_evlist__apply_drv_configs(evlist, &pos, &err_term); | 959 | ret = perf_evlist__apply_drv_configs(evlist, &pos, &err_term); |
960 | if (ret) { | 960 | if (ret) { |
961 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | 961 | pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", |
962 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, | 962 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, |
963 | str_error_r(errno, msg, sizeof(msg))); | 963 | str_error_r(errno, msg, sizeof(msg))); |
964 | goto out_delete; | 964 | goto out_delete; |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d014350adc52..4b2a5d298197 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -681,6 +681,10 @@ static struct syscall_fmt { | |||
681 | { .name = "mlockall", .errmsg = true, | 681 | { .name = "mlockall", .errmsg = true, |
682 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, | 682 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, |
683 | { .name = "mmap", .hexret = true, | 683 | { .name = "mmap", .hexret = true, |
684 | /* The standard mmap maps to old_mmap on s390x */ | ||
685 | #if defined(__s390x__) | ||
686 | .alias = "old_mmap", | ||
687 | #endif | ||
684 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ | 688 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ |
685 | [2] = SCA_MMAP_PROT, /* prot */ | 689 | [2] = SCA_MMAP_PROT, /* prot */ |
686 | [3] = SCA_MMAP_FLAGS, /* flags */ }, }, | 690 | [3] = SCA_MMAP_FLAGS, /* flags */ }, }, |
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c index e9651a9d670e..cf36de7ea255 100644 --- a/tools/perf/jvmti/jvmti_agent.c +++ b/tools/perf/jvmti/jvmti_agent.c | |||
@@ -304,7 +304,7 @@ jvmti_close(void *agent) | |||
304 | FILE *fp = agent; | 304 | FILE *fp = agent; |
305 | 305 | ||
306 | if (!fp) { | 306 | if (!fp) { |
307 | warnx("jvmti: incalid fd in close_agent"); | 307 | warnx("jvmti: invalid fd in close_agent"); |
308 | return -1; | 308 | return -1; |
309 | } | 309 | } |
310 | 310 | ||
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h index bedf5d0ba9ff..c53a41f48b63 100644 --- a/tools/perf/jvmti/jvmti_agent.h +++ b/tools/perf/jvmti/jvmti_agent.h | |||
@@ -5,8 +5,6 @@ | |||
5 | #include <stdint.h> | 5 | #include <stdint.h> |
6 | #include <jvmti.h> | 6 | #include <jvmti.h> |
7 | 7 | ||
8 | #define __unused __attribute__((unused)) | ||
9 | |||
10 | #if defined(__cplusplus) | 8 | #if defined(__cplusplus) |
11 | extern "C" { | 9 | extern "C" { |
12 | #endif | 10 | #endif |
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c index 5612641c69b4..6d710904c837 100644 --- a/tools/perf/jvmti/libjvmti.c +++ b/tools/perf/jvmti/libjvmti.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <linux/compiler.h> | ||
1 | #include <sys/types.h> | 2 | #include <sys/types.h> |
2 | #include <stdio.h> | 3 | #include <stdio.h> |
3 | #include <string.h> | 4 | #include <string.h> |
@@ -238,7 +239,7 @@ code_generated_cb(jvmtiEnv *jvmti, | |||
238 | } | 239 | } |
239 | 240 | ||
240 | JNIEXPORT jint JNICALL | 241 | JNIEXPORT jint JNICALL |
241 | Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused) | 242 | Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __maybe_unused) |
242 | { | 243 | { |
243 | jvmtiEventCallbacks cb; | 244 | jvmtiEventCallbacks cb; |
244 | jvmtiCapabilities caps1; | 245 | jvmtiCapabilities caps1; |
@@ -313,7 +314,7 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused) | |||
313 | } | 314 | } |
314 | 315 | ||
315 | JNIEXPORT void JNICALL | 316 | JNIEXPORT void JNICALL |
316 | Agent_OnUnload(JavaVM *jvm __unused) | 317 | Agent_OnUnload(JavaVM *jvm __maybe_unused) |
317 | { | 318 | { |
318 | int ret; | 319 | int ret; |
319 | 320 | ||
diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build index 9213a1273697..999a4e878162 100644 --- a/tools/perf/pmu-events/Build +++ b/tools/perf/pmu-events/Build | |||
@@ -2,7 +2,7 @@ hostprogs := jevents | |||
2 | 2 | ||
3 | jevents-y += json.o jsmn.o jevents.o | 3 | jevents-y += json.o jsmn.o jevents.o |
4 | pmu-events-y += pmu-events.o | 4 | pmu-events-y += pmu-events.o |
5 | JDIR = pmu-events/arch/$(ARCH) | 5 | JDIR = pmu-events/arch/$(SRCARCH) |
6 | JSON = $(shell [ -d $(JDIR) ] && \ | 6 | JSON = $(shell [ -d $(JDIR) ] && \ |
7 | find $(JDIR) -name '*.json' -o -name 'mapfile.csv') | 7 | find $(JDIR) -name '*.json' -o -name 'mapfile.csv') |
8 | # | 8 | # |
@@ -10,4 +10,4 @@ JSON = $(shell [ -d $(JDIR) ] && \ | |||
10 | # directory and create tables in pmu-events.c. | 10 | # directory and create tables in pmu-events.c. |
11 | # | 11 | # |
12 | $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JEVENTS) | 12 | $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JEVENTS) |
13 | $(Q)$(call echo-cmd,gen)$(JEVENTS) $(ARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V) | 13 | $(Q)$(call echo-cmd,gen)$(JEVENTS) $(SRCARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V) |
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index baa073f38334..bd0aabb2bd0f 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c | |||
@@ -48,10 +48,6 @@ | |||
48 | #include "json.h" | 48 | #include "json.h" |
49 | #include "jevents.h" | 49 | #include "jevents.h" |
50 | 50 | ||
51 | #ifndef __maybe_unused | ||
52 | #define __maybe_unused __attribute__((unused)) | ||
53 | #endif | ||
54 | |||
55 | int verbose; | 51 | int verbose; |
56 | char *prog; | 52 | char *prog; |
57 | 53 | ||
diff --git a/tools/perf/scripts/python/bin/intel-pt-events-record b/tools/perf/scripts/python/bin/intel-pt-events-record new file mode 100644 index 000000000000..10fe2b6977d4 --- /dev/null +++ b/tools/perf/scripts/python/bin/intel-pt-events-record | |||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # | ||
4 | # print Intel PT Power Events and PTWRITE. The intel_pt PMU event needs | ||
5 | # to be specified with appropriate config terms. | ||
6 | # | ||
7 | if ! echo "$@" | grep -q intel_pt ; then | ||
8 | echo "Options must include the Intel PT event e.g. -e intel_pt/pwr_evt,ptw/" | ||
9 | echo "and for power events it probably needs to be system wide i.e. -a option" | ||
10 | echo "For example: -a -e intel_pt/pwr_evt,branch=0/ sleep 1" | ||
11 | exit 1 | ||
12 | fi | ||
13 | perf record $@ | ||
diff --git a/tools/perf/scripts/python/bin/intel-pt-events-report b/tools/perf/scripts/python/bin/intel-pt-events-report new file mode 100644 index 000000000000..9a9c92fcd026 --- /dev/null +++ b/tools/perf/scripts/python/bin/intel-pt-events-report | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/bash | ||
2 | # description: print Intel PT Power Events and PTWRITE | ||
3 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py \ No newline at end of file | ||
diff --git a/tools/perf/scripts/python/intel-pt-events.py b/tools/perf/scripts/python/intel-pt-events.py new file mode 100644 index 000000000000..b19172d673af --- /dev/null +++ b/tools/perf/scripts/python/intel-pt-events.py | |||
@@ -0,0 +1,128 @@ | |||
1 | # intel-pt-events.py: Print Intel PT Power Events and PTWRITE | ||
2 | # Copyright (c) 2017, Intel Corporation. | ||
3 | # | ||
4 | # This program is free software; you can redistribute it and/or modify it | ||
5 | # under the terms and conditions of the GNU General Public License, | ||
6 | # version 2, as published by the Free Software Foundation. | ||
7 | # | ||
8 | # This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | # more details. | ||
12 | |||
13 | import os | ||
14 | import sys | ||
15 | import struct | ||
16 | |||
17 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | ||
18 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | ||
19 | |||
20 | # These perf imports are not used at present | ||
21 | #from perf_trace_context import * | ||
22 | #from Core import * | ||
23 | |||
24 | def trace_begin(): | ||
25 | print "Intel PT Power Events and PTWRITE" | ||
26 | |||
27 | def trace_end(): | ||
28 | print "End" | ||
29 | |||
30 | def trace_unhandled(event_name, context, event_fields_dict): | ||
31 | print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) | ||
32 | |||
33 | def print_ptwrite(raw_buf): | ||
34 | data = struct.unpack_from("<IQ", raw_buf) | ||
35 | flags = data[0] | ||
36 | payload = data[1] | ||
37 | exact_ip = flags & 1 | ||
38 | print "IP: %u payload: %#x" % (exact_ip, payload), | ||
39 | |||
40 | def print_cbr(raw_buf): | ||
41 | data = struct.unpack_from("<BBBBII", raw_buf) | ||
42 | cbr = data[0] | ||
43 | f = (data[4] + 500) / 1000 | ||
44 | p = ((cbr * 1000 / data[2]) + 5) / 10 | ||
45 | print "%3u freq: %4u MHz (%3u%%)" % (cbr, f, p), | ||
46 | |||
47 | def print_mwait(raw_buf): | ||
48 | data = struct.unpack_from("<IQ", raw_buf) | ||
49 | payload = data[1] | ||
50 | hints = payload & 0xff | ||
51 | extensions = (payload >> 32) & 0x3 | ||
52 | print "hints: %#x extensions: %#x" % (hints, extensions), | ||
53 | |||
54 | def print_pwre(raw_buf): | ||
55 | data = struct.unpack_from("<IQ", raw_buf) | ||
56 | payload = data[1] | ||
57 | hw = (payload >> 7) & 1 | ||
58 | cstate = (payload >> 12) & 0xf | ||
59 | subcstate = (payload >> 8) & 0xf | ||
60 | print "hw: %u cstate: %u sub-cstate: %u" % (hw, cstate, subcstate), | ||
61 | |||
62 | def print_exstop(raw_buf): | ||
63 | data = struct.unpack_from("<I", raw_buf) | ||
64 | flags = data[0] | ||
65 | exact_ip = flags & 1 | ||
66 | print "IP: %u" % (exact_ip), | ||
67 | |||
68 | def print_pwrx(raw_buf): | ||
69 | data = struct.unpack_from("<IQ", raw_buf) | ||
70 | payload = data[1] | ||
71 | deepest_cstate = payload & 0xf | ||
72 | last_cstate = (payload >> 4) & 0xf | ||
73 | wake_reason = (payload >> 8) & 0xf | ||
74 | print "deepest cstate: %u last cstate: %u wake reason: %#x" % (deepest_cstate, last_cstate, wake_reason), | ||
75 | |||
76 | def print_common_start(comm, sample, name): | ||
77 | ts = sample["time"] | ||
78 | cpu = sample["cpu"] | ||
79 | pid = sample["pid"] | ||
80 | tid = sample["tid"] | ||
81 | print "%16s %5u/%-5u [%03u] %9u.%09u %7s:" % (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name), | ||
82 | |||
83 | def print_common_ip(sample, symbol, dso): | ||
84 | ip = sample["ip"] | ||
85 | print "%16x %s (%s)" % (ip, symbol, dso) | ||
86 | |||
87 | def process_event(param_dict): | ||
88 | event_attr = param_dict["attr"] | ||
89 | sample = param_dict["sample"] | ||
90 | raw_buf = param_dict["raw_buf"] | ||
91 | comm = param_dict["comm"] | ||
92 | name = param_dict["ev_name"] | ||
93 | |||
94 | # Symbol and dso info are not always resolved | ||
95 | if (param_dict.has_key("dso")): | ||
96 | dso = param_dict["dso"] | ||
97 | else: | ||
98 | dso = "[unknown]" | ||
99 | |||
100 | if (param_dict.has_key("symbol")): | ||
101 | symbol = param_dict["symbol"] | ||
102 | else: | ||
103 | symbol = "[unknown]" | ||
104 | |||
105 | if name == "ptwrite": | ||
106 | print_common_start(comm, sample, name) | ||
107 | print_ptwrite(raw_buf) | ||
108 | print_common_ip(sample, symbol, dso) | ||
109 | elif name == "cbr": | ||
110 | print_common_start(comm, sample, name) | ||
111 | print_cbr(raw_buf) | ||
112 | print_common_ip(sample, symbol, dso) | ||
113 | elif name == "mwait": | ||
114 | print_common_start(comm, sample, name) | ||
115 | print_mwait(raw_buf) | ||
116 | print_common_ip(sample, symbol, dso) | ||
117 | elif name == "pwre": | ||
118 | print_common_start(comm, sample, name) | ||
119 | print_pwre(raw_buf) | ||
120 | print_common_ip(sample, symbol, dso) | ||
121 | elif name == "exstop": | ||
122 | print_common_start(comm, sample, name) | ||
123 | print_exstop(raw_buf) | ||
124 | print_common_ip(sample, symbol, dso) | ||
125 | elif name == "pwrx": | ||
126 | print_common_start(comm, sample, name) | ||
127 | print_pwrx(raw_buf) | ||
128 | print_common_ip(sample, symbol, dso) | ||
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index af58ebc243ef..84222bdb8689 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build | |||
@@ -75,7 +75,7 @@ $(OUTPUT)tests/llvm-src-relocation.c: tests/bpf-script-test-relocation.c tests/B | |||
75 | $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ | 75 | $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ |
76 | $(Q)echo ';' >> $@ | 76 | $(Q)echo ';' >> $@ |
77 | 77 | ||
78 | ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64 powerpc)) | 78 | ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc)) |
79 | perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o | 79 | perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o |
80 | endif | 80 | endif |
81 | 81 | ||
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 0dd77494bb58..0e77b2cf61ec 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * permissions. All the event text files are stored there. | 18 | * permissions. All the event text files are stored there. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <debug.h> | ||
21 | #include <errno.h> | 22 | #include <errno.h> |
22 | #include <inttypes.h> | 23 | #include <inttypes.h> |
23 | #include <stdlib.h> | 24 | #include <stdlib.h> |
@@ -29,14 +30,11 @@ | |||
29 | #include <sys/stat.h> | 30 | #include <sys/stat.h> |
30 | #include <unistd.h> | 31 | #include <unistd.h> |
31 | #include "../perf.h" | 32 | #include "../perf.h" |
32 | #include "util.h" | ||
33 | #include <subcmd/exec-cmd.h> | 33 | #include <subcmd/exec-cmd.h> |
34 | #include "tests.h" | 34 | #include "tests.h" |
35 | 35 | ||
36 | #define ENV "PERF_TEST_ATTR" | 36 | #define ENV "PERF_TEST_ATTR" |
37 | 37 | ||
38 | extern int verbose; | ||
39 | |||
40 | static char *dir; | 38 | static char *dir; |
41 | 39 | ||
42 | void test_attr__init(void) | 40 | void test_attr__init(void) |
@@ -138,8 +136,10 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, | |||
138 | { | 136 | { |
139 | int errno_saved = errno; | 137 | int errno_saved = errno; |
140 | 138 | ||
141 | if (store_event(attr, pid, cpu, fd, group_fd, flags)) | 139 | if (store_event(attr, pid, cpu, fd, group_fd, flags)) { |
142 | die("test attr FAILED"); | 140 | pr_err("test attr FAILED"); |
141 | exit(128); | ||
142 | } | ||
143 | 143 | ||
144 | errno = errno_saved; | 144 | errno = errno_saved; |
145 | } | 145 | } |
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index 1091bd47adfd..cdf21a9d0c35 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py | |||
@@ -16,6 +16,13 @@ class Fail(Exception): | |||
16 | def getMsg(self): | 16 | def getMsg(self): |
17 | return '\'%s\' - %s' % (self.test.path, self.msg) | 17 | return '\'%s\' - %s' % (self.test.path, self.msg) |
18 | 18 | ||
19 | class Notest(Exception): | ||
20 | def __init__(self, test, arch): | ||
21 | self.arch = arch | ||
22 | self.test = test | ||
23 | def getMsg(self): | ||
24 | return '[%s] \'%s\'' % (self.arch, self.test.path) | ||
25 | |||
19 | class Unsup(Exception): | 26 | class Unsup(Exception): |
20 | def __init__(self, test): | 27 | def __init__(self, test): |
21 | self.test = test | 28 | self.test = test |
@@ -112,6 +119,9 @@ class Event(dict): | |||
112 | # 'command' - perf command name | 119 | # 'command' - perf command name |
113 | # 'args' - special command arguments | 120 | # 'args' - special command arguments |
114 | # 'ret' - expected command return value (0 by default) | 121 | # 'ret' - expected command return value (0 by default) |
122 | # 'arch' - architecture specific test (optional) | ||
123 | # comma separated list, ! at the beginning | ||
124 | # negates it. | ||
115 | # | 125 | # |
116 | # [eventX:base] | 126 | # [eventX:base] |
117 | # - one or multiple instances in file | 127 | # - one or multiple instances in file |
@@ -134,6 +144,12 @@ class Test(object): | |||
134 | except: | 144 | except: |
135 | self.ret = 0 | 145 | self.ret = 0 |
136 | 146 | ||
147 | try: | ||
148 | self.arch = parser.get('config', 'arch') | ||
149 | log.warning("test limitation '%s'" % self.arch) | ||
150 | except: | ||
151 | self.arch = '' | ||
152 | |||
137 | self.expect = {} | 153 | self.expect = {} |
138 | self.result = {} | 154 | self.result = {} |
139 | log.debug(" loading expected events"); | 155 | log.debug(" loading expected events"); |
@@ -145,6 +161,31 @@ class Test(object): | |||
145 | else: | 161 | else: |
146 | return True | 162 | return True |
147 | 163 | ||
164 | def skip_test(self, myarch): | ||
165 | # If architecture not set always run test | ||
166 | if self.arch == '': | ||
167 | # log.warning("test for arch %s is ok" % myarch) | ||
168 | return False | ||
169 | |||
170 | # Allow multiple values in assignment separated by ',' | ||
171 | arch_list = self.arch.split(',') | ||
172 | |||
173 | # Handle negated list such as !s390x,ppc | ||
174 | if arch_list[0][0] == '!': | ||
175 | arch_list[0] = arch_list[0][1:] | ||
176 | log.warning("excluded architecture list %s" % arch_list) | ||
177 | for arch_item in arch_list: | ||
178 | # log.warning("test for %s arch is %s" % (arch_item, myarch)) | ||
179 | if arch_item == myarch: | ||
180 | return True | ||
181 | return False | ||
182 | |||
183 | for arch_item in arch_list: | ||
184 | # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch)) | ||
185 | if arch_item == myarch: | ||
186 | return False | ||
187 | return True | ||
188 | |||
148 | def load_events(self, path, events): | 189 | def load_events(self, path, events): |
149 | parser_event = ConfigParser.SafeConfigParser() | 190 | parser_event = ConfigParser.SafeConfigParser() |
150 | parser_event.read(path) | 191 | parser_event.read(path) |
@@ -168,6 +209,11 @@ class Test(object): | |||
168 | events[section] = e | 209 | events[section] = e |
169 | 210 | ||
170 | def run_cmd(self, tempdir): | 211 | def run_cmd(self, tempdir): |
212 | junk1, junk2, junk3, junk4, myarch = (os.uname()) | ||
213 | |||
214 | if self.skip_test(myarch): | ||
215 | raise Notest(self, myarch) | ||
216 | |||
171 | cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, | 217 | cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, |
172 | self.perf, self.command, tempdir, self.args) | 218 | self.perf, self.command, tempdir, self.args) |
173 | ret = os.WEXITSTATUS(os.system(cmd)) | 219 | ret = os.WEXITSTATUS(os.system(cmd)) |
@@ -265,6 +311,8 @@ def run_tests(options): | |||
265 | Test(f, options).run() | 311 | Test(f, options).run() |
266 | except Unsup, obj: | 312 | except Unsup, obj: |
267 | log.warning("unsupp %s" % obj.getMsg()) | 313 | log.warning("unsupp %s" % obj.getMsg()) |
314 | except Notest, obj: | ||
315 | log.warning("skipped %s" % obj.getMsg()) | ||
268 | 316 | ||
269 | def setup_log(verbose): | 317 | def setup_log(verbose): |
270 | global log | 318 | global log |
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c index e7664fe3bd33..39bbb97cd30a 100644 --- a/tools/perf/tests/bp_signal.c +++ b/tools/perf/tests/bp_signal.c | |||
@@ -62,8 +62,7 @@ static void __test_function(volatile long *ptr) | |||
62 | } | 62 | } |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | __attribute__ ((noinline)) | 65 | static noinline int test_function(void) |
66 | static int test_function(void) | ||
67 | { | 66 | { |
68 | __test_function(&the_var); | 67 | __test_function(&the_var); |
69 | the_var++; | 68 | the_var++; |
@@ -288,3 +287,17 @@ int test__bp_signal(int subtest __maybe_unused) | |||
288 | return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ? | 287 | return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ? |
289 | TEST_OK : TEST_FAIL; | 288 | TEST_OK : TEST_FAIL; |
290 | } | 289 | } |
290 | |||
291 | bool test__bp_signal_is_supported(void) | ||
292 | { | ||
293 | /* | ||
294 | * The powerpc so far does not have support to even create | ||
295 | * instruction breakpoint using the perf event interface. | ||
296 | * Once it's there we can release this. | ||
297 | */ | ||
298 | #ifdef __powerpc__ | ||
299 | return false; | ||
300 | #else | ||
301 | return true; | ||
302 | #endif | ||
303 | } | ||
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c index 89f92fa67cc4..3b1ac6f31b15 100644 --- a/tools/perf/tests/bp_signal_overflow.c +++ b/tools/perf/tests/bp_signal_overflow.c | |||
@@ -28,8 +28,7 @@ | |||
28 | 28 | ||
29 | static int overflows; | 29 | static int overflows; |
30 | 30 | ||
31 | __attribute__ ((noinline)) | 31 | static noinline int test_function(void) |
32 | static int test_function(void) | ||
33 | { | 32 | { |
34 | return time(NULL); | 33 | return time(NULL); |
35 | } | 34 | } |
diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c index 7230e62c70fc..b4ebc75e25ae 100644 --- a/tools/perf/tests/bpf-script-test-prologue.c +++ b/tools/perf/tests/bpf-script-test-prologue.c | |||
@@ -10,6 +10,15 @@ | |||
10 | 10 | ||
11 | #include <uapi/linux/fs.h> | 11 | #include <uapi/linux/fs.h> |
12 | 12 | ||
13 | /* | ||
14 | * If CONFIG_PROFILE_ALL_BRANCHES is selected, | ||
15 | * 'if' is redefined after include kernel header. | ||
16 | * Recover 'if' for BPF object code. | ||
17 | */ | ||
18 | #ifdef if | ||
19 | # undef if | ||
20 | #endif | ||
21 | |||
13 | #define FMODE_READ 0x1 | 22 | #define FMODE_READ 0x1 |
14 | #define FMODE_WRITE 0x2 | 23 | #define FMODE_WRITE 0x2 |
15 | 24 | ||
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 9e08d297f1a9..3ccfd58a8c3c 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -97,10 +97,12 @@ static struct test generic_tests[] = { | |||
97 | { | 97 | { |
98 | .desc = "Breakpoint overflow signal handler", | 98 | .desc = "Breakpoint overflow signal handler", |
99 | .func = test__bp_signal, | 99 | .func = test__bp_signal, |
100 | .is_supported = test__bp_signal_is_supported, | ||
100 | }, | 101 | }, |
101 | { | 102 | { |
102 | .desc = "Breakpoint overflow sampling", | 103 | .desc = "Breakpoint overflow sampling", |
103 | .func = test__bp_signal_overflow, | 104 | .func = test__bp_signal_overflow, |
105 | .is_supported = test__bp_signal_is_supported, | ||
104 | }, | 106 | }, |
105 | { | 107 | { |
106 | .desc = "Number of exit events of a simple workload", | 108 | .desc = "Number of exit events of a simple workload", |
@@ -401,6 +403,11 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) | |||
401 | if (!perf_test__matches(t, curr, argc, argv)) | 403 | if (!perf_test__matches(t, curr, argc, argv)) |
402 | continue; | 404 | continue; |
403 | 405 | ||
406 | if (t->is_supported && !t->is_supported()) { | ||
407 | pr_debug("%2d: %-*s: Disabled\n", i, width, t->desc); | ||
408 | continue; | ||
409 | } | ||
410 | |||
404 | pr_info("%2d: %-*s:", i, width, t->desc); | 411 | pr_info("%2d: %-*s:", i, width, t->desc); |
405 | 412 | ||
406 | if (intlist__find(skiplist, i)) { | 413 | if (intlist__find(skiplist, i)) { |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 1f14e7612cbb..94b7c7b02bde 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
@@ -229,6 +229,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, | |||
229 | unsigned char buf2[BUFSZ]; | 229 | unsigned char buf2[BUFSZ]; |
230 | size_t ret_len; | 230 | size_t ret_len; |
231 | u64 objdump_addr; | 231 | u64 objdump_addr; |
232 | const char *objdump_name; | ||
233 | char decomp_name[KMOD_DECOMP_LEN]; | ||
232 | int ret; | 234 | int ret; |
233 | 235 | ||
234 | pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); | 236 | pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); |
@@ -289,9 +291,25 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, | |||
289 | state->done[state->done_cnt++] = al.map->start; | 291 | state->done[state->done_cnt++] = al.map->start; |
290 | } | 292 | } |
291 | 293 | ||
294 | objdump_name = al.map->dso->long_name; | ||
295 | if (dso__needs_decompress(al.map->dso)) { | ||
296 | if (dso__decompress_kmodule_path(al.map->dso, objdump_name, | ||
297 | decomp_name, | ||
298 | sizeof(decomp_name)) < 0) { | ||
299 | pr_debug("decompression failed\n"); | ||
300 | return -1; | ||
301 | } | ||
302 | |||
303 | objdump_name = decomp_name; | ||
304 | } | ||
305 | |||
292 | /* Read the object code using objdump */ | 306 | /* Read the object code using objdump */ |
293 | objdump_addr = map__rip_2objdump(al.map, al.addr); | 307 | objdump_addr = map__rip_2objdump(al.map, al.addr); |
294 | ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len); | 308 | ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); |
309 | |||
310 | if (dso__needs_decompress(al.map->dso)) | ||
311 | unlink(objdump_name); | ||
312 | |||
295 | if (ret > 0) { | 313 | if (ret > 0) { |
296 | /* | 314 | /* |
297 | * The kernel maps are inaccurate - assume objdump is right in | 315 | * The kernel maps are inaccurate - assume objdump is right in |
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index dfe5c89e2049..3e56d08f7995 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c | |||
@@ -76,8 +76,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) | |||
76 | return strcmp((const char *) symbol, funcs[idx]); | 76 | return strcmp((const char *) symbol, funcs[idx]); |
77 | } | 77 | } |
78 | 78 | ||
79 | __attribute__ ((noinline)) | 79 | static noinline int unwind_thread(struct thread *thread) |
80 | static int unwind_thread(struct thread *thread) | ||
81 | { | 80 | { |
82 | struct perf_sample sample; | 81 | struct perf_sample sample; |
83 | unsigned long cnt = 0; | 82 | unsigned long cnt = 0; |
@@ -108,8 +107,7 @@ static int unwind_thread(struct thread *thread) | |||
108 | 107 | ||
109 | static int global_unwind_retval = -INT_MAX; | 108 | static int global_unwind_retval = -INT_MAX; |
110 | 109 | ||
111 | __attribute__ ((noinline)) | 110 | static noinline int compare(void *p1, void *p2) |
112 | static int compare(void *p1, void *p2) | ||
113 | { | 111 | { |
114 | /* Any possible value should be 'thread' */ | 112 | /* Any possible value should be 'thread' */ |
115 | struct thread *thread = *(struct thread **)p1; | 113 | struct thread *thread = *(struct thread **)p1; |
@@ -128,8 +126,7 @@ static int compare(void *p1, void *p2) | |||
128 | return p1 - p2; | 126 | return p1 - p2; |
129 | } | 127 | } |
130 | 128 | ||
131 | __attribute__ ((noinline)) | 129 | static noinline int krava_3(struct thread *thread) |
132 | static int krava_3(struct thread *thread) | ||
133 | { | 130 | { |
134 | struct thread *array[2] = {thread, thread}; | 131 | struct thread *array[2] = {thread, thread}; |
135 | void *fp = &bsearch; | 132 | void *fp = &bsearch; |
@@ -147,14 +144,12 @@ static int krava_3(struct thread *thread) | |||
147 | return global_unwind_retval; | 144 | return global_unwind_retval; |
148 | } | 145 | } |
149 | 146 | ||
150 | __attribute__ ((noinline)) | 147 | static noinline int krava_2(struct thread *thread) |
151 | static int krava_2(struct thread *thread) | ||
152 | { | 148 | { |
153 | return krava_3(thread); | 149 | return krava_3(thread); |
154 | } | 150 | } |
155 | 151 | ||
156 | __attribute__ ((noinline)) | 152 | static noinline int krava_1(struct thread *thread) |
157 | static int krava_1(struct thread *thread) | ||
158 | { | 153 | { |
159 | return krava_2(thread); | 154 | return krava_2(thread); |
160 | } | 155 | } |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 7fad885491c5..812a053d1941 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -1810,17 +1810,6 @@ static int test_pmu_events(void) | |||
1810 | return ret; | 1810 | return ret; |
1811 | } | 1811 | } |
1812 | 1812 | ||
1813 | static void debug_warn(const char *warn, va_list params) | ||
1814 | { | ||
1815 | char msg[1024]; | ||
1816 | |||
1817 | if (verbose <= 0) | ||
1818 | return; | ||
1819 | |||
1820 | vsnprintf(msg, sizeof(msg), warn, params); | ||
1821 | fprintf(stderr, " Warning: %s\n", msg); | ||
1822 | } | ||
1823 | |||
1824 | int test__parse_events(int subtest __maybe_unused) | 1813 | int test__parse_events(int subtest __maybe_unused) |
1825 | { | 1814 | { |
1826 | int ret1, ret2 = 0; | 1815 | int ret1, ret2 = 0; |
@@ -1832,8 +1821,6 @@ do { \ | |||
1832 | ret2 = ret1; \ | 1821 | ret2 = ret1; \ |
1833 | } while (0) | 1822 | } while (0) |
1834 | 1823 | ||
1835 | set_warning_routine(debug_warn); | ||
1836 | |||
1837 | TEST_EVENTS(test__events); | 1824 | TEST_EVENTS(test__events); |
1838 | 1825 | ||
1839 | if (test_pmu()) | 1826 | if (test_pmu()) |
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 32873ec91a4e..cf00ebad2ef5 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c | |||
@@ -83,7 +83,7 @@ int test__task_exit(int subtest __maybe_unused) | |||
83 | 83 | ||
84 | evsel = perf_evlist__first(evlist); | 84 | evsel = perf_evlist__first(evlist); |
85 | evsel->attr.task = 1; | 85 | evsel->attr.task = 1; |
86 | evsel->attr.sample_freq = 0; | 86 | evsel->attr.sample_freq = 1; |
87 | evsel->attr.inherit = 0; | 87 | evsel->attr.inherit = 0; |
88 | evsel->attr.watermark = 0; | 88 | evsel->attr.watermark = 0; |
89 | evsel->attr.wakeup_events = 1; | 89 | evsel->attr.wakeup_events = 1; |
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 631859629403..577363809c9b 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -34,6 +34,7 @@ struct test { | |||
34 | int (*get_nr)(void); | 34 | int (*get_nr)(void); |
35 | const char *(*get_desc)(int subtest); | 35 | const char *(*get_desc)(int subtest); |
36 | } subtest; | 36 | } subtest; |
37 | bool (*is_supported)(void); | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | /* Tests */ | 40 | /* Tests */ |
@@ -99,6 +100,8 @@ const char *test__clang_subtest_get_desc(int subtest); | |||
99 | int test__clang_subtest_get_nr(void); | 100 | int test__clang_subtest_get_nr(void); |
100 | int test__unit_number__scnprint(int subtest); | 101 | int test__unit_number__scnprint(int subtest); |
101 | 102 | ||
103 | bool test__bp_signal_is_supported(void); | ||
104 | |||
102 | #if defined(__arm__) || defined(__aarch64__) | 105 | #if defined(__arm__) || defined(__aarch64__) |
103 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 106 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
104 | struct thread; | 107 | struct thread; |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d990ad08a3c6..27f41f28dcb4 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -46,12 +46,15 @@ static struct annotate_browser_opt { | |||
46 | .jump_arrows = true, | 46 | .jump_arrows = true, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | struct arch; | ||
50 | |||
49 | struct annotate_browser { | 51 | struct annotate_browser { |
50 | struct ui_browser b; | 52 | struct ui_browser b; |
51 | struct rb_root entries; | 53 | struct rb_root entries; |
52 | struct rb_node *curr_hot; | 54 | struct rb_node *curr_hot; |
53 | struct disasm_line *selection; | 55 | struct disasm_line *selection; |
54 | struct disasm_line **offsets; | 56 | struct disasm_line **offsets; |
57 | struct arch *arch; | ||
55 | int nr_events; | 58 | int nr_events; |
56 | u64 start; | 59 | u64 start; |
57 | int nr_asm_entries; | 60 | int nr_asm_entries; |
@@ -125,43 +128,57 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
125 | int i, pcnt_width = annotate_browser__pcnt_width(ab); | 128 | int i, pcnt_width = annotate_browser__pcnt_width(ab); |
126 | double percent_max = 0.0; | 129 | double percent_max = 0.0; |
127 | char bf[256]; | 130 | char bf[256]; |
131 | bool show_title = false; | ||
128 | 132 | ||
129 | for (i = 0; i < ab->nr_events; i++) { | 133 | for (i = 0; i < ab->nr_events; i++) { |
130 | if (bdl->samples[i].percent > percent_max) | 134 | if (bdl->samples[i].percent > percent_max) |
131 | percent_max = bdl->samples[i].percent; | 135 | percent_max = bdl->samples[i].percent; |
132 | } | 136 | } |
133 | 137 | ||
138 | if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) { | ||
139 | if (ab->have_cycles) { | ||
140 | if (dl->ipc == 0.0 && dl->cycles == 0) | ||
141 | show_title = true; | ||
142 | } else | ||
143 | show_title = true; | ||
144 | } | ||
145 | |||
134 | if (dl->offset != -1 && percent_max != 0.0) { | 146 | if (dl->offset != -1 && percent_max != 0.0) { |
135 | if (percent_max != 0.0) { | 147 | for (i = 0; i < ab->nr_events; i++) { |
136 | for (i = 0; i < ab->nr_events; i++) { | 148 | ui_browser__set_percent_color(browser, |
137 | ui_browser__set_percent_color(browser, | 149 | bdl->samples[i].percent, |
138 | bdl->samples[i].percent, | 150 | current_entry); |
139 | current_entry); | 151 | if (annotate_browser__opts.show_total_period) { |
140 | if (annotate_browser__opts.show_total_period) { | 152 | ui_browser__printf(browser, "%6" PRIu64 " ", |
141 | ui_browser__printf(browser, "%6" PRIu64 " ", | 153 | bdl->samples[i].nr); |
142 | bdl->samples[i].nr); | 154 | } else { |
143 | } else { | 155 | ui_browser__printf(browser, "%6.2f ", |
144 | ui_browser__printf(browser, "%6.2f ", | 156 | bdl->samples[i].percent); |
145 | bdl->samples[i].percent); | ||
146 | } | ||
147 | } | 157 | } |
148 | } else { | ||
149 | ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); | ||
150 | } | 158 | } |
151 | } else { | 159 | } else { |
152 | ui_browser__set_percent_color(browser, 0, current_entry); | 160 | ui_browser__set_percent_color(browser, 0, current_entry); |
153 | ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); | 161 | |
162 | if (!show_title) | ||
163 | ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); | ||
164 | else | ||
165 | ui_browser__printf(browser, "%*s", 7, "Percent"); | ||
154 | } | 166 | } |
155 | if (ab->have_cycles) { | 167 | if (ab->have_cycles) { |
156 | if (dl->ipc) | 168 | if (dl->ipc) |
157 | ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc); | 169 | ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc); |
158 | else | 170 | else if (!show_title) |
159 | ui_browser__write_nstring(browser, " ", IPC_WIDTH); | 171 | ui_browser__write_nstring(browser, " ", IPC_WIDTH); |
172 | else | ||
173 | ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC"); | ||
174 | |||
160 | if (dl->cycles) | 175 | if (dl->cycles) |
161 | ui_browser__printf(browser, "%*" PRIu64 " ", | 176 | ui_browser__printf(browser, "%*" PRIu64 " ", |
162 | CYCLES_WIDTH - 1, dl->cycles); | 177 | CYCLES_WIDTH - 1, dl->cycles); |
163 | else | 178 | else if (!show_title) |
164 | ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); | 179 | ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); |
180 | else | ||
181 | ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle"); | ||
165 | } | 182 | } |
166 | 183 | ||
167 | SLsmg_write_char(' '); | 184 | SLsmg_write_char(' '); |
@@ -1056,7 +1073,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, | |||
1056 | (nr_pcnt - 1); | 1073 | (nr_pcnt - 1); |
1057 | } | 1074 | } |
1058 | 1075 | ||
1059 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl); | 1076 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), |
1077 | sizeof_bdl, &browser.arch); | ||
1060 | if (err) { | 1078 | if (err) { |
1061 | char msg[BUFSIZ]; | 1079 | char msg[BUFSIZ]; |
1062 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); | 1080 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); |
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index e99ba86158d2..d903fd493416 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c | |||
@@ -168,7 +168,8 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, | |||
168 | if (map->dso->annotate_warned) | 168 | if (map->dso->annotate_warned) |
169 | return -1; | 169 | return -1; |
170 | 170 | ||
171 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0); | 171 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), |
172 | 0, NULL); | ||
172 | if (err) { | 173 | if (err) { |
173 | char msg[BUFSIZ]; | 174 | char msg[BUFSIZ]; |
174 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); | 175 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 59addd52d9cd..ddb2c6fbdf91 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -210,6 +210,8 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, | |||
210 | return 0; | 210 | return 0; |
211 | 211 | ||
212 | ret = b->callchain->max_depth - a->callchain->max_depth; | 212 | ret = b->callchain->max_depth - a->callchain->max_depth; |
213 | if (callchain_param.order == ORDER_CALLER) | ||
214 | ret = -ret; | ||
213 | } | 215 | } |
214 | return ret; | 216 | return ret; |
215 | } | 217 | } |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 683f8340460c..be1caabb9290 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -239,10 +239,20 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op | |||
239 | const char *s = strchr(ops->raw, '+'); | 239 | const char *s = strchr(ops->raw, '+'); |
240 | const char *c = strchr(ops->raw, ','); | 240 | const char *c = strchr(ops->raw, ','); |
241 | 241 | ||
242 | if (c++ != NULL) | 242 | /* |
243 | * skip over possible up to 2 operands to get to address, e.g.: | ||
244 | * tbnz w0, #26, ffff0000083cd190 <security_file_permission+0xd0> | ||
245 | */ | ||
246 | if (c++ != NULL) { | ||
243 | ops->target.addr = strtoull(c, NULL, 16); | 247 | ops->target.addr = strtoull(c, NULL, 16); |
244 | else | 248 | if (!ops->target.addr) { |
249 | c = strchr(c, ','); | ||
250 | if (c++ != NULL) | ||
251 | ops->target.addr = strtoull(c, NULL, 16); | ||
252 | } | ||
253 | } else { | ||
245 | ops->target.addr = strtoull(ops->raw, NULL, 16); | 254 | ops->target.addr = strtoull(ops->raw, NULL, 16); |
255 | } | ||
246 | 256 | ||
247 | if (s++ != NULL) { | 257 | if (s++ != NULL) { |
248 | ops->target.offset = strtoull(s, NULL, 16); | 258 | ops->target.offset = strtoull(s, NULL, 16); |
@@ -257,10 +267,27 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op | |||
257 | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, | 267 | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, |
258 | struct ins_operands *ops) | 268 | struct ins_operands *ops) |
259 | { | 269 | { |
270 | const char *c = strchr(ops->raw, ','); | ||
271 | |||
260 | if (!ops->target.addr || ops->target.offset < 0) | 272 | if (!ops->target.addr || ops->target.offset < 0) |
261 | return ins__raw_scnprintf(ins, bf, size, ops); | 273 | return ins__raw_scnprintf(ins, bf, size, ops); |
262 | 274 | ||
263 | return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); | 275 | if (c != NULL) { |
276 | const char *c2 = strchr(c + 1, ','); | ||
277 | |||
278 | /* check for 3-op insn */ | ||
279 | if (c2 != NULL) | ||
280 | c = c2; | ||
281 | c++; | ||
282 | |||
283 | /* mirror arch objdump's space-after-comma style */ | ||
284 | if (*c == ' ') | ||
285 | c++; | ||
286 | } | ||
287 | |||
288 | return scnprintf(bf, size, "%-6.6s %.*s%" PRIx64, | ||
289 | ins->name, c ? c - ops->raw : 0, ops->raw, | ||
290 | ops->target.offset); | ||
264 | } | 291 | } |
265 | 292 | ||
266 | static struct ins_ops jump_ops = { | 293 | static struct ins_ops jump_ops = { |
@@ -1294,6 +1321,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil | |||
1294 | char linkname[PATH_MAX]; | 1321 | char linkname[PATH_MAX]; |
1295 | char *build_id_filename; | 1322 | char *build_id_filename; |
1296 | char *build_id_path = NULL; | 1323 | char *build_id_path = NULL; |
1324 | char *pos; | ||
1297 | 1325 | ||
1298 | if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && | 1326 | if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && |
1299 | !dso__is_kcore(dso)) | 1327 | !dso__is_kcore(dso)) |
@@ -1313,7 +1341,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil | |||
1313 | if (!build_id_path) | 1341 | if (!build_id_path) |
1314 | return -1; | 1342 | return -1; |
1315 | 1343 | ||
1316 | dirname(build_id_path); | 1344 | /* |
1345 | * old style build-id cache has name of XX/XXXXXXX.. while | ||
1346 | * new style has XX/XXXXXXX../{elf,kallsyms,vdso}. | ||
1347 | * extract the build-id part of dirname in the new style only. | ||
1348 | */ | ||
1349 | pos = strrchr(build_id_path, '/'); | ||
1350 | if (pos && strlen(pos) < SBUILD_ID_SIZE - 2) | ||
1351 | dirname(build_id_path); | ||
1317 | 1352 | ||
1318 | if (dso__is_kcore(dso) || | 1353 | if (dso__is_kcore(dso) || |
1319 | readlink(build_id_path, linkname, sizeof(linkname)) < 0 || | 1354 | readlink(build_id_path, linkname, sizeof(linkname)) < 0 || |
@@ -1344,7 +1379,9 @@ static const char *annotate__norm_arch(const char *arch_name) | |||
1344 | return normalize_arch((char *)arch_name); | 1379 | return normalize_arch((char *)arch_name); |
1345 | } | 1380 | } |
1346 | 1381 | ||
1347 | int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize) | 1382 | int symbol__disassemble(struct symbol *sym, struct map *map, |
1383 | const char *arch_name, size_t privsize, | ||
1384 | struct arch **parch) | ||
1348 | { | 1385 | { |
1349 | struct dso *dso = map->dso; | 1386 | struct dso *dso = map->dso; |
1350 | char command[PATH_MAX * 2]; | 1387 | char command[PATH_MAX * 2]; |
@@ -1370,6 +1407,9 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na | |||
1370 | if (arch == NULL) | 1407 | if (arch == NULL) |
1371 | return -ENOTSUP; | 1408 | return -ENOTSUP; |
1372 | 1409 | ||
1410 | if (parch) | ||
1411 | *parch = arch; | ||
1412 | |||
1373 | if (arch->init) { | 1413 | if (arch->init) { |
1374 | err = arch->init(arch); | 1414 | err = arch->init(arch); |
1375 | if (err) { | 1415 | if (err) { |
@@ -1396,31 +1436,10 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na | |||
1396 | sizeof(symfs_filename)); | 1436 | sizeof(symfs_filename)); |
1397 | } | 1437 | } |
1398 | } else if (dso__needs_decompress(dso)) { | 1438 | } else if (dso__needs_decompress(dso)) { |
1399 | char tmp[PATH_MAX]; | 1439 | char tmp[KMOD_DECOMP_LEN]; |
1400 | struct kmod_path m; | ||
1401 | int fd; | ||
1402 | bool ret; | ||
1403 | |||
1404 | if (kmod_path__parse_ext(&m, symfs_filename)) | ||
1405 | goto out; | ||
1406 | |||
1407 | snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX"); | ||
1408 | |||
1409 | fd = mkstemp(tmp); | ||
1410 | if (fd < 0) { | ||
1411 | free(m.ext); | ||
1412 | goto out; | ||
1413 | } | ||
1414 | |||
1415 | ret = decompress_to_file(m.ext, symfs_filename, fd); | ||
1416 | |||
1417 | if (ret) | ||
1418 | pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename); | ||
1419 | |||
1420 | free(m.ext); | ||
1421 | close(fd); | ||
1422 | 1440 | ||
1423 | if (!ret) | 1441 | if (dso__decompress_kmodule_path(dso, symfs_filename, |
1442 | tmp, sizeof(tmp)) < 0) | ||
1424 | goto out; | 1443 | goto out; |
1425 | 1444 | ||
1426 | strcpy(symfs_filename, tmp); | 1445 | strcpy(symfs_filename, tmp); |
@@ -1429,7 +1448,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na | |||
1429 | snprintf(command, sizeof(command), | 1448 | snprintf(command, sizeof(command), |
1430 | "%s %s%s --start-address=0x%016" PRIx64 | 1449 | "%s %s%s --start-address=0x%016" PRIx64 |
1431 | " --stop-address=0x%016" PRIx64 | 1450 | " --stop-address=0x%016" PRIx64 |
1432 | " -l -d %s %s -C %s 2>/dev/null|grep -v %s:|expand", | 1451 | " -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand", |
1433 | objdump_path ? objdump_path : "objdump", | 1452 | objdump_path ? objdump_path : "objdump", |
1434 | disassembler_style ? "-M " : "", | 1453 | disassembler_style ? "-M " : "", |
1435 | disassembler_style ? disassembler_style : "", | 1454 | disassembler_style ? disassembler_style : "", |
@@ -1887,7 +1906,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1887 | struct rb_root source_line = RB_ROOT; | 1906 | struct rb_root source_line = RB_ROOT; |
1888 | u64 len; | 1907 | u64 len; |
1889 | 1908 | ||
1890 | if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0) < 0) | 1909 | if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), |
1910 | 0, NULL) < 0) | ||
1891 | return -1; | 1911 | return -1; |
1892 | 1912 | ||
1893 | len = symbol__size(sym); | 1913 | len = symbol__size(sym); |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 948aa8e6fd39..21055034aedd 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -158,7 +158,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | |||
158 | int symbol__alloc_hist(struct symbol *sym); | 158 | int symbol__alloc_hist(struct symbol *sym); |
159 | void symbol__annotate_zero_histograms(struct symbol *sym); | 159 | void symbol__annotate_zero_histograms(struct symbol *sym); |
160 | 160 | ||
161 | int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize); | 161 | int symbol__disassemble(struct symbol *sym, struct map *map, |
162 | const char *arch_name, size_t privsize, | ||
163 | struct arch **parch); | ||
162 | 164 | ||
163 | enum symbol_disassemble_errno { | 165 | enum symbol_disassemble_errno { |
164 | SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, | 166 | SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 0daf63b9ee3e..5547457566a7 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -322,6 +322,13 @@ static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues, | |||
322 | return auxtrace_queues__add_buffer(queues, idx, buffer); | 322 | return auxtrace_queues__add_buffer(queues, idx, buffer); |
323 | } | 323 | } |
324 | 324 | ||
325 | static bool filter_cpu(struct perf_session *session, int cpu) | ||
326 | { | ||
327 | unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; | ||
328 | |||
329 | return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); | ||
330 | } | ||
331 | |||
325 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, | 332 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, |
326 | struct perf_session *session, | 333 | struct perf_session *session, |
327 | union perf_event *event, off_t data_offset, | 334 | union perf_event *event, off_t data_offset, |
@@ -331,6 +338,9 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, | |||
331 | unsigned int idx; | 338 | unsigned int idx; |
332 | int err; | 339 | int err; |
333 | 340 | ||
341 | if (filter_cpu(session, event->auxtrace.cpu)) | ||
342 | return 0; | ||
343 | |||
334 | buffer = zalloc(sizeof(struct auxtrace_buffer)); | 344 | buffer = zalloc(sizeof(struct auxtrace_buffer)); |
335 | if (!buffer) | 345 | if (!buffer) |
336 | return -ENOMEM; | 346 | return -ENOMEM; |
@@ -947,6 +957,8 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) | |||
947 | synth_opts->instructions = true; | 957 | synth_opts->instructions = true; |
948 | synth_opts->branches = true; | 958 | synth_opts->branches = true; |
949 | synth_opts->transactions = true; | 959 | synth_opts->transactions = true; |
960 | synth_opts->ptwrites = true; | ||
961 | synth_opts->pwr_events = true; | ||
950 | synth_opts->errors = true; | 962 | synth_opts->errors = true; |
951 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; | 963 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; |
952 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | 964 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
@@ -1030,6 +1042,12 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, | |||
1030 | case 'x': | 1042 | case 'x': |
1031 | synth_opts->transactions = true; | 1043 | synth_opts->transactions = true; |
1032 | break; | 1044 | break; |
1045 | case 'w': | ||
1046 | synth_opts->ptwrites = true; | ||
1047 | break; | ||
1048 | case 'p': | ||
1049 | synth_opts->pwr_events = true; | ||
1050 | break; | ||
1033 | case 'e': | 1051 | case 'e': |
1034 | synth_opts->errors = true; | 1052 | synth_opts->errors = true; |
1035 | break; | 1053 | break; |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 9f0de72d58e2..33b5e6cdf38c 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -59,6 +59,8 @@ enum itrace_period_type { | |||
59 | * @instructions: whether to synthesize 'instructions' events | 59 | * @instructions: whether to synthesize 'instructions' events |
60 | * @branches: whether to synthesize 'branches' events | 60 | * @branches: whether to synthesize 'branches' events |
61 | * @transactions: whether to synthesize events for transactions | 61 | * @transactions: whether to synthesize events for transactions |
62 | * @ptwrites: whether to synthesize events for ptwrites | ||
63 | * @pwr_events: whether to synthesize power events | ||
62 | * @errors: whether to synthesize decoder error events | 64 | * @errors: whether to synthesize decoder error events |
63 | * @dont_decode: whether to skip decoding entirely | 65 | * @dont_decode: whether to skip decoding entirely |
64 | * @log: write a decoding log | 66 | * @log: write a decoding log |
@@ -72,6 +74,7 @@ enum itrace_period_type { | |||
72 | * @period: 'instructions' events period | 74 | * @period: 'instructions' events period |
73 | * @period_type: 'instructions' events period type | 75 | * @period_type: 'instructions' events period type |
74 | * @initial_skip: skip N events at the beginning. | 76 | * @initial_skip: skip N events at the beginning. |
77 | * @cpu_bitmap: CPUs for which to synthesize events, or NULL for all | ||
75 | */ | 78 | */ |
76 | struct itrace_synth_opts { | 79 | struct itrace_synth_opts { |
77 | bool set; | 80 | bool set; |
@@ -79,6 +82,8 @@ struct itrace_synth_opts { | |||
79 | bool instructions; | 82 | bool instructions; |
80 | bool branches; | 83 | bool branches; |
81 | bool transactions; | 84 | bool transactions; |
85 | bool ptwrites; | ||
86 | bool pwr_events; | ||
82 | bool errors; | 87 | bool errors; |
83 | bool dont_decode; | 88 | bool dont_decode; |
84 | bool log; | 89 | bool log; |
@@ -92,6 +97,7 @@ struct itrace_synth_opts { | |||
92 | unsigned long long period; | 97 | unsigned long long period; |
93 | enum itrace_period_type period_type; | 98 | enum itrace_period_type period_type; |
94 | unsigned long initial_skip; | 99 | unsigned long initial_skip; |
100 | unsigned long *cpu_bitmap; | ||
95 | }; | 101 | }; |
96 | 102 | ||
97 | /** | 103 | /** |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 168cc49654e7..e0148b081bdf 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -278,51 +278,6 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) | |||
278 | return bf; | 278 | return bf; |
279 | } | 279 | } |
280 | 280 | ||
281 | bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size) | ||
282 | { | ||
283 | char *id_name = NULL, *ch; | ||
284 | struct stat sb; | ||
285 | char sbuild_id[SBUILD_ID_SIZE]; | ||
286 | |||
287 | if (!dso->has_build_id) | ||
288 | goto err; | ||
289 | |||
290 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | ||
291 | id_name = build_id_cache__linkname(sbuild_id, NULL, 0); | ||
292 | if (!id_name) | ||
293 | goto err; | ||
294 | if (access(id_name, F_OK)) | ||
295 | goto err; | ||
296 | if (lstat(id_name, &sb) == -1) | ||
297 | goto err; | ||
298 | if ((size_t)sb.st_size > size - 1) | ||
299 | goto err; | ||
300 | if (readlink(id_name, bf, size - 1) < 0) | ||
301 | goto err; | ||
302 | |||
303 | bf[sb.st_size] = '\0'; | ||
304 | |||
305 | /* | ||
306 | * link should be: | ||
307 | * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92 | ||
308 | */ | ||
309 | ch = strrchr(bf, '/'); | ||
310 | if (!ch) | ||
311 | goto err; | ||
312 | if (ch - 3 < bf) | ||
313 | goto err; | ||
314 | |||
315 | free(id_name); | ||
316 | return strncmp(".ko", ch - 3, 3) == 0; | ||
317 | err: | ||
318 | pr_err("Invalid build id: %s\n", id_name ? : | ||
319 | dso->long_name ? : | ||
320 | dso->short_name ? : | ||
321 | "[unknown]"); | ||
322 | free(id_name); | ||
323 | return false; | ||
324 | } | ||
325 | |||
326 | #define dsos__for_each_with_build_id(pos, head) \ | 281 | #define dsos__for_each_with_build_id(pos, head) \ |
327 | list_for_each_entry(pos, head, node) \ | 282 | list_for_each_entry(pos, head, node) \ |
328 | if (!pos->has_build_id) \ | 283 | if (!pos->has_build_id) \ |
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 8a89b195c1fc..96690a55c62c 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h | |||
@@ -17,7 +17,6 @@ char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf, | |||
17 | size_t size); | 17 | size_t size); |
18 | 18 | ||
19 | char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); | 19 | char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); |
20 | bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size); | ||
21 | 20 | ||
22 | int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, | 21 | int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, |
23 | struct perf_sample *sample, struct perf_evsel *evsel, | 22 | struct perf_sample *sample, struct perf_evsel *evsel, |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 0328f297a748..0175765c05b9 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <subcmd/pager.h> | 5 | #include <subcmd/pager.h> |
6 | #include "../ui/ui.h" | 6 | #include "../ui/ui.h" |
7 | 7 | ||
8 | #include <linux/compiler.h> | ||
8 | #include <linux/string.h> | 9 | #include <linux/string.h> |
9 | 10 | ||
10 | #define CMD_EXEC_PATH "--exec-path" | 11 | #define CMD_EXEC_PATH "--exec-path" |
@@ -24,6 +25,6 @@ static inline int is_absolute_path(const char *path) | |||
24 | return path[0] == '/'; | 25 | return path[0] == '/'; |
25 | } | 26 | } |
26 | 27 | ||
27 | char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); | 28 | char *mkpath(const char *fmt, ...) __printf(1, 2); |
28 | 29 | ||
29 | #endif /* __PERF_CACHE_H */ | 30 | #endif /* __PERF_CACHE_H */ |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 81fc29ac798f..b4204b43ed58 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -621,14 +621,19 @@ enum match_result { | |||
621 | static enum match_result match_chain_srcline(struct callchain_cursor_node *node, | 621 | static enum match_result match_chain_srcline(struct callchain_cursor_node *node, |
622 | struct callchain_list *cnode) | 622 | struct callchain_list *cnode) |
623 | { | 623 | { |
624 | char *left = get_srcline(cnode->ms.map->dso, | 624 | char *left = NULL; |
625 | char *right = NULL; | ||
626 | enum match_result ret = MATCH_EQ; | ||
627 | int cmp; | ||
628 | |||
629 | if (cnode->ms.map) | ||
630 | left = get_srcline(cnode->ms.map->dso, | ||
625 | map__rip_2objdump(cnode->ms.map, cnode->ip), | 631 | map__rip_2objdump(cnode->ms.map, cnode->ip), |
626 | cnode->ms.sym, true, false); | 632 | cnode->ms.sym, true, false); |
627 | char *right = get_srcline(node->map->dso, | 633 | if (node->map) |
634 | right = get_srcline(node->map->dso, | ||
628 | map__rip_2objdump(node->map, node->ip), | 635 | map__rip_2objdump(node->map, node->ip), |
629 | node->sym, true, false); | 636 | node->sym, true, false); |
630 | enum match_result ret = MATCH_EQ; | ||
631 | int cmp; | ||
632 | 637 | ||
633 | if (left && right) | 638 | if (left && right) |
634 | cmp = strcmp(left, right); | 639 | cmp = strcmp(left, right); |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 8d724f0fa5a8..31a7dea248d0 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -335,32 +335,42 @@ static int perf_parse_long(const char *value, long *ret) | |||
335 | return 0; | 335 | return 0; |
336 | } | 336 | } |
337 | 337 | ||
338 | static void die_bad_config(const char *name) | 338 | static void bad_config(const char *name) |
339 | { | 339 | { |
340 | if (config_file_name) | 340 | if (config_file_name) |
341 | die("bad config value for '%s' in %s", name, config_file_name); | 341 | pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name); |
342 | die("bad config value for '%s'", name); | 342 | else |
343 | pr_warning("bad config value for '%s', ignoring...\n", name); | ||
343 | } | 344 | } |
344 | 345 | ||
345 | u64 perf_config_u64(const char *name, const char *value) | 346 | int perf_config_u64(u64 *dest, const char *name, const char *value) |
346 | { | 347 | { |
347 | long long ret = 0; | 348 | long long ret = 0; |
348 | 349 | ||
349 | if (!perf_parse_llong(value, &ret)) | 350 | if (!perf_parse_llong(value, &ret)) { |
350 | die_bad_config(name); | 351 | bad_config(name); |
351 | return (u64) ret; | 352 | return -1; |
353 | } | ||
354 | |||
355 | *dest = ret; | ||
356 | return 0; | ||
352 | } | 357 | } |
353 | 358 | ||
354 | int perf_config_int(const char *name, const char *value) | 359 | int perf_config_int(int *dest, const char *name, const char *value) |
355 | { | 360 | { |
356 | long ret = 0; | 361 | long ret = 0; |
357 | if (!perf_parse_long(value, &ret)) | 362 | if (!perf_parse_long(value, &ret)) { |
358 | die_bad_config(name); | 363 | bad_config(name); |
359 | return ret; | 364 | return -1; |
365 | } | ||
366 | *dest = ret; | ||
367 | return 0; | ||
360 | } | 368 | } |
361 | 369 | ||
362 | static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) | 370 | static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) |
363 | { | 371 | { |
372 | int ret; | ||
373 | |||
364 | *is_bool = 1; | 374 | *is_bool = 1; |
365 | if (!value) | 375 | if (!value) |
366 | return 1; | 376 | return 1; |
@@ -371,7 +381,7 @@ static int perf_config_bool_or_int(const char *name, const char *value, int *is_ | |||
371 | if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) | 381 | if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) |
372 | return 0; | 382 | return 0; |
373 | *is_bool = 0; | 383 | *is_bool = 0; |
374 | return perf_config_int(name, value); | 384 | return perf_config_int(&ret, name, value) < 0 ? -1 : ret; |
375 | } | 385 | } |
376 | 386 | ||
377 | int perf_config_bool(const char *name, const char *value) | 387 | int perf_config_bool(const char *name, const char *value) |
@@ -657,8 +667,7 @@ static int perf_config_set__init(struct perf_config_set *set) | |||
657 | 667 | ||
658 | user_config = strdup(mkpath("%s/.perfconfig", home)); | 668 | user_config = strdup(mkpath("%s/.perfconfig", home)); |
659 | if (user_config == NULL) { | 669 | if (user_config == NULL) { |
660 | warning("Not enough memory to process %s/.perfconfig, " | 670 | pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.", home); |
661 | "ignoring it.", home); | ||
662 | goto out; | 671 | goto out; |
663 | } | 672 | } |
664 | 673 | ||
@@ -671,8 +680,7 @@ static int perf_config_set__init(struct perf_config_set *set) | |||
671 | ret = 0; | 680 | ret = 0; |
672 | 681 | ||
673 | if (st.st_uid && (st.st_uid != geteuid())) { | 682 | if (st.st_uid && (st.st_uid != geteuid())) { |
674 | warning("File %s not owned by current user or root, " | 683 | pr_warning("File %s not owned by current user or root, ignoring it.", user_config); |
675 | "ignoring it.", user_config); | ||
676 | goto out_free; | 684 | goto out_free; |
677 | } | 685 | } |
678 | 686 | ||
@@ -795,7 +803,8 @@ void perf_config_set__delete(struct perf_config_set *set) | |||
795 | */ | 803 | */ |
796 | int config_error_nonbool(const char *var) | 804 | int config_error_nonbool(const char *var) |
797 | { | 805 | { |
798 | return error("Missing value for '%s'", var); | 806 | pr_err("Missing value for '%s'", var); |
807 | return -1; | ||
799 | } | 808 | } |
800 | 809 | ||
801 | void set_buildid_dir(const char *dir) | 810 | void set_buildid_dir(const char *dir) |
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 1a59a6b43f8b..b6bb11f3f165 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h | |||
@@ -27,8 +27,8 @@ extern const char *config_exclusive_filename; | |||
27 | typedef int (*config_fn_t)(const char *, const char *, void *); | 27 | typedef int (*config_fn_t)(const char *, const char *, void *); |
28 | int perf_default_config(const char *, const char *, void *); | 28 | int perf_default_config(const char *, const char *, void *); |
29 | int perf_config(config_fn_t fn, void *); | 29 | int perf_config(config_fn_t fn, void *); |
30 | int perf_config_int(const char *, const char *); | 30 | int perf_config_int(int *dest, const char *, const char *); |
31 | u64 perf_config_u64(const char *, const char *); | 31 | int perf_config_u64(u64 *dest, const char *, const char *); |
32 | int perf_config_bool(const char *, const char *); | 32 | int perf_config_bool(const char *, const char *); |
33 | int config_error_nonbool(const char *); | 33 | int config_error_nonbool(const char *); |
34 | const char *perf_etc_perfconfig(void); | 34 | const char *perf_etc_perfconfig(void); |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 89d50318833d..3149b70799fd 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
@@ -1444,10 +1444,8 @@ static int convert__config(const char *var, const char *value, void *cb) | |||
1444 | { | 1444 | { |
1445 | struct convert *c = cb; | 1445 | struct convert *c = cb; |
1446 | 1446 | ||
1447 | if (!strcmp(var, "convert.queue-size")) { | 1447 | if (!strcmp(var, "convert.queue-size")) |
1448 | c->queue_size = perf_config_u64(var, value); | 1448 | return perf_config_u64(&c->queue_size, var, value); |
1449 | return 0; | ||
1450 | } | ||
1451 | 1449 | ||
1452 | return 0; | 1450 | return 0; |
1453 | } | 1451 | } |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 8a23ea1a71c7..c818bdb1c1ab 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <linux/compiler.h> | ||
7 | #include "event.h" | 8 | #include "event.h" |
8 | #include "../ui/helpline.h" | 9 | #include "../ui/helpline.h" |
9 | #include "../ui/progress.h" | 10 | #include "../ui/progress.h" |
@@ -40,16 +41,16 @@ extern int debug_data_convert; | |||
40 | 41 | ||
41 | #define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ | 42 | #define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ |
42 | 43 | ||
43 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 44 | int dump_printf(const char *fmt, ...) __printf(1, 2); |
44 | void trace_event(union perf_event *event); | 45 | void trace_event(union perf_event *event); |
45 | 46 | ||
46 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 47 | int ui__error(const char *format, ...) __printf(1, 2); |
47 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 48 | int ui__warning(const char *format, ...) __printf(1, 2); |
48 | 49 | ||
49 | void pr_stat(const char *fmt, ...); | 50 | void pr_stat(const char *fmt, ...); |
50 | 51 | ||
51 | int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); | 52 | int eprintf(int level, int var, const char *fmt, ...) __printf(3, 4); |
52 | int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5))); | 53 | int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __printf(4, 5); |
53 | int veprintf(int level, int var, const char *fmt, va_list args); | 54 | int veprintf(int level, int var, const char *fmt, va_list args); |
54 | 55 | ||
55 | int perf_debug_option(const char *str); | 56 | int perf_debug_option(const char *str); |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index a96a99d2369f..4e7ab611377a 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -248,6 +248,64 @@ bool dso__needs_decompress(struct dso *dso) | |||
248 | dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; | 248 | dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; |
249 | } | 249 | } |
250 | 250 | ||
251 | static int decompress_kmodule(struct dso *dso, const char *name, char *tmpbuf) | ||
252 | { | ||
253 | int fd = -1; | ||
254 | struct kmod_path m; | ||
255 | |||
256 | if (!dso__needs_decompress(dso)) | ||
257 | return -1; | ||
258 | |||
259 | if (kmod_path__parse_ext(&m, dso->long_name)) | ||
260 | return -1; | ||
261 | |||
262 | if (!m.comp) | ||
263 | goto out; | ||
264 | |||
265 | fd = mkstemp(tmpbuf); | ||
266 | if (fd < 0) { | ||
267 | dso->load_errno = errno; | ||
268 | goto out; | ||
269 | } | ||
270 | |||
271 | if (!decompress_to_file(m.ext, name, fd)) { | ||
272 | dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE; | ||
273 | close(fd); | ||
274 | fd = -1; | ||
275 | } | ||
276 | |||
277 | out: | ||
278 | free(m.ext); | ||
279 | return fd; | ||
280 | } | ||
281 | |||
282 | int dso__decompress_kmodule_fd(struct dso *dso, const char *name) | ||
283 | { | ||
284 | char tmpbuf[] = KMOD_DECOMP_NAME; | ||
285 | int fd; | ||
286 | |||
287 | fd = decompress_kmodule(dso, name, tmpbuf); | ||
288 | unlink(tmpbuf); | ||
289 | return fd; | ||
290 | } | ||
291 | |||
292 | int dso__decompress_kmodule_path(struct dso *dso, const char *name, | ||
293 | char *pathname, size_t len) | ||
294 | { | ||
295 | char tmpbuf[] = KMOD_DECOMP_NAME; | ||
296 | int fd; | ||
297 | |||
298 | fd = decompress_kmodule(dso, name, tmpbuf); | ||
299 | if (fd < 0) { | ||
300 | unlink(tmpbuf); | ||
301 | return -1; | ||
302 | } | ||
303 | |||
304 | strncpy(pathname, tmpbuf, len); | ||
305 | close(fd); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
251 | /* | 309 | /* |
252 | * Parses kernel module specified in @path and updates | 310 | * Parses kernel module specified in @path and updates |
253 | * @m argument like: | 311 | * @m argument like: |
@@ -335,6 +393,21 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
335 | return 0; | 393 | return 0; |
336 | } | 394 | } |
337 | 395 | ||
396 | void dso__set_module_info(struct dso *dso, struct kmod_path *m, | ||
397 | struct machine *machine) | ||
398 | { | ||
399 | if (machine__is_host(machine)) | ||
400 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | ||
401 | else | ||
402 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | ||
403 | |||
404 | /* _KMODULE_COMP should be next to _KMODULE */ | ||
405 | if (m->kmod && m->comp) | ||
406 | dso->symtab_type++; | ||
407 | |||
408 | dso__set_short_name(dso, strdup(m->name), true); | ||
409 | } | ||
410 | |||
338 | /* | 411 | /* |
339 | * Global list of open DSOs and the counter. | 412 | * Global list of open DSOs and the counter. |
340 | */ | 413 | */ |
@@ -381,7 +454,7 @@ static int do_open(char *name) | |||
381 | 454 | ||
382 | static int __open_dso(struct dso *dso, struct machine *machine) | 455 | static int __open_dso(struct dso *dso, struct machine *machine) |
383 | { | 456 | { |
384 | int fd; | 457 | int fd = -EINVAL; |
385 | char *root_dir = (char *)""; | 458 | char *root_dir = (char *)""; |
386 | char *name = malloc(PATH_MAX); | 459 | char *name = malloc(PATH_MAX); |
387 | 460 | ||
@@ -392,15 +465,30 @@ static int __open_dso(struct dso *dso, struct machine *machine) | |||
392 | root_dir = machine->root_dir; | 465 | root_dir = machine->root_dir; |
393 | 466 | ||
394 | if (dso__read_binary_type_filename(dso, dso->binary_type, | 467 | if (dso__read_binary_type_filename(dso, dso->binary_type, |
395 | root_dir, name, PATH_MAX)) { | 468 | root_dir, name, PATH_MAX)) |
396 | free(name); | 469 | goto out; |
397 | return -EINVAL; | ||
398 | } | ||
399 | 470 | ||
400 | if (!is_regular_file(name)) | 471 | if (!is_regular_file(name)) |
401 | return -EINVAL; | 472 | goto out; |
473 | |||
474 | if (dso__needs_decompress(dso)) { | ||
475 | char newpath[KMOD_DECOMP_LEN]; | ||
476 | size_t len = sizeof(newpath); | ||
477 | |||
478 | if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) { | ||
479 | fd = -dso->load_errno; | ||
480 | goto out; | ||
481 | } | ||
482 | |||
483 | strcpy(name, newpath); | ||
484 | } | ||
402 | 485 | ||
403 | fd = do_open(name); | 486 | fd = do_open(name); |
487 | |||
488 | if (dso__needs_decompress(dso)) | ||
489 | unlink(name); | ||
490 | |||
491 | out: | ||
404 | free(name); | 492 | free(name); |
405 | return fd; | 493 | return fd; |
406 | } | 494 | } |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 12350b171727..bd061ba7b47c 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -244,6 +244,12 @@ bool is_supported_compression(const char *ext); | |||
244 | bool is_kernel_module(const char *pathname, int cpumode); | 244 | bool is_kernel_module(const char *pathname, int cpumode); |
245 | bool decompress_to_file(const char *ext, const char *filename, int output_fd); | 245 | bool decompress_to_file(const char *ext, const char *filename, int output_fd); |
246 | bool dso__needs_decompress(struct dso *dso); | 246 | bool dso__needs_decompress(struct dso *dso); |
247 | int dso__decompress_kmodule_fd(struct dso *dso, const char *name); | ||
248 | int dso__decompress_kmodule_path(struct dso *dso, const char *name, | ||
249 | char *pathname, size_t len); | ||
250 | |||
251 | #define KMOD_DECOMP_NAME "/tmp/perf-kmod-XXXXXX" | ||
252 | #define KMOD_DECOMP_LEN sizeof(KMOD_DECOMP_NAME) | ||
247 | 253 | ||
248 | struct kmod_path { | 254 | struct kmod_path { |
249 | char *name; | 255 | char *name; |
@@ -259,6 +265,9 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
259 | #define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false) | 265 | #define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false) |
260 | #define kmod_path__parse_ext(__m, __p) __kmod_path__parse(__m, __p, false, true) | 266 | #define kmod_path__parse_ext(__m, __p) __kmod_path__parse(__m, __p, false, true) |
261 | 267 | ||
268 | void dso__set_module_info(struct dso *dso, struct kmod_path *m, | ||
269 | struct machine *machine); | ||
270 | |||
262 | /* | 271 | /* |
263 | * The dso__data_* external interface provides following functions: | 272 | * The dso__data_* external interface provides following functions: |
264 | * dso__data_get_fd | 273 | * dso__data_get_fd |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 7c3fa1c8cbcd..9967c87af7a6 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -252,6 +252,127 @@ enum auxtrace_error_type { | |||
252 | PERF_AUXTRACE_ERROR_MAX | 252 | PERF_AUXTRACE_ERROR_MAX |
253 | }; | 253 | }; |
254 | 254 | ||
255 | /* Attribute type for custom synthesized events */ | ||
256 | #define PERF_TYPE_SYNTH (INT_MAX + 1U) | ||
257 | |||
258 | /* Attribute config for custom synthesized events */ | ||
259 | enum perf_synth_id { | ||
260 | PERF_SYNTH_INTEL_PTWRITE, | ||
261 | PERF_SYNTH_INTEL_MWAIT, | ||
262 | PERF_SYNTH_INTEL_PWRE, | ||
263 | PERF_SYNTH_INTEL_EXSTOP, | ||
264 | PERF_SYNTH_INTEL_PWRX, | ||
265 | PERF_SYNTH_INTEL_CBR, | ||
266 | }; | ||
267 | |||
268 | /* | ||
269 | * Raw data formats for synthesized events. Note that 4 bytes of padding are | ||
270 | * present to match the 'size' member of PERF_SAMPLE_RAW data which is always | ||
271 | * 8-byte aligned. That means we must dereference raw_data with an offset of 4. | ||
272 | * Refer perf_sample__synth_ptr() and perf_synth__raw_data(). It also means the | ||
273 | * structure sizes are 4 bytes bigger than the raw_size, refer | ||
274 | * perf_synth__raw_size(). | ||
275 | */ | ||
276 | |||
277 | struct perf_synth_intel_ptwrite { | ||
278 | u32 padding; | ||
279 | union { | ||
280 | struct { | ||
281 | u32 ip : 1, | ||
282 | reserved : 31; | ||
283 | }; | ||
284 | u32 flags; | ||
285 | }; | ||
286 | u64 payload; | ||
287 | }; | ||
288 | |||
289 | struct perf_synth_intel_mwait { | ||
290 | u32 padding; | ||
291 | u32 reserved; | ||
292 | union { | ||
293 | struct { | ||
294 | u64 hints : 8, | ||
295 | reserved1 : 24, | ||
296 | extensions : 2, | ||
297 | reserved2 : 30; | ||
298 | }; | ||
299 | u64 payload; | ||
300 | }; | ||
301 | }; | ||
302 | |||
303 | struct perf_synth_intel_pwre { | ||
304 | u32 padding; | ||
305 | u32 reserved; | ||
306 | union { | ||
307 | struct { | ||
308 | u64 reserved1 : 7, | ||
309 | hw : 1, | ||
310 | subcstate : 4, | ||
311 | cstate : 4, | ||
312 | reserved2 : 48; | ||
313 | }; | ||
314 | u64 payload; | ||
315 | }; | ||
316 | }; | ||
317 | |||
318 | struct perf_synth_intel_exstop { | ||
319 | u32 padding; | ||
320 | union { | ||
321 | struct { | ||
322 | u32 ip : 1, | ||
323 | reserved : 31; | ||
324 | }; | ||
325 | u32 flags; | ||
326 | }; | ||
327 | }; | ||
328 | |||
329 | struct perf_synth_intel_pwrx { | ||
330 | u32 padding; | ||
331 | u32 reserved; | ||
332 | union { | ||
333 | struct { | ||
334 | u64 deepest_cstate : 4, | ||
335 | last_cstate : 4, | ||
336 | wake_reason : 4, | ||
337 | reserved1 : 52; | ||
338 | }; | ||
339 | u64 payload; | ||
340 | }; | ||
341 | }; | ||
342 | |||
343 | struct perf_synth_intel_cbr { | ||
344 | u32 padding; | ||
345 | union { | ||
346 | struct { | ||
347 | u32 cbr : 8, | ||
348 | reserved1 : 8, | ||
349 | max_nonturbo : 8, | ||
350 | reserved2 : 8; | ||
351 | }; | ||
352 | u32 flags; | ||
353 | }; | ||
354 | u32 freq; | ||
355 | u32 reserved3; | ||
356 | }; | ||
357 | |||
358 | /* | ||
359 | * raw_data is always 4 bytes from an 8-byte boundary, so subtract 4 to get | ||
360 | * 8-byte alignment. | ||
361 | */ | ||
362 | static inline void *perf_sample__synth_ptr(struct perf_sample *sample) | ||
363 | { | ||
364 | return sample->raw_data - 4; | ||
365 | } | ||
366 | |||
367 | static inline void *perf_synth__raw_data(void *p) | ||
368 | { | ||
369 | return p + 4; | ||
370 | } | ||
371 | |||
372 | #define perf_synth__raw_size(d) (sizeof(d) - 4) | ||
373 | |||
374 | #define perf_sample__bad_synth_size(s, d) ((s)->raw_size < sizeof(d) - 4) | ||
375 | |||
255 | /* | 376 | /* |
256 | * The kernel collects the number of events it couldn't send in a stretch and | 377 | * The kernel collects the number of events it couldn't send in a stretch and |
257 | * when possible sends this number in a PERF_RECORD_LOST event. The number of | 378 | * when possible sends this number in a PERF_RECORD_LOST event. The number of |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 94cea4398a13..8d601fbdd8d6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef __PERF_EVLIST_H | 1 | #ifndef __PERF_EVLIST_H |
2 | #define __PERF_EVLIST_H 1 | 2 | #define __PERF_EVLIST_H 1 |
3 | 3 | ||
4 | #include <linux/compiler.h> | ||
4 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
5 | #include <linux/refcount.h> | 6 | #include <linux/refcount.h> |
6 | #include <linux/list.h> | 7 | #include <linux/list.h> |
@@ -34,7 +35,7 @@ struct perf_mmap { | |||
34 | refcount_t refcnt; | 35 | refcount_t refcnt; |
35 | u64 prev; | 36 | u64 prev; |
36 | struct auxtrace_mmap auxtrace_mmap; | 37 | struct auxtrace_mmap auxtrace_mmap; |
37 | char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); | 38 | char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); |
38 | }; | 39 | }; |
39 | 40 | ||
40 | static inline size_t | 41 | static inline size_t |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e4f7902d5afa..6f4882f8d61f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -11,13 +11,17 @@ | |||
11 | #include <errno.h> | 11 | #include <errno.h> |
12 | #include <inttypes.h> | 12 | #include <inttypes.h> |
13 | #include <linux/bitops.h> | 13 | #include <linux/bitops.h> |
14 | #include <api/fs/fs.h> | ||
14 | #include <api/fs/tracing_path.h> | 15 | #include <api/fs/tracing_path.h> |
15 | #include <traceevent/event-parse.h> | 16 | #include <traceevent/event-parse.h> |
16 | #include <linux/hw_breakpoint.h> | 17 | #include <linux/hw_breakpoint.h> |
17 | #include <linux/perf_event.h> | 18 | #include <linux/perf_event.h> |
19 | #include <linux/compiler.h> | ||
18 | #include <linux/err.h> | 20 | #include <linux/err.h> |
19 | #include <sys/ioctl.h> | 21 | #include <sys/ioctl.h> |
20 | #include <sys/resource.h> | 22 | #include <sys/resource.h> |
23 | #include <sys/types.h> | ||
24 | #include <dirent.h> | ||
21 | #include "asm/bug.h" | 25 | #include "asm/bug.h" |
22 | #include "callchain.h" | 26 | #include "callchain.h" |
23 | #include "cgroup.h" | 27 | #include "cgroup.h" |
@@ -273,8 +277,20 @@ struct perf_evsel *perf_evsel__new_cycles(void) | |||
273 | struct perf_evsel *evsel; | 277 | struct perf_evsel *evsel; |
274 | 278 | ||
275 | event_attr_init(&attr); | 279 | event_attr_init(&attr); |
280 | /* | ||
281 | * Unnamed union member, not supported as struct member named | ||
282 | * initializer in older compilers such as gcc 4.4.7 | ||
283 | * | ||
284 | * Just for probing the precise_ip: | ||
285 | */ | ||
286 | attr.sample_period = 1; | ||
276 | 287 | ||
277 | perf_event_attr__set_max_precise_ip(&attr); | 288 | perf_event_attr__set_max_precise_ip(&attr); |
289 | /* | ||
290 | * Now let the usual logic to set up the perf_event_attr defaults | ||
291 | * to kick in when we return and before perf_evsel__open() is called. | ||
292 | */ | ||
293 | attr.sample_period = 0; | ||
278 | 294 | ||
279 | evsel = perf_evsel__new(&attr); | 295 | evsel = perf_evsel__new(&attr); |
280 | if (evsel == NULL) | 296 | if (evsel == NULL) |
@@ -1429,7 +1445,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | |||
1429 | } | 1445 | } |
1430 | 1446 | ||
1431 | static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, | 1447 | static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, |
1432 | void *priv __attribute__((unused))) | 1448 | void *priv __maybe_unused) |
1433 | { | 1449 | { |
1434 | return fprintf(fp, " %-32s %s\n", name, val); | 1450 | return fprintf(fp, " %-32s %s\n", name, val); |
1435 | } | 1451 | } |
@@ -2459,6 +2475,42 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | |||
2459 | return false; | 2475 | return false; |
2460 | } | 2476 | } |
2461 | 2477 | ||
2478 | static bool find_process(const char *name) | ||
2479 | { | ||
2480 | size_t len = strlen(name); | ||
2481 | DIR *dir; | ||
2482 | struct dirent *d; | ||
2483 | int ret = -1; | ||
2484 | |||
2485 | dir = opendir(procfs__mountpoint()); | ||
2486 | if (!dir) | ||
2487 | return false; | ||
2488 | |||
2489 | /* Walk through the directory. */ | ||
2490 | while (ret && (d = readdir(dir)) != NULL) { | ||
2491 | char path[PATH_MAX]; | ||
2492 | char *data; | ||
2493 | size_t size; | ||
2494 | |||
2495 | if ((d->d_type != DT_DIR) || | ||
2496 | !strcmp(".", d->d_name) || | ||
2497 | !strcmp("..", d->d_name)) | ||
2498 | continue; | ||
2499 | |||
2500 | scnprintf(path, sizeof(path), "%s/%s/comm", | ||
2501 | procfs__mountpoint(), d->d_name); | ||
2502 | |||
2503 | if (filename__read_str(path, &data, &size)) | ||
2504 | continue; | ||
2505 | |||
2506 | ret = strncmp(name, data, len); | ||
2507 | free(data); | ||
2508 | } | ||
2509 | |||
2510 | closedir(dir); | ||
2511 | return ret ? false : true; | ||
2512 | } | ||
2513 | |||
2462 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | 2514 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, |
2463 | int err, char *msg, size_t size) | 2515 | int err, char *msg, size_t size) |
2464 | { | 2516 | { |
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index e415aee6a245..583f3a602506 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "map.h" | 7 | #include "map.h" |
8 | #include "strlist.h" | 8 | #include "strlist.h" |
9 | #include "symbol.h" | 9 | #include "symbol.h" |
10 | #include "srcline.h" | ||
10 | 11 | ||
11 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | 12 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) |
12 | { | 13 | { |
@@ -168,6 +169,38 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, | |||
168 | if (!print_oneline) | 169 | if (!print_oneline) |
169 | printed += fprintf(fp, "\n"); | 170 | printed += fprintf(fp, "\n"); |
170 | 171 | ||
172 | if (symbol_conf.inline_name && node->map) { | ||
173 | struct inline_node *inode; | ||
174 | |||
175 | addr = map__rip_2objdump(node->map, node->ip), | ||
176 | inode = dso__parse_addr_inlines(node->map->dso, addr); | ||
177 | |||
178 | if (inode) { | ||
179 | struct inline_list *ilist; | ||
180 | |||
181 | list_for_each_entry(ilist, &inode->val, list) { | ||
182 | if (print_arrow) | ||
183 | printed += fprintf(fp, " <-"); | ||
184 | |||
185 | /* IP is same, just skip it */ | ||
186 | if (print_ip) | ||
187 | printed += fprintf(fp, "%c%16s", | ||
188 | s, ""); | ||
189 | if (print_sym) | ||
190 | printed += fprintf(fp, " %s", | ||
191 | ilist->funcname); | ||
192 | if (print_srcline) | ||
193 | printed += fprintf(fp, "\n %s:%d", | ||
194 | ilist->filename, | ||
195 | ilist->line_nr); | ||
196 | if (!print_oneline) | ||
197 | printed += fprintf(fp, "\n"); | ||
198 | } | ||
199 | |||
200 | inline_node__delete(inode); | ||
201 | } | ||
202 | } | ||
203 | |||
171 | if (symbol_conf.bt_stop_list && | 204 | if (symbol_conf.bt_stop_list && |
172 | node->sym && | 205 | node->sym && |
173 | strlist__has_entry(symbol_conf.bt_stop_list, | 206 | strlist__has_entry(symbol_conf.bt_stop_list, |
diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c index 5980f7d256b1..40789d8603d0 100644 --- a/tools/perf/util/genelf_debug.c +++ b/tools/perf/util/genelf_debug.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * @remark Copyright 2007 OProfile authors | 11 | * @remark Copyright 2007 OProfile authors |
12 | * @author Philippe Elie | 12 | * @author Philippe Elie |
13 | */ | 13 | */ |
14 | #include <linux/compiler.h> | ||
14 | #include <sys/types.h> | 15 | #include <sys/types.h> |
15 | #include <stdio.h> | 16 | #include <stdio.h> |
16 | #include <getopt.h> | 17 | #include <getopt.h> |
@@ -125,7 +126,7 @@ struct debug_line_header { | |||
125 | * and filesize, last entry is followed by en empty string. | 126 | * and filesize, last entry is followed by en empty string. |
126 | */ | 127 | */ |
127 | /* follow the first program statement */ | 128 | /* follow the first program statement */ |
128 | } __attribute__((packed)); | 129 | } __packed; |
129 | 130 | ||
130 | /* DWARF 2 spec talk only about one possible compilation unit header while | 131 | /* DWARF 2 spec talk only about one possible compilation unit header while |
131 | * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not | 132 | * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not |
@@ -138,7 +139,7 @@ struct compilation_unit_header { | |||
138 | uhalf version; | 139 | uhalf version; |
139 | uword debug_abbrev_offset; | 140 | uword debug_abbrev_offset; |
140 | ubyte pointer_size; | 141 | ubyte pointer_size; |
141 | } __attribute__((packed)); | 142 | } __packed; |
142 | 143 | ||
143 | #define DW_LNS_num_opcode (DW_LNS_set_isa + 1) | 144 | #define DW_LNS_num_opcode (DW_LNS_set_isa + 1) |
144 | 145 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 314a07151fb7..76ed7d03e500 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <unistd.h> | 8 | #include <unistd.h> |
9 | #include <stdio.h> | 9 | #include <stdio.h> |
10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
11 | #include <linux/compiler.h> | ||
11 | #include <linux/list.h> | 12 | #include <linux/list.h> |
12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
13 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
@@ -841,7 +842,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused, | |||
841 | 842 | ||
842 | /* | 843 | /* |
843 | * default get_cpuid(): nothing gets recorded | 844 | * default get_cpuid(): nothing gets recorded |
844 | * actual implementation must be in arch/$(ARCH)/util/header.c | 845 | * actual implementation must be in arch/$(SRCARCH)/util/header.c |
845 | */ | 846 | */ |
846 | int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) | 847 | int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) |
847 | { | 848 | { |
@@ -1274,7 +1275,7 @@ error: | |||
1274 | } | 1275 | } |
1275 | 1276 | ||
1276 | static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, | 1277 | static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, |
1277 | void *priv __attribute__((unused))) | 1278 | void *priv __maybe_unused) |
1278 | { | 1279 | { |
1279 | return fprintf(fp, ", %s = %s", name, val); | 1280 | return fprintf(fp, ", %s = %s", name, val); |
1280 | } | 1281 | } |
@@ -1469,8 +1470,16 @@ static int __event_process_build_id(struct build_id_event *bev, | |||
1469 | 1470 | ||
1470 | dso__set_build_id(dso, &bev->build_id); | 1471 | dso__set_build_id(dso, &bev->build_id); |
1471 | 1472 | ||
1472 | if (!is_kernel_module(filename, cpumode)) | 1473 | if (dso_type != DSO_TYPE_USER) { |
1473 | dso->kernel = dso_type; | 1474 | struct kmod_path m = { .name = NULL, }; |
1475 | |||
1476 | if (!kmod_path__parse_name(&m, filename) && m.kmod) | ||
1477 | dso__set_module_info(dso, &m, machine); | ||
1478 | else | ||
1479 | dso->kernel = dso_type; | ||
1480 | |||
1481 | free(m.name); | ||
1482 | } | ||
1474 | 1483 | ||
1475 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), | 1484 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), |
1476 | sbuild_id); | 1485 | sbuild_id); |
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index 1c88ad6425b8..15b95300d7f3 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c | |||
@@ -12,7 +12,7 @@ static int perf_unknown_cmd_config(const char *var, const char *value, | |||
12 | void *cb __maybe_unused) | 12 | void *cb __maybe_unused) |
13 | { | 13 | { |
14 | if (!strcmp(var, "help.autocorrect")) | 14 | if (!strcmp(var, "help.autocorrect")) |
15 | autocorrect = perf_config_int(var,value); | 15 | return perf_config_int(&autocorrect, var,value); |
16 | 16 | ||
17 | return 0; | 17 | return 0; |
18 | } | 18 | } |
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index b2834ac7b1f5..218ee2bac9a5 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c | |||
@@ -866,8 +866,6 @@ static void intel_bts_print_info(u64 *arr, int start, int finish) | |||
866 | fprintf(stdout, intel_bts_info_fmts[i], arr[i]); | 866 | fprintf(stdout, intel_bts_info_fmts[i], arr[i]); |
867 | } | 867 | } |
868 | 868 | ||
869 | u64 intel_bts_auxtrace_info_priv[INTEL_BTS_AUXTRACE_PRIV_SIZE]; | ||
870 | |||
871 | int intel_bts_process_auxtrace_info(union perf_event *event, | 869 | int intel_bts_process_auxtrace_info(union perf_event *event, |
872 | struct perf_session *session) | 870 | struct perf_session *session) |
873 | { | 871 | { |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 7cf7f7aca4d2..aa1593ce551d 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
@@ -64,6 +64,25 @@ enum intel_pt_pkt_state { | |||
64 | INTEL_PT_STATE_FUP_NO_TIP, | 64 | INTEL_PT_STATE_FUP_NO_TIP, |
65 | }; | 65 | }; |
66 | 66 | ||
67 | static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state) | ||
68 | { | ||
69 | switch (pkt_state) { | ||
70 | case INTEL_PT_STATE_NO_PSB: | ||
71 | case INTEL_PT_STATE_NO_IP: | ||
72 | case INTEL_PT_STATE_ERR_RESYNC: | ||
73 | case INTEL_PT_STATE_IN_SYNC: | ||
74 | case INTEL_PT_STATE_TNT: | ||
75 | return true; | ||
76 | case INTEL_PT_STATE_TIP: | ||
77 | case INTEL_PT_STATE_TIP_PGD: | ||
78 | case INTEL_PT_STATE_FUP: | ||
79 | case INTEL_PT_STATE_FUP_NO_TIP: | ||
80 | return false; | ||
81 | default: | ||
82 | return true; | ||
83 | }; | ||
84 | } | ||
85 | |||
67 | #ifdef INTEL_PT_STRICT | 86 | #ifdef INTEL_PT_STRICT |
68 | #define INTEL_PT_STATE_ERR1 INTEL_PT_STATE_NO_PSB | 87 | #define INTEL_PT_STATE_ERR1 INTEL_PT_STATE_NO_PSB |
69 | #define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_PSB | 88 | #define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_PSB |
@@ -87,11 +106,13 @@ struct intel_pt_decoder { | |||
87 | const unsigned char *buf; | 106 | const unsigned char *buf; |
88 | size_t len; | 107 | size_t len; |
89 | bool return_compression; | 108 | bool return_compression; |
109 | bool branch_enable; | ||
90 | bool mtc_insn; | 110 | bool mtc_insn; |
91 | bool pge; | 111 | bool pge; |
92 | bool have_tma; | 112 | bool have_tma; |
93 | bool have_cyc; | 113 | bool have_cyc; |
94 | bool fixup_last_mtc; | 114 | bool fixup_last_mtc; |
115 | bool have_last_ip; | ||
95 | uint64_t pos; | 116 | uint64_t pos; |
96 | uint64_t last_ip; | 117 | uint64_t last_ip; |
97 | uint64_t ip; | 118 | uint64_t ip; |
@@ -99,6 +120,7 @@ struct intel_pt_decoder { | |||
99 | uint64_t timestamp; | 120 | uint64_t timestamp; |
100 | uint64_t tsc_timestamp; | 121 | uint64_t tsc_timestamp; |
101 | uint64_t ref_timestamp; | 122 | uint64_t ref_timestamp; |
123 | uint64_t sample_timestamp; | ||
102 | uint64_t ret_addr; | 124 | uint64_t ret_addr; |
103 | uint64_t ctc_timestamp; | 125 | uint64_t ctc_timestamp; |
104 | uint64_t ctc_delta; | 126 | uint64_t ctc_delta; |
@@ -119,6 +141,7 @@ struct intel_pt_decoder { | |||
119 | int pkt_len; | 141 | int pkt_len; |
120 | int last_packet_type; | 142 | int last_packet_type; |
121 | unsigned int cbr; | 143 | unsigned int cbr; |
144 | unsigned int cbr_seen; | ||
122 | unsigned int max_non_turbo_ratio; | 145 | unsigned int max_non_turbo_ratio; |
123 | double max_non_turbo_ratio_fp; | 146 | double max_non_turbo_ratio_fp; |
124 | double cbr_cyc_to_tsc; | 147 | double cbr_cyc_to_tsc; |
@@ -136,9 +159,18 @@ struct intel_pt_decoder { | |||
136 | bool continuous_period; | 159 | bool continuous_period; |
137 | bool overflow; | 160 | bool overflow; |
138 | bool set_fup_tx_flags; | 161 | bool set_fup_tx_flags; |
162 | bool set_fup_ptw; | ||
163 | bool set_fup_mwait; | ||
164 | bool set_fup_pwre; | ||
165 | bool set_fup_exstop; | ||
139 | unsigned int fup_tx_flags; | 166 | unsigned int fup_tx_flags; |
140 | unsigned int tx_flags; | 167 | unsigned int tx_flags; |
168 | uint64_t fup_ptw_payload; | ||
169 | uint64_t fup_mwait_payload; | ||
170 | uint64_t fup_pwre_payload; | ||
171 | uint64_t cbr_payload; | ||
141 | uint64_t timestamp_insn_cnt; | 172 | uint64_t timestamp_insn_cnt; |
173 | uint64_t sample_insn_cnt; | ||
142 | uint64_t stuck_ip; | 174 | uint64_t stuck_ip; |
143 | int no_progress; | 175 | int no_progress; |
144 | int stuck_ip_prd; | 176 | int stuck_ip_prd; |
@@ -192,6 +224,7 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) | |||
192 | decoder->pgd_ip = params->pgd_ip; | 224 | decoder->pgd_ip = params->pgd_ip; |
193 | decoder->data = params->data; | 225 | decoder->data = params->data; |
194 | decoder->return_compression = params->return_compression; | 226 | decoder->return_compression = params->return_compression; |
227 | decoder->branch_enable = params->branch_enable; | ||
195 | 228 | ||
196 | decoder->period = params->period; | 229 | decoder->period = params->period; |
197 | decoder->period_type = params->period_type; | 230 | decoder->period_type = params->period_type; |
@@ -398,6 +431,7 @@ static uint64_t intel_pt_calc_ip(const struct intel_pt_pkt *packet, | |||
398 | static inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder) | 431 | static inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder) |
399 | { | 432 | { |
400 | decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip); | 433 | decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip); |
434 | decoder->have_last_ip = true; | ||
401 | } | 435 | } |
402 | 436 | ||
403 | static inline void intel_pt_set_ip(struct intel_pt_decoder *decoder) | 437 | static inline void intel_pt_set_ip(struct intel_pt_decoder *decoder) |
@@ -635,6 +669,8 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) | |||
635 | case INTEL_PT_PAD: | 669 | case INTEL_PT_PAD: |
636 | case INTEL_PT_VMCS: | 670 | case INTEL_PT_VMCS: |
637 | case INTEL_PT_MNT: | 671 | case INTEL_PT_MNT: |
672 | case INTEL_PT_PTWRITE: | ||
673 | case INTEL_PT_PTWRITE_IP: | ||
638 | return 0; | 674 | return 0; |
639 | 675 | ||
640 | case INTEL_PT_MTC: | 676 | case INTEL_PT_MTC: |
@@ -675,6 +711,12 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) | |||
675 | break; | 711 | break; |
676 | 712 | ||
677 | case INTEL_PT_TSC: | 713 | case INTEL_PT_TSC: |
714 | /* | ||
715 | * For now, do not support using TSC packets - refer | ||
716 | * intel_pt_calc_cyc_to_tsc(). | ||
717 | */ | ||
718 | if (data->from_mtc) | ||
719 | return 1; | ||
678 | timestamp = pkt_info->packet.payload | | 720 | timestamp = pkt_info->packet.payload | |
679 | (data->timestamp & (0xffULL << 56)); | 721 | (data->timestamp & (0xffULL << 56)); |
680 | if (data->from_mtc && timestamp < data->timestamp && | 722 | if (data->from_mtc && timestamp < data->timestamp && |
@@ -733,6 +775,11 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) | |||
733 | 775 | ||
734 | case INTEL_PT_TIP_PGD: | 776 | case INTEL_PT_TIP_PGD: |
735 | case INTEL_PT_TRACESTOP: | 777 | case INTEL_PT_TRACESTOP: |
778 | case INTEL_PT_EXSTOP: | ||
779 | case INTEL_PT_EXSTOP_IP: | ||
780 | case INTEL_PT_MWAIT: | ||
781 | case INTEL_PT_PWRE: | ||
782 | case INTEL_PT_PWRX: | ||
736 | case INTEL_PT_OVF: | 783 | case INTEL_PT_OVF: |
737 | case INTEL_PT_BAD: /* Does not happen */ | 784 | case INTEL_PT_BAD: /* Does not happen */ |
738 | default: | 785 | default: |
@@ -787,6 +834,14 @@ static void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder, | |||
787 | .cbr_cyc_to_tsc = 0, | 834 | .cbr_cyc_to_tsc = 0, |
788 | }; | 835 | }; |
789 | 836 | ||
837 | /* | ||
838 | * For now, do not support using TSC packets for at least the reasons: | ||
839 | * 1) timing might have stopped | ||
840 | * 2) TSC packets within PSB+ can slip against CYC packets | ||
841 | */ | ||
842 | if (!from_mtc) | ||
843 | return; | ||
844 | |||
790 | intel_pt_pkt_lookahead(decoder, intel_pt_calc_cyc_cb, &data); | 845 | intel_pt_pkt_lookahead(decoder, intel_pt_calc_cyc_cb, &data); |
791 | } | 846 | } |
792 | 847 | ||
@@ -898,6 +953,7 @@ static int intel_pt_walk_insn(struct intel_pt_decoder *decoder, | |||
898 | 953 | ||
899 | decoder->tot_insn_cnt += insn_cnt; | 954 | decoder->tot_insn_cnt += insn_cnt; |
900 | decoder->timestamp_insn_cnt += insn_cnt; | 955 | decoder->timestamp_insn_cnt += insn_cnt; |
956 | decoder->sample_insn_cnt += insn_cnt; | ||
901 | decoder->period_insn_cnt += insn_cnt; | 957 | decoder->period_insn_cnt += insn_cnt; |
902 | 958 | ||
903 | if (err) { | 959 | if (err) { |
@@ -990,6 +1046,57 @@ out_no_progress: | |||
990 | return err; | 1046 | return err; |
991 | } | 1047 | } |
992 | 1048 | ||
1049 | static bool intel_pt_fup_event(struct intel_pt_decoder *decoder) | ||
1050 | { | ||
1051 | bool ret = false; | ||
1052 | |||
1053 | if (decoder->set_fup_tx_flags) { | ||
1054 | decoder->set_fup_tx_flags = false; | ||
1055 | decoder->tx_flags = decoder->fup_tx_flags; | ||
1056 | decoder->state.type = INTEL_PT_TRANSACTION; | ||
1057 | decoder->state.from_ip = decoder->ip; | ||
1058 | decoder->state.to_ip = 0; | ||
1059 | decoder->state.flags = decoder->fup_tx_flags; | ||
1060 | return true; | ||
1061 | } | ||
1062 | if (decoder->set_fup_ptw) { | ||
1063 | decoder->set_fup_ptw = false; | ||
1064 | decoder->state.type = INTEL_PT_PTW; | ||
1065 | decoder->state.flags |= INTEL_PT_FUP_IP; | ||
1066 | decoder->state.from_ip = decoder->ip; | ||
1067 | decoder->state.to_ip = 0; | ||
1068 | decoder->state.ptw_payload = decoder->fup_ptw_payload; | ||
1069 | return true; | ||
1070 | } | ||
1071 | if (decoder->set_fup_mwait) { | ||
1072 | decoder->set_fup_mwait = false; | ||
1073 | decoder->state.type = INTEL_PT_MWAIT_OP; | ||
1074 | decoder->state.from_ip = decoder->ip; | ||
1075 | decoder->state.to_ip = 0; | ||
1076 | decoder->state.mwait_payload = decoder->fup_mwait_payload; | ||
1077 | ret = true; | ||
1078 | } | ||
1079 | if (decoder->set_fup_pwre) { | ||
1080 | decoder->set_fup_pwre = false; | ||
1081 | decoder->state.type |= INTEL_PT_PWR_ENTRY; | ||
1082 | decoder->state.type &= ~INTEL_PT_BRANCH; | ||
1083 | decoder->state.from_ip = decoder->ip; | ||
1084 | decoder->state.to_ip = 0; | ||
1085 | decoder->state.pwre_payload = decoder->fup_pwre_payload; | ||
1086 | ret = true; | ||
1087 | } | ||
1088 | if (decoder->set_fup_exstop) { | ||
1089 | decoder->set_fup_exstop = false; | ||
1090 | decoder->state.type |= INTEL_PT_EX_STOP; | ||
1091 | decoder->state.type &= ~INTEL_PT_BRANCH; | ||
1092 | decoder->state.flags |= INTEL_PT_FUP_IP; | ||
1093 | decoder->state.from_ip = decoder->ip; | ||
1094 | decoder->state.to_ip = 0; | ||
1095 | ret = true; | ||
1096 | } | ||
1097 | return ret; | ||
1098 | } | ||
1099 | |||
993 | static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) | 1100 | static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) |
994 | { | 1101 | { |
995 | struct intel_pt_insn intel_pt_insn; | 1102 | struct intel_pt_insn intel_pt_insn; |
@@ -1003,15 +1110,8 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) | |||
1003 | if (err == INTEL_PT_RETURN) | 1110 | if (err == INTEL_PT_RETURN) |
1004 | return 0; | 1111 | return 0; |
1005 | if (err == -EAGAIN) { | 1112 | if (err == -EAGAIN) { |
1006 | if (decoder->set_fup_tx_flags) { | 1113 | if (intel_pt_fup_event(decoder)) |
1007 | decoder->set_fup_tx_flags = false; | ||
1008 | decoder->tx_flags = decoder->fup_tx_flags; | ||
1009 | decoder->state.type = INTEL_PT_TRANSACTION; | ||
1010 | decoder->state.from_ip = decoder->ip; | ||
1011 | decoder->state.to_ip = 0; | ||
1012 | decoder->state.flags = decoder->fup_tx_flags; | ||
1013 | return 0; | 1114 | return 0; |
1014 | } | ||
1015 | return err; | 1115 | return err; |
1016 | } | 1116 | } |
1017 | decoder->set_fup_tx_flags = false; | 1117 | decoder->set_fup_tx_flags = false; |
@@ -1360,7 +1460,9 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder) | |||
1360 | 1460 | ||
1361 | static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) | 1461 | static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) |
1362 | { | 1462 | { |
1363 | unsigned int cbr = decoder->packet.payload; | 1463 | unsigned int cbr = decoder->packet.payload & 0xff; |
1464 | |||
1465 | decoder->cbr_payload = decoder->packet.payload; | ||
1364 | 1466 | ||
1365 | if (decoder->cbr == cbr) | 1467 | if (decoder->cbr == cbr) |
1366 | return; | 1468 | return; |
@@ -1417,6 +1519,13 @@ static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder) | |||
1417 | case INTEL_PT_TRACESTOP: | 1519 | case INTEL_PT_TRACESTOP: |
1418 | case INTEL_PT_BAD: | 1520 | case INTEL_PT_BAD: |
1419 | case INTEL_PT_PSB: | 1521 | case INTEL_PT_PSB: |
1522 | case INTEL_PT_PTWRITE: | ||
1523 | case INTEL_PT_PTWRITE_IP: | ||
1524 | case INTEL_PT_EXSTOP: | ||
1525 | case INTEL_PT_EXSTOP_IP: | ||
1526 | case INTEL_PT_MWAIT: | ||
1527 | case INTEL_PT_PWRE: | ||
1528 | case INTEL_PT_PWRX: | ||
1420 | decoder->have_tma = false; | 1529 | decoder->have_tma = false; |
1421 | intel_pt_log("ERROR: Unexpected packet\n"); | 1530 | intel_pt_log("ERROR: Unexpected packet\n"); |
1422 | return -EAGAIN; | 1531 | return -EAGAIN; |
@@ -1446,7 +1555,8 @@ static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder) | |||
1446 | 1555 | ||
1447 | case INTEL_PT_FUP: | 1556 | case INTEL_PT_FUP: |
1448 | decoder->pge = true; | 1557 | decoder->pge = true; |
1449 | intel_pt_set_last_ip(decoder); | 1558 | if (decoder->packet.count) |
1559 | intel_pt_set_last_ip(decoder); | ||
1450 | break; | 1560 | break; |
1451 | 1561 | ||
1452 | case INTEL_PT_MODE_TSX: | 1562 | case INTEL_PT_MODE_TSX: |
@@ -1497,6 +1607,13 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) | |||
1497 | case INTEL_PT_MODE_TSX: | 1607 | case INTEL_PT_MODE_TSX: |
1498 | case INTEL_PT_BAD: | 1608 | case INTEL_PT_BAD: |
1499 | case INTEL_PT_PSBEND: | 1609 | case INTEL_PT_PSBEND: |
1610 | case INTEL_PT_PTWRITE: | ||
1611 | case INTEL_PT_PTWRITE_IP: | ||
1612 | case INTEL_PT_EXSTOP: | ||
1613 | case INTEL_PT_EXSTOP_IP: | ||
1614 | case INTEL_PT_MWAIT: | ||
1615 | case INTEL_PT_PWRE: | ||
1616 | case INTEL_PT_PWRX: | ||
1500 | intel_pt_log("ERROR: Missing TIP after FUP\n"); | 1617 | intel_pt_log("ERROR: Missing TIP after FUP\n"); |
1501 | decoder->pkt_state = INTEL_PT_STATE_ERR3; | 1618 | decoder->pkt_state = INTEL_PT_STATE_ERR3; |
1502 | return -ENOENT; | 1619 | return -ENOENT; |
@@ -1625,6 +1742,15 @@ next: | |||
1625 | break; | 1742 | break; |
1626 | } | 1743 | } |
1627 | intel_pt_set_last_ip(decoder); | 1744 | intel_pt_set_last_ip(decoder); |
1745 | if (!decoder->branch_enable) { | ||
1746 | decoder->ip = decoder->last_ip; | ||
1747 | if (intel_pt_fup_event(decoder)) | ||
1748 | return 0; | ||
1749 | no_tip = false; | ||
1750 | break; | ||
1751 | } | ||
1752 | if (decoder->set_fup_mwait) | ||
1753 | no_tip = true; | ||
1628 | err = intel_pt_walk_fup(decoder); | 1754 | err = intel_pt_walk_fup(decoder); |
1629 | if (err != -EAGAIN) { | 1755 | if (err != -EAGAIN) { |
1630 | if (err) | 1756 | if (err) |
@@ -1650,6 +1776,8 @@ next: | |||
1650 | break; | 1776 | break; |
1651 | 1777 | ||
1652 | case INTEL_PT_PSB: | 1778 | case INTEL_PT_PSB: |
1779 | decoder->last_ip = 0; | ||
1780 | decoder->have_last_ip = true; | ||
1653 | intel_pt_clear_stack(&decoder->stack); | 1781 | intel_pt_clear_stack(&decoder->stack); |
1654 | err = intel_pt_walk_psbend(decoder); | 1782 | err = intel_pt_walk_psbend(decoder); |
1655 | if (err == -EAGAIN) | 1783 | if (err == -EAGAIN) |
@@ -1696,6 +1824,16 @@ next: | |||
1696 | 1824 | ||
1697 | case INTEL_PT_CBR: | 1825 | case INTEL_PT_CBR: |
1698 | intel_pt_calc_cbr(decoder); | 1826 | intel_pt_calc_cbr(decoder); |
1827 | if (!decoder->branch_enable && | ||
1828 | decoder->cbr != decoder->cbr_seen) { | ||
1829 | decoder->cbr_seen = decoder->cbr; | ||
1830 | decoder->state.type = INTEL_PT_CBR_CHG; | ||
1831 | decoder->state.from_ip = decoder->ip; | ||
1832 | decoder->state.to_ip = 0; | ||
1833 | decoder->state.cbr_payload = | ||
1834 | decoder->packet.payload; | ||
1835 | return 0; | ||
1836 | } | ||
1699 | break; | 1837 | break; |
1700 | 1838 | ||
1701 | case INTEL_PT_MODE_EXEC: | 1839 | case INTEL_PT_MODE_EXEC: |
@@ -1722,6 +1860,71 @@ next: | |||
1722 | case INTEL_PT_PAD: | 1860 | case INTEL_PT_PAD: |
1723 | break; | 1861 | break; |
1724 | 1862 | ||
1863 | case INTEL_PT_PTWRITE_IP: | ||
1864 | decoder->fup_ptw_payload = decoder->packet.payload; | ||
1865 | err = intel_pt_get_next_packet(decoder); | ||
1866 | if (err) | ||
1867 | return err; | ||
1868 | if (decoder->packet.type == INTEL_PT_FUP) { | ||
1869 | decoder->set_fup_ptw = true; | ||
1870 | no_tip = true; | ||
1871 | } else { | ||
1872 | intel_pt_log_at("ERROR: Missing FUP after PTWRITE", | ||
1873 | decoder->pos); | ||
1874 | } | ||
1875 | goto next; | ||
1876 | |||
1877 | case INTEL_PT_PTWRITE: | ||
1878 | decoder->state.type = INTEL_PT_PTW; | ||
1879 | decoder->state.from_ip = decoder->ip; | ||
1880 | decoder->state.to_ip = 0; | ||
1881 | decoder->state.ptw_payload = decoder->packet.payload; | ||
1882 | return 0; | ||
1883 | |||
1884 | case INTEL_PT_MWAIT: | ||
1885 | decoder->fup_mwait_payload = decoder->packet.payload; | ||
1886 | decoder->set_fup_mwait = true; | ||
1887 | break; | ||
1888 | |||
1889 | case INTEL_PT_PWRE: | ||
1890 | if (decoder->set_fup_mwait) { | ||
1891 | decoder->fup_pwre_payload = | ||
1892 | decoder->packet.payload; | ||
1893 | decoder->set_fup_pwre = true; | ||
1894 | break; | ||
1895 | } | ||
1896 | decoder->state.type = INTEL_PT_PWR_ENTRY; | ||
1897 | decoder->state.from_ip = decoder->ip; | ||
1898 | decoder->state.to_ip = 0; | ||
1899 | decoder->state.pwrx_payload = decoder->packet.payload; | ||
1900 | return 0; | ||
1901 | |||
1902 | case INTEL_PT_EXSTOP_IP: | ||
1903 | err = intel_pt_get_next_packet(decoder); | ||
1904 | if (err) | ||
1905 | return err; | ||
1906 | if (decoder->packet.type == INTEL_PT_FUP) { | ||
1907 | decoder->set_fup_exstop = true; | ||
1908 | no_tip = true; | ||
1909 | } else { | ||
1910 | intel_pt_log_at("ERROR: Missing FUP after EXSTOP", | ||
1911 | decoder->pos); | ||
1912 | } | ||
1913 | goto next; | ||
1914 | |||
1915 | case INTEL_PT_EXSTOP: | ||
1916 | decoder->state.type = INTEL_PT_EX_STOP; | ||
1917 | decoder->state.from_ip = decoder->ip; | ||
1918 | decoder->state.to_ip = 0; | ||
1919 | return 0; | ||
1920 | |||
1921 | case INTEL_PT_PWRX: | ||
1922 | decoder->state.type = INTEL_PT_PWR_EXIT; | ||
1923 | decoder->state.from_ip = decoder->ip; | ||
1924 | decoder->state.to_ip = 0; | ||
1925 | decoder->state.pwrx_payload = decoder->packet.payload; | ||
1926 | return 0; | ||
1927 | |||
1725 | default: | 1928 | default: |
1726 | return intel_pt_bug(decoder); | 1929 | return intel_pt_bug(decoder); |
1727 | } | 1930 | } |
@@ -1730,8 +1933,9 @@ next: | |||
1730 | 1933 | ||
1731 | static inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder) | 1934 | static inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder) |
1732 | { | 1935 | { |
1733 | return decoder->last_ip || decoder->packet.count == 0 || | 1936 | return decoder->packet.count && |
1734 | decoder->packet.count == 3 || decoder->packet.count == 6; | 1937 | (decoder->have_last_ip || decoder->packet.count == 3 || |
1938 | decoder->packet.count == 6); | ||
1735 | } | 1939 | } |
1736 | 1940 | ||
1737 | /* Walk PSB+ packets to get in sync. */ | 1941 | /* Walk PSB+ packets to get in sync. */ |
@@ -1750,6 +1954,13 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder) | |||
1750 | __fallthrough; | 1954 | __fallthrough; |
1751 | case INTEL_PT_TIP_PGE: | 1955 | case INTEL_PT_TIP_PGE: |
1752 | case INTEL_PT_TIP: | 1956 | case INTEL_PT_TIP: |
1957 | case INTEL_PT_PTWRITE: | ||
1958 | case INTEL_PT_PTWRITE_IP: | ||
1959 | case INTEL_PT_EXSTOP: | ||
1960 | case INTEL_PT_EXSTOP_IP: | ||
1961 | case INTEL_PT_MWAIT: | ||
1962 | case INTEL_PT_PWRE: | ||
1963 | case INTEL_PT_PWRX: | ||
1753 | intel_pt_log("ERROR: Unexpected packet\n"); | 1964 | intel_pt_log("ERROR: Unexpected packet\n"); |
1754 | return -ENOENT; | 1965 | return -ENOENT; |
1755 | 1966 | ||
@@ -1854,14 +2065,10 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) | |||
1854 | break; | 2065 | break; |
1855 | 2066 | ||
1856 | case INTEL_PT_FUP: | 2067 | case INTEL_PT_FUP: |
1857 | if (decoder->overflow) { | 2068 | if (intel_pt_have_ip(decoder)) |
1858 | if (intel_pt_have_ip(decoder)) | 2069 | intel_pt_set_ip(decoder); |
1859 | intel_pt_set_ip(decoder); | 2070 | if (decoder->ip) |
1860 | if (decoder->ip) | 2071 | return 0; |
1861 | return 0; | ||
1862 | } | ||
1863 | if (decoder->packet.count) | ||
1864 | intel_pt_set_last_ip(decoder); | ||
1865 | break; | 2072 | break; |
1866 | 2073 | ||
1867 | case INTEL_PT_MTC: | 2074 | case INTEL_PT_MTC: |
@@ -1910,6 +2117,9 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) | |||
1910 | break; | 2117 | break; |
1911 | 2118 | ||
1912 | case INTEL_PT_PSB: | 2119 | case INTEL_PT_PSB: |
2120 | decoder->last_ip = 0; | ||
2121 | decoder->have_last_ip = true; | ||
2122 | intel_pt_clear_stack(&decoder->stack); | ||
1913 | err = intel_pt_walk_psb(decoder); | 2123 | err = intel_pt_walk_psb(decoder); |
1914 | if (err) | 2124 | if (err) |
1915 | return err; | 2125 | return err; |
@@ -1925,6 +2135,13 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) | |||
1925 | case INTEL_PT_VMCS: | 2135 | case INTEL_PT_VMCS: |
1926 | case INTEL_PT_MNT: | 2136 | case INTEL_PT_MNT: |
1927 | case INTEL_PT_PAD: | 2137 | case INTEL_PT_PAD: |
2138 | case INTEL_PT_PTWRITE: | ||
2139 | case INTEL_PT_PTWRITE_IP: | ||
2140 | case INTEL_PT_EXSTOP: | ||
2141 | case INTEL_PT_EXSTOP_IP: | ||
2142 | case INTEL_PT_MWAIT: | ||
2143 | case INTEL_PT_PWRE: | ||
2144 | case INTEL_PT_PWRX: | ||
1928 | default: | 2145 | default: |
1929 | break; | 2146 | break; |
1930 | } | 2147 | } |
@@ -1935,6 +2152,19 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder) | |||
1935 | { | 2152 | { |
1936 | int err; | 2153 | int err; |
1937 | 2154 | ||
2155 | decoder->set_fup_tx_flags = false; | ||
2156 | decoder->set_fup_ptw = false; | ||
2157 | decoder->set_fup_mwait = false; | ||
2158 | decoder->set_fup_pwre = false; | ||
2159 | decoder->set_fup_exstop = false; | ||
2160 | |||
2161 | if (!decoder->branch_enable) { | ||
2162 | decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; | ||
2163 | decoder->overflow = false; | ||
2164 | decoder->state.type = 0; /* Do not have a sample */ | ||
2165 | return 0; | ||
2166 | } | ||
2167 | |||
1938 | intel_pt_log("Scanning for full IP\n"); | 2168 | intel_pt_log("Scanning for full IP\n"); |
1939 | err = intel_pt_walk_to_ip(decoder); | 2169 | err = intel_pt_walk_to_ip(decoder); |
1940 | if (err) | 2170 | if (err) |
@@ -2043,6 +2273,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) | |||
2043 | 2273 | ||
2044 | decoder->pge = false; | 2274 | decoder->pge = false; |
2045 | decoder->continuous_period = false; | 2275 | decoder->continuous_period = false; |
2276 | decoder->have_last_ip = false; | ||
2046 | decoder->last_ip = 0; | 2277 | decoder->last_ip = 0; |
2047 | decoder->ip = 0; | 2278 | decoder->ip = 0; |
2048 | intel_pt_clear_stack(&decoder->stack); | 2279 | intel_pt_clear_stack(&decoder->stack); |
@@ -2051,6 +2282,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) | |||
2051 | if (err) | 2282 | if (err) |
2052 | return err; | 2283 | return err; |
2053 | 2284 | ||
2285 | decoder->have_last_ip = true; | ||
2054 | decoder->pkt_state = INTEL_PT_STATE_NO_IP; | 2286 | decoder->pkt_state = INTEL_PT_STATE_NO_IP; |
2055 | 2287 | ||
2056 | err = intel_pt_walk_psb(decoder); | 2288 | err = intel_pt_walk_psb(decoder); |
@@ -2069,7 +2301,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) | |||
2069 | 2301 | ||
2070 | static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) | 2302 | static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) |
2071 | { | 2303 | { |
2072 | uint64_t est = decoder->timestamp_insn_cnt << 1; | 2304 | uint64_t est = decoder->sample_insn_cnt << 1; |
2073 | 2305 | ||
2074 | if (!decoder->cbr || !decoder->max_non_turbo_ratio) | 2306 | if (!decoder->cbr || !decoder->max_non_turbo_ratio) |
2075 | goto out; | 2307 | goto out; |
@@ -2077,7 +2309,7 @@ static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) | |||
2077 | est *= decoder->max_non_turbo_ratio; | 2309 | est *= decoder->max_non_turbo_ratio; |
2078 | est /= decoder->cbr; | 2310 | est /= decoder->cbr; |
2079 | out: | 2311 | out: |
2080 | return decoder->timestamp + est; | 2312 | return decoder->sample_timestamp + est; |
2081 | } | 2313 | } |
2082 | 2314 | ||
2083 | const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) | 2315 | const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) |
@@ -2093,8 +2325,10 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) | |||
2093 | err = intel_pt_sync(decoder); | 2325 | err = intel_pt_sync(decoder); |
2094 | break; | 2326 | break; |
2095 | case INTEL_PT_STATE_NO_IP: | 2327 | case INTEL_PT_STATE_NO_IP: |
2328 | decoder->have_last_ip = false; | ||
2096 | decoder->last_ip = 0; | 2329 | decoder->last_ip = 0; |
2097 | /* Fall through */ | 2330 | decoder->ip = 0; |
2331 | __fallthrough; | ||
2098 | case INTEL_PT_STATE_ERR_RESYNC: | 2332 | case INTEL_PT_STATE_ERR_RESYNC: |
2099 | err = intel_pt_sync_ip(decoder); | 2333 | err = intel_pt_sync_ip(decoder); |
2100 | break; | 2334 | break; |
@@ -2130,15 +2364,29 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) | |||
2130 | } | 2364 | } |
2131 | } while (err == -ENOLINK); | 2365 | } while (err == -ENOLINK); |
2132 | 2366 | ||
2133 | decoder->state.err = err ? intel_pt_ext_err(err) : 0; | 2367 | if (err) { |
2134 | decoder->state.timestamp = decoder->timestamp; | 2368 | decoder->state.err = intel_pt_ext_err(err); |
2369 | decoder->state.from_ip = decoder->ip; | ||
2370 | decoder->sample_timestamp = decoder->timestamp; | ||
2371 | decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; | ||
2372 | } else { | ||
2373 | decoder->state.err = 0; | ||
2374 | if (decoder->cbr != decoder->cbr_seen && decoder->state.type) { | ||
2375 | decoder->cbr_seen = decoder->cbr; | ||
2376 | decoder->state.type |= INTEL_PT_CBR_CHG; | ||
2377 | decoder->state.cbr_payload = decoder->cbr_payload; | ||
2378 | } | ||
2379 | if (intel_pt_sample_time(decoder->pkt_state)) { | ||
2380 | decoder->sample_timestamp = decoder->timestamp; | ||
2381 | decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; | ||
2382 | } | ||
2383 | } | ||
2384 | |||
2385 | decoder->state.timestamp = decoder->sample_timestamp; | ||
2135 | decoder->state.est_timestamp = intel_pt_est_timestamp(decoder); | 2386 | decoder->state.est_timestamp = intel_pt_est_timestamp(decoder); |
2136 | decoder->state.cr3 = decoder->cr3; | 2387 | decoder->state.cr3 = decoder->cr3; |
2137 | decoder->state.tot_insn_cnt = decoder->tot_insn_cnt; | 2388 | decoder->state.tot_insn_cnt = decoder->tot_insn_cnt; |
2138 | 2389 | ||
2139 | if (err) | ||
2140 | decoder->state.from_ip = decoder->ip; | ||
2141 | |||
2142 | return &decoder->state; | 2390 | return &decoder->state; |
2143 | } | 2391 | } |
2144 | 2392 | ||
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index e90619a43c0c..921b22e8ca0e 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h | |||
@@ -25,11 +25,18 @@ | |||
25 | #define INTEL_PT_IN_TX (1 << 0) | 25 | #define INTEL_PT_IN_TX (1 << 0) |
26 | #define INTEL_PT_ABORT_TX (1 << 1) | 26 | #define INTEL_PT_ABORT_TX (1 << 1) |
27 | #define INTEL_PT_ASYNC (1 << 2) | 27 | #define INTEL_PT_ASYNC (1 << 2) |
28 | #define INTEL_PT_FUP_IP (1 << 3) | ||
28 | 29 | ||
29 | enum intel_pt_sample_type { | 30 | enum intel_pt_sample_type { |
30 | INTEL_PT_BRANCH = 1 << 0, | 31 | INTEL_PT_BRANCH = 1 << 0, |
31 | INTEL_PT_INSTRUCTION = 1 << 1, | 32 | INTEL_PT_INSTRUCTION = 1 << 1, |
32 | INTEL_PT_TRANSACTION = 1 << 2, | 33 | INTEL_PT_TRANSACTION = 1 << 2, |
34 | INTEL_PT_PTW = 1 << 3, | ||
35 | INTEL_PT_MWAIT_OP = 1 << 4, | ||
36 | INTEL_PT_PWR_ENTRY = 1 << 5, | ||
37 | INTEL_PT_EX_STOP = 1 << 6, | ||
38 | INTEL_PT_PWR_EXIT = 1 << 7, | ||
39 | INTEL_PT_CBR_CHG = 1 << 8, | ||
33 | }; | 40 | }; |
34 | 41 | ||
35 | enum intel_pt_period_type { | 42 | enum intel_pt_period_type { |
@@ -63,6 +70,11 @@ struct intel_pt_state { | |||
63 | uint64_t timestamp; | 70 | uint64_t timestamp; |
64 | uint64_t est_timestamp; | 71 | uint64_t est_timestamp; |
65 | uint64_t trace_nr; | 72 | uint64_t trace_nr; |
73 | uint64_t ptw_payload; | ||
74 | uint64_t mwait_payload; | ||
75 | uint64_t pwre_payload; | ||
76 | uint64_t pwrx_payload; | ||
77 | uint64_t cbr_payload; | ||
66 | uint32_t flags; | 78 | uint32_t flags; |
67 | enum intel_pt_insn_op insn_op; | 79 | enum intel_pt_insn_op insn_op; |
68 | int insn_len; | 80 | int insn_len; |
@@ -87,6 +99,7 @@ struct intel_pt_params { | |||
87 | bool (*pgd_ip)(uint64_t ip, void *data); | 99 | bool (*pgd_ip)(uint64_t ip, void *data); |
88 | void *data; | 100 | void *data; |
89 | bool return_compression; | 101 | bool return_compression; |
102 | bool branch_enable; | ||
90 | uint64_t period; | 103 | uint64_t period; |
91 | enum intel_pt_period_type period_type; | 104 | enum intel_pt_period_type period_type; |
92 | unsigned max_non_turbo_ratio; | 105 | unsigned max_non_turbo_ratio; |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.h b/tools/perf/util/intel-pt-decoder/intel-pt-log.h index debe751dc3d6..45b64f93f358 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-log.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #ifndef INCLUDE__INTEL_PT_LOG_H__ | 16 | #ifndef INCLUDE__INTEL_PT_LOG_H__ |
17 | #define INCLUDE__INTEL_PT_LOG_H__ | 17 | #define INCLUDE__INTEL_PT_LOG_H__ |
18 | 18 | ||
19 | #include <linux/compiler.h> | ||
19 | #include <stdint.h> | 20 | #include <stdint.h> |
20 | #include <inttypes.h> | 21 | #include <inttypes.h> |
21 | 22 | ||
@@ -34,8 +35,7 @@ void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip); | |||
34 | void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, | 35 | void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, |
35 | uint64_t ip); | 36 | uint64_t ip); |
36 | 37 | ||
37 | __attribute__((format(printf, 1, 2))) | 38 | void __intel_pt_log(const char *fmt, ...) __printf(1, 2); |
38 | void __intel_pt_log(const char *fmt, ...); | ||
39 | 39 | ||
40 | #define intel_pt_log(fmt, ...) \ | 40 | #define intel_pt_log(fmt, ...) \ |
41 | do { \ | 41 | do { \ |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index 7528ae4f7e28..ba4c9dd18643 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | |||
@@ -64,6 +64,13 @@ static const char * const packet_name[] = { | |||
64 | [INTEL_PT_PIP] = "PIP", | 64 | [INTEL_PT_PIP] = "PIP", |
65 | [INTEL_PT_OVF] = "OVF", | 65 | [INTEL_PT_OVF] = "OVF", |
66 | [INTEL_PT_MNT] = "MNT", | 66 | [INTEL_PT_MNT] = "MNT", |
67 | [INTEL_PT_PTWRITE] = "PTWRITE", | ||
68 | [INTEL_PT_PTWRITE_IP] = "PTWRITE", | ||
69 | [INTEL_PT_EXSTOP] = "EXSTOP", | ||
70 | [INTEL_PT_EXSTOP_IP] = "EXSTOP", | ||
71 | [INTEL_PT_MWAIT] = "MWAIT", | ||
72 | [INTEL_PT_PWRE] = "PWRE", | ||
73 | [INTEL_PT_PWRX] = "PWRX", | ||
67 | }; | 74 | }; |
68 | 75 | ||
69 | const char *intel_pt_pkt_name(enum intel_pt_pkt_type type) | 76 | const char *intel_pt_pkt_name(enum intel_pt_pkt_type type) |
@@ -123,7 +130,7 @@ static int intel_pt_get_cbr(const unsigned char *buf, size_t len, | |||
123 | if (len < 4) | 130 | if (len < 4) |
124 | return INTEL_PT_NEED_MORE_BYTES; | 131 | return INTEL_PT_NEED_MORE_BYTES; |
125 | packet->type = INTEL_PT_CBR; | 132 | packet->type = INTEL_PT_CBR; |
126 | packet->payload = buf[2]; | 133 | packet->payload = le16_to_cpu(*(uint16_t *)(buf + 2)); |
127 | return 4; | 134 | return 4; |
128 | } | 135 | } |
129 | 136 | ||
@@ -217,12 +224,80 @@ static int intel_pt_get_3byte(const unsigned char *buf, size_t len, | |||
217 | } | 224 | } |
218 | } | 225 | } |
219 | 226 | ||
227 | static int intel_pt_get_ptwrite(const unsigned char *buf, size_t len, | ||
228 | struct intel_pt_pkt *packet) | ||
229 | { | ||
230 | packet->count = (buf[1] >> 5) & 0x3; | ||
231 | packet->type = buf[1] & BIT(7) ? INTEL_PT_PTWRITE_IP : | ||
232 | INTEL_PT_PTWRITE; | ||
233 | |||
234 | switch (packet->count) { | ||
235 | case 0: | ||
236 | if (len < 6) | ||
237 | return INTEL_PT_NEED_MORE_BYTES; | ||
238 | packet->payload = le32_to_cpu(*(uint32_t *)(buf + 2)); | ||
239 | return 6; | ||
240 | case 1: | ||
241 | if (len < 10) | ||
242 | return INTEL_PT_NEED_MORE_BYTES; | ||
243 | packet->payload = le64_to_cpu(*(uint64_t *)(buf + 2)); | ||
244 | return 10; | ||
245 | default: | ||
246 | return INTEL_PT_BAD_PACKET; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static int intel_pt_get_exstop(struct intel_pt_pkt *packet) | ||
251 | { | ||
252 | packet->type = INTEL_PT_EXSTOP; | ||
253 | return 2; | ||
254 | } | ||
255 | |||
256 | static int intel_pt_get_exstop_ip(struct intel_pt_pkt *packet) | ||
257 | { | ||
258 | packet->type = INTEL_PT_EXSTOP_IP; | ||
259 | return 2; | ||
260 | } | ||
261 | |||
262 | static int intel_pt_get_mwait(const unsigned char *buf, size_t len, | ||
263 | struct intel_pt_pkt *packet) | ||
264 | { | ||
265 | if (len < 10) | ||
266 | return INTEL_PT_NEED_MORE_BYTES; | ||
267 | packet->type = INTEL_PT_MWAIT; | ||
268 | packet->payload = le64_to_cpu(*(uint64_t *)(buf + 2)); | ||
269 | return 10; | ||
270 | } | ||
271 | |||
272 | static int intel_pt_get_pwre(const unsigned char *buf, size_t len, | ||
273 | struct intel_pt_pkt *packet) | ||
274 | { | ||
275 | if (len < 4) | ||
276 | return INTEL_PT_NEED_MORE_BYTES; | ||
277 | packet->type = INTEL_PT_PWRE; | ||
278 | memcpy_le64(&packet->payload, buf + 2, 2); | ||
279 | return 4; | ||
280 | } | ||
281 | |||
282 | static int intel_pt_get_pwrx(const unsigned char *buf, size_t len, | ||
283 | struct intel_pt_pkt *packet) | ||
284 | { | ||
285 | if (len < 7) | ||
286 | return INTEL_PT_NEED_MORE_BYTES; | ||
287 | packet->type = INTEL_PT_PWRX; | ||
288 | memcpy_le64(&packet->payload, buf + 2, 5); | ||
289 | return 7; | ||
290 | } | ||
291 | |||
220 | static int intel_pt_get_ext(const unsigned char *buf, size_t len, | 292 | static int intel_pt_get_ext(const unsigned char *buf, size_t len, |
221 | struct intel_pt_pkt *packet) | 293 | struct intel_pt_pkt *packet) |
222 | { | 294 | { |
223 | if (len < 2) | 295 | if (len < 2) |
224 | return INTEL_PT_NEED_MORE_BYTES; | 296 | return INTEL_PT_NEED_MORE_BYTES; |
225 | 297 | ||
298 | if ((buf[1] & 0x1f) == 0x12) | ||
299 | return intel_pt_get_ptwrite(buf, len, packet); | ||
300 | |||
226 | switch (buf[1]) { | 301 | switch (buf[1]) { |
227 | case 0xa3: /* Long TNT */ | 302 | case 0xa3: /* Long TNT */ |
228 | return intel_pt_get_long_tnt(buf, len, packet); | 303 | return intel_pt_get_long_tnt(buf, len, packet); |
@@ -244,6 +319,16 @@ static int intel_pt_get_ext(const unsigned char *buf, size_t len, | |||
244 | return intel_pt_get_tma(buf, len, packet); | 319 | return intel_pt_get_tma(buf, len, packet); |
245 | case 0xC3: /* 3-byte header */ | 320 | case 0xC3: /* 3-byte header */ |
246 | return intel_pt_get_3byte(buf, len, packet); | 321 | return intel_pt_get_3byte(buf, len, packet); |
322 | case 0x62: /* EXSTOP no IP */ | ||
323 | return intel_pt_get_exstop(packet); | ||
324 | case 0xE2: /* EXSTOP with IP */ | ||
325 | return intel_pt_get_exstop_ip(packet); | ||
326 | case 0xC2: /* MWAIT */ | ||
327 | return intel_pt_get_mwait(buf, len, packet); | ||
328 | case 0x22: /* PWRE */ | ||
329 | return intel_pt_get_pwre(buf, len, packet); | ||
330 | case 0xA2: /* PWRX */ | ||
331 | return intel_pt_get_pwrx(buf, len, packet); | ||
247 | default: | 332 | default: |
248 | return INTEL_PT_BAD_PACKET; | 333 | return INTEL_PT_BAD_PACKET; |
249 | } | 334 | } |
@@ -522,6 +607,29 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, | |||
522 | ret = snprintf(buf, buf_len, "%s 0x%llx (NR=%d)", | 607 | ret = snprintf(buf, buf_len, "%s 0x%llx (NR=%d)", |
523 | name, payload, nr); | 608 | name, payload, nr); |
524 | return ret; | 609 | return ret; |
610 | case INTEL_PT_PTWRITE: | ||
611 | return snprintf(buf, buf_len, "%s 0x%llx IP:0", name, payload); | ||
612 | case INTEL_PT_PTWRITE_IP: | ||
613 | return snprintf(buf, buf_len, "%s 0x%llx IP:1", name, payload); | ||
614 | case INTEL_PT_EXSTOP: | ||
615 | return snprintf(buf, buf_len, "%s IP:0", name); | ||
616 | case INTEL_PT_EXSTOP_IP: | ||
617 | return snprintf(buf, buf_len, "%s IP:1", name); | ||
618 | case INTEL_PT_MWAIT: | ||
619 | return snprintf(buf, buf_len, "%s 0x%llx Hints 0x%x Extensions 0x%x", | ||
620 | name, payload, (unsigned int)(payload & 0xff), | ||
621 | (unsigned int)((payload >> 32) & 0x3)); | ||
622 | case INTEL_PT_PWRE: | ||
623 | return snprintf(buf, buf_len, "%s 0x%llx HW:%u CState:%u Sub-CState:%u", | ||
624 | name, payload, !!(payload & 0x80), | ||
625 | (unsigned int)((payload >> 12) & 0xf), | ||
626 | (unsigned int)((payload >> 8) & 0xf)); | ||
627 | case INTEL_PT_PWRX: | ||
628 | return snprintf(buf, buf_len, "%s 0x%llx Last CState:%u Deepest CState:%u Wake Reason 0x%x", | ||
629 | name, payload, | ||
630 | (unsigned int)((payload >> 4) & 0xf), | ||
631 | (unsigned int)(payload & 0xf), | ||
632 | (unsigned int)((payload >> 8) & 0xf)); | ||
525 | default: | 633 | default: |
526 | break; | 634 | break; |
527 | } | 635 | } |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h index 781bb79883bd..73ddc3a88d07 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h | |||
@@ -52,6 +52,13 @@ enum intel_pt_pkt_type { | |||
52 | INTEL_PT_PIP, | 52 | INTEL_PT_PIP, |
53 | INTEL_PT_OVF, | 53 | INTEL_PT_OVF, |
54 | INTEL_PT_MNT, | 54 | INTEL_PT_MNT, |
55 | INTEL_PT_PTWRITE, | ||
56 | INTEL_PT_PTWRITE_IP, | ||
57 | INTEL_PT_EXSTOP, | ||
58 | INTEL_PT_EXSTOP_IP, | ||
59 | INTEL_PT_MWAIT, | ||
60 | INTEL_PT_PWRE, | ||
61 | INTEL_PT_PWRX, | ||
55 | }; | 62 | }; |
56 | 63 | ||
57 | struct intel_pt_pkt { | 64 | struct intel_pt_pkt { |
diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 767be7c76034..12e377184ee4 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt | |||
@@ -1009,7 +1009,7 @@ GrpTable: Grp15 | |||
1009 | 1: fxstor | RDGSBASE Ry (F3),(11B) | 1009 | 1: fxstor | RDGSBASE Ry (F3),(11B) |
1010 | 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) | 1010 | 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) |
1011 | 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) | 1011 | 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) |
1012 | 4: XSAVE | 1012 | 4: XSAVE | ptwrite Ey (F3),(11B) |
1013 | 5: XRSTOR | lfence (11B) | 1013 | 5: XRSTOR | lfence (11B) |
1014 | 6: XSAVEOPT | clwb (66) | mfence (11B) | 1014 | 6: XSAVEOPT | clwb (66) | mfence (11B) |
1015 | 7: clflush | clflushopt (66) | sfence (11B) | 1015 | 7: clflush | clflushopt (66) | sfence (11B) |
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 4c7718f87a08..b58f9fd1e2ee 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
@@ -81,7 +81,6 @@ struct intel_pt { | |||
81 | 81 | ||
82 | bool sample_instructions; | 82 | bool sample_instructions; |
83 | u64 instructions_sample_type; | 83 | u64 instructions_sample_type; |
84 | u64 instructions_sample_period; | ||
85 | u64 instructions_id; | 84 | u64 instructions_id; |
86 | 85 | ||
87 | bool sample_branches; | 86 | bool sample_branches; |
@@ -93,6 +92,18 @@ struct intel_pt { | |||
93 | u64 transactions_sample_type; | 92 | u64 transactions_sample_type; |
94 | u64 transactions_id; | 93 | u64 transactions_id; |
95 | 94 | ||
95 | bool sample_ptwrites; | ||
96 | u64 ptwrites_sample_type; | ||
97 | u64 ptwrites_id; | ||
98 | |||
99 | bool sample_pwr_events; | ||
100 | u64 pwr_events_sample_type; | ||
101 | u64 mwait_id; | ||
102 | u64 pwre_id; | ||
103 | u64 exstop_id; | ||
104 | u64 pwrx_id; | ||
105 | u64 cbr_id; | ||
106 | |||
96 | bool synth_needs_swap; | 107 | bool synth_needs_swap; |
97 | 108 | ||
98 | u64 tsc_bit; | 109 | u64 tsc_bit; |
@@ -103,6 +114,7 @@ struct intel_pt { | |||
103 | u64 cyc_bit; | 114 | u64 cyc_bit; |
104 | u64 noretcomp_bit; | 115 | u64 noretcomp_bit; |
105 | unsigned max_non_turbo_ratio; | 116 | unsigned max_non_turbo_ratio; |
117 | unsigned cbr2khz; | ||
106 | 118 | ||
107 | unsigned long num_events; | 119 | unsigned long num_events; |
108 | 120 | ||
@@ -668,6 +680,19 @@ static bool intel_pt_return_compression(struct intel_pt *pt) | |||
668 | return true; | 680 | return true; |
669 | } | 681 | } |
670 | 682 | ||
683 | static bool intel_pt_branch_enable(struct intel_pt *pt) | ||
684 | { | ||
685 | struct perf_evsel *evsel; | ||
686 | u64 config; | ||
687 | |||
688 | evlist__for_each_entry(pt->session->evlist, evsel) { | ||
689 | if (intel_pt_get_config(pt, &evsel->attr, &config) && | ||
690 | (config & 1) && !(config & 0x2000)) | ||
691 | return false; | ||
692 | } | ||
693 | return true; | ||
694 | } | ||
695 | |||
671 | static unsigned int intel_pt_mtc_period(struct intel_pt *pt) | 696 | static unsigned int intel_pt_mtc_period(struct intel_pt *pt) |
672 | { | 697 | { |
673 | struct perf_evsel *evsel; | 698 | struct perf_evsel *evsel; |
@@ -799,6 +824,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
799 | params.walk_insn = intel_pt_walk_next_insn; | 824 | params.walk_insn = intel_pt_walk_next_insn; |
800 | params.data = ptq; | 825 | params.data = ptq; |
801 | params.return_compression = intel_pt_return_compression(pt); | 826 | params.return_compression = intel_pt_return_compression(pt); |
827 | params.branch_enable = intel_pt_branch_enable(pt); | ||
802 | params.max_non_turbo_ratio = pt->max_non_turbo_ratio; | 828 | params.max_non_turbo_ratio = pt->max_non_turbo_ratio; |
803 | params.mtc_period = intel_pt_mtc_period(pt); | 829 | params.mtc_period = intel_pt_mtc_period(pt); |
804 | params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n; | 830 | params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n; |
@@ -1044,6 +1070,36 @@ static void intel_pt_update_last_branch_rb(struct intel_pt_queue *ptq) | |||
1044 | bs->nr += 1; | 1070 | bs->nr += 1; |
1045 | } | 1071 | } |
1046 | 1072 | ||
1073 | static inline bool intel_pt_skip_event(struct intel_pt *pt) | ||
1074 | { | ||
1075 | return pt->synth_opts.initial_skip && | ||
1076 | pt->num_events++ < pt->synth_opts.initial_skip; | ||
1077 | } | ||
1078 | |||
1079 | static void intel_pt_prep_b_sample(struct intel_pt *pt, | ||
1080 | struct intel_pt_queue *ptq, | ||
1081 | union perf_event *event, | ||
1082 | struct perf_sample *sample) | ||
1083 | { | ||
1084 | event->sample.header.type = PERF_RECORD_SAMPLE; | ||
1085 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
1086 | event->sample.header.size = sizeof(struct perf_event_header); | ||
1087 | |||
1088 | if (!pt->timeless_decoding) | ||
1089 | sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | ||
1090 | |||
1091 | sample->cpumode = PERF_RECORD_MISC_USER; | ||
1092 | sample->ip = ptq->state->from_ip; | ||
1093 | sample->pid = ptq->pid; | ||
1094 | sample->tid = ptq->tid; | ||
1095 | sample->addr = ptq->state->to_ip; | ||
1096 | sample->period = 1; | ||
1097 | sample->cpu = ptq->cpu; | ||
1098 | sample->flags = ptq->flags; | ||
1099 | sample->insn_len = ptq->insn_len; | ||
1100 | memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
1101 | } | ||
1102 | |||
1047 | static int intel_pt_inject_event(union perf_event *event, | 1103 | static int intel_pt_inject_event(union perf_event *event, |
1048 | struct perf_sample *sample, u64 type, | 1104 | struct perf_sample *sample, u64 type, |
1049 | bool swapped) | 1105 | bool swapped) |
@@ -1052,9 +1108,35 @@ static int intel_pt_inject_event(union perf_event *event, | |||
1052 | return perf_event__synthesize_sample(event, type, 0, sample, swapped); | 1108 | return perf_event__synthesize_sample(event, type, 0, sample, swapped); |
1053 | } | 1109 | } |
1054 | 1110 | ||
1055 | static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | 1111 | static inline int intel_pt_opt_inject(struct intel_pt *pt, |
1112 | union perf_event *event, | ||
1113 | struct perf_sample *sample, u64 type) | ||
1114 | { | ||
1115 | if (!pt->synth_opts.inject) | ||
1116 | return 0; | ||
1117 | |||
1118 | return intel_pt_inject_event(event, sample, type, pt->synth_needs_swap); | ||
1119 | } | ||
1120 | |||
1121 | static int intel_pt_deliver_synth_b_event(struct intel_pt *pt, | ||
1122 | union perf_event *event, | ||
1123 | struct perf_sample *sample, u64 type) | ||
1056 | { | 1124 | { |
1057 | int ret; | 1125 | int ret; |
1126 | |||
1127 | ret = intel_pt_opt_inject(pt, event, sample, type); | ||
1128 | if (ret) | ||
1129 | return ret; | ||
1130 | |||
1131 | ret = perf_session__deliver_synth_event(pt->session, event, sample); | ||
1132 | if (ret) | ||
1133 | pr_err("Intel PT: failed to deliver event, error %d\n", ret); | ||
1134 | |||
1135 | return ret; | ||
1136 | } | ||
1137 | |||
1138 | static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | ||
1139 | { | ||
1058 | struct intel_pt *pt = ptq->pt; | 1140 | struct intel_pt *pt = ptq->pt; |
1059 | union perf_event *event = ptq->event_buf; | 1141 | union perf_event *event = ptq->event_buf; |
1060 | struct perf_sample sample = { .ip = 0, }; | 1142 | struct perf_sample sample = { .ip = 0, }; |
@@ -1066,29 +1148,13 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | |||
1066 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) | 1148 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) |
1067 | return 0; | 1149 | return 0; |
1068 | 1150 | ||
1069 | if (pt->synth_opts.initial_skip && | 1151 | if (intel_pt_skip_event(pt)) |
1070 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
1071 | return 0; | 1152 | return 0; |
1072 | 1153 | ||
1073 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1154 | intel_pt_prep_b_sample(pt, ptq, event, &sample); |
1074 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
1075 | event->sample.header.size = sizeof(struct perf_event_header); | ||
1076 | 1155 | ||
1077 | if (!pt->timeless_decoding) | ||
1078 | sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | ||
1079 | |||
1080 | sample.cpumode = PERF_RECORD_MISC_USER; | ||
1081 | sample.ip = ptq->state->from_ip; | ||
1082 | sample.pid = ptq->pid; | ||
1083 | sample.tid = ptq->tid; | ||
1084 | sample.addr = ptq->state->to_ip; | ||
1085 | sample.id = ptq->pt->branches_id; | 1156 | sample.id = ptq->pt->branches_id; |
1086 | sample.stream_id = ptq->pt->branches_id; | 1157 | sample.stream_id = ptq->pt->branches_id; |
1087 | sample.period = 1; | ||
1088 | sample.cpu = ptq->cpu; | ||
1089 | sample.flags = ptq->flags; | ||
1090 | sample.insn_len = ptq->insn_len; | ||
1091 | memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
1092 | 1158 | ||
1093 | /* | 1159 | /* |
1094 | * perf report cannot handle events without a branch stack when using | 1160 | * perf report cannot handle events without a branch stack when using |
@@ -1105,144 +1171,251 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | |||
1105 | sample.branch_stack = (struct branch_stack *)&dummy_bs; | 1171 | sample.branch_stack = (struct branch_stack *)&dummy_bs; |
1106 | } | 1172 | } |
1107 | 1173 | ||
1108 | if (pt->synth_opts.inject) { | 1174 | return intel_pt_deliver_synth_b_event(pt, event, &sample, |
1109 | ret = intel_pt_inject_event(event, &sample, | 1175 | pt->branches_sample_type); |
1110 | pt->branches_sample_type, | 1176 | } |
1111 | pt->synth_needs_swap); | 1177 | |
1112 | if (ret) | 1178 | static void intel_pt_prep_sample(struct intel_pt *pt, |
1113 | return ret; | 1179 | struct intel_pt_queue *ptq, |
1180 | union perf_event *event, | ||
1181 | struct perf_sample *sample) | ||
1182 | { | ||
1183 | intel_pt_prep_b_sample(pt, ptq, event, sample); | ||
1184 | |||
1185 | if (pt->synth_opts.callchain) { | ||
1186 | thread_stack__sample(ptq->thread, ptq->chain, | ||
1187 | pt->synth_opts.callchain_sz, sample->ip); | ||
1188 | sample->callchain = ptq->chain; | ||
1114 | } | 1189 | } |
1115 | 1190 | ||
1116 | ret = perf_session__deliver_synth_event(pt->session, event, &sample); | 1191 | if (pt->synth_opts.last_branch) { |
1117 | if (ret) | 1192 | intel_pt_copy_last_branch_rb(ptq); |
1118 | pr_err("Intel Processor Trace: failed to deliver branch event, error %d\n", | 1193 | sample->branch_stack = ptq->last_branch; |
1119 | ret); | 1194 | } |
1195 | } | ||
1196 | |||
1197 | static inline int intel_pt_deliver_synth_event(struct intel_pt *pt, | ||
1198 | struct intel_pt_queue *ptq, | ||
1199 | union perf_event *event, | ||
1200 | struct perf_sample *sample, | ||
1201 | u64 type) | ||
1202 | { | ||
1203 | int ret; | ||
1204 | |||
1205 | ret = intel_pt_deliver_synth_b_event(pt, event, sample, type); | ||
1206 | |||
1207 | if (pt->synth_opts.last_branch) | ||
1208 | intel_pt_reset_last_branch_rb(ptq); | ||
1120 | 1209 | ||
1121 | return ret; | 1210 | return ret; |
1122 | } | 1211 | } |
1123 | 1212 | ||
1124 | static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) | 1213 | static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) |
1125 | { | 1214 | { |
1126 | int ret; | ||
1127 | struct intel_pt *pt = ptq->pt; | 1215 | struct intel_pt *pt = ptq->pt; |
1128 | union perf_event *event = ptq->event_buf; | 1216 | union perf_event *event = ptq->event_buf; |
1129 | struct perf_sample sample = { .ip = 0, }; | 1217 | struct perf_sample sample = { .ip = 0, }; |
1130 | 1218 | ||
1131 | if (pt->synth_opts.initial_skip && | 1219 | if (intel_pt_skip_event(pt)) |
1132 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
1133 | return 0; | 1220 | return 0; |
1134 | 1221 | ||
1135 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1222 | intel_pt_prep_sample(pt, ptq, event, &sample); |
1136 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
1137 | event->sample.header.size = sizeof(struct perf_event_header); | ||
1138 | |||
1139 | if (!pt->timeless_decoding) | ||
1140 | sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | ||
1141 | 1223 | ||
1142 | sample.cpumode = PERF_RECORD_MISC_USER; | ||
1143 | sample.ip = ptq->state->from_ip; | ||
1144 | sample.pid = ptq->pid; | ||
1145 | sample.tid = ptq->tid; | ||
1146 | sample.addr = ptq->state->to_ip; | ||
1147 | sample.id = ptq->pt->instructions_id; | 1224 | sample.id = ptq->pt->instructions_id; |
1148 | sample.stream_id = ptq->pt->instructions_id; | 1225 | sample.stream_id = ptq->pt->instructions_id; |
1149 | sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt; | 1226 | sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt; |
1150 | sample.cpu = ptq->cpu; | ||
1151 | sample.flags = ptq->flags; | ||
1152 | sample.insn_len = ptq->insn_len; | ||
1153 | memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
1154 | 1227 | ||
1155 | ptq->last_insn_cnt = ptq->state->tot_insn_cnt; | 1228 | ptq->last_insn_cnt = ptq->state->tot_insn_cnt; |
1156 | 1229 | ||
1157 | if (pt->synth_opts.callchain) { | 1230 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, |
1158 | thread_stack__sample(ptq->thread, ptq->chain, | 1231 | pt->instructions_sample_type); |
1159 | pt->synth_opts.callchain_sz, sample.ip); | 1232 | } |
1160 | sample.callchain = ptq->chain; | ||
1161 | } | ||
1162 | 1233 | ||
1163 | if (pt->synth_opts.last_branch) { | 1234 | static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) |
1164 | intel_pt_copy_last_branch_rb(ptq); | 1235 | { |
1165 | sample.branch_stack = ptq->last_branch; | 1236 | struct intel_pt *pt = ptq->pt; |
1166 | } | 1237 | union perf_event *event = ptq->event_buf; |
1238 | struct perf_sample sample = { .ip = 0, }; | ||
1167 | 1239 | ||
1168 | if (pt->synth_opts.inject) { | 1240 | if (intel_pt_skip_event(pt)) |
1169 | ret = intel_pt_inject_event(event, &sample, | 1241 | return 0; |
1170 | pt->instructions_sample_type, | ||
1171 | pt->synth_needs_swap); | ||
1172 | if (ret) | ||
1173 | return ret; | ||
1174 | } | ||
1175 | 1242 | ||
1176 | ret = perf_session__deliver_synth_event(pt->session, event, &sample); | 1243 | intel_pt_prep_sample(pt, ptq, event, &sample); |
1177 | if (ret) | ||
1178 | pr_err("Intel Processor Trace: failed to deliver instruction event, error %d\n", | ||
1179 | ret); | ||
1180 | 1244 | ||
1181 | if (pt->synth_opts.last_branch) | 1245 | sample.id = ptq->pt->transactions_id; |
1182 | intel_pt_reset_last_branch_rb(ptq); | 1246 | sample.stream_id = ptq->pt->transactions_id; |
1183 | 1247 | ||
1184 | return ret; | 1248 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, |
1249 | pt->transactions_sample_type); | ||
1185 | } | 1250 | } |
1186 | 1251 | ||
1187 | static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) | 1252 | static void intel_pt_prep_p_sample(struct intel_pt *pt, |
1253 | struct intel_pt_queue *ptq, | ||
1254 | union perf_event *event, | ||
1255 | struct perf_sample *sample) | ||
1256 | { | ||
1257 | intel_pt_prep_sample(pt, ptq, event, sample); | ||
1258 | |||
1259 | /* | ||
1260 | * Zero IP is used to mean "trace start" but that is not the case for | ||
1261 | * power or PTWRITE events with no IP, so clear the flags. | ||
1262 | */ | ||
1263 | if (!sample->ip) | ||
1264 | sample->flags = 0; | ||
1265 | } | ||
1266 | |||
1267 | static int intel_pt_synth_ptwrite_sample(struct intel_pt_queue *ptq) | ||
1188 | { | 1268 | { |
1189 | int ret; | ||
1190 | struct intel_pt *pt = ptq->pt; | 1269 | struct intel_pt *pt = ptq->pt; |
1191 | union perf_event *event = ptq->event_buf; | 1270 | union perf_event *event = ptq->event_buf; |
1192 | struct perf_sample sample = { .ip = 0, }; | 1271 | struct perf_sample sample = { .ip = 0, }; |
1272 | struct perf_synth_intel_ptwrite raw; | ||
1193 | 1273 | ||
1194 | if (pt->synth_opts.initial_skip && | 1274 | if (intel_pt_skip_event(pt)) |
1195 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
1196 | return 0; | 1275 | return 0; |
1197 | 1276 | ||
1198 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1277 | intel_pt_prep_p_sample(pt, ptq, event, &sample); |
1199 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
1200 | event->sample.header.size = sizeof(struct perf_event_header); | ||
1201 | 1278 | ||
1202 | if (!pt->timeless_decoding) | 1279 | sample.id = ptq->pt->ptwrites_id; |
1203 | sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | 1280 | sample.stream_id = ptq->pt->ptwrites_id; |
1204 | 1281 | ||
1205 | sample.cpumode = PERF_RECORD_MISC_USER; | 1282 | raw.flags = 0; |
1206 | sample.ip = ptq->state->from_ip; | 1283 | raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP); |
1207 | sample.pid = ptq->pid; | 1284 | raw.payload = cpu_to_le64(ptq->state->ptw_payload); |
1208 | sample.tid = ptq->tid; | ||
1209 | sample.addr = ptq->state->to_ip; | ||
1210 | sample.id = ptq->pt->transactions_id; | ||
1211 | sample.stream_id = ptq->pt->transactions_id; | ||
1212 | sample.period = 1; | ||
1213 | sample.cpu = ptq->cpu; | ||
1214 | sample.flags = ptq->flags; | ||
1215 | sample.insn_len = ptq->insn_len; | ||
1216 | memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
1217 | 1285 | ||
1218 | if (pt->synth_opts.callchain) { | 1286 | sample.raw_size = perf_synth__raw_size(raw); |
1219 | thread_stack__sample(ptq->thread, ptq->chain, | 1287 | sample.raw_data = perf_synth__raw_data(&raw); |
1220 | pt->synth_opts.callchain_sz, sample.ip); | ||
1221 | sample.callchain = ptq->chain; | ||
1222 | } | ||
1223 | 1288 | ||
1224 | if (pt->synth_opts.last_branch) { | 1289 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, |
1225 | intel_pt_copy_last_branch_rb(ptq); | 1290 | pt->ptwrites_sample_type); |
1226 | sample.branch_stack = ptq->last_branch; | 1291 | } |
1227 | } | ||
1228 | 1292 | ||
1229 | if (pt->synth_opts.inject) { | 1293 | static int intel_pt_synth_cbr_sample(struct intel_pt_queue *ptq) |
1230 | ret = intel_pt_inject_event(event, &sample, | 1294 | { |
1231 | pt->transactions_sample_type, | 1295 | struct intel_pt *pt = ptq->pt; |
1232 | pt->synth_needs_swap); | 1296 | union perf_event *event = ptq->event_buf; |
1233 | if (ret) | 1297 | struct perf_sample sample = { .ip = 0, }; |
1234 | return ret; | 1298 | struct perf_synth_intel_cbr raw; |
1235 | } | 1299 | u32 flags; |
1236 | 1300 | ||
1237 | ret = perf_session__deliver_synth_event(pt->session, event, &sample); | 1301 | if (intel_pt_skip_event(pt)) |
1238 | if (ret) | 1302 | return 0; |
1239 | pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", | ||
1240 | ret); | ||
1241 | 1303 | ||
1242 | if (pt->synth_opts.last_branch) | 1304 | intel_pt_prep_p_sample(pt, ptq, event, &sample); |
1243 | intel_pt_reset_last_branch_rb(ptq); | ||
1244 | 1305 | ||
1245 | return ret; | 1306 | sample.id = ptq->pt->cbr_id; |
1307 | sample.stream_id = ptq->pt->cbr_id; | ||
1308 | |||
1309 | flags = (u16)ptq->state->cbr_payload | (pt->max_non_turbo_ratio << 16); | ||
1310 | raw.flags = cpu_to_le32(flags); | ||
1311 | raw.freq = cpu_to_le32(raw.cbr * pt->cbr2khz); | ||
1312 | raw.reserved3 = 0; | ||
1313 | |||
1314 | sample.raw_size = perf_synth__raw_size(raw); | ||
1315 | sample.raw_data = perf_synth__raw_data(&raw); | ||
1316 | |||
1317 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
1318 | pt->pwr_events_sample_type); | ||
1319 | } | ||
1320 | |||
1321 | static int intel_pt_synth_mwait_sample(struct intel_pt_queue *ptq) | ||
1322 | { | ||
1323 | struct intel_pt *pt = ptq->pt; | ||
1324 | union perf_event *event = ptq->event_buf; | ||
1325 | struct perf_sample sample = { .ip = 0, }; | ||
1326 | struct perf_synth_intel_mwait raw; | ||
1327 | |||
1328 | if (intel_pt_skip_event(pt)) | ||
1329 | return 0; | ||
1330 | |||
1331 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
1332 | |||
1333 | sample.id = ptq->pt->mwait_id; | ||
1334 | sample.stream_id = ptq->pt->mwait_id; | ||
1335 | |||
1336 | raw.reserved = 0; | ||
1337 | raw.payload = cpu_to_le64(ptq->state->mwait_payload); | ||
1338 | |||
1339 | sample.raw_size = perf_synth__raw_size(raw); | ||
1340 | sample.raw_data = perf_synth__raw_data(&raw); | ||
1341 | |||
1342 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
1343 | pt->pwr_events_sample_type); | ||
1344 | } | ||
1345 | |||
1346 | static int intel_pt_synth_pwre_sample(struct intel_pt_queue *ptq) | ||
1347 | { | ||
1348 | struct intel_pt *pt = ptq->pt; | ||
1349 | union perf_event *event = ptq->event_buf; | ||
1350 | struct perf_sample sample = { .ip = 0, }; | ||
1351 | struct perf_synth_intel_pwre raw; | ||
1352 | |||
1353 | if (intel_pt_skip_event(pt)) | ||
1354 | return 0; | ||
1355 | |||
1356 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
1357 | |||
1358 | sample.id = ptq->pt->pwre_id; | ||
1359 | sample.stream_id = ptq->pt->pwre_id; | ||
1360 | |||
1361 | raw.reserved = 0; | ||
1362 | raw.payload = cpu_to_le64(ptq->state->pwre_payload); | ||
1363 | |||
1364 | sample.raw_size = perf_synth__raw_size(raw); | ||
1365 | sample.raw_data = perf_synth__raw_data(&raw); | ||
1366 | |||
1367 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
1368 | pt->pwr_events_sample_type); | ||
1369 | } | ||
1370 | |||
1371 | static int intel_pt_synth_exstop_sample(struct intel_pt_queue *ptq) | ||
1372 | { | ||
1373 | struct intel_pt *pt = ptq->pt; | ||
1374 | union perf_event *event = ptq->event_buf; | ||
1375 | struct perf_sample sample = { .ip = 0, }; | ||
1376 | struct perf_synth_intel_exstop raw; | ||
1377 | |||
1378 | if (intel_pt_skip_event(pt)) | ||
1379 | return 0; | ||
1380 | |||
1381 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
1382 | |||
1383 | sample.id = ptq->pt->exstop_id; | ||
1384 | sample.stream_id = ptq->pt->exstop_id; | ||
1385 | |||
1386 | raw.flags = 0; | ||
1387 | raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP); | ||
1388 | |||
1389 | sample.raw_size = perf_synth__raw_size(raw); | ||
1390 | sample.raw_data = perf_synth__raw_data(&raw); | ||
1391 | |||
1392 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
1393 | pt->pwr_events_sample_type); | ||
1394 | } | ||
1395 | |||
1396 | static int intel_pt_synth_pwrx_sample(struct intel_pt_queue *ptq) | ||
1397 | { | ||
1398 | struct intel_pt *pt = ptq->pt; | ||
1399 | union perf_event *event = ptq->event_buf; | ||
1400 | struct perf_sample sample = { .ip = 0, }; | ||
1401 | struct perf_synth_intel_pwrx raw; | ||
1402 | |||
1403 | if (intel_pt_skip_event(pt)) | ||
1404 | return 0; | ||
1405 | |||
1406 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
1407 | |||
1408 | sample.id = ptq->pt->pwrx_id; | ||
1409 | sample.stream_id = ptq->pt->pwrx_id; | ||
1410 | |||
1411 | raw.reserved = 0; | ||
1412 | raw.payload = cpu_to_le64(ptq->state->pwrx_payload); | ||
1413 | |||
1414 | sample.raw_size = perf_synth__raw_size(raw); | ||
1415 | sample.raw_data = perf_synth__raw_data(&raw); | ||
1416 | |||
1417 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
1418 | pt->pwr_events_sample_type); | ||
1246 | } | 1419 | } |
1247 | 1420 | ||
1248 | static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu, | 1421 | static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu, |
@@ -1296,6 +1469,10 @@ static inline bool intel_pt_is_switch_ip(struct intel_pt_queue *ptq, u64 ip) | |||
1296 | PERF_IP_FLAG_INTERRUPT | PERF_IP_FLAG_TX_ABORT)); | 1469 | PERF_IP_FLAG_INTERRUPT | PERF_IP_FLAG_TX_ABORT)); |
1297 | } | 1470 | } |
1298 | 1471 | ||
1472 | #define INTEL_PT_PWR_EVT (INTEL_PT_MWAIT_OP | INTEL_PT_PWR_ENTRY | \ | ||
1473 | INTEL_PT_EX_STOP | INTEL_PT_PWR_EXIT | \ | ||
1474 | INTEL_PT_CBR_CHG) | ||
1475 | |||
1299 | static int intel_pt_sample(struct intel_pt_queue *ptq) | 1476 | static int intel_pt_sample(struct intel_pt_queue *ptq) |
1300 | { | 1477 | { |
1301 | const struct intel_pt_state *state = ptq->state; | 1478 | const struct intel_pt_state *state = ptq->state; |
@@ -1307,24 +1484,52 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) | |||
1307 | 1484 | ||
1308 | ptq->have_sample = false; | 1485 | ptq->have_sample = false; |
1309 | 1486 | ||
1310 | if (pt->sample_instructions && | 1487 | if (pt->sample_pwr_events && (state->type & INTEL_PT_PWR_EVT)) { |
1311 | (state->type & INTEL_PT_INSTRUCTION) && | 1488 | if (state->type & INTEL_PT_CBR_CHG) { |
1312 | (!pt->synth_opts.initial_skip || | 1489 | err = intel_pt_synth_cbr_sample(ptq); |
1313 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | 1490 | if (err) |
1491 | return err; | ||
1492 | } | ||
1493 | if (state->type & INTEL_PT_MWAIT_OP) { | ||
1494 | err = intel_pt_synth_mwait_sample(ptq); | ||
1495 | if (err) | ||
1496 | return err; | ||
1497 | } | ||
1498 | if (state->type & INTEL_PT_PWR_ENTRY) { | ||
1499 | err = intel_pt_synth_pwre_sample(ptq); | ||
1500 | if (err) | ||
1501 | return err; | ||
1502 | } | ||
1503 | if (state->type & INTEL_PT_EX_STOP) { | ||
1504 | err = intel_pt_synth_exstop_sample(ptq); | ||
1505 | if (err) | ||
1506 | return err; | ||
1507 | } | ||
1508 | if (state->type & INTEL_PT_PWR_EXIT) { | ||
1509 | err = intel_pt_synth_pwrx_sample(ptq); | ||
1510 | if (err) | ||
1511 | return err; | ||
1512 | } | ||
1513 | } | ||
1514 | |||
1515 | if (pt->sample_instructions && (state->type & INTEL_PT_INSTRUCTION)) { | ||
1314 | err = intel_pt_synth_instruction_sample(ptq); | 1516 | err = intel_pt_synth_instruction_sample(ptq); |
1315 | if (err) | 1517 | if (err) |
1316 | return err; | 1518 | return err; |
1317 | } | 1519 | } |
1318 | 1520 | ||
1319 | if (pt->sample_transactions && | 1521 | if (pt->sample_transactions && (state->type & INTEL_PT_TRANSACTION)) { |
1320 | (state->type & INTEL_PT_TRANSACTION) && | ||
1321 | (!pt->synth_opts.initial_skip || | ||
1322 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | ||
1323 | err = intel_pt_synth_transaction_sample(ptq); | 1522 | err = intel_pt_synth_transaction_sample(ptq); |
1324 | if (err) | 1523 | if (err) |
1325 | return err; | 1524 | return err; |
1326 | } | 1525 | } |
1327 | 1526 | ||
1527 | if (pt->sample_ptwrites && (state->type & INTEL_PT_PTW)) { | ||
1528 | err = intel_pt_synth_ptwrite_sample(ptq); | ||
1529 | if (err) | ||
1530 | return err; | ||
1531 | } | ||
1532 | |||
1328 | if (!(state->type & INTEL_PT_BRANCH)) | 1533 | if (!(state->type & INTEL_PT_BRANCH)) |
1329 | return 0; | 1534 | return 0; |
1330 | 1535 | ||
@@ -1925,36 +2130,65 @@ static int intel_pt_event_synth(struct perf_tool *tool, | |||
1925 | NULL); | 2130 | NULL); |
1926 | } | 2131 | } |
1927 | 2132 | ||
1928 | static int intel_pt_synth_event(struct perf_session *session, | 2133 | static int intel_pt_synth_event(struct perf_session *session, const char *name, |
1929 | struct perf_event_attr *attr, u64 id) | 2134 | struct perf_event_attr *attr, u64 id) |
1930 | { | 2135 | { |
1931 | struct intel_pt_synth intel_pt_synth; | 2136 | struct intel_pt_synth intel_pt_synth; |
2137 | int err; | ||
2138 | |||
2139 | pr_debug("Synthesizing '%s' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | ||
2140 | name, id, (u64)attr->sample_type); | ||
1932 | 2141 | ||
1933 | memset(&intel_pt_synth, 0, sizeof(struct intel_pt_synth)); | 2142 | memset(&intel_pt_synth, 0, sizeof(struct intel_pt_synth)); |
1934 | intel_pt_synth.session = session; | 2143 | intel_pt_synth.session = session; |
1935 | 2144 | ||
1936 | return perf_event__synthesize_attr(&intel_pt_synth.dummy_tool, attr, 1, | 2145 | err = perf_event__synthesize_attr(&intel_pt_synth.dummy_tool, attr, 1, |
1937 | &id, intel_pt_event_synth); | 2146 | &id, intel_pt_event_synth); |
2147 | if (err) | ||
2148 | pr_err("%s: failed to synthesize '%s' event type\n", | ||
2149 | __func__, name); | ||
2150 | |||
2151 | return err; | ||
1938 | } | 2152 | } |
1939 | 2153 | ||
1940 | static int intel_pt_synth_events(struct intel_pt *pt, | 2154 | static void intel_pt_set_event_name(struct perf_evlist *evlist, u64 id, |
1941 | struct perf_session *session) | 2155 | const char *name) |
1942 | { | 2156 | { |
1943 | struct perf_evlist *evlist = session->evlist; | ||
1944 | struct perf_evsel *evsel; | 2157 | struct perf_evsel *evsel; |
1945 | struct perf_event_attr attr; | ||
1946 | bool found = false; | ||
1947 | u64 id; | ||
1948 | int err; | ||
1949 | 2158 | ||
1950 | evlist__for_each_entry(evlist, evsel) { | 2159 | evlist__for_each_entry(evlist, evsel) { |
1951 | if (evsel->attr.type == pt->pmu_type && evsel->ids) { | 2160 | if (evsel->id && evsel->id[0] == id) { |
1952 | found = true; | 2161 | if (evsel->name) |
2162 | zfree(&evsel->name); | ||
2163 | evsel->name = strdup(name); | ||
1953 | break; | 2164 | break; |
1954 | } | 2165 | } |
1955 | } | 2166 | } |
2167 | } | ||
1956 | 2168 | ||
1957 | if (!found) { | 2169 | static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, |
2170 | struct perf_evlist *evlist) | ||
2171 | { | ||
2172 | struct perf_evsel *evsel; | ||
2173 | |||
2174 | evlist__for_each_entry(evlist, evsel) { | ||
2175 | if (evsel->attr.type == pt->pmu_type && evsel->ids) | ||
2176 | return evsel; | ||
2177 | } | ||
2178 | |||
2179 | return NULL; | ||
2180 | } | ||
2181 | |||
2182 | static int intel_pt_synth_events(struct intel_pt *pt, | ||
2183 | struct perf_session *session) | ||
2184 | { | ||
2185 | struct perf_evlist *evlist = session->evlist; | ||
2186 | struct perf_evsel *evsel = intel_pt_evsel(pt, evlist); | ||
2187 | struct perf_event_attr attr; | ||
2188 | u64 id; | ||
2189 | int err; | ||
2190 | |||
2191 | if (!evsel) { | ||
1958 | pr_debug("There are no selected events with Intel Processor Trace data\n"); | 2192 | pr_debug("There are no selected events with Intel Processor Trace data\n"); |
1959 | return 0; | 2193 | return 0; |
1960 | } | 2194 | } |
@@ -1983,6 +2217,25 @@ static int intel_pt_synth_events(struct intel_pt *pt, | |||
1983 | if (!id) | 2217 | if (!id) |
1984 | id = 1; | 2218 | id = 1; |
1985 | 2219 | ||
2220 | if (pt->synth_opts.branches) { | ||
2221 | attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; | ||
2222 | attr.sample_period = 1; | ||
2223 | attr.sample_type |= PERF_SAMPLE_ADDR; | ||
2224 | err = intel_pt_synth_event(session, "branches", &attr, id); | ||
2225 | if (err) | ||
2226 | return err; | ||
2227 | pt->sample_branches = true; | ||
2228 | pt->branches_sample_type = attr.sample_type; | ||
2229 | pt->branches_id = id; | ||
2230 | id += 1; | ||
2231 | attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR; | ||
2232 | } | ||
2233 | |||
2234 | if (pt->synth_opts.callchain) | ||
2235 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
2236 | if (pt->synth_opts.last_branch) | ||
2237 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
2238 | |||
1986 | if (pt->synth_opts.instructions) { | 2239 | if (pt->synth_opts.instructions) { |
1987 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; | 2240 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; |
1988 | if (pt->synth_opts.period_type == PERF_ITRACE_PERIOD_NANOSECS) | 2241 | if (pt->synth_opts.period_type == PERF_ITRACE_PERIOD_NANOSECS) |
@@ -1990,70 +2243,90 @@ static int intel_pt_synth_events(struct intel_pt *pt, | |||
1990 | intel_pt_ns_to_ticks(pt, pt->synth_opts.period); | 2243 | intel_pt_ns_to_ticks(pt, pt->synth_opts.period); |
1991 | else | 2244 | else |
1992 | attr.sample_period = pt->synth_opts.period; | 2245 | attr.sample_period = pt->synth_opts.period; |
1993 | pt->instructions_sample_period = attr.sample_period; | 2246 | err = intel_pt_synth_event(session, "instructions", &attr, id); |
1994 | if (pt->synth_opts.callchain) | 2247 | if (err) |
1995 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
1996 | if (pt->synth_opts.last_branch) | ||
1997 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
1998 | pr_debug("Synthesizing 'instructions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | ||
1999 | id, (u64)attr.sample_type); | ||
2000 | err = intel_pt_synth_event(session, &attr, id); | ||
2001 | if (err) { | ||
2002 | pr_err("%s: failed to synthesize 'instructions' event type\n", | ||
2003 | __func__); | ||
2004 | return err; | 2248 | return err; |
2005 | } | ||
2006 | pt->sample_instructions = true; | 2249 | pt->sample_instructions = true; |
2007 | pt->instructions_sample_type = attr.sample_type; | 2250 | pt->instructions_sample_type = attr.sample_type; |
2008 | pt->instructions_id = id; | 2251 | pt->instructions_id = id; |
2009 | id += 1; | 2252 | id += 1; |
2010 | } | 2253 | } |
2011 | 2254 | ||
2255 | attr.sample_type &= ~(u64)PERF_SAMPLE_PERIOD; | ||
2256 | attr.sample_period = 1; | ||
2257 | |||
2012 | if (pt->synth_opts.transactions) { | 2258 | if (pt->synth_opts.transactions) { |
2013 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; | 2259 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; |
2014 | attr.sample_period = 1; | 2260 | err = intel_pt_synth_event(session, "transactions", &attr, id); |
2015 | if (pt->synth_opts.callchain) | 2261 | if (err) |
2016 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
2017 | if (pt->synth_opts.last_branch) | ||
2018 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
2019 | pr_debug("Synthesizing 'transactions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | ||
2020 | id, (u64)attr.sample_type); | ||
2021 | err = intel_pt_synth_event(session, &attr, id); | ||
2022 | if (err) { | ||
2023 | pr_err("%s: failed to synthesize 'transactions' event type\n", | ||
2024 | __func__); | ||
2025 | return err; | 2262 | return err; |
2026 | } | ||
2027 | pt->sample_transactions = true; | 2263 | pt->sample_transactions = true; |
2264 | pt->transactions_sample_type = attr.sample_type; | ||
2028 | pt->transactions_id = id; | 2265 | pt->transactions_id = id; |
2266 | intel_pt_set_event_name(evlist, id, "transactions"); | ||
2029 | id += 1; | 2267 | id += 1; |
2030 | evlist__for_each_entry(evlist, evsel) { | ||
2031 | if (evsel->id && evsel->id[0] == pt->transactions_id) { | ||
2032 | if (evsel->name) | ||
2033 | zfree(&evsel->name); | ||
2034 | evsel->name = strdup("transactions"); | ||
2035 | break; | ||
2036 | } | ||
2037 | } | ||
2038 | } | 2268 | } |
2039 | 2269 | ||
2040 | if (pt->synth_opts.branches) { | 2270 | attr.type = PERF_TYPE_SYNTH; |
2041 | attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; | 2271 | attr.sample_type |= PERF_SAMPLE_RAW; |
2042 | attr.sample_period = 1; | 2272 | |
2043 | attr.sample_type |= PERF_SAMPLE_ADDR; | 2273 | if (pt->synth_opts.ptwrites) { |
2044 | attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; | 2274 | attr.config = PERF_SYNTH_INTEL_PTWRITE; |
2045 | attr.sample_type &= ~(u64)PERF_SAMPLE_BRANCH_STACK; | 2275 | err = intel_pt_synth_event(session, "ptwrite", &attr, id); |
2046 | pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | 2276 | if (err) |
2047 | id, (u64)attr.sample_type); | ||
2048 | err = intel_pt_synth_event(session, &attr, id); | ||
2049 | if (err) { | ||
2050 | pr_err("%s: failed to synthesize 'branches' event type\n", | ||
2051 | __func__); | ||
2052 | return err; | 2277 | return err; |
2053 | } | 2278 | pt->sample_ptwrites = true; |
2054 | pt->sample_branches = true; | 2279 | pt->ptwrites_sample_type = attr.sample_type; |
2055 | pt->branches_sample_type = attr.sample_type; | 2280 | pt->ptwrites_id = id; |
2056 | pt->branches_id = id; | 2281 | intel_pt_set_event_name(evlist, id, "ptwrite"); |
2282 | id += 1; | ||
2283 | } | ||
2284 | |||
2285 | if (pt->synth_opts.pwr_events) { | ||
2286 | pt->sample_pwr_events = true; | ||
2287 | pt->pwr_events_sample_type = attr.sample_type; | ||
2288 | |||
2289 | attr.config = PERF_SYNTH_INTEL_CBR; | ||
2290 | err = intel_pt_synth_event(session, "cbr", &attr, id); | ||
2291 | if (err) | ||
2292 | return err; | ||
2293 | pt->cbr_id = id; | ||
2294 | intel_pt_set_event_name(evlist, id, "cbr"); | ||
2295 | id += 1; | ||
2296 | } | ||
2297 | |||
2298 | if (pt->synth_opts.pwr_events && (evsel->attr.config & 0x10)) { | ||
2299 | attr.config = PERF_SYNTH_INTEL_MWAIT; | ||
2300 | err = intel_pt_synth_event(session, "mwait", &attr, id); | ||
2301 | if (err) | ||
2302 | return err; | ||
2303 | pt->mwait_id = id; | ||
2304 | intel_pt_set_event_name(evlist, id, "mwait"); | ||
2305 | id += 1; | ||
2306 | |||
2307 | attr.config = PERF_SYNTH_INTEL_PWRE; | ||
2308 | err = intel_pt_synth_event(session, "pwre", &attr, id); | ||
2309 | if (err) | ||
2310 | return err; | ||
2311 | pt->pwre_id = id; | ||
2312 | intel_pt_set_event_name(evlist, id, "pwre"); | ||
2313 | id += 1; | ||
2314 | |||
2315 | attr.config = PERF_SYNTH_INTEL_EXSTOP; | ||
2316 | err = intel_pt_synth_event(session, "exstop", &attr, id); | ||
2317 | if (err) | ||
2318 | return err; | ||
2319 | pt->exstop_id = id; | ||
2320 | intel_pt_set_event_name(evlist, id, "exstop"); | ||
2321 | id += 1; | ||
2322 | |||
2323 | attr.config = PERF_SYNTH_INTEL_PWRX; | ||
2324 | err = intel_pt_synth_event(session, "pwrx", &attr, id); | ||
2325 | if (err) | ||
2326 | return err; | ||
2327 | pt->pwrx_id = id; | ||
2328 | intel_pt_set_event_name(evlist, id, "pwrx"); | ||
2329 | id += 1; | ||
2057 | } | 2330 | } |
2058 | 2331 | ||
2059 | pt->synth_needs_swap = evsel->needs_swap; | 2332 | pt->synth_needs_swap = evsel->needs_swap; |
@@ -2322,6 +2595,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event, | |||
2322 | intel_pt_log("TSC frequency %"PRIu64"\n", tsc_freq); | 2595 | intel_pt_log("TSC frequency %"PRIu64"\n", tsc_freq); |
2323 | intel_pt_log("Maximum non-turbo ratio %u\n", | 2596 | intel_pt_log("Maximum non-turbo ratio %u\n", |
2324 | pt->max_non_turbo_ratio); | 2597 | pt->max_non_turbo_ratio); |
2598 | pt->cbr2khz = tsc_freq / pt->max_non_turbo_ratio / 1000; | ||
2325 | } | 2599 | } |
2326 | 2600 | ||
2327 | if (pt->synth_opts.calls) | 2601 | if (pt->synth_opts.calls) |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index d97e014c3df3..5de2b86b9880 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -572,16 +572,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine, | |||
572 | if (dso == NULL) | 572 | if (dso == NULL) |
573 | goto out_unlock; | 573 | goto out_unlock; |
574 | 574 | ||
575 | if (machine__is_host(machine)) | 575 | dso__set_module_info(dso, m, machine); |
576 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | ||
577 | else | ||
578 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | ||
579 | |||
580 | /* _KMODULE_COMP should be next to _KMODULE */ | ||
581 | if (m->kmod && m->comp) | ||
582 | dso->symtab_type++; | ||
583 | |||
584 | dso__set_short_name(dso, strdup(m->name), true); | ||
585 | dso__set_long_name(dso, strdup(filename), true); | 576 | dso__set_long_name(dso, strdup(filename), true); |
586 | } | 577 | } |
587 | 578 | ||
@@ -1218,10 +1209,12 @@ int machine__create_kernel_maps(struct machine *machine) | |||
1218 | */ | 1209 | */ |
1219 | map_groups__fixup_end(&machine->kmaps); | 1210 | map_groups__fixup_end(&machine->kmaps); |
1220 | 1211 | ||
1221 | if (machine__get_running_kernel_start(machine, &name, &addr)) { | 1212 | if (!machine__get_running_kernel_start(machine, &name, &addr)) { |
1222 | } else if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) { | 1213 | if (name && |
1223 | machine__destroy_kernel_maps(machine); | 1214 | maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) { |
1224 | return -1; | 1215 | machine__destroy_kernel_maps(machine); |
1216 | return -1; | ||
1217 | } | ||
1225 | } | 1218 | } |
1226 | 1219 | ||
1227 | return 0; | 1220 | return 0; |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index ea7f450dc609..389e9729331f 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __PMU_H | 2 | #define __PMU_H |
3 | 3 | ||
4 | #include <linux/bitmap.h> | 4 | #include <linux/bitmap.h> |
5 | #include <linux/compiler.h> | ||
5 | #include <linux/perf_event.h> | 6 | #include <linux/perf_event.h> |
6 | #include <stdbool.h> | 7 | #include <stdbool.h> |
7 | #include "evsel.h" | 8 | #include "evsel.h" |
@@ -83,8 +84,7 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet, | |||
83 | bool long_desc, bool details_flag); | 84 | bool long_desc, bool details_flag); |
84 | bool pmu_have_event(const char *pname, const char *name); | 85 | bool pmu_have_event(const char *pname, const char *name); |
85 | 86 | ||
86 | int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, | 87 | int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4); |
87 | ...) __attribute__((format(scanf, 3, 4))); | ||
88 | 88 | ||
89 | int perf_pmu__test(void); | 89 | int perf_pmu__test(void); |
90 | 90 | ||
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 84e7e698411e..a2670e9d652d 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -619,7 +619,7 @@ static int post_process_probe_trace_point(struct probe_trace_point *tp, | |||
619 | struct map *map, unsigned long offs) | 619 | struct map *map, unsigned long offs) |
620 | { | 620 | { |
621 | struct symbol *sym; | 621 | struct symbol *sym; |
622 | u64 addr = tp->address + tp->offset - offs; | 622 | u64 addr = tp->address - offs; |
623 | 623 | ||
624 | sym = map__find_symbol(map, addr); | 624 | sym = map__find_symbol(map, addr); |
625 | if (!sym) | 625 | if (!sym) |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 373842656fb6..5812947418dd 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef _PROBE_EVENT_H | 1 | #ifndef _PROBE_EVENT_H |
2 | #define _PROBE_EVENT_H | 2 | #define _PROBE_EVENT_H |
3 | 3 | ||
4 | #include <linux/compiler.h> | ||
4 | #include <stdbool.h> | 5 | #include <stdbool.h> |
5 | #include "intlist.h" | 6 | #include "intlist.h" |
6 | 7 | ||
@@ -171,8 +172,7 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev, | |||
171 | struct symbol *sym); | 172 | struct symbol *sym); |
172 | 173 | ||
173 | /* If there is no space to write, returns -E2BIG. */ | 174 | /* If there is no space to write, returns -E2BIG. */ |
174 | int e_snprintf(char *str, size_t size, const char *format, ...) | 175 | int e_snprintf(char *str, size_t size, const char *format, ...) __printf(3, 4); |
175 | __attribute__((format(printf, 3, 4))); | ||
176 | 176 | ||
177 | /* Maximum index number of event-name postfix */ | 177 | /* Maximum index number of event-name postfix */ |
178 | #define MAX_EVENT_INDEX 1024 | 178 | #define MAX_EVENT_INDEX 1024 |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 9d92af7d0718..57b7a00e6f16 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <stdbool.h> | 28 | #include <stdbool.h> |
29 | #include <errno.h> | 29 | #include <errno.h> |
30 | #include <linux/bitmap.h> | 30 | #include <linux/bitmap.h> |
31 | #include <linux/compiler.h> | ||
31 | #include <linux/time64.h> | 32 | #include <linux/time64.h> |
32 | 33 | ||
33 | #include "../../perf.h" | 34 | #include "../../perf.h" |
@@ -84,7 +85,7 @@ struct tables { | |||
84 | 85 | ||
85 | static struct tables tables_global; | 86 | static struct tables tables_global; |
86 | 87 | ||
87 | static void handler_call_die(const char *handler_name) NORETURN; | 88 | static void handler_call_die(const char *handler_name) __noreturn; |
88 | static void handler_call_die(const char *handler_name) | 89 | static void handler_call_die(const char *handler_name) |
89 | { | 90 | { |
90 | PyErr_Print(); | 91 | PyErr_Print(); |
@@ -1219,7 +1220,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1219 | fprintf(ofp, "# be retrieved using Python functions of the form " | 1220 | fprintf(ofp, "# be retrieved using Python functions of the form " |
1220 | "common_*(context).\n"); | 1221 | "common_*(context).\n"); |
1221 | 1222 | ||
1222 | fprintf(ofp, "# See the perf-trace-python Documentation for the list " | 1223 | fprintf(ofp, "# See the perf-script-python Documentation for the list " |
1223 | "of available functions.\n\n"); | 1224 | "of available functions.\n\n"); |
1224 | 1225 | ||
1225 | fprintf(ofp, "import os\n"); | 1226 | fprintf(ofp, "import os\n"); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7dc1096264c5..d19c40a81040 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -2035,7 +2035,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
2035 | 2035 | ||
2036 | if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) { | 2036 | if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) { |
2037 | pr_err("File does not contain CPU events. " | 2037 | pr_err("File does not contain CPU events. " |
2038 | "Remove -c option to proceed.\n"); | 2038 | "Remove -C option to proceed.\n"); |
2039 | return -1; | 2039 | return -1; |
2040 | } | 2040 | } |
2041 | } | 2041 | } |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5762ae4e9e91..8b327c955a4f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -2532,12 +2532,12 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, | |||
2532 | ret = sort_dimension__add(list, tok, evlist, level); | 2532 | ret = sort_dimension__add(list, tok, evlist, level); |
2533 | if (ret == -EINVAL) { | 2533 | if (ret == -EINVAL) { |
2534 | if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) | 2534 | if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) |
2535 | error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); | 2535 | pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); |
2536 | else | 2536 | else |
2537 | error("Invalid --sort key: `%s'", tok); | 2537 | pr_err("Invalid --sort key: `%s'", tok); |
2538 | break; | 2538 | break; |
2539 | } else if (ret == -ESRCH) { | 2539 | } else if (ret == -ESRCH) { |
2540 | error("Unknown --sort key: `%s'", tok); | 2540 | pr_err("Unknown --sort key: `%s'", tok); |
2541 | break; | 2541 | break; |
2542 | } | 2542 | } |
2543 | } | 2543 | } |
@@ -2594,7 +2594,7 @@ static int setup_sort_order(struct perf_evlist *evlist) | |||
2594 | return 0; | 2594 | return 0; |
2595 | 2595 | ||
2596 | if (sort_order[1] == '\0') { | 2596 | if (sort_order[1] == '\0') { |
2597 | error("Invalid --sort key: `+'"); | 2597 | pr_err("Invalid --sort key: `+'"); |
2598 | return -EINVAL; | 2598 | return -EINVAL; |
2599 | } | 2599 | } |
2600 | 2600 | ||
@@ -2604,7 +2604,7 @@ static int setup_sort_order(struct perf_evlist *evlist) | |||
2604 | */ | 2604 | */ |
2605 | if (asprintf(&new_sort_order, "%s,%s", | 2605 | if (asprintf(&new_sort_order, "%s,%s", |
2606 | get_default_sort_order(evlist), sort_order + 1) < 0) { | 2606 | get_default_sort_order(evlist), sort_order + 1) < 0) { |
2607 | error("Not enough memory to set up --sort"); | 2607 | pr_err("Not enough memory to set up --sort"); |
2608 | return -ENOMEM; | 2608 | return -ENOMEM; |
2609 | } | 2609 | } |
2610 | 2610 | ||
@@ -2668,7 +2668,7 @@ static int __setup_sorting(struct perf_evlist *evlist) | |||
2668 | 2668 | ||
2669 | str = strdup(sort_keys); | 2669 | str = strdup(sort_keys); |
2670 | if (str == NULL) { | 2670 | if (str == NULL) { |
2671 | error("Not enough memory to setup sort keys"); | 2671 | pr_err("Not enough memory to setup sort keys"); |
2672 | return -ENOMEM; | 2672 | return -ENOMEM; |
2673 | } | 2673 | } |
2674 | 2674 | ||
@@ -2678,7 +2678,7 @@ static int __setup_sorting(struct perf_evlist *evlist) | |||
2678 | if (!is_strict_order(field_order)) { | 2678 | if (!is_strict_order(field_order)) { |
2679 | str = setup_overhead(str); | 2679 | str = setup_overhead(str); |
2680 | if (str == NULL) { | 2680 | if (str == NULL) { |
2681 | error("Not enough memory to setup overhead keys"); | 2681 | pr_err("Not enough memory to setup overhead keys"); |
2682 | return -ENOMEM; | 2682 | return -ENOMEM; |
2683 | } | 2683 | } |
2684 | } | 2684 | } |
@@ -2834,10 +2834,10 @@ static int setup_output_list(struct perf_hpp_list *list, char *str) | |||
2834 | tok; tok = strtok_r(NULL, ", ", &tmp)) { | 2834 | tok; tok = strtok_r(NULL, ", ", &tmp)) { |
2835 | ret = output_field_add(list, tok); | 2835 | ret = output_field_add(list, tok); |
2836 | if (ret == -EINVAL) { | 2836 | if (ret == -EINVAL) { |
2837 | error("Invalid --fields key: `%s'", tok); | 2837 | pr_err("Invalid --fields key: `%s'", tok); |
2838 | break; | 2838 | break; |
2839 | } else if (ret == -ESRCH) { | 2839 | } else if (ret == -ESRCH) { |
2840 | error("Unknown --fields key: `%s'", tok); | 2840 | pr_err("Unknown --fields key: `%s'", tok); |
2841 | break; | 2841 | break; |
2842 | } | 2842 | } |
2843 | } | 2843 | } |
@@ -2877,7 +2877,7 @@ static int __setup_output_field(void) | |||
2877 | 2877 | ||
2878 | strp = str = strdup(field_order); | 2878 | strp = str = strdup(field_order); |
2879 | if (str == NULL) { | 2879 | if (str == NULL) { |
2880 | error("Not enough memory to setup output fields"); | 2880 | pr_err("Not enough memory to setup output fields"); |
2881 | return -ENOMEM; | 2881 | return -ENOMEM; |
2882 | } | 2882 | } |
2883 | 2883 | ||
@@ -2885,7 +2885,7 @@ static int __setup_output_field(void) | |||
2885 | strp++; | 2885 | strp++; |
2886 | 2886 | ||
2887 | if (!strlen(strp)) { | 2887 | if (!strlen(strp)) { |
2888 | error("Invalid --fields key: `+'"); | 2888 | pr_err("Invalid --fields key: `+'"); |
2889 | goto out; | 2889 | goto out; |
2890 | } | 2890 | } |
2891 | 2891 | ||
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index df051a52393c..ebc88a74e67b 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c | |||
@@ -56,7 +56,10 @@ static int inline_list__append(char *filename, char *funcname, int line_nr, | |||
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
59 | list_add_tail(&ilist->list, &node->val); | 59 | if (callchain_param.order == ORDER_CALLEE) |
60 | list_add_tail(&ilist->list, &node->val); | ||
61 | else | ||
62 | list_add(&ilist->list, &node->val); | ||
60 | 63 | ||
61 | return 0; | 64 | return 0; |
62 | } | 65 | } |
@@ -200,12 +203,14 @@ static void addr2line_cleanup(struct a2l_data *a2l) | |||
200 | 203 | ||
201 | #define MAX_INLINE_NEST 1024 | 204 | #define MAX_INLINE_NEST 1024 |
202 | 205 | ||
203 | static void inline_list__reverse(struct inline_node *node) | 206 | static int inline_list__append_dso_a2l(struct dso *dso, |
207 | struct inline_node *node) | ||
204 | { | 208 | { |
205 | struct inline_list *ilist, *n; | 209 | struct a2l_data *a2l = dso->a2l; |
210 | char *funcname = a2l->funcname ? strdup(a2l->funcname) : NULL; | ||
211 | char *filename = a2l->filename ? strdup(a2l->filename) : NULL; | ||
206 | 212 | ||
207 | list_for_each_entry_safe_reverse(ilist, n, &node->val, list) | 213 | return inline_list__append(filename, funcname, a2l->line, node, dso); |
208 | list_move_tail(&ilist->list, &node->val); | ||
209 | } | 214 | } |
210 | 215 | ||
211 | static int addr2line(const char *dso_name, u64 addr, | 216 | static int addr2line(const char *dso_name, u64 addr, |
@@ -230,36 +235,36 @@ static int addr2line(const char *dso_name, u64 addr, | |||
230 | 235 | ||
231 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); | 236 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); |
232 | 237 | ||
233 | if (a2l->found && unwind_inlines) { | 238 | if (!a2l->found) |
239 | return 0; | ||
240 | |||
241 | if (unwind_inlines) { | ||
234 | int cnt = 0; | 242 | int cnt = 0; |
235 | 243 | ||
244 | if (node && inline_list__append_dso_a2l(dso, node)) | ||
245 | return 0; | ||
246 | |||
236 | while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, | 247 | while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, |
237 | &a2l->funcname, &a2l->line) && | 248 | &a2l->funcname, &a2l->line) && |
238 | cnt++ < MAX_INLINE_NEST) { | 249 | cnt++ < MAX_INLINE_NEST) { |
239 | 250 | ||
240 | if (node != NULL) { | 251 | if (node != NULL) { |
241 | if (inline_list__append(strdup(a2l->filename), | 252 | if (inline_list__append_dso_a2l(dso, node)) |
242 | strdup(a2l->funcname), | ||
243 | a2l->line, node, | ||
244 | dso) != 0) | ||
245 | return 0; | 253 | return 0; |
254 | // found at least one inline frame | ||
255 | ret = 1; | ||
246 | } | 256 | } |
247 | } | 257 | } |
258 | } | ||
248 | 259 | ||
249 | if ((node != NULL) && | 260 | if (file) { |
250 | (callchain_param.order != ORDER_CALLEE)) { | 261 | *file = a2l->filename ? strdup(a2l->filename) : NULL; |
251 | inline_list__reverse(node); | 262 | ret = *file ? 1 : 0; |
252 | } | ||
253 | } | 263 | } |
254 | 264 | ||
255 | if (a2l->found && a2l->filename) { | 265 | if (line) |
256 | *file = strdup(a2l->filename); | ||
257 | *line = a2l->line; | 266 | *line = a2l->line; |
258 | 267 | ||
259 | if (*file) | ||
260 | ret = 1; | ||
261 | } | ||
262 | |||
263 | return ret; | 268 | return ret; |
264 | } | 269 | } |
265 | 270 | ||
@@ -278,8 +283,6 @@ void dso__free_a2l(struct dso *dso) | |||
278 | static struct inline_node *addr2inlines(const char *dso_name, u64 addr, | 283 | static struct inline_node *addr2inlines(const char *dso_name, u64 addr, |
279 | struct dso *dso) | 284 | struct dso *dso) |
280 | { | 285 | { |
281 | char *file = NULL; | ||
282 | unsigned int line = 0; | ||
283 | struct inline_node *node; | 286 | struct inline_node *node; |
284 | 287 | ||
285 | node = zalloc(sizeof(*node)); | 288 | node = zalloc(sizeof(*node)); |
@@ -291,7 +294,7 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr, | |||
291 | INIT_LIST_HEAD(&node->val); | 294 | INIT_LIST_HEAD(&node->val); |
292 | node->addr = addr; | 295 | node->addr = addr; |
293 | 296 | ||
294 | if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node)) | 297 | if (!addr2line(dso_name, addr, NULL, NULL, dso, TRUE, node)) |
295 | goto out_free_inline_node; | 298 | goto out_free_inline_node; |
296 | 299 | ||
297 | if (list_empty(&node->val)) | 300 | if (list_empty(&node->val)) |
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index ac10cc675d39..719d6cb86952 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c | |||
@@ -44,6 +44,8 @@ static struct stats runtime_topdown_slots_issued[NUM_CTX][MAX_NR_CPUS]; | |||
44 | static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; | 44 | static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; |
45 | static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; | 45 | static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; |
46 | static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; | 46 | static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; |
47 | static struct stats runtime_smi_num_stats[NUM_CTX][MAX_NR_CPUS]; | ||
48 | static struct stats runtime_aperf_stats[NUM_CTX][MAX_NR_CPUS]; | ||
47 | static struct rblist runtime_saved_values; | 49 | static struct rblist runtime_saved_values; |
48 | static bool have_frontend_stalled; | 50 | static bool have_frontend_stalled; |
49 | 51 | ||
@@ -157,6 +159,8 @@ void perf_stat__reset_shadow_stats(void) | |||
157 | memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); | 159 | memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); |
158 | memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); | 160 | memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); |
159 | memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); | 161 | memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); |
162 | memset(runtime_smi_num_stats, 0, sizeof(runtime_smi_num_stats)); | ||
163 | memset(runtime_aperf_stats, 0, sizeof(runtime_aperf_stats)); | ||
160 | 164 | ||
161 | next = rb_first(&runtime_saved_values.entries); | 165 | next = rb_first(&runtime_saved_values.entries); |
162 | while (next) { | 166 | while (next) { |
@@ -217,6 +221,10 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, | |||
217 | update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); | 221 | update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); |
218 | else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) | 222 | else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) |
219 | update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); | 223 | update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); |
224 | else if (perf_stat_evsel__is(counter, SMI_NUM)) | ||
225 | update_stats(&runtime_smi_num_stats[ctx][cpu], count[0]); | ||
226 | else if (perf_stat_evsel__is(counter, APERF)) | ||
227 | update_stats(&runtime_aperf_stats[ctx][cpu], count[0]); | ||
220 | 228 | ||
221 | if (counter->collect_stat) { | 229 | if (counter->collect_stat) { |
222 | struct saved_value *v = saved_value_lookup(counter, cpu, ctx, | 230 | struct saved_value *v = saved_value_lookup(counter, cpu, ctx, |
@@ -592,6 +600,29 @@ static double td_be_bound(int ctx, int cpu) | |||
592 | return sanitize_val(1.0 - sum); | 600 | return sanitize_val(1.0 - sum); |
593 | } | 601 | } |
594 | 602 | ||
603 | static void print_smi_cost(int cpu, struct perf_evsel *evsel, | ||
604 | struct perf_stat_output_ctx *out) | ||
605 | { | ||
606 | double smi_num, aperf, cycles, cost = 0.0; | ||
607 | int ctx = evsel_context(evsel); | ||
608 | const char *color = NULL; | ||
609 | |||
610 | smi_num = avg_stats(&runtime_smi_num_stats[ctx][cpu]); | ||
611 | aperf = avg_stats(&runtime_aperf_stats[ctx][cpu]); | ||
612 | cycles = avg_stats(&runtime_cycles_stats[ctx][cpu]); | ||
613 | |||
614 | if ((cycles == 0) || (aperf == 0)) | ||
615 | return; | ||
616 | |||
617 | if (smi_num) | ||
618 | cost = (aperf - cycles) / aperf * 100.00; | ||
619 | |||
620 | if (cost > 10) | ||
621 | color = PERF_COLOR_RED; | ||
622 | out->print_metric(out->ctx, color, "%8.1f%%", "SMI cycles%", cost); | ||
623 | out->print_metric(out->ctx, NULL, "%4.0f", "SMI#", smi_num); | ||
624 | } | ||
625 | |||
595 | void perf_stat__print_shadow_stats(struct perf_evsel *evsel, | 626 | void perf_stat__print_shadow_stats(struct perf_evsel *evsel, |
596 | double avg, int cpu, | 627 | double avg, int cpu, |
597 | struct perf_stat_output_ctx *out) | 628 | struct perf_stat_output_ctx *out) |
@@ -825,6 +856,8 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, | |||
825 | } | 856 | } |
826 | snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); | 857 | snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); |
827 | print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); | 858 | print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); |
859 | } else if (perf_stat_evsel__is(evsel, SMI_NUM)) { | ||
860 | print_smi_cost(cpu, evsel, out); | ||
828 | } else { | 861 | } else { |
829 | print_metric(ctxp, NULL, NULL, NULL, 0); | 862 | print_metric(ctxp, NULL, NULL, NULL, 0); |
830 | } | 863 | } |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index c58174443dc1..53b9a994a3dc 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
@@ -86,6 +86,8 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { | |||
86 | ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), | 86 | ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), |
87 | ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), | 87 | ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), |
88 | ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), | 88 | ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), |
89 | ID(SMI_NUM, msr/smi/), | ||
90 | ID(APERF, msr/aperf/), | ||
89 | }; | 91 | }; |
90 | #undef ID | 92 | #undef ID |
91 | 93 | ||
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 0a65ae23f495..7522bf10b03e 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h | |||
@@ -22,6 +22,8 @@ enum perf_stat_evsel_id { | |||
22 | PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, | 22 | PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, |
23 | PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, | 23 | PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, |
24 | PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, | 24 | PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, |
25 | PERF_STAT_EVSEL_ID__SMI_NUM, | ||
26 | PERF_STAT_EVSEL_ID__APERF, | ||
25 | PERF_STAT_EVSEL_ID__MAX, | 27 | PERF_STAT_EVSEL_ID__MAX, |
26 | }; | 28 | }; |
27 | 29 | ||
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index 318424ea561d..802d743378af 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <stdarg.h> | 42 | #include <stdarg.h> |
43 | #include <stddef.h> | 43 | #include <stddef.h> |
44 | #include <string.h> | 44 | #include <string.h> |
45 | #include <linux/compiler.h> | ||
45 | #include <sys/types.h> | 46 | #include <sys/types.h> |
46 | 47 | ||
47 | extern char strbuf_slopbuf[]; | 48 | extern char strbuf_slopbuf[]; |
@@ -85,8 +86,7 @@ static inline int strbuf_addstr(struct strbuf *sb, const char *s) { | |||
85 | return strbuf_add(sb, s, strlen(s)); | 86 | return strbuf_add(sb, s, strlen(s)); |
86 | } | 87 | } |
87 | 88 | ||
88 | __attribute__((format(printf,2,3))) | 89 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...) __printf(2, 3); |
89 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...); | ||
90 | 90 | ||
91 | /* XXX: if read fails, any partial read is undone */ | 91 | /* XXX: if read fails, any partial read is undone */ |
92 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); | 92 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index e7ee47f7377a..502505cf236a 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -637,43 +637,6 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata) | |||
637 | return 0; | 637 | return 0; |
638 | } | 638 | } |
639 | 639 | ||
640 | static int decompress_kmodule(struct dso *dso, const char *name, | ||
641 | enum dso_binary_type type) | ||
642 | { | ||
643 | int fd = -1; | ||
644 | char tmpbuf[] = "/tmp/perf-kmod-XXXXXX"; | ||
645 | struct kmod_path m; | ||
646 | |||
647 | if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP && | ||
648 | type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP && | ||
649 | type != DSO_BINARY_TYPE__BUILD_ID_CACHE) | ||
650 | return -1; | ||
651 | |||
652 | if (type == DSO_BINARY_TYPE__BUILD_ID_CACHE) | ||
653 | name = dso->long_name; | ||
654 | |||
655 | if (kmod_path__parse_ext(&m, name) || !m.comp) | ||
656 | return -1; | ||
657 | |||
658 | fd = mkstemp(tmpbuf); | ||
659 | if (fd < 0) { | ||
660 | dso->load_errno = errno; | ||
661 | goto out; | ||
662 | } | ||
663 | |||
664 | if (!decompress_to_file(m.ext, name, fd)) { | ||
665 | dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE; | ||
666 | close(fd); | ||
667 | fd = -1; | ||
668 | } | ||
669 | |||
670 | unlink(tmpbuf); | ||
671 | |||
672 | out: | ||
673 | free(m.ext); | ||
674 | return fd; | ||
675 | } | ||
676 | |||
677 | bool symsrc__possibly_runtime(struct symsrc *ss) | 640 | bool symsrc__possibly_runtime(struct symsrc *ss) |
678 | { | 641 | { |
679 | return ss->dynsym || ss->opdsec; | 642 | return ss->dynsym || ss->opdsec; |
@@ -705,9 +668,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, | |||
705 | int fd; | 668 | int fd; |
706 | 669 | ||
707 | if (dso__needs_decompress(dso)) { | 670 | if (dso__needs_decompress(dso)) { |
708 | fd = decompress_kmodule(dso, name, type); | 671 | fd = dso__decompress_kmodule_fd(dso, name); |
709 | if (fd < 0) | 672 | if (fd < 0) |
710 | return -1; | 673 | return -1; |
674 | |||
675 | type = dso->symtab_type; | ||
711 | } else { | 676 | } else { |
712 | fd = open(name, O_RDONLY); | 677 | fd = open(name, O_RDONLY); |
713 | if (fd < 0) { | 678 | if (fd < 0) { |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8f2b068ff756..e7a98dbd2aed 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1562,10 +1562,6 @@ int dso__load(struct dso *dso, struct map *map) | |||
1562 | if (!runtime_ss && syms_ss) | 1562 | if (!runtime_ss && syms_ss) |
1563 | runtime_ss = syms_ss; | 1563 | runtime_ss = syms_ss; |
1564 | 1564 | ||
1565 | if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE) | ||
1566 | if (dso__build_id_is_kmod(dso, name, PATH_MAX)) | ||
1567 | kmod = true; | ||
1568 | |||
1569 | if (syms_ss) | 1565 | if (syms_ss) |
1570 | ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); | 1566 | ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); |
1571 | else | 1567 | else |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 746bbee645d9..e0a6e9a6a053 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <errno.h> | 24 | #include <errno.h> |
25 | 25 | ||
26 | #include "../perf.h" | 26 | #include "../perf.h" |
27 | #include "util.h" | 27 | #include "debug.h" |
28 | #include "trace-event.h" | 28 | #include "trace-event.h" |
29 | 29 | ||
30 | #include "sane_ctype.h" | 30 | #include "sane_ctype.h" |
@@ -150,7 +150,7 @@ void parse_ftrace_printk(struct pevent *pevent, | |||
150 | while (line) { | 150 | while (line) { |
151 | addr_str = strtok_r(line, ":", &fmt); | 151 | addr_str = strtok_r(line, ":", &fmt); |
152 | if (!addr_str) { | 152 | if (!addr_str) { |
153 | warning("printk format with empty entry"); | 153 | pr_warning("printk format with empty entry"); |
154 | break; | 154 | break; |
155 | } | 155 | } |
156 | addr = strtoull(addr_str, NULL, 16); | 156 | addr = strtoull(addr_str, NULL, 16); |
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index f90e11a555b2..7755a5e0fe5e 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c | |||
@@ -39,6 +39,14 @@ static int __report_module(struct addr_location *al, u64 ip, | |||
39 | return 0; | 39 | return 0; |
40 | 40 | ||
41 | mod = dwfl_addrmodule(ui->dwfl, ip); | 41 | mod = dwfl_addrmodule(ui->dwfl, ip); |
42 | if (mod) { | ||
43 | Dwarf_Addr s; | ||
44 | |||
45 | dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); | ||
46 | if (s != al->map->start) | ||
47 | mod = 0; | ||
48 | } | ||
49 | |||
42 | if (!mod) | 50 | if (!mod) |
43 | mod = dwfl_report_elf(ui->dwfl, dso->short_name, | 51 | mod = dwfl_report_elf(ui->dwfl, dso->short_name, |
44 | dso->long_name, -1, al->map->start, | 52 | dso->long_name, -1, al->map->start, |
@@ -168,12 +176,24 @@ frame_callback(Dwfl_Frame *state, void *arg) | |||
168 | { | 176 | { |
169 | struct unwind_info *ui = arg; | 177 | struct unwind_info *ui = arg; |
170 | Dwarf_Addr pc; | 178 | Dwarf_Addr pc; |
179 | bool isactivation; | ||
171 | 180 | ||
172 | if (!dwfl_frame_pc(state, &pc, NULL)) { | 181 | if (!dwfl_frame_pc(state, &pc, NULL)) { |
173 | pr_err("%s", dwfl_errmsg(-1)); | 182 | pr_err("%s", dwfl_errmsg(-1)); |
174 | return DWARF_CB_ABORT; | 183 | return DWARF_CB_ABORT; |
175 | } | 184 | } |
176 | 185 | ||
186 | // report the module before we query for isactivation | ||
187 | report_module(pc, ui); | ||
188 | |||
189 | if (!dwfl_frame_pc(state, &pc, &isactivation)) { | ||
190 | pr_err("%s", dwfl_errmsg(-1)); | ||
191 | return DWARF_CB_ABORT; | ||
192 | } | ||
193 | |||
194 | if (!isactivation) | ||
195 | --pc; | ||
196 | |||
177 | return entry(pc, ui) || !(--ui->max_stack) ? | 197 | return entry(pc, ui) || !(--ui->max_stack) ? |
178 | DWARF_CB_ABORT : DWARF_CB_OK; | 198 | DWARF_CB_ABORT : DWARF_CB_OK; |
179 | } | 199 | } |
@@ -220,7 +240,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | |||
220 | 240 | ||
221 | err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui); | 241 | err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui); |
222 | 242 | ||
223 | if (err && !ui->max_stack) | 243 | if (err && ui->max_stack != max_stack) |
224 | err = 0; | 244 | err = 0; |
225 | 245 | ||
226 | /* | 246 | /* |
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index f8455bed6e65..672c2ada9357 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c | |||
@@ -692,6 +692,17 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, | |||
692 | 692 | ||
693 | while (!ret && (unw_step(&c) > 0) && i < max_stack) { | 693 | while (!ret && (unw_step(&c) > 0) && i < max_stack) { |
694 | unw_get_reg(&c, UNW_REG_IP, &ips[i]); | 694 | unw_get_reg(&c, UNW_REG_IP, &ips[i]); |
695 | |||
696 | /* | ||
697 | * Decrement the IP for any non-activation frames. | ||
698 | * this is required to properly find the srcline | ||
699 | * for caller frames. | ||
700 | * See also the documentation for dwfl_frame_pc(), | ||
701 | * which this code tries to replicate. | ||
702 | */ | ||
703 | if (unw_is_signal_frame(&c) <= 0) | ||
704 | --ips[i]; | ||
705 | |||
695 | ++i; | 706 | ++i; |
696 | } | 707 | } |
697 | 708 | ||
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index 996046a66fe5..6cc9d9888ce0 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c | |||
@@ -9,75 +9,17 @@ | |||
9 | #include "util.h" | 9 | #include "util.h" |
10 | #include "debug.h" | 10 | #include "debug.h" |
11 | 11 | ||
12 | static void report(const char *prefix, const char *err, va_list params) | 12 | static __noreturn void usage_builtin(const char *err) |
13 | { | ||
14 | char msg[1024]; | ||
15 | vsnprintf(msg, sizeof(msg), err, params); | ||
16 | fprintf(stderr, " %s%s\n", prefix, msg); | ||
17 | } | ||
18 | |||
19 | static NORETURN void usage_builtin(const char *err) | ||
20 | { | 13 | { |
21 | fprintf(stderr, "\n Usage: %s\n", err); | 14 | fprintf(stderr, "\n Usage: %s\n", err); |
22 | exit(129); | 15 | exit(129); |
23 | } | 16 | } |
24 | 17 | ||
25 | static NORETURN void die_builtin(const char *err, va_list params) | ||
26 | { | ||
27 | report(" Fatal: ", err, params); | ||
28 | exit(128); | ||
29 | } | ||
30 | |||
31 | static void error_builtin(const char *err, va_list params) | ||
32 | { | ||
33 | report(" Error: ", err, params); | ||
34 | } | ||
35 | |||
36 | static void warn_builtin(const char *warn, va_list params) | ||
37 | { | ||
38 | report(" Warning: ", warn, params); | ||
39 | } | ||
40 | |||
41 | /* If we are in a dlopen()ed .so write to a global variable would segfault | 18 | /* If we are in a dlopen()ed .so write to a global variable would segfault |
42 | * (ugh), so keep things static. */ | 19 | * (ugh), so keep things static. */ |
43 | static void (*usage_routine)(const char *err) NORETURN = usage_builtin; | 20 | static void (*usage_routine)(const char *err) __noreturn = usage_builtin; |
44 | static void (*error_routine)(const char *err, va_list params) = error_builtin; | ||
45 | static void (*warn_routine)(const char *err, va_list params) = warn_builtin; | ||
46 | |||
47 | void set_warning_routine(void (*routine)(const char *err, va_list params)) | ||
48 | { | ||
49 | warn_routine = routine; | ||
50 | } | ||
51 | 21 | ||
52 | void usage(const char *err) | 22 | void usage(const char *err) |
53 | { | 23 | { |
54 | usage_routine(err); | 24 | usage_routine(err); |
55 | } | 25 | } |
56 | |||
57 | void die(const char *err, ...) | ||
58 | { | ||
59 | va_list params; | ||
60 | |||
61 | va_start(params, err); | ||
62 | die_builtin(err, params); | ||
63 | va_end(params); | ||
64 | } | ||
65 | |||
66 | int error(const char *err, ...) | ||
67 | { | ||
68 | va_list params; | ||
69 | |||
70 | va_start(params, err); | ||
71 | error_routine(err, params); | ||
72 | va_end(params); | ||
73 | return -1; | ||
74 | } | ||
75 | |||
76 | void warning(const char *warn, ...) | ||
77 | { | ||
78 | va_list params; | ||
79 | |||
80 | va_start(params, warn); | ||
81 | warn_routine(warn, params); | ||
82 | va_end(params); | ||
83 | } | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 28c9f335006c..988111e0bab5 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -343,43 +343,6 @@ int perf_event_paranoid(void) | |||
343 | 343 | ||
344 | return value; | 344 | return value; |
345 | } | 345 | } |
346 | |||
347 | bool find_process(const char *name) | ||
348 | { | ||
349 | size_t len = strlen(name); | ||
350 | DIR *dir; | ||
351 | struct dirent *d; | ||
352 | int ret = -1; | ||
353 | |||
354 | dir = opendir(procfs__mountpoint()); | ||
355 | if (!dir) | ||
356 | return false; | ||
357 | |||
358 | /* Walk through the directory. */ | ||
359 | while (ret && (d = readdir(dir)) != NULL) { | ||
360 | char path[PATH_MAX]; | ||
361 | char *data; | ||
362 | size_t size; | ||
363 | |||
364 | if ((d->d_type != DT_DIR) || | ||
365 | !strcmp(".", d->d_name) || | ||
366 | !strcmp("..", d->d_name)) | ||
367 | continue; | ||
368 | |||
369 | scnprintf(path, sizeof(path), "%s/%s/comm", | ||
370 | procfs__mountpoint(), d->d_name); | ||
371 | |||
372 | if (filename__read_str(path, &data, &size)) | ||
373 | continue; | ||
374 | |||
375 | ret = strncmp(name, data, len); | ||
376 | free(data); | ||
377 | } | ||
378 | |||
379 | closedir(dir); | ||
380 | return ret ? false : true; | ||
381 | } | ||
382 | |||
383 | static int | 346 | static int |
384 | fetch_ubuntu_kernel_version(unsigned int *puint) | 347 | fetch_ubuntu_kernel_version(unsigned int *puint) |
385 | { | 348 | { |
@@ -387,8 +350,12 @@ fetch_ubuntu_kernel_version(unsigned int *puint) | |||
387 | size_t line_len = 0; | 350 | size_t line_len = 0; |
388 | char *ptr, *line = NULL; | 351 | char *ptr, *line = NULL; |
389 | int version, patchlevel, sublevel, err; | 352 | int version, patchlevel, sublevel, err; |
390 | FILE *vsig = fopen("/proc/version_signature", "r"); | 353 | FILE *vsig; |
354 | |||
355 | if (!puint) | ||
356 | return 0; | ||
391 | 357 | ||
358 | vsig = fopen("/proc/version_signature", "r"); | ||
392 | if (!vsig) { | 359 | if (!vsig) { |
393 | pr_debug("Open /proc/version_signature failed: %s\n", | 360 | pr_debug("Open /proc/version_signature failed: %s\n", |
394 | strerror(errno)); | 361 | strerror(errno)); |
@@ -418,8 +385,7 @@ fetch_ubuntu_kernel_version(unsigned int *puint) | |||
418 | goto errout; | 385 | goto errout; |
419 | } | 386 | } |
420 | 387 | ||
421 | if (puint) | 388 | *puint = (version << 16) + (patchlevel << 8) + sublevel; |
422 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | ||
423 | err = 0; | 389 | err = 0; |
424 | errout: | 390 | errout: |
425 | free(line); | 391 | free(line); |
@@ -446,6 +412,9 @@ fetch_kernel_version(unsigned int *puint, char *str, | |||
446 | str[str_size - 1] = '\0'; | 412 | str[str_size - 1] = '\0'; |
447 | } | 413 | } |
448 | 414 | ||
415 | if (!puint || int_ver_ready) | ||
416 | return 0; | ||
417 | |||
449 | err = sscanf(utsname.release, "%d.%d.%d", | 418 | err = sscanf(utsname.release, "%d.%d.%d", |
450 | &version, &patchlevel, &sublevel); | 419 | &version, &patchlevel, &sublevel); |
451 | 420 | ||
@@ -455,8 +424,7 @@ fetch_kernel_version(unsigned int *puint, char *str, | |||
455 | return -1; | 424 | return -1; |
456 | } | 425 | } |
457 | 426 | ||
458 | if (puint && !int_ver_ready) | 427 | *puint = (version << 16) + (patchlevel << 8) + sublevel; |
459 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | ||
460 | return 0; | 428 | return 0; |
461 | } | 429 | } |
462 | 430 | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 5dfb9bb6482d..2c9e58a45310 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -1,7 +1,6 @@ | |||
1 | #ifndef GIT_COMPAT_UTIL_H | 1 | #ifndef GIT_COMPAT_UTIL_H |
2 | #define GIT_COMPAT_UTIL_H | 2 | #define GIT_COMPAT_UTIL_H |
3 | 3 | ||
4 | #define _ALL_SOURCE 1 | ||
5 | #define _BSD_SOURCE 1 | 4 | #define _BSD_SOURCE 1 |
6 | /* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ | 5 | /* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ |
7 | #define _DEFAULT_SOURCE 1 | 6 | #define _DEFAULT_SOURCE 1 |
@@ -11,24 +10,12 @@ | |||
11 | #include <stddef.h> | 10 | #include <stddef.h> |
12 | #include <stdlib.h> | 11 | #include <stdlib.h> |
13 | #include <stdarg.h> | 12 | #include <stdarg.h> |
13 | #include <linux/compiler.h> | ||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | 15 | ||
16 | #ifdef __GNUC__ | ||
17 | #define NORETURN __attribute__((__noreturn__)) | ||
18 | #else | ||
19 | #define NORETURN | ||
20 | #ifndef __attribute__ | ||
21 | #define __attribute__(x) | ||
22 | #endif | ||
23 | #endif | ||
24 | |||
25 | /* General helper functions */ | 16 | /* General helper functions */ |
26 | void usage(const char *err) NORETURN; | 17 | void usage(const char *err) __noreturn; |
27 | void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); | 18 | void die(const char *err, ...) __noreturn __printf(1, 2); |
28 | int error(const char *err, ...) __attribute__((format (printf, 1, 2))); | ||
29 | void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); | ||
30 | |||
31 | void set_warning_routine(void (*routine)(const char *err, va_list params)); | ||
32 | 19 | ||
33 | static inline void *zalloc(size_t size) | 20 | static inline void *zalloc(size_t size) |
34 | { | 21 | { |
@@ -57,8 +44,6 @@ int hex2u64(const char *ptr, u64 *val); | |||
57 | extern unsigned int page_size; | 44 | extern unsigned int page_size; |
58 | extern int cacheline_size; | 45 | extern int cacheline_size; |
59 | 46 | ||
60 | bool find_process(const char *name); | ||
61 | |||
62 | int fetch_kernel_version(unsigned int *puint, | 47 | int fetch_kernel_version(unsigned int *puint, |
63 | char *str, size_t str_sz); | 48 | char *str, size_t str_sz); |
64 | #define KVER_VERSION(x) (((x) >> 16) & 0xff) | 49 | #define KVER_VERSION(x) (((x) >> 16) & 0xff) |
diff --git a/tools/power/acpi/.gitignore b/tools/power/acpi/.gitignore new file mode 100644 index 000000000000..cba3d994995c --- /dev/null +++ b/tools/power/acpi/.gitignore | |||
@@ -0,0 +1,4 @@ | |||
1 | acpidbg | ||
2 | acpidump | ||
3 | ec | ||
4 | include | ||
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c index c04e8fea2c60..025c1b07049d 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixxf.c +++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c | |||
@@ -750,9 +750,9 @@ acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 msec_timeout) | |||
750 | { | 750 | { |
751 | acpi_status status = AE_OK; | 751 | acpi_status status = AE_OK; |
752 | sem_t *sem = (sem_t *) handle; | 752 | sem_t *sem = (sem_t *) handle; |
753 | int ret_val; | ||
753 | #ifndef ACPI_USE_ALTERNATE_TIMEOUT | 754 | #ifndef ACPI_USE_ALTERNATE_TIMEOUT |
754 | struct timespec time; | 755 | struct timespec time; |
755 | int ret_val; | ||
756 | #endif | 756 | #endif |
757 | 757 | ||
758 | if (!sem) { | 758 | if (!sem) { |
@@ -778,7 +778,10 @@ acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 msec_timeout) | |||
778 | 778 | ||
779 | case ACPI_WAIT_FOREVER: | 779 | case ACPI_WAIT_FOREVER: |
780 | 780 | ||
781 | if (sem_wait(sem)) { | 781 | while (((ret_val = sem_wait(sem)) == -1) && (errno == EINTR)) { |
782 | continue; /* Restart if interrupted */ | ||
783 | } | ||
784 | if (ret_val != 0) { | ||
782 | status = (AE_TIME); | 785 | status = (AE_TIME); |
783 | } | 786 | } |
784 | break; | 787 | break; |
@@ -831,7 +834,8 @@ acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 msec_timeout) | |||
831 | 834 | ||
832 | while (((ret_val = sem_timedwait(sem, &time)) == -1) | 835 | while (((ret_val = sem_timedwait(sem, &time)) == -1) |
833 | && (errno == EINTR)) { | 836 | && (errno == EINTR)) { |
834 | continue; | 837 | continue; /* Restart if interrupted */ |
838 | |||
835 | } | 839 | } |
836 | 840 | ||
837 | if (ret_val != 0) { | 841 | if (ret_val != 0) { |
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c index 6437ef39aeea..5fd5c5b8c7b8 100644 --- a/tools/power/cpupower/utils/helpers/amd.c +++ b/tools/power/cpupower/utils/helpers/amd.c | |||
@@ -26,6 +26,15 @@ union msr_pstate { | |||
26 | unsigned res3:21; | 26 | unsigned res3:21; |
27 | unsigned en:1; | 27 | unsigned en:1; |
28 | } bits; | 28 | } bits; |
29 | struct { | ||
30 | unsigned fid:8; | ||
31 | unsigned did:6; | ||
32 | unsigned vid:8; | ||
33 | unsigned iddval:8; | ||
34 | unsigned idddiv:2; | ||
35 | unsigned res1:30; | ||
36 | unsigned en:1; | ||
37 | } fam17h_bits; | ||
29 | unsigned long long val; | 38 | unsigned long long val; |
30 | }; | 39 | }; |
31 | 40 | ||
@@ -35,6 +44,8 @@ static int get_did(int family, union msr_pstate pstate) | |||
35 | 44 | ||
36 | if (family == 0x12) | 45 | if (family == 0x12) |
37 | t = pstate.val & 0xf; | 46 | t = pstate.val & 0xf; |
47 | else if (family == 0x17) | ||
48 | t = pstate.fam17h_bits.did; | ||
38 | else | 49 | else |
39 | t = pstate.bits.did; | 50 | t = pstate.bits.did; |
40 | 51 | ||
@@ -44,16 +55,20 @@ static int get_did(int family, union msr_pstate pstate) | |||
44 | static int get_cof(int family, union msr_pstate pstate) | 55 | static int get_cof(int family, union msr_pstate pstate) |
45 | { | 56 | { |
46 | int t; | 57 | int t; |
47 | int fid, did; | 58 | int fid, did, cof; |
48 | 59 | ||
49 | did = get_did(family, pstate); | 60 | did = get_did(family, pstate); |
50 | 61 | if (family == 0x17) { | |
51 | t = 0x10; | 62 | fid = pstate.fam17h_bits.fid; |
52 | fid = pstate.bits.fid; | 63 | cof = 200 * fid / did; |
53 | if (family == 0x11) | 64 | } else { |
54 | t = 0x8; | 65 | t = 0x10; |
55 | 66 | fid = pstate.bits.fid; | |
56 | return (100 * (fid + t)) >> did; | 67 | if (family == 0x11) |
68 | t = 0x8; | ||
69 | cof = (100 * (fid + t)) >> did; | ||
70 | } | ||
71 | return cof; | ||
57 | } | 72 | } |
58 | 73 | ||
59 | /* Needs: | 74 | /* Needs: |
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index afb66f80554e..799a18be60aa 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -70,6 +70,8 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL, | |||
70 | #define CPUPOWER_CAP_IS_SNB 0x00000020 | 70 | #define CPUPOWER_CAP_IS_SNB 0x00000020 |
71 | #define CPUPOWER_CAP_INTEL_IDA 0x00000040 | 71 | #define CPUPOWER_CAP_INTEL_IDA 0x00000040 |
72 | 72 | ||
73 | #define CPUPOWER_AMD_CPBDIS 0x02000000 | ||
74 | |||
73 | #define MAX_HW_PSTATES 10 | 75 | #define MAX_HW_PSTATES 10 |
74 | 76 | ||
75 | struct cpupower_cpu_info { | 77 | struct cpupower_cpu_info { |
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c index 1609243f5c64..601d719d4e60 100644 --- a/tools/power/cpupower/utils/helpers/misc.c +++ b/tools/power/cpupower/utils/helpers/misc.c | |||
@@ -2,11 +2,14 @@ | |||
2 | 2 | ||
3 | #include "helpers/helpers.h" | 3 | #include "helpers/helpers.h" |
4 | 4 | ||
5 | #define MSR_AMD_HWCR 0xc0010015 | ||
6 | |||
5 | int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, | 7 | int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, |
6 | int *states) | 8 | int *states) |
7 | { | 9 | { |
8 | struct cpupower_cpu_info cpu_info; | 10 | struct cpupower_cpu_info cpu_info; |
9 | int ret; | 11 | int ret; |
12 | unsigned long long val; | ||
10 | 13 | ||
11 | *support = *active = *states = 0; | 14 | *support = *active = *states = 0; |
12 | 15 | ||
@@ -16,10 +19,22 @@ int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, | |||
16 | 19 | ||
17 | if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) { | 20 | if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) { |
18 | *support = 1; | 21 | *support = 1; |
19 | amd_pci_get_num_boost_states(active, states); | 22 | |
20 | if (ret <= 0) | 23 | /* AMD Family 0x17 does not utilize PCI D18F4 like prior |
21 | return ret; | 24 | * families and has no fixed discrete boost states but |
22 | *support = 1; | 25 | * has Hardware determined variable increments instead. |
26 | */ | ||
27 | |||
28 | if (cpu_info.family == 0x17) { | ||
29 | if (!read_msr(cpu, MSR_AMD_HWCR, &val)) { | ||
30 | if (!(val & CPUPOWER_AMD_CPBDIS)) | ||
31 | *active = 1; | ||
32 | } | ||
33 | } else { | ||
34 | ret = amd_pci_get_num_boost_states(active, states); | ||
35 | if (ret) | ||
36 | return ret; | ||
37 | } | ||
23 | } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA) | 38 | } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA) |
24 | *support = *active = 1; | 39 | *support = *active = 1; |
25 | return 0; | 40 | return 0; |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index b11294730771..0dafba2c1e7d 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -57,7 +57,6 @@ unsigned int list_header_only; | |||
57 | unsigned int dump_only; | 57 | unsigned int dump_only; |
58 | unsigned int do_snb_cstates; | 58 | unsigned int do_snb_cstates; |
59 | unsigned int do_knl_cstates; | 59 | unsigned int do_knl_cstates; |
60 | unsigned int do_skl_residency; | ||
61 | unsigned int do_slm_cstates; | 60 | unsigned int do_slm_cstates; |
62 | unsigned int use_c1_residency_msr; | 61 | unsigned int use_c1_residency_msr; |
63 | unsigned int has_aperf; | 62 | unsigned int has_aperf; |
@@ -93,6 +92,7 @@ unsigned int do_ring_perf_limit_reasons; | |||
93 | unsigned int crystal_hz; | 92 | unsigned int crystal_hz; |
94 | unsigned long long tsc_hz; | 93 | unsigned long long tsc_hz; |
95 | int base_cpu; | 94 | int base_cpu; |
95 | int do_migrate; | ||
96 | double discover_bclk(unsigned int family, unsigned int model); | 96 | double discover_bclk(unsigned int family, unsigned int model); |
97 | unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */ | 97 | unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */ |
98 | /* IA32_HWP_REQUEST, IA32_HWP_STATUS */ | 98 | /* IA32_HWP_REQUEST, IA32_HWP_STATUS */ |
@@ -151,6 +151,8 @@ size_t cpu_present_setsize, cpu_affinity_setsize, cpu_subset_size; | |||
151 | #define MAX_ADDED_COUNTERS 16 | 151 | #define MAX_ADDED_COUNTERS 16 |
152 | 152 | ||
153 | struct thread_data { | 153 | struct thread_data { |
154 | struct timeval tv_begin; | ||
155 | struct timeval tv_end; | ||
154 | unsigned long long tsc; | 156 | unsigned long long tsc; |
155 | unsigned long long aperf; | 157 | unsigned long long aperf; |
156 | unsigned long long mperf; | 158 | unsigned long long mperf; |
@@ -301,6 +303,9 @@ int for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg | |||
301 | 303 | ||
302 | int cpu_migrate(int cpu) | 304 | int cpu_migrate(int cpu) |
303 | { | 305 | { |
306 | if (!do_migrate) | ||
307 | return 0; | ||
308 | |||
304 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); | 309 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); |
305 | CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set); | 310 | CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set); |
306 | if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1) | 311 | if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1) |
@@ -384,8 +389,14 @@ struct msr_counter bic[] = { | |||
384 | { 0x0, "CPU" }, | 389 | { 0x0, "CPU" }, |
385 | { 0x0, "Mod%c6" }, | 390 | { 0x0, "Mod%c6" }, |
386 | { 0x0, "sysfs" }, | 391 | { 0x0, "sysfs" }, |
392 | { 0x0, "Totl%C0" }, | ||
393 | { 0x0, "Any%C0" }, | ||
394 | { 0x0, "GFX%C0" }, | ||
395 | { 0x0, "CPUGFX%" }, | ||
387 | }; | 396 | }; |
388 | 397 | ||
398 | |||
399 | |||
389 | #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) | 400 | #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) |
390 | #define BIC_Package (1ULL << 0) | 401 | #define BIC_Package (1ULL << 0) |
391 | #define BIC_Avg_MHz (1ULL << 1) | 402 | #define BIC_Avg_MHz (1ULL << 1) |
@@ -426,6 +437,10 @@ struct msr_counter bic[] = { | |||
426 | #define BIC_CPU (1ULL << 36) | 437 | #define BIC_CPU (1ULL << 36) |
427 | #define BIC_Mod_c6 (1ULL << 37) | 438 | #define BIC_Mod_c6 (1ULL << 37) |
428 | #define BIC_sysfs (1ULL << 38) | 439 | #define BIC_sysfs (1ULL << 38) |
440 | #define BIC_Totl_c0 (1ULL << 39) | ||
441 | #define BIC_Any_c0 (1ULL << 40) | ||
442 | #define BIC_GFX_c0 (1ULL << 41) | ||
443 | #define BIC_CPUGFX (1ULL << 42) | ||
429 | 444 | ||
430 | unsigned long long bic_enabled = 0xFFFFFFFFFFFFFFFFULL; | 445 | unsigned long long bic_enabled = 0xFFFFFFFFFFFFFFFFULL; |
431 | unsigned long long bic_present = BIC_sysfs; | 446 | unsigned long long bic_present = BIC_sysfs; |
@@ -521,6 +536,8 @@ void print_header(char *delim) | |||
521 | struct msr_counter *mp; | 536 | struct msr_counter *mp; |
522 | int printed = 0; | 537 | int printed = 0; |
523 | 538 | ||
539 | if (debug) | ||
540 | outp += sprintf(outp, "usec %s", delim); | ||
524 | if (DO_BIC(BIC_Package)) | 541 | if (DO_BIC(BIC_Package)) |
525 | outp += sprintf(outp, "%sPackage", (printed++ ? delim : "")); | 542 | outp += sprintf(outp, "%sPackage", (printed++ ? delim : "")); |
526 | if (DO_BIC(BIC_Core)) | 543 | if (DO_BIC(BIC_Core)) |
@@ -599,12 +616,14 @@ void print_header(char *delim) | |||
599 | if (DO_BIC(BIC_GFXMHz)) | 616 | if (DO_BIC(BIC_GFXMHz)) |
600 | outp += sprintf(outp, "%sGFXMHz", (printed++ ? delim : "")); | 617 | outp += sprintf(outp, "%sGFXMHz", (printed++ ? delim : "")); |
601 | 618 | ||
602 | if (do_skl_residency) { | 619 | if (DO_BIC(BIC_Totl_c0)) |
603 | outp += sprintf(outp, "%sTotl%%C0", (printed++ ? delim : "")); | 620 | outp += sprintf(outp, "%sTotl%%C0", (printed++ ? delim : "")); |
621 | if (DO_BIC(BIC_Any_c0)) | ||
604 | outp += sprintf(outp, "%sAny%%C0", (printed++ ? delim : "")); | 622 | outp += sprintf(outp, "%sAny%%C0", (printed++ ? delim : "")); |
623 | if (DO_BIC(BIC_GFX_c0)) | ||
605 | outp += sprintf(outp, "%sGFX%%C0", (printed++ ? delim : "")); | 624 | outp += sprintf(outp, "%sGFX%%C0", (printed++ ? delim : "")); |
625 | if (DO_BIC(BIC_CPUGFX)) | ||
606 | outp += sprintf(outp, "%sCPUGFX%%", (printed++ ? delim : "")); | 626 | outp += sprintf(outp, "%sCPUGFX%%", (printed++ ? delim : "")); |
607 | } | ||
608 | 627 | ||
609 | if (DO_BIC(BIC_Pkgpc2)) | 628 | if (DO_BIC(BIC_Pkgpc2)) |
610 | outp += sprintf(outp, "%sPkg%%pc2", (printed++ ? delim : "")); | 629 | outp += sprintf(outp, "%sPkg%%pc2", (printed++ ? delim : "")); |
@@ -771,6 +790,14 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
771 | (cpu_subset && !CPU_ISSET_S(t->cpu_id, cpu_subset_size, cpu_subset))) | 790 | (cpu_subset && !CPU_ISSET_S(t->cpu_id, cpu_subset_size, cpu_subset))) |
772 | return 0; | 791 | return 0; |
773 | 792 | ||
793 | if (debug) { | ||
794 | /* on each row, print how many usec each timestamp took to gather */ | ||
795 | struct timeval tv; | ||
796 | |||
797 | timersub(&t->tv_end, &t->tv_begin, &tv); | ||
798 | outp += sprintf(outp, "%5ld\t", tv.tv_sec * 1000000 + tv.tv_usec); | ||
799 | } | ||
800 | |||
774 | interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0; | 801 | interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0; |
775 | 802 | ||
776 | tsc = t->tsc * tsc_tweak; | 803 | tsc = t->tsc * tsc_tweak; |
@@ -912,12 +939,14 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
912 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->gfx_mhz); | 939 | outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->gfx_mhz); |
913 | 940 | ||
914 | /* Totl%C0, Any%C0 GFX%C0 CPUGFX% */ | 941 | /* Totl%C0, Any%C0 GFX%C0 CPUGFX% */ |
915 | if (do_skl_residency) { | 942 | if (DO_BIC(BIC_Totl_c0)) |
916 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_wtd_core_c0/tsc); | 943 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_wtd_core_c0/tsc); |
944 | if (DO_BIC(BIC_Any_c0)) | ||
917 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_core_c0/tsc); | 945 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_core_c0/tsc); |
946 | if (DO_BIC(BIC_GFX_c0)) | ||
918 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_gfxe_c0/tsc); | 947 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_any_gfxe_c0/tsc); |
948 | if (DO_BIC(BIC_CPUGFX)) | ||
919 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_both_core_gfxe_c0/tsc); | 949 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pkg_both_core_gfxe_c0/tsc); |
920 | } | ||
921 | 950 | ||
922 | if (DO_BIC(BIC_Pkgpc2)) | 951 | if (DO_BIC(BIC_Pkgpc2)) |
923 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc2/tsc); | 952 | outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->pc2/tsc); |
@@ -1038,12 +1067,16 @@ delta_package(struct pkg_data *new, struct pkg_data *old) | |||
1038 | int i; | 1067 | int i; |
1039 | struct msr_counter *mp; | 1068 | struct msr_counter *mp; |
1040 | 1069 | ||
1041 | if (do_skl_residency) { | 1070 | |
1071 | if (DO_BIC(BIC_Totl_c0)) | ||
1042 | old->pkg_wtd_core_c0 = new->pkg_wtd_core_c0 - old->pkg_wtd_core_c0; | 1072 | old->pkg_wtd_core_c0 = new->pkg_wtd_core_c0 - old->pkg_wtd_core_c0; |
1073 | if (DO_BIC(BIC_Any_c0)) | ||
1043 | old->pkg_any_core_c0 = new->pkg_any_core_c0 - old->pkg_any_core_c0; | 1074 | old->pkg_any_core_c0 = new->pkg_any_core_c0 - old->pkg_any_core_c0; |
1075 | if (DO_BIC(BIC_GFX_c0)) | ||
1044 | old->pkg_any_gfxe_c0 = new->pkg_any_gfxe_c0 - old->pkg_any_gfxe_c0; | 1076 | old->pkg_any_gfxe_c0 = new->pkg_any_gfxe_c0 - old->pkg_any_gfxe_c0; |
1077 | if (DO_BIC(BIC_CPUGFX)) | ||
1045 | old->pkg_both_core_gfxe_c0 = new->pkg_both_core_gfxe_c0 - old->pkg_both_core_gfxe_c0; | 1078 | old->pkg_both_core_gfxe_c0 = new->pkg_both_core_gfxe_c0 - old->pkg_both_core_gfxe_c0; |
1046 | } | 1079 | |
1047 | old->pc2 = new->pc2 - old->pc2; | 1080 | old->pc2 = new->pc2 - old->pc2; |
1048 | if (DO_BIC(BIC_Pkgpc3)) | 1081 | if (DO_BIC(BIC_Pkgpc3)) |
1049 | old->pc3 = new->pc3 - old->pc3; | 1082 | old->pc3 = new->pc3 - old->pc3; |
@@ -1292,12 +1325,14 @@ int sum_counters(struct thread_data *t, struct core_data *c, | |||
1292 | if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) | 1325 | if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) |
1293 | return 0; | 1326 | return 0; |
1294 | 1327 | ||
1295 | if (do_skl_residency) { | 1328 | if (DO_BIC(BIC_Totl_c0)) |
1296 | average.packages.pkg_wtd_core_c0 += p->pkg_wtd_core_c0; | 1329 | average.packages.pkg_wtd_core_c0 += p->pkg_wtd_core_c0; |
1330 | if (DO_BIC(BIC_Any_c0)) | ||
1297 | average.packages.pkg_any_core_c0 += p->pkg_any_core_c0; | 1331 | average.packages.pkg_any_core_c0 += p->pkg_any_core_c0; |
1332 | if (DO_BIC(BIC_GFX_c0)) | ||
1298 | average.packages.pkg_any_gfxe_c0 += p->pkg_any_gfxe_c0; | 1333 | average.packages.pkg_any_gfxe_c0 += p->pkg_any_gfxe_c0; |
1334 | if (DO_BIC(BIC_CPUGFX)) | ||
1299 | average.packages.pkg_both_core_gfxe_c0 += p->pkg_both_core_gfxe_c0; | 1335 | average.packages.pkg_both_core_gfxe_c0 += p->pkg_both_core_gfxe_c0; |
1300 | } | ||
1301 | 1336 | ||
1302 | average.packages.pc2 += p->pc2; | 1337 | average.packages.pc2 += p->pc2; |
1303 | if (DO_BIC(BIC_Pkgpc3)) | 1338 | if (DO_BIC(BIC_Pkgpc3)) |
@@ -1357,12 +1392,14 @@ void compute_average(struct thread_data *t, struct core_data *c, | |||
1357 | average.cores.c7 /= topo.num_cores; | 1392 | average.cores.c7 /= topo.num_cores; |
1358 | average.cores.mc6_us /= topo.num_cores; | 1393 | average.cores.mc6_us /= topo.num_cores; |
1359 | 1394 | ||
1360 | if (do_skl_residency) { | 1395 | if (DO_BIC(BIC_Totl_c0)) |
1361 | average.packages.pkg_wtd_core_c0 /= topo.num_packages; | 1396 | average.packages.pkg_wtd_core_c0 /= topo.num_packages; |
1397 | if (DO_BIC(BIC_Any_c0)) | ||
1362 | average.packages.pkg_any_core_c0 /= topo.num_packages; | 1398 | average.packages.pkg_any_core_c0 /= topo.num_packages; |
1399 | if (DO_BIC(BIC_GFX_c0)) | ||
1363 | average.packages.pkg_any_gfxe_c0 /= topo.num_packages; | 1400 | average.packages.pkg_any_gfxe_c0 /= topo.num_packages; |
1401 | if (DO_BIC(BIC_CPUGFX)) | ||
1364 | average.packages.pkg_both_core_gfxe_c0 /= topo.num_packages; | 1402 | average.packages.pkg_both_core_gfxe_c0 /= topo.num_packages; |
1365 | } | ||
1366 | 1403 | ||
1367 | average.packages.pc2 /= topo.num_packages; | 1404 | average.packages.pc2 /= topo.num_packages; |
1368 | if (DO_BIC(BIC_Pkgpc3)) | 1405 | if (DO_BIC(BIC_Pkgpc3)) |
@@ -1482,6 +1519,9 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |||
1482 | struct msr_counter *mp; | 1519 | struct msr_counter *mp; |
1483 | int i; | 1520 | int i; |
1484 | 1521 | ||
1522 | |||
1523 | gettimeofday(&t->tv_begin, (struct timezone *)NULL); | ||
1524 | |||
1485 | if (cpu_migrate(cpu)) { | 1525 | if (cpu_migrate(cpu)) { |
1486 | fprintf(outf, "Could not migrate to CPU %d\n", cpu); | 1526 | fprintf(outf, "Could not migrate to CPU %d\n", cpu); |
1487 | return -1; | 1527 | return -1; |
@@ -1565,7 +1605,7 @@ retry: | |||
1565 | 1605 | ||
1566 | /* collect core counters only for 1st thread in core */ | 1606 | /* collect core counters only for 1st thread in core */ |
1567 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) | 1607 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) |
1568 | return 0; | 1608 | goto done; |
1569 | 1609 | ||
1570 | if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates) { | 1610 | if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates) { |
1571 | if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3)) | 1611 | if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3)) |
@@ -1601,15 +1641,21 @@ retry: | |||
1601 | 1641 | ||
1602 | /* collect package counters only for 1st core in package */ | 1642 | /* collect package counters only for 1st core in package */ |
1603 | if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) | 1643 | if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) |
1604 | return 0; | 1644 | goto done; |
1605 | 1645 | ||
1606 | if (do_skl_residency) { | 1646 | if (DO_BIC(BIC_Totl_c0)) { |
1607 | if (get_msr(cpu, MSR_PKG_WEIGHTED_CORE_C0_RES, &p->pkg_wtd_core_c0)) | 1647 | if (get_msr(cpu, MSR_PKG_WEIGHTED_CORE_C0_RES, &p->pkg_wtd_core_c0)) |
1608 | return -10; | 1648 | return -10; |
1649 | } | ||
1650 | if (DO_BIC(BIC_Any_c0)) { | ||
1609 | if (get_msr(cpu, MSR_PKG_ANY_CORE_C0_RES, &p->pkg_any_core_c0)) | 1651 | if (get_msr(cpu, MSR_PKG_ANY_CORE_C0_RES, &p->pkg_any_core_c0)) |
1610 | return -11; | 1652 | return -11; |
1653 | } | ||
1654 | if (DO_BIC(BIC_GFX_c0)) { | ||
1611 | if (get_msr(cpu, MSR_PKG_ANY_GFXE_C0_RES, &p->pkg_any_gfxe_c0)) | 1655 | if (get_msr(cpu, MSR_PKG_ANY_GFXE_C0_RES, &p->pkg_any_gfxe_c0)) |
1612 | return -12; | 1656 | return -12; |
1657 | } | ||
1658 | if (DO_BIC(BIC_CPUGFX)) { | ||
1613 | if (get_msr(cpu, MSR_PKG_BOTH_CORE_GFXE_C0_RES, &p->pkg_both_core_gfxe_c0)) | 1659 | if (get_msr(cpu, MSR_PKG_BOTH_CORE_GFXE_C0_RES, &p->pkg_both_core_gfxe_c0)) |
1614 | return -13; | 1660 | return -13; |
1615 | } | 1661 | } |
@@ -1688,6 +1734,8 @@ retry: | |||
1688 | if (get_mp(cpu, mp, &p->counter[i])) | 1734 | if (get_mp(cpu, mp, &p->counter[i])) |
1689 | return -10; | 1735 | return -10; |
1690 | } | 1736 | } |
1737 | done: | ||
1738 | gettimeofday(&t->tv_end, (struct timezone *)NULL); | ||
1691 | 1739 | ||
1692 | return 0; | 1740 | return 0; |
1693 | } | 1741 | } |
@@ -3895,6 +3943,9 @@ void decode_misc_enable_msr(void) | |||
3895 | { | 3943 | { |
3896 | unsigned long long msr; | 3944 | unsigned long long msr; |
3897 | 3945 | ||
3946 | if (!genuine_intel) | ||
3947 | return; | ||
3948 | |||
3898 | if (!get_msr(base_cpu, MSR_IA32_MISC_ENABLE, &msr)) | 3949 | if (!get_msr(base_cpu, MSR_IA32_MISC_ENABLE, &msr)) |
3899 | fprintf(outf, "cpu%d: MSR_IA32_MISC_ENABLE: 0x%08llx (%sTCC %sEIST %sMWAIT %sPREFETCH %sTURBO)\n", | 3950 | fprintf(outf, "cpu%d: MSR_IA32_MISC_ENABLE: 0x%08llx (%sTCC %sEIST %sMWAIT %sPREFETCH %sTURBO)\n", |
3900 | base_cpu, msr, | 3951 | base_cpu, msr, |
@@ -4198,7 +4249,12 @@ void process_cpuid() | |||
4198 | BIC_PRESENT(BIC_Pkgpc10); | 4249 | BIC_PRESENT(BIC_Pkgpc10); |
4199 | } | 4250 | } |
4200 | do_irtl_hsw = has_hsw_msrs(family, model); | 4251 | do_irtl_hsw = has_hsw_msrs(family, model); |
4201 | do_skl_residency = has_skl_msrs(family, model); | 4252 | if (has_skl_msrs(family, model)) { |
4253 | BIC_PRESENT(BIC_Totl_c0); | ||
4254 | BIC_PRESENT(BIC_Any_c0); | ||
4255 | BIC_PRESENT(BIC_GFX_c0); | ||
4256 | BIC_PRESENT(BIC_CPUGFX); | ||
4257 | } | ||
4202 | do_slm_cstates = is_slm(family, model); | 4258 | do_slm_cstates = is_slm(family, model); |
4203 | do_knl_cstates = is_knl(family, model); | 4259 | do_knl_cstates = is_knl(family, model); |
4204 | 4260 | ||
@@ -4578,7 +4634,7 @@ int get_and_dump_counters(void) | |||
4578 | } | 4634 | } |
4579 | 4635 | ||
4580 | void print_version() { | 4636 | void print_version() { |
4581 | fprintf(outf, "turbostat version 17.04.12" | 4637 | fprintf(outf, "turbostat version 17.06.23" |
4582 | " - Len Brown <lenb@kernel.org>\n"); | 4638 | " - Len Brown <lenb@kernel.org>\n"); |
4583 | } | 4639 | } |
4584 | 4640 | ||
@@ -4951,6 +5007,7 @@ void cmdline(int argc, char **argv) | |||
4951 | {"hide", required_argument, 0, 'H'}, // meh, -h taken by --help | 5007 | {"hide", required_argument, 0, 'H'}, // meh, -h taken by --help |
4952 | {"Joules", no_argument, 0, 'J'}, | 5008 | {"Joules", no_argument, 0, 'J'}, |
4953 | {"list", no_argument, 0, 'l'}, | 5009 | {"list", no_argument, 0, 'l'}, |
5010 | {"migrate", no_argument, 0, 'm'}, | ||
4954 | {"out", required_argument, 0, 'o'}, | 5011 | {"out", required_argument, 0, 'o'}, |
4955 | {"quiet", no_argument, 0, 'q'}, | 5012 | {"quiet", no_argument, 0, 'q'}, |
4956 | {"show", required_argument, 0, 's'}, | 5013 | {"show", required_argument, 0, 's'}, |
@@ -4962,7 +5019,7 @@ void cmdline(int argc, char **argv) | |||
4962 | 5019 | ||
4963 | progname = argv[0]; | 5020 | progname = argv[0]; |
4964 | 5021 | ||
4965 | while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:o:qST:v", | 5022 | while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:Jmo:qST:v", |
4966 | long_options, &option_index)) != -1) { | 5023 | long_options, &option_index)) != -1) { |
4967 | switch (opt) { | 5024 | switch (opt) { |
4968 | case 'a': | 5025 | case 'a': |
@@ -5005,6 +5062,9 @@ void cmdline(int argc, char **argv) | |||
5005 | list_header_only++; | 5062 | list_header_only++; |
5006 | quiet++; | 5063 | quiet++; |
5007 | break; | 5064 | break; |
5065 | case 'm': | ||
5066 | do_migrate = 1; | ||
5067 | break; | ||
5008 | case 'o': | 5068 | case 'o': |
5009 | outf = fopen_or_die(optarg, "w"); | 5069 | outf = fopen_or_die(optarg, "w"); |
5010 | break; | 5070 | break; |
diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile index 971c9ffdcb50..a711eec0c895 100644 --- a/tools/power/x86/x86_energy_perf_policy/Makefile +++ b/tools/power/x86/x86_energy_perf_policy/Makefile | |||
@@ -1,10 +1,27 @@ | |||
1 | DESTDIR ?= | 1 | CC = $(CROSS_COMPILE)gcc |
2 | BUILD_OUTPUT := $(CURDIR) | ||
3 | PREFIX := /usr | ||
4 | DESTDIR := | ||
5 | |||
6 | ifeq ("$(origin O)", "command line") | ||
7 | BUILD_OUTPUT := $(O) | ||
8 | endif | ||
2 | 9 | ||
3 | x86_energy_perf_policy : x86_energy_perf_policy.c | 10 | x86_energy_perf_policy : x86_energy_perf_policy.c |
11 | CFLAGS += -Wall | ||
12 | CFLAGS += -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"' | ||
13 | |||
14 | %: %.c | ||
15 | @mkdir -p $(BUILD_OUTPUT) | ||
16 | $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ | ||
4 | 17 | ||
18 | .PHONY : clean | ||
5 | clean : | 19 | clean : |
6 | rm -f x86_energy_perf_policy | 20 | @rm -f $(BUILD_OUTPUT)/x86_energy_perf_policy |
21 | |||
22 | install : x86_energy_perf_policy | ||
23 | install -d $(DESTDIR)$(PREFIX)/bin | ||
24 | install $(BUILD_OUTPUT)/x86_energy_perf_policy $(DESTDIR)$(PREFIX)/bin/x86_energy_perf_policy | ||
25 | install -d $(DESTDIR)$(PREFIX)/share/man/man8 | ||
26 | install x86_energy_perf_policy.8 $(DESTDIR)$(PREFIX)/share/man/man8 | ||
7 | 27 | ||
8 | install : | ||
9 | install x86_energy_perf_policy ${DESTDIR}/usr/bin/ | ||
10 | install x86_energy_perf_policy.8 ${DESTDIR}/usr/share/man/man8/ | ||
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 index 8eaaad648cdb..17db1c3af4d0 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 | |||
@@ -1,104 +1,213 @@ | |||
1 | .\" This page Copyright (C) 2010 Len Brown <len.brown@intel.com> | 1 | .\" This page Copyright (C) 2010 - 2015 Len Brown <len.brown@intel.com> |
2 | .\" Distributed under the GPL, Copyleft 1994. | 2 | .\" Distributed under the GPL, Copyleft 1994. |
3 | .TH X86_ENERGY_PERF_POLICY 8 | 3 | .TH X86_ENERGY_PERF_POLICY 8 |
4 | .SH NAME | 4 | .SH NAME |
5 | x86_energy_perf_policy \- read or write MSR_IA32_ENERGY_PERF_BIAS | 5 | x86_energy_perf_policy \- Manage Energy vs. Performance Policy via x86 Model Specific Registers |
6 | .SH SYNOPSIS | 6 | .SH SYNOPSIS |
7 | .ft B | ||
8 | .B x86_energy_perf_policy | 7 | .B x86_energy_perf_policy |
9 | .RB [ "\-c cpu" ] | 8 | .RB "[ options ] [ scope ] [field \ value]" |
10 | .RB [ "\-v" ] | ||
11 | .RB "\-r" | ||
12 | .br | 9 | .br |
13 | .B x86_energy_perf_policy | 10 | .RB "scope: \-\-cpu\ cpu-list | \-\-pkg\ pkg-list" |
14 | .RB [ "\-c cpu" ] | ||
15 | .RB [ "\-v" ] | ||
16 | .RB 'performance' | ||
17 | .br | 11 | .br |
18 | .B x86_energy_perf_policy | 12 | .RB "cpu-list, pkg-list: # | #,# | #-# | all" |
19 | .RB [ "\-c cpu" ] | ||
20 | .RB [ "\-v" ] | ||
21 | .RB 'normal' | ||
22 | .br | 13 | .br |
23 | .B x86_energy_perf_policy | 14 | .RB "field: \-\-all | \-\-epb | \-\-hwp-epp | \-\-hwp-min | \-\-hwp-max | \-\-hwp-desired" |
24 | .RB [ "\-c cpu" ] | ||
25 | .RB [ "\-v" ] | ||
26 | .RB 'powersave' | ||
27 | .br | 15 | .br |
28 | .B x86_energy_perf_policy | 16 | .RB "other: (\-\-force | \-\-hwp-enable | \-\-turbo-enable) value)" |
29 | .RB [ "\-c cpu" ] | ||
30 | .RB [ "\-v" ] | ||
31 | .RB n | ||
32 | .br | 17 | .br |
18 | .RB "value: # | default | performance | balance-performance | balance-power | power" | ||
33 | .SH DESCRIPTION | 19 | .SH DESCRIPTION |
34 | \fBx86_energy_perf_policy\fP | 20 | \fBx86_energy_perf_policy\fP |
35 | allows software to convey | 21 | displays and updates energy-performance policy settings specific to |
36 | its policy for the relative importance of performance | 22 | Intel Architecture Processors. Settings are accessed via Model Specific Register (MSR) |
37 | versus energy savings to the processor. | 23 | updates, no matter if the Linux cpufreq sub-system is enabled or not. |
38 | 24 | ||
39 | The processor uses this information in model-specific ways | 25 | Policy in MSR_IA32_ENERGY_PERF_BIAS (EPB) |
40 | when it must select trade-offs between performance and | 26 | may affect a wide range of hardware decisions, |
41 | energy efficiency. | 27 | such as how aggressively the hardware enters and exits CPU idle states (C-states) |
28 | and Processor Performance States (P-states). | ||
29 | This policy hint does not replace explicit OS C-state and P-state selection. | ||
30 | Rather, it tells the hardware how aggressively to implement those selections. | ||
31 | Further, it allows the OS to influence energy/performance trade-offs where there | ||
32 | is no software interface, such as in the opportunistic "turbo-mode" P-state range. | ||
33 | Note that MSR_IA32_ENERGY_PERF_BIAS is defined per CPU, | ||
34 | but some implementations | ||
35 | share a single MSR among all CPUs in each processor package. | ||
36 | On those systems, a write to EPB on one processor will | ||
37 | be visible, and will have an effect, on all CPUs | ||
38 | in the same processor package. | ||
42 | 39 | ||
43 | This policy hint does not supersede Processor Performance states | 40 | Hardware P-States (HWP) are effectively an expansion of hardware |
44 | (P-states) or CPU Idle power states (C-states), but allows | 41 | P-state control from the opportunistic turbo-mode P-state range |
45 | software to have influence where it would otherwise be unable | 42 | to include the entire range of available P-states. |
46 | to express a preference. | 43 | On Broadwell Xeon, the initial HWP implementation, EBP influenced HWP. |
44 | That influence was removed in subsequent generations, | ||
45 | where it was moved to the | ||
46 | Energy_Performance_Preference (EPP) field in | ||
47 | a pair of dedicated MSRs -- MSR_IA32_HWP_REQUEST and MSR_IA32_HWP_REQUEST_PKG. | ||
47 | 48 | ||
48 | For example, this setting may tell the hardware how | 49 | EPP is the most commonly managed knob in HWP mode, |
49 | aggressively or conservatively to control frequency | 50 | but MSR_IA32_HWP_REQUEST also allows the user to specify |
50 | in the "turbo range" above the explicitly OS-controlled | 51 | minimum-frequency for Quality-of-Service, |
51 | P-state frequency range. It may also tell the hardware | 52 | and maximum-frequency for power-capping. |
52 | how aggressively is should enter the OS requested C-states. | 53 | MSR_IA32_HWP_REQUEST is defined per-CPU. |
53 | 54 | ||
54 | Support for this feature is indicated by CPUID.06H.ECX.bit3 | 55 | MSR_IA32_HWP_REQUEST_PKG has the same capability as MSR_IA32_HWP_REQUEST, |
55 | per the Intel Architectures Software Developer's Manual. | 56 | but it can simultaneously set the default policy for all CPUs within a package. |
57 | A bit in per-CPU MSR_IA32_HWP_REQUEST indicates whether it is | ||
58 | over-ruled-by or exempt-from MSR_IA32_HWP_REQUEST_PKG. | ||
56 | 59 | ||
57 | .SS Options | 60 | MSR_HWP_CAPABILITIES shows the default values for the fields |
58 | \fB-c\fP limits operation to a single CPU. | 61 | in MSR_IA32_HWP_REQUEST. It is displayed when no values |
59 | The default is to operate on all CPUs. | 62 | are being written. |
60 | Note that MSR_IA32_ENERGY_PERF_BIAS is defined per | 63 | |
61 | logical processor, but that the initial implementations | 64 | .SS SCOPE OPTIONS |
62 | of the MSR were shared among all processors in each package. | ||
63 | .PP | ||
64 | \fB-v\fP increases verbosity. By default | ||
65 | x86_energy_perf_policy is silent. | ||
66 | .PP | ||
67 | \fB-r\fP is for "read-only" mode - the unchanged state | ||
68 | is read and displayed. | ||
69 | .PP | 65 | .PP |
70 | .I performance | 66 | \fB-c, --cpu\fP Operate on the MSR_IA32_HWP_REQUEST for each CPU in a CPU-list. |
71 | Set a policy where performance is paramount. | 67 | The CPU-list may be comma-separated CPU numbers, with dash for range |
72 | The processor will be unwilling to sacrifice any performance | 68 | or the string "all". Eg. '--cpu 1,4,6-8' or '--cpu all'. |
73 | for the sake of energy saving. This is the hardware default. | 69 | When --cpu is used, \fB--hwp-use-pkg\fP is available, which specifies whether the per-cpu |
70 | MSR_IA32_HWP_REQUEST should be over-ruled by MSR_IA32_HWP_REQUEST_PKG (1), | ||
71 | or exempt from MSR_IA32_HWP_REQUEST_PKG (0). | ||
72 | |||
73 | \fB-p, --pkg\fP Operate on the MSR_IA32_HWP_REQUEST_PKG for each package in the package-list. | ||
74 | The list is a string of individual package numbers separated | ||
75 | by commas, and or ranges of package numbers separated by a dash, | ||
76 | or the string "all". | ||
77 | For example '--pkg 1,3' or '--pkg all' | ||
78 | |||
79 | .SS VALUE OPTIONS | ||
74 | .PP | 80 | .PP |
75 | .I normal | 81 | .I normal | default |
76 | Set a policy with a normal balance between performance and energy efficiency. | 82 | Set a policy with a normal balance between performance and energy efficiency. |
77 | The processor will tolerate minor performance compromise | 83 | The processor will tolerate minor performance compromise |
78 | for potentially significant energy savings. | 84 | for potentially significant energy savings. |
79 | This reasonable default for most desktops and servers. | 85 | This is a reasonable default for most desktops and servers. |
86 | "default" is a synonym for "normal". | ||
80 | .PP | 87 | .PP |
81 | .I powersave | 88 | .I performance |
89 | Set a policy for maximum performance, | ||
90 | accepting no performance sacrifice for the benefit of energy efficiency. | ||
91 | .PP | ||
92 | .I balance-performance | ||
93 | Set a policy with a high priority on performance, | ||
94 | but allowing some performance loss to benefit energy efficiency. | ||
95 | .PP | ||
96 | .I balance-power | ||
97 | Set a policy where the performance and power are balanced. | ||
98 | This is the default. | ||
99 | .PP | ||
100 | .I power | ||
82 | Set a policy where the processor can accept | 101 | Set a policy where the processor can accept |
83 | a measurable performance hit to maximize energy efficiency. | 102 | a measurable performance impact to maximize energy efficiency. |
103 | |||
84 | .PP | 104 | .PP |
85 | .I n | 105 | The following table shows the mapping from the value strings above to actual MSR values. |
86 | Set MSR_IA32_ENERGY_PERF_BIAS to the specified number. | 106 | This mapping is defined in the Linux-kernel header, msr-index.h. |
87 | The range of valid numbers is 0-15, where 0 is maximum | ||
88 | performance and 15 is maximum energy efficiency. | ||
89 | 107 | ||
108 | .nf | ||
109 | VALUE STRING EPB EPP | ||
110 | performance 0 0 | ||
111 | balance-performance 4 128 | ||
112 | normal, default 6 128 | ||
113 | balance-power 8 192 | ||
114 | power 15 255 | ||
115 | .fi | ||
116 | .PP | ||
117 | For MSR_IA32_HWP_REQUEST performance fields | ||
118 | (--hwp-min, --hwp-max, --hwp-desired), the value option | ||
119 | is in units of 100 MHz, Eg. 12 signifies 1200 MHz. | ||
120 | |||
121 | .SS FIELD OPTIONS | ||
122 | \fB-a, --all value-string\fP Sets all EPB and EPP and HWP limit fields to the value associated with | ||
123 | the value-string. In addition, enables turbo-mode and HWP-mode, if they were previous disabled. | ||
124 | Thus "--all normal" will set a system without cpufreq into a well known configuration. | ||
125 | .PP | ||
126 | \fB-B, --epb\fP set EPB per-core or per-package. | ||
127 | See value strings in the table above. | ||
128 | .PP | ||
129 | \fB-d, --debug\fP debug increases verbosity. By default | ||
130 | x86_energy_perf_policy is silent for updates, | ||
131 | and verbose for read-only mode. | ||
132 | .PP | ||
133 | \fB-P, --hwp-epp\fP set HWP.EPP per-core or per-package. | ||
134 | See value strings in the table above. | ||
135 | .PP | ||
136 | \fB-m, --hwp-min\fP request HWP to not go below the specified core/bus ratio. | ||
137 | The "default" is the value found in IA32_HWP_CAPABILITIES.min. | ||
138 | .PP | ||
139 | \fB-M, --hwp-max\fP request HWP not exceed a the specified core/bus ratio. | ||
140 | The "default" is the value found in IA32_HWP_CAPABILITIES.max. | ||
141 | .PP | ||
142 | \fB-D, --hwp-desired\fP request HWP 'desired' frequency. | ||
143 | The "normal" setting is 0, which | ||
144 | corresponds to 'full autonomous' HWP control. | ||
145 | Non-zero performance values request a specific performance | ||
146 | level on this processor, specified in multiples of 100 MHz. | ||
147 | .PP | ||
148 | \fB-w, --hwp-window\fP specify integer number of microsec | ||
149 | in the sliding window that HWP uses to maintain average frequency. | ||
150 | This parameter is meaningful only when the "desired" field above is non-zero. | ||
151 | Default is 0, allowing the HW to choose. | ||
152 | .SH OTHER OPTIONS | ||
153 | .PP | ||
154 | \fB-f, --force\fP writes the specified values without bounds checking. | ||
155 | .PP | ||
156 | \fB-U, --hwp-use-pkg\fP (0 | 1), when used in conjunction with --cpu, | ||
157 | indicates whether the per-CPU MSR_IA32_HWP_REQUEST should be overruled (1) | ||
158 | or exempt (0) from per-Package MSR_IA32_HWP_REQUEST_PKG settings. | ||
159 | The default is exempt. | ||
160 | .PP | ||
161 | \fB-H, --hwp-enable\fP enable HardWare-P-state (HWP) mode. Once enabled, system RESET is required to disable HWP mode. | ||
162 | .PP | ||
163 | \fB-t, --turbo-enable\fP enable (1) or disable (0) turbo mode. | ||
164 | .PP | ||
165 | \fB-v, --version\fP print version and exit. | ||
166 | .PP | ||
167 | If no request to change policy is made, | ||
168 | the default behavior is to read | ||
169 | and display the current system state, | ||
170 | including the default capabilities. | ||
171 | .SH WARNING | ||
172 | .PP | ||
173 | This utility writes directly to Model Specific Registers. | ||
174 | There is no locking or coordination should this utility | ||
175 | be used to modify HWP limit fields at the same time that | ||
176 | intel_pstate's sysfs attributes access the same MSRs. | ||
177 | .PP | ||
178 | Note that --hwp-desired and --hwp-window are considered experimental. | ||
179 | Future versions of Linux reserve the right to access these | ||
180 | fields internally -- potentially conflicting with user-space access. | ||
181 | .SH EXAMPLE | ||
182 | .nf | ||
183 | # sudo x86_energy_perf_policy | ||
184 | cpu0: EPB 6 | ||
185 | cpu0: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
186 | cpu0: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
187 | cpu1: EPB 6 | ||
188 | cpu1: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
189 | cpu1: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
190 | cpu2: EPB 6 | ||
191 | cpu2: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
192 | cpu2: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
193 | cpu3: EPB 6 | ||
194 | cpu3: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
195 | cpu3: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
196 | .fi | ||
90 | .SH NOTES | 197 | .SH NOTES |
91 | .B "x86_energy_perf_policy " | 198 | .B "x86_energy_perf_policy" |
92 | runs only as root. | 199 | runs only as root. |
93 | .SH FILES | 200 | .SH FILES |
94 | .ta | 201 | .ta |
95 | .nf | 202 | .nf |
96 | /dev/cpu/*/msr | 203 | /dev/cpu/*/msr |
97 | .fi | 204 | .fi |
98 | |||
99 | .SH "SEE ALSO" | 205 | .SH "SEE ALSO" |
206 | .nf | ||
100 | msr(4) | 207 | msr(4) |
208 | Intel(R) 64 and IA-32 Architectures Software Developer's Manual | ||
209 | .fi | ||
101 | .PP | 210 | .PP |
102 | .SH AUTHORS | 211 | .SH AUTHORS |
103 | .nf | 212 | .nf |
104 | Written by Len Brown <len.brown@intel.com> | 213 | Len Brown |
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 40b3e5482f8a..65bbe627a425 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c | |||
@@ -3,322 +3,1424 @@ | |||
3 | * policy preference bias on recent X86 processors. | 3 | * policy preference bias on recent X86 processors. |
4 | */ | 4 | */ |
5 | /* | 5 | /* |
6 | * Copyright (c) 2010, Intel Corporation. | 6 | * Copyright (c) 2010 - 2017 Intel Corporation. |
7 | * Len Brown <len.brown@intel.com> | 7 | * Len Brown <len.brown@intel.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is released under GPL v2 |
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | */ | 10 | */ |
22 | 11 | ||
12 | #define _GNU_SOURCE | ||
13 | #include MSRHEADER | ||
23 | #include <stdio.h> | 14 | #include <stdio.h> |
24 | #include <unistd.h> | 15 | #include <unistd.h> |
25 | #include <sys/types.h> | 16 | #include <sys/types.h> |
17 | #include <sched.h> | ||
26 | #include <sys/stat.h> | 18 | #include <sys/stat.h> |
27 | #include <sys/resource.h> | 19 | #include <sys/resource.h> |
20 | #include <getopt.h> | ||
21 | #include <err.h> | ||
28 | #include <fcntl.h> | 22 | #include <fcntl.h> |
29 | #include <signal.h> | 23 | #include <signal.h> |
30 | #include <sys/time.h> | 24 | #include <sys/time.h> |
25 | #include <limits.h> | ||
31 | #include <stdlib.h> | 26 | #include <stdlib.h> |
32 | #include <string.h> | 27 | #include <string.h> |
28 | #include <cpuid.h> | ||
29 | #include <errno.h> | ||
30 | |||
31 | #define OPTARG_NORMAL (INT_MAX - 1) | ||
32 | #define OPTARG_POWER (INT_MAX - 2) | ||
33 | #define OPTARG_BALANCE_POWER (INT_MAX - 3) | ||
34 | #define OPTARG_BALANCE_PERFORMANCE (INT_MAX - 4) | ||
35 | #define OPTARG_PERFORMANCE (INT_MAX - 5) | ||
36 | |||
37 | struct msr_hwp_cap { | ||
38 | unsigned char highest; | ||
39 | unsigned char guaranteed; | ||
40 | unsigned char efficient; | ||
41 | unsigned char lowest; | ||
42 | }; | ||
33 | 43 | ||
34 | unsigned int verbose; /* set with -v */ | 44 | struct msr_hwp_request { |
35 | unsigned int read_only; /* set with -r */ | 45 | unsigned char hwp_min; |
46 | unsigned char hwp_max; | ||
47 | unsigned char hwp_desired; | ||
48 | unsigned char hwp_epp; | ||
49 | unsigned int hwp_window; | ||
50 | unsigned char hwp_use_pkg; | ||
51 | } req_update; | ||
52 | |||
53 | unsigned int debug; | ||
54 | unsigned int verbose; | ||
55 | unsigned int force; | ||
36 | char *progname; | 56 | char *progname; |
37 | unsigned long long new_bias; | 57 | int base_cpu; |
38 | int cpu = -1; | 58 | unsigned char update_epb; |
59 | unsigned long long new_epb; | ||
60 | unsigned char turbo_is_enabled; | ||
61 | unsigned char update_turbo; | ||
62 | unsigned char turbo_update_value; | ||
63 | unsigned char update_hwp_epp; | ||
64 | unsigned char update_hwp_min; | ||
65 | unsigned char update_hwp_max; | ||
66 | unsigned char update_hwp_desired; | ||
67 | unsigned char update_hwp_window; | ||
68 | unsigned char update_hwp_use_pkg; | ||
69 | unsigned char update_hwp_enable; | ||
70 | #define hwp_update_enabled() (update_hwp_enable | update_hwp_epp | update_hwp_max | update_hwp_min | update_hwp_desired | update_hwp_window | update_hwp_use_pkg) | ||
71 | int max_cpu_num; | ||
72 | int max_pkg_num; | ||
73 | #define MAX_PACKAGES 64 | ||
74 | unsigned int first_cpu_in_pkg[MAX_PACKAGES]; | ||
75 | unsigned long long pkg_present_set; | ||
76 | unsigned long long pkg_selected_set; | ||
77 | cpu_set_t *cpu_present_set; | ||
78 | cpu_set_t *cpu_selected_set; | ||
79 | int genuine_intel; | ||
80 | |||
81 | size_t cpu_setsize; | ||
82 | |||
83 | char *proc_stat = "/proc/stat"; | ||
84 | |||
85 | unsigned int has_epb; /* MSR_IA32_ENERGY_PERF_BIAS */ | ||
86 | unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */ | ||
87 | /* IA32_HWP_REQUEST, IA32_HWP_STATUS */ | ||
88 | unsigned int has_hwp_notify; /* IA32_HWP_INTERRUPT */ | ||
89 | unsigned int has_hwp_activity_window; /* IA32_HWP_REQUEST[bits 41:32] */ | ||
90 | unsigned int has_hwp_epp; /* IA32_HWP_REQUEST[bits 31:24] */ | ||
91 | unsigned int has_hwp_request_pkg; /* IA32_HWP_REQUEST_PKG */ | ||
92 | |||
93 | unsigned int bdx_highest_ratio; | ||
39 | 94 | ||
40 | /* | 95 | /* |
41 | * Usage: | 96 | * maintain compatibility with original implementation, but don't document it: |
42 | * | ||
43 | * -c cpu: limit action to a single CPU (default is all CPUs) | ||
44 | * -v: verbose output (can invoke more than once) | ||
45 | * -r: read-only, don't change any settings | ||
46 | * | ||
47 | * performance | ||
48 | * Performance is paramount. | ||
49 | * Unwilling to sacrifice any performance | ||
50 | * for the sake of energy saving. (hardware default) | ||
51 | * | ||
52 | * normal | ||
53 | * Can tolerate minor performance compromise | ||
54 | * for potentially significant energy savings. | ||
55 | * (reasonable default for most desktops and servers) | ||
56 | * | ||
57 | * powersave | ||
58 | * Can tolerate significant performance hit | ||
59 | * to maximize energy savings. | ||
60 | * | ||
61 | * n | ||
62 | * a numerical value to write to the underlying MSR. | ||
63 | */ | 97 | */ |
64 | void usage(void) | 98 | void usage(void) |
65 | { | 99 | { |
66 | printf("%s: [-c cpu] [-v] " | 100 | fprintf(stderr, "%s [options] [scope][field value]\n", progname); |
67 | "(-r | 'performance' | 'normal' | 'powersave' | n)\n", | 101 | fprintf(stderr, "scope: --cpu cpu-list [--hwp-use-pkg #] | --pkg pkg-list\n"); |
68 | progname); | 102 | fprintf(stderr, "field: --all | --epb | --hwp-epp | --hwp-min | --hwp-max | --hwp-desired\n"); |
103 | fprintf(stderr, "other: --hwp-enable | --turbo-enable (0 | 1) | --help | --force\n"); | ||
104 | fprintf(stderr, | ||
105 | "value: ( # | \"normal\" | \"performance\" | \"balance-performance\" | \"balance-power\"| \"power\")\n"); | ||
106 | fprintf(stderr, "--hwp-window usec\n"); | ||
107 | |||
108 | fprintf(stderr, "Specify only Energy Performance BIAS (legacy usage):\n"); | ||
109 | fprintf(stderr, "%s: [-c cpu] [-v] (-r | policy-value )\n", progname); | ||
110 | |||
69 | exit(1); | 111 | exit(1); |
70 | } | 112 | } |
71 | 113 | ||
72 | #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 | 114 | /* |
115 | * If bdx_highest_ratio is set, | ||
116 | * then we must translate between MSR format and simple ratio | ||
117 | * used on the cmdline. | ||
118 | */ | ||
119 | int ratio_2_msr_perf(int ratio) | ||
120 | { | ||
121 | int msr_perf; | ||
122 | |||
123 | if (!bdx_highest_ratio) | ||
124 | return ratio; | ||
125 | |||
126 | msr_perf = ratio * 255 / bdx_highest_ratio; | ||
127 | |||
128 | if (debug) | ||
129 | fprintf(stderr, "%d = ratio_to_msr_perf(%d)\n", msr_perf, ratio); | ||
130 | |||
131 | return msr_perf; | ||
132 | } | ||
133 | int msr_perf_2_ratio(int msr_perf) | ||
134 | { | ||
135 | int ratio; | ||
136 | double d; | ||
137 | |||
138 | if (!bdx_highest_ratio) | ||
139 | return msr_perf; | ||
140 | |||
141 | d = (double)msr_perf * (double) bdx_highest_ratio / 255.0; | ||
142 | d = d + 0.5; /* round */ | ||
143 | ratio = (int)d; | ||
144 | |||
145 | if (debug) | ||
146 | fprintf(stderr, "%d = msr_perf_ratio(%d) {%f}\n", ratio, msr_perf, d); | ||
147 | |||
148 | return ratio; | ||
149 | } | ||
150 | int parse_cmdline_epb(int i) | ||
151 | { | ||
152 | if (!has_epb) | ||
153 | errx(1, "EPB not enabled on this platform"); | ||
154 | |||
155 | update_epb = 1; | ||
156 | |||
157 | switch (i) { | ||
158 | case OPTARG_POWER: | ||
159 | return ENERGY_PERF_BIAS_POWERSAVE; | ||
160 | case OPTARG_BALANCE_POWER: | ||
161 | return ENERGY_PERF_BIAS_BALANCE_POWERSAVE; | ||
162 | case OPTARG_NORMAL: | ||
163 | return ENERGY_PERF_BIAS_NORMAL; | ||
164 | case OPTARG_BALANCE_PERFORMANCE: | ||
165 | return ENERGY_PERF_BIAS_BALANCE_PERFORMANCE; | ||
166 | case OPTARG_PERFORMANCE: | ||
167 | return ENERGY_PERF_BIAS_PERFORMANCE; | ||
168 | } | ||
169 | if (i < 0 || i > ENERGY_PERF_BIAS_POWERSAVE) | ||
170 | errx(1, "--epb must be from 0 to 15"); | ||
171 | return i; | ||
172 | } | ||
173 | |||
174 | #define HWP_CAP_LOWEST 0 | ||
175 | #define HWP_CAP_HIGHEST 255 | ||
176 | |||
177 | /* | ||
178 | * "performance" changes hwp_min to cap.highest | ||
179 | * All others leave it at cap.lowest | ||
180 | */ | ||
181 | int parse_cmdline_hwp_min(int i) | ||
182 | { | ||
183 | update_hwp_min = 1; | ||
184 | |||
185 | switch (i) { | ||
186 | case OPTARG_POWER: | ||
187 | case OPTARG_BALANCE_POWER: | ||
188 | case OPTARG_NORMAL: | ||
189 | case OPTARG_BALANCE_PERFORMANCE: | ||
190 | return HWP_CAP_LOWEST; | ||
191 | case OPTARG_PERFORMANCE: | ||
192 | return HWP_CAP_HIGHEST; | ||
193 | } | ||
194 | return i; | ||
195 | } | ||
196 | /* | ||
197 | * "power" changes hwp_max to cap.lowest | ||
198 | * All others leave it at cap.highest | ||
199 | */ | ||
200 | int parse_cmdline_hwp_max(int i) | ||
201 | { | ||
202 | update_hwp_max = 1; | ||
203 | |||
204 | switch (i) { | ||
205 | case OPTARG_POWER: | ||
206 | return HWP_CAP_LOWEST; | ||
207 | case OPTARG_NORMAL: | ||
208 | case OPTARG_BALANCE_POWER: | ||
209 | case OPTARG_BALANCE_PERFORMANCE: | ||
210 | case OPTARG_PERFORMANCE: | ||
211 | return HWP_CAP_HIGHEST; | ||
212 | } | ||
213 | return i; | ||
214 | } | ||
215 | /* | ||
216 | * for --hwp-des, all strings leave it in autonomous mode | ||
217 | * If you want to change it, you need to explicitly pick a value | ||
218 | */ | ||
219 | int parse_cmdline_hwp_desired(int i) | ||
220 | { | ||
221 | update_hwp_desired = 1; | ||
222 | |||
223 | switch (i) { | ||
224 | case OPTARG_POWER: | ||
225 | case OPTARG_BALANCE_POWER: | ||
226 | case OPTARG_BALANCE_PERFORMANCE: | ||
227 | case OPTARG_NORMAL: | ||
228 | case OPTARG_PERFORMANCE: | ||
229 | return 0; /* autonomous */ | ||
230 | } | ||
231 | return i; | ||
232 | } | ||
233 | |||
234 | int parse_cmdline_hwp_window(int i) | ||
235 | { | ||
236 | unsigned int exponent; | ||
237 | |||
238 | update_hwp_window = 1; | ||
239 | |||
240 | switch (i) { | ||
241 | case OPTARG_POWER: | ||
242 | case OPTARG_BALANCE_POWER: | ||
243 | case OPTARG_NORMAL: | ||
244 | case OPTARG_BALANCE_PERFORMANCE: | ||
245 | case OPTARG_PERFORMANCE: | ||
246 | return 0; | ||
247 | } | ||
248 | if (i < 0 || i > 1270000000) { | ||
249 | fprintf(stderr, "--hwp-window: 0 for auto; 1 - 1270000000 usec for window duration\n"); | ||
250 | usage(); | ||
251 | } | ||
252 | for (exponent = 0; ; ++exponent) { | ||
253 | if (debug) | ||
254 | printf("%d 10^%d\n", i, exponent); | ||
255 | |||
256 | if (i <= 127) | ||
257 | break; | ||
258 | |||
259 | i = i / 10; | ||
260 | } | ||
261 | if (debug) | ||
262 | fprintf(stderr, "%d*10^%d: 0x%x\n", i, exponent, (exponent << 7) | i); | ||
263 | |||
264 | return (exponent << 7) | i; | ||
265 | } | ||
266 | int parse_cmdline_hwp_epp(int i) | ||
267 | { | ||
268 | update_hwp_epp = 1; | ||
269 | |||
270 | switch (i) { | ||
271 | case OPTARG_POWER: | ||
272 | return HWP_EPP_POWERSAVE; | ||
273 | case OPTARG_BALANCE_POWER: | ||
274 | return HWP_EPP_BALANCE_POWERSAVE; | ||
275 | case OPTARG_NORMAL: | ||
276 | case OPTARG_BALANCE_PERFORMANCE: | ||
277 | return HWP_EPP_BALANCE_PERFORMANCE; | ||
278 | case OPTARG_PERFORMANCE: | ||
279 | return HWP_EPP_PERFORMANCE; | ||
280 | } | ||
281 | if (i < 0 || i > 0xff) { | ||
282 | fprintf(stderr, "--hwp-epp must be from 0 to 0xff\n"); | ||
283 | usage(); | ||
284 | } | ||
285 | return i; | ||
286 | } | ||
287 | int parse_cmdline_turbo(int i) | ||
288 | { | ||
289 | update_turbo = 1; | ||
290 | |||
291 | switch (i) { | ||
292 | case OPTARG_POWER: | ||
293 | return 0; | ||
294 | case OPTARG_NORMAL: | ||
295 | case OPTARG_BALANCE_POWER: | ||
296 | case OPTARG_BALANCE_PERFORMANCE: | ||
297 | case OPTARG_PERFORMANCE: | ||
298 | return 1; | ||
299 | } | ||
300 | if (i < 0 || i > 1) { | ||
301 | fprintf(stderr, "--turbo-enable: 1 to enable, 0 to disable\n"); | ||
302 | usage(); | ||
303 | } | ||
304 | return i; | ||
305 | } | ||
306 | |||
307 | int parse_optarg_string(char *s) | ||
308 | { | ||
309 | int i; | ||
310 | char *endptr; | ||
311 | |||
312 | if (!strncmp(s, "default", 7)) | ||
313 | return OPTARG_NORMAL; | ||
314 | |||
315 | if (!strncmp(s, "normal", 6)) | ||
316 | return OPTARG_NORMAL; | ||
317 | |||
318 | if (!strncmp(s, "power", 9)) | ||
319 | return OPTARG_POWER; | ||
320 | |||
321 | if (!strncmp(s, "balance-power", 17)) | ||
322 | return OPTARG_BALANCE_POWER; | ||
323 | |||
324 | if (!strncmp(s, "balance-performance", 19)) | ||
325 | return OPTARG_BALANCE_PERFORMANCE; | ||
326 | |||
327 | if (!strncmp(s, "performance", 11)) | ||
328 | return OPTARG_PERFORMANCE; | ||
329 | |||
330 | i = strtol(s, &endptr, 0); | ||
331 | if (s == endptr) { | ||
332 | fprintf(stderr, "no digits in \"%s\"\n", s); | ||
333 | usage(); | ||
334 | } | ||
335 | if (i == LONG_MIN || i == LONG_MAX) | ||
336 | errx(-1, "%s", s); | ||
337 | |||
338 | if (i > 0xFF) | ||
339 | errx(-1, "%d (0x%x) must be < 256", i, i); | ||
340 | |||
341 | if (i < 0) | ||
342 | errx(-1, "%d (0x%x) must be >= 0", i, i); | ||
343 | return i; | ||
344 | } | ||
345 | |||
346 | void parse_cmdline_all(char *s) | ||
347 | { | ||
348 | force++; | ||
349 | update_hwp_enable = 1; | ||
350 | req_update.hwp_min = parse_cmdline_hwp_min(parse_optarg_string(s)); | ||
351 | req_update.hwp_max = parse_cmdline_hwp_max(parse_optarg_string(s)); | ||
352 | req_update.hwp_epp = parse_cmdline_hwp_epp(parse_optarg_string(s)); | ||
353 | if (has_epb) | ||
354 | new_epb = parse_cmdline_epb(parse_optarg_string(s)); | ||
355 | turbo_update_value = parse_cmdline_turbo(parse_optarg_string(s)); | ||
356 | req_update.hwp_desired = parse_cmdline_hwp_desired(parse_optarg_string(s)); | ||
357 | req_update.hwp_window = parse_cmdline_hwp_window(parse_optarg_string(s)); | ||
358 | } | ||
359 | |||
360 | void validate_cpu_selected_set(void) | ||
361 | { | ||
362 | int cpu; | ||
363 | |||
364 | if (CPU_COUNT_S(cpu_setsize, cpu_selected_set) == 0) | ||
365 | errx(0, "no CPUs requested"); | ||
366 | |||
367 | for (cpu = 0; cpu <= max_cpu_num; ++cpu) { | ||
368 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_selected_set)) | ||
369 | if (!CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
370 | errx(1, "Requested cpu% is not present", cpu); | ||
371 | } | ||
372 | } | ||
373 | |||
374 | void parse_cmdline_cpu(char *s) | ||
375 | { | ||
376 | char *startp, *endp; | ||
377 | int cpu = 0; | ||
378 | |||
379 | if (pkg_selected_set) { | ||
380 | usage(); | ||
381 | errx(1, "--cpu | --pkg"); | ||
382 | } | ||
383 | cpu_selected_set = CPU_ALLOC((max_cpu_num + 1)); | ||
384 | if (cpu_selected_set == NULL) | ||
385 | err(1, "cpu_selected_set"); | ||
386 | CPU_ZERO_S(cpu_setsize, cpu_selected_set); | ||
387 | |||
388 | for (startp = s; startp && *startp;) { | ||
389 | |||
390 | if (*startp == ',') { | ||
391 | startp++; | ||
392 | continue; | ||
393 | } | ||
394 | |||
395 | if (*startp == '-') { | ||
396 | int end_cpu; | ||
73 | 397 | ||
74 | #define BIAS_PERFORMANCE 0 | 398 | startp++; |
75 | #define BIAS_BALANCE 6 | 399 | end_cpu = strtol(startp, &endp, 10); |
76 | #define BIAS_POWERSAVE 15 | 400 | if (startp == endp) |
401 | continue; | ||
402 | |||
403 | while (cpu <= end_cpu) { | ||
404 | if (cpu > max_cpu_num) | ||
405 | errx(1, "Requested cpu%d exceeds max cpu%d", cpu, max_cpu_num); | ||
406 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
407 | cpu++; | ||
408 | } | ||
409 | startp = endp; | ||
410 | continue; | ||
411 | } | ||
412 | |||
413 | if (strncmp(startp, "all", 3) == 0) { | ||
414 | for (cpu = 0; cpu <= max_cpu_num; cpu += 1) { | ||
415 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
416 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
417 | } | ||
418 | startp += 3; | ||
419 | if (*startp == 0) | ||
420 | break; | ||
421 | } | ||
422 | /* "--cpu even" is not documented */ | ||
423 | if (strncmp(startp, "even", 4) == 0) { | ||
424 | for (cpu = 0; cpu <= max_cpu_num; cpu += 2) { | ||
425 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
426 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
427 | } | ||
428 | startp += 4; | ||
429 | if (*startp == 0) | ||
430 | break; | ||
431 | } | ||
432 | |||
433 | /* "--cpu odd" is not documented */ | ||
434 | if (strncmp(startp, "odd", 3) == 0) { | ||
435 | for (cpu = 1; cpu <= max_cpu_num; cpu += 2) { | ||
436 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
437 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
438 | } | ||
439 | startp += 3; | ||
440 | if (*startp == 0) | ||
441 | break; | ||
442 | } | ||
443 | |||
444 | cpu = strtol(startp, &endp, 10); | ||
445 | if (startp == endp) | ||
446 | errx(1, "--cpu cpu-set: confused by '%s'", startp); | ||
447 | if (cpu > max_cpu_num) | ||
448 | errx(1, "Requested cpu%d exceeds max cpu%d", cpu, max_cpu_num); | ||
449 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
450 | startp = endp; | ||
451 | } | ||
452 | |||
453 | validate_cpu_selected_set(); | ||
454 | |||
455 | } | ||
456 | |||
457 | void parse_cmdline_pkg(char *s) | ||
458 | { | ||
459 | char *startp, *endp; | ||
460 | int pkg = 0; | ||
461 | |||
462 | if (cpu_selected_set) { | ||
463 | usage(); | ||
464 | errx(1, "--pkg | --cpu"); | ||
465 | } | ||
466 | pkg_selected_set = 0; | ||
467 | |||
468 | for (startp = s; startp && *startp;) { | ||
469 | |||
470 | if (*startp == ',') { | ||
471 | startp++; | ||
472 | continue; | ||
473 | } | ||
474 | |||
475 | if (*startp == '-') { | ||
476 | int end_pkg; | ||
477 | |||
478 | startp++; | ||
479 | end_pkg = strtol(startp, &endp, 10); | ||
480 | if (startp == endp) | ||
481 | continue; | ||
482 | |||
483 | while (pkg <= end_pkg) { | ||
484 | if (pkg > max_pkg_num) | ||
485 | errx(1, "Requested pkg%d exceeds max pkg%d", pkg, max_pkg_num); | ||
486 | pkg_selected_set |= 1 << pkg; | ||
487 | pkg++; | ||
488 | } | ||
489 | startp = endp; | ||
490 | continue; | ||
491 | } | ||
492 | |||
493 | if (strncmp(startp, "all", 3) == 0) { | ||
494 | pkg_selected_set = pkg_present_set; | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | pkg = strtol(startp, &endp, 10); | ||
499 | if (pkg > max_pkg_num) | ||
500 | errx(1, "Requested pkg%d Exceeds max pkg%d", pkg, max_pkg_num); | ||
501 | pkg_selected_set |= 1 << pkg; | ||
502 | startp = endp; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | void for_packages(unsigned long long pkg_set, int (func)(int)) | ||
507 | { | ||
508 | int pkg_num; | ||
509 | |||
510 | for (pkg_num = 0; pkg_num <= max_pkg_num; ++pkg_num) { | ||
511 | if (pkg_set & (1UL << pkg_num)) | ||
512 | func(pkg_num); | ||
513 | } | ||
514 | } | ||
515 | |||
516 | void print_version(void) | ||
517 | { | ||
518 | printf("x86_energy_perf_policy 17.05.11 (C) Len Brown <len.brown@intel.com>\n"); | ||
519 | } | ||
77 | 520 | ||
78 | void cmdline(int argc, char **argv) | 521 | void cmdline(int argc, char **argv) |
79 | { | 522 | { |
80 | int opt; | 523 | int opt; |
524 | int option_index = 0; | ||
525 | |||
526 | static struct option long_options[] = { | ||
527 | {"all", required_argument, 0, 'a'}, | ||
528 | {"cpu", required_argument, 0, 'c'}, | ||
529 | {"pkg", required_argument, 0, 'p'}, | ||
530 | {"debug", no_argument, 0, 'd'}, | ||
531 | {"hwp-desired", required_argument, 0, 'D'}, | ||
532 | {"epb", required_argument, 0, 'B'}, | ||
533 | {"force", no_argument, 0, 'f'}, | ||
534 | {"hwp-enable", no_argument, 0, 'e'}, | ||
535 | {"help", no_argument, 0, 'h'}, | ||
536 | {"hwp-epp", required_argument, 0, 'P'}, | ||
537 | {"hwp-min", required_argument, 0, 'm'}, | ||
538 | {"hwp-max", required_argument, 0, 'M'}, | ||
539 | {"read", no_argument, 0, 'r'}, | ||
540 | {"turbo-enable", required_argument, 0, 't'}, | ||
541 | {"hwp-use-pkg", required_argument, 0, 'u'}, | ||
542 | {"version", no_argument, 0, 'v'}, | ||
543 | {"hwp-window", required_argument, 0, 'w'}, | ||
544 | {0, 0, 0, 0 } | ||
545 | }; | ||
81 | 546 | ||
82 | progname = argv[0]; | 547 | progname = argv[0]; |
83 | 548 | ||
84 | while ((opt = getopt(argc, argv, "+rvc:")) != -1) { | 549 | while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw", |
550 | long_options, &option_index)) != -1) { | ||
85 | switch (opt) { | 551 | switch (opt) { |
552 | case 'a': | ||
553 | parse_cmdline_all(optarg); | ||
554 | break; | ||
555 | case 'B': | ||
556 | new_epb = parse_cmdline_epb(parse_optarg_string(optarg)); | ||
557 | break; | ||
86 | case 'c': | 558 | case 'c': |
87 | cpu = atoi(optarg); | 559 | parse_cmdline_cpu(optarg); |
560 | break; | ||
561 | case 'e': | ||
562 | update_hwp_enable = 1; | ||
563 | break; | ||
564 | case 'h': | ||
565 | usage(); | ||
566 | break; | ||
567 | case 'd': | ||
568 | debug++; | ||
569 | verbose++; | ||
570 | break; | ||
571 | case 'f': | ||
572 | force++; | ||
573 | break; | ||
574 | case 'D': | ||
575 | req_update.hwp_desired = parse_cmdline_hwp_desired(parse_optarg_string(optarg)); | ||
576 | break; | ||
577 | case 'm': | ||
578 | req_update.hwp_min = parse_cmdline_hwp_min(parse_optarg_string(optarg)); | ||
579 | break; | ||
580 | case 'M': | ||
581 | req_update.hwp_max = parse_cmdline_hwp_max(parse_optarg_string(optarg)); | ||
582 | break; | ||
583 | case 'p': | ||
584 | parse_cmdline_pkg(optarg); | ||
585 | break; | ||
586 | case 'P': | ||
587 | req_update.hwp_epp = parse_cmdline_hwp_epp(parse_optarg_string(optarg)); | ||
88 | break; | 588 | break; |
89 | case 'r': | 589 | case 'r': |
90 | read_only = 1; | 590 | /* v1 used -r to specify read-only mode, now the default */ |
591 | break; | ||
592 | case 't': | ||
593 | turbo_update_value = parse_cmdline_turbo(parse_optarg_string(optarg)); | ||
594 | break; | ||
595 | case 'u': | ||
596 | update_hwp_use_pkg++; | ||
597 | if (atoi(optarg) == 0) | ||
598 | req_update.hwp_use_pkg = 0; | ||
599 | else | ||
600 | req_update.hwp_use_pkg = 1; | ||
91 | break; | 601 | break; |
92 | case 'v': | 602 | case 'v': |
93 | verbose++; | 603 | print_version(); |
604 | exit(0); | ||
605 | break; | ||
606 | case 'w': | ||
607 | req_update.hwp_window = parse_cmdline_hwp_window(parse_optarg_string(optarg)); | ||
94 | break; | 608 | break; |
95 | default: | 609 | default: |
96 | usage(); | 610 | usage(); |
97 | } | 611 | } |
98 | } | 612 | } |
99 | /* if -r, then should be no additional optind */ | ||
100 | if (read_only && (argc > optind)) | ||
101 | usage(); | ||
102 | |||
103 | /* | 613 | /* |
104 | * if no -r , then must be one additional optind | 614 | * v1 allowed "performance"|"normal"|"power" with no policy specifier |
615 | * to update BIAS. Continue to support that, even though no longer documented. | ||
105 | */ | 616 | */ |
106 | if (!read_only) { | 617 | if (argc == optind + 1) |
618 | new_epb = parse_cmdline_epb(parse_optarg_string(argv[optind])); | ||
107 | 619 | ||
108 | if (argc != optind + 1) { | 620 | if (argc > optind + 1) { |
109 | printf("must supply -r or policy param\n"); | 621 | fprintf(stderr, "stray parameter '%s'\n", argv[optind + 1]); |
110 | usage(); | 622 | usage(); |
111 | } | 623 | } |
624 | } | ||
112 | 625 | ||
113 | if (!strcmp("performance", argv[optind])) { | 626 | |
114 | new_bias = BIAS_PERFORMANCE; | 627 | int get_msr(int cpu, int offset, unsigned long long *msr) |
115 | } else if (!strcmp("normal", argv[optind])) { | 628 | { |
116 | new_bias = BIAS_BALANCE; | 629 | int retval; |
117 | } else if (!strcmp("powersave", argv[optind])) { | 630 | char pathname[32]; |
118 | new_bias = BIAS_POWERSAVE; | 631 | int fd; |
119 | } else { | 632 | |
120 | char *endptr; | 633 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); |
121 | 634 | fd = open(pathname, O_RDONLY); | |
122 | new_bias = strtoull(argv[optind], &endptr, 0); | 635 | if (fd < 0) |
123 | if (endptr == argv[optind] || | 636 | err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname); |
124 | new_bias > BIAS_POWERSAVE) { | 637 | |
125 | fprintf(stderr, "invalid value: %s\n", | 638 | retval = pread(fd, msr, sizeof(*msr), offset); |
126 | argv[optind]); | 639 | if (retval != sizeof(*msr)) |
127 | usage(); | 640 | err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset); |
128 | } | 641 | |
129 | } | 642 | if (debug > 1) |
643 | fprintf(stderr, "get_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, *msr); | ||
644 | |||
645 | close(fd); | ||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | int put_msr(int cpu, int offset, unsigned long long new_msr) | ||
650 | { | ||
651 | char pathname[32]; | ||
652 | int retval; | ||
653 | int fd; | ||
654 | |||
655 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); | ||
656 | fd = open(pathname, O_RDWR); | ||
657 | if (fd < 0) | ||
658 | err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname); | ||
659 | |||
660 | retval = pwrite(fd, &new_msr, sizeof(new_msr), offset); | ||
661 | if (retval != sizeof(new_msr)) | ||
662 | err(-2, "pwrite(cpu%d, offset 0x%x, 0x%llx) = %d", cpu, offset, new_msr, retval); | ||
663 | |||
664 | close(fd); | ||
665 | |||
666 | if (debug > 1) | ||
667 | fprintf(stderr, "put_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, new_msr); | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | void print_hwp_cap(int cpu, struct msr_hwp_cap *cap, char *str) | ||
673 | { | ||
674 | if (cpu != -1) | ||
675 | printf("cpu%d: ", cpu); | ||
676 | |||
677 | printf("HWP_CAP: low %d eff %d guar %d high %d\n", | ||
678 | cap->lowest, cap->efficient, cap->guaranteed, cap->highest); | ||
679 | } | ||
680 | void read_hwp_cap(int cpu, struct msr_hwp_cap *cap, unsigned int msr_offset) | ||
681 | { | ||
682 | unsigned long long msr; | ||
683 | |||
684 | get_msr(cpu, msr_offset, &msr); | ||
685 | |||
686 | cap->highest = msr_perf_2_ratio(HWP_HIGHEST_PERF(msr)); | ||
687 | cap->guaranteed = msr_perf_2_ratio(HWP_GUARANTEED_PERF(msr)); | ||
688 | cap->efficient = msr_perf_2_ratio(HWP_MOSTEFFICIENT_PERF(msr)); | ||
689 | cap->lowest = msr_perf_2_ratio(HWP_LOWEST_PERF(msr)); | ||
690 | } | ||
691 | |||
692 | void print_hwp_request(int cpu, struct msr_hwp_request *h, char *str) | ||
693 | { | ||
694 | if (cpu != -1) | ||
695 | printf("cpu%d: ", cpu); | ||
696 | |||
697 | if (str) | ||
698 | printf("%s", str); | ||
699 | |||
700 | printf("HWP_REQ: min %d max %d des %d epp %d window 0x%x (%d*10^%dus) use_pkg %d\n", | ||
701 | h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, | ||
702 | h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7, h->hwp_use_pkg); | ||
703 | } | ||
704 | void print_hwp_request_pkg(int pkg, struct msr_hwp_request *h, char *str) | ||
705 | { | ||
706 | printf("pkg%d: ", pkg); | ||
707 | |||
708 | if (str) | ||
709 | printf("%s", str); | ||
710 | |||
711 | printf("HWP_REQ_PKG: min %d max %d des %d epp %d window 0x%x (%d*10^%dus)\n", | ||
712 | h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, | ||
713 | h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7); | ||
714 | } | ||
715 | void read_hwp_request(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset) | ||
716 | { | ||
717 | unsigned long long msr; | ||
718 | |||
719 | get_msr(cpu, msr_offset, &msr); | ||
720 | |||
721 | hwp_req->hwp_min = msr_perf_2_ratio((((msr) >> 0) & 0xff)); | ||
722 | hwp_req->hwp_max = msr_perf_2_ratio((((msr) >> 8) & 0xff)); | ||
723 | hwp_req->hwp_desired = msr_perf_2_ratio((((msr) >> 16) & 0xff)); | ||
724 | hwp_req->hwp_epp = (((msr) >> 24) & 0xff); | ||
725 | hwp_req->hwp_window = (((msr) >> 32) & 0x3ff); | ||
726 | hwp_req->hwp_use_pkg = (((msr) >> 42) & 0x1); | ||
727 | } | ||
728 | |||
729 | void write_hwp_request(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset) | ||
730 | { | ||
731 | unsigned long long msr = 0; | ||
732 | |||
733 | if (debug > 1) | ||
734 | printf("cpu%d: requesting min %d max %d des %d epp %d window 0x%0x use_pkg %d\n", | ||
735 | cpu, hwp_req->hwp_min, hwp_req->hwp_max, | ||
736 | hwp_req->hwp_desired, hwp_req->hwp_epp, | ||
737 | hwp_req->hwp_window, hwp_req->hwp_use_pkg); | ||
738 | |||
739 | msr |= HWP_MIN_PERF(ratio_2_msr_perf(hwp_req->hwp_min)); | ||
740 | msr |= HWP_MAX_PERF(ratio_2_msr_perf(hwp_req->hwp_max)); | ||
741 | msr |= HWP_DESIRED_PERF(ratio_2_msr_perf(hwp_req->hwp_desired)); | ||
742 | msr |= HWP_ENERGY_PERF_PREFERENCE(hwp_req->hwp_epp); | ||
743 | msr |= HWP_ACTIVITY_WINDOW(hwp_req->hwp_window); | ||
744 | msr |= HWP_PACKAGE_CONTROL(hwp_req->hwp_use_pkg); | ||
745 | |||
746 | put_msr(cpu, msr_offset, msr); | ||
747 | } | ||
748 | |||
749 | int print_cpu_msrs(int cpu) | ||
750 | { | ||
751 | unsigned long long msr; | ||
752 | struct msr_hwp_request req; | ||
753 | struct msr_hwp_cap cap; | ||
754 | |||
755 | if (has_epb) { | ||
756 | get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr); | ||
757 | |||
758 | printf("cpu%d: EPB %u\n", cpu, (unsigned int) msr); | ||
130 | } | 759 | } |
760 | |||
761 | if (!has_hwp) | ||
762 | return 0; | ||
763 | |||
764 | read_hwp_request(cpu, &req, MSR_HWP_REQUEST); | ||
765 | print_hwp_request(cpu, &req, ""); | ||
766 | |||
767 | read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES); | ||
768 | print_hwp_cap(cpu, &cap, ""); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | int print_pkg_msrs(int pkg) | ||
774 | { | ||
775 | struct msr_hwp_request req; | ||
776 | unsigned long long msr; | ||
777 | |||
778 | if (!has_hwp) | ||
779 | return 0; | ||
780 | |||
781 | read_hwp_request(first_cpu_in_pkg[pkg], &req, MSR_HWP_REQUEST_PKG); | ||
782 | print_hwp_request_pkg(pkg, &req, ""); | ||
783 | |||
784 | if (has_hwp_notify) { | ||
785 | get_msr(first_cpu_in_pkg[pkg], MSR_HWP_INTERRUPT, &msr); | ||
786 | fprintf(stderr, | ||
787 | "pkg%d: MSR_HWP_INTERRUPT: 0x%08llx (Excursion_Min-%sabled, Guaranteed_Perf_Change-%sabled)\n", | ||
788 | pkg, msr, | ||
789 | ((msr) & 0x2) ? "EN" : "Dis", | ||
790 | ((msr) & 0x1) ? "EN" : "Dis"); | ||
791 | } | ||
792 | get_msr(first_cpu_in_pkg[pkg], MSR_HWP_STATUS, &msr); | ||
793 | fprintf(stderr, | ||
794 | "pkg%d: MSR_HWP_STATUS: 0x%08llx (%sExcursion_Min, %sGuaranteed_Perf_Change)\n", | ||
795 | pkg, msr, | ||
796 | ((msr) & 0x4) ? "" : "No-", | ||
797 | ((msr) & 0x1) ? "" : "No-"); | ||
798 | |||
799 | return 0; | ||
131 | } | 800 | } |
132 | 801 | ||
133 | /* | 802 | /* |
134 | * validate_cpuid() | 803 | * Assumption: All HWP systems have 100 MHz bus clock |
135 | * returns on success, quietly exits on failure (make verbose with -v) | ||
136 | */ | 804 | */ |
137 | void validate_cpuid(void) | 805 | int ratio_2_sysfs_khz(int ratio) |
138 | { | 806 | { |
139 | unsigned int eax, ebx, ecx, edx, max_level; | 807 | int bclk_khz = 100 * 1000; /* 100,000 KHz = 100 MHz */ |
140 | unsigned int fms, family, model, stepping; | ||
141 | 808 | ||
142 | eax = ebx = ecx = edx = 0; | 809 | return ratio * bclk_khz; |
810 | } | ||
811 | /* | ||
812 | * If HWP is enabled and cpufreq sysfs attribtes are present, | ||
813 | * then update sysfs, so that it will not become | ||
814 | * stale when we write to MSRs. | ||
815 | * (intel_pstate's max_perf_pct and min_perf_pct will follow cpufreq, | ||
816 | * so we don't have to touch that.) | ||
817 | */ | ||
818 | void update_cpufreq_scaling_freq(int is_max, int cpu, unsigned int ratio) | ||
819 | { | ||
820 | char pathname[64]; | ||
821 | FILE *fp; | ||
822 | int retval; | ||
823 | int khz; | ||
143 | 824 | ||
144 | asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), | 825 | sprintf(pathname, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_%s_freq", |
145 | "=d" (edx) : "a" (0)); | 826 | cpu, is_max ? "max" : "min"); |
146 | 827 | ||
147 | if (ebx != 0x756e6547 || edx != 0x49656e69 || ecx != 0x6c65746e) { | 828 | fp = fopen(pathname, "w"); |
148 | if (verbose) | 829 | if (!fp) { |
149 | fprintf(stderr, "%.4s%.4s%.4s != GenuineIntel", | 830 | if (debug) |
150 | (char *)&ebx, (char *)&edx, (char *)&ecx); | 831 | perror(pathname); |
151 | exit(1); | 832 | return; |
152 | } | 833 | } |
153 | 834 | ||
154 | asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); | 835 | khz = ratio_2_sysfs_khz(ratio); |
155 | family = (fms >> 8) & 0xf; | 836 | retval = fprintf(fp, "%d", khz); |
156 | model = (fms >> 4) & 0xf; | 837 | if (retval < 0) |
157 | stepping = fms & 0xf; | 838 | if (debug) |
158 | if (family == 6 || family == 0xf) | 839 | perror("fprintf"); |
159 | model += ((fms >> 16) & 0xf) << 4; | 840 | if (debug) |
841 | printf("echo %d > %s\n", khz, pathname); | ||
160 | 842 | ||
161 | if (verbose > 1) | 843 | fclose(fp); |
162 | printf("CPUID %d levels family:model:stepping " | 844 | } |
163 | "0x%x:%x:%x (%d:%d:%d)\n", max_level, | ||
164 | family, model, stepping, family, model, stepping); | ||
165 | 845 | ||
166 | if (!(edx & (1 << 5))) { | 846 | /* |
167 | if (verbose) | 847 | * We update all sysfs before updating any MSRs because of |
168 | printf("CPUID: no MSR\n"); | 848 | * bugs in cpufreq/intel_pstate where the sysfs writes |
169 | exit(1); | 849 | * for a CPU may change the min/max values on other CPUS. |
850 | */ | ||
851 | |||
852 | int update_sysfs(int cpu) | ||
853 | { | ||
854 | if (!has_hwp) | ||
855 | return 0; | ||
856 | |||
857 | if (!hwp_update_enabled()) | ||
858 | return 0; | ||
859 | |||
860 | if (access("/sys/devices/system/cpu/cpu0/cpufreq", F_OK)) | ||
861 | return 0; | ||
862 | |||
863 | if (update_hwp_min) | ||
864 | update_cpufreq_scaling_freq(0, cpu, req_update.hwp_min); | ||
865 | |||
866 | if (update_hwp_max) | ||
867 | update_cpufreq_scaling_freq(1, cpu, req_update.hwp_max); | ||
868 | |||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | int verify_hwp_req_self_consistency(int cpu, struct msr_hwp_request *req) | ||
873 | { | ||
874 | /* fail if min > max requested */ | ||
875 | if (req->hwp_min > req->hwp_max) { | ||
876 | errx(1, "cpu%d: requested hwp-min %d > hwp_max %d", | ||
877 | cpu, req->hwp_min, req->hwp_max); | ||
170 | } | 878 | } |
171 | 879 | ||
172 | /* | 880 | /* fail if desired > max requestd */ |
173 | * Support for MSR_IA32_ENERGY_PERF_BIAS | 881 | if (req->hwp_desired && (req->hwp_desired > req->hwp_max)) { |
174 | * is indicated by CPUID.06H.ECX.bit3 | 882 | errx(1, "cpu%d: requested hwp-desired %d > hwp_max %d", |
175 | */ | 883 | cpu, req->hwp_desired, req->hwp_max); |
176 | asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (6)); | ||
177 | if (verbose) | ||
178 | printf("CPUID.06H.ECX: 0x%x\n", ecx); | ||
179 | if (!(ecx & (1 << 3))) { | ||
180 | if (verbose) | ||
181 | printf("CPUID: No MSR_IA32_ENERGY_PERF_BIAS\n"); | ||
182 | exit(1); | ||
183 | } | 884 | } |
184 | return; /* success */ | 885 | /* fail if desired < min requestd */ |
886 | if (req->hwp_desired && (req->hwp_desired < req->hwp_min)) { | ||
887 | errx(1, "cpu%d: requested hwp-desired %d < requested hwp_min %d", | ||
888 | cpu, req->hwp_desired, req->hwp_min); | ||
889 | } | ||
890 | |||
891 | return 0; | ||
185 | } | 892 | } |
186 | 893 | ||
187 | unsigned long long get_msr(int cpu, int offset) | 894 | int check_hwp_request_v_hwp_capabilities(int cpu, struct msr_hwp_request *req, struct msr_hwp_cap *cap) |
188 | { | 895 | { |
189 | unsigned long long msr; | 896 | if (update_hwp_max) { |
190 | char msr_path[32]; | 897 | if (req->hwp_max > cap->highest) |
191 | int retval; | 898 | errx(1, "cpu%d: requested max %d > capabilities highest %d, use --force?", |
192 | int fd; | 899 | cpu, req->hwp_max, cap->highest); |
900 | if (req->hwp_max < cap->lowest) | ||
901 | errx(1, "cpu%d: requested max %d < capabilities lowest %d, use --force?", | ||
902 | cpu, req->hwp_max, cap->lowest); | ||
903 | } | ||
193 | 904 | ||
194 | sprintf(msr_path, "/dev/cpu/%d/msr", cpu); | 905 | if (update_hwp_min) { |
195 | fd = open(msr_path, O_RDONLY); | 906 | if (req->hwp_min > cap->highest) |
196 | if (fd < 0) { | 907 | errx(1, "cpu%d: requested min %d > capabilities highest %d, use --force?", |
197 | printf("Try \"# modprobe msr\"\n"); | 908 | cpu, req->hwp_min, cap->highest); |
198 | perror(msr_path); | 909 | if (req->hwp_min < cap->lowest) |
199 | exit(1); | 910 | errx(1, "cpu%d: requested min %d < capabilities lowest %d, use --force?", |
911 | cpu, req->hwp_min, cap->lowest); | ||
200 | } | 912 | } |
201 | 913 | ||
202 | retval = pread(fd, &msr, sizeof msr, offset); | 914 | if (update_hwp_min && update_hwp_max && (req->hwp_min > req->hwp_max)) |
915 | errx(1, "cpu%d: requested min %d > requested max %d", | ||
916 | cpu, req->hwp_min, req->hwp_max); | ||
203 | 917 | ||
204 | if (retval != sizeof msr) { | 918 | if (update_hwp_desired && req->hwp_desired) { |
205 | printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval); | 919 | if (req->hwp_desired > req->hwp_max) |
206 | exit(-2); | 920 | errx(1, "cpu%d: requested desired %d > requested max %d, use --force?", |
921 | cpu, req->hwp_desired, req->hwp_max); | ||
922 | if (req->hwp_desired < req->hwp_min) | ||
923 | errx(1, "cpu%d: requested desired %d < requested min %d, use --force?", | ||
924 | cpu, req->hwp_desired, req->hwp_min); | ||
925 | if (req->hwp_desired < cap->lowest) | ||
926 | errx(1, "cpu%d: requested desired %d < capabilities lowest %d, use --force?", | ||
927 | cpu, req->hwp_desired, cap->lowest); | ||
928 | if (req->hwp_desired > cap->highest) | ||
929 | errx(1, "cpu%d: requested desired %d > capabilities highest %d, use --force?", | ||
930 | cpu, req->hwp_desired, cap->highest); | ||
207 | } | 931 | } |
208 | close(fd); | 932 | |
209 | return msr; | 933 | return 0; |
210 | } | 934 | } |
211 | 935 | ||
212 | unsigned long long put_msr(int cpu, unsigned long long new_msr, int offset) | 936 | int update_hwp_request(int cpu) |
213 | { | 937 | { |
214 | unsigned long long old_msr; | 938 | struct msr_hwp_request req; |
215 | char msr_path[32]; | 939 | struct msr_hwp_cap cap; |
216 | int retval; | 940 | |
217 | int fd; | 941 | int msr_offset = MSR_HWP_REQUEST; |
942 | |||
943 | read_hwp_request(cpu, &req, msr_offset); | ||
944 | if (debug) | ||
945 | print_hwp_request(cpu, &req, "old: "); | ||
946 | |||
947 | if (update_hwp_min) | ||
948 | req.hwp_min = req_update.hwp_min; | ||
949 | |||
950 | if (update_hwp_max) | ||
951 | req.hwp_max = req_update.hwp_max; | ||
952 | |||
953 | if (update_hwp_desired) | ||
954 | req.hwp_desired = req_update.hwp_desired; | ||
955 | |||
956 | if (update_hwp_window) | ||
957 | req.hwp_window = req_update.hwp_window; | ||
958 | |||
959 | if (update_hwp_epp) | ||
960 | req.hwp_epp = req_update.hwp_epp; | ||
961 | |||
962 | req.hwp_use_pkg = req_update.hwp_use_pkg; | ||
963 | |||
964 | read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES); | ||
965 | if (debug) | ||
966 | print_hwp_cap(cpu, &cap, ""); | ||
967 | |||
968 | if (!force) | ||
969 | check_hwp_request_v_hwp_capabilities(cpu, &req, &cap); | ||
970 | |||
971 | verify_hwp_req_self_consistency(cpu, &req); | ||
218 | 972 | ||
219 | sprintf(msr_path, "/dev/cpu/%d/msr", cpu); | 973 | write_hwp_request(cpu, &req, msr_offset); |
220 | fd = open(msr_path, O_RDWR); | 974 | |
221 | if (fd < 0) { | 975 | if (debug) { |
222 | perror(msr_path); | 976 | read_hwp_request(cpu, &req, msr_offset); |
223 | exit(1); | 977 | print_hwp_request(cpu, &req, "new: "); |
224 | } | 978 | } |
979 | return 0; | ||
980 | } | ||
981 | int update_hwp_request_pkg(int pkg) | ||
982 | { | ||
983 | struct msr_hwp_request req; | ||
984 | struct msr_hwp_cap cap; | ||
985 | int cpu = first_cpu_in_pkg[pkg]; | ||
986 | |||
987 | int msr_offset = MSR_HWP_REQUEST_PKG; | ||
988 | |||
989 | read_hwp_request(cpu, &req, msr_offset); | ||
990 | if (debug) | ||
991 | print_hwp_request_pkg(pkg, &req, "old: "); | ||
992 | |||
993 | if (update_hwp_min) | ||
994 | req.hwp_min = req_update.hwp_min; | ||
995 | |||
996 | if (update_hwp_max) | ||
997 | req.hwp_max = req_update.hwp_max; | ||
998 | |||
999 | if (update_hwp_desired) | ||
1000 | req.hwp_desired = req_update.hwp_desired; | ||
1001 | |||
1002 | if (update_hwp_window) | ||
1003 | req.hwp_window = req_update.hwp_window; | ||
1004 | |||
1005 | if (update_hwp_epp) | ||
1006 | req.hwp_epp = req_update.hwp_epp; | ||
1007 | |||
1008 | read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES); | ||
1009 | if (debug) | ||
1010 | print_hwp_cap(cpu, &cap, ""); | ||
1011 | |||
1012 | if (!force) | ||
1013 | check_hwp_request_v_hwp_capabilities(cpu, &req, &cap); | ||
1014 | |||
1015 | verify_hwp_req_self_consistency(cpu, &req); | ||
1016 | |||
1017 | write_hwp_request(cpu, &req, msr_offset); | ||
225 | 1018 | ||
226 | retval = pread(fd, &old_msr, sizeof old_msr, offset); | 1019 | if (debug) { |
227 | if (retval != sizeof old_msr) { | 1020 | read_hwp_request(cpu, &req, msr_offset); |
228 | perror("pwrite"); | 1021 | print_hwp_request_pkg(pkg, &req, "new: "); |
229 | printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval); | ||
230 | exit(-2); | ||
231 | } | 1022 | } |
1023 | return 0; | ||
1024 | } | ||
1025 | |||
1026 | int enable_hwp_on_cpu(int cpu) | ||
1027 | { | ||
1028 | unsigned long long msr; | ||
1029 | |||
1030 | get_msr(cpu, MSR_PM_ENABLE, &msr); | ||
1031 | put_msr(cpu, MSR_PM_ENABLE, 1); | ||
1032 | |||
1033 | if (verbose) | ||
1034 | printf("cpu%d: MSR_PM_ENABLE old: %d new: %d\n", cpu, (unsigned int) msr, 1); | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | |||
1039 | int update_cpu_msrs(int cpu) | ||
1040 | { | ||
1041 | unsigned long long msr; | ||
1042 | |||
232 | 1043 | ||
233 | retval = pwrite(fd, &new_msr, sizeof new_msr, offset); | 1044 | if (update_epb) { |
234 | if (retval != sizeof new_msr) { | 1045 | get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr); |
235 | perror("pwrite"); | 1046 | put_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, new_epb); |
236 | printf("pwrite cpu%d 0x%x = %d\n", cpu, offset, retval); | 1047 | |
237 | exit(-2); | 1048 | if (verbose) |
1049 | printf("cpu%d: ENERGY_PERF_BIAS old: %d new: %d\n", | ||
1050 | cpu, (unsigned int) msr, (unsigned int) new_epb); | ||
238 | } | 1051 | } |
239 | 1052 | ||
240 | close(fd); | 1053 | if (update_turbo) { |
1054 | int turbo_is_present_and_disabled; | ||
1055 | |||
1056 | get_msr(cpu, MSR_IA32_MISC_ENABLE, &msr); | ||
1057 | |||
1058 | turbo_is_present_and_disabled = ((msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE) != 0); | ||
1059 | |||
1060 | if (turbo_update_value == 1) { | ||
1061 | if (turbo_is_present_and_disabled) { | ||
1062 | msr &= ~MSR_IA32_MISC_ENABLE_TURBO_DISABLE; | ||
1063 | put_msr(cpu, MSR_IA32_MISC_ENABLE, msr); | ||
1064 | if (verbose) | ||
1065 | printf("cpu%d: turbo ENABLE\n", cpu); | ||
1066 | } | ||
1067 | } else { | ||
1068 | /* | ||
1069 | * if "turbo_is_enabled" were known to be describe this cpu | ||
1070 | * then we could use it here to skip redundant disable requests. | ||
1071 | * but cpu may be in a different package, so we always write. | ||
1072 | */ | ||
1073 | msr |= MSR_IA32_MISC_ENABLE_TURBO_DISABLE; | ||
1074 | put_msr(cpu, MSR_IA32_MISC_ENABLE, msr); | ||
1075 | if (verbose) | ||
1076 | printf("cpu%d: turbo DISABLE\n", cpu); | ||
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | if (!has_hwp) | ||
1081 | return 0; | ||
1082 | |||
1083 | if (!hwp_update_enabled()) | ||
1084 | return 0; | ||
1085 | |||
1086 | update_hwp_request(cpu); | ||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | /* | ||
1091 | * Open a file, and exit on failure | ||
1092 | */ | ||
1093 | FILE *fopen_or_die(const char *path, const char *mode) | ||
1094 | { | ||
1095 | FILE *filep = fopen(path, "r"); | ||
241 | 1096 | ||
242 | return old_msr; | 1097 | if (!filep) |
1098 | err(1, "%s: open failed", path); | ||
1099 | return filep; | ||
243 | } | 1100 | } |
244 | 1101 | ||
245 | void print_msr(int cpu) | 1102 | unsigned int get_pkg_num(int cpu) |
246 | { | 1103 | { |
247 | printf("cpu%d: 0x%016llx\n", | 1104 | FILE *fp; |
248 | cpu, get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS)); | 1105 | char pathname[128]; |
1106 | unsigned int pkg; | ||
1107 | int retval; | ||
1108 | |||
1109 | sprintf(pathname, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); | ||
1110 | |||
1111 | fp = fopen_or_die(pathname, "r"); | ||
1112 | retval = fscanf(fp, "%d\n", &pkg); | ||
1113 | if (retval != 1) | ||
1114 | errx(1, "%s: failed to parse", pathname); | ||
1115 | return pkg; | ||
249 | } | 1116 | } |
250 | 1117 | ||
251 | void update_msr(int cpu) | 1118 | int set_max_cpu_pkg_num(int cpu) |
252 | { | 1119 | { |
253 | unsigned long long previous_msr; | 1120 | unsigned int pkg; |
254 | 1121 | ||
255 | previous_msr = put_msr(cpu, new_bias, MSR_IA32_ENERGY_PERF_BIAS); | 1122 | if (max_cpu_num < cpu) |
1123 | max_cpu_num = cpu; | ||
256 | 1124 | ||
257 | if (verbose) | 1125 | pkg = get_pkg_num(cpu); |
258 | printf("cpu%d msr0x%x 0x%016llx -> 0x%016llx\n", | 1126 | |
259 | cpu, MSR_IA32_ENERGY_PERF_BIAS, previous_msr, new_bias); | 1127 | if (pkg >= MAX_PACKAGES) |
1128 | errx(1, "cpu%d: %d >= MAX_PACKAGES (%d)", cpu, pkg, MAX_PACKAGES); | ||
1129 | |||
1130 | if (pkg > max_pkg_num) | ||
1131 | max_pkg_num = pkg; | ||
260 | 1132 | ||
261 | return; | 1133 | if ((pkg_present_set & (1ULL << pkg)) == 0) { |
1134 | pkg_present_set |= (1ULL << pkg); | ||
1135 | first_cpu_in_pkg[pkg] = cpu; | ||
1136 | } | ||
1137 | |||
1138 | return 0; | ||
1139 | } | ||
1140 | int mark_cpu_present(int cpu) | ||
1141 | { | ||
1142 | CPU_SET_S(cpu, cpu_setsize, cpu_present_set); | ||
1143 | return 0; | ||
262 | } | 1144 | } |
263 | 1145 | ||
264 | char *proc_stat = "/proc/stat"; | ||
265 | /* | 1146 | /* |
266 | * run func() on every cpu in /dev/cpu | 1147 | * run func(cpu) on every cpu in /proc/stat |
1148 | * return max_cpu number | ||
267 | */ | 1149 | */ |
268 | void for_every_cpu(void (func)(int)) | 1150 | int for_all_proc_cpus(int (func)(int)) |
269 | { | 1151 | { |
270 | FILE *fp; | 1152 | FILE *fp; |
1153 | int cpu_num; | ||
271 | int retval; | 1154 | int retval; |
272 | 1155 | ||
273 | fp = fopen(proc_stat, "r"); | 1156 | fp = fopen_or_die(proc_stat, "r"); |
274 | if (fp == NULL) { | ||
275 | perror(proc_stat); | ||
276 | exit(1); | ||
277 | } | ||
278 | 1157 | ||
279 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); | 1158 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); |
280 | if (retval != 0) { | 1159 | if (retval != 0) |
281 | perror("/proc/stat format"); | 1160 | err(1, "%s: failed to parse format", proc_stat); |
282 | exit(1); | ||
283 | } | ||
284 | 1161 | ||
285 | while (1) { | 1162 | while (1) { |
286 | int cpu; | 1163 | retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); |
287 | |||
288 | retval = fscanf(fp, | ||
289 | "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", | ||
290 | &cpu); | ||
291 | if (retval != 1) | 1164 | if (retval != 1) |
292 | break; | 1165 | break; |
293 | 1166 | ||
294 | func(cpu); | 1167 | retval = func(cpu_num); |
1168 | if (retval) { | ||
1169 | fclose(fp); | ||
1170 | return retval; | ||
1171 | } | ||
295 | } | 1172 | } |
296 | fclose(fp); | 1173 | fclose(fp); |
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | void for_all_cpus_in_set(size_t set_size, cpu_set_t *cpu_set, int (func)(int)) | ||
1178 | { | ||
1179 | int cpu_num; | ||
1180 | |||
1181 | for (cpu_num = 0; cpu_num <= max_cpu_num; ++cpu_num) | ||
1182 | if (CPU_ISSET_S(cpu_num, set_size, cpu_set)) | ||
1183 | func(cpu_num); | ||
1184 | } | ||
1185 | |||
1186 | void init_data_structures(void) | ||
1187 | { | ||
1188 | for_all_proc_cpus(set_max_cpu_pkg_num); | ||
1189 | |||
1190 | cpu_setsize = CPU_ALLOC_SIZE((max_cpu_num + 1)); | ||
1191 | |||
1192 | cpu_present_set = CPU_ALLOC((max_cpu_num + 1)); | ||
1193 | if (cpu_present_set == NULL) | ||
1194 | err(3, "CPU_ALLOC"); | ||
1195 | CPU_ZERO_S(cpu_setsize, cpu_present_set); | ||
1196 | for_all_proc_cpus(mark_cpu_present); | ||
1197 | } | ||
1198 | |||
1199 | /* clear has_hwp if it is not enable (or being enabled) */ | ||
1200 | |||
1201 | void verify_hwp_is_enabled(void) | ||
1202 | { | ||
1203 | unsigned long long msr; | ||
1204 | |||
1205 | if (!has_hwp) /* set in early_cpuid() */ | ||
1206 | return; | ||
1207 | |||
1208 | /* MSR_PM_ENABLE[1] == 1 if HWP is enabled and MSRs visible */ | ||
1209 | get_msr(base_cpu, MSR_PM_ENABLE, &msr); | ||
1210 | if ((msr & 1) == 0) { | ||
1211 | fprintf(stderr, "HWP can be enabled using '--hwp-enable'\n"); | ||
1212 | has_hwp = 0; | ||
1213 | return; | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | int req_update_bounds_check(void) | ||
1218 | { | ||
1219 | if (!hwp_update_enabled()) | ||
1220 | return 0; | ||
1221 | |||
1222 | /* fail if min > max requested */ | ||
1223 | if ((update_hwp_max && update_hwp_min) && | ||
1224 | (req_update.hwp_min > req_update.hwp_max)) { | ||
1225 | printf("hwp-min %d > hwp_max %d\n", req_update.hwp_min, req_update.hwp_max); | ||
1226 | return -EINVAL; | ||
1227 | } | ||
1228 | |||
1229 | /* fail if desired > max requestd */ | ||
1230 | if (req_update.hwp_desired && update_hwp_max && | ||
1231 | (req_update.hwp_desired > req_update.hwp_max)) { | ||
1232 | printf("hwp-desired cannot be greater than hwp_max\n"); | ||
1233 | return -EINVAL; | ||
1234 | } | ||
1235 | /* fail if desired < min requestd */ | ||
1236 | if (req_update.hwp_desired && update_hwp_min && | ||
1237 | (req_update.hwp_desired < req_update.hwp_min)) { | ||
1238 | printf("hwp-desired cannot be less than hwp_min\n"); | ||
1239 | return -EINVAL; | ||
1240 | } | ||
1241 | |||
1242 | return 0; | ||
1243 | } | ||
1244 | |||
1245 | void set_base_cpu(void) | ||
1246 | { | ||
1247 | base_cpu = sched_getcpu(); | ||
1248 | if (base_cpu < 0) | ||
1249 | err(-ENODEV, "No valid cpus found"); | ||
1250 | } | ||
1251 | |||
1252 | |||
1253 | void probe_dev_msr(void) | ||
1254 | { | ||
1255 | struct stat sb; | ||
1256 | char pathname[32]; | ||
1257 | |||
1258 | sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); | ||
1259 | if (stat(pathname, &sb)) | ||
1260 | if (system("/sbin/modprobe msr > /dev/null 2>&1")) | ||
1261 | err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" "); | ||
1262 | } | ||
1263 | /* | ||
1264 | * early_cpuid() | ||
1265 | * initialize turbo_is_enabled, has_hwp, has_epb | ||
1266 | * before cmdline is parsed | ||
1267 | */ | ||
1268 | void early_cpuid(void) | ||
1269 | { | ||
1270 | unsigned int eax, ebx, ecx, edx, max_level; | ||
1271 | unsigned int fms, family, model; | ||
1272 | |||
1273 | __get_cpuid(0, &max_level, &ebx, &ecx, &edx); | ||
1274 | |||
1275 | if (max_level < 6) | ||
1276 | errx(1, "Processor not supported\n"); | ||
1277 | |||
1278 | __get_cpuid(1, &fms, &ebx, &ecx, &edx); | ||
1279 | family = (fms >> 8) & 0xf; | ||
1280 | model = (fms >> 4) & 0xf; | ||
1281 | if (family == 6 || family == 0xf) | ||
1282 | model += ((fms >> 16) & 0xf) << 4; | ||
1283 | |||
1284 | if (model == 0x4F) { | ||
1285 | unsigned long long msr; | ||
1286 | |||
1287 | get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr); | ||
1288 | |||
1289 | bdx_highest_ratio = msr & 0xFF; | ||
1290 | } | ||
1291 | |||
1292 | __get_cpuid(0x6, &eax, &ebx, &ecx, &edx); | ||
1293 | turbo_is_enabled = (eax >> 1) & 1; | ||
1294 | has_hwp = (eax >> 7) & 1; | ||
1295 | has_epb = (ecx >> 3) & 1; | ||
1296 | } | ||
1297 | |||
1298 | /* | ||
1299 | * parse_cpuid() | ||
1300 | * set | ||
1301 | * has_hwp, has_hwp_notify, has_hwp_activity_window, has_hwp_epp, has_hwp_request_pkg, has_epb | ||
1302 | */ | ||
1303 | void parse_cpuid(void) | ||
1304 | { | ||
1305 | unsigned int eax, ebx, ecx, edx, max_level; | ||
1306 | unsigned int fms, family, model, stepping; | ||
1307 | |||
1308 | eax = ebx = ecx = edx = 0; | ||
1309 | |||
1310 | __get_cpuid(0, &max_level, &ebx, &ecx, &edx); | ||
1311 | |||
1312 | if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) | ||
1313 | genuine_intel = 1; | ||
1314 | |||
1315 | if (debug) | ||
1316 | fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", | ||
1317 | (char *)&ebx, (char *)&edx, (char *)&ecx); | ||
1318 | |||
1319 | __get_cpuid(1, &fms, &ebx, &ecx, &edx); | ||
1320 | family = (fms >> 8) & 0xf; | ||
1321 | model = (fms >> 4) & 0xf; | ||
1322 | stepping = fms & 0xf; | ||
1323 | if (family == 6 || family == 0xf) | ||
1324 | model += ((fms >> 16) & 0xf) << 4; | ||
1325 | |||
1326 | if (debug) { | ||
1327 | fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", | ||
1328 | max_level, family, model, stepping, family, model, stepping); | ||
1329 | fprintf(stderr, "CPUID(1): %s %s %s %s %s %s %s %s\n", | ||
1330 | ecx & (1 << 0) ? "SSE3" : "-", | ||
1331 | ecx & (1 << 3) ? "MONITOR" : "-", | ||
1332 | ecx & (1 << 7) ? "EIST" : "-", | ||
1333 | ecx & (1 << 8) ? "TM2" : "-", | ||
1334 | edx & (1 << 4) ? "TSC" : "-", | ||
1335 | edx & (1 << 5) ? "MSR" : "-", | ||
1336 | edx & (1 << 22) ? "ACPI-TM" : "-", | ||
1337 | edx & (1 << 29) ? "TM" : "-"); | ||
1338 | } | ||
1339 | |||
1340 | if (!(edx & (1 << 5))) | ||
1341 | errx(1, "CPUID: no MSR"); | ||
1342 | |||
1343 | |||
1344 | __get_cpuid(0x6, &eax, &ebx, &ecx, &edx); | ||
1345 | /* turbo_is_enabled already set */ | ||
1346 | /* has_hwp already set */ | ||
1347 | has_hwp_notify = eax & (1 << 8); | ||
1348 | has_hwp_activity_window = eax & (1 << 9); | ||
1349 | has_hwp_epp = eax & (1 << 10); | ||
1350 | has_hwp_request_pkg = eax & (1 << 11); | ||
1351 | |||
1352 | if (!has_hwp_request_pkg && update_hwp_use_pkg) | ||
1353 | errx(1, "--hwp-use-pkg is not available on this hardware"); | ||
1354 | |||
1355 | /* has_epb already set */ | ||
1356 | |||
1357 | if (debug) | ||
1358 | fprintf(stderr, | ||
1359 | "CPUID(6): %sTURBO, %sHWP, %sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n", | ||
1360 | turbo_is_enabled ? "" : "No-", | ||
1361 | has_hwp ? "" : "No-", | ||
1362 | has_hwp_notify ? "" : "No-", | ||
1363 | has_hwp_activity_window ? "" : "No-", | ||
1364 | has_hwp_epp ? "" : "No-", | ||
1365 | has_hwp_request_pkg ? "" : "No-", | ||
1366 | has_epb ? "" : "No-"); | ||
1367 | |||
1368 | return; /* success */ | ||
297 | } | 1369 | } |
298 | 1370 | ||
299 | int main(int argc, char **argv) | 1371 | int main(int argc, char **argv) |
300 | { | 1372 | { |
1373 | set_base_cpu(); | ||
1374 | probe_dev_msr(); | ||
1375 | init_data_structures(); | ||
1376 | |||
1377 | early_cpuid(); /* initial cpuid parse before cmdline */ | ||
1378 | |||
301 | cmdline(argc, argv); | 1379 | cmdline(argc, argv); |
302 | 1380 | ||
303 | if (verbose > 1) | 1381 | if (debug) |
304 | printf("x86_energy_perf_policy Nov 24, 2010" | 1382 | print_version(); |
305 | " - Len Brown <lenb@kernel.org>\n"); | 1383 | |
306 | if (verbose > 1 && !read_only) | 1384 | parse_cpuid(); |
307 | printf("new_bias %lld\n", new_bias); | 1385 | |
308 | 1386 | /* If CPU-set and PKG-set are not initialized, default to all CPUs */ | |
309 | validate_cpuid(); | 1387 | if ((cpu_selected_set == 0) && (pkg_selected_set == 0)) |
310 | 1388 | cpu_selected_set = cpu_present_set; | |
311 | if (cpu != -1) { | 1389 | |
312 | if (read_only) | 1390 | /* |
313 | print_msr(cpu); | 1391 | * If HWP is being enabled, do it now, so that subsequent operations |
314 | else | 1392 | * that access HWP registers can work. |
315 | update_msr(cpu); | 1393 | */ |
316 | } else { | 1394 | if (update_hwp_enable) |
317 | if (read_only) | 1395 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, enable_hwp_on_cpu); |
318 | for_every_cpu(print_msr); | 1396 | |
319 | else | 1397 | /* If HWP present, but disabled, warn and ignore from here forward */ |
320 | for_every_cpu(update_msr); | 1398 | verify_hwp_is_enabled(); |
1399 | |||
1400 | if (req_update_bounds_check()) | ||
1401 | return -EINVAL; | ||
1402 | |||
1403 | /* display information only, no updates to settings */ | ||
1404 | if (!update_epb && !update_turbo && !hwp_update_enabled()) { | ||
1405 | if (cpu_selected_set) | ||
1406 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, print_cpu_msrs); | ||
1407 | |||
1408 | if (has_hwp_request_pkg) { | ||
1409 | if (pkg_selected_set == 0) | ||
1410 | pkg_selected_set = pkg_present_set; | ||
1411 | |||
1412 | for_packages(pkg_selected_set, print_pkg_msrs); | ||
1413 | } | ||
1414 | |||
1415 | return 0; | ||
321 | } | 1416 | } |
322 | 1417 | ||
1418 | /* update CPU set */ | ||
1419 | if (cpu_selected_set) { | ||
1420 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_sysfs); | ||
1421 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_cpu_msrs); | ||
1422 | } else if (pkg_selected_set) | ||
1423 | for_packages(pkg_selected_set, update_hwp_request_pkg); | ||
1424 | |||
323 | return 0; | 1425 | return 0; |
324 | } | 1426 | } |
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index 64cae1a5deff..e1f75a1914a1 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c | |||
@@ -370,7 +370,7 @@ acpi_status __wrap_acpi_evaluate_object(acpi_handle handle, acpi_string path, | |||
370 | } | 370 | } |
371 | EXPORT_SYMBOL(__wrap_acpi_evaluate_object); | 371 | EXPORT_SYMBOL(__wrap_acpi_evaluate_object); |
372 | 372 | ||
373 | union acpi_object * __wrap_acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, | 373 | union acpi_object * __wrap_acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, |
374 | u64 rev, u64 func, union acpi_object *argv4) | 374 | u64 rev, u64 func, union acpi_object *argv4) |
375 | { | 375 | { |
376 | union acpi_object *obj = ERR_PTR(-ENXIO); | 376 | union acpi_object *obj = ERR_PTR(-ENXIO); |
@@ -379,11 +379,11 @@ union acpi_object * __wrap_acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, | |||
379 | rcu_read_lock(); | 379 | rcu_read_lock(); |
380 | ops = list_first_or_null_rcu(&iomap_head, typeof(*ops), list); | 380 | ops = list_first_or_null_rcu(&iomap_head, typeof(*ops), list); |
381 | if (ops) | 381 | if (ops) |
382 | obj = ops->evaluate_dsm(handle, uuid, rev, func, argv4); | 382 | obj = ops->evaluate_dsm(handle, guid, rev, func, argv4); |
383 | rcu_read_unlock(); | 383 | rcu_read_unlock(); |
384 | 384 | ||
385 | if (IS_ERR(obj)) | 385 | if (IS_ERR(obj)) |
386 | return acpi_evaluate_dsm(handle, uuid, rev, func, argv4); | 386 | return acpi_evaluate_dsm(handle, guid, rev, func, argv4); |
387 | return obj; | 387 | return obj; |
388 | } | 388 | } |
389 | EXPORT_SYMBOL(__wrap_acpi_evaluate_dsm); | 389 | EXPORT_SYMBOL(__wrap_acpi_evaluate_dsm); |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index c2187178fb13..4c2fa98ef39d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -1559,7 +1559,7 @@ static unsigned long nfit_ctl_handle; | |||
1559 | union acpi_object *result; | 1559 | union acpi_object *result; |
1560 | 1560 | ||
1561 | static union acpi_object *nfit_test_evaluate_dsm(acpi_handle handle, | 1561 | static union acpi_object *nfit_test_evaluate_dsm(acpi_handle handle, |
1562 | const u8 *uuid, u64 rev, u64 func, union acpi_object *argv4) | 1562 | const guid_t *guid, u64 rev, u64 func, union acpi_object *argv4) |
1563 | { | 1563 | { |
1564 | if (handle != &nfit_ctl_handle) | 1564 | if (handle != &nfit_ctl_handle) |
1565 | return ERR_PTR(-ENXIO); | 1565 | return ERR_PTR(-ENXIO); |
@@ -1943,7 +1943,7 @@ static __init int nfit_test_init(void) | |||
1943 | nfit_test->setup = nfit_test0_setup; | 1943 | nfit_test->setup = nfit_test0_setup; |
1944 | break; | 1944 | break; |
1945 | case 1: | 1945 | case 1: |
1946 | nfit_test->num_pm = 1; | 1946 | nfit_test->num_pm = 2; |
1947 | nfit_test->dcr_idx = NUM_DCR; | 1947 | nfit_test->dcr_idx = NUM_DCR; |
1948 | nfit_test->num_dcr = 2; | 1948 | nfit_test->num_dcr = 2; |
1949 | nfit_test->alloc = nfit_test1_alloc; | 1949 | nfit_test->alloc = nfit_test1_alloc; |
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index f54c0032c6ff..d3d63dd5ed38 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #ifndef __NFIT_TEST_H__ | 13 | #ifndef __NFIT_TEST_H__ |
14 | #define __NFIT_TEST_H__ | 14 | #define __NFIT_TEST_H__ |
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/uuid.h> | ||
16 | #include <linux/ioport.h> | 17 | #include <linux/ioport.h> |
17 | #include <linux/spinlock_types.h> | 18 | #include <linux/spinlock_types.h> |
18 | 19 | ||
@@ -36,7 +37,8 @@ typedef void *acpi_handle; | |||
36 | 37 | ||
37 | typedef struct nfit_test_resource *(*nfit_test_lookup_fn)(resource_size_t); | 38 | typedef struct nfit_test_resource *(*nfit_test_lookup_fn)(resource_size_t); |
38 | typedef union acpi_object *(*nfit_test_evaluate_dsm_fn)(acpi_handle handle, | 39 | typedef union acpi_object *(*nfit_test_evaluate_dsm_fn)(acpi_handle handle, |
39 | const u8 *uuid, u64 rev, u64 func, union acpi_object *argv4); | 40 | const guid_t *guid, u64 rev, u64 func, |
41 | union acpi_object *argv4); | ||
40 | void __iomem *__wrap_ioremap_nocache(resource_size_t offset, | 42 | void __iomem *__wrap_ioremap_nocache(resource_size_t offset, |
41 | unsigned long size); | 43 | unsigned long size); |
42 | void __wrap_iounmap(volatile void __iomem *addr); | 44 | void __wrap_iounmap(volatile void __iomem *addr); |
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 91edd0566237..2ca51a8a588c 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
@@ -11,9 +11,11 @@ endif | |||
11 | CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include | 11 | CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include |
12 | LDLIBS += -lcap -lelf | 12 | LDLIBS += -lcap -lelf |
13 | 13 | ||
14 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs | 14 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ |
15 | test_align | ||
15 | 16 | ||
16 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o | 17 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ |
18 | test_pkt_md_access.o | ||
17 | 19 | ||
18 | TEST_PROGS := test_kmod.sh | 20 | TEST_PROGS := test_kmod.sh |
19 | 21 | ||
@@ -34,6 +36,7 @@ $(BPFOBJ): force | |||
34 | CLANG ?= clang | 36 | CLANG ?= clang |
35 | 37 | ||
36 | %.o: %.c | 38 | %.o: %.c |
37 | $(CLANG) -I. -I../../../include/uapi -I../../../../samples/bpf/ \ | 39 | $(CLANG) -I. -I./include/uapi -I../../../include/uapi \ |
40 | -I../../../../samples/bpf/ \ | ||
38 | -Wno-compare-distinct-pointer-types \ | 41 | -Wno-compare-distinct-pointer-types \ |
39 | -O2 -target bpf -c $< -o $@ | 42 | -O2 -target bpf -c $< -o $@ |
diff --git a/tools/testing/selftests/bpf/bpf_endian.h b/tools/testing/selftests/bpf/bpf_endian.h index 19d0604f8694..487cbfb89beb 100644 --- a/tools/testing/selftests/bpf/bpf_endian.h +++ b/tools/testing/selftests/bpf/bpf_endian.h | |||
@@ -1,23 +1,42 @@ | |||
1 | #ifndef __BPF_ENDIAN__ | 1 | #ifndef __BPF_ENDIAN__ |
2 | #define __BPF_ENDIAN__ | 2 | #define __BPF_ENDIAN__ |
3 | 3 | ||
4 | #include <asm/byteorder.h> | 4 | #include <linux/swab.h> |
5 | 5 | ||
6 | #if __BYTE_ORDER == __LITTLE_ENDIAN | 6 | /* LLVM's BPF target selects the endianness of the CPU |
7 | # define __bpf_ntohs(x) __builtin_bswap16(x) | 7 | * it compiles on, or the user specifies (bpfel/bpfeb), |
8 | # define __bpf_htons(x) __builtin_bswap16(x) | 8 | * respectively. The used __BYTE_ORDER__ is defined by |
9 | #elif __BYTE_ORDER == __BIG_ENDIAN | 9 | * the compiler, we cannot rely on __BYTE_ORDER from |
10 | # define __bpf_ntohs(x) (x) | 10 | * libc headers, since it doesn't reflect the actual |
11 | # define __bpf_htons(x) (x) | 11 | * requested byte order. |
12 | * | ||
13 | * Note, LLVM's BPF target has different __builtin_bswapX() | ||
14 | * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE | ||
15 | * in bpfel and bpfeb case, which means below, that we map | ||
16 | * to cpu_to_be16(). We could use it unconditionally in BPF | ||
17 | * case, but better not rely on it, so that this header here | ||
18 | * can be used from application and BPF program side, which | ||
19 | * use different targets. | ||
20 | */ | ||
21 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||
22 | # define __bpf_ntohs(x) __builtin_bswap16(x) | ||
23 | # define __bpf_htons(x) __builtin_bswap16(x) | ||
24 | # define __bpf_constant_ntohs(x) ___constant_swab16(x) | ||
25 | # define __bpf_constant_htons(x) ___constant_swab16(x) | ||
26 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | ||
27 | # define __bpf_ntohs(x) (x) | ||
28 | # define __bpf_htons(x) (x) | ||
29 | # define __bpf_constant_ntohs(x) (x) | ||
30 | # define __bpf_constant_htons(x) (x) | ||
12 | #else | 31 | #else |
13 | # error "Fix your __BYTE_ORDER?!" | 32 | # error "Fix your compiler's __BYTE_ORDER__?!" |
14 | #endif | 33 | #endif |
15 | 34 | ||
16 | #define bpf_htons(x) \ | 35 | #define bpf_htons(x) \ |
17 | (__builtin_constant_p(x) ? \ | 36 | (__builtin_constant_p(x) ? \ |
18 | __constant_htons(x) : __bpf_htons(x)) | 37 | __bpf_constant_htons(x) : __bpf_htons(x)) |
19 | #define bpf_ntohs(x) \ | 38 | #define bpf_ntohs(x) \ |
20 | (__builtin_constant_p(x) ? \ | 39 | (__builtin_constant_p(x) ? \ |
21 | __constant_ntohs(x) : __bpf_ntohs(x)) | 40 | __bpf_constant_ntohs(x) : __bpf_ntohs(x)) |
22 | 41 | ||
23 | #endif | 42 | #endif /* __BPF_ENDIAN__ */ |
diff --git a/tools/testing/selftests/bpf/include/uapi/linux/types.h b/tools/testing/selftests/bpf/include/uapi/linux/types.h new file mode 100644 index 000000000000..51841848fbfe --- /dev/null +++ b/tools/testing/selftests/bpf/include/uapi/linux/types.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef _UAPI_LINUX_TYPES_H | ||
2 | #define _UAPI_LINUX_TYPES_H | ||
3 | |||
4 | #include <asm-generic/int-ll64.h> | ||
5 | |||
6 | /* copied from linux:include/uapi/linux/types.h */ | ||
7 | #define __bitwise | ||
8 | typedef __u16 __bitwise __le16; | ||
9 | typedef __u16 __bitwise __be16; | ||
10 | typedef __u32 __bitwise __le32; | ||
11 | typedef __u32 __bitwise __be32; | ||
12 | typedef __u64 __bitwise __le64; | ||
13 | typedef __u64 __bitwise __be64; | ||
14 | |||
15 | typedef __u16 __bitwise __sum16; | ||
16 | typedef __u32 __bitwise __wsum; | ||
17 | |||
18 | #define __aligned_u64 __u64 __attribute__((aligned(8))) | ||
19 | #define __aligned_be64 __be64 __attribute__((aligned(8))) | ||
20 | #define __aligned_le64 __le64 __attribute__((aligned(8))) | ||
21 | |||
22 | #endif /* _UAPI_LINUX_TYPES_H */ | ||
diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c new file mode 100644 index 000000000000..bccebd935907 --- /dev/null +++ b/tools/testing/selftests/bpf/test_align.c | |||
@@ -0,0 +1,458 @@ | |||
1 | #include <asm/types.h> | ||
2 | #include <linux/types.h> | ||
3 | #include <stdint.h> | ||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <unistd.h> | ||
7 | #include <errno.h> | ||
8 | #include <string.h> | ||
9 | #include <stddef.h> | ||
10 | #include <stdbool.h> | ||
11 | |||
12 | #include <sys/resource.h> | ||
13 | |||
14 | #include <linux/unistd.h> | ||
15 | #include <linux/filter.h> | ||
16 | #include <linux/bpf_perf_event.h> | ||
17 | #include <linux/bpf.h> | ||
18 | |||
19 | #include <bpf/bpf.h> | ||
20 | |||
21 | #include "../../../include/linux/filter.h" | ||
22 | |||
23 | #ifndef ARRAY_SIZE | ||
24 | # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
25 | #endif | ||
26 | |||
27 | #define MAX_INSNS 512 | ||
28 | #define MAX_MATCHES 16 | ||
29 | |||
30 | struct bpf_align_test { | ||
31 | const char *descr; | ||
32 | struct bpf_insn insns[MAX_INSNS]; | ||
33 | enum { | ||
34 | UNDEF, | ||
35 | ACCEPT, | ||
36 | REJECT | ||
37 | } result; | ||
38 | enum bpf_prog_type prog_type; | ||
39 | const char *matches[MAX_MATCHES]; | ||
40 | }; | ||
41 | |||
42 | static struct bpf_align_test tests[] = { | ||
43 | { | ||
44 | .descr = "mov", | ||
45 | .insns = { | ||
46 | BPF_MOV64_IMM(BPF_REG_3, 2), | ||
47 | BPF_MOV64_IMM(BPF_REG_3, 4), | ||
48 | BPF_MOV64_IMM(BPF_REG_3, 8), | ||
49 | BPF_MOV64_IMM(BPF_REG_3, 16), | ||
50 | BPF_MOV64_IMM(BPF_REG_3, 32), | ||
51 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
52 | BPF_EXIT_INSN(), | ||
53 | }, | ||
54 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
55 | .matches = { | ||
56 | "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp", | ||
57 | "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | ||
58 | "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | ||
59 | "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp", | ||
60 | "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp", | ||
61 | }, | ||
62 | }, | ||
63 | { | ||
64 | .descr = "shift", | ||
65 | .insns = { | ||
66 | BPF_MOV64_IMM(BPF_REG_3, 1), | ||
67 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
68 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
69 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
70 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
71 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_3, 4), | ||
72 | BPF_MOV64_IMM(BPF_REG_4, 32), | ||
73 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
74 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
75 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
76 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
77 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
78 | BPF_EXIT_INSN(), | ||
79 | }, | ||
80 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
81 | .matches = { | ||
82 | "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp", | ||
83 | "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp", | ||
84 | "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | ||
85 | "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | ||
86 | "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp", | ||
87 | "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp", | ||
88 | "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp", | ||
89 | "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp", | ||
90 | "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | ||
91 | "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | ||
92 | "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp", | ||
93 | }, | ||
94 | }, | ||
95 | { | ||
96 | .descr = "addsub", | ||
97 | .insns = { | ||
98 | BPF_MOV64_IMM(BPF_REG_3, 4), | ||
99 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 4), | ||
100 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 2), | ||
101 | BPF_MOV64_IMM(BPF_REG_4, 8), | ||
102 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
103 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2), | ||
104 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
105 | BPF_EXIT_INSN(), | ||
106 | }, | ||
107 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
108 | .matches = { | ||
109 | "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | ||
110 | "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp", | ||
111 | "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp", | ||
112 | "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | ||
113 | "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp", | ||
114 | "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp", | ||
115 | }, | ||
116 | }, | ||
117 | { | ||
118 | .descr = "mul", | ||
119 | .insns = { | ||
120 | BPF_MOV64_IMM(BPF_REG_3, 7), | ||
121 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 1), | ||
122 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 2), | ||
123 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 4), | ||
124 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
125 | BPF_EXIT_INSN(), | ||
126 | }, | ||
127 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
128 | .matches = { | ||
129 | "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp", | ||
130 | "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp", | ||
131 | "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp", | ||
132 | "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp", | ||
133 | }, | ||
134 | }, | ||
135 | |||
136 | #define PREP_PKT_POINTERS \ | ||
137 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \ | ||
138 | offsetof(struct __sk_buff, data)), \ | ||
139 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \ | ||
140 | offsetof(struct __sk_buff, data_end)) | ||
141 | |||
142 | #define LOAD_UNKNOWN(DST_REG) \ | ||
143 | PREP_PKT_POINTERS, \ | ||
144 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), \ | ||
145 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), \ | ||
146 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_0, 1), \ | ||
147 | BPF_EXIT_INSN(), \ | ||
148 | BPF_LDX_MEM(BPF_B, DST_REG, BPF_REG_2, 0) | ||
149 | |||
150 | { | ||
151 | .descr = "unknown shift", | ||
152 | .insns = { | ||
153 | LOAD_UNKNOWN(BPF_REG_3), | ||
154 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
155 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
156 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
157 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1), | ||
158 | LOAD_UNKNOWN(BPF_REG_4), | ||
159 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 5), | ||
160 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
161 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
162 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
163 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1), | ||
164 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
165 | BPF_EXIT_INSN(), | ||
166 | }, | ||
167 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
168 | .matches = { | ||
169 | "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp", | ||
170 | "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp", | ||
171 | "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp", | ||
172 | "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp", | ||
173 | "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp", | ||
174 | "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp", | ||
175 | "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp", | ||
176 | "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp", | ||
177 | "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp", | ||
178 | "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp", | ||
179 | "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp", | ||
180 | }, | ||
181 | }, | ||
182 | { | ||
183 | .descr = "unknown mul", | ||
184 | .insns = { | ||
185 | LOAD_UNKNOWN(BPF_REG_3), | ||
186 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_3), | ||
187 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 1), | ||
188 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_3), | ||
189 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2), | ||
190 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_3), | ||
191 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 4), | ||
192 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_3), | ||
193 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 8), | ||
194 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2), | ||
195 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
196 | BPF_EXIT_INSN(), | ||
197 | }, | ||
198 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
199 | .matches = { | ||
200 | "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp", | ||
201 | "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | ||
202 | "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp", | ||
203 | "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | ||
204 | "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp", | ||
205 | "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | ||
206 | "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp", | ||
207 | "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | ||
208 | "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp", | ||
209 | "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp" | ||
210 | }, | ||
211 | }, | ||
212 | { | ||
213 | .descr = "packet const offset", | ||
214 | .insns = { | ||
215 | PREP_PKT_POINTERS, | ||
216 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
217 | |||
218 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
219 | |||
220 | /* Skip over ethernet header. */ | ||
221 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14), | ||
222 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
223 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
224 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
225 | BPF_EXIT_INSN(), | ||
226 | |||
227 | BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 0), | ||
228 | BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 1), | ||
229 | BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 2), | ||
230 | BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 3), | ||
231 | BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 0), | ||
232 | BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 2), | ||
233 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0), | ||
234 | |||
235 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
236 | BPF_EXIT_INSN(), | ||
237 | }, | ||
238 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
239 | .matches = { | ||
240 | "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp", | ||
241 | "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp", | ||
242 | "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp", | ||
243 | "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp", | ||
244 | "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp", | ||
245 | "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp", | ||
246 | }, | ||
247 | }, | ||
248 | { | ||
249 | .descr = "packet variable offset", | ||
250 | .insns = { | ||
251 | LOAD_UNKNOWN(BPF_REG_6), | ||
252 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2), | ||
253 | |||
254 | /* First, add a constant to the R5 packet pointer, | ||
255 | * then a variable with a known alignment. | ||
256 | */ | ||
257 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
258 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14), | ||
259 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), | ||
260 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
261 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
262 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
263 | BPF_EXIT_INSN(), | ||
264 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0), | ||
265 | |||
266 | /* Now, test in the other direction. Adding first | ||
267 | * the variable offset to R5, then the constant. | ||
268 | */ | ||
269 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
270 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), | ||
271 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14), | ||
272 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
273 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
274 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
275 | BPF_EXIT_INSN(), | ||
276 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0), | ||
277 | |||
278 | /* Test multiple accumulations of unknown values | ||
279 | * into a packet pointer. | ||
280 | */ | ||
281 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
282 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14), | ||
283 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), | ||
284 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4), | ||
285 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), | ||
286 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
287 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
288 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
289 | BPF_EXIT_INSN(), | ||
290 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0), | ||
291 | |||
292 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
293 | BPF_EXIT_INSN(), | ||
294 | }, | ||
295 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
296 | .matches = { | ||
297 | /* Calculated offset in R6 has unknown value, but known | ||
298 | * alignment of 4. | ||
299 | */ | ||
300 | "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp", | ||
301 | |||
302 | /* Offset is added to packet pointer R5, resulting in known | ||
303 | * auxiliary alignment and offset. | ||
304 | */ | ||
305 | "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
306 | |||
307 | /* At the time the word size load is performed from R5, | ||
308 | * it's total offset is NET_IP_ALIGN + reg->off (0) + | ||
309 | * reg->aux_off (14) which is 16. Then the variable | ||
310 | * offset is considered using reg->aux_off_align which | ||
311 | * is 4 and meets the load's requirements. | ||
312 | */ | ||
313 | "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
314 | |||
315 | |||
316 | /* Variable offset is added to R5 packet pointer, | ||
317 | * resulting in auxiliary alignment of 4. | ||
318 | */ | ||
319 | "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
320 | |||
321 | /* Constant offset is added to R5, resulting in | ||
322 | * reg->off of 14. | ||
323 | */ | ||
324 | "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
325 | |||
326 | /* At the time the word size load is performed from R5, | ||
327 | * it's total offset is NET_IP_ALIGN + reg->off (14) which | ||
328 | * is 16. Then the variable offset is considered using | ||
329 | * reg->aux_off_align which is 4 and meets the load's | ||
330 | * requirements. | ||
331 | */ | ||
332 | "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
333 | |||
334 | /* Constant offset is added to R5 packet pointer, | ||
335 | * resulting in reg->off value of 14. | ||
336 | */ | ||
337 | "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp", | ||
338 | /* Variable offset is added to R5, resulting in an | ||
339 | * auxiliary offset of 14, and an auxiliary alignment of 4. | ||
340 | */ | ||
341 | "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
342 | /* Constant is added to R5 again, setting reg->off to 4. */ | ||
343 | "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
344 | /* And once more we add a variable, which causes an accumulation | ||
345 | * of reg->off into reg->aux_off_align, with resulting value of | ||
346 | * 18. The auxiliary alignment stays at 4. | ||
347 | */ | ||
348 | "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
349 | /* At the time the word size load is performed from R5, | ||
350 | * it's total offset is NET_IP_ALIGN + reg->off (0) + | ||
351 | * reg->aux_off (18) which is 20. Then the variable offset | ||
352 | * is considered using reg->aux_off_align which is 4 and meets | ||
353 | * the load's requirements. | ||
354 | */ | ||
355 | "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | ||
356 | }, | ||
357 | }, | ||
358 | }; | ||
359 | |||
360 | static int probe_filter_length(const struct bpf_insn *fp) | ||
361 | { | ||
362 | int len; | ||
363 | |||
364 | for (len = MAX_INSNS - 1; len > 0; --len) | ||
365 | if (fp[len].code != 0 || fp[len].imm != 0) | ||
366 | break; | ||
367 | return len + 1; | ||
368 | } | ||
369 | |||
370 | static char bpf_vlog[32768]; | ||
371 | |||
372 | static int do_test_single(struct bpf_align_test *test) | ||
373 | { | ||
374 | struct bpf_insn *prog = test->insns; | ||
375 | int prog_type = test->prog_type; | ||
376 | int prog_len, i; | ||
377 | int fd_prog; | ||
378 | int ret; | ||
379 | |||
380 | prog_len = probe_filter_length(prog); | ||
381 | fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, | ||
382 | prog, prog_len, 1, "GPL", 0, | ||
383 | bpf_vlog, sizeof(bpf_vlog)); | ||
384 | if (fd_prog < 0) { | ||
385 | printf("Failed to load program.\n"); | ||
386 | printf("%s", bpf_vlog); | ||
387 | ret = 1; | ||
388 | } else { | ||
389 | ret = 0; | ||
390 | for (i = 0; i < MAX_MATCHES; i++) { | ||
391 | const char *t, *m = test->matches[i]; | ||
392 | |||
393 | if (!m) | ||
394 | break; | ||
395 | t = strstr(bpf_vlog, m); | ||
396 | if (!t) { | ||
397 | printf("Failed to find match: %s\n", m); | ||
398 | ret = 1; | ||
399 | printf("%s", bpf_vlog); | ||
400 | break; | ||
401 | } | ||
402 | } | ||
403 | close(fd_prog); | ||
404 | } | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | static int do_test(unsigned int from, unsigned int to) | ||
409 | { | ||
410 | int all_pass = 0; | ||
411 | int all_fail = 0; | ||
412 | unsigned int i; | ||
413 | |||
414 | for (i = from; i < to; i++) { | ||
415 | struct bpf_align_test *test = &tests[i]; | ||
416 | int fail; | ||
417 | |||
418 | printf("Test %3d: %s ... ", | ||
419 | i, test->descr); | ||
420 | fail = do_test_single(test); | ||
421 | if (fail) { | ||
422 | all_fail++; | ||
423 | printf("FAIL\n"); | ||
424 | } else { | ||
425 | all_pass++; | ||
426 | printf("PASS\n"); | ||
427 | } | ||
428 | } | ||
429 | printf("Results: %d pass %d fail\n", | ||
430 | all_pass, all_fail); | ||
431 | return all_fail ? EXIT_FAILURE : EXIT_SUCCESS; | ||
432 | } | ||
433 | |||
434 | int main(int argc, char **argv) | ||
435 | { | ||
436 | unsigned int from = 0, to = ARRAY_SIZE(tests); | ||
437 | struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; | ||
438 | |||
439 | setrlimit(RLIMIT_MEMLOCK, &rinf); | ||
440 | |||
441 | if (argc == 3) { | ||
442 | unsigned int l = atoi(argv[argc - 2]); | ||
443 | unsigned int u = atoi(argv[argc - 1]); | ||
444 | |||
445 | if (l < to && u < to) { | ||
446 | from = l; | ||
447 | to = u + 1; | ||
448 | } | ||
449 | } else if (argc == 2) { | ||
450 | unsigned int t = atoi(argv[argc - 1]); | ||
451 | |||
452 | if (t < to) { | ||
453 | from = t; | ||
454 | to = t + 1; | ||
455 | } | ||
456 | } | ||
457 | return do_test(from, to); | ||
458 | } | ||
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 93314524de0d..79601c81e169 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c | |||
@@ -239,6 +239,54 @@ static void test_hashmap_percpu(int task, void *data) | |||
239 | close(fd); | 239 | close(fd); |
240 | } | 240 | } |
241 | 241 | ||
242 | static void test_hashmap_walk(int task, void *data) | ||
243 | { | ||
244 | int fd, i, max_entries = 100000; | ||
245 | long long key, value, next_key; | ||
246 | bool next_key_valid = true; | ||
247 | |||
248 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), | ||
249 | max_entries, map_flags); | ||
250 | if (fd < 0) { | ||
251 | printf("Failed to create hashmap '%s'!\n", strerror(errno)); | ||
252 | exit(1); | ||
253 | } | ||
254 | |||
255 | for (i = 0; i < max_entries; i++) { | ||
256 | key = i; value = key; | ||
257 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0); | ||
258 | } | ||
259 | |||
260 | for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key, | ||
261 | &next_key) == 0; i++) { | ||
262 | key = next_key; | ||
263 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0); | ||
264 | } | ||
265 | |||
266 | assert(i == max_entries); | ||
267 | |||
268 | assert(bpf_map_get_next_key(fd, NULL, &key) == 0); | ||
269 | for (i = 0; next_key_valid; i++) { | ||
270 | next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0; | ||
271 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0); | ||
272 | value++; | ||
273 | assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0); | ||
274 | key = next_key; | ||
275 | } | ||
276 | |||
277 | assert(i == max_entries); | ||
278 | |||
279 | for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key, | ||
280 | &next_key) == 0; i++) { | ||
281 | key = next_key; | ||
282 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0); | ||
283 | assert(value - 1 == key); | ||
284 | } | ||
285 | |||
286 | assert(i == max_entries); | ||
287 | close(fd); | ||
288 | } | ||
289 | |||
242 | static void test_arraymap(int task, void *data) | 290 | static void test_arraymap(int task, void *data) |
243 | { | 291 | { |
244 | int key, next_key, fd; | 292 | int key, next_key, fd; |
@@ -464,6 +512,7 @@ static void test_map_stress(void) | |||
464 | run_parallel(100, test_hashmap, NULL); | 512 | run_parallel(100, test_hashmap, NULL); |
465 | run_parallel(100, test_hashmap_percpu, NULL); | 513 | run_parallel(100, test_hashmap_percpu, NULL); |
466 | run_parallel(100, test_hashmap_sizes, NULL); | 514 | run_parallel(100, test_hashmap_sizes, NULL); |
515 | run_parallel(100, test_hashmap_walk, NULL); | ||
467 | 516 | ||
468 | run_parallel(100, test_arraymap, NULL); | 517 | run_parallel(100, test_arraymap, NULL); |
469 | run_parallel(100, test_arraymap_percpu, NULL); | 518 | run_parallel(100, test_arraymap_percpu, NULL); |
@@ -549,6 +598,7 @@ static void run_all_tests(void) | |||
549 | { | 598 | { |
550 | test_hashmap(0, NULL); | 599 | test_hashmap(0, NULL); |
551 | test_hashmap_percpu(0, NULL); | 600 | test_hashmap_percpu(0, NULL); |
601 | test_hashmap_walk(0, NULL); | ||
552 | 602 | ||
553 | test_arraymap(0, NULL); | 603 | test_arraymap(0, NULL); |
554 | test_arraymap_percpu(0, NULL); | 604 | test_arraymap_percpu(0, NULL); |
diff --git a/tools/testing/selftests/bpf/test_obj_id.c b/tools/testing/selftests/bpf/test_obj_id.c new file mode 100644 index 000000000000..880d2963b472 --- /dev/null +++ b/tools/testing/selftests/bpf/test_obj_id.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* Copyright (c) 2017 Facebook | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of version 2 of the GNU General Public | ||
5 | * License as published by the Free Software Foundation. | ||
6 | */ | ||
7 | #include <stddef.h> | ||
8 | #include <linux/bpf.h> | ||
9 | #include <linux/pkt_cls.h> | ||
10 | #include "bpf_helpers.h" | ||
11 | |||
12 | /* It is a dumb bpf program such that it must have no | ||
13 | * issue to be loaded since testing the verifier is | ||
14 | * not the focus here. | ||
15 | */ | ||
16 | |||
17 | int _version SEC("version") = 1; | ||
18 | |||
19 | struct bpf_map_def SEC("maps") test_map_id = { | ||
20 | .type = BPF_MAP_TYPE_ARRAY, | ||
21 | .key_size = sizeof(__u32), | ||
22 | .value_size = sizeof(__u64), | ||
23 | .max_entries = 1, | ||
24 | }; | ||
25 | |||
26 | SEC("test_obj_id_dummy") | ||
27 | int test_obj_id(struct __sk_buff *skb) | ||
28 | { | ||
29 | __u32 key = 0; | ||
30 | __u64 *value; | ||
31 | |||
32 | value = bpf_map_lookup_elem(&test_map_id, &key); | ||
33 | |||
34 | return TC_ACT_OK; | ||
35 | } | ||
diff --git a/tools/testing/selftests/bpf/test_pkt_access.c b/tools/testing/selftests/bpf/test_pkt_access.c index 39387bb7e08c..6e11ba11709e 100644 --- a/tools/testing/selftests/bpf/test_pkt_access.c +++ b/tools/testing/selftests/bpf/test_pkt_access.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * License as published by the Free Software Foundation. | 5 | * License as published by the Free Software Foundation. |
6 | */ | 6 | */ |
7 | #include <stddef.h> | 7 | #include <stddef.h> |
8 | #include <string.h> | ||
8 | #include <linux/bpf.h> | 9 | #include <linux/bpf.h> |
9 | #include <linux/if_ether.h> | 10 | #include <linux/if_ether.h> |
10 | #include <linux/if_packet.h> | 11 | #include <linux/if_packet.h> |
diff --git a/tools/testing/selftests/bpf/test_pkt_md_access.c b/tools/testing/selftests/bpf/test_pkt_md_access.c new file mode 100644 index 000000000000..71729d47eb85 --- /dev/null +++ b/tools/testing/selftests/bpf/test_pkt_md_access.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* Copyright (c) 2017 Facebook | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of version 2 of the GNU General Public | ||
5 | * License as published by the Free Software Foundation. | ||
6 | */ | ||
7 | #include <stddef.h> | ||
8 | #include <string.h> | ||
9 | #include <linux/bpf.h> | ||
10 | #include <linux/pkt_cls.h> | ||
11 | #include "bpf_helpers.h" | ||
12 | |||
13 | int _version SEC("version") = 1; | ||
14 | |||
15 | #define TEST_FIELD(TYPE, FIELD, MASK) \ | ||
16 | { \ | ||
17 | TYPE tmp = *(volatile TYPE *)&skb->FIELD; \ | ||
18 | if (tmp != ((*(volatile __u32 *)&skb->FIELD) & MASK)) \ | ||
19 | return TC_ACT_SHOT; \ | ||
20 | } | ||
21 | |||
22 | SEC("test1") | ||
23 | int process(struct __sk_buff *skb) | ||
24 | { | ||
25 | TEST_FIELD(__u8, len, 0xFF); | ||
26 | TEST_FIELD(__u16, len, 0xFFFF); | ||
27 | TEST_FIELD(__u32, len, 0xFFFFFFFF); | ||
28 | TEST_FIELD(__u16, protocol, 0xFFFF); | ||
29 | TEST_FIELD(__u32, protocol, 0xFFFFFFFF); | ||
30 | TEST_FIELD(__u8, hash, 0xFF); | ||
31 | TEST_FIELD(__u16, hash, 0xFFFF); | ||
32 | TEST_FIELD(__u32, hash, 0xFFFFFFFF); | ||
33 | |||
34 | return TC_ACT_OK; | ||
35 | } | ||
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index b59f5ed4ae40..5855cd3d3d45 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c | |||
@@ -22,6 +22,8 @@ typedef __u16 __sum16; | |||
22 | 22 | ||
23 | #include <sys/wait.h> | 23 | #include <sys/wait.h> |
24 | #include <sys/resource.h> | 24 | #include <sys/resource.h> |
25 | #include <sys/types.h> | ||
26 | #include <fcntl.h> | ||
25 | 27 | ||
26 | #include <linux/bpf.h> | 28 | #include <linux/bpf.h> |
27 | #include <linux/err.h> | 29 | #include <linux/err.h> |
@@ -70,6 +72,7 @@ static struct { | |||
70 | pass_cnt++; \ | 72 | pass_cnt++; \ |
71 | printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\ | 73 | printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\ |
72 | } \ | 74 | } \ |
75 | __ret; \ | ||
73 | }) | 76 | }) |
74 | 77 | ||
75 | static int bpf_prog_load(const char *file, enum bpf_prog_type type, | 78 | static int bpf_prog_load(const char *file, enum bpf_prog_type type, |
@@ -283,6 +286,224 @@ static void test_tcp_estats(void) | |||
283 | bpf_object__close(obj); | 286 | bpf_object__close(obj); |
284 | } | 287 | } |
285 | 288 | ||
289 | static inline __u64 ptr_to_u64(const void *ptr) | ||
290 | { | ||
291 | return (__u64) (unsigned long) ptr; | ||
292 | } | ||
293 | |||
294 | static void test_bpf_obj_id(void) | ||
295 | { | ||
296 | const __u64 array_magic_value = 0xfaceb00c; | ||
297 | const __u32 array_key = 0; | ||
298 | const int nr_iters = 2; | ||
299 | const char *file = "./test_obj_id.o"; | ||
300 | const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; | ||
301 | |||
302 | struct bpf_object *objs[nr_iters]; | ||
303 | int prog_fds[nr_iters], map_fds[nr_iters]; | ||
304 | /* +1 to test for the info_len returned by kernel */ | ||
305 | struct bpf_prog_info prog_infos[nr_iters + 1]; | ||
306 | struct bpf_map_info map_infos[nr_iters + 1]; | ||
307 | char jited_insns[128], xlated_insns[128]; | ||
308 | __u32 i, next_id, info_len, nr_id_found, duration = 0; | ||
309 | int sysctl_fd, jit_enabled = 0, err = 0; | ||
310 | __u64 array_value; | ||
311 | |||
312 | sysctl_fd = open(jit_sysctl, 0, O_RDONLY); | ||
313 | if (sysctl_fd != -1) { | ||
314 | char tmpc; | ||
315 | |||
316 | if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1) | ||
317 | jit_enabled = (tmpc != '0'); | ||
318 | close(sysctl_fd); | ||
319 | } | ||
320 | |||
321 | err = bpf_prog_get_fd_by_id(0); | ||
322 | CHECK(err >= 0 || errno != ENOENT, | ||
323 | "get-fd-by-notexist-prog-id", "err %d errno %d\n", err, errno); | ||
324 | |||
325 | err = bpf_map_get_fd_by_id(0); | ||
326 | CHECK(err >= 0 || errno != ENOENT, | ||
327 | "get-fd-by-notexist-map-id", "err %d errno %d\n", err, errno); | ||
328 | |||
329 | for (i = 0; i < nr_iters; i++) | ||
330 | objs[i] = NULL; | ||
331 | |||
332 | /* Check bpf_obj_get_info_by_fd() */ | ||
333 | for (i = 0; i < nr_iters; i++) { | ||
334 | err = bpf_prog_load(file, BPF_PROG_TYPE_SOCKET_FILTER, | ||
335 | &objs[i], &prog_fds[i]); | ||
336 | /* test_obj_id.o is a dumb prog. It should never fail | ||
337 | * to load. | ||
338 | */ | ||
339 | assert(!err); | ||
340 | |||
341 | /* Check getting prog info */ | ||
342 | info_len = sizeof(struct bpf_prog_info) * 2; | ||
343 | prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns); | ||
344 | prog_infos[i].jited_prog_len = sizeof(jited_insns); | ||
345 | prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns); | ||
346 | prog_infos[i].xlated_prog_len = sizeof(xlated_insns); | ||
347 | err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i], | ||
348 | &info_len); | ||
349 | if (CHECK(err || | ||
350 | prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER || | ||
351 | info_len != sizeof(struct bpf_prog_info) || | ||
352 | (jit_enabled && !prog_infos[i].jited_prog_len) || | ||
353 | !prog_infos[i].xlated_prog_len, | ||
354 | "get-prog-info(fd)", | ||
355 | "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u\n", | ||
356 | err, errno, i, | ||
357 | prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, | ||
358 | info_len, sizeof(struct bpf_prog_info), | ||
359 | jit_enabled, | ||
360 | prog_infos[i].jited_prog_len, | ||
361 | prog_infos[i].xlated_prog_len)) | ||
362 | goto done; | ||
363 | |||
364 | map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); | ||
365 | assert(map_fds[i] >= 0); | ||
366 | err = bpf_map_update_elem(map_fds[i], &array_key, | ||
367 | &array_magic_value, 0); | ||
368 | assert(!err); | ||
369 | |||
370 | /* Check getting map info */ | ||
371 | info_len = sizeof(struct bpf_map_info) * 2; | ||
372 | err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i], | ||
373 | &info_len); | ||
374 | if (CHECK(err || | ||
375 | map_infos[i].type != BPF_MAP_TYPE_ARRAY || | ||
376 | map_infos[i].key_size != sizeof(__u32) || | ||
377 | map_infos[i].value_size != sizeof(__u64) || | ||
378 | map_infos[i].max_entries != 1 || | ||
379 | map_infos[i].map_flags != 0 || | ||
380 | info_len != sizeof(struct bpf_map_info), | ||
381 | "get-map-info(fd)", | ||
382 | "err %d errno %d type %d(%d) info_len %u(%lu) key_size %u value_size %u max_entries %u map_flags %X\n", | ||
383 | err, errno, | ||
384 | map_infos[i].type, BPF_MAP_TYPE_ARRAY, | ||
385 | info_len, sizeof(struct bpf_map_info), | ||
386 | map_infos[i].key_size, | ||
387 | map_infos[i].value_size, | ||
388 | map_infos[i].max_entries, | ||
389 | map_infos[i].map_flags)) | ||
390 | goto done; | ||
391 | } | ||
392 | |||
393 | /* Check bpf_prog_get_next_id() */ | ||
394 | nr_id_found = 0; | ||
395 | next_id = 0; | ||
396 | while (!bpf_prog_get_next_id(next_id, &next_id)) { | ||
397 | struct bpf_prog_info prog_info; | ||
398 | int prog_fd; | ||
399 | |||
400 | info_len = sizeof(prog_info); | ||
401 | |||
402 | prog_fd = bpf_prog_get_fd_by_id(next_id); | ||
403 | if (prog_fd < 0 && errno == ENOENT) | ||
404 | /* The bpf_prog is in the dead row */ | ||
405 | continue; | ||
406 | if (CHECK(prog_fd < 0, "get-prog-fd(next_id)", | ||
407 | "prog_fd %d next_id %d errno %d\n", | ||
408 | prog_fd, next_id, errno)) | ||
409 | break; | ||
410 | |||
411 | for (i = 0; i < nr_iters; i++) | ||
412 | if (prog_infos[i].id == next_id) | ||
413 | break; | ||
414 | |||
415 | if (i == nr_iters) | ||
416 | continue; | ||
417 | |||
418 | nr_id_found++; | ||
419 | |||
420 | err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len); | ||
421 | CHECK(err || info_len != sizeof(struct bpf_prog_info) || | ||
422 | memcmp(&prog_info, &prog_infos[i], info_len), | ||
423 | "get-prog-info(next_id->fd)", | ||
424 | "err %d errno %d info_len %u(%lu) memcmp %d\n", | ||
425 | err, errno, info_len, sizeof(struct bpf_prog_info), | ||
426 | memcmp(&prog_info, &prog_infos[i], info_len)); | ||
427 | |||
428 | close(prog_fd); | ||
429 | } | ||
430 | CHECK(nr_id_found != nr_iters, | ||
431 | "check total prog id found by get_next_id", | ||
432 | "nr_id_found %u(%u)\n", | ||
433 | nr_id_found, nr_iters); | ||
434 | |||
435 | /* Check bpf_map_get_next_id() */ | ||
436 | nr_id_found = 0; | ||
437 | next_id = 0; | ||
438 | while (!bpf_map_get_next_id(next_id, &next_id)) { | ||
439 | struct bpf_map_info map_info; | ||
440 | int map_fd; | ||
441 | |||
442 | info_len = sizeof(map_info); | ||
443 | |||
444 | map_fd = bpf_map_get_fd_by_id(next_id); | ||
445 | if (map_fd < 0 && errno == ENOENT) | ||
446 | /* The bpf_map is in the dead row */ | ||
447 | continue; | ||
448 | if (CHECK(map_fd < 0, "get-map-fd(next_id)", | ||
449 | "map_fd %d next_id %u errno %d\n", | ||
450 | map_fd, next_id, errno)) | ||
451 | break; | ||
452 | |||
453 | for (i = 0; i < nr_iters; i++) | ||
454 | if (map_infos[i].id == next_id) | ||
455 | break; | ||
456 | |||
457 | if (i == nr_iters) | ||
458 | continue; | ||
459 | |||
460 | nr_id_found++; | ||
461 | |||
462 | err = bpf_map_lookup_elem(map_fd, &array_key, &array_value); | ||
463 | assert(!err); | ||
464 | |||
465 | err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len); | ||
466 | CHECK(err || info_len != sizeof(struct bpf_map_info) || | ||
467 | memcmp(&map_info, &map_infos[i], info_len) || | ||
468 | array_value != array_magic_value, | ||
469 | "check get-map-info(next_id->fd)", | ||
470 | "err %d errno %d info_len %u(%lu) memcmp %d array_value %llu(%llu)\n", | ||
471 | err, errno, info_len, sizeof(struct bpf_map_info), | ||
472 | memcmp(&map_info, &map_infos[i], info_len), | ||
473 | array_value, array_magic_value); | ||
474 | |||
475 | close(map_fd); | ||
476 | } | ||
477 | CHECK(nr_id_found != nr_iters, | ||
478 | "check total map id found by get_next_id", | ||
479 | "nr_id_found %u(%u)\n", | ||
480 | nr_id_found, nr_iters); | ||
481 | |||
482 | done: | ||
483 | for (i = 0; i < nr_iters; i++) | ||
484 | bpf_object__close(objs[i]); | ||
485 | } | ||
486 | |||
487 | static void test_pkt_md_access(void) | ||
488 | { | ||
489 | const char *file = "./test_pkt_md_access.o"; | ||
490 | struct bpf_object *obj; | ||
491 | __u32 duration, retval; | ||
492 | int err, prog_fd; | ||
493 | |||
494 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); | ||
495 | if (err) | ||
496 | return; | ||
497 | |||
498 | err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4), | ||
499 | NULL, NULL, &retval, &duration); | ||
500 | CHECK(err || retval, "", | ||
501 | "err %d errno %d retval %d duration %d\n", | ||
502 | err, errno, retval, duration); | ||
503 | |||
504 | bpf_object__close(obj); | ||
505 | } | ||
506 | |||
286 | int main(void) | 507 | int main(void) |
287 | { | 508 | { |
288 | struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; | 509 | struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; |
@@ -293,7 +514,9 @@ int main(void) | |||
293 | test_xdp(); | 514 | test_xdp(); |
294 | test_l4lb(); | 515 | test_l4lb(); |
295 | test_tcp_estats(); | 516 | test_tcp_estats(); |
517 | test_bpf_obj_id(); | ||
518 | test_pkt_md_access(); | ||
296 | 519 | ||
297 | printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); | 520 | printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); |
298 | return 0; | 521 | return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; |
299 | } | 522 | } |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 3773562056da..404aec520812 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #define MAX_NR_MAPS 4 | 49 | #define MAX_NR_MAPS 4 |
50 | 50 | ||
51 | #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) | 51 | #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) |
52 | #define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1) | ||
52 | 53 | ||
53 | struct bpf_test { | 54 | struct bpf_test { |
54 | const char *descr; | 55 | const char *descr; |
@@ -1072,44 +1073,75 @@ static struct bpf_test tests[] = { | |||
1072 | .result = ACCEPT, | 1073 | .result = ACCEPT, |
1073 | }, | 1074 | }, |
1074 | { | 1075 | { |
1075 | "check cb access: byte, oob 1", | 1076 | "__sk_buff->hash, offset 0, byte store not permitted", |
1076 | .insns = { | 1077 | .insns = { |
1077 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1078 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1078 | BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, | 1079 | BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, |
1079 | offsetof(struct __sk_buff, cb[4]) + 4), | 1080 | offsetof(struct __sk_buff, hash)), |
1080 | BPF_EXIT_INSN(), | 1081 | BPF_EXIT_INSN(), |
1081 | }, | 1082 | }, |
1082 | .errstr = "invalid bpf_context access", | 1083 | .errstr = "invalid bpf_context access", |
1083 | .result = REJECT, | 1084 | .result = REJECT, |
1084 | }, | 1085 | }, |
1085 | { | 1086 | { |
1086 | "check cb access: byte, oob 2", | 1087 | "__sk_buff->tc_index, offset 3, byte store not permitted", |
1087 | .insns = { | 1088 | .insns = { |
1088 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1089 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1089 | BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, | 1090 | BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, |
1090 | offsetof(struct __sk_buff, cb[0]) - 1), | 1091 | offsetof(struct __sk_buff, tc_index) + 3), |
1091 | BPF_EXIT_INSN(), | 1092 | BPF_EXIT_INSN(), |
1092 | }, | 1093 | }, |
1093 | .errstr = "invalid bpf_context access", | 1094 | .errstr = "invalid bpf_context access", |
1094 | .result = REJECT, | 1095 | .result = REJECT, |
1095 | }, | 1096 | }, |
1096 | { | 1097 | { |
1097 | "check cb access: byte, oob 3", | 1098 | "check skb->hash byte load permitted", |
1098 | .insns = { | 1099 | .insns = { |
1099 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1100 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1101 | #ifdef __LITTLE_ENDIAN | ||
1100 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | 1102 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, |
1101 | offsetof(struct __sk_buff, cb[4]) + 4), | 1103 | offsetof(struct __sk_buff, hash)), |
1104 | #else | ||
1105 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | ||
1106 | offsetof(struct __sk_buff, hash) + 3), | ||
1107 | #endif | ||
1108 | BPF_EXIT_INSN(), | ||
1109 | }, | ||
1110 | .result = ACCEPT, | ||
1111 | }, | ||
1112 | { | ||
1113 | "check skb->hash byte load not permitted 1", | ||
1114 | .insns = { | ||
1115 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1116 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | ||
1117 | offsetof(struct __sk_buff, hash) + 1), | ||
1102 | BPF_EXIT_INSN(), | 1118 | BPF_EXIT_INSN(), |
1103 | }, | 1119 | }, |
1104 | .errstr = "invalid bpf_context access", | 1120 | .errstr = "invalid bpf_context access", |
1105 | .result = REJECT, | 1121 | .result = REJECT, |
1106 | }, | 1122 | }, |
1107 | { | 1123 | { |
1108 | "check cb access: byte, oob 4", | 1124 | "check skb->hash byte load not permitted 2", |
1109 | .insns = { | 1125 | .insns = { |
1110 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1126 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1111 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | 1127 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, |
1112 | offsetof(struct __sk_buff, cb[0]) - 1), | 1128 | offsetof(struct __sk_buff, hash) + 2), |
1129 | BPF_EXIT_INSN(), | ||
1130 | }, | ||
1131 | .errstr = "invalid bpf_context access", | ||
1132 | .result = REJECT, | ||
1133 | }, | ||
1134 | { | ||
1135 | "check skb->hash byte load not permitted 3", | ||
1136 | .insns = { | ||
1137 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1138 | #ifdef __LITTLE_ENDIAN | ||
1139 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | ||
1140 | offsetof(struct __sk_buff, hash) + 3), | ||
1141 | #else | ||
1142 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | ||
1143 | offsetof(struct __sk_buff, hash)), | ||
1144 | #endif | ||
1113 | BPF_EXIT_INSN(), | 1145 | BPF_EXIT_INSN(), |
1114 | }, | 1146 | }, |
1115 | .errstr = "invalid bpf_context access", | 1147 | .errstr = "invalid bpf_context access", |
@@ -1187,44 +1219,53 @@ static struct bpf_test tests[] = { | |||
1187 | .result = REJECT, | 1219 | .result = REJECT, |
1188 | }, | 1220 | }, |
1189 | { | 1221 | { |
1190 | "check cb access: half, oob 1", | 1222 | "check __sk_buff->hash, offset 0, half store not permitted", |
1191 | .insns = { | 1223 | .insns = { |
1192 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1224 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1193 | BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0, | 1225 | BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0, |
1194 | offsetof(struct __sk_buff, cb[4]) + 4), | 1226 | offsetof(struct __sk_buff, hash)), |
1195 | BPF_EXIT_INSN(), | 1227 | BPF_EXIT_INSN(), |
1196 | }, | 1228 | }, |
1197 | .errstr = "invalid bpf_context access", | 1229 | .errstr = "invalid bpf_context access", |
1198 | .result = REJECT, | 1230 | .result = REJECT, |
1199 | }, | 1231 | }, |
1200 | { | 1232 | { |
1201 | "check cb access: half, oob 2", | 1233 | "check __sk_buff->tc_index, offset 2, half store not permitted", |
1202 | .insns = { | 1234 | .insns = { |
1203 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1235 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1204 | BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0, | 1236 | BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0, |
1205 | offsetof(struct __sk_buff, cb[0]) - 2), | 1237 | offsetof(struct __sk_buff, tc_index) + 2), |
1206 | BPF_EXIT_INSN(), | 1238 | BPF_EXIT_INSN(), |
1207 | }, | 1239 | }, |
1208 | .errstr = "invalid bpf_context access", | 1240 | .errstr = "invalid bpf_context access", |
1209 | .result = REJECT, | 1241 | .result = REJECT, |
1210 | }, | 1242 | }, |
1211 | { | 1243 | { |
1212 | "check cb access: half, oob 3", | 1244 | "check skb->hash half load permitted", |
1213 | .insns = { | 1245 | .insns = { |
1214 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1246 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1247 | #ifdef __LITTLE_ENDIAN | ||
1248 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
1249 | offsetof(struct __sk_buff, hash)), | ||
1250 | #else | ||
1215 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | 1251 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, |
1216 | offsetof(struct __sk_buff, cb[4]) + 4), | 1252 | offsetof(struct __sk_buff, hash) + 2), |
1253 | #endif | ||
1217 | BPF_EXIT_INSN(), | 1254 | BPF_EXIT_INSN(), |
1218 | }, | 1255 | }, |
1219 | .errstr = "invalid bpf_context access", | 1256 | .result = ACCEPT, |
1220 | .result = REJECT, | ||
1221 | }, | 1257 | }, |
1222 | { | 1258 | { |
1223 | "check cb access: half, oob 4", | 1259 | "check skb->hash half load not permitted", |
1224 | .insns = { | 1260 | .insns = { |
1225 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1261 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1262 | #ifdef __LITTLE_ENDIAN | ||
1226 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | 1263 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, |
1227 | offsetof(struct __sk_buff, cb[0]) - 2), | 1264 | offsetof(struct __sk_buff, hash) + 2), |
1265 | #else | ||
1266 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
1267 | offsetof(struct __sk_buff, hash)), | ||
1268 | #endif | ||
1228 | BPF_EXIT_INSN(), | 1269 | BPF_EXIT_INSN(), |
1229 | }, | 1270 | }, |
1230 | .errstr = "invalid bpf_context access", | 1271 | .errstr = "invalid bpf_context access", |
@@ -1367,28 +1408,6 @@ static struct bpf_test tests[] = { | |||
1367 | "check cb access: double, oob 2", | 1408 | "check cb access: double, oob 2", |
1368 | .insns = { | 1409 | .insns = { |
1369 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1410 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1370 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, | ||
1371 | offsetof(struct __sk_buff, cb[4]) + 8), | ||
1372 | BPF_EXIT_INSN(), | ||
1373 | }, | ||
1374 | .errstr = "invalid bpf_context access", | ||
1375 | .result = REJECT, | ||
1376 | }, | ||
1377 | { | ||
1378 | "check cb access: double, oob 3", | ||
1379 | .insns = { | ||
1380 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1381 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, | ||
1382 | offsetof(struct __sk_buff, cb[0]) - 8), | ||
1383 | BPF_EXIT_INSN(), | ||
1384 | }, | ||
1385 | .errstr = "invalid bpf_context access", | ||
1386 | .result = REJECT, | ||
1387 | }, | ||
1388 | { | ||
1389 | "check cb access: double, oob 4", | ||
1390 | .insns = { | ||
1391 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1392 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, | 1411 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, |
1393 | offsetof(struct __sk_buff, cb[4])), | 1412 | offsetof(struct __sk_buff, cb[4])), |
1394 | BPF_EXIT_INSN(), | 1413 | BPF_EXIT_INSN(), |
@@ -1397,22 +1416,22 @@ static struct bpf_test tests[] = { | |||
1397 | .result = REJECT, | 1416 | .result = REJECT, |
1398 | }, | 1417 | }, |
1399 | { | 1418 | { |
1400 | "check cb access: double, oob 5", | 1419 | "check __sk_buff->ifindex dw store not permitted", |
1401 | .insns = { | 1420 | .insns = { |
1402 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1421 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1403 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, | 1422 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, |
1404 | offsetof(struct __sk_buff, cb[4]) + 8), | 1423 | offsetof(struct __sk_buff, ifindex)), |
1405 | BPF_EXIT_INSN(), | 1424 | BPF_EXIT_INSN(), |
1406 | }, | 1425 | }, |
1407 | .errstr = "invalid bpf_context access", | 1426 | .errstr = "invalid bpf_context access", |
1408 | .result = REJECT, | 1427 | .result = REJECT, |
1409 | }, | 1428 | }, |
1410 | { | 1429 | { |
1411 | "check cb access: double, oob 6", | 1430 | "check __sk_buff->ifindex dw load not permitted", |
1412 | .insns = { | 1431 | .insns = { |
1413 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1432 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1414 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, | 1433 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, |
1415 | offsetof(struct __sk_buff, cb[0]) - 8), | 1434 | offsetof(struct __sk_buff, ifindex)), |
1416 | BPF_EXIT_INSN(), | 1435 | BPF_EXIT_INSN(), |
1417 | }, | 1436 | }, |
1418 | .errstr = "invalid bpf_context access", | 1437 | .errstr = "invalid bpf_context access", |
@@ -2615,6 +2634,195 @@ static struct bpf_test tests[] = { | |||
2615 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2634 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2616 | }, | 2635 | }, |
2617 | { | 2636 | { |
2637 | "direct packet access: test17 (pruning, alignment)", | ||
2638 | .insns = { | ||
2639 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2640 | offsetof(struct __sk_buff, data)), | ||
2641 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2642 | offsetof(struct __sk_buff, data_end)), | ||
2643 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | ||
2644 | offsetof(struct __sk_buff, mark)), | ||
2645 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
2646 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 14), | ||
2647 | BPF_JMP_IMM(BPF_JGT, BPF_REG_7, 1, 4), | ||
2648 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
2649 | BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, -4), | ||
2650 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2651 | BPF_EXIT_INSN(), | ||
2652 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
2653 | BPF_JMP_A(-6), | ||
2654 | }, | ||
2655 | .errstr = "misaligned packet access off 2+15+-4 size 4", | ||
2656 | .result = REJECT, | ||
2657 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2658 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
2659 | }, | ||
2660 | { | ||
2661 | "direct packet access: test18 (imm += pkt_ptr, 1)", | ||
2662 | .insns = { | ||
2663 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2664 | offsetof(struct __sk_buff, data)), | ||
2665 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2666 | offsetof(struct __sk_buff, data_end)), | ||
2667 | BPF_MOV64_IMM(BPF_REG_0, 8), | ||
2668 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), | ||
2669 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
2670 | BPF_STX_MEM(BPF_B, BPF_REG_2, BPF_REG_2, 0), | ||
2671 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2672 | BPF_EXIT_INSN(), | ||
2673 | }, | ||
2674 | .result = ACCEPT, | ||
2675 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2676 | }, | ||
2677 | { | ||
2678 | "direct packet access: test19 (imm += pkt_ptr, 2)", | ||
2679 | .insns = { | ||
2680 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2681 | offsetof(struct __sk_buff, data)), | ||
2682 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2683 | offsetof(struct __sk_buff, data_end)), | ||
2684 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
2685 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
2686 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 3), | ||
2687 | BPF_MOV64_IMM(BPF_REG_4, 4), | ||
2688 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), | ||
2689 | BPF_STX_MEM(BPF_B, BPF_REG_4, BPF_REG_4, 0), | ||
2690 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2691 | BPF_EXIT_INSN(), | ||
2692 | }, | ||
2693 | .result = ACCEPT, | ||
2694 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2695 | }, | ||
2696 | { | ||
2697 | "direct packet access: test20 (x += pkt_ptr, 1)", | ||
2698 | .insns = { | ||
2699 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2700 | offsetof(struct __sk_buff, data)), | ||
2701 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2702 | offsetof(struct __sk_buff, data_end)), | ||
2703 | BPF_MOV64_IMM(BPF_REG_0, 0xffffffff), | ||
2704 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), | ||
2705 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), | ||
2706 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffff), | ||
2707 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
2708 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), | ||
2709 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_4), | ||
2710 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xffff - 1), | ||
2711 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | ||
2712 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), | ||
2713 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2714 | BPF_EXIT_INSN(), | ||
2715 | }, | ||
2716 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2717 | .result = ACCEPT, | ||
2718 | }, | ||
2719 | { | ||
2720 | "direct packet access: test21 (x += pkt_ptr, 2)", | ||
2721 | .insns = { | ||
2722 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2723 | offsetof(struct __sk_buff, data)), | ||
2724 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2725 | offsetof(struct __sk_buff, data_end)), | ||
2726 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
2727 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
2728 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 9), | ||
2729 | BPF_MOV64_IMM(BPF_REG_4, 0xffffffff), | ||
2730 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_4, -8), | ||
2731 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), | ||
2732 | BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 0xffff), | ||
2733 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), | ||
2734 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_4), | ||
2735 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xffff - 1), | ||
2736 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | ||
2737 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), | ||
2738 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2739 | BPF_EXIT_INSN(), | ||
2740 | }, | ||
2741 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2742 | .result = ACCEPT, | ||
2743 | }, | ||
2744 | { | ||
2745 | "direct packet access: test22 (x += pkt_ptr, 3)", | ||
2746 | .insns = { | ||
2747 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2748 | offsetof(struct __sk_buff, data)), | ||
2749 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2750 | offsetof(struct __sk_buff, data_end)), | ||
2751 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
2752 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
2753 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), | ||
2754 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, -16), | ||
2755 | BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_10, -16), | ||
2756 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 11), | ||
2757 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8), | ||
2758 | BPF_MOV64_IMM(BPF_REG_4, 0xffffffff), | ||
2759 | BPF_STX_XADD(BPF_DW, BPF_REG_10, BPF_REG_4, -8), | ||
2760 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), | ||
2761 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 48), | ||
2762 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), | ||
2763 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), | ||
2764 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2), | ||
2765 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 2), | ||
2766 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
2767 | BPF_STX_MEM(BPF_H, BPF_REG_4, BPF_REG_2, 0), | ||
2768 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2769 | BPF_EXIT_INSN(), | ||
2770 | }, | ||
2771 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2772 | .result = ACCEPT, | ||
2773 | }, | ||
2774 | { | ||
2775 | "direct packet access: test23 (x += pkt_ptr, 4)", | ||
2776 | .insns = { | ||
2777 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2778 | offsetof(struct __sk_buff, data)), | ||
2779 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2780 | offsetof(struct __sk_buff, data_end)), | ||
2781 | BPF_MOV64_IMM(BPF_REG_0, 0xffffffff), | ||
2782 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), | ||
2783 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), | ||
2784 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffff), | ||
2785 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
2786 | BPF_MOV64_IMM(BPF_REG_0, 31), | ||
2787 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4), | ||
2788 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), | ||
2789 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_0), | ||
2790 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0xffff - 1), | ||
2791 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
2792 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_0, 0), | ||
2793 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2794 | BPF_EXIT_INSN(), | ||
2795 | }, | ||
2796 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2797 | .result = REJECT, | ||
2798 | .errstr = "cannot add integer value with 47 upper zero bits to ptr_to_packet", | ||
2799 | }, | ||
2800 | { | ||
2801 | "direct packet access: test24 (x += pkt_ptr, 5)", | ||
2802 | .insns = { | ||
2803 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2804 | offsetof(struct __sk_buff, data)), | ||
2805 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2806 | offsetof(struct __sk_buff, data_end)), | ||
2807 | BPF_MOV64_IMM(BPF_REG_0, 0xffffffff), | ||
2808 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), | ||
2809 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), | ||
2810 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xff), | ||
2811 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
2812 | BPF_MOV64_IMM(BPF_REG_0, 64), | ||
2813 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4), | ||
2814 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), | ||
2815 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_0), | ||
2816 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0xffff - 1), | ||
2817 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
2818 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_0, 0), | ||
2819 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2820 | BPF_EXIT_INSN(), | ||
2821 | }, | ||
2822 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2823 | .result = ACCEPT, | ||
2824 | }, | ||
2825 | { | ||
2618 | "helper access to packet: test1, valid packet_ptr range", | 2826 | "helper access to packet: test1, valid packet_ptr range", |
2619 | .insns = { | 2827 | .insns = { |
2620 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | 2828 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
@@ -3341,6 +3549,70 @@ static struct bpf_test tests[] = { | |||
3341 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 3549 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
3342 | }, | 3550 | }, |
3343 | { | 3551 | { |
3552 | "alu ops on ptr_to_map_value_or_null, 1", | ||
3553 | .insns = { | ||
3554 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
3555 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
3556 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3557 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3558 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3559 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3560 | BPF_FUNC_map_lookup_elem), | ||
3561 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
3562 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -2), | ||
3563 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2), | ||
3564 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3565 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | ||
3566 | BPF_EXIT_INSN(), | ||
3567 | }, | ||
3568 | .fixup_map1 = { 4 }, | ||
3569 | .errstr = "R4 invalid mem access", | ||
3570 | .result = REJECT, | ||
3571 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
3572 | }, | ||
3573 | { | ||
3574 | "alu ops on ptr_to_map_value_or_null, 2", | ||
3575 | .insns = { | ||
3576 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
3577 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
3578 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3579 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3580 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3581 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3582 | BPF_FUNC_map_lookup_elem), | ||
3583 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
3584 | BPF_ALU64_IMM(BPF_AND, BPF_REG_4, -1), | ||
3585 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3586 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | ||
3587 | BPF_EXIT_INSN(), | ||
3588 | }, | ||
3589 | .fixup_map1 = { 4 }, | ||
3590 | .errstr = "R4 invalid mem access", | ||
3591 | .result = REJECT, | ||
3592 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
3593 | }, | ||
3594 | { | ||
3595 | "alu ops on ptr_to_map_value_or_null, 3", | ||
3596 | .insns = { | ||
3597 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
3598 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
3599 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3600 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3601 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3602 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3603 | BPF_FUNC_map_lookup_elem), | ||
3604 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
3605 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 1), | ||
3606 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3607 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | ||
3608 | BPF_EXIT_INSN(), | ||
3609 | }, | ||
3610 | .fixup_map1 = { 4 }, | ||
3611 | .errstr = "R4 invalid mem access", | ||
3612 | .result = REJECT, | ||
3613 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
3614 | }, | ||
3615 | { | ||
3344 | "invalid memory access with multiple map_lookup_elem calls", | 3616 | "invalid memory access with multiple map_lookup_elem calls", |
3345 | .insns = { | 3617 | .insns = { |
3346 | BPF_MOV64_IMM(BPF_REG_1, 10), | 3618 | BPF_MOV64_IMM(BPF_REG_1, 10), |
@@ -3660,6 +3932,72 @@ static struct bpf_test tests[] = { | |||
3660 | .errstr = "invalid bpf_context access", | 3932 | .errstr = "invalid bpf_context access", |
3661 | }, | 3933 | }, |
3662 | { | 3934 | { |
3935 | "leak pointer into ctx 1", | ||
3936 | .insns = { | ||
3937 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3938 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, | ||
3939 | offsetof(struct __sk_buff, cb[0])), | ||
3940 | BPF_LD_MAP_FD(BPF_REG_2, 0), | ||
3941 | BPF_STX_XADD(BPF_DW, BPF_REG_1, BPF_REG_2, | ||
3942 | offsetof(struct __sk_buff, cb[0])), | ||
3943 | BPF_EXIT_INSN(), | ||
3944 | }, | ||
3945 | .fixup_map1 = { 2 }, | ||
3946 | .errstr_unpriv = "R2 leaks addr into mem", | ||
3947 | .result_unpriv = REJECT, | ||
3948 | .result = ACCEPT, | ||
3949 | }, | ||
3950 | { | ||
3951 | "leak pointer into ctx 2", | ||
3952 | .insns = { | ||
3953 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3954 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, | ||
3955 | offsetof(struct __sk_buff, cb[0])), | ||
3956 | BPF_STX_XADD(BPF_DW, BPF_REG_1, BPF_REG_10, | ||
3957 | offsetof(struct __sk_buff, cb[0])), | ||
3958 | BPF_EXIT_INSN(), | ||
3959 | }, | ||
3960 | .errstr_unpriv = "R10 leaks addr into mem", | ||
3961 | .result_unpriv = REJECT, | ||
3962 | .result = ACCEPT, | ||
3963 | }, | ||
3964 | { | ||
3965 | "leak pointer into ctx 3", | ||
3966 | .insns = { | ||
3967 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3968 | BPF_LD_MAP_FD(BPF_REG_2, 0), | ||
3969 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, | ||
3970 | offsetof(struct __sk_buff, cb[0])), | ||
3971 | BPF_EXIT_INSN(), | ||
3972 | }, | ||
3973 | .fixup_map1 = { 1 }, | ||
3974 | .errstr_unpriv = "R2 leaks addr into ctx", | ||
3975 | .result_unpriv = REJECT, | ||
3976 | .result = ACCEPT, | ||
3977 | }, | ||
3978 | { | ||
3979 | "leak pointer into map val", | ||
3980 | .insns = { | ||
3981 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
3982 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
3983 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3984 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3985 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3986 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3987 | BPF_FUNC_map_lookup_elem), | ||
3988 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), | ||
3989 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
3990 | BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0), | ||
3991 | BPF_STX_XADD(BPF_DW, BPF_REG_0, BPF_REG_6, 0), | ||
3992 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3993 | BPF_EXIT_INSN(), | ||
3994 | }, | ||
3995 | .fixup_map1 = { 4 }, | ||
3996 | .errstr_unpriv = "R6 leaks addr into mem", | ||
3997 | .result_unpriv = REJECT, | ||
3998 | .result = ACCEPT, | ||
3999 | }, | ||
4000 | { | ||
3663 | "helper access to map: full range", | 4001 | "helper access to map: full range", |
3664 | .insns = { | 4002 | .insns = { |
3665 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 4003 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -4937,7 +5275,241 @@ static struct bpf_test tests[] = { | |||
4937 | .fixup_map_in_map = { 3 }, | 5275 | .fixup_map_in_map = { 3 }, |
4938 | .errstr = "R1 type=map_value_or_null expected=map_ptr", | 5276 | .errstr = "R1 type=map_value_or_null expected=map_ptr", |
4939 | .result = REJECT, | 5277 | .result = REJECT, |
4940 | } | 5278 | }, |
5279 | { | ||
5280 | "ld_abs: check calling conv, r1", | ||
5281 | .insns = { | ||
5282 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5283 | BPF_MOV64_IMM(BPF_REG_1, 0), | ||
5284 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5285 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5286 | BPF_EXIT_INSN(), | ||
5287 | }, | ||
5288 | .errstr = "R1 !read_ok", | ||
5289 | .result = REJECT, | ||
5290 | }, | ||
5291 | { | ||
5292 | "ld_abs: check calling conv, r2", | ||
5293 | .insns = { | ||
5294 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5295 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5296 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5297 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
5298 | BPF_EXIT_INSN(), | ||
5299 | }, | ||
5300 | .errstr = "R2 !read_ok", | ||
5301 | .result = REJECT, | ||
5302 | }, | ||
5303 | { | ||
5304 | "ld_abs: check calling conv, r3", | ||
5305 | .insns = { | ||
5306 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5307 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5308 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5309 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_3), | ||
5310 | BPF_EXIT_INSN(), | ||
5311 | }, | ||
5312 | .errstr = "R3 !read_ok", | ||
5313 | .result = REJECT, | ||
5314 | }, | ||
5315 | { | ||
5316 | "ld_abs: check calling conv, r4", | ||
5317 | .insns = { | ||
5318 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5319 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
5320 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5321 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), | ||
5322 | BPF_EXIT_INSN(), | ||
5323 | }, | ||
5324 | .errstr = "R4 !read_ok", | ||
5325 | .result = REJECT, | ||
5326 | }, | ||
5327 | { | ||
5328 | "ld_abs: check calling conv, r5", | ||
5329 | .insns = { | ||
5330 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5331 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
5332 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5333 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_5), | ||
5334 | BPF_EXIT_INSN(), | ||
5335 | }, | ||
5336 | .errstr = "R5 !read_ok", | ||
5337 | .result = REJECT, | ||
5338 | }, | ||
5339 | { | ||
5340 | "ld_abs: check calling conv, r7", | ||
5341 | .insns = { | ||
5342 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5343 | BPF_MOV64_IMM(BPF_REG_7, 0), | ||
5344 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5345 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), | ||
5346 | BPF_EXIT_INSN(), | ||
5347 | }, | ||
5348 | .result = ACCEPT, | ||
5349 | }, | ||
5350 | { | ||
5351 | "ld_ind: check calling conv, r1", | ||
5352 | .insns = { | ||
5353 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5354 | BPF_MOV64_IMM(BPF_REG_1, 1), | ||
5355 | BPF_LD_IND(BPF_W, BPF_REG_1, -0x200000), | ||
5356 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5357 | BPF_EXIT_INSN(), | ||
5358 | }, | ||
5359 | .errstr = "R1 !read_ok", | ||
5360 | .result = REJECT, | ||
5361 | }, | ||
5362 | { | ||
5363 | "ld_ind: check calling conv, r2", | ||
5364 | .insns = { | ||
5365 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5366 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
5367 | BPF_LD_IND(BPF_W, BPF_REG_2, -0x200000), | ||
5368 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
5369 | BPF_EXIT_INSN(), | ||
5370 | }, | ||
5371 | .errstr = "R2 !read_ok", | ||
5372 | .result = REJECT, | ||
5373 | }, | ||
5374 | { | ||
5375 | "ld_ind: check calling conv, r3", | ||
5376 | .insns = { | ||
5377 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5378 | BPF_MOV64_IMM(BPF_REG_3, 1), | ||
5379 | BPF_LD_IND(BPF_W, BPF_REG_3, -0x200000), | ||
5380 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_3), | ||
5381 | BPF_EXIT_INSN(), | ||
5382 | }, | ||
5383 | .errstr = "R3 !read_ok", | ||
5384 | .result = REJECT, | ||
5385 | }, | ||
5386 | { | ||
5387 | "ld_ind: check calling conv, r4", | ||
5388 | .insns = { | ||
5389 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5390 | BPF_MOV64_IMM(BPF_REG_4, 1), | ||
5391 | BPF_LD_IND(BPF_W, BPF_REG_4, -0x200000), | ||
5392 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), | ||
5393 | BPF_EXIT_INSN(), | ||
5394 | }, | ||
5395 | .errstr = "R4 !read_ok", | ||
5396 | .result = REJECT, | ||
5397 | }, | ||
5398 | { | ||
5399 | "ld_ind: check calling conv, r5", | ||
5400 | .insns = { | ||
5401 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5402 | BPF_MOV64_IMM(BPF_REG_5, 1), | ||
5403 | BPF_LD_IND(BPF_W, BPF_REG_5, -0x200000), | ||
5404 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_5), | ||
5405 | BPF_EXIT_INSN(), | ||
5406 | }, | ||
5407 | .errstr = "R5 !read_ok", | ||
5408 | .result = REJECT, | ||
5409 | }, | ||
5410 | { | ||
5411 | "ld_ind: check calling conv, r7", | ||
5412 | .insns = { | ||
5413 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5414 | BPF_MOV64_IMM(BPF_REG_7, 1), | ||
5415 | BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000), | ||
5416 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), | ||
5417 | BPF_EXIT_INSN(), | ||
5418 | }, | ||
5419 | .result = ACCEPT, | ||
5420 | }, | ||
5421 | { | ||
5422 | "check bpf_perf_event_data->sample_period byte load permitted", | ||
5423 | .insns = { | ||
5424 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5425 | #ifdef __LITTLE_ENDIAN | ||
5426 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | ||
5427 | offsetof(struct bpf_perf_event_data, sample_period)), | ||
5428 | #else | ||
5429 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, | ||
5430 | offsetof(struct bpf_perf_event_data, sample_period) + 7), | ||
5431 | #endif | ||
5432 | BPF_EXIT_INSN(), | ||
5433 | }, | ||
5434 | .result = ACCEPT, | ||
5435 | .prog_type = BPF_PROG_TYPE_PERF_EVENT, | ||
5436 | }, | ||
5437 | { | ||
5438 | "check bpf_perf_event_data->sample_period half load permitted", | ||
5439 | .insns = { | ||
5440 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5441 | #ifdef __LITTLE_ENDIAN | ||
5442 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
5443 | offsetof(struct bpf_perf_event_data, sample_period)), | ||
5444 | #else | ||
5445 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
5446 | offsetof(struct bpf_perf_event_data, sample_period) + 6), | ||
5447 | #endif | ||
5448 | BPF_EXIT_INSN(), | ||
5449 | }, | ||
5450 | .result = ACCEPT, | ||
5451 | .prog_type = BPF_PROG_TYPE_PERF_EVENT, | ||
5452 | }, | ||
5453 | { | ||
5454 | "check bpf_perf_event_data->sample_period word load permitted", | ||
5455 | .insns = { | ||
5456 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5457 | #ifdef __LITTLE_ENDIAN | ||
5458 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
5459 | offsetof(struct bpf_perf_event_data, sample_period)), | ||
5460 | #else | ||
5461 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
5462 | offsetof(struct bpf_perf_event_data, sample_period) + 4), | ||
5463 | #endif | ||
5464 | BPF_EXIT_INSN(), | ||
5465 | }, | ||
5466 | .result = ACCEPT, | ||
5467 | .prog_type = BPF_PROG_TYPE_PERF_EVENT, | ||
5468 | }, | ||
5469 | { | ||
5470 | "check bpf_perf_event_data->sample_period dword load permitted", | ||
5471 | .insns = { | ||
5472 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5473 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, | ||
5474 | offsetof(struct bpf_perf_event_data, sample_period)), | ||
5475 | BPF_EXIT_INSN(), | ||
5476 | }, | ||
5477 | .result = ACCEPT, | ||
5478 | .prog_type = BPF_PROG_TYPE_PERF_EVENT, | ||
5479 | }, | ||
5480 | { | ||
5481 | "check skb->data half load not permitted", | ||
5482 | .insns = { | ||
5483 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5484 | #ifdef __LITTLE_ENDIAN | ||
5485 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
5486 | offsetof(struct __sk_buff, data)), | ||
5487 | #else | ||
5488 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
5489 | offsetof(struct __sk_buff, data) + 2), | ||
5490 | #endif | ||
5491 | BPF_EXIT_INSN(), | ||
5492 | }, | ||
5493 | .result = REJECT, | ||
5494 | .errstr = "invalid bpf_context access", | ||
5495 | }, | ||
5496 | { | ||
5497 | "check skb->tc_classid half load not permitted for lwt prog", | ||
5498 | .insns = { | ||
5499 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5500 | #ifdef __LITTLE_ENDIAN | ||
5501 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
5502 | offsetof(struct __sk_buff, tc_classid)), | ||
5503 | #else | ||
5504 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, | ||
5505 | offsetof(struct __sk_buff, tc_classid) + 2), | ||
5506 | #endif | ||
5507 | BPF_EXIT_INSN(), | ||
5508 | }, | ||
5509 | .result = REJECT, | ||
5510 | .errstr = "invalid bpf_context access", | ||
5511 | .prog_type = BPF_PROG_TYPE_LWT_IN, | ||
5512 | }, | ||
4941 | }; | 5513 | }; |
4942 | 5514 | ||
4943 | static int probe_filter_length(const struct bpf_insn *fp) | 5515 | static int probe_filter_length(const struct bpf_insn *fp) |
@@ -5059,9 +5631,9 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
5059 | 5631 | ||
5060 | do_test_fixup(test, prog, map_fds); | 5632 | do_test_fixup(test, prog, map_fds); |
5061 | 5633 | ||
5062 | fd_prog = bpf_load_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, | 5634 | fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, |
5063 | prog, prog_len, "GPL", 0, bpf_vlog, | 5635 | prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT, |
5064 | sizeof(bpf_vlog)); | 5636 | "GPL", 0, bpf_vlog, sizeof(bpf_vlog)); |
5065 | 5637 | ||
5066 | expected_ret = unpriv && test->result_unpriv != UNDEF ? | 5638 | expected_ret = unpriv && test->result_unpriv != UNDEF ? |
5067 | test->result_unpriv : test->result; | 5639 | test->result_unpriv : test->result; |
@@ -5187,7 +5759,7 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) | |||
5187 | } | 5759 | } |
5188 | 5760 | ||
5189 | printf("Summary: %d PASSED, %d FAILED\n", passes, errors); | 5761 | printf("Summary: %d PASSED, %d FAILED\n", passes, errors); |
5190 | return errors ? -errors : 0; | 5762 | return errors ? EXIT_FAILURE : EXIT_SUCCESS; |
5191 | } | 5763 | } |
5192 | 5764 | ||
5193 | int main(int argc, char **argv) | 5765 | int main(int argc, char **argv) |
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest index 32e6211e1c6e..717581145cfc 100755 --- a/tools/testing/selftests/ftrace/ftracetest +++ b/tools/testing/selftests/ftrace/ftracetest | |||
@@ -58,7 +58,7 @@ parse_opts() { # opts | |||
58 | ;; | 58 | ;; |
59 | --verbose|-v|-vv) | 59 | --verbose|-v|-vv) |
60 | VERBOSE=$((VERBOSE + 1)) | 60 | VERBOSE=$((VERBOSE + 1)) |
61 | [ $1 == '-vv' ] && VERBOSE=$((VERBOSE + 1)) | 61 | [ $1 = '-vv' ] && VERBOSE=$((VERBOSE + 1)) |
62 | shift 1 | 62 | shift 1 |
63 | ;; | 63 | ;; |
64 | --debug|-d) | 64 | --debug|-d) |
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc index 07bb3e5930b4..aa31368851c9 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc | |||
@@ -48,7 +48,7 @@ test_event_enabled() { | |||
48 | e=`cat $EVENT_ENABLE` | 48 | e=`cat $EVENT_ENABLE` |
49 | if [ "$e" != $val ]; then | 49 | if [ "$e" != $val ]; then |
50 | echo "Expected $val but found $e" | 50 | echo "Expected $val but found $e" |
51 | exit -1 | 51 | exit 1 |
52 | fi | 52 | fi |
53 | } | 53 | } |
54 | 54 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions index 9aec6fcb7729..f2019b37370d 100644 --- a/tools/testing/selftests/ftrace/test.d/functions +++ b/tools/testing/selftests/ftrace/test.d/functions | |||
@@ -34,10 +34,10 @@ reset_ftrace_filter() { # reset all triggers in set_ftrace_filter | |||
34 | echo > set_ftrace_filter | 34 | echo > set_ftrace_filter |
35 | grep -v '^#' set_ftrace_filter | while read t; do | 35 | grep -v '^#' set_ftrace_filter | while read t; do |
36 | tr=`echo $t | cut -d: -f2` | 36 | tr=`echo $t | cut -d: -f2` |
37 | if [ "$tr" == "" ]; then | 37 | if [ "$tr" = "" ]; then |
38 | continue | 38 | continue |
39 | fi | 39 | fi |
40 | if [ $tr == "enable_event" -o $tr == "disable_event" ]; then | 40 | if [ $tr = "enable_event" -o $tr = "disable_event" ]; then |
41 | tr=`echo $t | cut -d: -f1-4` | 41 | tr=`echo $t | cut -d: -f1-4` |
42 | limit=`echo $t | cut -d: -f5` | 42 | limit=`echo $t | cut -d: -f5` |
43 | else | 43 | else |
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc index 4c5a061a5b4e..c73db7863adb 100644 --- a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc +++ b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc | |||
@@ -75,9 +75,13 @@ rmdir foo | |||
75 | if [ -d foo ]; then | 75 | if [ -d foo ]; then |
76 | fail "foo still exists" | 76 | fail "foo still exists" |
77 | fi | 77 | fi |
78 | exit 0 | ||
79 | |||
80 | 78 | ||
79 | mkdir foo | ||
80 | echo "schedule:enable_event:sched:sched_switch" > foo/set_ftrace_filter | ||
81 | rmdir foo | ||
82 | if [ -d foo ]; then | ||
83 | fail "foo still exists" | ||
84 | fi | ||
81 | 85 | ||
82 | 86 | ||
83 | instance_slam() { | 87 | instance_slam() { |
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc new file mode 100644 index 000000000000..f4d1ff785d67 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc | |||
@@ -0,0 +1,21 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Register/unregister many kprobe events | ||
3 | |||
4 | # ftrace fentry skip size depends on the machine architecture. | ||
5 | # Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc | ||
6 | case `uname -m` in | ||
7 | x86_64|i[3456]86) OFFS=5;; | ||
8 | ppc*) OFFS=4;; | ||
9 | *) OFFS=0;; | ||
10 | esac | ||
11 | |||
12 | echo "Setup up to 256 kprobes" | ||
13 | grep t /proc/kallsyms | cut -f3 -d" " | grep -v .*\\..* | \ | ||
14 | head -n 256 | while read i; do echo p ${i}+${OFFS} ; done > kprobe_events ||: | ||
15 | |||
16 | echo 1 > events/kprobes/enable | ||
17 | echo 0 > events/kprobes/enable | ||
18 | echo > kprobe_events | ||
19 | echo "Waiting for unoptimizing & freeing" | ||
20 | sleep 5 | ||
21 | echo "Done" | ||
diff --git a/tools/testing/selftests/ntb/ntb_test.sh b/tools/testing/selftests/ntb/ntb_test.sh index a676d3eefefb..13f5198ba0ee 100755 --- a/tools/testing/selftests/ntb/ntb_test.sh +++ b/tools/testing/selftests/ntb/ntb_test.sh | |||
@@ -305,7 +305,7 @@ function perf_test() | |||
305 | echo "Running remote perf test $WITH DMA" | 305 | echo "Running remote perf test $WITH DMA" |
306 | write_file "" $REMOTE_PERF/run | 306 | write_file "" $REMOTE_PERF/run |
307 | echo -n " " | 307 | echo -n " " |
308 | read_file $LOCAL_PERF/run | 308 | read_file $REMOTE_PERF/run |
309 | echo " Passed" | 309 | echo " Passed" |
310 | 310 | ||
311 | _modprobe -r ntb_perf | 311 | _modprobe -r ntb_perf |
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 427621792229..2f1f7b013293 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore | |||
@@ -11,3 +11,4 @@ tm-signal-context-chk-fpu | |||
11 | tm-signal-context-chk-gpr | 11 | tm-signal-context-chk-gpr |
12 | tm-signal-context-chk-vmx | 12 | tm-signal-context-chk-vmx |
13 | tm-signal-context-chk-vsx | 13 | tm-signal-context-chk-vsx |
14 | tm-vmx-unavail | ||
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 5576ee6a51f2..958c11c14acd 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile | |||
@@ -2,7 +2,8 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu | |||
2 | tm-signal-context-chk-vmx tm-signal-context-chk-vsx | 2 | tm-signal-context-chk-vmx tm-signal-context-chk-vsx |
3 | 3 | ||
4 | TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ | 4 | TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ |
5 | tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS) | 5 | tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail \ |
6 | $(SIGNAL_CONTEXT_CHK_TESTS) | ||
6 | 7 | ||
7 | include ../../lib.mk | 8 | include ../../lib.mk |
8 | 9 | ||
@@ -13,6 +14,7 @@ CFLAGS += -mhtm | |||
13 | $(OUTPUT)/tm-syscall: tm-syscall-asm.S | 14 | $(OUTPUT)/tm-syscall: tm-syscall-asm.S |
14 | $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include | 15 | $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include |
15 | $(OUTPUT)/tm-tmspr: CFLAGS += -pthread | 16 | $(OUTPUT)/tm-tmspr: CFLAGS += -pthread |
17 | $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 | ||
16 | 18 | ||
17 | SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) | 19 | SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) |
18 | $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S | 20 | $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S |
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c index d9c49f41515e..e79ccd6aada1 100644 --- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c +++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c | |||
@@ -42,12 +42,12 @@ int test_body(void) | |||
42 | printf("Check DSCR TM context switch: "); | 42 | printf("Check DSCR TM context switch: "); |
43 | fflush(stdout); | 43 | fflush(stdout); |
44 | for (;;) { | 44 | for (;;) { |
45 | rv = 1; | ||
46 | asm __volatile__ ( | 45 | asm __volatile__ ( |
47 | /* set a known value into the DSCR */ | 46 | /* set a known value into the DSCR */ |
48 | "ld 3, %[dscr1];" | 47 | "ld 3, %[dscr1];" |
49 | "mtspr %[sprn_dscr], 3;" | 48 | "mtspr %[sprn_dscr], 3;" |
50 | 49 | ||
50 | "li %[rv], 1;" | ||
51 | /* start and suspend a transaction */ | 51 | /* start and suspend a transaction */ |
52 | "tbegin.;" | 52 | "tbegin.;" |
53 | "beq 1f;" | 53 | "beq 1f;" |
diff --git a/tools/testing/selftests/powerpc/tm/tm-vmx-unavail.c b/tools/testing/selftests/powerpc/tm/tm-vmx-unavail.c new file mode 100644 index 000000000000..137185ba4937 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-vmx-unavail.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Copyright 2017, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * Original: Breno Leitao <brenohl@br.ibm.com> & | ||
5 | * Gustavo Bueno Romero <gromero@br.ibm.com> | ||
6 | * Edited: Michael Neuling | ||
7 | * | ||
8 | * Force VMX unavailable during a transaction and see if it corrupts | ||
9 | * the checkpointed VMX register state after the abort. | ||
10 | */ | ||
11 | |||
12 | #include <inttypes.h> | ||
13 | #include <htmintrin.h> | ||
14 | #include <string.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <stdio.h> | ||
17 | #include <pthread.h> | ||
18 | #include <sys/mman.h> | ||
19 | #include <unistd.h> | ||
20 | #include <pthread.h> | ||
21 | |||
22 | #include "tm.h" | ||
23 | #include "utils.h" | ||
24 | |||
25 | int passed; | ||
26 | |||
27 | void *worker(void *unused) | ||
28 | { | ||
29 | __int128 vmx0; | ||
30 | uint64_t texasr; | ||
31 | |||
32 | asm goto ( | ||
33 | "li 3, 1;" /* Stick non-zero value in VMX0 */ | ||
34 | "std 3, 0(%[vmx0_ptr]);" | ||
35 | "lvx 0, 0, %[vmx0_ptr];" | ||
36 | |||
37 | /* Wait here a bit so we get scheduled out 255 times */ | ||
38 | "lis 3, 0x3fff;" | ||
39 | "1: ;" | ||
40 | "addi 3, 3, -1;" | ||
41 | "cmpdi 3, 0;" | ||
42 | "bne 1b;" | ||
43 | |||
44 | /* Kernel will hopefully turn VMX off now */ | ||
45 | |||
46 | "tbegin. ;" | ||
47 | "beq failure;" | ||
48 | |||
49 | /* Cause VMX unavail. Any VMX instruction */ | ||
50 | "vaddcuw 0,0,0;" | ||
51 | |||
52 | "tend. ;" | ||
53 | "b %l[success];" | ||
54 | |||
55 | /* Check VMX0 sanity after abort */ | ||
56 | "failure: ;" | ||
57 | "lvx 1, 0, %[vmx0_ptr];" | ||
58 | "vcmpequb. 2, 0, 1;" | ||
59 | "bc 4, 24, %l[value_mismatch];" | ||
60 | "b %l[value_match];" | ||
61 | : | ||
62 | : [vmx0_ptr] "r"(&vmx0) | ||
63 | : "r3" | ||
64 | : success, value_match, value_mismatch | ||
65 | ); | ||
66 | |||
67 | /* HTM aborted and VMX0 is corrupted */ | ||
68 | value_mismatch: | ||
69 | texasr = __builtin_get_texasr(); | ||
70 | |||
71 | printf("\n\n==============\n\n"); | ||
72 | printf("Failure with error: %lx\n", _TEXASR_FAILURE_CODE(texasr)); | ||
73 | printf("Summary error : %lx\n", _TEXASR_FAILURE_SUMMARY(texasr)); | ||
74 | printf("TFIAR exact : %lx\n\n", _TEXASR_TFIAR_EXACT(texasr)); | ||
75 | |||
76 | passed = 0; | ||
77 | return NULL; | ||
78 | |||
79 | /* HTM aborted but VMX0 is correct */ | ||
80 | value_match: | ||
81 | // printf("!"); | ||
82 | return NULL; | ||
83 | |||
84 | success: | ||
85 | // printf("."); | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
89 | int tm_vmx_unavail_test() | ||
90 | { | ||
91 | int threads; | ||
92 | pthread_t *thread; | ||
93 | |||
94 | SKIP_IF(!have_htm()); | ||
95 | |||
96 | passed = 1; | ||
97 | |||
98 | threads = sysconf(_SC_NPROCESSORS_ONLN) * 4; | ||
99 | thread = malloc(sizeof(pthread_t)*threads); | ||
100 | if (!thread) | ||
101 | return EXIT_FAILURE; | ||
102 | |||
103 | for (uint64_t i = 0; i < threads; i++) | ||
104 | pthread_create(&thread[i], NULL, &worker, NULL); | ||
105 | |||
106 | for (uint64_t i = 0; i < threads; i++) | ||
107 | pthread_join(thread[i], NULL); | ||
108 | |||
109 | free(thread); | ||
110 | |||
111 | return passed ? EXIT_SUCCESS : EXIT_FAILURE; | ||
112 | } | ||
113 | |||
114 | |||
115 | int main(int argc, char **argv) | ||
116 | { | ||
117 | return test_harness(tm_vmx_unavail_test, "tm_vmx_unavail_test"); | ||
118 | } | ||
diff --git a/tools/testing/selftests/rcutorture/bin/configcheck.sh b/tools/testing/selftests/rcutorture/bin/configcheck.sh index eee31e261bf7..70fca318a82b 100755 --- a/tools/testing/selftests/rcutorture/bin/configcheck.sh +++ b/tools/testing/selftests/rcutorture/bin/configcheck.sh | |||
@@ -27,7 +27,7 @@ cat $1 > $T/.config | |||
27 | 27 | ||
28 | cat $2 | sed -e 's/\(.*\)=n/# \1 is not set/' -e 's/^#CHECK#//' | | 28 | cat $2 | sed -e 's/\(.*\)=n/# \1 is not set/' -e 's/^#CHECK#//' | |
29 | awk ' | 29 | awk ' |
30 | BEGIN { | 30 | { |
31 | print "if grep -q \"" $0 "\" < '"$T/.config"'"; | 31 | print "if grep -q \"" $0 "\" < '"$T/.config"'"; |
32 | print "then"; | 32 | print "then"; |
33 | print "\t:"; | 33 | print "\t:"; |
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-build.sh b/tools/testing/selftests/rcutorture/bin/kvm-build.sh index 00cb0db2643d..c29f2ec0bf9f 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-build.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-build.sh | |||
@@ -45,7 +45,7 @@ T=/tmp/test-linux.sh.$$ | |||
45 | trap 'rm -rf $T' 0 | 45 | trap 'rm -rf $T' 0 |
46 | mkdir $T | 46 | mkdir $T |
47 | 47 | ||
48 | grep -v 'CONFIG_[A-Z]*_TORTURE_TEST' < ${config_template} > $T/config | 48 | grep -v 'CONFIG_[A-Z]*_TORTURE_TEST=' < ${config_template} > $T/config |
49 | cat << ___EOF___ >> $T/config | 49 | cat << ___EOF___ >> $T/config |
50 | CONFIG_INITRAMFS_SOURCE="$TORTURE_INITRD" | 50 | CONFIG_INITRAMFS_SOURCE="$TORTURE_INITRD" |
51 | CONFIG_VIRTIO_PCI=y | 51 | CONFIG_VIRTIO_PCI=y |
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 3b3c1b693ee1..50091de3a911 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh | |||
@@ -296,10 +296,7 @@ if test -d .git | |||
296 | then | 296 | then |
297 | git status >> $resdir/$ds/testid.txt | 297 | git status >> $resdir/$ds/testid.txt |
298 | git rev-parse HEAD >> $resdir/$ds/testid.txt | 298 | git rev-parse HEAD >> $resdir/$ds/testid.txt |
299 | if ! git diff HEAD > $T/git-diff 2>&1 | 299 | git diff HEAD >> $resdir/$ds/testid.txt |
300 | then | ||
301 | cp $T/git-diff $resdir/$ds | ||
302 | fi | ||
303 | fi | 300 | fi |
304 | ___EOF___ | 301 | ___EOF___ |
305 | awk < $T/cfgcpu.pack \ | 302 | awk < $T/cfgcpu.pack \ |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST index a3a1a05a2b5c..6a0b9f69faad 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST +++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST | |||
@@ -9,6 +9,8 @@ TREE08 | |||
9 | TREE09 | 9 | TREE09 |
10 | SRCU-N | 10 | SRCU-N |
11 | SRCU-P | 11 | SRCU-P |
12 | SRCU-t | ||
13 | SRCU-u | ||
12 | TINY01 | 14 | TINY01 |
13 | TINY02 | 15 | TINY02 |
14 | TASKS01 | 16 | TASKS01 |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-C.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-C.boot new file mode 100644 index 000000000000..84a7d51b7481 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-C.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=srcud | |||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N index 1a087c3c8bb8..2da8b49589a0 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N +++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N | |||
@@ -5,4 +5,4 @@ CONFIG_HOTPLUG_CPU=y | |||
5 | CONFIG_PREEMPT_NONE=y | 5 | CONFIG_PREEMPT_NONE=y |
6 | CONFIG_PREEMPT_VOLUNTARY=n | 6 | CONFIG_PREEMPT_VOLUNTARY=n |
7 | CONFIG_PREEMPT=n | 7 | CONFIG_PREEMPT=n |
8 | CONFIG_RCU_EXPERT=y | 8 | #CHECK#CONFIG_RCU_EXPERT=n |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P index 4837430a71c0..ab7ccd38232b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P +++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P | |||
@@ -2,7 +2,11 @@ CONFIG_RCU_TRACE=n | |||
2 | CONFIG_SMP=y | 2 | CONFIG_SMP=y |
3 | CONFIG_NR_CPUS=8 | 3 | CONFIG_NR_CPUS=8 |
4 | CONFIG_HOTPLUG_CPU=y | 4 | CONFIG_HOTPLUG_CPU=y |
5 | CONFIG_RCU_EXPERT=y | ||
6 | CONFIG_RCU_FANOUT=2 | ||
7 | CONFIG_RCU_FANOUT_LEAF=2 | ||
5 | CONFIG_PREEMPT_NONE=n | 8 | CONFIG_PREEMPT_NONE=n |
6 | CONFIG_PREEMPT_VOLUNTARY=n | 9 | CONFIG_PREEMPT_VOLUNTARY=n |
7 | CONFIG_PREEMPT=y | 10 | CONFIG_PREEMPT=y |
8 | #CHECK#CONFIG_RCU_EXPERT=n | 11 | CONFIG_DEBUG_LOCK_ALLOC=y |
12 | CONFIG_PROVE_LOCKING=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-t b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-t new file mode 100644 index 000000000000..6c78022c8cd8 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-t | |||
@@ -0,0 +1,10 @@ | |||
1 | CONFIG_SMP=n | ||
2 | CONFIG_PREEMPT_NONE=y | ||
3 | CONFIG_PREEMPT_VOLUNTARY=n | ||
4 | CONFIG_PREEMPT=n | ||
5 | #CHECK#CONFIG_TINY_SRCU=y | ||
6 | CONFIG_RCU_TRACE=n | ||
7 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
8 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
9 | CONFIG_DEBUG_ATOMIC_SLEEP=y | ||
10 | #CHECK#CONFIG_PREEMPT_COUNT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-t.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-t.boot new file mode 100644 index 000000000000..238bfe3bd0cc --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-t.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=srcu | |||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-u b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-u new file mode 100644 index 000000000000..6bc24e99862f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-u | |||
@@ -0,0 +1,9 @@ | |||
1 | CONFIG_SMP=n | ||
2 | CONFIG_PREEMPT_NONE=y | ||
3 | CONFIG_PREEMPT_VOLUNTARY=n | ||
4 | CONFIG_PREEMPT=n | ||
5 | #CHECK#CONFIG_TINY_SRCU=y | ||
6 | CONFIG_RCU_TRACE=n | ||
7 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
8 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
9 | CONFIG_PREEMPT_COUNT=n | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-u.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-u.boot new file mode 100644 index 000000000000..84a7d51b7481 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-u.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=srcud | |||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY02 b/tools/testing/selftests/rcutorture/configs/rcu/TINY02 index a59f7686e219..d8674264318d 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TINY02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY02 | |||
@@ -6,10 +6,9 @@ CONFIG_PREEMPT=n | |||
6 | CONFIG_HZ_PERIODIC=y | 6 | CONFIG_HZ_PERIODIC=y |
7 | CONFIG_NO_HZ_IDLE=n | 7 | CONFIG_NO_HZ_IDLE=n |
8 | CONFIG_NO_HZ_FULL=n | 8 | CONFIG_NO_HZ_FULL=n |
9 | CONFIG_RCU_TRACE=y | ||
10 | CONFIG_PROVE_LOCKING=y | 9 | CONFIG_PROVE_LOCKING=y |
11 | CONFIG_PROVE_RCU_REPEATEDLY=y | ||
12 | #CHECK#CONFIG_PROVE_RCU=y | 10 | #CHECK#CONFIG_PROVE_RCU=y |
13 | CONFIG_DEBUG_LOCK_ALLOC=y | 11 | CONFIG_DEBUG_LOCK_ALLOC=y |
12 | CONFIG_DEBUG_OBJECTS=y | ||
14 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | 13 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y |
15 | CONFIG_PREEMPT_COUNT=y | 14 | CONFIG_DEBUG_ATOMIC_SLEEP=y |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 index 359cb258f639..b5b53973c01e 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 | |||
@@ -10,12 +10,9 @@ CONFIG_RCU_FAST_NO_HZ=y | |||
10 | CONFIG_RCU_TRACE=y | 10 | CONFIG_RCU_TRACE=y |
11 | CONFIG_HOTPLUG_CPU=y | 11 | CONFIG_HOTPLUG_CPU=y |
12 | CONFIG_MAXSMP=y | 12 | CONFIG_MAXSMP=y |
13 | CONFIG_CPUMASK_OFFSTACK=y | ||
13 | CONFIG_RCU_NOCB_CPU=y | 14 | CONFIG_RCU_NOCB_CPU=y |
14 | CONFIG_RCU_NOCB_CPU_ZERO=y | ||
15 | CONFIG_DEBUG_LOCK_ALLOC=n | 15 | CONFIG_DEBUG_LOCK_ALLOC=n |
16 | CONFIG_RCU_BOOST=n | 16 | CONFIG_RCU_BOOST=n |
17 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 17 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
18 | CONFIG_RCU_EXPERT=y | 18 | CONFIG_RCU_EXPERT=y |
19 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
20 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
21 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot index adc3abc82fb8..1d14e1383016 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot | |||
@@ -1 +1,5 @@ | |||
1 | rcutorture.torture_type=rcu_bh maxcpus=8 | 1 | rcutorture.torture_type=rcu_bh maxcpus=8 |
2 | rcutree.gp_preinit_delay=3 | ||
3 | rcutree.gp_init_delay=3 | ||
4 | rcutree.gp_cleanup_delay=3 | ||
5 | rcu_nocbs=0 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 index c1ab5926568b..35e639e39366 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 | |||
@@ -18,9 +18,6 @@ CONFIG_RCU_NOCB_CPU=n | |||
18 | CONFIG_DEBUG_LOCK_ALLOC=y | 18 | CONFIG_DEBUG_LOCK_ALLOC=y |
19 | CONFIG_PROVE_LOCKING=n | 19 | CONFIG_PROVE_LOCKING=n |
20 | CONFIG_RCU_BOOST=n | 20 | CONFIG_RCU_BOOST=n |
21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
22 | CONFIG_RCU_EXPERT=y | 21 | CONFIG_RCU_EXPERT=y |
23 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | 22 | CONFIG_DEBUG_OBJECTS=y |
24 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
25 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
26 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | 23 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 index 3b93ee544e70..2dc31b16e506 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 | |||
@@ -14,9 +14,5 @@ CONFIG_RCU_FANOUT_LEAF=2 | |||
14 | CONFIG_RCU_NOCB_CPU=n | 14 | CONFIG_RCU_NOCB_CPU=n |
15 | CONFIG_DEBUG_LOCK_ALLOC=n | 15 | CONFIG_DEBUG_LOCK_ALLOC=n |
16 | CONFIG_RCU_BOOST=y | 16 | CONFIG_RCU_BOOST=y |
17 | CONFIG_RCU_KTHREAD_PRIO=2 | ||
18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 17 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
19 | CONFIG_RCU_EXPERT=y | 18 | CONFIG_RCU_EXPERT=y |
20 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
21 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
22 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot index 120c0c88d100..5d2cc0bd50a0 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot | |||
@@ -1 +1,5 @@ | |||
1 | rcutorture.onoff_interval=1 rcutorture.onoff_holdoff=30 | 1 | rcutorture.onoff_interval=1 rcutorture.onoff_holdoff=30 |
2 | rcutree.gp_preinit_delay=3 | ||
3 | rcutree.gp_init_delay=3 | ||
4 | rcutree.gp_cleanup_delay=3 | ||
5 | rcutree.kthread_prio=2 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 5af758e783c7..27d22695d64c 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 | |||
@@ -15,11 +15,7 @@ CONFIG_SUSPEND=n | |||
15 | CONFIG_HIBERNATION=n | 15 | CONFIG_HIBERNATION=n |
16 | CONFIG_RCU_FANOUT=4 | 16 | CONFIG_RCU_FANOUT=4 |
17 | CONFIG_RCU_FANOUT_LEAF=3 | 17 | CONFIG_RCU_FANOUT_LEAF=3 |
18 | CONFIG_RCU_NOCB_CPU=n | ||
19 | CONFIG_DEBUG_LOCK_ALLOC=n | 18 | CONFIG_DEBUG_LOCK_ALLOC=n |
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 19 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
21 | CONFIG_RCU_EXPERT=y | 20 | CONFIG_RCU_EXPERT=y |
22 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
23 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
25 | CONFIG_RCU_EQS_DEBUG=y | 21 | CONFIG_RCU_EQS_DEBUG=y |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 index d4cdc0d74e16..2dde0d9964e3 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 | |||
@@ -13,12 +13,8 @@ CONFIG_HOTPLUG_CPU=y | |||
13 | CONFIG_RCU_FANOUT=6 | 13 | CONFIG_RCU_FANOUT=6 |
14 | CONFIG_RCU_FANOUT_LEAF=6 | 14 | CONFIG_RCU_FANOUT_LEAF=6 |
15 | CONFIG_RCU_NOCB_CPU=y | 15 | CONFIG_RCU_NOCB_CPU=y |
16 | CONFIG_RCU_NOCB_CPU_NONE=y | ||
17 | CONFIG_DEBUG_LOCK_ALLOC=y | 16 | CONFIG_DEBUG_LOCK_ALLOC=y |
18 | CONFIG_PROVE_LOCKING=y | 17 | CONFIG_PROVE_LOCKING=y |
19 | #CHECK#CONFIG_PROVE_RCU=y | 18 | #CHECK#CONFIG_PROVE_RCU=y |
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 19 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
21 | CONFIG_RCU_EXPERT=y | 20 | CONFIG_RCU_EXPERT=y |
22 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
23 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot index 15b3e1a86f74..c7fd050dfcd9 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot | |||
@@ -1,2 +1,5 @@ | |||
1 | rcutorture.torture_type=sched | 1 | rcutorture.torture_type=sched |
2 | rcupdate.rcu_self_test_sched=1 | 2 | rcupdate.rcu_self_test_sched=1 |
3 | rcutree.gp_preinit_delay=3 | ||
4 | rcutree.gp_init_delay=3 | ||
5 | rcutree.gp_cleanup_delay=3 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 index 4cb02bd28f08..05a4eec3f27b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 | |||
@@ -18,8 +18,6 @@ CONFIG_RCU_NOCB_CPU=n | |||
18 | CONFIG_DEBUG_LOCK_ALLOC=y | 18 | CONFIG_DEBUG_LOCK_ALLOC=y |
19 | CONFIG_PROVE_LOCKING=y | 19 | CONFIG_PROVE_LOCKING=y |
20 | #CHECK#CONFIG_PROVE_RCU=y | 20 | #CHECK#CONFIG_PROVE_RCU=y |
21 | CONFIG_DEBUG_OBJECTS=y | ||
21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | 22 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y |
22 | CONFIG_RCU_EXPERT=y | 23 | CONFIG_RCU_EXPERT=y |
23 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
25 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot index dd90f28ed700..ad18b52a2cad 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot | |||
@@ -2,3 +2,6 @@ rcupdate.rcu_self_test=1 | |||
2 | rcupdate.rcu_self_test_bh=1 | 2 | rcupdate.rcu_self_test_bh=1 |
3 | rcupdate.rcu_self_test_sched=1 | 3 | rcupdate.rcu_self_test_sched=1 |
4 | rcutree.rcu_fanout_exact=1 | 4 | rcutree.rcu_fanout_exact=1 |
5 | rcutree.gp_preinit_delay=3 | ||
6 | rcutree.gp_init_delay=3 | ||
7 | rcutree.gp_cleanup_delay=3 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 index b12a3ea1867e..0f4759f4232e 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 | |||
@@ -1,6 +1,5 @@ | |||
1 | CONFIG_SMP=y | 1 | CONFIG_SMP=y |
2 | CONFIG_NR_CPUS=16 | 2 | CONFIG_NR_CPUS=16 |
3 | CONFIG_CPUMASK_OFFSTACK=y | ||
4 | CONFIG_PREEMPT_NONE=y | 3 | CONFIG_PREEMPT_NONE=y |
5 | CONFIG_PREEMPT_VOLUNTARY=n | 4 | CONFIG_PREEMPT_VOLUNTARY=n |
6 | CONFIG_PREEMPT=n | 5 | CONFIG_PREEMPT=n |
@@ -9,16 +8,11 @@ CONFIG_HZ_PERIODIC=n | |||
9 | CONFIG_NO_HZ_IDLE=n | 8 | CONFIG_NO_HZ_IDLE=n |
10 | CONFIG_NO_HZ_FULL=y | 9 | CONFIG_NO_HZ_FULL=y |
11 | CONFIG_NO_HZ_FULL_ALL=n | 10 | CONFIG_NO_HZ_FULL_ALL=n |
12 | CONFIG_NO_HZ_FULL_SYSIDLE=y | ||
13 | CONFIG_RCU_FAST_NO_HZ=n | 11 | CONFIG_RCU_FAST_NO_HZ=n |
14 | CONFIG_RCU_TRACE=y | 12 | CONFIG_RCU_TRACE=y |
15 | CONFIG_HOTPLUG_CPU=y | 13 | CONFIG_HOTPLUG_CPU=y |
16 | CONFIG_RCU_FANOUT=2 | 14 | CONFIG_RCU_FANOUT=2 |
17 | CONFIG_RCU_FANOUT_LEAF=2 | 15 | CONFIG_RCU_FANOUT_LEAF=2 |
18 | CONFIG_RCU_NOCB_CPU=n | ||
19 | CONFIG_DEBUG_LOCK_ALLOC=n | 16 | CONFIG_DEBUG_LOCK_ALLOC=n |
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 17 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
21 | CONFIG_RCU_EXPERT=y | 18 | CONFIG_RCU_EXPERT=y |
22 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
23 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 index 099cc63c6a3b..fb1c763c10c5 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 | |||
@@ -15,7 +15,6 @@ CONFIG_HIBERNATION=n | |||
15 | CONFIG_RCU_FANOUT=3 | 15 | CONFIG_RCU_FANOUT=3 |
16 | CONFIG_RCU_FANOUT_LEAF=2 | 16 | CONFIG_RCU_FANOUT_LEAF=2 |
17 | CONFIG_RCU_NOCB_CPU=y | 17 | CONFIG_RCU_NOCB_CPU=y |
18 | CONFIG_RCU_NOCB_CPU_ALL=y | ||
19 | CONFIG_DEBUG_LOCK_ALLOC=n | 18 | CONFIG_DEBUG_LOCK_ALLOC=n |
20 | CONFIG_PROVE_LOCKING=n | 19 | CONFIG_PROVE_LOCKING=n |
21 | CONFIG_RCU_BOOST=n | 20 | CONFIG_RCU_BOOST=n |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T deleted file mode 100644 index 2ad13f0d29cc..000000000000 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=16 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=n | ||
11 | CONFIG_RCU_TRACE=y | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | CONFIG_SUSPEND=n | ||
14 | CONFIG_HIBERNATION=n | ||
15 | CONFIG_RCU_FANOUT=3 | ||
16 | CONFIG_RCU_FANOUT_LEAF=2 | ||
17 | CONFIG_RCU_NOCB_CPU=y | ||
18 | CONFIG_RCU_NOCB_CPU_ALL=y | ||
19 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
20 | CONFIG_RCU_BOOST=n | ||
21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot index fb066dc82769..1bd8efc4141e 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot | |||
@@ -2,3 +2,4 @@ rcutorture.torture_type=sched | |||
2 | rcupdate.rcu_self_test=1 | 2 | rcupdate.rcu_self_test=1 |
3 | rcupdate.rcu_self_test_sched=1 | 3 | rcupdate.rcu_self_test_sched=1 |
4 | rcutree.rcu_fanout_exact=1 | 4 | rcutree.rcu_fanout_exact=1 |
5 | rcu_nocbs=0-7 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcuperf/TINY index 917d2517b5b5..fb05ef5279b4 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/TINY | |||
@@ -1,21 +1,16 @@ | |||
1 | CONFIG_SMP=y | 1 | CONFIG_SMP=n |
2 | CONFIG_NR_CPUS=8 | 2 | CONFIG_PREEMPT_NONE=y |
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | 3 | CONFIG_PREEMPT_VOLUNTARY=n |
5 | CONFIG_PREEMPT=y | 4 | CONFIG_PREEMPT=n |
6 | #CHECK#CONFIG_PREEMPT_RCU=y | 5 | #CHECK#CONFIG_TINY_RCU=y |
7 | CONFIG_HZ_PERIODIC=n | 6 | CONFIG_HZ_PERIODIC=n |
8 | CONFIG_NO_HZ_IDLE=y | 7 | CONFIG_NO_HZ_IDLE=y |
9 | CONFIG_NO_HZ_FULL=n | 8 | CONFIG_NO_HZ_FULL=n |
10 | CONFIG_RCU_FAST_NO_HZ=n | 9 | CONFIG_RCU_FAST_NO_HZ=n |
11 | CONFIG_RCU_TRACE=y | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | CONFIG_SUSPEND=n | ||
14 | CONFIG_HIBERNATION=n | ||
15 | CONFIG_RCU_FANOUT=3 | ||
16 | CONFIG_RCU_FANOUT_LEAF=3 | ||
17 | CONFIG_RCU_NOCB_CPU=n | 10 | CONFIG_RCU_NOCB_CPU=n |
18 | CONFIG_DEBUG_LOCK_ALLOC=y | 11 | CONFIG_DEBUG_LOCK_ALLOC=n |
19 | CONFIG_PROVE_LOCKING=n | 12 | CONFIG_PROVE_LOCKING=n |
20 | CONFIG_RCU_BOOST=n | 13 | CONFIG_RCU_BOOST=n |
21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 14 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
15 | CONFIG_RCU_EXPERT=y | ||
16 | CONFIG_RCU_TRACE=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE index a312f671a29a..721cfda76ab2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE | |||
@@ -7,7 +7,6 @@ CONFIG_HZ_PERIODIC=n | |||
7 | CONFIG_NO_HZ_IDLE=y | 7 | CONFIG_NO_HZ_IDLE=y |
8 | CONFIG_NO_HZ_FULL=n | 8 | CONFIG_NO_HZ_FULL=n |
9 | CONFIG_RCU_FAST_NO_HZ=n | 9 | CONFIG_RCU_FAST_NO_HZ=n |
10 | CONFIG_RCU_TRACE=n | ||
11 | CONFIG_HOTPLUG_CPU=n | 10 | CONFIG_HOTPLUG_CPU=n |
12 | CONFIG_SUSPEND=n | 11 | CONFIG_SUSPEND=n |
13 | CONFIG_HIBERNATION=n | 12 | CONFIG_HIBERNATION=n |
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 index 985fb170d13c..7629f5dd73b2 100644 --- a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 | |||
@@ -8,7 +8,6 @@ CONFIG_HZ_PERIODIC=n | |||
8 | CONFIG_NO_HZ_IDLE=y | 8 | CONFIG_NO_HZ_IDLE=y |
9 | CONFIG_NO_HZ_FULL=n | 9 | CONFIG_NO_HZ_FULL=n |
10 | CONFIG_RCU_FAST_NO_HZ=n | 10 | CONFIG_RCU_FAST_NO_HZ=n |
11 | CONFIG_RCU_TRACE=n | ||
12 | CONFIG_HOTPLUG_CPU=n | 11 | CONFIG_HOTPLUG_CPU=n |
13 | CONFIG_SUSPEND=n | 12 | CONFIG_SUSPEND=n |
14 | CONFIG_HIBERNATION=n | 13 | CONFIG_HIBERNATION=n |
diff --git a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt index 24396ae8355b..a75b16991a92 100644 --- a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt +++ b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt | |||
@@ -18,7 +18,6 @@ CONFIG_PROVE_RCU | |||
18 | 18 | ||
19 | In common code tested by TREE_RCU test cases. | 19 | In common code tested by TREE_RCU test cases. |
20 | 20 | ||
21 | CONFIG_NO_HZ_FULL_SYSIDLE | ||
22 | CONFIG_RCU_NOCB_CPU | 21 | CONFIG_RCU_NOCB_CPU |
23 | 22 | ||
24 | Meaningless for TINY_RCU. | 23 | Meaningless for TINY_RCU. |
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt index 364801b1a230..9ad3f89c8dc7 100644 --- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt | |||
@@ -9,28 +9,20 @@ CONFIG_DEBUG_OBJECTS_RCU_HEAD -- Do one. | |||
9 | CONFIG_HOTPLUG_CPU -- Do half. (Every second.) | 9 | CONFIG_HOTPLUG_CPU -- Do half. (Every second.) |
10 | CONFIG_HZ_PERIODIC -- Do one. | 10 | CONFIG_HZ_PERIODIC -- Do one. |
11 | CONFIG_NO_HZ_IDLE -- Do those not otherwise specified. (Groups of two.) | 11 | CONFIG_NO_HZ_IDLE -- Do those not otherwise specified. (Groups of two.) |
12 | CONFIG_NO_HZ_FULL -- Do two, one with CONFIG_NO_HZ_FULL_SYSIDLE. | 12 | CONFIG_NO_HZ_FULL -- Do two, one with partial CPU enablement. |
13 | CONFIG_NO_HZ_FULL_SYSIDLE -- Do one. | ||
14 | CONFIG_PREEMPT -- Do half. (First three and #8.) | 13 | CONFIG_PREEMPT -- Do half. (First three and #8.) |
15 | CONFIG_PROVE_LOCKING -- Do several, covering CONFIG_DEBUG_LOCK_ALLOC=y and not. | 14 | CONFIG_PROVE_LOCKING -- Do several, covering CONFIG_DEBUG_LOCK_ALLOC=y and not. |
16 | CONFIG_PROVE_RCU -- Hardwired to CONFIG_PROVE_LOCKING. | 15 | CONFIG_PROVE_RCU -- Hardwired to CONFIG_PROVE_LOCKING. |
17 | CONFIG_PROVE_RCU_REPEATEDLY -- Do one. | ||
18 | CONFIG_RCU_BOOST -- one of PREEMPT_RCU. | 16 | CONFIG_RCU_BOOST -- one of PREEMPT_RCU. |
19 | CONFIG_RCU_KTHREAD_PRIO -- set to 2 for _BOOST testing. | ||
20 | CONFIG_RCU_FANOUT -- Cover hierarchy, but overlap with others. | 17 | CONFIG_RCU_FANOUT -- Cover hierarchy, but overlap with others. |
21 | CONFIG_RCU_FANOUT_LEAF -- Do one non-default. | 18 | CONFIG_RCU_FANOUT_LEAF -- Do one non-default. |
22 | CONFIG_RCU_FAST_NO_HZ -- Do one, but not with CONFIG_RCU_NOCB_CPU_ALL. | 19 | CONFIG_RCU_FAST_NO_HZ -- Do one, but not with all nohz_full CPUs. |
23 | CONFIG_RCU_NOCB_CPU -- Do three, see below. | 20 | CONFIG_RCU_NOCB_CPU -- Do three, one with no rcu_nocbs CPUs, one with |
24 | CONFIG_RCU_NOCB_CPU_ALL -- Do one. | 21 | rcu_nocbs=0, and one with all rcu_nocbs CPUs. |
25 | CONFIG_RCU_NOCB_CPU_NONE -- Do one. | ||
26 | CONFIG_RCU_NOCB_CPU_ZERO -- Do one. | ||
27 | CONFIG_RCU_TRACE -- Do half. | 22 | CONFIG_RCU_TRACE -- Do half. |
28 | CONFIG_SMP -- Need one !SMP for PREEMPT_RCU. | 23 | CONFIG_SMP -- Need one !SMP for PREEMPT_RCU. |
29 | CONFIG_RCU_EXPERT=n -- Do a few, but these have to be vanilla configurations. | 24 | CONFIG_RCU_EXPERT=n -- Do a few, but these have to be vanilla configurations. |
30 | CONFIG_RCU_EQS_DEBUG -- Do at least one for CONFIG_NO_HZ_FULL and not. | 25 | CONFIG_RCU_EQS_DEBUG -- Do at least one for CONFIG_NO_HZ_FULL and not. |
31 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP -- Do for all but a couple TREE scenarios. | ||
32 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT -- Do for all but a couple TREE scenarios. | ||
33 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT -- Do for all but a couple TREE scenarios. | ||
34 | 26 | ||
35 | RCU-bh: Do one with PREEMPT and one with !PREEMPT. | 27 | RCU-bh: Do one with PREEMPT and one with !PREEMPT. |
36 | RCU-sched: Do one with PREEMPT but not BOOST. | 28 | RCU-sched: Do one with PREEMPT but not BOOST. |
@@ -52,10 +44,6 @@ CONFIG_64BIT | |||
52 | 44 | ||
53 | Used only to check CONFIG_RCU_FANOUT value, inspection suffices. | 45 | Used only to check CONFIG_RCU_FANOUT value, inspection suffices. |
54 | 46 | ||
55 | CONFIG_NO_HZ_FULL_SYSIDLE_SMALL | ||
56 | |||
57 | Defer until Frederic uses this. | ||
58 | |||
59 | CONFIG_PREEMPT_COUNT | 47 | CONFIG_PREEMPT_COUNT |
60 | CONFIG_PREEMPT_RCU | 48 | CONFIG_PREEMPT_RCU |
61 | 49 | ||
@@ -78,30 +66,16 @@ CONFIG_RCU_TORTURE_TEST_RUNNABLE | |||
78 | 66 | ||
79 | Always used in KVM testing. | 67 | Always used in KVM testing. |
80 | 68 | ||
81 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT_DELAY | ||
82 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY | ||
83 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP_DELAY | ||
84 | |||
85 | Inspection suffices, ignore. | ||
86 | |||
87 | CONFIG_PREEMPT_RCU | 69 | CONFIG_PREEMPT_RCU |
88 | CONFIG_TREE_RCU | 70 | CONFIG_TREE_RCU |
89 | CONFIG_TINY_RCU | 71 | CONFIG_TINY_RCU |
90 | 72 | ||
91 | These are controlled by CONFIG_PREEMPT and/or CONFIG_SMP. | 73 | These are controlled by CONFIG_PREEMPT and/or CONFIG_SMP. |
92 | 74 | ||
93 | CONFIG_SPARSE_RCU_POINTER | ||
94 | |||
95 | Makes sense only for sparse runs, not for kernel builds. | ||
96 | |||
97 | CONFIG_SRCU | 75 | CONFIG_SRCU |
98 | CONFIG_TASKS_RCU | 76 | CONFIG_TASKS_RCU |
99 | 77 | ||
100 | Selected by CONFIG_RCU_TORTURE_TEST, so cannot disable. | 78 | Selected by CONFIG_RCU_TORTURE_TEST, so cannot disable. |
101 | 79 | ||
102 | CONFIG_RCU_TRACE | ||
103 | |||
104 | Implied by CONFIG_RCU_TRACE for Tree RCU. | ||
105 | |||
106 | 80 | ||
107 | boot parameters ignored: TBD | 81 | boot parameters ignored: TBD |
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk index 8ff89043d0a9..c9e8bc5082a7 100755 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk | |||
@@ -1,4 +1,4 @@ | |||
1 | #!/bin/awk -f | 1 | #!/usr/bin/awk -f |
2 | 2 | ||
3 | # Modify SRCU for formal verification. The first argument should be srcu.h and | 3 | # Modify SRCU for formal verification. The first argument should be srcu.h and |
4 | # the second should be srcu.c. Outputs modified srcu.h and srcu.c into the | 4 | # the second should be srcu.c. Outputs modified srcu.h and srcu.c into the |
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 03f1fa495d74..00a928b833d0 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c | |||
@@ -1822,6 +1822,23 @@ struct tsync_sibling { | |||
1822 | struct __test_metadata *metadata; | 1822 | struct __test_metadata *metadata; |
1823 | }; | 1823 | }; |
1824 | 1824 | ||
1825 | /* | ||
1826 | * To avoid joining joined threads (which is not allowed by Bionic), | ||
1827 | * make sure we both successfully join and clear the tid to skip a | ||
1828 | * later join attempt during fixture teardown. Any remaining threads | ||
1829 | * will be directly killed during teardown. | ||
1830 | */ | ||
1831 | #define PTHREAD_JOIN(tid, status) \ | ||
1832 | do { \ | ||
1833 | int _rc = pthread_join(tid, status); \ | ||
1834 | if (_rc) { \ | ||
1835 | TH_LOG("pthread_join of tid %u failed: %d\n", \ | ||
1836 | (unsigned int)tid, _rc); \ | ||
1837 | } else { \ | ||
1838 | tid = 0; \ | ||
1839 | } \ | ||
1840 | } while (0) | ||
1841 | |||
1825 | FIXTURE_DATA(TSYNC) { | 1842 | FIXTURE_DATA(TSYNC) { |
1826 | struct sock_fprog root_prog, apply_prog; | 1843 | struct sock_fprog root_prog, apply_prog; |
1827 | struct tsync_sibling sibling[TSYNC_SIBLINGS]; | 1844 | struct tsync_sibling sibling[TSYNC_SIBLINGS]; |
@@ -1890,14 +1907,14 @@ FIXTURE_TEARDOWN(TSYNC) | |||
1890 | 1907 | ||
1891 | for ( ; sib < self->sibling_count; ++sib) { | 1908 | for ( ; sib < self->sibling_count; ++sib) { |
1892 | struct tsync_sibling *s = &self->sibling[sib]; | 1909 | struct tsync_sibling *s = &self->sibling[sib]; |
1893 | void *status; | ||
1894 | 1910 | ||
1895 | if (!s->tid) | 1911 | if (!s->tid) |
1896 | continue; | 1912 | continue; |
1897 | if (pthread_kill(s->tid, 0)) { | 1913 | /* |
1898 | pthread_cancel(s->tid); | 1914 | * If a thread is still running, it may be stuck, so hit |
1899 | pthread_join(s->tid, &status); | 1915 | * it over the head really hard. |
1900 | } | 1916 | */ |
1917 | pthread_kill(s->tid, 9); | ||
1901 | } | 1918 | } |
1902 | pthread_mutex_destroy(&self->mutex); | 1919 | pthread_mutex_destroy(&self->mutex); |
1903 | pthread_cond_destroy(&self->cond); | 1920 | pthread_cond_destroy(&self->cond); |
@@ -1987,9 +2004,9 @@ TEST_F(TSYNC, siblings_fail_prctl) | |||
1987 | pthread_mutex_unlock(&self->mutex); | 2004 | pthread_mutex_unlock(&self->mutex); |
1988 | 2005 | ||
1989 | /* Ensure diverging sibling failed to call prctl. */ | 2006 | /* Ensure diverging sibling failed to call prctl. */ |
1990 | pthread_join(self->sibling[0].tid, &status); | 2007 | PTHREAD_JOIN(self->sibling[0].tid, &status); |
1991 | EXPECT_EQ(SIBLING_EXIT_FAILURE, (long)status); | 2008 | EXPECT_EQ(SIBLING_EXIT_FAILURE, (long)status); |
1992 | pthread_join(self->sibling[1].tid, &status); | 2009 | PTHREAD_JOIN(self->sibling[1].tid, &status); |
1993 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); | 2010 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); |
1994 | } | 2011 | } |
1995 | 2012 | ||
@@ -2029,9 +2046,9 @@ TEST_F(TSYNC, two_siblings_with_ancestor) | |||
2029 | } | 2046 | } |
2030 | pthread_mutex_unlock(&self->mutex); | 2047 | pthread_mutex_unlock(&self->mutex); |
2031 | /* Ensure they are both killed and don't exit cleanly. */ | 2048 | /* Ensure they are both killed and don't exit cleanly. */ |
2032 | pthread_join(self->sibling[0].tid, &status); | 2049 | PTHREAD_JOIN(self->sibling[0].tid, &status); |
2033 | EXPECT_EQ(0x0, (long)status); | 2050 | EXPECT_EQ(0x0, (long)status); |
2034 | pthread_join(self->sibling[1].tid, &status); | 2051 | PTHREAD_JOIN(self->sibling[1].tid, &status); |
2035 | EXPECT_EQ(0x0, (long)status); | 2052 | EXPECT_EQ(0x0, (long)status); |
2036 | } | 2053 | } |
2037 | 2054 | ||
@@ -2055,9 +2072,9 @@ TEST_F(TSYNC, two_sibling_want_nnp) | |||
2055 | pthread_mutex_unlock(&self->mutex); | 2072 | pthread_mutex_unlock(&self->mutex); |
2056 | 2073 | ||
2057 | /* Ensure they are both upset about lacking nnp. */ | 2074 | /* Ensure they are both upset about lacking nnp. */ |
2058 | pthread_join(self->sibling[0].tid, &status); | 2075 | PTHREAD_JOIN(self->sibling[0].tid, &status); |
2059 | EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status); | 2076 | EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status); |
2060 | pthread_join(self->sibling[1].tid, &status); | 2077 | PTHREAD_JOIN(self->sibling[1].tid, &status); |
2061 | EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status); | 2078 | EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status); |
2062 | } | 2079 | } |
2063 | 2080 | ||
@@ -2095,9 +2112,9 @@ TEST_F(TSYNC, two_siblings_with_no_filter) | |||
2095 | pthread_mutex_unlock(&self->mutex); | 2112 | pthread_mutex_unlock(&self->mutex); |
2096 | 2113 | ||
2097 | /* Ensure they are both killed and don't exit cleanly. */ | 2114 | /* Ensure they are both killed and don't exit cleanly. */ |
2098 | pthread_join(self->sibling[0].tid, &status); | 2115 | PTHREAD_JOIN(self->sibling[0].tid, &status); |
2099 | EXPECT_EQ(0x0, (long)status); | 2116 | EXPECT_EQ(0x0, (long)status); |
2100 | pthread_join(self->sibling[1].tid, &status); | 2117 | PTHREAD_JOIN(self->sibling[1].tid, &status); |
2101 | EXPECT_EQ(0x0, (long)status); | 2118 | EXPECT_EQ(0x0, (long)status); |
2102 | } | 2119 | } |
2103 | 2120 | ||
@@ -2140,9 +2157,9 @@ TEST_F(TSYNC, two_siblings_with_one_divergence) | |||
2140 | pthread_mutex_unlock(&self->mutex); | 2157 | pthread_mutex_unlock(&self->mutex); |
2141 | 2158 | ||
2142 | /* Ensure they are both unkilled. */ | 2159 | /* Ensure they are both unkilled. */ |
2143 | pthread_join(self->sibling[0].tid, &status); | 2160 | PTHREAD_JOIN(self->sibling[0].tid, &status); |
2144 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); | 2161 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); |
2145 | pthread_join(self->sibling[1].tid, &status); | 2162 | PTHREAD_JOIN(self->sibling[1].tid, &status); |
2146 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); | 2163 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); |
2147 | } | 2164 | } |
2148 | 2165 | ||
@@ -2199,7 +2216,7 @@ TEST_F(TSYNC, two_siblings_not_under_filter) | |||
2199 | TH_LOG("cond broadcast non-zero"); | 2216 | TH_LOG("cond broadcast non-zero"); |
2200 | } | 2217 | } |
2201 | pthread_mutex_unlock(&self->mutex); | 2218 | pthread_mutex_unlock(&self->mutex); |
2202 | pthread_join(self->sibling[sib].tid, &status); | 2219 | PTHREAD_JOIN(self->sibling[sib].tid, &status); |
2203 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); | 2220 | EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); |
2204 | /* Poll for actual task death. pthread_join doesn't guarantee it. */ | 2221 | /* Poll for actual task death. pthread_join doesn't guarantee it. */ |
2205 | while (!kill(self->sibling[sib].system_tid, 0)) | 2222 | while (!kill(self->sibling[sib].system_tid, 0)) |
@@ -2224,7 +2241,7 @@ TEST_F(TSYNC, two_siblings_not_under_filter) | |||
2224 | TH_LOG("cond broadcast non-zero"); | 2241 | TH_LOG("cond broadcast non-zero"); |
2225 | } | 2242 | } |
2226 | pthread_mutex_unlock(&self->mutex); | 2243 | pthread_mutex_unlock(&self->mutex); |
2227 | pthread_join(self->sibling[sib].tid, &status); | 2244 | PTHREAD_JOIN(self->sibling[sib].tid, &status); |
2228 | EXPECT_EQ(0, (long)status); | 2245 | EXPECT_EQ(0, (long)status); |
2229 | /* Poll for actual task death. pthread_join doesn't guarantee it. */ | 2246 | /* Poll for actual task death. pthread_join doesn't guarantee it. */ |
2230 | while (!kill(self->sibling[sib].system_tid, 0)) | 2247 | while (!kill(self->sibling[sib].system_tid, 0)) |
diff --git a/tools/testing/selftests/tc-testing/.gitignore b/tools/testing/selftests/tc-testing/.gitignore new file mode 100644 index 000000000000..c18dd8d83cee --- /dev/null +++ b/tools/testing/selftests/tc-testing/.gitignore | |||
@@ -0,0 +1 @@ | |||
__pycache__/ | |||
diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README new file mode 100644 index 000000000000..970ff294fec8 --- /dev/null +++ b/tools/testing/selftests/tc-testing/README | |||
@@ -0,0 +1,102 @@ | |||
1 | tdc - Linux Traffic Control (tc) unit testing suite | ||
2 | |||
3 | Author: Lucas Bates - lucasb@mojatatu.com | ||
4 | |||
5 | tdc is a Python script to load tc unit tests from a separate JSON file and | ||
6 | execute them inside a network namespace dedicated to the task. | ||
7 | |||
8 | |||
9 | REQUIREMENTS | ||
10 | ------------ | ||
11 | |||
12 | * Minimum Python version of 3.4. Earlier 3.X versions may work but are not | ||
13 | guaranteed. | ||
14 | |||
15 | * The kernel must have network namespace support | ||
16 | |||
17 | * The kernel must have veth support available, as a veth pair is created | ||
18 | prior to running the tests. | ||
19 | |||
20 | * All tc-related features must be built in or available as modules. | ||
21 | To check what is required in current setup run: | ||
22 | ./tdc.py -c | ||
23 | |||
24 | Note: | ||
25 | In the current release, tdc run will abort due to a failure in setup or | ||
26 | teardown commands - which includes not being able to run a test simply | ||
27 | because the kernel did not support a specific feature. (This will be | ||
28 | handled in a future version - the current workaround is to run the tests | ||
29 | on specific test categories that your kernel supports) | ||
30 | |||
31 | |||
32 | BEFORE YOU RUN | ||
33 | -------------- | ||
34 | |||
35 | The path to the tc executable that will be most commonly tested can be defined | ||
36 | in the tdc_config.py file. Find the 'TC' entry in the NAMES dictionary and | ||
37 | define the path. | ||
38 | |||
39 | If you need to test a different tc executable on the fly, you can do so by | ||
40 | using the -p option when running tdc: | ||
41 | ./tdc.py -p /path/to/tc | ||
42 | |||
43 | |||
44 | RUNNING TDC | ||
45 | ----------- | ||
46 | |||
47 | To use tdc, root privileges are required. tdc will not run otherwise. | ||
48 | |||
49 | All tests are executed inside a network namespace to prevent conflicts | ||
50 | within the host. | ||
51 | |||
52 | Running tdc without any arguments will run all tests. Refer to the section | ||
53 | on command line arguments for more information, or run: | ||
54 | ./tdc.py -h | ||
55 | |||
56 | tdc will list the test names as they are being run, and print a summary in | ||
57 | TAP (Test Anything Protocol) format when they are done. If tests fail, | ||
58 | output captured from the failing test will be printed immediately following | ||
59 | the failed test in the TAP output. | ||
60 | |||
61 | |||
62 | USER-DEFINED CONSTANTS | ||
63 | ---------------------- | ||
64 | |||
65 | The tdc_config.py file contains multiple values that can be altered to suit | ||
66 | your needs. Any value in the NAMES dictionary can be altered without affecting | ||
67 | the tests to be run. These values are used in the tc commands that will be | ||
68 | executed as part of the test. More will be added as test cases require. | ||
69 | |||
70 | Example: | ||
71 | $TC qdisc add dev $DEV1 ingress | ||
72 | |||
73 | |||
74 | COMMAND LINE ARGUMENTS | ||
75 | ---------------------- | ||
76 | |||
77 | Run tdc.py -h to see the full list of available arguments. | ||
78 | |||
79 | -p PATH Specify the tc executable located at PATH to be used on this | ||
80 | test run | ||
81 | -c Show the available test case categories in this test file | ||
82 | -c CATEGORY Run only tests that belong to CATEGORY | ||
83 | -f FILE Read test cases from the JSON file named FILE | ||
84 | -l [CATEGORY] List all test cases in the JSON file. If CATEGORY is | ||
85 | specified, list test cases matching that category. | ||
86 | -s ID Show the test case matching ID | ||
87 | -e ID Execute the test case identified by ID | ||
88 | -i Generate unique ID numbers for test cases with no existing | ||
89 | ID number | ||
90 | |||
91 | |||
92 | ACKNOWLEDGEMENTS | ||
93 | ---------------- | ||
94 | |||
95 | Thanks to: | ||
96 | |||
97 | Jamal Hadi Salim, for providing valuable test cases | ||
98 | Keara Leibovitz, who wrote the CLI test driver that I used as a base for the | ||
99 | first version of the tc testing suite. This work was presented at | ||
100 | Netdev 1.2 Tokyo in October 2016. | ||
101 | Samir Hussain, for providing help while I dove into Python for the first time | ||
102 | and being a second eye for this code. | ||
diff --git a/tools/testing/selftests/tc-testing/TODO.txt b/tools/testing/selftests/tc-testing/TODO.txt new file mode 100644 index 000000000000..6a266d811a78 --- /dev/null +++ b/tools/testing/selftests/tc-testing/TODO.txt | |||
@@ -0,0 +1,10 @@ | |||
1 | tc Testing Suite To-Do list: | ||
2 | |||
3 | - Determine what tc features are supported in the kernel. If features are not | ||
4 | present, prevent the related categories from running. | ||
5 | |||
6 | - Add support for multiple versions of tc to run successively | ||
7 | |||
8 | - Improve error messages when tdc aborts its run | ||
9 | |||
10 | - Allow tdc to write its results to file | ||
diff --git a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt new file mode 100644 index 000000000000..4e09257bc443 --- /dev/null +++ b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt | |||
@@ -0,0 +1,69 @@ | |||
1 | tdc - Adding test cases for tdc | ||
2 | |||
3 | Author: Lucas Bates - lucasb@mojatatu.com | ||
4 | |||
5 | ADDING TEST CASES | ||
6 | ----------------- | ||
7 | |||
8 | User-defined tests should be added by defining a separate JSON file. This | ||
9 | will help prevent conflicts when updating the repository. Refer to | ||
10 | template.json for the required JSON format for test cases. | ||
11 | |||
12 | Include the 'id' field, but do not assign a value. Running tdc with the -i | ||
13 | option will generate a unique ID for that test case. | ||
14 | |||
15 | tdc will recursively search the 'tc' subdirectory for .json files. Any | ||
16 | test case files you create in these directories will automatically be included. | ||
17 | If you wish to store your custom test cases elsewhere, be sure to run tdc | ||
18 | with the -f argument and the path to your file. | ||
19 | |||
20 | Be aware of required escape characters in the JSON data - particularly when | ||
21 | defining the match pattern. Refer to the tctests.json file for examples when | ||
22 | in doubt. | ||
23 | |||
24 | |||
25 | TEST CASE STRUCTURE | ||
26 | ------------------- | ||
27 | |||
28 | Each test case has required data: | ||
29 | |||
30 | id: A unique alphanumeric value to identify a particular test case | ||
31 | name: Descriptive name that explains the command under test | ||
32 | category: A list of single-word descriptions covering what the command | ||
33 | under test is testing. Example: filter, actions, u32, gact, etc. | ||
34 | setup: The list of commands required to ensure the command under test | ||
35 | succeeds. For example: if testing a filter, the command to create | ||
36 | the qdisc would appear here. | ||
37 | cmdUnderTest: The tc command being tested itself. | ||
38 | expExitCode: The code returned by the command under test upon its termination. | ||
39 | tdc will compare this value against the actual returned value. | ||
40 | verifyCmd: The tc command to be run to verify successful execution. | ||
41 | For example: if the command under test creates a gact action, | ||
42 | verifyCmd should be "$TC actions show action gact" | ||
43 | matchPattern: A regular expression to be applied against the output of the | ||
44 | verifyCmd to prove the command under test succeeded. This pattern | ||
45 | should be as specific as possible so that a false positive is not | ||
46 | matched. | ||
47 | matchCount: How many times the regex in matchPattern should match. A value | ||
48 | of 0 is acceptable. | ||
49 | teardown: The list of commands to clean up after the test is completed. | ||
50 | The environment should be returned to the same state as when | ||
51 | this test was started: qdiscs deleted, actions flushed, etc. | ||
52 | |||
53 | |||
54 | SETUP/TEARDOWN ERRORS | ||
55 | --------------------- | ||
56 | |||
57 | If an error is detected during the setup/teardown process, execution of the | ||
58 | tests will immediately stop with an error message and the namespace in which | ||
59 | the tests are run will be destroyed. This is to prevent inaccurate results | ||
60 | in the test cases. | ||
61 | |||
62 | Repeated failures of the setup/teardown may indicate a problem with the test | ||
63 | case, or possibly even a bug in one of the commands that are not being tested. | ||
64 | |||
65 | It's possible to include acceptable exit codes with the setup/teardown command | ||
66 | so that it doesn't halt the script for an error that doesn't matter. Turn the | ||
67 | individual command into a list, with the command being first, followed by all | ||
68 | acceptable exit codes for the command. | ||
69 | |||
diff --git a/tools/testing/selftests/tc-testing/creating-testcases/template.json b/tools/testing/selftests/tc-testing/creating-testcases/template.json new file mode 100644 index 000000000000..87971744bdd4 --- /dev/null +++ b/tools/testing/selftests/tc-testing/creating-testcases/template.json | |||
@@ -0,0 +1,40 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "", | ||
4 | "name": "", | ||
5 | "category": [ | ||
6 | "", | ||
7 | "" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | "" | ||
11 | ], | ||
12 | "cmdUnderTest": "", | ||
13 | "expExitCode": "", | ||
14 | "verifyCmd": "", | ||
15 | "matchPattern": "", | ||
16 | "matchCount": "", | ||
17 | "teardown": [ | ||
18 | "" | ||
19 | ] | ||
20 | }, | ||
21 | { | ||
22 | "id": "", | ||
23 | "name": "", | ||
24 | "category": [ | ||
25 | "", | ||
26 | "" | ||
27 | ], | ||
28 | "setup": [ | ||
29 | "" | ||
30 | ], | ||
31 | "cmdUnderTest": "", | ||
32 | "expExitCode": "", | ||
33 | "verifyCmd": "", | ||
34 | "matchPattern": "", | ||
35 | "matchCount": "", | ||
36 | "teardown": [ | ||
37 | "" | ||
38 | ] | ||
39 | } | ||
40 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json b/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json new file mode 100644 index 000000000000..af519bc97a8e --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json | |||
@@ -0,0 +1,1115 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "e89a", | ||
4 | "name": "Add valid pass action", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "gact" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action gact", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action pass index 8", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions list action gact", | ||
20 | "matchPattern": "action order [0-9]*: gact action pass.*index 8 ref", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action gact" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "a02c", | ||
28 | "name": "Add valid pipe action", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "gact" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action gact", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ] | ||
40 | ], | ||
41 | "cmdUnderTest": "$TC actions add action pipe index 6", | ||
42 | "expExitCode": "0", | ||
43 | "verifyCmd": "$TC actions list action gact", | ||
44 | "matchPattern": "action order [0-9]*: gact action pipe.*index 6 ref", | ||
45 | "matchCount": "1", | ||
46 | "teardown": [ | ||
47 | "$TC actions flush action gact" | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "id": "feef", | ||
52 | "name": "Add valid reclassify action", | ||
53 | "category": [ | ||
54 | "actions", | ||
55 | "gact" | ||
56 | ], | ||
57 | "setup": [ | ||
58 | [ | ||
59 | "$TC actions flush action gact", | ||
60 | 0, | ||
61 | 1, | ||
62 | 255 | ||
63 | ] | ||
64 | ], | ||
65 | "cmdUnderTest": "$TC actions add action reclassify index 5", | ||
66 | "expExitCode": "0", | ||
67 | "verifyCmd": "$TC actions list action gact", | ||
68 | "matchPattern": "action order [0-9]*: gact action reclassify.*index 5 ref", | ||
69 | "matchCount": "1", | ||
70 | "teardown": [ | ||
71 | "$TC actions flush action gact" | ||
72 | ] | ||
73 | }, | ||
74 | { | ||
75 | "id": "8a7a", | ||
76 | "name": "Add valid drop action", | ||
77 | "category": [ | ||
78 | "actions", | ||
79 | "gact" | ||
80 | ], | ||
81 | "setup": [ | ||
82 | [ | ||
83 | "$TC actions flush action gact", | ||
84 | 0, | ||
85 | 1, | ||
86 | 255 | ||
87 | ] | ||
88 | ], | ||
89 | "cmdUnderTest": "$TC actions add action drop index 30", | ||
90 | "expExitCode": "0", | ||
91 | "verifyCmd": "$TC actions list action gact", | ||
92 | "matchPattern": "action order [0-9]*: gact action drop.*index 30 ref", | ||
93 | "matchCount": "1", | ||
94 | "teardown": [ | ||
95 | "$TC actions flush action gact" | ||
96 | ] | ||
97 | }, | ||
98 | { | ||
99 | "id": "9a52", | ||
100 | "name": "Add valid continue action", | ||
101 | "category": [ | ||
102 | "actions", | ||
103 | "gact" | ||
104 | ], | ||
105 | "setup": [ | ||
106 | [ | ||
107 | "$TC actions flush action gact", | ||
108 | 0, | ||
109 | 1, | ||
110 | 255 | ||
111 | ] | ||
112 | ], | ||
113 | "cmdUnderTest": "$TC actions add action continue index 432", | ||
114 | "expExitCode": "0", | ||
115 | "verifyCmd": "$TC actions list action gact", | ||
116 | "matchPattern": "action order [0-9]*: gact action continue.*index 432 ref", | ||
117 | "matchCount": "1", | ||
118 | "teardown": [ | ||
119 | "$TC actions flush action gact" | ||
120 | ] | ||
121 | }, | ||
122 | { | ||
123 | "id": "d700", | ||
124 | "name": "Add invalid action", | ||
125 | "category": [ | ||
126 | "actions", | ||
127 | "gact" | ||
128 | ], | ||
129 | "setup": [ | ||
130 | [ | ||
131 | "$TC actions flush action gact", | ||
132 | 0, | ||
133 | 1, | ||
134 | 255 | ||
135 | ] | ||
136 | ], | ||
137 | "cmdUnderTest": "$TC actions add action pump index 386", | ||
138 | "expExitCode": "255", | ||
139 | "verifyCmd": "$TC actions list action gact", | ||
140 | "matchPattern": "action order [0-9]*: gact action.*index 386 ref", | ||
141 | "matchCount": "0", | ||
142 | "teardown": [ | ||
143 | "$TC actions flush action gact" | ||
144 | ] | ||
145 | }, | ||
146 | { | ||
147 | "id": "9215", | ||
148 | "name": "Add action with duplicate index", | ||
149 | "category": [ | ||
150 | "actions", | ||
151 | "gact" | ||
152 | ], | ||
153 | "setup": [ | ||
154 | [ | ||
155 | "$TC actions flush action gact", | ||
156 | 0, | ||
157 | 1, | ||
158 | 255 | ||
159 | ], | ||
160 | "$TC actions add action pipe index 15" | ||
161 | ], | ||
162 | "cmdUnderTest": "$TC actions add action drop index 15", | ||
163 | "expExitCode": "255", | ||
164 | "verifyCmd": "$TC actions list action gact", | ||
165 | "matchPattern": "action order [0-9]*: gact action drop.*index 15 ref", | ||
166 | "matchCount": "0", | ||
167 | "teardown": [ | ||
168 | "$TC actions flush action gact" | ||
169 | ] | ||
170 | }, | ||
171 | { | ||
172 | "id": "798e", | ||
173 | "name": "Add action with index exceeding 32-bit maximum", | ||
174 | "category": [ | ||
175 | "actions", | ||
176 | "gact" | ||
177 | ], | ||
178 | "setup": [ | ||
179 | [ | ||
180 | "$TC actions flush action gact", | ||
181 | 0, | ||
182 | 1, | ||
183 | 255 | ||
184 | ] | ||
185 | ], | ||
186 | "cmdUnderTest": "$TC actions add action drop index 4294967296", | ||
187 | "expExitCode": "255", | ||
188 | "verifyCmd": "actions list action gact", | ||
189 | "matchPattern": "action order [0-9]*: gact action drop.*index 4294967296 ref", | ||
190 | "matchCount": "0", | ||
191 | "teardown": [ | ||
192 | "$TC actions flush action gact" | ||
193 | ] | ||
194 | }, | ||
195 | { | ||
196 | "id": "22be", | ||
197 | "name": "Add action with index at 32-bit maximum", | ||
198 | "category": [ | ||
199 | "actions", | ||
200 | "gact" | ||
201 | ], | ||
202 | "setup": [ | ||
203 | [ | ||
204 | "$TC actions flush action gact", | ||
205 | 0, | ||
206 | 1, | ||
207 | 255 | ||
208 | ] | ||
209 | ], | ||
210 | "cmdUnderTest": "$TC actions add action drop index 4294967295", | ||
211 | "expExitCode": "0", | ||
212 | "verifyCmd": "$TC actions list action gact", | ||
213 | "matchPattern": "action order [0-9]*: gact action drop.*index 4294967295 ref", | ||
214 | "matchCount": "1", | ||
215 | "teardown": [ | ||
216 | "$TC actions flush action gact" | ||
217 | ] | ||
218 | }, | ||
219 | { | ||
220 | "id": "ac2a", | ||
221 | "name": "List actions", | ||
222 | "category": [ | ||
223 | "actions", | ||
224 | "gact" | ||
225 | ], | ||
226 | "setup": [ | ||
227 | [ | ||
228 | "$TC actions flush action gact", | ||
229 | 0, | ||
230 | 1, | ||
231 | 255 | ||
232 | ], | ||
233 | "$TC actions add action reclassify index 101", | ||
234 | "$TC actions add action reclassify index 102", | ||
235 | "$TC actions add action reclassify index 103", | ||
236 | "$TC actions add action reclassify index 104", | ||
237 | "$TC actions add action reclassify index 105" | ||
238 | ], | ||
239 | "cmdUnderTest": "$TC actions list action gact", | ||
240 | "expExitCode": "0", | ||
241 | "verifyCmd": "$TC actions list action gact", | ||
242 | "matchPattern": "action order [0-9]*: gact action reclassify", | ||
243 | "matchCount": "5", | ||
244 | "teardown": [ | ||
245 | "$TC actions flush action gact" | ||
246 | ] | ||
247 | }, | ||
248 | { | ||
249 | "id": "63ec", | ||
250 | "name": "Delete pass action", | ||
251 | "category": [ | ||
252 | "actions", | ||
253 | "gact" | ||
254 | ], | ||
255 | "setup": [ | ||
256 | [ | ||
257 | "$TC actions flush action gact", | ||
258 | 0, | ||
259 | 1, | ||
260 | 255 | ||
261 | ], | ||
262 | "$TC actions add action pass index 1" | ||
263 | ], | ||
264 | "cmdUnderTest": "$TC actions del action gact index 1", | ||
265 | "expExitCode": "0", | ||
266 | "verifyCmd": "$TC actions list action gact", | ||
267 | "matchPattern": "action order [0-9]*: gact action pass.*index 1 ref", | ||
268 | "matchCount": "0", | ||
269 | "teardown": [ | ||
270 | "$TC actions flush action gact" | ||
271 | ] | ||
272 | }, | ||
273 | { | ||
274 | "id": "46be", | ||
275 | "name": "Delete pipe action", | ||
276 | "category": [ | ||
277 | "actions", | ||
278 | "gact" | ||
279 | ], | ||
280 | "setup": [ | ||
281 | [ | ||
282 | "$TC actions flush action gact", | ||
283 | 0, | ||
284 | 1, | ||
285 | 255 | ||
286 | ], | ||
287 | "$TC actions add action pipe index 9" | ||
288 | ], | ||
289 | "cmdUnderTest": "$TC actions del action gact index 9", | ||
290 | "expExitCode": "0", | ||
291 | "verifyCmd": "$TC actions list action gact", | ||
292 | "matchPattern": "action order [0-9]*: gact action pipe.*index 9 ref", | ||
293 | "matchCount": "0", | ||
294 | "teardown": [ | ||
295 | "$TC actions flush action gact" | ||
296 | ] | ||
297 | }, | ||
298 | { | ||
299 | "id": "2e08", | ||
300 | "name": "Delete reclassify action", | ||
301 | "category": [ | ||
302 | "actions", | ||
303 | "gact" | ||
304 | ], | ||
305 | "setup": [ | ||
306 | [ | ||
307 | "$TC actions flush action gact", | ||
308 | 0, | ||
309 | 1, | ||
310 | 255 | ||
311 | ], | ||
312 | "$TC actions add action reclassify index 65536" | ||
313 | ], | ||
314 | "cmdUnderTest": "$TC actions del action gact index 65536", | ||
315 | "expExitCode": "0", | ||
316 | "verifyCmd": "$TC actions list action gact", | ||
317 | "matchPattern": "action order [0-9]*: gact action reclassify.*index 65536 ref", | ||
318 | "matchCount": "0", | ||
319 | "teardown": [ | ||
320 | "$TC actions flush action gact" | ||
321 | ] | ||
322 | }, | ||
323 | { | ||
324 | "id": "99c4", | ||
325 | "name": "Delete drop action", | ||
326 | "category": [ | ||
327 | "actions", | ||
328 | "gact" | ||
329 | ], | ||
330 | "setup": [ | ||
331 | [ | ||
332 | "$TC actions flush action gact", | ||
333 | 0, | ||
334 | 1, | ||
335 | 255 | ||
336 | ], | ||
337 | "$TC actions add action drop index 16" | ||
338 | ], | ||
339 | "cmdUnderTest": "$TC actions del action gact index 16", | ||
340 | "expExitCode": "0", | ||
341 | "verifyCmd": "$TC actions list action gact", | ||
342 | "matchPattern": "action order [0-9]*: gact action drop.*index 16 ref", | ||
343 | "matchCount": "0", | ||
344 | "teardown": [ | ||
345 | "$TC actions flush action gact" | ||
346 | ] | ||
347 | }, | ||
348 | { | ||
349 | "id": "fb6b", | ||
350 | "name": "Delete continue action", | ||
351 | "category": [ | ||
352 | "actions", | ||
353 | "gact" | ||
354 | ], | ||
355 | "setup": [ | ||
356 | [ | ||
357 | "$TC actions flush action gact", | ||
358 | 0, | ||
359 | 1, | ||
360 | 255 | ||
361 | ], | ||
362 | "$TC actions add action continue index 32" | ||
363 | ], | ||
364 | "cmdUnderTest": "$TC actions del action gact index 32", | ||
365 | "expExitCode": "0", | ||
366 | "verifyCmd": "actions list action gact", | ||
367 | "matchPattern": "action order [0-9]*: gact action continue.*index 32 ref", | ||
368 | "matchCount": "0", | ||
369 | "teardown": [ | ||
370 | "$TC actions flush action gact" | ||
371 | ] | ||
372 | }, | ||
373 | { | ||
374 | "id": "0eb3", | ||
375 | "name": "Delete non-existent action", | ||
376 | "category": [ | ||
377 | "actions", | ||
378 | "gact" | ||
379 | ], | ||
380 | "setup": [ | ||
381 | [ | ||
382 | "$TC actions flush action gact", | ||
383 | 0, | ||
384 | 1, | ||
385 | 255 | ||
386 | ] | ||
387 | ], | ||
388 | "cmdUnderTest": "$TC actions del action gact index 2", | ||
389 | "expExitCode": "255", | ||
390 | "verifyCmd": "$TC actions list action gact", | ||
391 | "matchPattern": "action order [0-9]*: gact action", | ||
392 | "matchCount": "0", | ||
393 | "teardown": [ | ||
394 | "$TC actions flush action gact" | ||
395 | ] | ||
396 | }, | ||
397 | { | ||
398 | "id": "5124", | ||
399 | "name": "Add mirred mirror to egress action", | ||
400 | "category": [ | ||
401 | "actions", | ||
402 | "mirred" | ||
403 | ], | ||
404 | "setup": [ | ||
405 | [ | ||
406 | "$TC actions flush action mirred", | ||
407 | 0, | ||
408 | 1, | ||
409 | 255 | ||
410 | ] | ||
411 | ], | ||
412 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 1 dev lo", | ||
413 | "expExitCode": "0", | ||
414 | "verifyCmd": "$TC actions list action mirred", | ||
415 | "matchPattern": "action order [0-9]*: mirred \\(Egress Mirror to device lo\\).*index 1 ref", | ||
416 | "matchCount": "1", | ||
417 | "teardown": [ | ||
418 | "$TC actions flush action mirred" | ||
419 | ] | ||
420 | }, | ||
421 | { | ||
422 | "id": "6fb4", | ||
423 | "name": "Add mirred redirect to egress action", | ||
424 | "category": [ | ||
425 | "actions", | ||
426 | "mirred" | ||
427 | ], | ||
428 | "setup": [ | ||
429 | [ | ||
430 | "$TC actions flush action mirred", | ||
431 | 0, | ||
432 | 1, | ||
433 | 255 | ||
434 | ] | ||
435 | ], | ||
436 | "cmdUnderTest": "$TC actions add action mirred egress redirect index 2 dev lo action pipe", | ||
437 | "expExitCode": "0", | ||
438 | "verifyCmd": "$TC actions list action mirred", | ||
439 | "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 2 ref", | ||
440 | "matchCount": "1", | ||
441 | "teardown": [ | ||
442 | "$TC actions flush action mirred" | ||
443 | ] | ||
444 | }, | ||
445 | { | ||
446 | "id": "ba38", | ||
447 | "name": "Get mirred actions", | ||
448 | "category": [ | ||
449 | "actions", | ||
450 | "mirred" | ||
451 | ], | ||
452 | "setup": [ | ||
453 | [ | ||
454 | "$TC actions flush action mirred", | ||
455 | 0, | ||
456 | 1, | ||
457 | 255 | ||
458 | ], | ||
459 | "$TC actions add action mirred egress mirror index 1 dev lo", | ||
460 | "$TC actions add action mirred egress redirect index 2 dev lo" | ||
461 | ], | ||
462 | "cmdUnderTest": "$TC actions show action mirred", | ||
463 | "expExitCode": "0", | ||
464 | "verifyCmd": "$TC actions list action mirred", | ||
465 | "matchPattern": "[Mirror|Redirect] to device lo", | ||
466 | "matchCount": "2", | ||
467 | "teardown": [ | ||
468 | "$TC actions flush action mirred" | ||
469 | ] | ||
470 | }, | ||
471 | { | ||
472 | "id": "d7c0", | ||
473 | "name": "Add invalid mirred direction", | ||
474 | "category": [ | ||
475 | "actions", | ||
476 | "mirred" | ||
477 | ], | ||
478 | "setup": [ | ||
479 | [ | ||
480 | "$TC actions flush action mirred", | ||
481 | 0, | ||
482 | 1, | ||
483 | 255 | ||
484 | ] | ||
485 | ], | ||
486 | "cmdUnderTest": "$TC actions add action mirred inbound mirror index 20 dev lo", | ||
487 | "expExitCode": "255", | ||
488 | "verifyCmd": "$TC actions list action mirred", | ||
489 | "matchPattern": "action order [0-9]*: mirred \\(.*to device lo\\).*index 20 ref", | ||
490 | "matchCount": "0", | ||
491 | "teardown": [ | ||
492 | "$TC actions flush action mirred" | ||
493 | ] | ||
494 | }, | ||
495 | { | ||
496 | "id": "e213", | ||
497 | "name": "Add invalid mirred action", | ||
498 | "category": [ | ||
499 | "actions", | ||
500 | "mirred" | ||
501 | ], | ||
502 | "setup": [ | ||
503 | [ | ||
504 | "$TC actions flush action mirred", | ||
505 | 0, | ||
506 | 1, | ||
507 | 255 | ||
508 | ] | ||
509 | ], | ||
510 | "cmdUnderTest": "$TC actions add action mirred egress remirror index 20 dev lo", | ||
511 | "expExitCode": "255", | ||
512 | "verifyCmd": "$TC actions list action mirred", | ||
513 | "matchPattern": "action order [0-9]*: mirred \\(Egress.*to device lo\\).*index 20 ref", | ||
514 | "matchCount": "0", | ||
515 | "teardown": [ | ||
516 | "$TC actions flush action mirred" | ||
517 | ] | ||
518 | }, | ||
519 | { | ||
520 | "id": "2d89", | ||
521 | "name": "Add mirred action with invalid device", | ||
522 | "category": [ | ||
523 | "actions", | ||
524 | "mirred" | ||
525 | ], | ||
526 | "setup": [ | ||
527 | [ | ||
528 | "$TC actions flush action mirred", | ||
529 | 0, | ||
530 | 1, | ||
531 | 255 | ||
532 | ] | ||
533 | ], | ||
534 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 20 dev eltoh", | ||
535 | "expExitCode": "255", | ||
536 | "verifyCmd": "$TC actions list action mirred", | ||
537 | "matchPattern": "action order [0-9]*: mirred \\(.*to device eltoh\\).*index 20 ref", | ||
538 | "matchCount": "0", | ||
539 | "teardown": [ | ||
540 | "$TC actions flush action mirred" | ||
541 | ] | ||
542 | }, | ||
543 | { | ||
544 | "id": "300b", | ||
545 | "name": "Add mirred action with duplicate index", | ||
546 | "category": [ | ||
547 | "actions", | ||
548 | "mirred" | ||
549 | ], | ||
550 | "setup": [ | ||
551 | [ | ||
552 | "$TC actions flush action mirred", | ||
553 | 0, | ||
554 | 1, | ||
555 | 255 | ||
556 | ], | ||
557 | "$TC actions add action mirred egress redirect index 15 dev lo" | ||
558 | ], | ||
559 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 15 dev lo", | ||
560 | "expExitCode": "255", | ||
561 | "verifyCmd": "$TC actions list action mirred", | ||
562 | "matchPattern": "action order [0-9]*: mirred \\(.*to device lo\\).*index 15 ref", | ||
563 | "matchCount": "1", | ||
564 | "teardown": [ | ||
565 | "$TC actions flush action mirred" | ||
566 | ] | ||
567 | }, | ||
568 | { | ||
569 | "id": "a70e", | ||
570 | "name": "Delete mirred mirror action", | ||
571 | "category": [ | ||
572 | "actions", | ||
573 | "mirred" | ||
574 | ], | ||
575 | "setup": [ | ||
576 | [ | ||
577 | "$TC actions flush action mirred", | ||
578 | 0, | ||
579 | 1, | ||
580 | 255 | ||
581 | ], | ||
582 | "$TC actions add action mirred egress mirror index 5 dev lo" | ||
583 | ], | ||
584 | "cmdUnderTest": "$TC actions del action mirred index 5", | ||
585 | "expExitCode": "0", | ||
586 | "verifyCmd": "$TC actions list action mirred", | ||
587 | "matchPattern": "action order [0-9]*: mirred \\(Egress Mirror to device lo\\).*index 5 ref", | ||
588 | "matchCount": "0", | ||
589 | "teardown": [ | ||
590 | "$TC actions flush action mirred" | ||
591 | ] | ||
592 | }, | ||
593 | { | ||
594 | "id": "3fb3", | ||
595 | "name": "Delete mirred redirect action", | ||
596 | "category": [ | ||
597 | "actions", | ||
598 | "mirred" | ||
599 | ], | ||
600 | "setup": [ | ||
601 | [ | ||
602 | "$TC actions flush action mirred", | ||
603 | 0, | ||
604 | 1, | ||
605 | 255 | ||
606 | ], | ||
607 | "$TC actions add action mirred egress redirect index 5 dev lo" | ||
608 | ], | ||
609 | "cmdUnderTest": "$TC actions del action mirred index 5", | ||
610 | "expExitCode": "0", | ||
611 | "verifyCmd": "$TC actions list action mirred", | ||
612 | "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 5 ref", | ||
613 | "matchCount": "0", | ||
614 | "teardown": [ | ||
615 | "$TC actions flush action mirred" | ||
616 | ] | ||
617 | }, | ||
618 | { | ||
619 | "id": "b078", | ||
620 | "name": "Add simple action", | ||
621 | "category": [ | ||
622 | "actions", | ||
623 | "simple" | ||
624 | ], | ||
625 | "setup": [ | ||
626 | [ | ||
627 | "$TC actions flush action simple", | ||
628 | 0, | ||
629 | 1, | ||
630 | 255 | ||
631 | ] | ||
632 | ], | ||
633 | "cmdUnderTest": "$TC actions add action simple sdata \"A triumph\" index 60", | ||
634 | "expExitCode": "0", | ||
635 | "verifyCmd": "$TC actions list action simple", | ||
636 | "matchPattern": "action order [0-9]*: Simple <A triumph>.*index 60 ref", | ||
637 | "matchCount": "1", | ||
638 | "teardown": [ | ||
639 | "$TC actions flush action simple" | ||
640 | ] | ||
641 | }, | ||
642 | { | ||
643 | "id": "6d4c", | ||
644 | "name": "Add simple action with duplicate index", | ||
645 | "category": [ | ||
646 | "actions", | ||
647 | "simple" | ||
648 | ], | ||
649 | "setup": [ | ||
650 | [ | ||
651 | "$TC actions flush action simple", | ||
652 | 0, | ||
653 | 1, | ||
654 | 255 | ||
655 | ], | ||
656 | "$TC actions add action simple sdata \"Aruba\" index 4" | ||
657 | ], | ||
658 | "cmdUnderTest": "$TC actions add action simple sdata \"Jamaica\" index 4", | ||
659 | "expExitCode": "255", | ||
660 | "verifyCmd": "$TC actions list action simple", | ||
661 | "matchPattern": "action order [0-9]*: Simple <Jamaica>.*ref", | ||
662 | "matchCount": "0", | ||
663 | "teardown": [ | ||
664 | "$TC actions flush action simple" | ||
665 | ] | ||
666 | }, | ||
667 | { | ||
668 | "id": "2542", | ||
669 | "name": "List simple actions", | ||
670 | "category": [ | ||
671 | "actions", | ||
672 | "simple" | ||
673 | ], | ||
674 | "setup": [ | ||
675 | [ | ||
676 | "$TC actions flush action simple", | ||
677 | 0, | ||
678 | 1, | ||
679 | 255 | ||
680 | ], | ||
681 | "$TC actions add action simple sdata \"Rock\"", | ||
682 | "$TC actions add action simple sdata \"Paper\"", | ||
683 | "$TC actions add action simple sdata \"Scissors\" index 98" | ||
684 | ], | ||
685 | "cmdUnderTest": "$TC actions list action simple", | ||
686 | "expExitCode": "0", | ||
687 | "verifyCmd": "$TC actions list action simple", | ||
688 | "matchPattern": "action order [0-9]*: Simple <[A-Z][a-z]*>", | ||
689 | "matchCount": "3", | ||
690 | "teardown": [ | ||
691 | "$TC actions flush action simple" | ||
692 | ] | ||
693 | }, | ||
694 | { | ||
695 | "id": "ea67", | ||
696 | "name": "Delete simple action", | ||
697 | "category": [ | ||
698 | "actions", | ||
699 | "simple" | ||
700 | ], | ||
701 | "setup": [ | ||
702 | [ | ||
703 | "$TC actions flush action simple", | ||
704 | 0, | ||
705 | 1, | ||
706 | 255 | ||
707 | ], | ||
708 | "$TC actions add action simple sdata \"Blinkenlights\" index 1" | ||
709 | ], | ||
710 | "cmdUnderTest": "$TC actions delete action simple index 1", | ||
711 | "expExitCode": "0", | ||
712 | "verifyCmd": "$TC actions list action simple", | ||
713 | "matchPattern": "action order [0-9]*: Simple <Blinkenlights>.*index 1 ref", | ||
714 | "matchCount": "0", | ||
715 | "teardown": [ | ||
716 | "$TC actions flush action simple" | ||
717 | ] | ||
718 | }, | ||
719 | { | ||
720 | "id": "8ff1", | ||
721 | "name": "Flush simple actions", | ||
722 | "category": [ | ||
723 | "actions", | ||
724 | "simple" | ||
725 | ], | ||
726 | "setup": [ | ||
727 | [ | ||
728 | "$TC actions flush action simple", | ||
729 | 0, | ||
730 | 1, | ||
731 | 255 | ||
732 | ], | ||
733 | "$TC actions add action simple sdata \"Kirk\"", | ||
734 | "$TC actions add action simple sdata \"Spock\" index 50", | ||
735 | "$TC actions add action simple sdata \"McCoy\" index 9" | ||
736 | ], | ||
737 | "cmdUnderTest": "$TC actions flush action simple", | ||
738 | "expExitCode": "0", | ||
739 | "verifyCmd": "$TC actions list action simple", | ||
740 | "matchPattern": "action order [0-9]*: Simple <[A-Z][a-z]*>", | ||
741 | "matchCount": "0", | ||
742 | "teardown": [ | ||
743 | "" | ||
744 | ] | ||
745 | }, | ||
746 | { | ||
747 | "id": "6236", | ||
748 | "name": "Add skbedit action with valid mark", | ||
749 | "category": [ | ||
750 | "actions", | ||
751 | "skbedit" | ||
752 | ], | ||
753 | "setup": [ | ||
754 | [ | ||
755 | "$TC actions flush action skbedit", | ||
756 | 0, | ||
757 | 1, | ||
758 | 255 | ||
759 | ] | ||
760 | ], | ||
761 | "cmdUnderTest": "$TC actions add action skbedit mark 1", | ||
762 | "expExitCode": "0", | ||
763 | "verifyCmd": "$TC actions list action skbedit", | ||
764 | "matchPattern": "action order [0-9]*: skbedit mark 1", | ||
765 | "matchCount": "1", | ||
766 | "teardown": [ | ||
767 | "$TC actions flush action skbedit" | ||
768 | ] | ||
769 | }, | ||
770 | { | ||
771 | "id": "407b", | ||
772 | "name": "Add skbedit action with invalid mark", | ||
773 | "category": [ | ||
774 | "actions", | ||
775 | "skbedit" | ||
776 | ], | ||
777 | "setup": [ | ||
778 | [ | ||
779 | "$TC actions flush action skbedit", | ||
780 | 0, | ||
781 | 1, | ||
782 | 255 | ||
783 | ] | ||
784 | ], | ||
785 | "cmdUnderTest": "$TC actions add action skbedit mark 666777888999", | ||
786 | "expExitCode": "255", | ||
787 | "verifyCmd": "$TC actions list action skbedit", | ||
788 | "matchPattern": "action order [0-9]*: skbedit mark", | ||
789 | "matchCount": "0", | ||
790 | "teardown": [ | ||
791 | "$TC actions flush action skbedit" | ||
792 | ] | ||
793 | }, | ||
794 | { | ||
795 | "id": "081d", | ||
796 | "name": "Add skbedit action with priority", | ||
797 | "category": [ | ||
798 | "actions", | ||
799 | "skbedit" | ||
800 | ], | ||
801 | "setup": [ | ||
802 | [ | ||
803 | "$TC actions flush action skbedit", | ||
804 | 0, | ||
805 | 1, | ||
806 | 255 | ||
807 | ] | ||
808 | ], | ||
809 | "cmdUnderTest": "$TC actions add action skbedit prio 99", | ||
810 | "expExitCode": "0", | ||
811 | "verifyCmd": "$TC actions list action skbedit", | ||
812 | "matchPattern": "action order [0-9]*: skbedit priority :99", | ||
813 | "matchCount": "1", | ||
814 | "teardown": [ | ||
815 | "$TC actions flush action skbedit" | ||
816 | ] | ||
817 | }, | ||
818 | { | ||
819 | "id": "cc37", | ||
820 | "name": "Add skbedit action with invalid priority", | ||
821 | "category": [ | ||
822 | "actions", | ||
823 | "skbedit" | ||
824 | ], | ||
825 | "setup": [ | ||
826 | [ | ||
827 | "$TC actions flush action skbedit", | ||
828 | 0, | ||
829 | 1, | ||
830 | 255 | ||
831 | ] | ||
832 | ], | ||
833 | "cmdUnderTest": "$TC actions add action skbedit prio foo", | ||
834 | "expExitCode": "255", | ||
835 | "verifyCmd": "$TC actions list action skbedit", | ||
836 | "matchPattern": "action order [0-9]*: skbedit priority", | ||
837 | "matchCount": "0", | ||
838 | "teardown": [ | ||
839 | "$TC actions flush action skbedit" | ||
840 | ] | ||
841 | }, | ||
842 | { | ||
843 | "id": "3c95", | ||
844 | "name": "Add skbedit action with queue_mapping", | ||
845 | "category": [ | ||
846 | "actions", | ||
847 | "skbedit" | ||
848 | ], | ||
849 | "setup": [ | ||
850 | [ | ||
851 | "$TC actions flush action skbedit", | ||
852 | 0, | ||
853 | 1, | ||
854 | 255 | ||
855 | ] | ||
856 | ], | ||
857 | "cmdUnderTest": "$TC actions add action skbedit queue_mapping 909", | ||
858 | "expExitCode": "0", | ||
859 | "verifyCmd": "$TC actions list action skbedit", | ||
860 | "matchPattern": "action order [0-9]*: skbedit queue_mapping 909", | ||
861 | "matchCount": "1", | ||
862 | "teardown": [ | ||
863 | "$TC actions flush action skbedit" | ||
864 | ] | ||
865 | }, | ||
866 | { | ||
867 | "id": "985c", | ||
868 | "name": "Add skbedit action with invalid queue_mapping", | ||
869 | "category": [ | ||
870 | "actions", | ||
871 | "skbedit" | ||
872 | ], | ||
873 | "setup": [ | ||
874 | [ | ||
875 | "$TC actions flush action skbedit", | ||
876 | 0, | ||
877 | 1, | ||
878 | 255 | ||
879 | ] | ||
880 | ], | ||
881 | "cmdUnderTest": "$TC actions add action skbedit queue_mapping 67000", | ||
882 | "expExitCode": "255", | ||
883 | "verifyCmd": "$TC actions list action skbedit", | ||
884 | "matchPattern": "action order [0-9]*: skbedit queue_mapping", | ||
885 | "matchCount": "0", | ||
886 | "teardown": [ | ||
887 | "$TC actions flush action skbedit" | ||
888 | ] | ||
889 | }, | ||
890 | { | ||
891 | "id": "224f", | ||
892 | "name": "Add skbedit action with ptype host", | ||
893 | "category": [ | ||
894 | "actions", | ||
895 | "skbedit" | ||
896 | ], | ||
897 | "setup": [ | ||
898 | [ | ||
899 | "$TC actions flush action skbedit", | ||
900 | 0, | ||
901 | 1, | ||
902 | 255 | ||
903 | ] | ||
904 | ], | ||
905 | "cmdUnderTest": "$TC actions add action skbedit ptype host", | ||
906 | "expExitCode": "0", | ||
907 | "verifyCmd": "$TC actions list action skbedit", | ||
908 | "matchPattern": "action order [0-9]*: skbedit ptype host", | ||
909 | "matchCount": "1", | ||
910 | "teardown": [ | ||
911 | "$TC actions flush action skbedit" | ||
912 | ] | ||
913 | }, | ||
914 | { | ||
915 | "id": "d1a3", | ||
916 | "name": "Add skbedit action with ptype otherhost", | ||
917 | "category": [ | ||
918 | "actions", | ||
919 | "skbedit" | ||
920 | ], | ||
921 | "setup": [ | ||
922 | [ | ||
923 | "$TC actions flush action skbedit", | ||
924 | 0, | ||
925 | 1, | ||
926 | 255 | ||
927 | ] | ||
928 | ], | ||
929 | "cmdUnderTest": "$TC actions add action skbedit ptype otherhost", | ||
930 | "expExitCode": "0", | ||
931 | "verifyCmd": "$TC actions list action skbedit", | ||
932 | "matchPattern": "action order [0-9]*: skbedit ptype otherhost", | ||
933 | "matchCount": "1", | ||
934 | "teardown": [ | ||
935 | "$TC actions flush action skbedit" | ||
936 | ] | ||
937 | }, | ||
938 | { | ||
939 | "id": "b9c6", | ||
940 | "name": "Add skbedit action with invalid ptype", | ||
941 | "category": [ | ||
942 | "actions", | ||
943 | "skbedit" | ||
944 | ], | ||
945 | "setup": [ | ||
946 | [ | ||
947 | "$TC actions flush action skbedit", | ||
948 | 0, | ||
949 | 1, | ||
950 | 255 | ||
951 | ] | ||
952 | ], | ||
953 | "cmdUnderTest": "$TC actions add action skbedit ptype openair", | ||
954 | "expExitCode": "255", | ||
955 | "verifyCmd": "$TC actions list action skbedit", | ||
956 | "matchPattern": "action order [0-9]*: skbedit ptype openair", | ||
957 | "matchCount": "0", | ||
958 | "teardown": [ | ||
959 | "$TC actions flush action skbedit" | ||
960 | ] | ||
961 | }, | ||
962 | { | ||
963 | "id": "5172", | ||
964 | "name": "List skbedit actions", | ||
965 | "category": [ | ||
966 | "actions", | ||
967 | "skbedit" | ||
968 | ], | ||
969 | "setup": [ | ||
970 | [ | ||
971 | "$TC actions flush action skbedit", | ||
972 | 0, | ||
973 | 1, | ||
974 | 255 | ||
975 | ], | ||
976 | "$TC actions add action skbedit ptype otherhost", | ||
977 | "$TC actions add action skbedit ptype broadcast", | ||
978 | "$TC actions add action skbedit mark 59", | ||
979 | "$TC actions add action skbedit mark 409" | ||
980 | ], | ||
981 | "cmdUnderTest": "$TC actions list action skbedit", | ||
982 | "expExitCode": "0", | ||
983 | "verifyCmd": "$TC actions list action skbedit", | ||
984 | "matchPattern": "action order [0-9]*: skbedit", | ||
985 | "matchCount": "4", | ||
986 | "teardown": [ | ||
987 | "$TC actions flush action skbedit" | ||
988 | ] | ||
989 | }, | ||
990 | { | ||
991 | "id": "a6d6", | ||
992 | "name": "Add skbedit action with index", | ||
993 | "category": [ | ||
994 | "actions", | ||
995 | "skbedit" | ||
996 | ], | ||
997 | "setup": [ | ||
998 | [ | ||
999 | "$TC actions flush action skbedit", | ||
1000 | 0, | ||
1001 | 1, | ||
1002 | 255 | ||
1003 | ] | ||
1004 | ], | ||
1005 | "cmdUnderTest": "$TC actions add action skbedit mark 808 index 4040404040", | ||
1006 | "expExitCode": "0", | ||
1007 | "verifyCmd": "$TC actions list action skbedit", | ||
1008 | "matchPattern": "index 4040404040", | ||
1009 | "matchCount": "1", | ||
1010 | "teardown": [ | ||
1011 | "$TC actions flush action skbedit" | ||
1012 | ] | ||
1013 | }, | ||
1014 | { | ||
1015 | "id": "38f3", | ||
1016 | "name": "Delete skbedit action", | ||
1017 | "category": [ | ||
1018 | "actions", | ||
1019 | "skbedit" | ||
1020 | ], | ||
1021 | "setup": [ | ||
1022 | [ | ||
1023 | "$TC actions flush action skbedit", | ||
1024 | 0, | ||
1025 | 1, | ||
1026 | 255 | ||
1027 | ], | ||
1028 | "$TC actions add action skbedit mark 42 index 9009" | ||
1029 | ], | ||
1030 | "cmdUnderTest": "$TC actions del action skbedit index 9009", | ||
1031 | "expExitCode": "0", | ||
1032 | "verifyCmd": "$TC actions list action skbedit", | ||
1033 | "matchPattern": "action order [0-9]*: skbedit mark 42", | ||
1034 | "matchCount": "0", | ||
1035 | "teardown": [ | ||
1036 | "$TC actions flush action skbedit" | ||
1037 | ] | ||
1038 | }, | ||
1039 | { | ||
1040 | "id": "ce97", | ||
1041 | "name": "Flush skbedit actions", | ||
1042 | "category": [ | ||
1043 | "actions", | ||
1044 | "skbedit" | ||
1045 | ], | ||
1046 | "setup": [ | ||
1047 | "$TC actions add action skbedit mark 500", | ||
1048 | "$TC actions add action skbedit mark 501", | ||
1049 | "$TC actions add action skbedit mark 502", | ||
1050 | "$TC actions add action skbedit mark 503", | ||
1051 | "$TC actions add action skbedit mark 504", | ||
1052 | "$TC actions add action skbedit mark 505", | ||
1053 | "$TC actions add action skbedit mark 506" | ||
1054 | ], | ||
1055 | "cmdUnderTest": "$TC actions flush action skbedit", | ||
1056 | "expExitCode": "0", | ||
1057 | "verifyCmd": "$TC actions list action skbedit", | ||
1058 | "matchPattern": "action order [0-9]*: skbedit", | ||
1059 | "matchCount": "0", | ||
1060 | "teardown": [ | ||
1061 | "$TC actions flush action skbedit" | ||
1062 | ] | ||
1063 | }, | ||
1064 | { | ||
1065 | "id": "f02c", | ||
1066 | "name": "Replace gact action", | ||
1067 | "category": [ | ||
1068 | "actions", | ||
1069 | "gact" | ||
1070 | ], | ||
1071 | "setup": [ | ||
1072 | [ | ||
1073 | "$TC actions flush action gact", | ||
1074 | 0, | ||
1075 | 1, | ||
1076 | 255 | ||
1077 | ], | ||
1078 | "$TC actions add action drop index 10", | ||
1079 | "$TC actions add action drop index 12" | ||
1080 | ], | ||
1081 | "cmdUnderTest": "$TC actions replace action ok index 12", | ||
1082 | "expExitCode": "0", | ||
1083 | "verifyCmd": "$TC actions ls action gact", | ||
1084 | "matchPattern": "action order [0-9]*: gact action pass", | ||
1085 | "matchCount": "1", | ||
1086 | "teardown": [ | ||
1087 | "$TC actions flush action gact" | ||
1088 | ] | ||
1089 | }, | ||
1090 | { | ||
1091 | "id": "525f", | ||
1092 | "name": "Get gact action by index", | ||
1093 | "category": [ | ||
1094 | "actions", | ||
1095 | "gact" | ||
1096 | ], | ||
1097 | "setup": [ | ||
1098 | [ | ||
1099 | "$TC actions flush action gact", | ||
1100 | 0, | ||
1101 | 1, | ||
1102 | 255 | ||
1103 | ], | ||
1104 | "$TC actions add action drop index 3900800700" | ||
1105 | ], | ||
1106 | "cmdUnderTest": "$TC actions get action gact index 3900800700", | ||
1107 | "expExitCode": "0", | ||
1108 | "verifyCmd": "$TC actions get action gact index 3900800700", | ||
1109 | "matchPattern": "index 3900800700", | ||
1110 | "matchCount": "1", | ||
1111 | "teardown": [ | ||
1112 | "$TC actions flush action gact" | ||
1113 | ] | ||
1114 | } | ||
1115 | ] \ No newline at end of file | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json new file mode 100644 index 000000000000..c727b96a59b0 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json | |||
@@ -0,0 +1,21 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "e9a3", | ||
4 | "name": "Add u32 with source match", | ||
5 | "category": [ | ||
6 | "filter", | ||
7 | "u32" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | "$TC qdisc add dev $DEV1 ingress" | ||
11 | ], | ||
12 | "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 u32 match ip src 127.0.0.1/32 flowid 1:1 action ok", | ||
13 | "expExitCode": "0", | ||
14 | "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", | ||
15 | "matchPattern": "match 7f000002/ffffffff at 12", | ||
16 | "matchCount": "0", | ||
17 | "teardown": [ | ||
18 | "$TC qdisc del dev $DEV1 ingress" | ||
19 | ] | ||
20 | } | ||
21 | ] \ No newline at end of file | ||
diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py new file mode 100755 index 000000000000..cd61b7844c0d --- /dev/null +++ b/tools/testing/selftests/tc-testing/tdc.py | |||
@@ -0,0 +1,413 @@ | |||
1 | #!/usr/bin/env python3 | ||
2 | |||
3 | """ | ||
4 | tdc.py - Linux tc (Traffic Control) unit test driver | ||
5 | |||
6 | Copyright (C) 2017 Lucas Bates <lucasb@mojatatu.com> | ||
7 | """ | ||
8 | |||
9 | import re | ||
10 | import os | ||
11 | import sys | ||
12 | import argparse | ||
13 | import json | ||
14 | import subprocess | ||
15 | from collections import OrderedDict | ||
16 | from string import Template | ||
17 | |||
18 | from tdc_config import * | ||
19 | from tdc_helper import * | ||
20 | |||
21 | |||
22 | USE_NS = True | ||
23 | |||
24 | |||
25 | def replace_keywords(cmd): | ||
26 | """ | ||
27 | For a given executable command, substitute any known | ||
28 | variables contained within NAMES with the correct values | ||
29 | """ | ||
30 | tcmd = Template(cmd) | ||
31 | subcmd = tcmd.safe_substitute(NAMES) | ||
32 | return subcmd | ||
33 | |||
34 | |||
35 | def exec_cmd(command, nsonly=True): | ||
36 | """ | ||
37 | Perform any required modifications on an executable command, then run | ||
38 | it in a subprocess and return the results. | ||
39 | """ | ||
40 | if (USE_NS and nsonly): | ||
41 | command = 'ip netns exec $NS ' + command | ||
42 | |||
43 | if '$' in command: | ||
44 | command = replace_keywords(command) | ||
45 | |||
46 | proc = subprocess.Popen(command, | ||
47 | shell=True, | ||
48 | stdout=subprocess.PIPE, | ||
49 | stderr=subprocess.PIPE) | ||
50 | (rawout, serr) = proc.communicate() | ||
51 | |||
52 | if proc.returncode != 0: | ||
53 | foutput = serr.decode("utf-8") | ||
54 | else: | ||
55 | foutput = rawout.decode("utf-8") | ||
56 | |||
57 | proc.stdout.close() | ||
58 | proc.stderr.close() | ||
59 | return proc, foutput | ||
60 | |||
61 | |||
62 | def prepare_env(cmdlist): | ||
63 | """ | ||
64 | Execute the setup/teardown commands for a test case. Optionally | ||
65 | terminate test execution if the command fails. | ||
66 | """ | ||
67 | for cmdinfo in cmdlist: | ||
68 | if (type(cmdinfo) == list): | ||
69 | exit_codes = cmdinfo[1:] | ||
70 | cmd = cmdinfo[0] | ||
71 | else: | ||
72 | exit_codes = [0] | ||
73 | cmd = cmdinfo | ||
74 | |||
75 | if (len(cmd) == 0): | ||
76 | continue | ||
77 | |||
78 | (proc, foutput) = exec_cmd(cmd) | ||
79 | |||
80 | if proc.returncode not in exit_codes: | ||
81 | |||
82 | print("Could not execute:") | ||
83 | print(cmd) | ||
84 | print("\nError message:") | ||
85 | print(foutput) | ||
86 | print("\nAborting test run.") | ||
87 | ns_destroy() | ||
88 | exit(1) | ||
89 | |||
90 | |||
91 | def test_runner(filtered_tests): | ||
92 | """ | ||
93 | Driver function for the unit tests. | ||
94 | |||
95 | Prints information about the tests being run, executes the setup and | ||
96 | teardown commands and the command under test itself. Also determines | ||
97 | success/failure based on the information in the test case and generates | ||
98 | TAP output accordingly. | ||
99 | """ | ||
100 | testlist = filtered_tests | ||
101 | tcount = len(testlist) | ||
102 | index = 1 | ||
103 | tap = str(index) + ".." + str(tcount) + "\n" | ||
104 | |||
105 | for tidx in testlist: | ||
106 | result = True | ||
107 | tresult = "" | ||
108 | print("Test " + tidx["id"] + ": " + tidx["name"]) | ||
109 | prepare_env(tidx["setup"]) | ||
110 | (p, procout) = exec_cmd(tidx["cmdUnderTest"]) | ||
111 | exit_code = p.returncode | ||
112 | |||
113 | if (exit_code != int(tidx["expExitCode"])): | ||
114 | result = False | ||
115 | print("exit:", exit_code, int(tidx["expExitCode"])) | ||
116 | print(procout) | ||
117 | else: | ||
118 | match_pattern = re.compile(str(tidx["matchPattern"]), re.DOTALL) | ||
119 | (p, procout) = exec_cmd(tidx["verifyCmd"]) | ||
120 | match_index = re.findall(match_pattern, procout) | ||
121 | if len(match_index) != int(tidx["matchCount"]): | ||
122 | result = False | ||
123 | |||
124 | if result == True: | ||
125 | tresult += "ok " | ||
126 | else: | ||
127 | tresult += "not ok " | ||
128 | tap += tresult + str(index) + " " + tidx["id"] + " " + tidx["name"] + "\n" | ||
129 | |||
130 | if result == False: | ||
131 | tap += procout | ||
132 | |||
133 | prepare_env(tidx["teardown"]) | ||
134 | index += 1 | ||
135 | |||
136 | return tap | ||
137 | |||
138 | |||
139 | def ns_create(): | ||
140 | """ | ||
141 | Create the network namespace in which the tests will be run and set up | ||
142 | the required network devices for it. | ||
143 | """ | ||
144 | if (USE_NS): | ||
145 | cmd = 'ip netns add $NS' | ||
146 | exec_cmd(cmd, False) | ||
147 | cmd = 'ip link add $DEV0 type veth peer name $DEV1' | ||
148 | exec_cmd(cmd, False) | ||
149 | cmd = 'ip link set $DEV1 netns $NS' | ||
150 | exec_cmd(cmd, False) | ||
151 | cmd = 'ip link set $DEV0 up' | ||
152 | exec_cmd(cmd, False) | ||
153 | cmd = 'ip -s $NS link set $DEV1 up' | ||
154 | exec_cmd(cmd, False) | ||
155 | |||
156 | |||
157 | def ns_destroy(): | ||
158 | """ | ||
159 | Destroy the network namespace for testing (and any associated network | ||
160 | devices as well) | ||
161 | """ | ||
162 | if (USE_NS): | ||
163 | cmd = 'ip netns delete $NS' | ||
164 | exec_cmd(cmd, False) | ||
165 | |||
166 | |||
167 | def has_blank_ids(idlist): | ||
168 | """ | ||
169 | Search the list for empty ID fields and return true/false accordingly. | ||
170 | """ | ||
171 | return not(all(k for k in idlist)) | ||
172 | |||
173 | |||
174 | def load_from_file(filename): | ||
175 | """ | ||
176 | Open the JSON file containing the test cases and return them as an | ||
177 | ordered dictionary object. | ||
178 | """ | ||
179 | with open(filename) as test_data: | ||
180 | testlist = json.load(test_data, object_pairs_hook=OrderedDict) | ||
181 | idlist = get_id_list(testlist) | ||
182 | if (has_blank_ids(idlist)): | ||
183 | for k in testlist: | ||
184 | k['filename'] = filename | ||
185 | return testlist | ||
186 | |||
187 | |||
188 | def args_parse(): | ||
189 | """ | ||
190 | Create the argument parser. | ||
191 | """ | ||
192 | parser = argparse.ArgumentParser(description='Linux TC unit tests') | ||
193 | return parser | ||
194 | |||
195 | |||
196 | def set_args(parser): | ||
197 | """ | ||
198 | Set the command line arguments for tdc. | ||
199 | """ | ||
200 | parser.add_argument('-p', '--path', type=str, | ||
201 | help='The full path to the tc executable to use') | ||
202 | parser.add_argument('-c', '--category', type=str, nargs='?', const='+c', | ||
203 | help='Run tests only from the specified category, or if no category is specified, list known categories.') | ||
204 | parser.add_argument('-f', '--file', type=str, | ||
205 | help='Run tests from the specified file') | ||
206 | parser.add_argument('-l', '--list', type=str, nargs='?', const="", metavar='CATEGORY', | ||
207 | help='List all test cases, or those only within the specified category') | ||
208 | parser.add_argument('-s', '--show', type=str, nargs=1, metavar='ID', dest='showID', | ||
209 | help='Display the test case with specified id') | ||
210 | parser.add_argument('-e', '--execute', type=str, nargs=1, metavar='ID', | ||
211 | help='Execute the single test case with specified ID') | ||
212 | parser.add_argument('-i', '--id', action='store_true', dest='gen_id', | ||
213 | help='Generate ID numbers for new test cases') | ||
214 | return parser | ||
215 | return parser | ||
216 | |||
217 | |||
218 | def check_default_settings(args): | ||
219 | """ | ||
220 | Process any arguments overriding the default settings, and ensure the | ||
221 | settings are correct. | ||
222 | """ | ||
223 | # Allow for overriding specific settings | ||
224 | global NAMES | ||
225 | |||
226 | if args.path != None: | ||
227 | NAMES['TC'] = args.path | ||
228 | if not os.path.isfile(NAMES['TC']): | ||
229 | print("The specified tc path " + NAMES['TC'] + " does not exist.") | ||
230 | exit(1) | ||
231 | |||
232 | |||
233 | def get_id_list(alltests): | ||
234 | """ | ||
235 | Generate a list of all IDs in the test cases. | ||
236 | """ | ||
237 | return [x["id"] for x in alltests] | ||
238 | |||
239 | |||
240 | def check_case_id(alltests): | ||
241 | """ | ||
242 | Check for duplicate test case IDs. | ||
243 | """ | ||
244 | idl = get_id_list(alltests) | ||
245 | return [x for x in idl if idl.count(x) > 1] | ||
246 | |||
247 | |||
248 | def does_id_exist(alltests, newid): | ||
249 | """ | ||
250 | Check if a given ID already exists in the list of test cases. | ||
251 | """ | ||
252 | idl = get_id_list(alltests) | ||
253 | return (any(newid == x for x in idl)) | ||
254 | |||
255 | |||
256 | def generate_case_ids(alltests): | ||
257 | """ | ||
258 | If a test case has a blank ID field, generate a random hex ID for it | ||
259 | and then write the test cases back to disk. | ||
260 | """ | ||
261 | import random | ||
262 | for c in alltests: | ||
263 | if (c["id"] == ""): | ||
264 | while True: | ||
265 | newid = str('%04x' % random.randrange(16**4)) | ||
266 | if (does_id_exist(alltests, newid)): | ||
267 | continue | ||
268 | else: | ||
269 | c['id'] = newid | ||
270 | break | ||
271 | |||
272 | ufilename = [] | ||
273 | for c in alltests: | ||
274 | if ('filename' in c): | ||
275 | ufilename.append(c['filename']) | ||
276 | ufilename = get_unique_item(ufilename) | ||
277 | for f in ufilename: | ||
278 | testlist = [] | ||
279 | for t in alltests: | ||
280 | if 'filename' in t: | ||
281 | if t['filename'] == f: | ||
282 | del t['filename'] | ||
283 | testlist.append(t) | ||
284 | outfile = open(f, "w") | ||
285 | json.dump(testlist, outfile, indent=4) | ||
286 | outfile.close() | ||
287 | |||
288 | |||
289 | def get_test_cases(args): | ||
290 | """ | ||
291 | If a test case file is specified, retrieve tests from that file. | ||
292 | Otherwise, glob for all json files in subdirectories and load from | ||
293 | each one. | ||
294 | """ | ||
295 | import fnmatch | ||
296 | if args.file != None: | ||
297 | if not os.path.isfile(args.file): | ||
298 | print("The specified test case file " + args.file + " does not exist.") | ||
299 | exit(1) | ||
300 | flist = [args.file] | ||
301 | else: | ||
302 | flist = [] | ||
303 | for root, dirnames, filenames in os.walk('tc-tests'): | ||
304 | for filename in fnmatch.filter(filenames, '*.json'): | ||
305 | flist.append(os.path.join(root, filename)) | ||
306 | alltests = list() | ||
307 | for casefile in flist: | ||
308 | alltests = alltests + (load_from_file(casefile)) | ||
309 | return alltests | ||
310 | |||
311 | |||
312 | def set_operation_mode(args): | ||
313 | """ | ||
314 | Load the test case data and process remaining arguments to determine | ||
315 | what the script should do for this run, and call the appropriate | ||
316 | function. | ||
317 | """ | ||
318 | alltests = get_test_cases(args) | ||
319 | |||
320 | if args.gen_id: | ||
321 | idlist = get_id_list(alltests) | ||
322 | if (has_blank_ids(idlist)): | ||
323 | alltests = generate_case_ids(alltests) | ||
324 | else: | ||
325 | print("No empty ID fields found in test files.") | ||
326 | exit(0) | ||
327 | |||
328 | duplicate_ids = check_case_id(alltests) | ||
329 | if (len(duplicate_ids) > 0): | ||
330 | print("The following test case IDs are not unique:") | ||
331 | print(str(set(duplicate_ids))) | ||
332 | print("Please correct them before continuing.") | ||
333 | exit(1) | ||
334 | |||
335 | ucat = get_test_categories(alltests) | ||
336 | |||
337 | if args.showID: | ||
338 | show_test_case_by_id(alltests, args.showID[0]) | ||
339 | exit(0) | ||
340 | |||
341 | if args.execute: | ||
342 | target_id = args.execute[0] | ||
343 | else: | ||
344 | target_id = "" | ||
345 | |||
346 | if args.category: | ||
347 | if (args.category == '+c'): | ||
348 | print("Available categories:") | ||
349 | print_sll(ucat) | ||
350 | exit(0) | ||
351 | else: | ||
352 | target_category = args.category | ||
353 | else: | ||
354 | target_category = "" | ||
355 | |||
356 | |||
357 | testcases = get_categorized_testlist(alltests, ucat) | ||
358 | |||
359 | if args.list: | ||
360 | if (len(args.list) == 0): | ||
361 | list_test_cases(alltests) | ||
362 | exit(0) | ||
363 | elif(len(args.list > 0)): | ||
364 | if (args.list not in ucat): | ||
365 | print("Unknown category " + args.list) | ||
366 | print("Available categories:") | ||
367 | print_sll(ucat) | ||
368 | exit(1) | ||
369 | list_test_cases(testcases[args.list]) | ||
370 | exit(0) | ||
371 | |||
372 | if (os.geteuid() != 0): | ||
373 | print("This script must be run with root privileges.\n") | ||
374 | exit(1) | ||
375 | |||
376 | ns_create() | ||
377 | |||
378 | if (len(target_category) == 0): | ||
379 | if (len(target_id) > 0): | ||
380 | alltests = list(filter(lambda x: target_id in x['id'], alltests)) | ||
381 | if (len(alltests) == 0): | ||
382 | print("Cannot find a test case with ID matching " + target_id) | ||
383 | exit(1) | ||
384 | catresults = test_runner(alltests) | ||
385 | print("All test results: " + "\n\n" + catresults) | ||
386 | elif (len(target_category) > 0): | ||
387 | if (target_category not in ucat): | ||
388 | print("Specified category is not present in this file.") | ||
389 | exit(1) | ||
390 | else: | ||
391 | catresults = test_runner(testcases[target_category]) | ||
392 | print("Category " + target_category + "\n\n" + catresults) | ||
393 | |||
394 | ns_destroy() | ||
395 | |||
396 | |||
397 | def main(): | ||
398 | """ | ||
399 | Start of execution; set up argument parser and get the arguments, | ||
400 | and start operations. | ||
401 | """ | ||
402 | parser = args_parse() | ||
403 | parser = set_args(parser) | ||
404 | (args, remaining) = parser.parse_known_args() | ||
405 | check_default_settings(args) | ||
406 | |||
407 | set_operation_mode(args) | ||
408 | |||
409 | exit(0) | ||
410 | |||
411 | |||
412 | if __name__ == "__main__": | ||
413 | main() | ||
diff --git a/tools/testing/selftests/tc-testing/tdc_config.py b/tools/testing/selftests/tc-testing/tdc_config.py new file mode 100644 index 000000000000..01087375a7c3 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tdc_config.py | |||
@@ -0,0 +1,17 @@ | |||
1 | """ | ||
2 | tdc_config.py - tdc user-specified values | ||
3 | |||
4 | Copyright (C) 2017 Lucas Bates <lucasb@mojatatu.com> | ||
5 | """ | ||
6 | |||
7 | # Dictionary containing all values that can be substituted in executable | ||
8 | # commands. | ||
9 | NAMES = { | ||
10 | # Substitute your own tc path here | ||
11 | 'TC': '/sbin/tc', | ||
12 | # Name of veth devices to be created for the namespace | ||
13 | 'DEV0': 'v0p0', | ||
14 | 'DEV1': 'v0p1', | ||
15 | # Name of the namespace to use | ||
16 | 'NS': 'tcut' | ||
17 | } | ||
diff --git a/tools/testing/selftests/tc-testing/tdc_helper.py b/tools/testing/selftests/tc-testing/tdc_helper.py new file mode 100644 index 000000000000..c3254f861fb2 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tdc_helper.py | |||
@@ -0,0 +1,75 @@ | |||
1 | """ | ||
2 | tdc_helper.py - tdc helper functions | ||
3 | |||
4 | Copyright (C) 2017 Lucas Bates <lucasb@mojatatu.com> | ||
5 | """ | ||
6 | |||
7 | def get_categorized_testlist(alltests, ucat): | ||
8 | """ Sort the master test list into categories. """ | ||
9 | testcases = dict() | ||
10 | |||
11 | for category in ucat: | ||
12 | testcases[category] = list(filter(lambda x: category in x['category'], alltests)) | ||
13 | |||
14 | return(testcases) | ||
15 | |||
16 | |||
17 | def get_unique_item(lst): | ||
18 | """ For a list, return a set of the unique items in the list. """ | ||
19 | return list(set(lst)) | ||
20 | |||
21 | |||
22 | def get_test_categories(alltests): | ||
23 | """ Discover all unique test categories present in the test case file. """ | ||
24 | ucat = [] | ||
25 | for t in alltests: | ||
26 | ucat.extend(get_unique_item(t['category'])) | ||
27 | ucat = get_unique_item(ucat) | ||
28 | return ucat | ||
29 | |||
30 | def list_test_cases(testlist): | ||
31 | """ Print IDs and names of all test cases. """ | ||
32 | for curcase in testlist: | ||
33 | print(curcase['id'] + ': (' + ', '.join(curcase['category']) + ") " + curcase['name']) | ||
34 | |||
35 | |||
36 | def list_categories(testlist): | ||
37 | """ Show all categories that are present in a test case file. """ | ||
38 | categories = set(map(lambda x: x['category'], testlist)) | ||
39 | print("Available categories:") | ||
40 | print(", ".join(str(s) for s in categories)) | ||
41 | print("") | ||
42 | |||
43 | |||
44 | def print_list(cmdlist): | ||
45 | """ Print a list of strings prepended with a tab. """ | ||
46 | for l in cmdlist: | ||
47 | if (type(l) == list): | ||
48 | print("\t" + str(l[0])) | ||
49 | else: | ||
50 | print("\t" + str(l)) | ||
51 | |||
52 | |||
53 | def print_sll(items): | ||
54 | print("\n".join(str(s) for s in items)) | ||
55 | |||
56 | |||
57 | def print_test_case(tcase): | ||
58 | """ Pretty-printing of a given test case. """ | ||
59 | for k in tcase.keys(): | ||
60 | if (type(tcase[k]) == list): | ||
61 | print(k + ":") | ||
62 | print_list(tcase[k]) | ||
63 | else: | ||
64 | print(k + ": " + tcase[k]) | ||
65 | |||
66 | |||
67 | def show_test_case_by_id(testlist, caseID): | ||
68 | """ Find the specified test case to pretty-print. """ | ||
69 | if not any(d.get('id', None) == caseID for d in testlist): | ||
70 | print("That ID does not exist.") | ||
71 | exit(1) | ||
72 | else: | ||
73 | print_test_case(next((d for d in testlist if d['id'] == caseID))) | ||
74 | |||
75 | |||
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index 5fa1d7e9a915..5801bbefbe89 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | BUILD_FLAGS = -DKTEST | 1 | BUILD_FLAGS = -DKTEST |
2 | CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) | 2 | CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) |
3 | LDFLAGS += -lrt -lpthread | 3 | LDFLAGS += -lrt -lpthread -lm |
4 | 4 | ||
5 | # these are all "safe" tests that don't modify | 5 | # these are all "safe" tests that don't modify |
6 | # system time or require escalated privileges | 6 | # system time or require escalated privileges |
@@ -8,7 +8,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ | |||
8 | inconsistency-check raw_skew threadtest rtctest | 8 | inconsistency-check raw_skew threadtest rtctest |
9 | 9 | ||
10 | TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ | 10 | TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ |
11 | skew_consistency clocksource-switch leap-a-day \ | 11 | skew_consistency clocksource-switch freq-step leap-a-day \ |
12 | leapcrash set-tai set-2038 set-tz | 12 | leapcrash set-tai set-2038 set-tz |
13 | 13 | ||
14 | 14 | ||
@@ -24,6 +24,7 @@ run_destructive_tests: run_tests | |||
24 | ./change_skew | 24 | ./change_skew |
25 | ./skew_consistency | 25 | ./skew_consistency |
26 | ./clocksource-switch | 26 | ./clocksource-switch |
27 | ./freq-step | ||
27 | ./leap-a-day -s -i 10 | 28 | ./leap-a-day -s -i 10 |
28 | ./leapcrash | 29 | ./leapcrash |
29 | ./set-tz | 30 | ./set-tz |
diff --git a/tools/testing/selftests/timers/freq-step.c b/tools/testing/selftests/timers/freq-step.c new file mode 100644 index 000000000000..e8c61830825a --- /dev/null +++ b/tools/testing/selftests/timers/freq-step.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * This test checks the response of the system clock to frequency | ||
3 | * steps made with adjtimex(). The frequency error and stability of | ||
4 | * the CLOCK_MONOTONIC clock relative to the CLOCK_MONOTONIC_RAW clock | ||
5 | * is measured in two intervals following the step. The test fails if | ||
6 | * values from the second interval exceed specified limits. | ||
7 | * | ||
8 | * Copyright (C) Miroslav Lichvar <mlichvar@redhat.com> 2017 | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #include <math.h> | ||
21 | #include <stdio.h> | ||
22 | #include <sys/timex.h> | ||
23 | #include <time.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include "../kselftest.h" | ||
27 | |||
28 | #define SAMPLES 100 | ||
29 | #define SAMPLE_READINGS 10 | ||
30 | #define MEAN_SAMPLE_INTERVAL 0.1 | ||
31 | #define STEP_INTERVAL 1.0 | ||
32 | #define MAX_PRECISION 100e-9 | ||
33 | #define MAX_FREQ_ERROR 10e-6 | ||
34 | #define MAX_STDDEV 1000e-9 | ||
35 | |||
36 | struct sample { | ||
37 | double offset; | ||
38 | double time; | ||
39 | }; | ||
40 | |||
41 | static time_t mono_raw_base; | ||
42 | static time_t mono_base; | ||
43 | static long user_hz; | ||
44 | static double precision; | ||
45 | static double mono_freq_offset; | ||
46 | |||
47 | static double diff_timespec(struct timespec *ts1, struct timespec *ts2) | ||
48 | { | ||
49 | return ts1->tv_sec - ts2->tv_sec + (ts1->tv_nsec - ts2->tv_nsec) / 1e9; | ||
50 | } | ||
51 | |||
52 | static double get_sample(struct sample *sample) | ||
53 | { | ||
54 | double delay, mindelay = 0.0; | ||
55 | struct timespec ts1, ts2, ts3; | ||
56 | int i; | ||
57 | |||
58 | for (i = 0; i < SAMPLE_READINGS; i++) { | ||
59 | clock_gettime(CLOCK_MONOTONIC_RAW, &ts1); | ||
60 | clock_gettime(CLOCK_MONOTONIC, &ts2); | ||
61 | clock_gettime(CLOCK_MONOTONIC_RAW, &ts3); | ||
62 | |||
63 | ts1.tv_sec -= mono_raw_base; | ||
64 | ts2.tv_sec -= mono_base; | ||
65 | ts3.tv_sec -= mono_raw_base; | ||
66 | |||
67 | delay = diff_timespec(&ts3, &ts1); | ||
68 | if (delay <= 1e-9) { | ||
69 | i--; | ||
70 | continue; | ||
71 | } | ||
72 | |||
73 | if (!i || delay < mindelay) { | ||
74 | sample->offset = diff_timespec(&ts2, &ts1); | ||
75 | sample->offset -= delay / 2.0; | ||
76 | sample->time = ts1.tv_sec + ts1.tv_nsec / 1e9; | ||
77 | mindelay = delay; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | return mindelay; | ||
82 | } | ||
83 | |||
84 | static void reset_ntp_error(void) | ||
85 | { | ||
86 | struct timex txc; | ||
87 | |||
88 | txc.modes = ADJ_SETOFFSET; | ||
89 | txc.time.tv_sec = 0; | ||
90 | txc.time.tv_usec = 0; | ||
91 | |||
92 | if (adjtimex(&txc) < 0) { | ||
93 | perror("[FAIL] adjtimex"); | ||
94 | ksft_exit_fail(); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static void set_frequency(double freq) | ||
99 | { | ||
100 | struct timex txc; | ||
101 | int tick_offset; | ||
102 | |||
103 | tick_offset = 1e6 * freq / user_hz; | ||
104 | |||
105 | txc.modes = ADJ_TICK | ADJ_FREQUENCY; | ||
106 | txc.tick = 1000000 / user_hz + tick_offset; | ||
107 | txc.freq = (1e6 * freq - user_hz * tick_offset) * (1 << 16); | ||
108 | |||
109 | if (adjtimex(&txc) < 0) { | ||
110 | perror("[FAIL] adjtimex"); | ||
111 | ksft_exit_fail(); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void regress(struct sample *samples, int n, double *intercept, | ||
116 | double *slope, double *r_stddev, double *r_max) | ||
117 | { | ||
118 | double x, y, r, x_sum, y_sum, xy_sum, x2_sum, r2_sum; | ||
119 | int i; | ||
120 | |||
121 | x_sum = 0.0, y_sum = 0.0, xy_sum = 0.0, x2_sum = 0.0; | ||
122 | |||
123 | for (i = 0; i < n; i++) { | ||
124 | x = samples[i].time; | ||
125 | y = samples[i].offset; | ||
126 | |||
127 | x_sum += x; | ||
128 | y_sum += y; | ||
129 | xy_sum += x * y; | ||
130 | x2_sum += x * x; | ||
131 | } | ||
132 | |||
133 | *slope = (xy_sum - x_sum * y_sum / n) / (x2_sum - x_sum * x_sum / n); | ||
134 | *intercept = (y_sum - *slope * x_sum) / n; | ||
135 | |||
136 | *r_max = 0.0, r2_sum = 0.0; | ||
137 | |||
138 | for (i = 0; i < n; i++) { | ||
139 | x = samples[i].time; | ||
140 | y = samples[i].offset; | ||
141 | r = fabs(x * *slope + *intercept - y); | ||
142 | if (*r_max < r) | ||
143 | *r_max = r; | ||
144 | r2_sum += r * r; | ||
145 | } | ||
146 | |||
147 | *r_stddev = sqrt(r2_sum / n); | ||
148 | } | ||
149 | |||
150 | static int run_test(int calibration, double freq_base, double freq_step) | ||
151 | { | ||
152 | struct sample samples[SAMPLES]; | ||
153 | double intercept, slope, stddev1, max1, stddev2, max2; | ||
154 | double freq_error1, freq_error2; | ||
155 | int i; | ||
156 | |||
157 | set_frequency(freq_base); | ||
158 | |||
159 | for (i = 0; i < 10; i++) | ||
160 | usleep(1e6 * MEAN_SAMPLE_INTERVAL / 10); | ||
161 | |||
162 | reset_ntp_error(); | ||
163 | |||
164 | set_frequency(freq_base + freq_step); | ||
165 | |||
166 | for (i = 0; i < 10; i++) | ||
167 | usleep(rand() % 2000000 * STEP_INTERVAL / 10); | ||
168 | |||
169 | set_frequency(freq_base); | ||
170 | |||
171 | for (i = 0; i < SAMPLES; i++) { | ||
172 | usleep(rand() % 2000000 * MEAN_SAMPLE_INTERVAL); | ||
173 | get_sample(&samples[i]); | ||
174 | } | ||
175 | |||
176 | if (calibration) { | ||
177 | regress(samples, SAMPLES, &intercept, &slope, &stddev1, &max1); | ||
178 | mono_freq_offset = slope; | ||
179 | printf("CLOCK_MONOTONIC_RAW frequency offset: %11.3f ppm\n", | ||
180 | 1e6 * mono_freq_offset); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | regress(samples, SAMPLES / 2, &intercept, &slope, &stddev1, &max1); | ||
185 | freq_error1 = slope * (1.0 - mono_freq_offset) - mono_freq_offset - | ||
186 | freq_base; | ||
187 | |||
188 | regress(samples + SAMPLES / 2, SAMPLES / 2, &intercept, &slope, | ||
189 | &stddev2, &max2); | ||
190 | freq_error2 = slope * (1.0 - mono_freq_offset) - mono_freq_offset - | ||
191 | freq_base; | ||
192 | |||
193 | printf("%6.0f %+10.3f %6.0f %7.0f %+10.3f %6.0f %7.0f\t", | ||
194 | 1e6 * freq_step, | ||
195 | 1e6 * freq_error1, 1e9 * stddev1, 1e9 * max1, | ||
196 | 1e6 * freq_error2, 1e9 * stddev2, 1e9 * max2); | ||
197 | |||
198 | if (fabs(freq_error2) > MAX_FREQ_ERROR || stddev2 > MAX_STDDEV) { | ||
199 | printf("[FAIL]\n"); | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | printf("[OK]\n"); | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static void init_test(void) | ||
208 | { | ||
209 | struct timespec ts; | ||
210 | struct sample sample; | ||
211 | |||
212 | if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) { | ||
213 | perror("[FAIL] clock_gettime(CLOCK_MONOTONIC_RAW)"); | ||
214 | ksft_exit_fail(); | ||
215 | } | ||
216 | |||
217 | mono_raw_base = ts.tv_sec; | ||
218 | |||
219 | if (clock_gettime(CLOCK_MONOTONIC, &ts)) { | ||
220 | perror("[FAIL] clock_gettime(CLOCK_MONOTONIC)"); | ||
221 | ksft_exit_fail(); | ||
222 | } | ||
223 | |||
224 | mono_base = ts.tv_sec; | ||
225 | |||
226 | user_hz = sysconf(_SC_CLK_TCK); | ||
227 | |||
228 | precision = get_sample(&sample) / 2.0; | ||
229 | printf("CLOCK_MONOTONIC_RAW+CLOCK_MONOTONIC precision: %.0f ns\t\t", | ||
230 | 1e9 * precision); | ||
231 | |||
232 | if (precision > MAX_PRECISION) { | ||
233 | printf("[SKIP]\n"); | ||
234 | ksft_exit_skip(); | ||
235 | } | ||
236 | |||
237 | printf("[OK]\n"); | ||
238 | srand(ts.tv_sec ^ ts.tv_nsec); | ||
239 | |||
240 | run_test(1, 0.0, 0.0); | ||
241 | } | ||
242 | |||
243 | int main(int argc, char **argv) | ||
244 | { | ||
245 | double freq_base, freq_step; | ||
246 | int i, j, fails = 0; | ||
247 | |||
248 | init_test(); | ||
249 | |||
250 | printf("Checking response to frequency step:\n"); | ||
251 | printf(" Step 1st interval 2nd interval\n"); | ||
252 | printf(" Freq Dev Max Freq Dev Max\n"); | ||
253 | |||
254 | for (i = 2; i >= 0; i--) { | ||
255 | for (j = 0; j < 5; j++) { | ||
256 | freq_base = (rand() % (1 << 24) - (1 << 23)) / 65536e6; | ||
257 | freq_step = 10e-6 * (1 << (6 * i)); | ||
258 | fails += run_test(0, freq_base, freq_step); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | set_frequency(0.0); | ||
263 | |||
264 | if (fails) | ||
265 | ksft_exit_fail(); | ||
266 | |||
267 | ksft_exit_pass(); | ||
268 | } | ||
diff --git a/tools/testing/selftests/timers/inconsistency-check.c b/tools/testing/selftests/timers/inconsistency-check.c index caf1bc9257c4..74c60e8759a0 100644 --- a/tools/testing/selftests/timers/inconsistency-check.c +++ b/tools/testing/selftests/timers/inconsistency-check.c | |||
@@ -118,7 +118,7 @@ int consistency_test(int clock_type, unsigned long seconds) | |||
118 | start_str = ctime(&t); | 118 | start_str = ctime(&t); |
119 | 119 | ||
120 | while (seconds == -1 || now - then < seconds) { | 120 | while (seconds == -1 || now - then < seconds) { |
121 | inconsistent = 0; | 121 | inconsistent = -1; |
122 | 122 | ||
123 | /* Fill list */ | 123 | /* Fill list */ |
124 | for (i = 0; i < CALLS_PER_LOOP; i++) | 124 | for (i = 0; i < CALLS_PER_LOOP; i++) |
@@ -130,7 +130,7 @@ int consistency_test(int clock_type, unsigned long seconds) | |||
130 | inconsistent = i; | 130 | inconsistent = i; |
131 | 131 | ||
132 | /* display inconsistency */ | 132 | /* display inconsistency */ |
133 | if (inconsistent) { | 133 | if (inconsistent >= 0) { |
134 | unsigned long long delta; | 134 | unsigned long long delta; |
135 | 135 | ||
136 | printf("\%s\n", start_str); | 136 | printf("\%s\n", start_str); |
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index 0692d99b6d8f..2d89b5f686b1 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c | |||
@@ -387,15 +387,17 @@ int main (int argc, char **argv) | |||
387 | /* pick defaults that works with all speeds, without short packets. | 387 | /* pick defaults that works with all speeds, without short packets. |
388 | * | 388 | * |
389 | * Best per-frame data rates: | 389 | * Best per-frame data rates: |
390 | * high speed, bulk 512 * 13 * 8 = 53248 | 390 | * super speed,bulk 1024 * 16 * 8 = 131072 |
391 | * interrupt 1024 * 3 * 8 = 24576 | 391 | * interrupt 1024 * 3 * 8 = 24576 |
392 | * full speed, bulk/intr 64 * 19 = 1216 | 392 | * high speed, bulk 512 * 13 * 8 = 53248 |
393 | * interrupt 64 * 1 = 64 | 393 | * interrupt 1024 * 3 * 8 = 24576 |
394 | * low speed, interrupt 8 * 1 = 8 | 394 | * full speed, bulk/intr 64 * 19 = 1216 |
395 | * interrupt 64 * 1 = 64 | ||
396 | * low speed, interrupt 8 * 1 = 8 | ||
395 | */ | 397 | */ |
396 | param.iterations = 1000; | 398 | param.iterations = 1000; |
397 | param.length = 1024; | 399 | param.length = 1024; |
398 | param.vary = 512; | 400 | param.vary = 1024; |
399 | param.sglen = 32; | 401 | param.sglen = 32; |
400 | 402 | ||
401 | /* for easy use when hotplugging */ | 403 | /* for easy use when hotplugging */ |
@@ -457,7 +459,7 @@ usage: | |||
457 | "\t-c iterations default 1000\n" | 459 | "\t-c iterations default 1000\n" |
458 | "\t-s transfer length default 1024\n" | 460 | "\t-s transfer length default 1024\n" |
459 | "\t-g sglen default 32\n" | 461 | "\t-g sglen default 32\n" |
460 | "\t-v vary default 512\n", | 462 | "\t-v vary default 1024\n", |
461 | argv[0]); | 463 | argv[0]); |
462 | return 1; | 464 | return 1; |
463 | } | 465 | } |
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index f659c146cdc8..9bd2cd71645d 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <limits.h> | 7 | #include <limits.h> |
8 | #include <netdb.h> | 8 | #include <netdb.h> |
9 | #include <libudev.h> | 9 | #include <libudev.h> |
10 | #include <dirent.h> | ||
10 | #include "sysfs_utils.h" | 11 | #include "sysfs_utils.h" |
11 | 12 | ||
12 | #undef PROGNAME | 13 | #undef PROGNAME |
@@ -35,18 +36,11 @@ err: | |||
35 | return NULL; | 36 | return NULL; |
36 | } | 37 | } |
37 | 38 | ||
38 | |||
39 | |||
40 | static int parse_status(const char *value) | 39 | static int parse_status(const char *value) |
41 | { | 40 | { |
42 | int ret = 0; | 41 | int ret = 0; |
43 | char *c; | 42 | char *c; |
44 | 43 | ||
45 | |||
46 | for (int i = 0; i < vhci_driver->nports; i++) | ||
47 | memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i])); | ||
48 | |||
49 | |||
50 | /* skip a header line */ | 44 | /* skip a header line */ |
51 | c = strchr(value, '\n'); | 45 | c = strchr(value, '\n'); |
52 | if (!c) | 46 | if (!c) |
@@ -57,9 +51,11 @@ static int parse_status(const char *value) | |||
57 | int port, status, speed, devid; | 51 | int port, status, speed, devid; |
58 | unsigned long socket; | 52 | unsigned long socket; |
59 | char lbusid[SYSFS_BUS_ID_SIZE]; | 53 | char lbusid[SYSFS_BUS_ID_SIZE]; |
54 | struct usbip_imported_device *idev; | ||
55 | char hub[3]; | ||
60 | 56 | ||
61 | ret = sscanf(c, "%d %d %d %x %lx %31s\n", | 57 | ret = sscanf(c, "%2s %d %d %d %x %lx %31s\n", |
62 | &port, &status, &speed, | 58 | hub, &port, &status, &speed, |
63 | &devid, &socket, lbusid); | 59 | &devid, &socket, lbusid); |
64 | 60 | ||
65 | if (ret < 5) { | 61 | if (ret < 5) { |
@@ -67,34 +63,36 @@ static int parse_status(const char *value) | |||
67 | BUG(); | 63 | BUG(); |
68 | } | 64 | } |
69 | 65 | ||
70 | dbg("port %d status %d speed %d devid %x", | 66 | dbg("hub %s port %d status %d speed %d devid %x", |
71 | port, status, speed, devid); | 67 | hub, port, status, speed, devid); |
72 | dbg("socket %lx lbusid %s", socket, lbusid); | 68 | dbg("socket %lx lbusid %s", socket, lbusid); |
73 | 69 | ||
74 | |||
75 | /* if a device is connected, look at it */ | 70 | /* if a device is connected, look at it */ |
76 | { | 71 | idev = &vhci_driver->idev[port]; |
77 | struct usbip_imported_device *idev = &vhci_driver->idev[port]; | 72 | memset(idev, 0, sizeof(*idev)); |
73 | |||
74 | if (strncmp("hs", hub, 2) == 0) | ||
75 | idev->hub = HUB_SPEED_HIGH; | ||
76 | else /* strncmp("ss", hub, 2) == 0 */ | ||
77 | idev->hub = HUB_SPEED_SUPER; | ||
78 | 78 | ||
79 | idev->port = port; | 79 | idev->port = port; |
80 | idev->status = status; | 80 | idev->status = status; |
81 | 81 | ||
82 | idev->devid = devid; | 82 | idev->devid = devid; |
83 | 83 | ||
84 | idev->busnum = (devid >> 16); | 84 | idev->busnum = (devid >> 16); |
85 | idev->devnum = (devid & 0x0000ffff); | 85 | idev->devnum = (devid & 0x0000ffff); |
86 | 86 | ||
87 | if (idev->status != VDEV_ST_NULL | 87 | if (idev->status != VDEV_ST_NULL |
88 | && idev->status != VDEV_ST_NOTASSIGNED) { | 88 | && idev->status != VDEV_ST_NOTASSIGNED) { |
89 | idev = imported_device_init(idev, lbusid); | 89 | idev = imported_device_init(idev, lbusid); |
90 | if (!idev) { | 90 | if (!idev) { |
91 | dbg("imported_device_init failed"); | 91 | dbg("imported_device_init failed"); |
92 | return -1; | 92 | return -1; |
93 | } | ||
94 | } | 93 | } |
95 | } | 94 | } |
96 | 95 | ||
97 | |||
98 | /* go to the next line */ | 96 | /* go to the next line */ |
99 | c = strchr(c, '\n'); | 97 | c = strchr(c, '\n'); |
100 | if (!c) | 98 | if (!c) |
@@ -107,18 +105,33 @@ static int parse_status(const char *value) | |||
107 | return 0; | 105 | return 0; |
108 | } | 106 | } |
109 | 107 | ||
108 | #define MAX_STATUS_NAME 16 | ||
109 | |||
110 | static int refresh_imported_device_list(void) | 110 | static int refresh_imported_device_list(void) |
111 | { | 111 | { |
112 | const char *attr_status; | 112 | const char *attr_status; |
113 | char status[MAX_STATUS_NAME+1] = "status"; | ||
114 | int i, ret; | ||
113 | 115 | ||
114 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, | 116 | for (i = 0; i < vhci_driver->ncontrollers; i++) { |
115 | "status"); | 117 | if (i > 0) |
116 | if (!attr_status) { | 118 | snprintf(status, sizeof(status), "status.%d", i); |
117 | err("udev_device_get_sysattr_value failed"); | 119 | |
118 | return -1; | 120 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, |
121 | status); | ||
122 | if (!attr_status) { | ||
123 | err("udev_device_get_sysattr_value failed"); | ||
124 | return -1; | ||
125 | } | ||
126 | |||
127 | dbg("controller %d", i); | ||
128 | |||
129 | ret = parse_status(attr_status); | ||
130 | if (ret != 0) | ||
131 | return ret; | ||
119 | } | 132 | } |
120 | 133 | ||
121 | return parse_status(attr_status); | 134 | return 0; |
122 | } | 135 | } |
123 | 136 | ||
124 | static int get_nports(void) | 137 | static int get_nports(void) |
@@ -134,6 +147,33 @@ static int get_nports(void) | |||
134 | return (int)strtoul(attr_nports, NULL, 10); | 147 | return (int)strtoul(attr_nports, NULL, 10); |
135 | } | 148 | } |
136 | 149 | ||
150 | static int vhci_hcd_filter(const struct dirent *dirent) | ||
151 | { | ||
152 | return strcmp(dirent->d_name, "vhci_hcd") >= 0; | ||
153 | } | ||
154 | |||
155 | static int get_ncontrollers(void) | ||
156 | { | ||
157 | struct dirent **namelist; | ||
158 | struct udev_device *platform; | ||
159 | int n; | ||
160 | |||
161 | platform = udev_device_get_parent(vhci_driver->hc_device); | ||
162 | if (platform == NULL) | ||
163 | return -1; | ||
164 | |||
165 | n = scandir(udev_device_get_syspath(platform), &namelist, vhci_hcd_filter, NULL); | ||
166 | if (n < 0) | ||
167 | err("scandir failed"); | ||
168 | else { | ||
169 | for (int i = 0; i < n; i++) | ||
170 | free(namelist[i]); | ||
171 | free(namelist); | ||
172 | } | ||
173 | |||
174 | return n; | ||
175 | } | ||
176 | |||
137 | /* | 177 | /* |
138 | * Read the given port's record. | 178 | * Read the given port's record. |
139 | * | 179 | * |
@@ -213,16 +253,31 @@ int usbip_vhci_driver_open(void) | |||
213 | vhci_driver->hc_device = | 253 | vhci_driver->hc_device = |
214 | udev_device_new_from_subsystem_sysname(udev_context, | 254 | udev_device_new_from_subsystem_sysname(udev_context, |
215 | USBIP_VHCI_BUS_TYPE, | 255 | USBIP_VHCI_BUS_TYPE, |
216 | USBIP_VHCI_DRV_NAME); | 256 | USBIP_VHCI_DEVICE_NAME); |
217 | if (!vhci_driver->hc_device) { | 257 | if (!vhci_driver->hc_device) { |
218 | err("udev_device_new_from_subsystem_sysname failed"); | 258 | err("udev_device_new_from_subsystem_sysname failed"); |
219 | goto err; | 259 | goto err; |
220 | } | 260 | } |
221 | 261 | ||
222 | vhci_driver->nports = get_nports(); | 262 | vhci_driver->nports = get_nports(); |
223 | |||
224 | dbg("available ports: %d", vhci_driver->nports); | 263 | dbg("available ports: %d", vhci_driver->nports); |
225 | 264 | ||
265 | if (vhci_driver->nports <= 0) { | ||
266 | err("no available ports"); | ||
267 | goto err; | ||
268 | } else if (vhci_driver->nports > MAXNPORT) { | ||
269 | err("port number exceeds %d", MAXNPORT); | ||
270 | goto err; | ||
271 | } | ||
272 | |||
273 | vhci_driver->ncontrollers = get_ncontrollers(); | ||
274 | dbg("available controllers: %d", vhci_driver->ncontrollers); | ||
275 | |||
276 | if (vhci_driver->ncontrollers <=0) { | ||
277 | err("no available usb controllers"); | ||
278 | goto err; | ||
279 | } | ||
280 | |||
226 | if (refresh_imported_device_list()) | 281 | if (refresh_imported_device_list()) |
227 | goto err; | 282 | goto err; |
228 | 283 | ||
@@ -270,11 +325,15 @@ err: | |||
270 | } | 325 | } |
271 | 326 | ||
272 | 327 | ||
273 | int usbip_vhci_get_free_port(void) | 328 | int usbip_vhci_get_free_port(uint32_t speed) |
274 | { | 329 | { |
275 | for (int i = 0; i < vhci_driver->nports; i++) { | 330 | for (int i = 0; i < vhci_driver->nports; i++) { |
331 | if (speed == USB_SPEED_SUPER && | ||
332 | vhci_driver->idev[i].hub != HUB_SPEED_SUPER) | ||
333 | continue; | ||
334 | |||
276 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) | 335 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) |
277 | return i; | 336 | return vhci_driver->idev[i].port; |
278 | } | 337 | } |
279 | 338 | ||
280 | return -1; | 339 | return -1; |
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index fa2316cf2cac..4898d3bafb10 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h | |||
@@ -11,9 +11,16 @@ | |||
11 | #include "usbip_common.h" | 11 | #include "usbip_common.h" |
12 | 12 | ||
13 | #define USBIP_VHCI_BUS_TYPE "platform" | 13 | #define USBIP_VHCI_BUS_TYPE "platform" |
14 | #define USBIP_VHCI_DEVICE_NAME "vhci_hcd.0" | ||
14 | #define MAXNPORT 128 | 15 | #define MAXNPORT 128 |
15 | 16 | ||
17 | enum hub_speed { | ||
18 | HUB_SPEED_HIGH = 0, | ||
19 | HUB_SPEED_SUPER, | ||
20 | }; | ||
21 | |||
16 | struct usbip_imported_device { | 22 | struct usbip_imported_device { |
23 | enum hub_speed hub; | ||
17 | uint8_t port; | 24 | uint8_t port; |
18 | uint32_t status; | 25 | uint32_t status; |
19 | 26 | ||
@@ -31,6 +38,7 @@ struct usbip_vhci_driver { | |||
31 | /* /sys/devices/platform/vhci_hcd */ | 38 | /* /sys/devices/platform/vhci_hcd */ |
32 | struct udev_device *hc_device; | 39 | struct udev_device *hc_device; |
33 | 40 | ||
41 | int ncontrollers; | ||
34 | int nports; | 42 | int nports; |
35 | struct usbip_imported_device idev[MAXNPORT]; | 43 | struct usbip_imported_device idev[MAXNPORT]; |
36 | }; | 44 | }; |
@@ -44,7 +52,7 @@ void usbip_vhci_driver_close(void); | |||
44 | int usbip_vhci_refresh_device_list(void); | 52 | int usbip_vhci_refresh_device_list(void); |
45 | 53 | ||
46 | 54 | ||
47 | int usbip_vhci_get_free_port(void); | 55 | int usbip_vhci_get_free_port(uint32_t speed); |
48 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, | 56 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, |
49 | uint32_t speed); | 57 | uint32_t speed); |
50 | 58 | ||
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index 70a6b507fb62..6e89768ffe30 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c | |||
@@ -94,6 +94,7 @@ static int import_device(int sockfd, struct usbip_usb_device *udev) | |||
94 | { | 94 | { |
95 | int rc; | 95 | int rc; |
96 | int port; | 96 | int port; |
97 | uint32_t speed = udev->speed; | ||
97 | 98 | ||
98 | rc = usbip_vhci_driver_open(); | 99 | rc = usbip_vhci_driver_open(); |
99 | if (rc < 0) { | 100 | if (rc < 0) { |
@@ -101,13 +102,15 @@ static int import_device(int sockfd, struct usbip_usb_device *udev) | |||
101 | return -1; | 102 | return -1; |
102 | } | 103 | } |
103 | 104 | ||
104 | port = usbip_vhci_get_free_port(); | 105 | port = usbip_vhci_get_free_port(speed); |
105 | if (port < 0) { | 106 | if (port < 0) { |
106 | err("no free port"); | 107 | err("no free port"); |
107 | usbip_vhci_driver_close(); | 108 | usbip_vhci_driver_close(); |
108 | return -1; | 109 | return -1; |
109 | } | 110 | } |
110 | 111 | ||
112 | dbg("got free port %d", port); | ||
113 | |||
111 | rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, | 114 | rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, |
112 | udev->devnum, udev->speed); | 115 | udev->devnum, udev->speed); |
113 | if (rc < 0) { | 116 | if (rc < 0) { |