Commit 59b2858f57bbd42f36aa177d21ab011a87da3de2
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Ingo Molnar: "Mostly tooling fixes, but also two PMU driver fixes" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf tools powerpc: Use dwfl_report_elf() instead of offline. perf tools: Fix segfault for symbol annotation on TUI perf test: Fix dwarf unwind using libunwind. perf tools: Avoid build splat for syscall numbers with uclibc perf tools: Elide strlcpy warning with uclibc perf tools: Fix statfs.f_type data type mismatch build error with uclibc tools: Remove bitops/hweight usage of bits in tools/perf perf machine: Fix __machine__findnew_thread() error path perf tools: Fix building error in x86_64 when dwarf unwind is on perf probe: Propagate error code when write(2) failed perf/x86/intel: Fix bug for "cycles:p" and "cycles:pp" on SLM perf/rapl: Fix sysfs_show() initialization for RAPL PMU
Showing 26 changed files Inline Diff
- arch/x86/kernel/cpu/perf_event_intel_ds.c
- arch/x86/kernel/cpu/perf_event_intel_rapl.c
- tools/include/asm-generic/bitops.h
- tools/include/asm-generic/bitops/arch_hweight.h
- tools/include/asm-generic/bitops/const_hweight.h
- tools/include/asm-generic/bitops/hweight.h
- tools/include/linux/bitops.h
- tools/lib/api/fs/debugfs.c
- tools/lib/api/fs/fs.c
- tools/perf/MANIFEST
- tools/perf/Makefile.perf
- tools/perf/arch/powerpc/util/skip-callchain-idx.c
- tools/perf/bench/sched-pipe.c
- tools/perf/builtin-top.c
- tools/perf/config/Makefile
- tools/perf/config/Makefile.arch
- tools/perf/perf-sys.h
- tools/perf/tests/dwarf-unwind.c
- tools/perf/util/annotate.h
- tools/perf/util/cache.h
- tools/perf/util/hweight.c
- tools/perf/util/include/asm/hweight.h
- tools/perf/util/machine.c
- tools/perf/util/probe-event.c
- tools/perf/util/python-ext-sources
- tools/perf/util/unwind-libunwind.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
1 | #include <linux/bitops.h> | 1 | #include <linux/bitops.h> |
2 | #include <linux/types.h> | 2 | #include <linux/types.h> |
3 | #include <linux/slab.h> | 3 | #include <linux/slab.h> |
4 | 4 | ||
5 | #include <asm/perf_event.h> | 5 | #include <asm/perf_event.h> |
6 | #include <asm/insn.h> | 6 | #include <asm/insn.h> |
7 | 7 | ||
8 | #include "perf_event.h" | 8 | #include "perf_event.h" |
9 | 9 | ||
10 | /* The size of a BTS record in bytes: */ | 10 | /* The size of a BTS record in bytes: */ |
11 | #define BTS_RECORD_SIZE 24 | 11 | #define BTS_RECORD_SIZE 24 |
12 | 12 | ||
13 | #define BTS_BUFFER_SIZE (PAGE_SIZE << 4) | 13 | #define BTS_BUFFER_SIZE (PAGE_SIZE << 4) |
14 | #define PEBS_BUFFER_SIZE PAGE_SIZE | 14 | #define PEBS_BUFFER_SIZE PAGE_SIZE |
15 | #define PEBS_FIXUP_SIZE PAGE_SIZE | 15 | #define PEBS_FIXUP_SIZE PAGE_SIZE |
16 | 16 | ||
17 | /* | 17 | /* |
18 | * pebs_record_32 for p4 and core not supported | 18 | * pebs_record_32 for p4 and core not supported |
19 | 19 | ||
20 | struct pebs_record_32 { | 20 | struct pebs_record_32 { |
21 | u32 flags, ip; | 21 | u32 flags, ip; |
22 | u32 ax, bc, cx, dx; | 22 | u32 ax, bc, cx, dx; |
23 | u32 si, di, bp, sp; | 23 | u32 si, di, bp, sp; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | */ | 26 | */ |
27 | 27 | ||
28 | union intel_x86_pebs_dse { | 28 | union intel_x86_pebs_dse { |
29 | u64 val; | 29 | u64 val; |
30 | struct { | 30 | struct { |
31 | unsigned int ld_dse:4; | 31 | unsigned int ld_dse:4; |
32 | unsigned int ld_stlb_miss:1; | 32 | unsigned int ld_stlb_miss:1; |
33 | unsigned int ld_locked:1; | 33 | unsigned int ld_locked:1; |
34 | unsigned int ld_reserved:26; | 34 | unsigned int ld_reserved:26; |
35 | }; | 35 | }; |
36 | struct { | 36 | struct { |
37 | unsigned int st_l1d_hit:1; | 37 | unsigned int st_l1d_hit:1; |
38 | unsigned int st_reserved1:3; | 38 | unsigned int st_reserved1:3; |
39 | unsigned int st_stlb_miss:1; | 39 | unsigned int st_stlb_miss:1; |
40 | unsigned int st_locked:1; | 40 | unsigned int st_locked:1; |
41 | unsigned int st_reserved2:26; | 41 | unsigned int st_reserved2:26; |
42 | }; | 42 | }; |
43 | }; | 43 | }; |
44 | 44 | ||
45 | 45 | ||
46 | /* | 46 | /* |
47 | * Map PEBS Load Latency Data Source encodings to generic | 47 | * Map PEBS Load Latency Data Source encodings to generic |
48 | * memory data source information | 48 | * memory data source information |
49 | */ | 49 | */ |
50 | #define P(a, b) PERF_MEM_S(a, b) | 50 | #define P(a, b) PERF_MEM_S(a, b) |
51 | #define OP_LH (P(OP, LOAD) | P(LVL, HIT)) | 51 | #define OP_LH (P(OP, LOAD) | P(LVL, HIT)) |
52 | #define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS)) | 52 | #define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS)) |
53 | 53 | ||
54 | static const u64 pebs_data_source[] = { | 54 | static const u64 pebs_data_source[] = { |
55 | P(OP, LOAD) | P(LVL, MISS) | P(LVL, L3) | P(SNOOP, NA),/* 0x00:ukn L3 */ | 55 | P(OP, LOAD) | P(LVL, MISS) | P(LVL, L3) | P(SNOOP, NA),/* 0x00:ukn L3 */ |
56 | OP_LH | P(LVL, L1) | P(SNOOP, NONE), /* 0x01: L1 local */ | 56 | OP_LH | P(LVL, L1) | P(SNOOP, NONE), /* 0x01: L1 local */ |
57 | OP_LH | P(LVL, LFB) | P(SNOOP, NONE), /* 0x02: LFB hit */ | 57 | OP_LH | P(LVL, LFB) | P(SNOOP, NONE), /* 0x02: LFB hit */ |
58 | OP_LH | P(LVL, L2) | P(SNOOP, NONE), /* 0x03: L2 hit */ | 58 | OP_LH | P(LVL, L2) | P(SNOOP, NONE), /* 0x03: L2 hit */ |
59 | OP_LH | P(LVL, L3) | P(SNOOP, NONE), /* 0x04: L3 hit */ | 59 | OP_LH | P(LVL, L3) | P(SNOOP, NONE), /* 0x04: L3 hit */ |
60 | OP_LH | P(LVL, L3) | P(SNOOP, MISS), /* 0x05: L3 hit, snoop miss */ | 60 | OP_LH | P(LVL, L3) | P(SNOOP, MISS), /* 0x05: L3 hit, snoop miss */ |
61 | OP_LH | P(LVL, L3) | P(SNOOP, HIT), /* 0x06: L3 hit, snoop hit */ | 61 | OP_LH | P(LVL, L3) | P(SNOOP, HIT), /* 0x06: L3 hit, snoop hit */ |
62 | OP_LH | P(LVL, L3) | P(SNOOP, HITM), /* 0x07: L3 hit, snoop hitm */ | 62 | OP_LH | P(LVL, L3) | P(SNOOP, HITM), /* 0x07: L3 hit, snoop hitm */ |
63 | OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HIT), /* 0x08: L3 miss snoop hit */ | 63 | OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HIT), /* 0x08: L3 miss snoop hit */ |
64 | OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HITM), /* 0x09: L3 miss snoop hitm*/ | 64 | OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HITM), /* 0x09: L3 miss snoop hitm*/ |
65 | OP_LH | P(LVL, LOC_RAM) | P(SNOOP, HIT), /* 0x0a: L3 miss, shared */ | 65 | OP_LH | P(LVL, LOC_RAM) | P(SNOOP, HIT), /* 0x0a: L3 miss, shared */ |
66 | OP_LH | P(LVL, REM_RAM1) | P(SNOOP, HIT), /* 0x0b: L3 miss, shared */ | 66 | OP_LH | P(LVL, REM_RAM1) | P(SNOOP, HIT), /* 0x0b: L3 miss, shared */ |
67 | OP_LH | P(LVL, LOC_RAM) | SNOOP_NONE_MISS,/* 0x0c: L3 miss, excl */ | 67 | OP_LH | P(LVL, LOC_RAM) | SNOOP_NONE_MISS,/* 0x0c: L3 miss, excl */ |
68 | OP_LH | P(LVL, REM_RAM1) | SNOOP_NONE_MISS,/* 0x0d: L3 miss, excl */ | 68 | OP_LH | P(LVL, REM_RAM1) | SNOOP_NONE_MISS,/* 0x0d: L3 miss, excl */ |
69 | OP_LH | P(LVL, IO) | P(SNOOP, NONE), /* 0x0e: I/O */ | 69 | OP_LH | P(LVL, IO) | P(SNOOP, NONE), /* 0x0e: I/O */ |
70 | OP_LH | P(LVL, UNC) | P(SNOOP, NONE), /* 0x0f: uncached */ | 70 | OP_LH | P(LVL, UNC) | P(SNOOP, NONE), /* 0x0f: uncached */ |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static u64 precise_store_data(u64 status) | 73 | static u64 precise_store_data(u64 status) |
74 | { | 74 | { |
75 | union intel_x86_pebs_dse dse; | 75 | union intel_x86_pebs_dse dse; |
76 | u64 val = P(OP, STORE) | P(SNOOP, NA) | P(LVL, L1) | P(TLB, L2); | 76 | u64 val = P(OP, STORE) | P(SNOOP, NA) | P(LVL, L1) | P(TLB, L2); |
77 | 77 | ||
78 | dse.val = status; | 78 | dse.val = status; |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * bit 4: TLB access | 81 | * bit 4: TLB access |
82 | * 1 = stored missed 2nd level TLB | 82 | * 1 = stored missed 2nd level TLB |
83 | * | 83 | * |
84 | * so it either hit the walker or the OS | 84 | * so it either hit the walker or the OS |
85 | * otherwise hit 2nd level TLB | 85 | * otherwise hit 2nd level TLB |
86 | */ | 86 | */ |
87 | if (dse.st_stlb_miss) | 87 | if (dse.st_stlb_miss) |
88 | val |= P(TLB, MISS); | 88 | val |= P(TLB, MISS); |
89 | else | 89 | else |
90 | val |= P(TLB, HIT); | 90 | val |= P(TLB, HIT); |
91 | 91 | ||
92 | /* | 92 | /* |
93 | * bit 0: hit L1 data cache | 93 | * bit 0: hit L1 data cache |
94 | * if not set, then all we know is that | 94 | * if not set, then all we know is that |
95 | * it missed L1D | 95 | * it missed L1D |
96 | */ | 96 | */ |
97 | if (dse.st_l1d_hit) | 97 | if (dse.st_l1d_hit) |
98 | val |= P(LVL, HIT); | 98 | val |= P(LVL, HIT); |
99 | else | 99 | else |
100 | val |= P(LVL, MISS); | 100 | val |= P(LVL, MISS); |
101 | 101 | ||
102 | /* | 102 | /* |
103 | * bit 5: Locked prefix | 103 | * bit 5: Locked prefix |
104 | */ | 104 | */ |
105 | if (dse.st_locked) | 105 | if (dse.st_locked) |
106 | val |= P(LOCK, LOCKED); | 106 | val |= P(LOCK, LOCKED); |
107 | 107 | ||
108 | return val; | 108 | return val; |
109 | } | 109 | } |
110 | 110 | ||
111 | static u64 precise_datala_hsw(struct perf_event *event, u64 status) | 111 | static u64 precise_datala_hsw(struct perf_event *event, u64 status) |
112 | { | 112 | { |
113 | union perf_mem_data_src dse; | 113 | union perf_mem_data_src dse; |
114 | 114 | ||
115 | dse.val = PERF_MEM_NA; | 115 | dse.val = PERF_MEM_NA; |
116 | 116 | ||
117 | if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) | 117 | if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) |
118 | dse.mem_op = PERF_MEM_OP_STORE; | 118 | dse.mem_op = PERF_MEM_OP_STORE; |
119 | else if (event->hw.flags & PERF_X86_EVENT_PEBS_LD_HSW) | 119 | else if (event->hw.flags & PERF_X86_EVENT_PEBS_LD_HSW) |
120 | dse.mem_op = PERF_MEM_OP_LOAD; | 120 | dse.mem_op = PERF_MEM_OP_LOAD; |
121 | 121 | ||
122 | /* | 122 | /* |
123 | * L1 info only valid for following events: | 123 | * L1 info only valid for following events: |
124 | * | 124 | * |
125 | * MEM_UOPS_RETIRED.STLB_MISS_STORES | 125 | * MEM_UOPS_RETIRED.STLB_MISS_STORES |
126 | * MEM_UOPS_RETIRED.LOCK_STORES | 126 | * MEM_UOPS_RETIRED.LOCK_STORES |
127 | * MEM_UOPS_RETIRED.SPLIT_STORES | 127 | * MEM_UOPS_RETIRED.SPLIT_STORES |
128 | * MEM_UOPS_RETIRED.ALL_STORES | 128 | * MEM_UOPS_RETIRED.ALL_STORES |
129 | */ | 129 | */ |
130 | if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) { | 130 | if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) { |
131 | if (status & 1) | 131 | if (status & 1) |
132 | dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; | 132 | dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; |
133 | else | 133 | else |
134 | dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS; | 134 | dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS; |
135 | } | 135 | } |
136 | return dse.val; | 136 | return dse.val; |
137 | } | 137 | } |
138 | 138 | ||
139 | static u64 load_latency_data(u64 status) | 139 | static u64 load_latency_data(u64 status) |
140 | { | 140 | { |
141 | union intel_x86_pebs_dse dse; | 141 | union intel_x86_pebs_dse dse; |
142 | u64 val; | 142 | u64 val; |
143 | int model = boot_cpu_data.x86_model; | 143 | int model = boot_cpu_data.x86_model; |
144 | int fam = boot_cpu_data.x86; | 144 | int fam = boot_cpu_data.x86; |
145 | 145 | ||
146 | dse.val = status; | 146 | dse.val = status; |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * use the mapping table for bit 0-3 | 149 | * use the mapping table for bit 0-3 |
150 | */ | 150 | */ |
151 | val = pebs_data_source[dse.ld_dse]; | 151 | val = pebs_data_source[dse.ld_dse]; |
152 | 152 | ||
153 | /* | 153 | /* |
154 | * Nehalem models do not support TLB, Lock infos | 154 | * Nehalem models do not support TLB, Lock infos |
155 | */ | 155 | */ |
156 | if (fam == 0x6 && (model == 26 || model == 30 | 156 | if (fam == 0x6 && (model == 26 || model == 30 |
157 | || model == 31 || model == 46)) { | 157 | || model == 31 || model == 46)) { |
158 | val |= P(TLB, NA) | P(LOCK, NA); | 158 | val |= P(TLB, NA) | P(LOCK, NA); |
159 | return val; | 159 | return val; |
160 | } | 160 | } |
161 | /* | 161 | /* |
162 | * bit 4: TLB access | 162 | * bit 4: TLB access |
163 | * 0 = did not miss 2nd level TLB | 163 | * 0 = did not miss 2nd level TLB |
164 | * 1 = missed 2nd level TLB | 164 | * 1 = missed 2nd level TLB |
165 | */ | 165 | */ |
166 | if (dse.ld_stlb_miss) | 166 | if (dse.ld_stlb_miss) |
167 | val |= P(TLB, MISS) | P(TLB, L2); | 167 | val |= P(TLB, MISS) | P(TLB, L2); |
168 | else | 168 | else |
169 | val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2); | 169 | val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2); |
170 | 170 | ||
171 | /* | 171 | /* |
172 | * bit 5: locked prefix | 172 | * bit 5: locked prefix |
173 | */ | 173 | */ |
174 | if (dse.ld_locked) | 174 | if (dse.ld_locked) |
175 | val |= P(LOCK, LOCKED); | 175 | val |= P(LOCK, LOCKED); |
176 | 176 | ||
177 | return val; | 177 | return val; |
178 | } | 178 | } |
179 | 179 | ||
180 | struct pebs_record_core { | 180 | struct pebs_record_core { |
181 | u64 flags, ip; | 181 | u64 flags, ip; |
182 | u64 ax, bx, cx, dx; | 182 | u64 ax, bx, cx, dx; |
183 | u64 si, di, bp, sp; | 183 | u64 si, di, bp, sp; |
184 | u64 r8, r9, r10, r11; | 184 | u64 r8, r9, r10, r11; |
185 | u64 r12, r13, r14, r15; | 185 | u64 r12, r13, r14, r15; |
186 | }; | 186 | }; |
187 | 187 | ||
188 | struct pebs_record_nhm { | 188 | struct pebs_record_nhm { |
189 | u64 flags, ip; | 189 | u64 flags, ip; |
190 | u64 ax, bx, cx, dx; | 190 | u64 ax, bx, cx, dx; |
191 | u64 si, di, bp, sp; | 191 | u64 si, di, bp, sp; |
192 | u64 r8, r9, r10, r11; | 192 | u64 r8, r9, r10, r11; |
193 | u64 r12, r13, r14, r15; | 193 | u64 r12, r13, r14, r15; |
194 | u64 status, dla, dse, lat; | 194 | u64 status, dla, dse, lat; |
195 | }; | 195 | }; |
196 | 196 | ||
197 | /* | 197 | /* |
198 | * Same as pebs_record_nhm, with two additional fields. | 198 | * Same as pebs_record_nhm, with two additional fields. |
199 | */ | 199 | */ |
200 | struct pebs_record_hsw { | 200 | struct pebs_record_hsw { |
201 | u64 flags, ip; | 201 | u64 flags, ip; |
202 | u64 ax, bx, cx, dx; | 202 | u64 ax, bx, cx, dx; |
203 | u64 si, di, bp, sp; | 203 | u64 si, di, bp, sp; |
204 | u64 r8, r9, r10, r11; | 204 | u64 r8, r9, r10, r11; |
205 | u64 r12, r13, r14, r15; | 205 | u64 r12, r13, r14, r15; |
206 | u64 status, dla, dse, lat; | 206 | u64 status, dla, dse, lat; |
207 | u64 real_ip, tsx_tuning; | 207 | u64 real_ip, tsx_tuning; |
208 | }; | 208 | }; |
209 | 209 | ||
210 | union hsw_tsx_tuning { | 210 | union hsw_tsx_tuning { |
211 | struct { | 211 | struct { |
212 | u32 cycles_last_block : 32, | 212 | u32 cycles_last_block : 32, |
213 | hle_abort : 1, | 213 | hle_abort : 1, |
214 | rtm_abort : 1, | 214 | rtm_abort : 1, |
215 | instruction_abort : 1, | 215 | instruction_abort : 1, |
216 | non_instruction_abort : 1, | 216 | non_instruction_abort : 1, |
217 | retry : 1, | 217 | retry : 1, |
218 | data_conflict : 1, | 218 | data_conflict : 1, |
219 | capacity_writes : 1, | 219 | capacity_writes : 1, |
220 | capacity_reads : 1; | 220 | capacity_reads : 1; |
221 | }; | 221 | }; |
222 | u64 value; | 222 | u64 value; |
223 | }; | 223 | }; |
224 | 224 | ||
225 | #define PEBS_HSW_TSX_FLAGS 0xff00000000ULL | 225 | #define PEBS_HSW_TSX_FLAGS 0xff00000000ULL |
226 | 226 | ||
227 | void init_debug_store_on_cpu(int cpu) | 227 | void init_debug_store_on_cpu(int cpu) |
228 | { | 228 | { |
229 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; | 229 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
230 | 230 | ||
231 | if (!ds) | 231 | if (!ds) |
232 | return; | 232 | return; |
233 | 233 | ||
234 | wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, | 234 | wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, |
235 | (u32)((u64)(unsigned long)ds), | 235 | (u32)((u64)(unsigned long)ds), |
236 | (u32)((u64)(unsigned long)ds >> 32)); | 236 | (u32)((u64)(unsigned long)ds >> 32)); |
237 | } | 237 | } |
238 | 238 | ||
239 | void fini_debug_store_on_cpu(int cpu) | 239 | void fini_debug_store_on_cpu(int cpu) |
240 | { | 240 | { |
241 | if (!per_cpu(cpu_hw_events, cpu).ds) | 241 | if (!per_cpu(cpu_hw_events, cpu).ds) |
242 | return; | 242 | return; |
243 | 243 | ||
244 | wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0); | 244 | wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0); |
245 | } | 245 | } |
246 | 246 | ||
247 | static DEFINE_PER_CPU(void *, insn_buffer); | 247 | static DEFINE_PER_CPU(void *, insn_buffer); |
248 | 248 | ||
249 | static int alloc_pebs_buffer(int cpu) | 249 | static int alloc_pebs_buffer(int cpu) |
250 | { | 250 | { |
251 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; | 251 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
252 | int node = cpu_to_node(cpu); | 252 | int node = cpu_to_node(cpu); |
253 | int max, thresh = 1; /* always use a single PEBS record */ | 253 | int max, thresh = 1; /* always use a single PEBS record */ |
254 | void *buffer, *ibuffer; | 254 | void *buffer, *ibuffer; |
255 | 255 | ||
256 | if (!x86_pmu.pebs) | 256 | if (!x86_pmu.pebs) |
257 | return 0; | 257 | return 0; |
258 | 258 | ||
259 | buffer = kzalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL, node); | 259 | buffer = kzalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL, node); |
260 | if (unlikely(!buffer)) | 260 | if (unlikely(!buffer)) |
261 | return -ENOMEM; | 261 | return -ENOMEM; |
262 | 262 | ||
263 | /* | 263 | /* |
264 | * HSW+ already provides us the eventing ip; no need to allocate this | 264 | * HSW+ already provides us the eventing ip; no need to allocate this |
265 | * buffer then. | 265 | * buffer then. |
266 | */ | 266 | */ |
267 | if (x86_pmu.intel_cap.pebs_format < 2) { | 267 | if (x86_pmu.intel_cap.pebs_format < 2) { |
268 | ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node); | 268 | ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node); |
269 | if (!ibuffer) { | 269 | if (!ibuffer) { |
270 | kfree(buffer); | 270 | kfree(buffer); |
271 | return -ENOMEM; | 271 | return -ENOMEM; |
272 | } | 272 | } |
273 | per_cpu(insn_buffer, cpu) = ibuffer; | 273 | per_cpu(insn_buffer, cpu) = ibuffer; |
274 | } | 274 | } |
275 | 275 | ||
276 | max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size; | 276 | max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size; |
277 | 277 | ||
278 | ds->pebs_buffer_base = (u64)(unsigned long)buffer; | 278 | ds->pebs_buffer_base = (u64)(unsigned long)buffer; |
279 | ds->pebs_index = ds->pebs_buffer_base; | 279 | ds->pebs_index = ds->pebs_buffer_base; |
280 | ds->pebs_absolute_maximum = ds->pebs_buffer_base + | 280 | ds->pebs_absolute_maximum = ds->pebs_buffer_base + |
281 | max * x86_pmu.pebs_record_size; | 281 | max * x86_pmu.pebs_record_size; |
282 | 282 | ||
283 | ds->pebs_interrupt_threshold = ds->pebs_buffer_base + | 283 | ds->pebs_interrupt_threshold = ds->pebs_buffer_base + |
284 | thresh * x86_pmu.pebs_record_size; | 284 | thresh * x86_pmu.pebs_record_size; |
285 | 285 | ||
286 | return 0; | 286 | return 0; |
287 | } | 287 | } |
288 | 288 | ||
289 | static void release_pebs_buffer(int cpu) | 289 | static void release_pebs_buffer(int cpu) |
290 | { | 290 | { |
291 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; | 291 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
292 | 292 | ||
293 | if (!ds || !x86_pmu.pebs) | 293 | if (!ds || !x86_pmu.pebs) |
294 | return; | 294 | return; |
295 | 295 | ||
296 | kfree(per_cpu(insn_buffer, cpu)); | 296 | kfree(per_cpu(insn_buffer, cpu)); |
297 | per_cpu(insn_buffer, cpu) = NULL; | 297 | per_cpu(insn_buffer, cpu) = NULL; |
298 | 298 | ||
299 | kfree((void *)(unsigned long)ds->pebs_buffer_base); | 299 | kfree((void *)(unsigned long)ds->pebs_buffer_base); |
300 | ds->pebs_buffer_base = 0; | 300 | ds->pebs_buffer_base = 0; |
301 | } | 301 | } |
302 | 302 | ||
303 | static int alloc_bts_buffer(int cpu) | 303 | static int alloc_bts_buffer(int cpu) |
304 | { | 304 | { |
305 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; | 305 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
306 | int node = cpu_to_node(cpu); | 306 | int node = cpu_to_node(cpu); |
307 | int max, thresh; | 307 | int max, thresh; |
308 | void *buffer; | 308 | void *buffer; |
309 | 309 | ||
310 | if (!x86_pmu.bts) | 310 | if (!x86_pmu.bts) |
311 | return 0; | 311 | return 0; |
312 | 312 | ||
313 | buffer = kzalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_NOWARN, node); | 313 | buffer = kzalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_NOWARN, node); |
314 | if (unlikely(!buffer)) { | 314 | if (unlikely(!buffer)) { |
315 | WARN_ONCE(1, "%s: BTS buffer allocation failure\n", __func__); | 315 | WARN_ONCE(1, "%s: BTS buffer allocation failure\n", __func__); |
316 | return -ENOMEM; | 316 | return -ENOMEM; |
317 | } | 317 | } |
318 | 318 | ||
319 | max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE; | 319 | max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE; |
320 | thresh = max / 16; | 320 | thresh = max / 16; |
321 | 321 | ||
322 | ds->bts_buffer_base = (u64)(unsigned long)buffer; | 322 | ds->bts_buffer_base = (u64)(unsigned long)buffer; |
323 | ds->bts_index = ds->bts_buffer_base; | 323 | ds->bts_index = ds->bts_buffer_base; |
324 | ds->bts_absolute_maximum = ds->bts_buffer_base + | 324 | ds->bts_absolute_maximum = ds->bts_buffer_base + |
325 | max * BTS_RECORD_SIZE; | 325 | max * BTS_RECORD_SIZE; |
326 | ds->bts_interrupt_threshold = ds->bts_absolute_maximum - | 326 | ds->bts_interrupt_threshold = ds->bts_absolute_maximum - |
327 | thresh * BTS_RECORD_SIZE; | 327 | thresh * BTS_RECORD_SIZE; |
328 | 328 | ||
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | 331 | ||
332 | static void release_bts_buffer(int cpu) | 332 | static void release_bts_buffer(int cpu) |
333 | { | 333 | { |
334 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; | 334 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
335 | 335 | ||
336 | if (!ds || !x86_pmu.bts) | 336 | if (!ds || !x86_pmu.bts) |
337 | return; | 337 | return; |
338 | 338 | ||
339 | kfree((void *)(unsigned long)ds->bts_buffer_base); | 339 | kfree((void *)(unsigned long)ds->bts_buffer_base); |
340 | ds->bts_buffer_base = 0; | 340 | ds->bts_buffer_base = 0; |
341 | } | 341 | } |
342 | 342 | ||
343 | static int alloc_ds_buffer(int cpu) | 343 | static int alloc_ds_buffer(int cpu) |
344 | { | 344 | { |
345 | int node = cpu_to_node(cpu); | 345 | int node = cpu_to_node(cpu); |
346 | struct debug_store *ds; | 346 | struct debug_store *ds; |
347 | 347 | ||
348 | ds = kzalloc_node(sizeof(*ds), GFP_KERNEL, node); | 348 | ds = kzalloc_node(sizeof(*ds), GFP_KERNEL, node); |
349 | if (unlikely(!ds)) | 349 | if (unlikely(!ds)) |
350 | return -ENOMEM; | 350 | return -ENOMEM; |
351 | 351 | ||
352 | per_cpu(cpu_hw_events, cpu).ds = ds; | 352 | per_cpu(cpu_hw_events, cpu).ds = ds; |
353 | 353 | ||
354 | return 0; | 354 | return 0; |
355 | } | 355 | } |
356 | 356 | ||
357 | static void release_ds_buffer(int cpu) | 357 | static void release_ds_buffer(int cpu) |
358 | { | 358 | { |
359 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; | 359 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
360 | 360 | ||
361 | if (!ds) | 361 | if (!ds) |
362 | return; | 362 | return; |
363 | 363 | ||
364 | per_cpu(cpu_hw_events, cpu).ds = NULL; | 364 | per_cpu(cpu_hw_events, cpu).ds = NULL; |
365 | kfree(ds); | 365 | kfree(ds); |
366 | } | 366 | } |
367 | 367 | ||
368 | void release_ds_buffers(void) | 368 | void release_ds_buffers(void) |
369 | { | 369 | { |
370 | int cpu; | 370 | int cpu; |
371 | 371 | ||
372 | if (!x86_pmu.bts && !x86_pmu.pebs) | 372 | if (!x86_pmu.bts && !x86_pmu.pebs) |
373 | return; | 373 | return; |
374 | 374 | ||
375 | get_online_cpus(); | 375 | get_online_cpus(); |
376 | for_each_online_cpu(cpu) | 376 | for_each_online_cpu(cpu) |
377 | fini_debug_store_on_cpu(cpu); | 377 | fini_debug_store_on_cpu(cpu); |
378 | 378 | ||
379 | for_each_possible_cpu(cpu) { | 379 | for_each_possible_cpu(cpu) { |
380 | release_pebs_buffer(cpu); | 380 | release_pebs_buffer(cpu); |
381 | release_bts_buffer(cpu); | 381 | release_bts_buffer(cpu); |
382 | release_ds_buffer(cpu); | 382 | release_ds_buffer(cpu); |
383 | } | 383 | } |
384 | put_online_cpus(); | 384 | put_online_cpus(); |
385 | } | 385 | } |
386 | 386 | ||
387 | void reserve_ds_buffers(void) | 387 | void reserve_ds_buffers(void) |
388 | { | 388 | { |
389 | int bts_err = 0, pebs_err = 0; | 389 | int bts_err = 0, pebs_err = 0; |
390 | int cpu; | 390 | int cpu; |
391 | 391 | ||
392 | x86_pmu.bts_active = 0; | 392 | x86_pmu.bts_active = 0; |
393 | x86_pmu.pebs_active = 0; | 393 | x86_pmu.pebs_active = 0; |
394 | 394 | ||
395 | if (!x86_pmu.bts && !x86_pmu.pebs) | 395 | if (!x86_pmu.bts && !x86_pmu.pebs) |
396 | return; | 396 | return; |
397 | 397 | ||
398 | if (!x86_pmu.bts) | 398 | if (!x86_pmu.bts) |
399 | bts_err = 1; | 399 | bts_err = 1; |
400 | 400 | ||
401 | if (!x86_pmu.pebs) | 401 | if (!x86_pmu.pebs) |
402 | pebs_err = 1; | 402 | pebs_err = 1; |
403 | 403 | ||
404 | get_online_cpus(); | 404 | get_online_cpus(); |
405 | 405 | ||
406 | for_each_possible_cpu(cpu) { | 406 | for_each_possible_cpu(cpu) { |
407 | if (alloc_ds_buffer(cpu)) { | 407 | if (alloc_ds_buffer(cpu)) { |
408 | bts_err = 1; | 408 | bts_err = 1; |
409 | pebs_err = 1; | 409 | pebs_err = 1; |
410 | } | 410 | } |
411 | 411 | ||
412 | if (!bts_err && alloc_bts_buffer(cpu)) | 412 | if (!bts_err && alloc_bts_buffer(cpu)) |
413 | bts_err = 1; | 413 | bts_err = 1; |
414 | 414 | ||
415 | if (!pebs_err && alloc_pebs_buffer(cpu)) | 415 | if (!pebs_err && alloc_pebs_buffer(cpu)) |
416 | pebs_err = 1; | 416 | pebs_err = 1; |
417 | 417 | ||
418 | if (bts_err && pebs_err) | 418 | if (bts_err && pebs_err) |
419 | break; | 419 | break; |
420 | } | 420 | } |
421 | 421 | ||
422 | if (bts_err) { | 422 | if (bts_err) { |
423 | for_each_possible_cpu(cpu) | 423 | for_each_possible_cpu(cpu) |
424 | release_bts_buffer(cpu); | 424 | release_bts_buffer(cpu); |
425 | } | 425 | } |
426 | 426 | ||
427 | if (pebs_err) { | 427 | if (pebs_err) { |
428 | for_each_possible_cpu(cpu) | 428 | for_each_possible_cpu(cpu) |
429 | release_pebs_buffer(cpu); | 429 | release_pebs_buffer(cpu); |
430 | } | 430 | } |
431 | 431 | ||
432 | if (bts_err && pebs_err) { | 432 | if (bts_err && pebs_err) { |
433 | for_each_possible_cpu(cpu) | 433 | for_each_possible_cpu(cpu) |
434 | release_ds_buffer(cpu); | 434 | release_ds_buffer(cpu); |
435 | } else { | 435 | } else { |
436 | if (x86_pmu.bts && !bts_err) | 436 | if (x86_pmu.bts && !bts_err) |
437 | x86_pmu.bts_active = 1; | 437 | x86_pmu.bts_active = 1; |
438 | 438 | ||
439 | if (x86_pmu.pebs && !pebs_err) | 439 | if (x86_pmu.pebs && !pebs_err) |
440 | x86_pmu.pebs_active = 1; | 440 | x86_pmu.pebs_active = 1; |
441 | 441 | ||
442 | for_each_online_cpu(cpu) | 442 | for_each_online_cpu(cpu) |
443 | init_debug_store_on_cpu(cpu); | 443 | init_debug_store_on_cpu(cpu); |
444 | } | 444 | } |
445 | 445 | ||
446 | put_online_cpus(); | 446 | put_online_cpus(); |
447 | } | 447 | } |
448 | 448 | ||
449 | /* | 449 | /* |
450 | * BTS | 450 | * BTS |
451 | */ | 451 | */ |
452 | 452 | ||
453 | struct event_constraint bts_constraint = | 453 | struct event_constraint bts_constraint = |
454 | EVENT_CONSTRAINT(0, 1ULL << INTEL_PMC_IDX_FIXED_BTS, 0); | 454 | EVENT_CONSTRAINT(0, 1ULL << INTEL_PMC_IDX_FIXED_BTS, 0); |
455 | 455 | ||
456 | void intel_pmu_enable_bts(u64 config) | 456 | void intel_pmu_enable_bts(u64 config) |
457 | { | 457 | { |
458 | unsigned long debugctlmsr; | 458 | unsigned long debugctlmsr; |
459 | 459 | ||
460 | debugctlmsr = get_debugctlmsr(); | 460 | debugctlmsr = get_debugctlmsr(); |
461 | 461 | ||
462 | debugctlmsr |= DEBUGCTLMSR_TR; | 462 | debugctlmsr |= DEBUGCTLMSR_TR; |
463 | debugctlmsr |= DEBUGCTLMSR_BTS; | 463 | debugctlmsr |= DEBUGCTLMSR_BTS; |
464 | debugctlmsr |= DEBUGCTLMSR_BTINT; | 464 | debugctlmsr |= DEBUGCTLMSR_BTINT; |
465 | 465 | ||
466 | if (!(config & ARCH_PERFMON_EVENTSEL_OS)) | 466 | if (!(config & ARCH_PERFMON_EVENTSEL_OS)) |
467 | debugctlmsr |= DEBUGCTLMSR_BTS_OFF_OS; | 467 | debugctlmsr |= DEBUGCTLMSR_BTS_OFF_OS; |
468 | 468 | ||
469 | if (!(config & ARCH_PERFMON_EVENTSEL_USR)) | 469 | if (!(config & ARCH_PERFMON_EVENTSEL_USR)) |
470 | debugctlmsr |= DEBUGCTLMSR_BTS_OFF_USR; | 470 | debugctlmsr |= DEBUGCTLMSR_BTS_OFF_USR; |
471 | 471 | ||
472 | update_debugctlmsr(debugctlmsr); | 472 | update_debugctlmsr(debugctlmsr); |
473 | } | 473 | } |
474 | 474 | ||
475 | void intel_pmu_disable_bts(void) | 475 | void intel_pmu_disable_bts(void) |
476 | { | 476 | { |
477 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 477 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
478 | unsigned long debugctlmsr; | 478 | unsigned long debugctlmsr; |
479 | 479 | ||
480 | if (!cpuc->ds) | 480 | if (!cpuc->ds) |
481 | return; | 481 | return; |
482 | 482 | ||
483 | debugctlmsr = get_debugctlmsr(); | 483 | debugctlmsr = get_debugctlmsr(); |
484 | 484 | ||
485 | debugctlmsr &= | 485 | debugctlmsr &= |
486 | ~(DEBUGCTLMSR_TR | DEBUGCTLMSR_BTS | DEBUGCTLMSR_BTINT | | 486 | ~(DEBUGCTLMSR_TR | DEBUGCTLMSR_BTS | DEBUGCTLMSR_BTINT | |
487 | DEBUGCTLMSR_BTS_OFF_OS | DEBUGCTLMSR_BTS_OFF_USR); | 487 | DEBUGCTLMSR_BTS_OFF_OS | DEBUGCTLMSR_BTS_OFF_USR); |
488 | 488 | ||
489 | update_debugctlmsr(debugctlmsr); | 489 | update_debugctlmsr(debugctlmsr); |
490 | } | 490 | } |
491 | 491 | ||
492 | int intel_pmu_drain_bts_buffer(void) | 492 | int intel_pmu_drain_bts_buffer(void) |
493 | { | 493 | { |
494 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 494 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
495 | struct debug_store *ds = cpuc->ds; | 495 | struct debug_store *ds = cpuc->ds; |
496 | struct bts_record { | 496 | struct bts_record { |
497 | u64 from; | 497 | u64 from; |
498 | u64 to; | 498 | u64 to; |
499 | u64 flags; | 499 | u64 flags; |
500 | }; | 500 | }; |
501 | struct perf_event *event = cpuc->events[INTEL_PMC_IDX_FIXED_BTS]; | 501 | struct perf_event *event = cpuc->events[INTEL_PMC_IDX_FIXED_BTS]; |
502 | struct bts_record *at, *top; | 502 | struct bts_record *at, *top; |
503 | struct perf_output_handle handle; | 503 | struct perf_output_handle handle; |
504 | struct perf_event_header header; | 504 | struct perf_event_header header; |
505 | struct perf_sample_data data; | 505 | struct perf_sample_data data; |
506 | struct pt_regs regs; | 506 | struct pt_regs regs; |
507 | 507 | ||
508 | if (!event) | 508 | if (!event) |
509 | return 0; | 509 | return 0; |
510 | 510 | ||
511 | if (!x86_pmu.bts_active) | 511 | if (!x86_pmu.bts_active) |
512 | return 0; | 512 | return 0; |
513 | 513 | ||
514 | at = (struct bts_record *)(unsigned long)ds->bts_buffer_base; | 514 | at = (struct bts_record *)(unsigned long)ds->bts_buffer_base; |
515 | top = (struct bts_record *)(unsigned long)ds->bts_index; | 515 | top = (struct bts_record *)(unsigned long)ds->bts_index; |
516 | 516 | ||
517 | if (top <= at) | 517 | if (top <= at) |
518 | return 0; | 518 | return 0; |
519 | 519 | ||
520 | memset(®s, 0, sizeof(regs)); | 520 | memset(®s, 0, sizeof(regs)); |
521 | 521 | ||
522 | ds->bts_index = ds->bts_buffer_base; | 522 | ds->bts_index = ds->bts_buffer_base; |
523 | 523 | ||
524 | perf_sample_data_init(&data, 0, event->hw.last_period); | 524 | perf_sample_data_init(&data, 0, event->hw.last_period); |
525 | 525 | ||
526 | /* | 526 | /* |
527 | * Prepare a generic sample, i.e. fill in the invariant fields. | 527 | * Prepare a generic sample, i.e. fill in the invariant fields. |
528 | * We will overwrite the from and to address before we output | 528 | * We will overwrite the from and to address before we output |
529 | * the sample. | 529 | * the sample. |
530 | */ | 530 | */ |
531 | perf_prepare_sample(&header, &data, event, ®s); | 531 | perf_prepare_sample(&header, &data, event, ®s); |
532 | 532 | ||
533 | if (perf_output_begin(&handle, event, header.size * (top - at))) | 533 | if (perf_output_begin(&handle, event, header.size * (top - at))) |
534 | return 1; | 534 | return 1; |
535 | 535 | ||
536 | for (; at < top; at++) { | 536 | for (; at < top; at++) { |
537 | data.ip = at->from; | 537 | data.ip = at->from; |
538 | data.addr = at->to; | 538 | data.addr = at->to; |
539 | 539 | ||
540 | perf_output_sample(&handle, &header, &data, event); | 540 | perf_output_sample(&handle, &header, &data, event); |
541 | } | 541 | } |
542 | 542 | ||
543 | perf_output_end(&handle); | 543 | perf_output_end(&handle); |
544 | 544 | ||
545 | /* There's new data available. */ | 545 | /* There's new data available. */ |
546 | event->hw.interrupts++; | 546 | event->hw.interrupts++; |
547 | event->pending_kill = POLL_IN; | 547 | event->pending_kill = POLL_IN; |
548 | return 1; | 548 | return 1; |
549 | } | 549 | } |
550 | 550 | ||
551 | /* | 551 | /* |
552 | * PEBS | 552 | * PEBS |
553 | */ | 553 | */ |
554 | struct event_constraint intel_core2_pebs_event_constraints[] = { | 554 | struct event_constraint intel_core2_pebs_event_constraints[] = { |
555 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ | 555 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ |
556 | INTEL_FLAGS_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */ | 556 | INTEL_FLAGS_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */ |
557 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */ | 557 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */ |
558 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */ | 558 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */ |
559 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */ | 559 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */ |
560 | EVENT_CONSTRAINT_END | 560 | EVENT_CONSTRAINT_END |
561 | }; | 561 | }; |
562 | 562 | ||
563 | struct event_constraint intel_atom_pebs_event_constraints[] = { | 563 | struct event_constraint intel_atom_pebs_event_constraints[] = { |
564 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ | 564 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ |
565 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */ | 565 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */ |
566 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */ | 566 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */ |
567 | EVENT_CONSTRAINT_END | 567 | EVENT_CONSTRAINT_END |
568 | }; | 568 | }; |
569 | 569 | ||
570 | struct event_constraint intel_slm_pebs_event_constraints[] = { | 570 | struct event_constraint intel_slm_pebs_event_constraints[] = { |
571 | /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ | 571 | /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */ |
572 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), | 572 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x1), |
573 | /* Allow all events as PEBS with no flags */ | 573 | /* Allow all events as PEBS with no flags */ |
574 | INTEL_ALL_EVENT_CONSTRAINT(0, 0x1), | 574 | INTEL_ALL_EVENT_CONSTRAINT(0, 0x1), |
575 | EVENT_CONSTRAINT_END | 575 | EVENT_CONSTRAINT_END |
576 | }; | 576 | }; |
577 | 577 | ||
578 | struct event_constraint intel_nehalem_pebs_event_constraints[] = { | 578 | struct event_constraint intel_nehalem_pebs_event_constraints[] = { |
579 | INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ | 579 | INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ |
580 | INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ | 580 | INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ |
581 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ | 581 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ |
582 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */ | 582 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */ |
583 | INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */ | 583 | INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */ |
584 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ | 584 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ |
585 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */ | 585 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */ |
586 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */ | 586 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */ |
587 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ | 587 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ |
588 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */ | 588 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */ |
589 | INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */ | 589 | INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */ |
590 | EVENT_CONSTRAINT_END | 590 | EVENT_CONSTRAINT_END |
591 | }; | 591 | }; |
592 | 592 | ||
593 | struct event_constraint intel_westmere_pebs_event_constraints[] = { | 593 | struct event_constraint intel_westmere_pebs_event_constraints[] = { |
594 | INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ | 594 | INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ |
595 | INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ | 595 | INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ |
596 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ | 596 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ |
597 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */ | 597 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */ |
598 | INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */ | 598 | INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */ |
599 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ | 599 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ |
600 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */ | 600 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */ |
601 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */ | 601 | INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */ |
602 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ | 602 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ |
603 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */ | 603 | INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */ |
604 | INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */ | 604 | INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */ |
605 | EVENT_CONSTRAINT_END | 605 | EVENT_CONSTRAINT_END |
606 | }; | 606 | }; |
607 | 607 | ||
608 | struct event_constraint intel_snb_pebs_event_constraints[] = { | 608 | struct event_constraint intel_snb_pebs_event_constraints[] = { |
609 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ | 609 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ |
610 | INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ | 610 | INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ |
611 | INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ | 611 | INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ |
612 | /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ | 612 | /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ |
613 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), | 613 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), |
614 | /* Allow all events as PEBS with no flags */ | 614 | /* Allow all events as PEBS with no flags */ |
615 | INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), | 615 | INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), |
616 | EVENT_CONSTRAINT_END | 616 | EVENT_CONSTRAINT_END |
617 | }; | 617 | }; |
618 | 618 | ||
619 | struct event_constraint intel_ivb_pebs_event_constraints[] = { | 619 | struct event_constraint intel_ivb_pebs_event_constraints[] = { |
620 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ | 620 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ |
621 | INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ | 621 | INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ |
622 | INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ | 622 | INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ |
623 | /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ | 623 | /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ |
624 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), | 624 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), |
625 | /* Allow all events as PEBS with no flags */ | 625 | /* Allow all events as PEBS with no flags */ |
626 | INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), | 626 | INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), |
627 | EVENT_CONSTRAINT_END | 627 | EVENT_CONSTRAINT_END |
628 | }; | 628 | }; |
629 | 629 | ||
630 | struct event_constraint intel_hsw_pebs_event_constraints[] = { | 630 | struct event_constraint intel_hsw_pebs_event_constraints[] = { |
631 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ | 631 | INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ |
632 | INTEL_PLD_CONSTRAINT(0x01cd, 0xf), /* MEM_TRANS_RETIRED.* */ | 632 | INTEL_PLD_CONSTRAINT(0x01cd, 0xf), /* MEM_TRANS_RETIRED.* */ |
633 | /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ | 633 | /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ |
634 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), | 634 | INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), |
635 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ | 635 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ |
636 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ | 636 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ |
637 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */ | 637 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */ |
638 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */ | 638 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */ |
639 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */ | 639 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */ |
640 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_STORES */ | 640 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_STORES */ |
641 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_STORES */ | 641 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_STORES */ |
642 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */ | 642 | INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */ |
643 | INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ | 643 | INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ |
644 | INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd2, 0xf), /* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */ | 644 | INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd2, 0xf), /* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */ |
645 | INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd3, 0xf), /* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */ | 645 | INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd3, 0xf), /* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */ |
646 | /* Allow all events as PEBS with no flags */ | 646 | /* Allow all events as PEBS with no flags */ |
647 | INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), | 647 | INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), |
648 | EVENT_CONSTRAINT_END | 648 | EVENT_CONSTRAINT_END |
649 | }; | 649 | }; |
650 | 650 | ||
651 | struct event_constraint *intel_pebs_constraints(struct perf_event *event) | 651 | struct event_constraint *intel_pebs_constraints(struct perf_event *event) |
652 | { | 652 | { |
653 | struct event_constraint *c; | 653 | struct event_constraint *c; |
654 | 654 | ||
655 | if (!event->attr.precise_ip) | 655 | if (!event->attr.precise_ip) |
656 | return NULL; | 656 | return NULL; |
657 | 657 | ||
658 | if (x86_pmu.pebs_constraints) { | 658 | if (x86_pmu.pebs_constraints) { |
659 | for_each_event_constraint(c, x86_pmu.pebs_constraints) { | 659 | for_each_event_constraint(c, x86_pmu.pebs_constraints) { |
660 | if ((event->hw.config & c->cmask) == c->code) { | 660 | if ((event->hw.config & c->cmask) == c->code) { |
661 | event->hw.flags |= c->flags; | 661 | event->hw.flags |= c->flags; |
662 | return c; | 662 | return c; |
663 | } | 663 | } |
664 | } | 664 | } |
665 | } | 665 | } |
666 | 666 | ||
667 | return &emptyconstraint; | 667 | return &emptyconstraint; |
668 | } | 668 | } |
669 | 669 | ||
670 | void intel_pmu_pebs_enable(struct perf_event *event) | 670 | void intel_pmu_pebs_enable(struct perf_event *event) |
671 | { | 671 | { |
672 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 672 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
673 | struct hw_perf_event *hwc = &event->hw; | 673 | struct hw_perf_event *hwc = &event->hw; |
674 | 674 | ||
675 | hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT; | 675 | hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT; |
676 | 676 | ||
677 | cpuc->pebs_enabled |= 1ULL << hwc->idx; | 677 | cpuc->pebs_enabled |= 1ULL << hwc->idx; |
678 | 678 | ||
679 | if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) | 679 | if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) |
680 | cpuc->pebs_enabled |= 1ULL << (hwc->idx + 32); | 680 | cpuc->pebs_enabled |= 1ULL << (hwc->idx + 32); |
681 | else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) | 681 | else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) |
682 | cpuc->pebs_enabled |= 1ULL << 63; | 682 | cpuc->pebs_enabled |= 1ULL << 63; |
683 | } | 683 | } |
684 | 684 | ||
685 | void intel_pmu_pebs_disable(struct perf_event *event) | 685 | void intel_pmu_pebs_disable(struct perf_event *event) |
686 | { | 686 | { |
687 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 687 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
688 | struct hw_perf_event *hwc = &event->hw; | 688 | struct hw_perf_event *hwc = &event->hw; |
689 | 689 | ||
690 | cpuc->pebs_enabled &= ~(1ULL << hwc->idx); | 690 | cpuc->pebs_enabled &= ~(1ULL << hwc->idx); |
691 | 691 | ||
692 | if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_LDLAT) | 692 | if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_LDLAT) |
693 | cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32)); | 693 | cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32)); |
694 | else if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_ST) | 694 | else if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_ST) |
695 | cpuc->pebs_enabled &= ~(1ULL << 63); | 695 | cpuc->pebs_enabled &= ~(1ULL << 63); |
696 | 696 | ||
697 | if (cpuc->enabled) | 697 | if (cpuc->enabled) |
698 | wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); | 698 | wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); |
699 | 699 | ||
700 | hwc->config |= ARCH_PERFMON_EVENTSEL_INT; | 700 | hwc->config |= ARCH_PERFMON_EVENTSEL_INT; |
701 | } | 701 | } |
702 | 702 | ||
703 | void intel_pmu_pebs_enable_all(void) | 703 | void intel_pmu_pebs_enable_all(void) |
704 | { | 704 | { |
705 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 705 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
706 | 706 | ||
707 | if (cpuc->pebs_enabled) | 707 | if (cpuc->pebs_enabled) |
708 | wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); | 708 | wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); |
709 | } | 709 | } |
710 | 710 | ||
711 | void intel_pmu_pebs_disable_all(void) | 711 | void intel_pmu_pebs_disable_all(void) |
712 | { | 712 | { |
713 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 713 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
714 | 714 | ||
715 | if (cpuc->pebs_enabled) | 715 | if (cpuc->pebs_enabled) |
716 | wrmsrl(MSR_IA32_PEBS_ENABLE, 0); | 716 | wrmsrl(MSR_IA32_PEBS_ENABLE, 0); |
717 | } | 717 | } |
718 | 718 | ||
719 | static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) | 719 | static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) |
720 | { | 720 | { |
721 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 721 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
722 | unsigned long from = cpuc->lbr_entries[0].from; | 722 | unsigned long from = cpuc->lbr_entries[0].from; |
723 | unsigned long old_to, to = cpuc->lbr_entries[0].to; | 723 | unsigned long old_to, to = cpuc->lbr_entries[0].to; |
724 | unsigned long ip = regs->ip; | 724 | unsigned long ip = regs->ip; |
725 | int is_64bit = 0; | 725 | int is_64bit = 0; |
726 | void *kaddr; | 726 | void *kaddr; |
727 | int size; | 727 | int size; |
728 | 728 | ||
729 | /* | 729 | /* |
730 | * We don't need to fixup if the PEBS assist is fault like | 730 | * We don't need to fixup if the PEBS assist is fault like |
731 | */ | 731 | */ |
732 | if (!x86_pmu.intel_cap.pebs_trap) | 732 | if (!x86_pmu.intel_cap.pebs_trap) |
733 | return 1; | 733 | return 1; |
734 | 734 | ||
735 | /* | 735 | /* |
736 | * No LBR entry, no basic block, no rewinding | 736 | * No LBR entry, no basic block, no rewinding |
737 | */ | 737 | */ |
738 | if (!cpuc->lbr_stack.nr || !from || !to) | 738 | if (!cpuc->lbr_stack.nr || !from || !to) |
739 | return 0; | 739 | return 0; |
740 | 740 | ||
741 | /* | 741 | /* |
742 | * Basic blocks should never cross user/kernel boundaries | 742 | * Basic blocks should never cross user/kernel boundaries |
743 | */ | 743 | */ |
744 | if (kernel_ip(ip) != kernel_ip(to)) | 744 | if (kernel_ip(ip) != kernel_ip(to)) |
745 | return 0; | 745 | return 0; |
746 | 746 | ||
747 | /* | 747 | /* |
748 | * unsigned math, either ip is before the start (impossible) or | 748 | * unsigned math, either ip is before the start (impossible) or |
749 | * the basic block is larger than 1 page (sanity) | 749 | * the basic block is larger than 1 page (sanity) |
750 | */ | 750 | */ |
751 | if ((ip - to) > PEBS_FIXUP_SIZE) | 751 | if ((ip - to) > PEBS_FIXUP_SIZE) |
752 | return 0; | 752 | return 0; |
753 | 753 | ||
754 | /* | 754 | /* |
755 | * We sampled a branch insn, rewind using the LBR stack | 755 | * We sampled a branch insn, rewind using the LBR stack |
756 | */ | 756 | */ |
757 | if (ip == to) { | 757 | if (ip == to) { |
758 | set_linear_ip(regs, from); | 758 | set_linear_ip(regs, from); |
759 | return 1; | 759 | return 1; |
760 | } | 760 | } |
761 | 761 | ||
762 | size = ip - to; | 762 | size = ip - to; |
763 | if (!kernel_ip(ip)) { | 763 | if (!kernel_ip(ip)) { |
764 | int bytes; | 764 | int bytes; |
765 | u8 *buf = this_cpu_read(insn_buffer); | 765 | u8 *buf = this_cpu_read(insn_buffer); |
766 | 766 | ||
767 | /* 'size' must fit our buffer, see above */ | 767 | /* 'size' must fit our buffer, see above */ |
768 | bytes = copy_from_user_nmi(buf, (void __user *)to, size); | 768 | bytes = copy_from_user_nmi(buf, (void __user *)to, size); |
769 | if (bytes != 0) | 769 | if (bytes != 0) |
770 | return 0; | 770 | return 0; |
771 | 771 | ||
772 | kaddr = buf; | 772 | kaddr = buf; |
773 | } else { | 773 | } else { |
774 | kaddr = (void *)to; | 774 | kaddr = (void *)to; |
775 | } | 775 | } |
776 | 776 | ||
777 | do { | 777 | do { |
778 | struct insn insn; | 778 | struct insn insn; |
779 | 779 | ||
780 | old_to = to; | 780 | old_to = to; |
781 | 781 | ||
782 | #ifdef CONFIG_X86_64 | 782 | #ifdef CONFIG_X86_64 |
783 | is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32); | 783 | is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32); |
784 | #endif | 784 | #endif |
785 | insn_init(&insn, kaddr, size, is_64bit); | 785 | insn_init(&insn, kaddr, size, is_64bit); |
786 | insn_get_length(&insn); | 786 | insn_get_length(&insn); |
787 | /* | 787 | /* |
788 | * Make sure there was not a problem decoding the | 788 | * Make sure there was not a problem decoding the |
789 | * instruction and getting the length. This is | 789 | * instruction and getting the length. This is |
790 | * doubly important because we have an infinite | 790 | * doubly important because we have an infinite |
791 | * loop if insn.length=0. | 791 | * loop if insn.length=0. |
792 | */ | 792 | */ |
793 | if (!insn.length) | 793 | if (!insn.length) |
794 | break; | 794 | break; |
795 | 795 | ||
796 | to += insn.length; | 796 | to += insn.length; |
797 | kaddr += insn.length; | 797 | kaddr += insn.length; |
798 | size -= insn.length; | 798 | size -= insn.length; |
799 | } while (to < ip); | 799 | } while (to < ip); |
800 | 800 | ||
801 | if (to == ip) { | 801 | if (to == ip) { |
802 | set_linear_ip(regs, old_to); | 802 | set_linear_ip(regs, old_to); |
803 | return 1; | 803 | return 1; |
804 | } | 804 | } |
805 | 805 | ||
806 | /* | 806 | /* |
807 | * Even though we decoded the basic block, the instruction stream | 807 | * Even though we decoded the basic block, the instruction stream |
808 | * never matched the given IP, either the TO or the IP got corrupted. | 808 | * never matched the given IP, either the TO or the IP got corrupted. |
809 | */ | 809 | */ |
810 | return 0; | 810 | return 0; |
811 | } | 811 | } |
812 | 812 | ||
813 | static inline u64 intel_hsw_weight(struct pebs_record_hsw *pebs) | 813 | static inline u64 intel_hsw_weight(struct pebs_record_hsw *pebs) |
814 | { | 814 | { |
815 | if (pebs->tsx_tuning) { | 815 | if (pebs->tsx_tuning) { |
816 | union hsw_tsx_tuning tsx = { .value = pebs->tsx_tuning }; | 816 | union hsw_tsx_tuning tsx = { .value = pebs->tsx_tuning }; |
817 | return tsx.cycles_last_block; | 817 | return tsx.cycles_last_block; |
818 | } | 818 | } |
819 | return 0; | 819 | return 0; |
820 | } | 820 | } |
821 | 821 | ||
822 | static inline u64 intel_hsw_transaction(struct pebs_record_hsw *pebs) | 822 | static inline u64 intel_hsw_transaction(struct pebs_record_hsw *pebs) |
823 | { | 823 | { |
824 | u64 txn = (pebs->tsx_tuning & PEBS_HSW_TSX_FLAGS) >> 32; | 824 | u64 txn = (pebs->tsx_tuning & PEBS_HSW_TSX_FLAGS) >> 32; |
825 | 825 | ||
826 | /* For RTM XABORTs also log the abort code from AX */ | 826 | /* For RTM XABORTs also log the abort code from AX */ |
827 | if ((txn & PERF_TXN_TRANSACTION) && (pebs->ax & 1)) | 827 | if ((txn & PERF_TXN_TRANSACTION) && (pebs->ax & 1)) |
828 | txn |= ((pebs->ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT; | 828 | txn |= ((pebs->ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT; |
829 | return txn; | 829 | return txn; |
830 | } | 830 | } |
831 | 831 | ||
832 | static void __intel_pmu_pebs_event(struct perf_event *event, | 832 | static void __intel_pmu_pebs_event(struct perf_event *event, |
833 | struct pt_regs *iregs, void *__pebs) | 833 | struct pt_regs *iregs, void *__pebs) |
834 | { | 834 | { |
835 | #define PERF_X86_EVENT_PEBS_HSW_PREC \ | 835 | #define PERF_X86_EVENT_PEBS_HSW_PREC \ |
836 | (PERF_X86_EVENT_PEBS_ST_HSW | \ | 836 | (PERF_X86_EVENT_PEBS_ST_HSW | \ |
837 | PERF_X86_EVENT_PEBS_LD_HSW | \ | 837 | PERF_X86_EVENT_PEBS_LD_HSW | \ |
838 | PERF_X86_EVENT_PEBS_NA_HSW) | 838 | PERF_X86_EVENT_PEBS_NA_HSW) |
839 | /* | 839 | /* |
840 | * We cast to the biggest pebs_record but are careful not to | 840 | * We cast to the biggest pebs_record but are careful not to |
841 | * unconditionally access the 'extra' entries. | 841 | * unconditionally access the 'extra' entries. |
842 | */ | 842 | */ |
843 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 843 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
844 | struct pebs_record_hsw *pebs = __pebs; | 844 | struct pebs_record_hsw *pebs = __pebs; |
845 | struct perf_sample_data data; | 845 | struct perf_sample_data data; |
846 | struct pt_regs regs; | 846 | struct pt_regs regs; |
847 | u64 sample_type; | 847 | u64 sample_type; |
848 | int fll, fst, dsrc; | 848 | int fll, fst, dsrc; |
849 | int fl = event->hw.flags; | 849 | int fl = event->hw.flags; |
850 | 850 | ||
851 | if (!intel_pmu_save_and_restart(event)) | 851 | if (!intel_pmu_save_and_restart(event)) |
852 | return; | 852 | return; |
853 | 853 | ||
854 | sample_type = event->attr.sample_type; | 854 | sample_type = event->attr.sample_type; |
855 | dsrc = sample_type & PERF_SAMPLE_DATA_SRC; | 855 | dsrc = sample_type & PERF_SAMPLE_DATA_SRC; |
856 | 856 | ||
857 | fll = fl & PERF_X86_EVENT_PEBS_LDLAT; | 857 | fll = fl & PERF_X86_EVENT_PEBS_LDLAT; |
858 | fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC); | 858 | fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC); |
859 | 859 | ||
860 | perf_sample_data_init(&data, 0, event->hw.last_period); | 860 | perf_sample_data_init(&data, 0, event->hw.last_period); |
861 | 861 | ||
862 | data.period = event->hw.last_period; | 862 | data.period = event->hw.last_period; |
863 | 863 | ||
864 | /* | 864 | /* |
865 | * Use latency for weight (only avail with PEBS-LL) | 865 | * Use latency for weight (only avail with PEBS-LL) |
866 | */ | 866 | */ |
867 | if (fll && (sample_type & PERF_SAMPLE_WEIGHT)) | 867 | if (fll && (sample_type & PERF_SAMPLE_WEIGHT)) |
868 | data.weight = pebs->lat; | 868 | data.weight = pebs->lat; |
869 | 869 | ||
870 | /* | 870 | /* |
871 | * data.data_src encodes the data source | 871 | * data.data_src encodes the data source |
872 | */ | 872 | */ |
873 | if (dsrc) { | 873 | if (dsrc) { |
874 | u64 val = PERF_MEM_NA; | 874 | u64 val = PERF_MEM_NA; |
875 | if (fll) | 875 | if (fll) |
876 | val = load_latency_data(pebs->dse); | 876 | val = load_latency_data(pebs->dse); |
877 | else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC)) | 877 | else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC)) |
878 | val = precise_datala_hsw(event, pebs->dse); | 878 | val = precise_datala_hsw(event, pebs->dse); |
879 | else if (fst) | 879 | else if (fst) |
880 | val = precise_store_data(pebs->dse); | 880 | val = precise_store_data(pebs->dse); |
881 | data.data_src.val = val; | 881 | data.data_src.val = val; |
882 | } | 882 | } |
883 | 883 | ||
884 | /* | 884 | /* |
885 | * We use the interrupt regs as a base because the PEBS record | 885 | * We use the interrupt regs as a base because the PEBS record |
886 | * does not contain a full regs set, specifically it seems to | 886 | * does not contain a full regs set, specifically it seems to |
887 | * lack segment descriptors, which get used by things like | 887 | * lack segment descriptors, which get used by things like |
888 | * user_mode(). | 888 | * user_mode(). |
889 | * | 889 | * |
890 | * In the simple case fix up only the IP and BP,SP regs, for | 890 | * In the simple case fix up only the IP and BP,SP regs, for |
891 | * PERF_SAMPLE_IP and PERF_SAMPLE_CALLCHAIN to function properly. | 891 | * PERF_SAMPLE_IP and PERF_SAMPLE_CALLCHAIN to function properly. |
892 | * A possible PERF_SAMPLE_REGS will have to transfer all regs. | 892 | * A possible PERF_SAMPLE_REGS will have to transfer all regs. |
893 | */ | 893 | */ |
894 | regs = *iregs; | 894 | regs = *iregs; |
895 | regs.flags = pebs->flags; | 895 | regs.flags = pebs->flags; |
896 | set_linear_ip(®s, pebs->ip); | 896 | set_linear_ip(®s, pebs->ip); |
897 | regs.bp = pebs->bp; | 897 | regs.bp = pebs->bp; |
898 | regs.sp = pebs->sp; | 898 | regs.sp = pebs->sp; |
899 | 899 | ||
900 | if (sample_type & PERF_SAMPLE_REGS_INTR) { | 900 | if (sample_type & PERF_SAMPLE_REGS_INTR) { |
901 | regs.ax = pebs->ax; | 901 | regs.ax = pebs->ax; |
902 | regs.bx = pebs->bx; | 902 | regs.bx = pebs->bx; |
903 | regs.cx = pebs->cx; | 903 | regs.cx = pebs->cx; |
904 | regs.dx = pebs->dx; | 904 | regs.dx = pebs->dx; |
905 | regs.si = pebs->si; | 905 | regs.si = pebs->si; |
906 | regs.di = pebs->di; | 906 | regs.di = pebs->di; |
907 | regs.bp = pebs->bp; | 907 | regs.bp = pebs->bp; |
908 | regs.sp = pebs->sp; | 908 | regs.sp = pebs->sp; |
909 | 909 | ||
910 | regs.flags = pebs->flags; | 910 | regs.flags = pebs->flags; |
911 | #ifndef CONFIG_X86_32 | 911 | #ifndef CONFIG_X86_32 |
912 | regs.r8 = pebs->r8; | 912 | regs.r8 = pebs->r8; |
913 | regs.r9 = pebs->r9; | 913 | regs.r9 = pebs->r9; |
914 | regs.r10 = pebs->r10; | 914 | regs.r10 = pebs->r10; |
915 | regs.r11 = pebs->r11; | 915 | regs.r11 = pebs->r11; |
916 | regs.r12 = pebs->r12; | 916 | regs.r12 = pebs->r12; |
917 | regs.r13 = pebs->r13; | 917 | regs.r13 = pebs->r13; |
918 | regs.r14 = pebs->r14; | 918 | regs.r14 = pebs->r14; |
919 | regs.r15 = pebs->r15; | 919 | regs.r15 = pebs->r15; |
920 | #endif | 920 | #endif |
921 | } | 921 | } |
922 | 922 | ||
923 | if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) { | 923 | if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) { |
924 | regs.ip = pebs->real_ip; | 924 | regs.ip = pebs->real_ip; |
925 | regs.flags |= PERF_EFLAGS_EXACT; | 925 | regs.flags |= PERF_EFLAGS_EXACT; |
926 | } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(®s)) | 926 | } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(®s)) |
927 | regs.flags |= PERF_EFLAGS_EXACT; | 927 | regs.flags |= PERF_EFLAGS_EXACT; |
928 | else | 928 | else |
929 | regs.flags &= ~PERF_EFLAGS_EXACT; | 929 | regs.flags &= ~PERF_EFLAGS_EXACT; |
930 | 930 | ||
931 | if ((sample_type & PERF_SAMPLE_ADDR) && | 931 | if ((sample_type & PERF_SAMPLE_ADDR) && |
932 | x86_pmu.intel_cap.pebs_format >= 1) | 932 | x86_pmu.intel_cap.pebs_format >= 1) |
933 | data.addr = pebs->dla; | 933 | data.addr = pebs->dla; |
934 | 934 | ||
935 | if (x86_pmu.intel_cap.pebs_format >= 2) { | 935 | if (x86_pmu.intel_cap.pebs_format >= 2) { |
936 | /* Only set the TSX weight when no memory weight. */ | 936 | /* Only set the TSX weight when no memory weight. */ |
937 | if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll) | 937 | if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll) |
938 | data.weight = intel_hsw_weight(pebs); | 938 | data.weight = intel_hsw_weight(pebs); |
939 | 939 | ||
940 | if (sample_type & PERF_SAMPLE_TRANSACTION) | 940 | if (sample_type & PERF_SAMPLE_TRANSACTION) |
941 | data.txn = intel_hsw_transaction(pebs); | 941 | data.txn = intel_hsw_transaction(pebs); |
942 | } | 942 | } |
943 | 943 | ||
944 | if (has_branch_stack(event)) | 944 | if (has_branch_stack(event)) |
945 | data.br_stack = &cpuc->lbr_stack; | 945 | data.br_stack = &cpuc->lbr_stack; |
946 | 946 | ||
947 | if (perf_event_overflow(event, &data, ®s)) | 947 | if (perf_event_overflow(event, &data, ®s)) |
948 | x86_pmu_stop(event, 0); | 948 | x86_pmu_stop(event, 0); |
949 | } | 949 | } |
950 | 950 | ||
951 | static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) | 951 | static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) |
952 | { | 952 | { |
953 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 953 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
954 | struct debug_store *ds = cpuc->ds; | 954 | struct debug_store *ds = cpuc->ds; |
955 | struct perf_event *event = cpuc->events[0]; /* PMC0 only */ | 955 | struct perf_event *event = cpuc->events[0]; /* PMC0 only */ |
956 | struct pebs_record_core *at, *top; | 956 | struct pebs_record_core *at, *top; |
957 | int n; | 957 | int n; |
958 | 958 | ||
959 | if (!x86_pmu.pebs_active) | 959 | if (!x86_pmu.pebs_active) |
960 | return; | 960 | return; |
961 | 961 | ||
962 | at = (struct pebs_record_core *)(unsigned long)ds->pebs_buffer_base; | 962 | at = (struct pebs_record_core *)(unsigned long)ds->pebs_buffer_base; |
963 | top = (struct pebs_record_core *)(unsigned long)ds->pebs_index; | 963 | top = (struct pebs_record_core *)(unsigned long)ds->pebs_index; |
964 | 964 | ||
965 | /* | 965 | /* |
966 | * Whatever else happens, drain the thing | 966 | * Whatever else happens, drain the thing |
967 | */ | 967 | */ |
968 | ds->pebs_index = ds->pebs_buffer_base; | 968 | ds->pebs_index = ds->pebs_buffer_base; |
969 | 969 | ||
970 | if (!test_bit(0, cpuc->active_mask)) | 970 | if (!test_bit(0, cpuc->active_mask)) |
971 | return; | 971 | return; |
972 | 972 | ||
973 | WARN_ON_ONCE(!event); | 973 | WARN_ON_ONCE(!event); |
974 | 974 | ||
975 | if (!event->attr.precise_ip) | 975 | if (!event->attr.precise_ip) |
976 | return; | 976 | return; |
977 | 977 | ||
978 | n = top - at; | 978 | n = top - at; |
979 | if (n <= 0) | 979 | if (n <= 0) |
980 | return; | 980 | return; |
981 | 981 | ||
982 | /* | 982 | /* |
983 | * Should not happen, we program the threshold at 1 and do not | 983 | * Should not happen, we program the threshold at 1 and do not |
984 | * set a reset value. | 984 | * set a reset value. |
985 | */ | 985 | */ |
986 | WARN_ONCE(n > 1, "bad leftover pebs %d\n", n); | 986 | WARN_ONCE(n > 1, "bad leftover pebs %d\n", n); |
987 | at += n - 1; | 987 | at += n - 1; |
988 | 988 | ||
989 | __intel_pmu_pebs_event(event, iregs, at); | 989 | __intel_pmu_pebs_event(event, iregs, at); |
990 | } | 990 | } |
991 | 991 | ||
992 | static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) | 992 | static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) |
993 | { | 993 | { |
994 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 994 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
995 | struct debug_store *ds = cpuc->ds; | 995 | struct debug_store *ds = cpuc->ds; |
996 | struct perf_event *event = NULL; | 996 | struct perf_event *event = NULL; |
997 | void *at, *top; | 997 | void *at, *top; |
998 | u64 status = 0; | 998 | u64 status = 0; |
999 | int bit; | 999 | int bit; |
1000 | 1000 | ||
1001 | if (!x86_pmu.pebs_active) | 1001 | if (!x86_pmu.pebs_active) |
1002 | return; | 1002 | return; |
1003 | 1003 | ||
1004 | at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base; | 1004 | at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base; |
1005 | top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index; | 1005 | top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index; |
1006 | 1006 | ||
1007 | ds->pebs_index = ds->pebs_buffer_base; | 1007 | ds->pebs_index = ds->pebs_buffer_base; |
1008 | 1008 | ||
1009 | if (unlikely(at > top)) | 1009 | if (unlikely(at > top)) |
1010 | return; | 1010 | return; |
1011 | 1011 | ||
1012 | /* | 1012 | /* |
1013 | * Should not happen, we program the threshold at 1 and do not | 1013 | * Should not happen, we program the threshold at 1 and do not |
1014 | * set a reset value. | 1014 | * set a reset value. |
1015 | */ | 1015 | */ |
1016 | WARN_ONCE(top - at > x86_pmu.max_pebs_events * x86_pmu.pebs_record_size, | 1016 | WARN_ONCE(top - at > x86_pmu.max_pebs_events * x86_pmu.pebs_record_size, |
1017 | "Unexpected number of pebs records %ld\n", | 1017 | "Unexpected number of pebs records %ld\n", |
1018 | (long)(top - at) / x86_pmu.pebs_record_size); | 1018 | (long)(top - at) / x86_pmu.pebs_record_size); |
1019 | 1019 | ||
1020 | for (; at < top; at += x86_pmu.pebs_record_size) { | 1020 | for (; at < top; at += x86_pmu.pebs_record_size) { |
1021 | struct pebs_record_nhm *p = at; | 1021 | struct pebs_record_nhm *p = at; |
1022 | 1022 | ||
1023 | for_each_set_bit(bit, (unsigned long *)&p->status, | 1023 | for_each_set_bit(bit, (unsigned long *)&p->status, |
1024 | x86_pmu.max_pebs_events) { | 1024 | x86_pmu.max_pebs_events) { |
1025 | event = cpuc->events[bit]; | 1025 | event = cpuc->events[bit]; |
1026 | if (!test_bit(bit, cpuc->active_mask)) | 1026 | if (!test_bit(bit, cpuc->active_mask)) |
1027 | continue; | 1027 | continue; |
1028 | 1028 | ||
1029 | WARN_ON_ONCE(!event); | 1029 | WARN_ON_ONCE(!event); |
1030 | 1030 | ||
1031 | if (!event->attr.precise_ip) | 1031 | if (!event->attr.precise_ip) |
1032 | continue; | 1032 | continue; |
1033 | 1033 | ||
1034 | if (__test_and_set_bit(bit, (unsigned long *)&status)) | 1034 | if (__test_and_set_bit(bit, (unsigned long *)&status)) |
1035 | continue; | 1035 | continue; |
1036 | 1036 | ||
1037 | break; | 1037 | break; |
1038 | } | 1038 | } |
1039 | 1039 | ||
1040 | if (!event || bit >= x86_pmu.max_pebs_events) | 1040 | if (!event || bit >= x86_pmu.max_pebs_events) |
1041 | continue; | 1041 | continue; |
1042 | 1042 | ||
1043 | __intel_pmu_pebs_event(event, iregs, at); | 1043 | __intel_pmu_pebs_event(event, iregs, at); |
1044 | } | 1044 | } |
1045 | } | 1045 | } |
1046 | 1046 | ||
1047 | /* | 1047 | /* |
1048 | * BTS, PEBS probe and setup | 1048 | * BTS, PEBS probe and setup |
1049 | */ | 1049 | */ |
1050 | 1050 | ||
1051 | void __init intel_ds_init(void) | 1051 | void __init intel_ds_init(void) |
1052 | { | 1052 | { |
1053 | /* | 1053 | /* |
1054 | * No support for 32bit formats | 1054 | * No support for 32bit formats |
1055 | */ | 1055 | */ |
1056 | if (!boot_cpu_has(X86_FEATURE_DTES64)) | 1056 | if (!boot_cpu_has(X86_FEATURE_DTES64)) |
1057 | return; | 1057 | return; |
1058 | 1058 | ||
1059 | x86_pmu.bts = boot_cpu_has(X86_FEATURE_BTS); | 1059 | x86_pmu.bts = boot_cpu_has(X86_FEATURE_BTS); |
1060 | x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS); | 1060 | x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS); |
1061 | if (x86_pmu.pebs) { | 1061 | if (x86_pmu.pebs) { |
1062 | char pebs_type = x86_pmu.intel_cap.pebs_trap ? '+' : '-'; | 1062 | char pebs_type = x86_pmu.intel_cap.pebs_trap ? '+' : '-'; |
1063 | int format = x86_pmu.intel_cap.pebs_format; | 1063 | int format = x86_pmu.intel_cap.pebs_format; |
1064 | 1064 | ||
1065 | switch (format) { | 1065 | switch (format) { |
1066 | case 0: | 1066 | case 0: |
1067 | printk(KERN_CONT "PEBS fmt0%c, ", pebs_type); | 1067 | printk(KERN_CONT "PEBS fmt0%c, ", pebs_type); |
1068 | x86_pmu.pebs_record_size = sizeof(struct pebs_record_core); | 1068 | x86_pmu.pebs_record_size = sizeof(struct pebs_record_core); |
1069 | x86_pmu.drain_pebs = intel_pmu_drain_pebs_core; | 1069 | x86_pmu.drain_pebs = intel_pmu_drain_pebs_core; |
1070 | break; | 1070 | break; |
1071 | 1071 | ||
1072 | case 1: | 1072 | case 1: |
1073 | printk(KERN_CONT "PEBS fmt1%c, ", pebs_type); | 1073 | printk(KERN_CONT "PEBS fmt1%c, ", pebs_type); |
1074 | x86_pmu.pebs_record_size = sizeof(struct pebs_record_nhm); | 1074 | x86_pmu.pebs_record_size = sizeof(struct pebs_record_nhm); |
1075 | x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm; | 1075 | x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm; |
1076 | break; | 1076 | break; |
1077 | 1077 | ||
1078 | case 2: | 1078 | case 2: |
1079 | pr_cont("PEBS fmt2%c, ", pebs_type); | 1079 | pr_cont("PEBS fmt2%c, ", pebs_type); |
1080 | x86_pmu.pebs_record_size = sizeof(struct pebs_record_hsw); | 1080 | x86_pmu.pebs_record_size = sizeof(struct pebs_record_hsw); |
1081 | x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm; | 1081 | x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm; |
1082 | break; | 1082 | break; |
1083 | 1083 | ||
1084 | default: | 1084 | default: |
1085 | printk(KERN_CONT "no PEBS fmt%d%c, ", format, pebs_type); | 1085 | printk(KERN_CONT "no PEBS fmt%d%c, ", format, pebs_type); |
1086 | x86_pmu.pebs = 0; | 1086 | x86_pmu.pebs = 0; |
1087 | } | 1087 | } |
1088 | } | 1088 | } |
1089 | } | 1089 | } |
1090 | 1090 | ||
1091 | void perf_restore_debug_store(void) | 1091 | void perf_restore_debug_store(void) |
1092 | { | 1092 | { |
1093 | struct debug_store *ds = __this_cpu_read(cpu_hw_events.ds); | 1093 | struct debug_store *ds = __this_cpu_read(cpu_hw_events.ds); |
1094 | 1094 | ||
1095 | if (!x86_pmu.bts && !x86_pmu.pebs) | 1095 | if (!x86_pmu.bts && !x86_pmu.pebs) |
1096 | return; | 1096 | return; |
1097 | 1097 | ||
1098 | wrmsrl(MSR_IA32_DS_AREA, (unsigned long)ds); | 1098 | wrmsrl(MSR_IA32_DS_AREA, (unsigned long)ds); |
1099 | } | 1099 | } |
1100 | 1100 |
arch/x86/kernel/cpu/perf_event_intel_rapl.c
1 | /* | 1 | /* |
2 | * perf_event_intel_rapl.c: support Intel RAPL energy consumption counters | 2 | * perf_event_intel_rapl.c: support Intel RAPL energy consumption counters |
3 | * Copyright (C) 2013 Google, Inc., Stephane Eranian | 3 | * Copyright (C) 2013 Google, Inc., Stephane Eranian |
4 | * | 4 | * |
5 | * Intel RAPL interface is specified in the IA-32 Manual Vol3b | 5 | * Intel RAPL interface is specified in the IA-32 Manual Vol3b |
6 | * section 14.7.1 (September 2013) | 6 | * section 14.7.1 (September 2013) |
7 | * | 7 | * |
8 | * RAPL provides more controls than just reporting energy consumption | 8 | * RAPL provides more controls than just reporting energy consumption |
9 | * however here we only expose the 3 energy consumption free running | 9 | * however here we only expose the 3 energy consumption free running |
10 | * counters (pp0, pkg, dram). | 10 | * counters (pp0, pkg, dram). |
11 | * | 11 | * |
12 | * Each of those counters increments in a power unit defined by the | 12 | * Each of those counters increments in a power unit defined by the |
13 | * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules | 13 | * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules |
14 | * but it can vary. | 14 | * but it can vary. |
15 | * | 15 | * |
16 | * Counter to rapl events mappings: | 16 | * Counter to rapl events mappings: |
17 | * | 17 | * |
18 | * pp0 counter: consumption of all physical cores (power plane 0) | 18 | * pp0 counter: consumption of all physical cores (power plane 0) |
19 | * event: rapl_energy_cores | 19 | * event: rapl_energy_cores |
20 | * perf code: 0x1 | 20 | * perf code: 0x1 |
21 | * | 21 | * |
22 | * pkg counter: consumption of the whole processor package | 22 | * pkg counter: consumption of the whole processor package |
23 | * event: rapl_energy_pkg | 23 | * event: rapl_energy_pkg |
24 | * perf code: 0x2 | 24 | * perf code: 0x2 |
25 | * | 25 | * |
26 | * dram counter: consumption of the dram domain (servers only) | 26 | * dram counter: consumption of the dram domain (servers only) |
27 | * event: rapl_energy_dram | 27 | * event: rapl_energy_dram |
28 | * perf code: 0x3 | 28 | * perf code: 0x3 |
29 | * | 29 | * |
30 | * dram counter: consumption of the builtin-gpu domain (client only) | 30 | * dram counter: consumption of the builtin-gpu domain (client only) |
31 | * event: rapl_energy_gpu | 31 | * event: rapl_energy_gpu |
32 | * perf code: 0x4 | 32 | * perf code: 0x4 |
33 | * | 33 | * |
34 | * We manage those counters as free running (read-only). They may be | 34 | * We manage those counters as free running (read-only). They may be |
35 | * use simultaneously by other tools, such as turbostat. | 35 | * use simultaneously by other tools, such as turbostat. |
36 | * | 36 | * |
37 | * The events only support system-wide mode counting. There is no | 37 | * The events only support system-wide mode counting. There is no |
38 | * sampling support because it does not make sense and is not | 38 | * sampling support because it does not make sense and is not |
39 | * supported by the RAPL hardware. | 39 | * supported by the RAPL hardware. |
40 | * | 40 | * |
41 | * Because we want to avoid floating-point operations in the kernel, | 41 | * Because we want to avoid floating-point operations in the kernel, |
42 | * the events are all reported in fixed point arithmetic (32.32). | 42 | * the events are all reported in fixed point arithmetic (32.32). |
43 | * Tools must adjust the counts to convert them to Watts using | 43 | * Tools must adjust the counts to convert them to Watts using |
44 | * the duration of the measurement. Tools may use a function such as | 44 | * the duration of the measurement. Tools may use a function such as |
45 | * ldexp(raw_count, -32); | 45 | * ldexp(raw_count, -32); |
46 | */ | 46 | */ |
47 | #include <linux/module.h> | 47 | #include <linux/module.h> |
48 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
49 | #include <linux/perf_event.h> | 49 | #include <linux/perf_event.h> |
50 | #include <asm/cpu_device_id.h> | 50 | #include <asm/cpu_device_id.h> |
51 | #include "perf_event.h" | 51 | #include "perf_event.h" |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * RAPL energy status counters | 54 | * RAPL energy status counters |
55 | */ | 55 | */ |
56 | #define RAPL_IDX_PP0_NRG_STAT 0 /* all cores */ | 56 | #define RAPL_IDX_PP0_NRG_STAT 0 /* all cores */ |
57 | #define INTEL_RAPL_PP0 0x1 /* pseudo-encoding */ | 57 | #define INTEL_RAPL_PP0 0x1 /* pseudo-encoding */ |
58 | #define RAPL_IDX_PKG_NRG_STAT 1 /* entire package */ | 58 | #define RAPL_IDX_PKG_NRG_STAT 1 /* entire package */ |
59 | #define INTEL_RAPL_PKG 0x2 /* pseudo-encoding */ | 59 | #define INTEL_RAPL_PKG 0x2 /* pseudo-encoding */ |
60 | #define RAPL_IDX_RAM_NRG_STAT 2 /* DRAM */ | 60 | #define RAPL_IDX_RAM_NRG_STAT 2 /* DRAM */ |
61 | #define INTEL_RAPL_RAM 0x3 /* pseudo-encoding */ | 61 | #define INTEL_RAPL_RAM 0x3 /* pseudo-encoding */ |
62 | #define RAPL_IDX_PP1_NRG_STAT 3 /* gpu */ | 62 | #define RAPL_IDX_PP1_NRG_STAT 3 /* gpu */ |
63 | #define INTEL_RAPL_PP1 0x4 /* pseudo-encoding */ | 63 | #define INTEL_RAPL_PP1 0x4 /* pseudo-encoding */ |
64 | 64 | ||
65 | /* Clients have PP0, PKG */ | 65 | /* Clients have PP0, PKG */ |
66 | #define RAPL_IDX_CLN (1<<RAPL_IDX_PP0_NRG_STAT|\ | 66 | #define RAPL_IDX_CLN (1<<RAPL_IDX_PP0_NRG_STAT|\ |
67 | 1<<RAPL_IDX_PKG_NRG_STAT|\ | 67 | 1<<RAPL_IDX_PKG_NRG_STAT|\ |
68 | 1<<RAPL_IDX_PP1_NRG_STAT) | 68 | 1<<RAPL_IDX_PP1_NRG_STAT) |
69 | 69 | ||
70 | /* Servers have PP0, PKG, RAM */ | 70 | /* Servers have PP0, PKG, RAM */ |
71 | #define RAPL_IDX_SRV (1<<RAPL_IDX_PP0_NRG_STAT|\ | 71 | #define RAPL_IDX_SRV (1<<RAPL_IDX_PP0_NRG_STAT|\ |
72 | 1<<RAPL_IDX_PKG_NRG_STAT|\ | 72 | 1<<RAPL_IDX_PKG_NRG_STAT|\ |
73 | 1<<RAPL_IDX_RAM_NRG_STAT) | 73 | 1<<RAPL_IDX_RAM_NRG_STAT) |
74 | 74 | ||
75 | /* Servers have PP0, PKG, RAM, PP1 */ | 75 | /* Servers have PP0, PKG, RAM, PP1 */ |
76 | #define RAPL_IDX_HSW (1<<RAPL_IDX_PP0_NRG_STAT|\ | 76 | #define RAPL_IDX_HSW (1<<RAPL_IDX_PP0_NRG_STAT|\ |
77 | 1<<RAPL_IDX_PKG_NRG_STAT|\ | 77 | 1<<RAPL_IDX_PKG_NRG_STAT|\ |
78 | 1<<RAPL_IDX_RAM_NRG_STAT|\ | 78 | 1<<RAPL_IDX_RAM_NRG_STAT|\ |
79 | 1<<RAPL_IDX_PP1_NRG_STAT) | 79 | 1<<RAPL_IDX_PP1_NRG_STAT) |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * event code: LSB 8 bits, passed in attr->config | 82 | * event code: LSB 8 bits, passed in attr->config |
83 | * any other bit is reserved | 83 | * any other bit is reserved |
84 | */ | 84 | */ |
85 | #define RAPL_EVENT_MASK 0xFFULL | 85 | #define RAPL_EVENT_MASK 0xFFULL |
86 | 86 | ||
87 | #define DEFINE_RAPL_FORMAT_ATTR(_var, _name, _format) \ | 87 | #define DEFINE_RAPL_FORMAT_ATTR(_var, _name, _format) \ |
88 | static ssize_t __rapl_##_var##_show(struct kobject *kobj, \ | 88 | static ssize_t __rapl_##_var##_show(struct kobject *kobj, \ |
89 | struct kobj_attribute *attr, \ | 89 | struct kobj_attribute *attr, \ |
90 | char *page) \ | 90 | char *page) \ |
91 | { \ | 91 | { \ |
92 | BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ | 92 | BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ |
93 | return sprintf(page, _format "\n"); \ | 93 | return sprintf(page, _format "\n"); \ |
94 | } \ | 94 | } \ |
95 | static struct kobj_attribute format_attr_##_var = \ | 95 | static struct kobj_attribute format_attr_##_var = \ |
96 | __ATTR(_name, 0444, __rapl_##_var##_show, NULL) | 96 | __ATTR(_name, 0444, __rapl_##_var##_show, NULL) |
97 | 97 | ||
98 | #define RAPL_EVENT_DESC(_name, _config) \ | 98 | #define RAPL_EVENT_DESC(_name, _config) \ |
99 | { \ | 99 | { \ |
100 | .attr = __ATTR(_name, 0444, rapl_event_show, NULL), \ | 100 | .attr = __ATTR(_name, 0444, rapl_event_show, NULL), \ |
101 | .config = _config, \ | 101 | .config = _config, \ |
102 | } | 102 | } |
103 | 103 | ||
104 | #define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */ | 104 | #define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */ |
105 | 105 | ||
106 | #define RAPL_EVENT_ATTR_STR(_name, v, str) \ | ||
107 | static struct perf_pmu_events_attr event_attr_##v = { \ | ||
108 | .attr = __ATTR(_name, 0444, rapl_sysfs_show, NULL), \ | ||
109 | .id = 0, \ | ||
110 | .event_str = str, \ | ||
111 | }; | ||
112 | |||
106 | struct rapl_pmu { | 113 | struct rapl_pmu { |
107 | spinlock_t lock; | 114 | spinlock_t lock; |
108 | int hw_unit; /* 1/2^hw_unit Joule */ | 115 | int hw_unit; /* 1/2^hw_unit Joule */ |
109 | int n_active; /* number of active events */ | 116 | int n_active; /* number of active events */ |
110 | struct list_head active_list; | 117 | struct list_head active_list; |
111 | struct pmu *pmu; /* pointer to rapl_pmu_class */ | 118 | struct pmu *pmu; /* pointer to rapl_pmu_class */ |
112 | ktime_t timer_interval; /* in ktime_t unit */ | 119 | ktime_t timer_interval; /* in ktime_t unit */ |
113 | struct hrtimer hrtimer; | 120 | struct hrtimer hrtimer; |
114 | }; | 121 | }; |
115 | 122 | ||
116 | static struct pmu rapl_pmu_class; | 123 | static struct pmu rapl_pmu_class; |
117 | static cpumask_t rapl_cpu_mask; | 124 | static cpumask_t rapl_cpu_mask; |
118 | static int rapl_cntr_mask; | 125 | static int rapl_cntr_mask; |
119 | 126 | ||
120 | static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu); | 127 | static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu); |
121 | static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu_to_free); | 128 | static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu_to_free); |
122 | 129 | ||
123 | static inline u64 rapl_read_counter(struct perf_event *event) | 130 | static inline u64 rapl_read_counter(struct perf_event *event) |
124 | { | 131 | { |
125 | u64 raw; | 132 | u64 raw; |
126 | rdmsrl(event->hw.event_base, raw); | 133 | rdmsrl(event->hw.event_base, raw); |
127 | return raw; | 134 | return raw; |
128 | } | 135 | } |
129 | 136 | ||
130 | static inline u64 rapl_scale(u64 v) | 137 | static inline u64 rapl_scale(u64 v) |
131 | { | 138 | { |
132 | /* | 139 | /* |
133 | * scale delta to smallest unit (1/2^32) | 140 | * scale delta to smallest unit (1/2^32) |
134 | * users must then scale back: count * 1/(1e9*2^32) to get Joules | 141 | * users must then scale back: count * 1/(1e9*2^32) to get Joules |
135 | * or use ldexp(count, -32). | 142 | * or use ldexp(count, -32). |
136 | * Watts = Joules/Time delta | 143 | * Watts = Joules/Time delta |
137 | */ | 144 | */ |
138 | return v << (32 - __this_cpu_read(rapl_pmu->hw_unit)); | 145 | return v << (32 - __this_cpu_read(rapl_pmu->hw_unit)); |
139 | } | 146 | } |
140 | 147 | ||
141 | static u64 rapl_event_update(struct perf_event *event) | 148 | static u64 rapl_event_update(struct perf_event *event) |
142 | { | 149 | { |
143 | struct hw_perf_event *hwc = &event->hw; | 150 | struct hw_perf_event *hwc = &event->hw; |
144 | u64 prev_raw_count, new_raw_count; | 151 | u64 prev_raw_count, new_raw_count; |
145 | s64 delta, sdelta; | 152 | s64 delta, sdelta; |
146 | int shift = RAPL_CNTR_WIDTH; | 153 | int shift = RAPL_CNTR_WIDTH; |
147 | 154 | ||
148 | again: | 155 | again: |
149 | prev_raw_count = local64_read(&hwc->prev_count); | 156 | prev_raw_count = local64_read(&hwc->prev_count); |
150 | rdmsrl(event->hw.event_base, new_raw_count); | 157 | rdmsrl(event->hw.event_base, new_raw_count); |
151 | 158 | ||
152 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, | 159 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, |
153 | new_raw_count) != prev_raw_count) { | 160 | new_raw_count) != prev_raw_count) { |
154 | cpu_relax(); | 161 | cpu_relax(); |
155 | goto again; | 162 | goto again; |
156 | } | 163 | } |
157 | 164 | ||
158 | /* | 165 | /* |
159 | * Now we have the new raw value and have updated the prev | 166 | * Now we have the new raw value and have updated the prev |
160 | * timestamp already. We can now calculate the elapsed delta | 167 | * timestamp already. We can now calculate the elapsed delta |
161 | * (event-)time and add that to the generic event. | 168 | * (event-)time and add that to the generic event. |
162 | * | 169 | * |
163 | * Careful, not all hw sign-extends above the physical width | 170 | * Careful, not all hw sign-extends above the physical width |
164 | * of the count. | 171 | * of the count. |
165 | */ | 172 | */ |
166 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | 173 | delta = (new_raw_count << shift) - (prev_raw_count << shift); |
167 | delta >>= shift; | 174 | delta >>= shift; |
168 | 175 | ||
169 | sdelta = rapl_scale(delta); | 176 | sdelta = rapl_scale(delta); |
170 | 177 | ||
171 | local64_add(sdelta, &event->count); | 178 | local64_add(sdelta, &event->count); |
172 | 179 | ||
173 | return new_raw_count; | 180 | return new_raw_count; |
174 | } | 181 | } |
175 | 182 | ||
176 | static void rapl_start_hrtimer(struct rapl_pmu *pmu) | 183 | static void rapl_start_hrtimer(struct rapl_pmu *pmu) |
177 | { | 184 | { |
178 | __hrtimer_start_range_ns(&pmu->hrtimer, | 185 | __hrtimer_start_range_ns(&pmu->hrtimer, |
179 | pmu->timer_interval, 0, | 186 | pmu->timer_interval, 0, |
180 | HRTIMER_MODE_REL_PINNED, 0); | 187 | HRTIMER_MODE_REL_PINNED, 0); |
181 | } | 188 | } |
182 | 189 | ||
183 | static void rapl_stop_hrtimer(struct rapl_pmu *pmu) | 190 | static void rapl_stop_hrtimer(struct rapl_pmu *pmu) |
184 | { | 191 | { |
185 | hrtimer_cancel(&pmu->hrtimer); | 192 | hrtimer_cancel(&pmu->hrtimer); |
186 | } | 193 | } |
187 | 194 | ||
188 | static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer) | 195 | static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer) |
189 | { | 196 | { |
190 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); | 197 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); |
191 | struct perf_event *event; | 198 | struct perf_event *event; |
192 | unsigned long flags; | 199 | unsigned long flags; |
193 | 200 | ||
194 | if (!pmu->n_active) | 201 | if (!pmu->n_active) |
195 | return HRTIMER_NORESTART; | 202 | return HRTIMER_NORESTART; |
196 | 203 | ||
197 | spin_lock_irqsave(&pmu->lock, flags); | 204 | spin_lock_irqsave(&pmu->lock, flags); |
198 | 205 | ||
199 | list_for_each_entry(event, &pmu->active_list, active_entry) { | 206 | list_for_each_entry(event, &pmu->active_list, active_entry) { |
200 | rapl_event_update(event); | 207 | rapl_event_update(event); |
201 | } | 208 | } |
202 | 209 | ||
203 | spin_unlock_irqrestore(&pmu->lock, flags); | 210 | spin_unlock_irqrestore(&pmu->lock, flags); |
204 | 211 | ||
205 | hrtimer_forward_now(hrtimer, pmu->timer_interval); | 212 | hrtimer_forward_now(hrtimer, pmu->timer_interval); |
206 | 213 | ||
207 | return HRTIMER_RESTART; | 214 | return HRTIMER_RESTART; |
208 | } | 215 | } |
209 | 216 | ||
210 | static void rapl_hrtimer_init(struct rapl_pmu *pmu) | 217 | static void rapl_hrtimer_init(struct rapl_pmu *pmu) |
211 | { | 218 | { |
212 | struct hrtimer *hr = &pmu->hrtimer; | 219 | struct hrtimer *hr = &pmu->hrtimer; |
213 | 220 | ||
214 | hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 221 | hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
215 | hr->function = rapl_hrtimer_handle; | 222 | hr->function = rapl_hrtimer_handle; |
216 | } | 223 | } |
217 | 224 | ||
218 | static void __rapl_pmu_event_start(struct rapl_pmu *pmu, | 225 | static void __rapl_pmu_event_start(struct rapl_pmu *pmu, |
219 | struct perf_event *event) | 226 | struct perf_event *event) |
220 | { | 227 | { |
221 | if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) | 228 | if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) |
222 | return; | 229 | return; |
223 | 230 | ||
224 | event->hw.state = 0; | 231 | event->hw.state = 0; |
225 | 232 | ||
226 | list_add_tail(&event->active_entry, &pmu->active_list); | 233 | list_add_tail(&event->active_entry, &pmu->active_list); |
227 | 234 | ||
228 | local64_set(&event->hw.prev_count, rapl_read_counter(event)); | 235 | local64_set(&event->hw.prev_count, rapl_read_counter(event)); |
229 | 236 | ||
230 | pmu->n_active++; | 237 | pmu->n_active++; |
231 | if (pmu->n_active == 1) | 238 | if (pmu->n_active == 1) |
232 | rapl_start_hrtimer(pmu); | 239 | rapl_start_hrtimer(pmu); |
233 | } | 240 | } |
234 | 241 | ||
235 | static void rapl_pmu_event_start(struct perf_event *event, int mode) | 242 | static void rapl_pmu_event_start(struct perf_event *event, int mode) |
236 | { | 243 | { |
237 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); | 244 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); |
238 | unsigned long flags; | 245 | unsigned long flags; |
239 | 246 | ||
240 | spin_lock_irqsave(&pmu->lock, flags); | 247 | spin_lock_irqsave(&pmu->lock, flags); |
241 | __rapl_pmu_event_start(pmu, event); | 248 | __rapl_pmu_event_start(pmu, event); |
242 | spin_unlock_irqrestore(&pmu->lock, flags); | 249 | spin_unlock_irqrestore(&pmu->lock, flags); |
243 | } | 250 | } |
244 | 251 | ||
245 | static void rapl_pmu_event_stop(struct perf_event *event, int mode) | 252 | static void rapl_pmu_event_stop(struct perf_event *event, int mode) |
246 | { | 253 | { |
247 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); | 254 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); |
248 | struct hw_perf_event *hwc = &event->hw; | 255 | struct hw_perf_event *hwc = &event->hw; |
249 | unsigned long flags; | 256 | unsigned long flags; |
250 | 257 | ||
251 | spin_lock_irqsave(&pmu->lock, flags); | 258 | spin_lock_irqsave(&pmu->lock, flags); |
252 | 259 | ||
253 | /* mark event as deactivated and stopped */ | 260 | /* mark event as deactivated and stopped */ |
254 | if (!(hwc->state & PERF_HES_STOPPED)) { | 261 | if (!(hwc->state & PERF_HES_STOPPED)) { |
255 | WARN_ON_ONCE(pmu->n_active <= 0); | 262 | WARN_ON_ONCE(pmu->n_active <= 0); |
256 | pmu->n_active--; | 263 | pmu->n_active--; |
257 | if (pmu->n_active == 0) | 264 | if (pmu->n_active == 0) |
258 | rapl_stop_hrtimer(pmu); | 265 | rapl_stop_hrtimer(pmu); |
259 | 266 | ||
260 | list_del(&event->active_entry); | 267 | list_del(&event->active_entry); |
261 | 268 | ||
262 | WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); | 269 | WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); |
263 | hwc->state |= PERF_HES_STOPPED; | 270 | hwc->state |= PERF_HES_STOPPED; |
264 | } | 271 | } |
265 | 272 | ||
266 | /* check if update of sw counter is necessary */ | 273 | /* check if update of sw counter is necessary */ |
267 | if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { | 274 | if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { |
268 | /* | 275 | /* |
269 | * Drain the remaining delta count out of a event | 276 | * Drain the remaining delta count out of a event |
270 | * that we are disabling: | 277 | * that we are disabling: |
271 | */ | 278 | */ |
272 | rapl_event_update(event); | 279 | rapl_event_update(event); |
273 | hwc->state |= PERF_HES_UPTODATE; | 280 | hwc->state |= PERF_HES_UPTODATE; |
274 | } | 281 | } |
275 | 282 | ||
276 | spin_unlock_irqrestore(&pmu->lock, flags); | 283 | spin_unlock_irqrestore(&pmu->lock, flags); |
277 | } | 284 | } |
278 | 285 | ||
279 | static int rapl_pmu_event_add(struct perf_event *event, int mode) | 286 | static int rapl_pmu_event_add(struct perf_event *event, int mode) |
280 | { | 287 | { |
281 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); | 288 | struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); |
282 | struct hw_perf_event *hwc = &event->hw; | 289 | struct hw_perf_event *hwc = &event->hw; |
283 | unsigned long flags; | 290 | unsigned long flags; |
284 | 291 | ||
285 | spin_lock_irqsave(&pmu->lock, flags); | 292 | spin_lock_irqsave(&pmu->lock, flags); |
286 | 293 | ||
287 | hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; | 294 | hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; |
288 | 295 | ||
289 | if (mode & PERF_EF_START) | 296 | if (mode & PERF_EF_START) |
290 | __rapl_pmu_event_start(pmu, event); | 297 | __rapl_pmu_event_start(pmu, event); |
291 | 298 | ||
292 | spin_unlock_irqrestore(&pmu->lock, flags); | 299 | spin_unlock_irqrestore(&pmu->lock, flags); |
293 | 300 | ||
294 | return 0; | 301 | return 0; |
295 | } | 302 | } |
296 | 303 | ||
297 | static void rapl_pmu_event_del(struct perf_event *event, int flags) | 304 | static void rapl_pmu_event_del(struct perf_event *event, int flags) |
298 | { | 305 | { |
299 | rapl_pmu_event_stop(event, PERF_EF_UPDATE); | 306 | rapl_pmu_event_stop(event, PERF_EF_UPDATE); |
300 | } | 307 | } |
301 | 308 | ||
302 | static int rapl_pmu_event_init(struct perf_event *event) | 309 | static int rapl_pmu_event_init(struct perf_event *event) |
303 | { | 310 | { |
304 | u64 cfg = event->attr.config & RAPL_EVENT_MASK; | 311 | u64 cfg = event->attr.config & RAPL_EVENT_MASK; |
305 | int bit, msr, ret = 0; | 312 | int bit, msr, ret = 0; |
306 | 313 | ||
307 | /* only look at RAPL events */ | 314 | /* only look at RAPL events */ |
308 | if (event->attr.type != rapl_pmu_class.type) | 315 | if (event->attr.type != rapl_pmu_class.type) |
309 | return -ENOENT; | 316 | return -ENOENT; |
310 | 317 | ||
311 | /* check only supported bits are set */ | 318 | /* check only supported bits are set */ |
312 | if (event->attr.config & ~RAPL_EVENT_MASK) | 319 | if (event->attr.config & ~RAPL_EVENT_MASK) |
313 | return -EINVAL; | 320 | return -EINVAL; |
314 | 321 | ||
315 | /* | 322 | /* |
316 | * check event is known (determines counter) | 323 | * check event is known (determines counter) |
317 | */ | 324 | */ |
318 | switch (cfg) { | 325 | switch (cfg) { |
319 | case INTEL_RAPL_PP0: | 326 | case INTEL_RAPL_PP0: |
320 | bit = RAPL_IDX_PP0_NRG_STAT; | 327 | bit = RAPL_IDX_PP0_NRG_STAT; |
321 | msr = MSR_PP0_ENERGY_STATUS; | 328 | msr = MSR_PP0_ENERGY_STATUS; |
322 | break; | 329 | break; |
323 | case INTEL_RAPL_PKG: | 330 | case INTEL_RAPL_PKG: |
324 | bit = RAPL_IDX_PKG_NRG_STAT; | 331 | bit = RAPL_IDX_PKG_NRG_STAT; |
325 | msr = MSR_PKG_ENERGY_STATUS; | 332 | msr = MSR_PKG_ENERGY_STATUS; |
326 | break; | 333 | break; |
327 | case INTEL_RAPL_RAM: | 334 | case INTEL_RAPL_RAM: |
328 | bit = RAPL_IDX_RAM_NRG_STAT; | 335 | bit = RAPL_IDX_RAM_NRG_STAT; |
329 | msr = MSR_DRAM_ENERGY_STATUS; | 336 | msr = MSR_DRAM_ENERGY_STATUS; |
330 | break; | 337 | break; |
331 | case INTEL_RAPL_PP1: | 338 | case INTEL_RAPL_PP1: |
332 | bit = RAPL_IDX_PP1_NRG_STAT; | 339 | bit = RAPL_IDX_PP1_NRG_STAT; |
333 | msr = MSR_PP1_ENERGY_STATUS; | 340 | msr = MSR_PP1_ENERGY_STATUS; |
334 | break; | 341 | break; |
335 | default: | 342 | default: |
336 | return -EINVAL; | 343 | return -EINVAL; |
337 | } | 344 | } |
338 | /* check event supported */ | 345 | /* check event supported */ |
339 | if (!(rapl_cntr_mask & (1 << bit))) | 346 | if (!(rapl_cntr_mask & (1 << bit))) |
340 | return -EINVAL; | 347 | return -EINVAL; |
341 | 348 | ||
342 | /* unsupported modes and filters */ | 349 | /* unsupported modes and filters */ |
343 | if (event->attr.exclude_user || | 350 | if (event->attr.exclude_user || |
344 | event->attr.exclude_kernel || | 351 | event->attr.exclude_kernel || |
345 | event->attr.exclude_hv || | 352 | event->attr.exclude_hv || |
346 | event->attr.exclude_idle || | 353 | event->attr.exclude_idle || |
347 | event->attr.exclude_host || | 354 | event->attr.exclude_host || |
348 | event->attr.exclude_guest || | 355 | event->attr.exclude_guest || |
349 | event->attr.sample_period) /* no sampling */ | 356 | event->attr.sample_period) /* no sampling */ |
350 | return -EINVAL; | 357 | return -EINVAL; |
351 | 358 | ||
352 | /* must be done before validate_group */ | 359 | /* must be done before validate_group */ |
353 | event->hw.event_base = msr; | 360 | event->hw.event_base = msr; |
354 | event->hw.config = cfg; | 361 | event->hw.config = cfg; |
355 | event->hw.idx = bit; | 362 | event->hw.idx = bit; |
356 | 363 | ||
357 | return ret; | 364 | return ret; |
358 | } | 365 | } |
359 | 366 | ||
360 | static void rapl_pmu_event_read(struct perf_event *event) | 367 | static void rapl_pmu_event_read(struct perf_event *event) |
361 | { | 368 | { |
362 | rapl_event_update(event); | 369 | rapl_event_update(event); |
363 | } | 370 | } |
364 | 371 | ||
365 | static ssize_t rapl_get_attr_cpumask(struct device *dev, | 372 | static ssize_t rapl_get_attr_cpumask(struct device *dev, |
366 | struct device_attribute *attr, char *buf) | 373 | struct device_attribute *attr, char *buf) |
367 | { | 374 | { |
368 | return cpumap_print_to_pagebuf(true, buf, &rapl_cpu_mask); | 375 | return cpumap_print_to_pagebuf(true, buf, &rapl_cpu_mask); |
369 | } | 376 | } |
370 | 377 | ||
371 | static DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL); | 378 | static DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL); |
372 | 379 | ||
373 | static struct attribute *rapl_pmu_attrs[] = { | 380 | static struct attribute *rapl_pmu_attrs[] = { |
374 | &dev_attr_cpumask.attr, | 381 | &dev_attr_cpumask.attr, |
375 | NULL, | 382 | NULL, |
376 | }; | 383 | }; |
377 | 384 | ||
378 | static struct attribute_group rapl_pmu_attr_group = { | 385 | static struct attribute_group rapl_pmu_attr_group = { |
379 | .attrs = rapl_pmu_attrs, | 386 | .attrs = rapl_pmu_attrs, |
380 | }; | 387 | }; |
381 | 388 | ||
382 | EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01"); | 389 | static ssize_t rapl_sysfs_show(struct device *dev, |
383 | EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02"); | 390 | struct device_attribute *attr, |
384 | EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03"); | 391 | char *page) |
385 | EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04"); | 392 | { |
393 | struct perf_pmu_events_attr *pmu_attr = \ | ||
394 | container_of(attr, struct perf_pmu_events_attr, attr); | ||
386 | 395 | ||
387 | EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules"); | 396 | if (pmu_attr->event_str) |
388 | EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules"); | 397 | return sprintf(page, "%s", pmu_attr->event_str); |
389 | EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules"); | ||
390 | EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules"); | ||
391 | 398 | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01"); | ||
403 | RAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02"); | ||
404 | RAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03"); | ||
405 | RAPL_EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04"); | ||
406 | |||
407 | RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules"); | ||
408 | RAPL_EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules"); | ||
409 | RAPL_EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules"); | ||
410 | RAPL_EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules"); | ||
411 | |||
392 | /* | 412 | /* |
393 | * we compute in 0.23 nJ increments regardless of MSR | 413 | * we compute in 0.23 nJ increments regardless of MSR |
394 | */ | 414 | */ |
395 | EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10"); | 415 | RAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10"); |
396 | EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10"); | 416 | RAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10"); |
397 | EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10"); | 417 | RAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10"); |
398 | EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10"); | 418 | RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10"); |
399 | 419 | ||
400 | static struct attribute *rapl_events_srv_attr[] = { | 420 | static struct attribute *rapl_events_srv_attr[] = { |
401 | EVENT_PTR(rapl_cores), | 421 | EVENT_PTR(rapl_cores), |
402 | EVENT_PTR(rapl_pkg), | 422 | EVENT_PTR(rapl_pkg), |
403 | EVENT_PTR(rapl_ram), | 423 | EVENT_PTR(rapl_ram), |
404 | 424 | ||
405 | EVENT_PTR(rapl_cores_unit), | 425 | EVENT_PTR(rapl_cores_unit), |
406 | EVENT_PTR(rapl_pkg_unit), | 426 | EVENT_PTR(rapl_pkg_unit), |
407 | EVENT_PTR(rapl_ram_unit), | 427 | EVENT_PTR(rapl_ram_unit), |
408 | 428 | ||
409 | EVENT_PTR(rapl_cores_scale), | 429 | EVENT_PTR(rapl_cores_scale), |
410 | EVENT_PTR(rapl_pkg_scale), | 430 | EVENT_PTR(rapl_pkg_scale), |
411 | EVENT_PTR(rapl_ram_scale), | 431 | EVENT_PTR(rapl_ram_scale), |
412 | NULL, | 432 | NULL, |
413 | }; | 433 | }; |
414 | 434 | ||
415 | static struct attribute *rapl_events_cln_attr[] = { | 435 | static struct attribute *rapl_events_cln_attr[] = { |
416 | EVENT_PTR(rapl_cores), | 436 | EVENT_PTR(rapl_cores), |
417 | EVENT_PTR(rapl_pkg), | 437 | EVENT_PTR(rapl_pkg), |
418 | EVENT_PTR(rapl_gpu), | 438 | EVENT_PTR(rapl_gpu), |
419 | 439 | ||
420 | EVENT_PTR(rapl_cores_unit), | 440 | EVENT_PTR(rapl_cores_unit), |
421 | EVENT_PTR(rapl_pkg_unit), | 441 | EVENT_PTR(rapl_pkg_unit), |
422 | EVENT_PTR(rapl_gpu_unit), | 442 | EVENT_PTR(rapl_gpu_unit), |
423 | 443 | ||
424 | EVENT_PTR(rapl_cores_scale), | 444 | EVENT_PTR(rapl_cores_scale), |
425 | EVENT_PTR(rapl_pkg_scale), | 445 | EVENT_PTR(rapl_pkg_scale), |
426 | EVENT_PTR(rapl_gpu_scale), | 446 | EVENT_PTR(rapl_gpu_scale), |
427 | NULL, | 447 | NULL, |
428 | }; | 448 | }; |
429 | 449 | ||
430 | static struct attribute *rapl_events_hsw_attr[] = { | 450 | static struct attribute *rapl_events_hsw_attr[] = { |
431 | EVENT_PTR(rapl_cores), | 451 | EVENT_PTR(rapl_cores), |
432 | EVENT_PTR(rapl_pkg), | 452 | EVENT_PTR(rapl_pkg), |
433 | EVENT_PTR(rapl_gpu), | 453 | EVENT_PTR(rapl_gpu), |
434 | EVENT_PTR(rapl_ram), | 454 | EVENT_PTR(rapl_ram), |
435 | 455 | ||
436 | EVENT_PTR(rapl_cores_unit), | 456 | EVENT_PTR(rapl_cores_unit), |
437 | EVENT_PTR(rapl_pkg_unit), | 457 | EVENT_PTR(rapl_pkg_unit), |
438 | EVENT_PTR(rapl_gpu_unit), | 458 | EVENT_PTR(rapl_gpu_unit), |
439 | EVENT_PTR(rapl_ram_unit), | 459 | EVENT_PTR(rapl_ram_unit), |
440 | 460 | ||
441 | EVENT_PTR(rapl_cores_scale), | 461 | EVENT_PTR(rapl_cores_scale), |
442 | EVENT_PTR(rapl_pkg_scale), | 462 | EVENT_PTR(rapl_pkg_scale), |
443 | EVENT_PTR(rapl_gpu_scale), | 463 | EVENT_PTR(rapl_gpu_scale), |
444 | EVENT_PTR(rapl_ram_scale), | 464 | EVENT_PTR(rapl_ram_scale), |
445 | NULL, | 465 | NULL, |
446 | }; | 466 | }; |
447 | 467 | ||
448 | static struct attribute_group rapl_pmu_events_group = { | 468 | static struct attribute_group rapl_pmu_events_group = { |
449 | .name = "events", | 469 | .name = "events", |
450 | .attrs = NULL, /* patched at runtime */ | 470 | .attrs = NULL, /* patched at runtime */ |
451 | }; | 471 | }; |
452 | 472 | ||
453 | DEFINE_RAPL_FORMAT_ATTR(event, event, "config:0-7"); | 473 | DEFINE_RAPL_FORMAT_ATTR(event, event, "config:0-7"); |
454 | static struct attribute *rapl_formats_attr[] = { | 474 | static struct attribute *rapl_formats_attr[] = { |
455 | &format_attr_event.attr, | 475 | &format_attr_event.attr, |
456 | NULL, | 476 | NULL, |
457 | }; | 477 | }; |
458 | 478 | ||
459 | static struct attribute_group rapl_pmu_format_group = { | 479 | static struct attribute_group rapl_pmu_format_group = { |
460 | .name = "format", | 480 | .name = "format", |
461 | .attrs = rapl_formats_attr, | 481 | .attrs = rapl_formats_attr, |
462 | }; | 482 | }; |
463 | 483 | ||
464 | const struct attribute_group *rapl_attr_groups[] = { | 484 | const struct attribute_group *rapl_attr_groups[] = { |
465 | &rapl_pmu_attr_group, | 485 | &rapl_pmu_attr_group, |
466 | &rapl_pmu_format_group, | 486 | &rapl_pmu_format_group, |
467 | &rapl_pmu_events_group, | 487 | &rapl_pmu_events_group, |
468 | NULL, | 488 | NULL, |
469 | }; | 489 | }; |
470 | 490 | ||
471 | static struct pmu rapl_pmu_class = { | 491 | static struct pmu rapl_pmu_class = { |
472 | .attr_groups = rapl_attr_groups, | 492 | .attr_groups = rapl_attr_groups, |
473 | .task_ctx_nr = perf_invalid_context, /* system-wide only */ | 493 | .task_ctx_nr = perf_invalid_context, /* system-wide only */ |
474 | .event_init = rapl_pmu_event_init, | 494 | .event_init = rapl_pmu_event_init, |
475 | .add = rapl_pmu_event_add, /* must have */ | 495 | .add = rapl_pmu_event_add, /* must have */ |
476 | .del = rapl_pmu_event_del, /* must have */ | 496 | .del = rapl_pmu_event_del, /* must have */ |
477 | .start = rapl_pmu_event_start, | 497 | .start = rapl_pmu_event_start, |
478 | .stop = rapl_pmu_event_stop, | 498 | .stop = rapl_pmu_event_stop, |
479 | .read = rapl_pmu_event_read, | 499 | .read = rapl_pmu_event_read, |
480 | }; | 500 | }; |
481 | 501 | ||
482 | static void rapl_cpu_exit(int cpu) | 502 | static void rapl_cpu_exit(int cpu) |
483 | { | 503 | { |
484 | struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu); | 504 | struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu); |
485 | int i, phys_id = topology_physical_package_id(cpu); | 505 | int i, phys_id = topology_physical_package_id(cpu); |
486 | int target = -1; | 506 | int target = -1; |
487 | 507 | ||
488 | /* find a new cpu on same package */ | 508 | /* find a new cpu on same package */ |
489 | for_each_online_cpu(i) { | 509 | for_each_online_cpu(i) { |
490 | if (i == cpu) | 510 | if (i == cpu) |
491 | continue; | 511 | continue; |
492 | if (phys_id == topology_physical_package_id(i)) { | 512 | if (phys_id == topology_physical_package_id(i)) { |
493 | target = i; | 513 | target = i; |
494 | break; | 514 | break; |
495 | } | 515 | } |
496 | } | 516 | } |
497 | /* | 517 | /* |
498 | * clear cpu from cpumask | 518 | * clear cpu from cpumask |
499 | * if was set in cpumask and still some cpu on package, | 519 | * if was set in cpumask and still some cpu on package, |
500 | * then move to new cpu | 520 | * then move to new cpu |
501 | */ | 521 | */ |
502 | if (cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask) && target >= 0) | 522 | if (cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask) && target >= 0) |
503 | cpumask_set_cpu(target, &rapl_cpu_mask); | 523 | cpumask_set_cpu(target, &rapl_cpu_mask); |
504 | 524 | ||
505 | WARN_ON(cpumask_empty(&rapl_cpu_mask)); | 525 | WARN_ON(cpumask_empty(&rapl_cpu_mask)); |
506 | /* | 526 | /* |
507 | * migrate events and context to new cpu | 527 | * migrate events and context to new cpu |
508 | */ | 528 | */ |
509 | if (target >= 0) | 529 | if (target >= 0) |
510 | perf_pmu_migrate_context(pmu->pmu, cpu, target); | 530 | perf_pmu_migrate_context(pmu->pmu, cpu, target); |
511 | 531 | ||
512 | /* cancel overflow polling timer for CPU */ | 532 | /* cancel overflow polling timer for CPU */ |
513 | rapl_stop_hrtimer(pmu); | 533 | rapl_stop_hrtimer(pmu); |
514 | } | 534 | } |
515 | 535 | ||
516 | static void rapl_cpu_init(int cpu) | 536 | static void rapl_cpu_init(int cpu) |
517 | { | 537 | { |
518 | int i, phys_id = topology_physical_package_id(cpu); | 538 | int i, phys_id = topology_physical_package_id(cpu); |
519 | 539 | ||
520 | /* check if phys_is is already covered */ | 540 | /* check if phys_is is already covered */ |
521 | for_each_cpu(i, &rapl_cpu_mask) { | 541 | for_each_cpu(i, &rapl_cpu_mask) { |
522 | if (phys_id == topology_physical_package_id(i)) | 542 | if (phys_id == topology_physical_package_id(i)) |
523 | return; | 543 | return; |
524 | } | 544 | } |
525 | /* was not found, so add it */ | 545 | /* was not found, so add it */ |
526 | cpumask_set_cpu(cpu, &rapl_cpu_mask); | 546 | cpumask_set_cpu(cpu, &rapl_cpu_mask); |
527 | } | 547 | } |
528 | 548 | ||
529 | static int rapl_cpu_prepare(int cpu) | 549 | static int rapl_cpu_prepare(int cpu) |
530 | { | 550 | { |
531 | struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu); | 551 | struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu); |
532 | int phys_id = topology_physical_package_id(cpu); | 552 | int phys_id = topology_physical_package_id(cpu); |
533 | u64 ms; | 553 | u64 ms; |
534 | u64 msr_rapl_power_unit_bits; | 554 | u64 msr_rapl_power_unit_bits; |
535 | 555 | ||
536 | if (pmu) | 556 | if (pmu) |
537 | return 0; | 557 | return 0; |
538 | 558 | ||
539 | if (phys_id < 0) | 559 | if (phys_id < 0) |
540 | return -1; | 560 | return -1; |
541 | 561 | ||
542 | /* protect rdmsrl() to handle virtualization */ | 562 | /* protect rdmsrl() to handle virtualization */ |
543 | if (rdmsrl_safe(MSR_RAPL_POWER_UNIT, &msr_rapl_power_unit_bits)) | 563 | if (rdmsrl_safe(MSR_RAPL_POWER_UNIT, &msr_rapl_power_unit_bits)) |
544 | return -1; | 564 | return -1; |
545 | 565 | ||
546 | pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu)); | 566 | pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu)); |
547 | if (!pmu) | 567 | if (!pmu) |
548 | return -1; | 568 | return -1; |
549 | 569 | ||
550 | spin_lock_init(&pmu->lock); | 570 | spin_lock_init(&pmu->lock); |
551 | 571 | ||
552 | INIT_LIST_HEAD(&pmu->active_list); | 572 | INIT_LIST_HEAD(&pmu->active_list); |
553 | 573 | ||
554 | /* | 574 | /* |
555 | * grab power unit as: 1/2^unit Joules | 575 | * grab power unit as: 1/2^unit Joules |
556 | * | 576 | * |
557 | * we cache in local PMU instance | 577 | * we cache in local PMU instance |
558 | */ | 578 | */ |
559 | pmu->hw_unit = (msr_rapl_power_unit_bits >> 8) & 0x1FULL; | 579 | pmu->hw_unit = (msr_rapl_power_unit_bits >> 8) & 0x1FULL; |
560 | pmu->pmu = &rapl_pmu_class; | 580 | pmu->pmu = &rapl_pmu_class; |
561 | 581 | ||
562 | /* | 582 | /* |
563 | * use reference of 200W for scaling the timeout | 583 | * use reference of 200W for scaling the timeout |
564 | * to avoid missing counter overflows. | 584 | * to avoid missing counter overflows. |
565 | * 200W = 200 Joules/sec | 585 | * 200W = 200 Joules/sec |
566 | * divide interval by 2 to avoid lockstep (2 * 100) | 586 | * divide interval by 2 to avoid lockstep (2 * 100) |
567 | * if hw unit is 32, then we use 2 ms 1/200/2 | 587 | * if hw unit is 32, then we use 2 ms 1/200/2 |
568 | */ | 588 | */ |
569 | if (pmu->hw_unit < 32) | 589 | if (pmu->hw_unit < 32) |
570 | ms = (1000 / (2 * 100)) * (1ULL << (32 - pmu->hw_unit - 1)); | 590 | ms = (1000 / (2 * 100)) * (1ULL << (32 - pmu->hw_unit - 1)); |
571 | else | 591 | else |
572 | ms = 2; | 592 | ms = 2; |
573 | 593 | ||
574 | pmu->timer_interval = ms_to_ktime(ms); | 594 | pmu->timer_interval = ms_to_ktime(ms); |
575 | 595 | ||
576 | rapl_hrtimer_init(pmu); | 596 | rapl_hrtimer_init(pmu); |
577 | 597 | ||
578 | /* set RAPL pmu for this cpu for now */ | 598 | /* set RAPL pmu for this cpu for now */ |
579 | per_cpu(rapl_pmu, cpu) = pmu; | 599 | per_cpu(rapl_pmu, cpu) = pmu; |
580 | per_cpu(rapl_pmu_to_free, cpu) = NULL; | 600 | per_cpu(rapl_pmu_to_free, cpu) = NULL; |
581 | 601 | ||
582 | return 0; | 602 | return 0; |
583 | } | 603 | } |
584 | 604 | ||
585 | static void rapl_cpu_kfree(int cpu) | 605 | static void rapl_cpu_kfree(int cpu) |
586 | { | 606 | { |
587 | struct rapl_pmu *pmu = per_cpu(rapl_pmu_to_free, cpu); | 607 | struct rapl_pmu *pmu = per_cpu(rapl_pmu_to_free, cpu); |
588 | 608 | ||
589 | kfree(pmu); | 609 | kfree(pmu); |
590 | 610 | ||
591 | per_cpu(rapl_pmu_to_free, cpu) = NULL; | 611 | per_cpu(rapl_pmu_to_free, cpu) = NULL; |
592 | } | 612 | } |
593 | 613 | ||
594 | static int rapl_cpu_dying(int cpu) | 614 | static int rapl_cpu_dying(int cpu) |
595 | { | 615 | { |
596 | struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu); | 616 | struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu); |
597 | 617 | ||
598 | if (!pmu) | 618 | if (!pmu) |
599 | return 0; | 619 | return 0; |
600 | 620 | ||
601 | per_cpu(rapl_pmu, cpu) = NULL; | 621 | per_cpu(rapl_pmu, cpu) = NULL; |
602 | 622 | ||
603 | per_cpu(rapl_pmu_to_free, cpu) = pmu; | 623 | per_cpu(rapl_pmu_to_free, cpu) = pmu; |
604 | 624 | ||
605 | return 0; | 625 | return 0; |
606 | } | 626 | } |
607 | 627 | ||
608 | static int rapl_cpu_notifier(struct notifier_block *self, | 628 | static int rapl_cpu_notifier(struct notifier_block *self, |
609 | unsigned long action, void *hcpu) | 629 | unsigned long action, void *hcpu) |
610 | { | 630 | { |
611 | unsigned int cpu = (long)hcpu; | 631 | unsigned int cpu = (long)hcpu; |
612 | 632 | ||
613 | switch (action & ~CPU_TASKS_FROZEN) { | 633 | switch (action & ~CPU_TASKS_FROZEN) { |
614 | case CPU_UP_PREPARE: | 634 | case CPU_UP_PREPARE: |
615 | rapl_cpu_prepare(cpu); | 635 | rapl_cpu_prepare(cpu); |
616 | break; | 636 | break; |
617 | case CPU_STARTING: | 637 | case CPU_STARTING: |
618 | rapl_cpu_init(cpu); | 638 | rapl_cpu_init(cpu); |
619 | break; | 639 | break; |
620 | case CPU_UP_CANCELED: | 640 | case CPU_UP_CANCELED: |
621 | case CPU_DYING: | 641 | case CPU_DYING: |
622 | rapl_cpu_dying(cpu); | 642 | rapl_cpu_dying(cpu); |
623 | break; | 643 | break; |
624 | case CPU_ONLINE: | 644 | case CPU_ONLINE: |
625 | case CPU_DEAD: | 645 | case CPU_DEAD: |
626 | rapl_cpu_kfree(cpu); | 646 | rapl_cpu_kfree(cpu); |
627 | break; | 647 | break; |
628 | case CPU_DOWN_PREPARE: | 648 | case CPU_DOWN_PREPARE: |
629 | rapl_cpu_exit(cpu); | 649 | rapl_cpu_exit(cpu); |
630 | break; | 650 | break; |
631 | default: | 651 | default: |
632 | break; | 652 | break; |
633 | } | 653 | } |
634 | 654 | ||
635 | return NOTIFY_OK; | 655 | return NOTIFY_OK; |
636 | } | 656 | } |
637 | 657 | ||
638 | static const struct x86_cpu_id rapl_cpu_match[] = { | 658 | static const struct x86_cpu_id rapl_cpu_match[] = { |
639 | [0] = { .vendor = X86_VENDOR_INTEL, .family = 6 }, | 659 | [0] = { .vendor = X86_VENDOR_INTEL, .family = 6 }, |
640 | [1] = {}, | 660 | [1] = {}, |
641 | }; | 661 | }; |
642 | 662 | ||
643 | static int __init rapl_pmu_init(void) | 663 | static int __init rapl_pmu_init(void) |
644 | { | 664 | { |
645 | struct rapl_pmu *pmu; | 665 | struct rapl_pmu *pmu; |
646 | int cpu, ret; | 666 | int cpu, ret; |
647 | 667 | ||
648 | /* | 668 | /* |
649 | * check for Intel processor family 6 | 669 | * check for Intel processor family 6 |
650 | */ | 670 | */ |
651 | if (!x86_match_cpu(rapl_cpu_match)) | 671 | if (!x86_match_cpu(rapl_cpu_match)) |
652 | return 0; | 672 | return 0; |
653 | 673 | ||
654 | /* check supported CPU */ | 674 | /* check supported CPU */ |
655 | switch (boot_cpu_data.x86_model) { | 675 | switch (boot_cpu_data.x86_model) { |
656 | case 42: /* Sandy Bridge */ | 676 | case 42: /* Sandy Bridge */ |
657 | case 58: /* Ivy Bridge */ | 677 | case 58: /* Ivy Bridge */ |
658 | rapl_cntr_mask = RAPL_IDX_CLN; | 678 | rapl_cntr_mask = RAPL_IDX_CLN; |
659 | rapl_pmu_events_group.attrs = rapl_events_cln_attr; | 679 | rapl_pmu_events_group.attrs = rapl_events_cln_attr; |
660 | break; | 680 | break; |
661 | case 60: /* Haswell */ | 681 | case 60: /* Haswell */ |
662 | case 69: /* Haswell-Celeron */ | 682 | case 69: /* Haswell-Celeron */ |
663 | rapl_cntr_mask = RAPL_IDX_HSW; | 683 | rapl_cntr_mask = RAPL_IDX_HSW; |
664 | rapl_pmu_events_group.attrs = rapl_events_hsw_attr; | 684 | rapl_pmu_events_group.attrs = rapl_events_hsw_attr; |
665 | break; | 685 | break; |
666 | case 45: /* Sandy Bridge-EP */ | 686 | case 45: /* Sandy Bridge-EP */ |
667 | case 62: /* IvyTown */ | 687 | case 62: /* IvyTown */ |
668 | rapl_cntr_mask = RAPL_IDX_SRV; | 688 | rapl_cntr_mask = RAPL_IDX_SRV; |
669 | rapl_pmu_events_group.attrs = rapl_events_srv_attr; | 689 | rapl_pmu_events_group.attrs = rapl_events_srv_attr; |
670 | break; | 690 | break; |
671 | 691 | ||
672 | default: | 692 | default: |
673 | /* unsupported */ | 693 | /* unsupported */ |
674 | return 0; | 694 | return 0; |
675 | } | 695 | } |
676 | 696 | ||
677 | cpu_notifier_register_begin(); | 697 | cpu_notifier_register_begin(); |
678 | 698 | ||
679 | for_each_online_cpu(cpu) { | 699 | for_each_online_cpu(cpu) { |
680 | ret = rapl_cpu_prepare(cpu); | 700 | ret = rapl_cpu_prepare(cpu); |
681 | if (ret) | 701 | if (ret) |
682 | goto out; | 702 | goto out; |
683 | rapl_cpu_init(cpu); | 703 | rapl_cpu_init(cpu); |
684 | } | 704 | } |
685 | 705 | ||
686 | __perf_cpu_notifier(rapl_cpu_notifier); | 706 | __perf_cpu_notifier(rapl_cpu_notifier); |
687 | 707 | ||
688 | ret = perf_pmu_register(&rapl_pmu_class, "power", -1); | 708 | ret = perf_pmu_register(&rapl_pmu_class, "power", -1); |
689 | if (WARN_ON(ret)) { | 709 | if (WARN_ON(ret)) { |
690 | pr_info("RAPL PMU detected, registration failed (%d), RAPL PMU disabled\n", ret); | 710 | pr_info("RAPL PMU detected, registration failed (%d), RAPL PMU disabled\n", ret); |
691 | cpu_notifier_register_done(); | 711 | cpu_notifier_register_done(); |
692 | return -1; | 712 | return -1; |
693 | } | 713 | } |
694 | 714 | ||
695 | pmu = __this_cpu_read(rapl_pmu); | 715 | pmu = __this_cpu_read(rapl_pmu); |
696 | 716 | ||
697 | pr_info("RAPL PMU detected, hw unit 2^-%d Joules," | 717 | pr_info("RAPL PMU detected, hw unit 2^-%d Joules," |
698 | " API unit is 2^-32 Joules," | 718 | " API unit is 2^-32 Joules," |
699 | " %d fixed counters" | 719 | " %d fixed counters" |
700 | " %llu ms ovfl timer\n", | 720 | " %llu ms ovfl timer\n", |
701 | pmu->hw_unit, | 721 | pmu->hw_unit, |
702 | hweight32(rapl_cntr_mask), | 722 | hweight32(rapl_cntr_mask), |
703 | ktime_to_ms(pmu->timer_interval)); | 723 | ktime_to_ms(pmu->timer_interval)); |
704 | 724 | ||
705 | out: | 725 | out: |
706 | cpu_notifier_register_done(); | 726 | cpu_notifier_register_done(); |
707 | 727 | ||
708 | return 0; | 728 | return 0; |
709 | } | 729 | } |
tools/include/asm-generic/bitops.h
1 | #ifndef __TOOLS_ASM_GENERIC_BITOPS_H | 1 | #ifndef __TOOLS_ASM_GENERIC_BITOPS_H |
2 | #define __TOOLS_ASM_GENERIC_BITOPS_H | 2 | #define __TOOLS_ASM_GENERIC_BITOPS_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * tools/ copied this from include/asm-generic/bitops.h, bit by bit as it needed | 5 | * tools/ copied this from include/asm-generic/bitops.h, bit by bit as it needed |
6 | * some functions. | 6 | * some functions. |
7 | * | 7 | * |
8 | * For the benefit of those who are trying to port Linux to another | 8 | * For the benefit of those who are trying to port Linux to another |
9 | * architecture, here are some C-language equivalents. You should | 9 | * architecture, here are some C-language equivalents. You should |
10 | * recode these in the native assembly language, if at all possible. | 10 | * recode these in the native assembly language, if at all possible. |
11 | * | 11 | * |
12 | * C language equivalents written by Theodore Ts'o, 9/26/92 | 12 | * C language equivalents written by Theodore Ts'o, 9/26/92 |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <asm-generic/bitops/__ffs.h> | 15 | #include <asm-generic/bitops/__ffs.h> |
16 | #include <asm-generic/bitops/fls.h> | 16 | #include <asm-generic/bitops/fls.h> |
17 | #include <asm-generic/bitops/__fls.h> | 17 | #include <asm-generic/bitops/__fls.h> |
18 | #include <asm-generic/bitops/fls64.h> | 18 | #include <asm-generic/bitops/fls64.h> |
19 | #include <asm-generic/bitops/find.h> | 19 | #include <asm-generic/bitops/find.h> |
20 | 20 | ||
21 | #ifndef _TOOLS_LINUX_BITOPS_H_ | 21 | #ifndef _TOOLS_LINUX_BITOPS_H_ |
22 | #error only <linux/bitops.h> can be included directly | 22 | #error only <linux/bitops.h> can be included directly |
23 | #endif | 23 | #endif |
24 | 24 | ||
25 | #include <asm-generic/bitops/hweight.h> | ||
26 | |||
25 | #include <asm-generic/bitops/atomic.h> | 27 | #include <asm-generic/bitops/atomic.h> |
26 | 28 | ||
27 | #endif /* __TOOLS_ASM_GENERIC_BITOPS_H */ | 29 | #endif /* __TOOLS_ASM_GENERIC_BITOPS_H */ |
28 | 30 |
tools/include/asm-generic/bitops/arch_hweight.h
File was created | 1 | #include "../../../../include/asm-generic/bitops/arch_hweight.h" | |
2 |
tools/include/asm-generic/bitops/const_hweight.h
File was created | 1 | #include "../../../../include/asm-generic/bitops/const_hweight.h" | |
2 |
tools/include/asm-generic/bitops/hweight.h
File was created | 1 | #ifndef _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ | |
2 | #define _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ | ||
3 | |||
4 | #include <asm-generic/bitops/arch_hweight.h> | ||
5 | #include <asm-generic/bitops/const_hweight.h> | ||
6 | |||
7 | #endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ */ | ||
8 |
tools/include/linux/bitops.h
1 | #ifndef _TOOLS_LINUX_BITOPS_H_ | 1 | #ifndef _TOOLS_LINUX_BITOPS_H_ |
2 | #define _TOOLS_LINUX_BITOPS_H_ | 2 | #define _TOOLS_LINUX_BITOPS_H_ |
3 | 3 | ||
4 | #include <asm/types.h> | ||
4 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
5 | #include <linux/compiler.h> | 6 | #include <linux/compiler.h> |
6 | #include <asm/hweight.h> | ||
7 | 7 | ||
8 | #ifndef __WORDSIZE | 8 | #ifndef __WORDSIZE |
9 | #define __WORDSIZE (__SIZEOF_LONG__ * 8) | 9 | #define __WORDSIZE (__SIZEOF_LONG__ * 8) |
10 | #endif | 10 | #endif |
11 | 11 | ||
12 | #define BITS_PER_LONG __WORDSIZE | 12 | #define BITS_PER_LONG __WORDSIZE |
13 | 13 | ||
14 | #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) | 14 | #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) |
15 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) | 15 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) |
16 | #define BITS_PER_BYTE 8 | 16 | #define BITS_PER_BYTE 8 |
17 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | 17 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) |
18 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) | 18 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) |
19 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) | 19 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) |
20 | #define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) | 20 | #define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) |
21 | |||
22 | extern unsigned int __sw_hweight8(unsigned int w); | ||
23 | extern unsigned int __sw_hweight16(unsigned int w); | ||
24 | extern unsigned int __sw_hweight32(unsigned int w); | ||
25 | extern unsigned long __sw_hweight64(__u64 w); | ||
21 | 26 | ||
22 | /* | 27 | /* |
23 | * Include this here because some architectures need generic_ffs/fls in | 28 | * Include this here because some architectures need generic_ffs/fls in |
24 | * scope | 29 | * scope |
25 | * | 30 | * |
26 | * XXX: this needs to be asm/bitops.h, when we get to per arch optimizations | 31 | * XXX: this needs to be asm/bitops.h, when we get to per arch optimizations |
27 | */ | 32 | */ |
28 | #include <asm-generic/bitops.h> | 33 | #include <asm-generic/bitops.h> |
29 | 34 | ||
30 | #define for_each_set_bit(bit, addr, size) \ | 35 | #define for_each_set_bit(bit, addr, size) \ |
31 | for ((bit) = find_first_bit((addr), (size)); \ | 36 | for ((bit) = find_first_bit((addr), (size)); \ |
32 | (bit) < (size); \ | 37 | (bit) < (size); \ |
33 | (bit) = find_next_bit((addr), (size), (bit) + 1)) | 38 | (bit) = find_next_bit((addr), (size), (bit) + 1)) |
34 | 39 | ||
35 | /* same as for_each_set_bit() but use bit as value to start with */ | 40 | /* same as for_each_set_bit() but use bit as value to start with */ |
36 | #define for_each_set_bit_from(bit, addr, size) \ | 41 | #define for_each_set_bit_from(bit, addr, size) \ |
37 | for ((bit) = find_next_bit((addr), (size), (bit)); \ | 42 | for ((bit) = find_next_bit((addr), (size), (bit)); \ |
38 | (bit) < (size); \ | 43 | (bit) < (size); \ |
39 | (bit) = find_next_bit((addr), (size), (bit) + 1)) | 44 | (bit) = find_next_bit((addr), (size), (bit) + 1)) |
40 | 45 | ||
41 | static inline unsigned long hweight_long(unsigned long w) | 46 | static inline unsigned long hweight_long(unsigned long w) |
42 | { | 47 | { |
43 | return sizeof(w) == 4 ? hweight32(w) : hweight64(w); | 48 | return sizeof(w) == 4 ? hweight32(w) : hweight64(w); |
44 | } | 49 | } |
45 | 50 | ||
46 | static inline unsigned fls_long(unsigned long l) | 51 | static inline unsigned fls_long(unsigned long l) |
47 | { | 52 | { |
48 | if (sizeof(l) == 4) | 53 | if (sizeof(l) == 4) |
49 | return fls(l); | 54 | return fls(l); |
50 | return fls64(l); | 55 | return fls64(l); |
51 | } | 56 | } |
52 | 57 | ||
53 | #endif | 58 | #endif |
tools/lib/api/fs/debugfs.c
1 | #include <errno.h> | 1 | #include <errno.h> |
2 | #include <stdio.h> | 2 | #include <stdio.h> |
3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
4 | #include <string.h> | 4 | #include <string.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include <sys/vfs.h> | 6 | #include <sys/vfs.h> |
7 | #include <sys/mount.h> | 7 | #include <sys/mount.h> |
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
9 | 9 | ||
10 | #include "debugfs.h" | 10 | #include "debugfs.h" |
11 | 11 | ||
12 | char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; | 12 | char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; |
13 | 13 | ||
14 | static const char * const debugfs_known_mountpoints[] = { | 14 | static const char * const debugfs_known_mountpoints[] = { |
15 | "/sys/kernel/debug", | 15 | "/sys/kernel/debug", |
16 | "/debug", | 16 | "/debug", |
17 | 0, | 17 | 0, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | static bool debugfs_found; | 20 | static bool debugfs_found; |
21 | 21 | ||
22 | /* find the path to the mounted debugfs */ | 22 | /* find the path to the mounted debugfs */ |
23 | const char *debugfs_find_mountpoint(void) | 23 | const char *debugfs_find_mountpoint(void) |
24 | { | 24 | { |
25 | const char * const *ptr; | 25 | const char * const *ptr; |
26 | char type[100]; | 26 | char type[100]; |
27 | FILE *fp; | 27 | FILE *fp; |
28 | 28 | ||
29 | if (debugfs_found) | 29 | if (debugfs_found) |
30 | return (const char *)debugfs_mountpoint; | 30 | return (const char *)debugfs_mountpoint; |
31 | 31 | ||
32 | ptr = debugfs_known_mountpoints; | 32 | ptr = debugfs_known_mountpoints; |
33 | while (*ptr) { | 33 | while (*ptr) { |
34 | if (debugfs_valid_mountpoint(*ptr) == 0) { | 34 | if (debugfs_valid_mountpoint(*ptr) == 0) { |
35 | debugfs_found = true; | 35 | debugfs_found = true; |
36 | strcpy(debugfs_mountpoint, *ptr); | 36 | strcpy(debugfs_mountpoint, *ptr); |
37 | return debugfs_mountpoint; | 37 | return debugfs_mountpoint; |
38 | } | 38 | } |
39 | ptr++; | 39 | ptr++; |
40 | } | 40 | } |
41 | 41 | ||
42 | /* give up and parse /proc/mounts */ | 42 | /* give up and parse /proc/mounts */ |
43 | fp = fopen("/proc/mounts", "r"); | 43 | fp = fopen("/proc/mounts", "r"); |
44 | if (fp == NULL) | 44 | if (fp == NULL) |
45 | return NULL; | 45 | return NULL; |
46 | 46 | ||
47 | while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", | 47 | while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", |
48 | debugfs_mountpoint, type) == 2) { | 48 | debugfs_mountpoint, type) == 2) { |
49 | if (strcmp(type, "debugfs") == 0) | 49 | if (strcmp(type, "debugfs") == 0) |
50 | break; | 50 | break; |
51 | } | 51 | } |
52 | fclose(fp); | 52 | fclose(fp); |
53 | 53 | ||
54 | if (strcmp(type, "debugfs") != 0) | 54 | if (strcmp(type, "debugfs") != 0) |
55 | return NULL; | 55 | return NULL; |
56 | 56 | ||
57 | debugfs_found = true; | 57 | debugfs_found = true; |
58 | 58 | ||
59 | return debugfs_mountpoint; | 59 | return debugfs_mountpoint; |
60 | } | 60 | } |
61 | 61 | ||
62 | /* verify that a mountpoint is actually a debugfs instance */ | 62 | /* verify that a mountpoint is actually a debugfs instance */ |
63 | 63 | ||
64 | int debugfs_valid_mountpoint(const char *debugfs) | 64 | int debugfs_valid_mountpoint(const char *debugfs) |
65 | { | 65 | { |
66 | struct statfs st_fs; | 66 | struct statfs st_fs; |
67 | 67 | ||
68 | if (statfs(debugfs, &st_fs) < 0) | 68 | if (statfs(debugfs, &st_fs) < 0) |
69 | return -ENOENT; | 69 | return -ENOENT; |
70 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | 70 | else if ((long)st_fs.f_type != (long)DEBUGFS_MAGIC) |
71 | return -ENOENT; | 71 | return -ENOENT; |
72 | 72 | ||
73 | return 0; | 73 | return 0; |
74 | } | 74 | } |
75 | 75 | ||
76 | /* mount the debugfs somewhere if it's not mounted */ | 76 | /* mount the debugfs somewhere if it's not mounted */ |
77 | char *debugfs_mount(const char *mountpoint) | 77 | char *debugfs_mount(const char *mountpoint) |
78 | { | 78 | { |
79 | /* see if it's already mounted */ | 79 | /* see if it's already mounted */ |
80 | if (debugfs_find_mountpoint()) | 80 | if (debugfs_find_mountpoint()) |
81 | goto out; | 81 | goto out; |
82 | 82 | ||
83 | /* if not mounted and no argument */ | 83 | /* if not mounted and no argument */ |
84 | if (mountpoint == NULL) { | 84 | if (mountpoint == NULL) { |
85 | /* see if environment variable set */ | 85 | /* see if environment variable set */ |
86 | mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); | 86 | mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); |
87 | /* if no environment variable, use default */ | 87 | /* if no environment variable, use default */ |
88 | if (mountpoint == NULL) | 88 | if (mountpoint == NULL) |
89 | mountpoint = "/sys/kernel/debug"; | 89 | mountpoint = "/sys/kernel/debug"; |
90 | } | 90 | } |
91 | 91 | ||
92 | if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) | 92 | if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) |
93 | return NULL; | 93 | return NULL; |
94 | 94 | ||
95 | /* save the mountpoint */ | 95 | /* save the mountpoint */ |
96 | debugfs_found = true; | 96 | debugfs_found = true; |
97 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); | 97 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); |
98 | out: | 98 | out: |
99 | return debugfs_mountpoint; | 99 | return debugfs_mountpoint; |
100 | } | 100 | } |
101 | 101 |
tools/lib/api/fs/fs.c
1 | /* TODO merge/factor in debugfs.c here */ | 1 | /* TODO merge/factor in debugfs.c here */ |
2 | 2 | ||
3 | #include <ctype.h> | 3 | #include <ctype.h> |
4 | #include <errno.h> | 4 | #include <errno.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include <sys/vfs.h> | 9 | #include <sys/vfs.h> |
10 | #include <sys/types.h> | 10 | #include <sys/types.h> |
11 | #include <sys/stat.h> | 11 | #include <sys/stat.h> |
12 | #include <fcntl.h> | 12 | #include <fcntl.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | 14 | ||
15 | #include "debugfs.h" | 15 | #include "debugfs.h" |
16 | #include "fs.h" | 16 | #include "fs.h" |
17 | 17 | ||
18 | static const char * const sysfs__fs_known_mountpoints[] = { | 18 | static const char * const sysfs__fs_known_mountpoints[] = { |
19 | "/sys", | 19 | "/sys", |
20 | 0, | 20 | 0, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | static const char * const procfs__known_mountpoints[] = { | 23 | static const char * const procfs__known_mountpoints[] = { |
24 | "/proc", | 24 | "/proc", |
25 | 0, | 25 | 0, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct fs { | 28 | struct fs { |
29 | const char *name; | 29 | const char *name; |
30 | const char * const *mounts; | 30 | const char * const *mounts; |
31 | char path[PATH_MAX + 1]; | 31 | char path[PATH_MAX + 1]; |
32 | bool found; | 32 | bool found; |
33 | long magic; | 33 | long magic; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | enum { | 36 | enum { |
37 | FS__SYSFS = 0, | 37 | FS__SYSFS = 0, |
38 | FS__PROCFS = 1, | 38 | FS__PROCFS = 1, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | static struct fs fs__entries[] = { | 41 | static struct fs fs__entries[] = { |
42 | [FS__SYSFS] = { | 42 | [FS__SYSFS] = { |
43 | .name = "sysfs", | 43 | .name = "sysfs", |
44 | .mounts = sysfs__fs_known_mountpoints, | 44 | .mounts = sysfs__fs_known_mountpoints, |
45 | .magic = SYSFS_MAGIC, | 45 | .magic = SYSFS_MAGIC, |
46 | }, | 46 | }, |
47 | [FS__PROCFS] = { | 47 | [FS__PROCFS] = { |
48 | .name = "proc", | 48 | .name = "proc", |
49 | .mounts = procfs__known_mountpoints, | 49 | .mounts = procfs__known_mountpoints, |
50 | .magic = PROC_SUPER_MAGIC, | 50 | .magic = PROC_SUPER_MAGIC, |
51 | }, | 51 | }, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static bool fs__read_mounts(struct fs *fs) | 54 | static bool fs__read_mounts(struct fs *fs) |
55 | { | 55 | { |
56 | bool found = false; | 56 | bool found = false; |
57 | char type[100]; | 57 | char type[100]; |
58 | FILE *fp; | 58 | FILE *fp; |
59 | 59 | ||
60 | fp = fopen("/proc/mounts", "r"); | 60 | fp = fopen("/proc/mounts", "r"); |
61 | if (fp == NULL) | 61 | if (fp == NULL) |
62 | return NULL; | 62 | return NULL; |
63 | 63 | ||
64 | while (!found && | 64 | while (!found && |
65 | fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", | 65 | fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", |
66 | fs->path, type) == 2) { | 66 | fs->path, type) == 2) { |
67 | 67 | ||
68 | if (strcmp(type, fs->name) == 0) | 68 | if (strcmp(type, fs->name) == 0) |
69 | found = true; | 69 | found = true; |
70 | } | 70 | } |
71 | 71 | ||
72 | fclose(fp); | 72 | fclose(fp); |
73 | return fs->found = found; | 73 | return fs->found = found; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int fs__valid_mount(const char *fs, long magic) | 76 | static int fs__valid_mount(const char *fs, long magic) |
77 | { | 77 | { |
78 | struct statfs st_fs; | 78 | struct statfs st_fs; |
79 | 79 | ||
80 | if (statfs(fs, &st_fs) < 0) | 80 | if (statfs(fs, &st_fs) < 0) |
81 | return -ENOENT; | 81 | return -ENOENT; |
82 | else if (st_fs.f_type != magic) | 82 | else if ((long)st_fs.f_type != magic) |
83 | return -ENOENT; | 83 | return -ENOENT; |
84 | 84 | ||
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | static bool fs__check_mounts(struct fs *fs) | 88 | static bool fs__check_mounts(struct fs *fs) |
89 | { | 89 | { |
90 | const char * const *ptr; | 90 | const char * const *ptr; |
91 | 91 | ||
92 | ptr = fs->mounts; | 92 | ptr = fs->mounts; |
93 | while (*ptr) { | 93 | while (*ptr) { |
94 | if (fs__valid_mount(*ptr, fs->magic) == 0) { | 94 | if (fs__valid_mount(*ptr, fs->magic) == 0) { |
95 | fs->found = true; | 95 | fs->found = true; |
96 | strcpy(fs->path, *ptr); | 96 | strcpy(fs->path, *ptr); |
97 | return true; | 97 | return true; |
98 | } | 98 | } |
99 | ptr++; | 99 | ptr++; |
100 | } | 100 | } |
101 | 101 | ||
102 | return false; | 102 | return false; |
103 | } | 103 | } |
104 | 104 | ||
105 | static void mem_toupper(char *f, size_t len) | 105 | static void mem_toupper(char *f, size_t len) |
106 | { | 106 | { |
107 | while (len) { | 107 | while (len) { |
108 | *f = toupper(*f); | 108 | *f = toupper(*f); |
109 | f++; | 109 | f++; |
110 | len--; | 110 | len--; |
111 | } | 111 | } |
112 | } | 112 | } |
113 | 113 | ||
114 | /* | 114 | /* |
115 | * Check for "NAME_PATH" environment variable to override fs location (for | 115 | * Check for "NAME_PATH" environment variable to override fs location (for |
116 | * testing). This matches the recommendation in Documentation/sysfs-rules.txt | 116 | * testing). This matches the recommendation in Documentation/sysfs-rules.txt |
117 | * for SYSFS_PATH. | 117 | * for SYSFS_PATH. |
118 | */ | 118 | */ |
119 | static bool fs__env_override(struct fs *fs) | 119 | static bool fs__env_override(struct fs *fs) |
120 | { | 120 | { |
121 | char *override_path; | 121 | char *override_path; |
122 | size_t name_len = strlen(fs->name); | 122 | size_t name_len = strlen(fs->name); |
123 | /* name + "_PATH" + '\0' */ | 123 | /* name + "_PATH" + '\0' */ |
124 | char upper_name[name_len + 5 + 1]; | 124 | char upper_name[name_len + 5 + 1]; |
125 | memcpy(upper_name, fs->name, name_len); | 125 | memcpy(upper_name, fs->name, name_len); |
126 | mem_toupper(upper_name, name_len); | 126 | mem_toupper(upper_name, name_len); |
127 | strcpy(&upper_name[name_len], "_PATH"); | 127 | strcpy(&upper_name[name_len], "_PATH"); |
128 | 128 | ||
129 | override_path = getenv(upper_name); | 129 | override_path = getenv(upper_name); |
130 | if (!override_path) | 130 | if (!override_path) |
131 | return false; | 131 | return false; |
132 | 132 | ||
133 | fs->found = true; | 133 | fs->found = true; |
134 | strncpy(fs->path, override_path, sizeof(fs->path)); | 134 | strncpy(fs->path, override_path, sizeof(fs->path)); |
135 | return true; | 135 | return true; |
136 | } | 136 | } |
137 | 137 | ||
138 | static const char *fs__get_mountpoint(struct fs *fs) | 138 | static const char *fs__get_mountpoint(struct fs *fs) |
139 | { | 139 | { |
140 | if (fs__env_override(fs)) | 140 | if (fs__env_override(fs)) |
141 | return fs->path; | 141 | return fs->path; |
142 | 142 | ||
143 | if (fs__check_mounts(fs)) | 143 | if (fs__check_mounts(fs)) |
144 | return fs->path; | 144 | return fs->path; |
145 | 145 | ||
146 | if (fs__read_mounts(fs)) | 146 | if (fs__read_mounts(fs)) |
147 | return fs->path; | 147 | return fs->path; |
148 | 148 | ||
149 | return NULL; | 149 | return NULL; |
150 | } | 150 | } |
151 | 151 | ||
152 | static const char *fs__mountpoint(int idx) | 152 | static const char *fs__mountpoint(int idx) |
153 | { | 153 | { |
154 | struct fs *fs = &fs__entries[idx]; | 154 | struct fs *fs = &fs__entries[idx]; |
155 | 155 | ||
156 | if (fs->found) | 156 | if (fs->found) |
157 | return (const char *)fs->path; | 157 | return (const char *)fs->path; |
158 | 158 | ||
159 | return fs__get_mountpoint(fs); | 159 | return fs__get_mountpoint(fs); |
160 | } | 160 | } |
161 | 161 | ||
162 | #define FS__MOUNTPOINT(name, idx) \ | 162 | #define FS__MOUNTPOINT(name, idx) \ |
163 | const char *name##__mountpoint(void) \ | 163 | const char *name##__mountpoint(void) \ |
164 | { \ | 164 | { \ |
165 | return fs__mountpoint(idx); \ | 165 | return fs__mountpoint(idx); \ |
166 | } | 166 | } |
167 | 167 | ||
168 | FS__MOUNTPOINT(sysfs, FS__SYSFS); | 168 | FS__MOUNTPOINT(sysfs, FS__SYSFS); |
169 | FS__MOUNTPOINT(procfs, FS__PROCFS); | 169 | FS__MOUNTPOINT(procfs, FS__PROCFS); |
170 | 170 | ||
171 | int filename__read_int(const char *filename, int *value) | 171 | int filename__read_int(const char *filename, int *value) |
172 | { | 172 | { |
173 | char line[64]; | 173 | char line[64]; |
174 | int fd = open(filename, O_RDONLY), err = -1; | 174 | int fd = open(filename, O_RDONLY), err = -1; |
175 | 175 | ||
176 | if (fd < 0) | 176 | if (fd < 0) |
177 | return -1; | 177 | return -1; |
178 | 178 | ||
179 | if (read(fd, line, sizeof(line)) > 0) { | 179 | if (read(fd, line, sizeof(line)) > 0) { |
180 | *value = atoi(line); | 180 | *value = atoi(line); |
181 | err = 0; | 181 | err = 0; |
182 | } | 182 | } |
183 | 183 | ||
184 | close(fd); | 184 | close(fd); |
185 | return err; | 185 | return err; |
186 | } | 186 | } |
187 | 187 | ||
188 | int sysctl__read_int(const char *sysctl, int *value) | 188 | int sysctl__read_int(const char *sysctl, int *value) |
189 | { | 189 | { |
190 | char path[PATH_MAX]; | 190 | char path[PATH_MAX]; |
191 | const char *procfs = procfs__mountpoint(); | 191 | const char *procfs = procfs__mountpoint(); |
192 | 192 | ||
193 | if (!procfs) | 193 | if (!procfs) |
194 | return -1; | 194 | return -1; |
195 | 195 | ||
196 | snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl); | 196 | snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl); |
197 | 197 | ||
198 | return filename__read_int(path, value); | 198 | return filename__read_int(path, value); |
199 | } | 199 | } |
200 | 200 |
tools/perf/MANIFEST
1 | tools/perf | 1 | tools/perf |
2 | tools/scripts | 2 | tools/scripts |
3 | tools/lib/traceevent | 3 | tools/lib/traceevent |
4 | tools/lib/api | 4 | tools/lib/api |
5 | tools/lib/symbol/kallsyms.c | 5 | tools/lib/symbol/kallsyms.c |
6 | tools/lib/symbol/kallsyms.h | 6 | tools/lib/symbol/kallsyms.h |
7 | tools/lib/util/find_next_bit.c | 7 | tools/lib/util/find_next_bit.c |
8 | tools/include/asm/bug.h | 8 | tools/include/asm/bug.h |
9 | tools/include/asm-generic/bitops/arch_hweight.h | ||
9 | tools/include/asm-generic/bitops/atomic.h | 10 | tools/include/asm-generic/bitops/atomic.h |
11 | tools/include/asm-generic/bitops/const_hweight.h | ||
10 | tools/include/asm-generic/bitops/__ffs.h | 12 | tools/include/asm-generic/bitops/__ffs.h |
11 | tools/include/asm-generic/bitops/__fls.h | 13 | tools/include/asm-generic/bitops/__fls.h |
12 | tools/include/asm-generic/bitops/find.h | 14 | tools/include/asm-generic/bitops/find.h |
13 | tools/include/asm-generic/bitops/fls64.h | 15 | tools/include/asm-generic/bitops/fls64.h |
14 | tools/include/asm-generic/bitops/fls.h | 16 | tools/include/asm-generic/bitops/fls.h |
17 | tools/include/asm-generic/bitops/hweight.h | ||
15 | tools/include/asm-generic/bitops.h | 18 | tools/include/asm-generic/bitops.h |
16 | tools/include/linux/bitops.h | 19 | tools/include/linux/bitops.h |
17 | tools/include/linux/compiler.h | 20 | tools/include/linux/compiler.h |
18 | tools/include/linux/export.h | 21 | tools/include/linux/export.h |
19 | tools/include/linux/hash.h | 22 | tools/include/linux/hash.h |
20 | tools/include/linux/log2.h | 23 | tools/include/linux/log2.h |
21 | tools/include/linux/types.h | 24 | tools/include/linux/types.h |
25 | include/asm-generic/bitops/arch_hweight.h | ||
26 | include/asm-generic/bitops/const_hweight.h | ||
22 | include/asm-generic/bitops/fls64.h | 27 | include/asm-generic/bitops/fls64.h |
23 | include/asm-generic/bitops/__fls.h | 28 | include/asm-generic/bitops/__fls.h |
24 | include/asm-generic/bitops/fls.h | 29 | include/asm-generic/bitops/fls.h |
25 | include/linux/const.h | 30 | include/linux/const.h |
26 | include/linux/perf_event.h | 31 | include/linux/perf_event.h |
27 | include/linux/rbtree.h | 32 | include/linux/rbtree.h |
28 | include/linux/list.h | 33 | include/linux/list.h |
29 | include/linux/hash.h | 34 | include/linux/hash.h |
30 | include/linux/stringify.h | 35 | include/linux/stringify.h |
31 | lib/find_next_bit.c | 36 | lib/find_next_bit.c |
37 | lib/hweight.c | ||
32 | lib/rbtree.c | 38 | lib/rbtree.c |
33 | include/linux/swab.h | 39 | include/linux/swab.h |
34 | arch/*/include/asm/unistd*.h | 40 | arch/*/include/asm/unistd*.h |
35 | arch/*/include/asm/perf_regs.h | 41 | arch/*/include/asm/perf_regs.h |
36 | arch/*/include/uapi/asm/unistd*.h | 42 | arch/*/include/uapi/asm/unistd*.h |
37 | arch/*/include/uapi/asm/perf_regs.h | 43 | arch/*/include/uapi/asm/perf_regs.h |
38 | arch/*/lib/memcpy*.S | 44 | arch/*/lib/memcpy*.S |
39 | arch/*/lib/memset*.S | 45 | arch/*/lib/memset*.S |
40 | include/linux/poison.h | 46 | include/linux/poison.h |
41 | include/linux/magic.h | 47 | include/linux/magic.h |
42 | include/linux/hw_breakpoint.h | 48 | include/linux/hw_breakpoint.h |
43 | include/linux/rbtree_augmented.h | 49 | include/linux/rbtree_augmented.h |
44 | include/uapi/linux/perf_event.h | 50 | include/uapi/linux/perf_event.h |
45 | include/uapi/linux/const.h | 51 | include/uapi/linux/const.h |
46 | include/uapi/linux/swab.h | 52 | include/uapi/linux/swab.h |
47 | include/uapi/linux/hw_breakpoint.h | 53 | include/uapi/linux/hw_breakpoint.h |
48 | arch/x86/include/asm/svm.h | 54 | arch/x86/include/asm/svm.h |
49 | arch/x86/include/asm/vmx.h | 55 | arch/x86/include/asm/vmx.h |
50 | arch/x86/include/asm/kvm_host.h | 56 | arch/x86/include/asm/kvm_host.h |
51 | arch/x86/include/uapi/asm/svm.h | 57 | arch/x86/include/uapi/asm/svm.h |
52 | arch/x86/include/uapi/asm/vmx.h | 58 | arch/x86/include/uapi/asm/vmx.h |
53 | arch/x86/include/uapi/asm/kvm.h | 59 | arch/x86/include/uapi/asm/kvm.h |
54 | arch/x86/include/uapi/asm/kvm_perf.h | 60 | arch/x86/include/uapi/asm/kvm_perf.h |
55 | arch/s390/include/uapi/asm/sie.h | 61 | arch/s390/include/uapi/asm/sie.h |
56 | arch/s390/include/uapi/asm/kvm_perf.h | 62 | arch/s390/include/uapi/asm/kvm_perf.h |
57 | 63 |
tools/perf/Makefile.perf
1 | include ../scripts/Makefile.include | 1 | include ../scripts/Makefile.include |
2 | 2 | ||
3 | # The default target of this Makefile is... | 3 | # The default target of this Makefile is... |
4 | all: | 4 | all: |
5 | 5 | ||
6 | include config/utilities.mak | 6 | include config/utilities.mak |
7 | 7 | ||
8 | # Define V to have a more verbose compile. | 8 | # Define V to have a more verbose compile. |
9 | # | 9 | # |
10 | # Define VF to have a more verbose feature check output. | 10 | # Define VF to have a more verbose feature check output. |
11 | # | 11 | # |
12 | # Define O to save output files in a separate directory. | 12 | # Define O to save output files in a separate directory. |
13 | # | 13 | # |
14 | # Define ARCH as name of target architecture if you want cross-builds. | 14 | # Define ARCH as name of target architecture if you want cross-builds. |
15 | # | 15 | # |
16 | # Define CROSS_COMPILE as prefix name of compiler if you want cross-builds. | 16 | # Define CROSS_COMPILE as prefix name of compiler if you want cross-builds. |
17 | # | 17 | # |
18 | # Define NO_LIBPERL to disable perl script extension. | 18 | # Define NO_LIBPERL to disable perl script extension. |
19 | # | 19 | # |
20 | # Define NO_LIBPYTHON to disable python script extension. | 20 | # Define NO_LIBPYTHON to disable python script extension. |
21 | # | 21 | # |
22 | # Define PYTHON to point to the python binary if the default | 22 | # Define PYTHON to point to the python binary if the default |
23 | # `python' is not correct; for example: PYTHON=python2 | 23 | # `python' is not correct; for example: PYTHON=python2 |
24 | # | 24 | # |
25 | # Define PYTHON_CONFIG to point to the python-config binary if | 25 | # Define PYTHON_CONFIG to point to the python-config binary if |
26 | # the default `$(PYTHON)-config' is not correct. | 26 | # the default `$(PYTHON)-config' is not correct. |
27 | # | 27 | # |
28 | # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 | 28 | # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 |
29 | # | 29 | # |
30 | # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. | 30 | # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. |
31 | # | 31 | # |
32 | # Define LDFLAGS=-static to build a static binary. | 32 | # Define LDFLAGS=-static to build a static binary. |
33 | # | 33 | # |
34 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. | 34 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. |
35 | # | 35 | # |
36 | # Define NO_DWARF if you do not want debug-info analysis feature at all. | 36 | # Define NO_DWARF if you do not want debug-info analysis feature at all. |
37 | # | 37 | # |
38 | # Define WERROR=0 to disable treating any warnings as errors. | 38 | # Define WERROR=0 to disable treating any warnings as errors. |
39 | # | 39 | # |
40 | # Define NO_NEWT if you do not want TUI support. (deprecated) | 40 | # Define NO_NEWT if you do not want TUI support. (deprecated) |
41 | # | 41 | # |
42 | # Define NO_SLANG if you do not want TUI support. | 42 | # Define NO_SLANG if you do not want TUI support. |
43 | # | 43 | # |
44 | # Define NO_GTK2 if you do not want GTK+ GUI support. | 44 | # Define NO_GTK2 if you do not want GTK+ GUI support. |
45 | # | 45 | # |
46 | # Define NO_DEMANGLE if you do not want C++ symbol demangling. | 46 | # Define NO_DEMANGLE if you do not want C++ symbol demangling. |
47 | # | 47 | # |
48 | # Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds) | 48 | # Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds) |
49 | # | 49 | # |
50 | # Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf | 50 | # Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf |
51 | # backtrace post unwind. | 51 | # backtrace post unwind. |
52 | # | 52 | # |
53 | # Define NO_BACKTRACE if you do not want stack backtrace debug feature | 53 | # Define NO_BACKTRACE if you do not want stack backtrace debug feature |
54 | # | 54 | # |
55 | # Define NO_LIBNUMA if you do not want numa perf benchmark | 55 | # Define NO_LIBNUMA if you do not want numa perf benchmark |
56 | # | 56 | # |
57 | # Define NO_LIBAUDIT if you do not want libaudit support | 57 | # Define NO_LIBAUDIT if you do not want libaudit support |
58 | # | 58 | # |
59 | # Define NO_LIBBIONIC if you do not want bionic support | 59 | # Define NO_LIBBIONIC if you do not want bionic support |
60 | # | 60 | # |
61 | # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support | 61 | # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support |
62 | # for dwarf backtrace post unwind. | 62 | # for dwarf backtrace post unwind. |
63 | # | 63 | # |
64 | # Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32 | 64 | # Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32 |
65 | # for reading the 32-bit compatibility VDSO in 64-bit mode | 65 | # for reading the 32-bit compatibility VDSO in 64-bit mode |
66 | # | 66 | # |
67 | # Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32 | 67 | # Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32 |
68 | # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode | 68 | # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode |
69 | # | 69 | # |
70 | # Define NO_ZLIB if you do not want to support compressed kernel modules | 70 | # Define NO_ZLIB if you do not want to support compressed kernel modules |
71 | 71 | ||
72 | 72 | ||
73 | ifeq ($(srctree),) | 73 | ifeq ($(srctree),) |
74 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 74 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) |
75 | srctree := $(patsubst %/,%,$(dir $(srctree))) | 75 | srctree := $(patsubst %/,%,$(dir $(srctree))) |
76 | #$(info Determined 'srctree' to be $(srctree)) | 76 | #$(info Determined 'srctree' to be $(srctree)) |
77 | endif | 77 | endif |
78 | 78 | ||
79 | ifneq ($(objtree),) | 79 | ifneq ($(objtree),) |
80 | #$(info Determined 'objtree' to be $(objtree)) | 80 | #$(info Determined 'objtree' to be $(objtree)) |
81 | endif | 81 | endif |
82 | 82 | ||
83 | ifneq ($(OUTPUT),) | 83 | ifneq ($(OUTPUT),) |
84 | #$(info Determined 'OUTPUT' to be $(OUTPUT)) | 84 | #$(info Determined 'OUTPUT' to be $(OUTPUT)) |
85 | endif | 85 | endif |
86 | 86 | ||
87 | $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD | 87 | $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD |
88 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 88 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
89 | @touch $(OUTPUT)PERF-VERSION-FILE | 89 | @touch $(OUTPUT)PERF-VERSION-FILE |
90 | 90 | ||
91 | CC = $(CROSS_COMPILE)gcc | 91 | CC = $(CROSS_COMPILE)gcc |
92 | AR = $(CROSS_COMPILE)ar | 92 | AR = $(CROSS_COMPILE)ar |
93 | PKG_CONFIG = $(CROSS_COMPILE)pkg-config | 93 | PKG_CONFIG = $(CROSS_COMPILE)pkg-config |
94 | 94 | ||
95 | RM = rm -f | 95 | RM = rm -f |
96 | LN = ln -f | 96 | LN = ln -f |
97 | MKDIR = mkdir | 97 | MKDIR = mkdir |
98 | FIND = find | 98 | FIND = find |
99 | INSTALL = install | 99 | INSTALL = install |
100 | FLEX = flex | 100 | FLEX = flex |
101 | BISON = bison | 101 | BISON = bison |
102 | STRIP = strip | 102 | STRIP = strip |
103 | 103 | ||
104 | LIB_DIR = $(srctree)/tools/lib/api/ | 104 | LIB_DIR = $(srctree)/tools/lib/api/ |
105 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ | 105 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ |
106 | 106 | ||
107 | # include config/Makefile by default and rule out | 107 | # include config/Makefile by default and rule out |
108 | # non-config cases | 108 | # non-config cases |
109 | config := 1 | 109 | config := 1 |
110 | 110 | ||
111 | NON_CONFIG_TARGETS := clean TAGS tags cscope help | 111 | NON_CONFIG_TARGETS := clean TAGS tags cscope help |
112 | 112 | ||
113 | ifdef MAKECMDGOALS | 113 | ifdef MAKECMDGOALS |
114 | ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),) | 114 | ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),) |
115 | config := 0 | 115 | config := 0 |
116 | endif | 116 | endif |
117 | endif | 117 | endif |
118 | 118 | ||
119 | ifeq ($(config),1) | 119 | ifeq ($(config),1) |
120 | include config/Makefile | 120 | include config/Makefile |
121 | endif | 121 | endif |
122 | 122 | ||
123 | export prefix bindir sharedir sysconfdir DESTDIR | 123 | export prefix bindir sharedir sysconfdir DESTDIR |
124 | 124 | ||
125 | # sparse is architecture-neutral, which means that we need to tell it | 125 | # sparse is architecture-neutral, which means that we need to tell it |
126 | # explicitly what architecture to check for. Fix this up for yours.. | 126 | # explicitly what architecture to check for. Fix this up for yours.. |
127 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ | 127 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ |
128 | 128 | ||
129 | # Guard against environment variables | 129 | # Guard against environment variables |
130 | BUILTIN_OBJS = | 130 | BUILTIN_OBJS = |
131 | LIB_H = | 131 | LIB_H = |
132 | LIB_OBJS = | 132 | LIB_OBJS = |
133 | GTK_OBJS = | 133 | GTK_OBJS = |
134 | PYRF_OBJS = | 134 | PYRF_OBJS = |
135 | SCRIPT_SH = | 135 | SCRIPT_SH = |
136 | 136 | ||
137 | SCRIPT_SH += perf-archive.sh | 137 | SCRIPT_SH += perf-archive.sh |
138 | SCRIPT_SH += perf-with-kcore.sh | 138 | SCRIPT_SH += perf-with-kcore.sh |
139 | 139 | ||
140 | grep-libs = $(filter -l%,$(1)) | 140 | grep-libs = $(filter -l%,$(1)) |
141 | strip-libs = $(filter-out -l%,$(1)) | 141 | strip-libs = $(filter-out -l%,$(1)) |
142 | 142 | ||
143 | ifneq ($(OUTPUT),) | 143 | ifneq ($(OUTPUT),) |
144 | TE_PATH=$(OUTPUT) | 144 | TE_PATH=$(OUTPUT) |
145 | ifneq ($(subdir),) | 145 | ifneq ($(subdir),) |
146 | LIB_PATH=$(OUTPUT)/../lib/api/ | 146 | LIB_PATH=$(OUTPUT)/../lib/api/ |
147 | else | 147 | else |
148 | LIB_PATH=$(OUTPUT) | 148 | LIB_PATH=$(OUTPUT) |
149 | endif | 149 | endif |
150 | else | 150 | else |
151 | TE_PATH=$(TRACE_EVENT_DIR) | 151 | TE_PATH=$(TRACE_EVENT_DIR) |
152 | LIB_PATH=$(LIB_DIR) | 152 | LIB_PATH=$(LIB_DIR) |
153 | endif | 153 | endif |
154 | 154 | ||
155 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | 155 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
156 | export LIBTRACEEVENT | 156 | export LIBTRACEEVENT |
157 | 157 | ||
158 | LIBAPIKFS = $(LIB_PATH)libapikfs.a | 158 | LIBAPIKFS = $(LIB_PATH)libapikfs.a |
159 | export LIBAPIKFS | 159 | export LIBAPIKFS |
160 | 160 | ||
161 | # python extension build directories | 161 | # python extension build directories |
162 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | 162 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
163 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ | 163 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ |
164 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | 164 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ |
165 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | 165 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP |
166 | 166 | ||
167 | python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | 167 | python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so |
168 | 168 | ||
169 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 169 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
170 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS) | 170 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS) |
171 | 171 | ||
172 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 172 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
173 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 173 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
174 | --quiet build_ext; \ | 174 | --quiet build_ext; \ |
175 | mkdir -p $(OUTPUT)python && \ | 175 | mkdir -p $(OUTPUT)python && \ |
176 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ | 176 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ |
177 | # | 177 | # |
178 | # No Perl scripts right now: | 178 | # No Perl scripts right now: |
179 | # | 179 | # |
180 | 180 | ||
181 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) | 181 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) |
182 | 182 | ||
183 | PROGRAMS += $(OUTPUT)perf | 183 | PROGRAMS += $(OUTPUT)perf |
184 | 184 | ||
185 | ifndef NO_PERF_READ_VDSO32 | 185 | ifndef NO_PERF_READ_VDSO32 |
186 | PROGRAMS += $(OUTPUT)perf-read-vdso32 | 186 | PROGRAMS += $(OUTPUT)perf-read-vdso32 |
187 | endif | 187 | endif |
188 | 188 | ||
189 | ifndef NO_PERF_READ_VDSOX32 | 189 | ifndef NO_PERF_READ_VDSOX32 |
190 | PROGRAMS += $(OUTPUT)perf-read-vdsox32 | 190 | PROGRAMS += $(OUTPUT)perf-read-vdsox32 |
191 | endif | 191 | endif |
192 | 192 | ||
193 | # what 'all' will build and 'install' will install, in perfexecdir | 193 | # what 'all' will build and 'install' will install, in perfexecdir |
194 | ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) | 194 | ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) |
195 | 195 | ||
196 | # what 'all' will build but not install in perfexecdir | 196 | # what 'all' will build but not install in perfexecdir |
197 | OTHER_PROGRAMS = $(OUTPUT)perf | 197 | OTHER_PROGRAMS = $(OUTPUT)perf |
198 | 198 | ||
199 | # Set paths to tools early so that they can be used for version tests. | 199 | # Set paths to tools early so that they can be used for version tests. |
200 | ifndef SHELL_PATH | 200 | ifndef SHELL_PATH |
201 | SHELL_PATH = /bin/sh | 201 | SHELL_PATH = /bin/sh |
202 | endif | 202 | endif |
203 | ifndef PERL_PATH | 203 | ifndef PERL_PATH |
204 | PERL_PATH = /usr/bin/perl | 204 | PERL_PATH = /usr/bin/perl |
205 | endif | 205 | endif |
206 | 206 | ||
207 | export PERL_PATH | 207 | export PERL_PATH |
208 | 208 | ||
209 | $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c | 209 | $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c |
210 | $(QUIET_FLEX)$(FLEX) -o $@ --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) util/parse-events.l | 210 | $(QUIET_FLEX)$(FLEX) -o $@ --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) util/parse-events.l |
211 | 211 | ||
212 | $(OUTPUT)util/parse-events-bison.c: util/parse-events.y | 212 | $(OUTPUT)util/parse-events-bison.c: util/parse-events.y |
213 | $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_ | 213 | $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_ |
214 | 214 | ||
215 | $(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c | 215 | $(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c |
216 | $(QUIET_FLEX)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l | 216 | $(QUIET_FLEX)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l |
217 | 217 | ||
218 | $(OUTPUT)util/pmu-bison.c: util/pmu.y | 218 | $(OUTPUT)util/pmu-bison.c: util/pmu.y |
219 | $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_ | 219 | $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_ |
220 | 220 | ||
221 | $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c | 221 | $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c |
222 | $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | 222 | $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c |
223 | 223 | ||
224 | LIB_FILE=$(OUTPUT)libperf.a | 224 | LIB_FILE=$(OUTPUT)libperf.a |
225 | 225 | ||
226 | LIB_H += ../lib/symbol/kallsyms.h | 226 | LIB_H += ../lib/symbol/kallsyms.h |
227 | LIB_H += ../../include/uapi/linux/perf_event.h | 227 | LIB_H += ../../include/uapi/linux/perf_event.h |
228 | LIB_H += ../../include/linux/rbtree.h | 228 | LIB_H += ../../include/linux/rbtree.h |
229 | LIB_H += ../../include/linux/list.h | 229 | LIB_H += ../../include/linux/list.h |
230 | LIB_H += ../../include/uapi/linux/const.h | 230 | LIB_H += ../../include/uapi/linux/const.h |
231 | LIB_H += ../include/linux/hash.h | 231 | LIB_H += ../include/linux/hash.h |
232 | LIB_H += ../../include/linux/stringify.h | 232 | LIB_H += ../../include/linux/stringify.h |
233 | LIB_H += util/include/linux/bitmap.h | 233 | LIB_H += util/include/linux/bitmap.h |
234 | LIB_H += ../include/linux/bitops.h | 234 | LIB_H += ../include/linux/bitops.h |
235 | LIB_H += ../include/asm-generic/bitops/arch_hweight.h | ||
235 | LIB_H += ../include/asm-generic/bitops/atomic.h | 236 | LIB_H += ../include/asm-generic/bitops/atomic.h |
237 | LIB_H += ../include/asm-generic/bitops/const_hweight.h | ||
236 | LIB_H += ../include/asm-generic/bitops/find.h | 238 | LIB_H += ../include/asm-generic/bitops/find.h |
237 | LIB_H += ../include/asm-generic/bitops/fls64.h | 239 | LIB_H += ../include/asm-generic/bitops/fls64.h |
238 | LIB_H += ../include/asm-generic/bitops/fls.h | 240 | LIB_H += ../include/asm-generic/bitops/fls.h |
239 | LIB_H += ../include/asm-generic/bitops/__ffs.h | 241 | LIB_H += ../include/asm-generic/bitops/__ffs.h |
240 | LIB_H += ../include/asm-generic/bitops/__fls.h | 242 | LIB_H += ../include/asm-generic/bitops/__fls.h |
243 | LIB_H += ../include/asm-generic/bitops/hweight.h | ||
241 | LIB_H += ../include/asm-generic/bitops.h | 244 | LIB_H += ../include/asm-generic/bitops.h |
242 | LIB_H += ../include/linux/compiler.h | 245 | LIB_H += ../include/linux/compiler.h |
243 | LIB_H += ../include/linux/log2.h | 246 | LIB_H += ../include/linux/log2.h |
244 | LIB_H += util/include/linux/const.h | 247 | LIB_H += util/include/linux/const.h |
245 | LIB_H += util/include/linux/ctype.h | 248 | LIB_H += util/include/linux/ctype.h |
246 | LIB_H += util/include/linux/kernel.h | 249 | LIB_H += util/include/linux/kernel.h |
247 | LIB_H += util/include/linux/list.h | 250 | LIB_H += util/include/linux/list.h |
248 | LIB_H += ../include/linux/export.h | 251 | LIB_H += ../include/linux/export.h |
249 | LIB_H += util/include/linux/poison.h | 252 | LIB_H += util/include/linux/poison.h |
250 | LIB_H += util/include/linux/rbtree.h | 253 | LIB_H += util/include/linux/rbtree.h |
251 | LIB_H += util/include/linux/rbtree_augmented.h | 254 | LIB_H += util/include/linux/rbtree_augmented.h |
252 | LIB_H += util/include/linux/string.h | 255 | LIB_H += util/include/linux/string.h |
253 | LIB_H += ../include/linux/types.h | 256 | LIB_H += ../include/linux/types.h |
254 | LIB_H += util/include/linux/linkage.h | 257 | LIB_H += util/include/linux/linkage.h |
255 | LIB_H += util/include/asm/asm-offsets.h | 258 | LIB_H += util/include/asm/asm-offsets.h |
256 | LIB_H += ../include/asm/bug.h | 259 | LIB_H += ../include/asm/bug.h |
257 | LIB_H += util/include/asm/byteorder.h | 260 | LIB_H += util/include/asm/byteorder.h |
258 | LIB_H += util/include/asm/hweight.h | ||
259 | LIB_H += util/include/asm/swab.h | 261 | LIB_H += util/include/asm/swab.h |
260 | LIB_H += util/include/asm/system.h | 262 | LIB_H += util/include/asm/system.h |
261 | LIB_H += util/include/asm/uaccess.h | 263 | LIB_H += util/include/asm/uaccess.h |
262 | LIB_H += util/include/dwarf-regs.h | 264 | LIB_H += util/include/dwarf-regs.h |
263 | LIB_H += util/include/asm/dwarf2.h | 265 | LIB_H += util/include/asm/dwarf2.h |
264 | LIB_H += util/include/asm/cpufeature.h | 266 | LIB_H += util/include/asm/cpufeature.h |
265 | LIB_H += util/include/asm/unistd_32.h | 267 | LIB_H += util/include/asm/unistd_32.h |
266 | LIB_H += util/include/asm/unistd_64.h | 268 | LIB_H += util/include/asm/unistd_64.h |
267 | LIB_H += perf.h | 269 | LIB_H += perf.h |
268 | LIB_H += util/annotate.h | 270 | LIB_H += util/annotate.h |
269 | LIB_H += util/cache.h | 271 | LIB_H += util/cache.h |
270 | LIB_H += util/callchain.h | 272 | LIB_H += util/callchain.h |
271 | LIB_H += util/build-id.h | 273 | LIB_H += util/build-id.h |
272 | LIB_H += util/db-export.h | 274 | LIB_H += util/db-export.h |
273 | LIB_H += util/debug.h | 275 | LIB_H += util/debug.h |
274 | LIB_H += util/pmu.h | 276 | LIB_H += util/pmu.h |
275 | LIB_H += util/event.h | 277 | LIB_H += util/event.h |
276 | LIB_H += util/evsel.h | 278 | LIB_H += util/evsel.h |
277 | LIB_H += util/evlist.h | 279 | LIB_H += util/evlist.h |
278 | LIB_H += util/exec_cmd.h | 280 | LIB_H += util/exec_cmd.h |
279 | LIB_H += util/find-vdso-map.c | 281 | LIB_H += util/find-vdso-map.c |
280 | LIB_H += util/levenshtein.h | 282 | LIB_H += util/levenshtein.h |
281 | LIB_H += util/machine.h | 283 | LIB_H += util/machine.h |
282 | LIB_H += util/map.h | 284 | LIB_H += util/map.h |
283 | LIB_H += util/parse-options.h | 285 | LIB_H += util/parse-options.h |
284 | LIB_H += util/parse-events.h | 286 | LIB_H += util/parse-events.h |
285 | LIB_H += util/quote.h | 287 | LIB_H += util/quote.h |
286 | LIB_H += util/util.h | 288 | LIB_H += util/util.h |
287 | LIB_H += util/xyarray.h | 289 | LIB_H += util/xyarray.h |
288 | LIB_H += util/header.h | 290 | LIB_H += util/header.h |
289 | LIB_H += util/help.h | 291 | LIB_H += util/help.h |
290 | LIB_H += util/session.h | 292 | LIB_H += util/session.h |
291 | LIB_H += util/ordered-events.h | 293 | LIB_H += util/ordered-events.h |
292 | LIB_H += util/strbuf.h | 294 | LIB_H += util/strbuf.h |
293 | LIB_H += util/strlist.h | 295 | LIB_H += util/strlist.h |
294 | LIB_H += util/strfilter.h | 296 | LIB_H += util/strfilter.h |
295 | LIB_H += util/svghelper.h | 297 | LIB_H += util/svghelper.h |
296 | LIB_H += util/tool.h | 298 | LIB_H += util/tool.h |
297 | LIB_H += util/run-command.h | 299 | LIB_H += util/run-command.h |
298 | LIB_H += util/sigchain.h | 300 | LIB_H += util/sigchain.h |
299 | LIB_H += util/dso.h | 301 | LIB_H += util/dso.h |
300 | LIB_H += util/symbol.h | 302 | LIB_H += util/symbol.h |
301 | LIB_H += util/color.h | 303 | LIB_H += util/color.h |
302 | LIB_H += util/values.h | 304 | LIB_H += util/values.h |
303 | LIB_H += util/sort.h | 305 | LIB_H += util/sort.h |
304 | LIB_H += util/hist.h | 306 | LIB_H += util/hist.h |
305 | LIB_H += util/comm.h | 307 | LIB_H += util/comm.h |
306 | LIB_H += util/thread.h | 308 | LIB_H += util/thread.h |
307 | LIB_H += util/thread_map.h | 309 | LIB_H += util/thread_map.h |
308 | LIB_H += util/trace-event.h | 310 | LIB_H += util/trace-event.h |
309 | LIB_H += util/probe-finder.h | 311 | LIB_H += util/probe-finder.h |
310 | LIB_H += util/dwarf-aux.h | 312 | LIB_H += util/dwarf-aux.h |
311 | LIB_H += util/probe-event.h | 313 | LIB_H += util/probe-event.h |
312 | LIB_H += util/pstack.h | 314 | LIB_H += util/pstack.h |
313 | LIB_H += util/cpumap.h | 315 | LIB_H += util/cpumap.h |
314 | LIB_H += util/top.h | 316 | LIB_H += util/top.h |
315 | LIB_H += $(ARCH_INCLUDE) | 317 | LIB_H += $(ARCH_INCLUDE) |
316 | LIB_H += util/cgroup.h | 318 | LIB_H += util/cgroup.h |
317 | LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h | 319 | LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h |
318 | LIB_H += util/target.h | 320 | LIB_H += util/target.h |
319 | LIB_H += util/rblist.h | 321 | LIB_H += util/rblist.h |
320 | LIB_H += util/intlist.h | 322 | LIB_H += util/intlist.h |
321 | LIB_H += util/perf_regs.h | 323 | LIB_H += util/perf_regs.h |
322 | LIB_H += util/unwind.h | 324 | LIB_H += util/unwind.h |
323 | LIB_H += util/vdso.h | 325 | LIB_H += util/vdso.h |
324 | LIB_H += util/tsc.h | 326 | LIB_H += util/tsc.h |
325 | LIB_H += ui/helpline.h | 327 | LIB_H += ui/helpline.h |
326 | LIB_H += ui/progress.h | 328 | LIB_H += ui/progress.h |
327 | LIB_H += ui/util.h | 329 | LIB_H += ui/util.h |
328 | LIB_H += ui/ui.h | 330 | LIB_H += ui/ui.h |
329 | LIB_H += util/data.h | 331 | LIB_H += util/data.h |
330 | LIB_H += util/kvm-stat.h | 332 | LIB_H += util/kvm-stat.h |
331 | LIB_H += util/thread-stack.h | 333 | LIB_H += util/thread-stack.h |
332 | 334 | ||
333 | LIB_OBJS += $(OUTPUT)util/abspath.o | 335 | LIB_OBJS += $(OUTPUT)util/abspath.o |
334 | LIB_OBJS += $(OUTPUT)util/alias.o | 336 | LIB_OBJS += $(OUTPUT)util/alias.o |
335 | LIB_OBJS += $(OUTPUT)util/annotate.o | 337 | LIB_OBJS += $(OUTPUT)util/annotate.o |
336 | LIB_OBJS += $(OUTPUT)util/build-id.o | 338 | LIB_OBJS += $(OUTPUT)util/build-id.o |
337 | LIB_OBJS += $(OUTPUT)util/config.o | 339 | LIB_OBJS += $(OUTPUT)util/config.o |
338 | LIB_OBJS += $(OUTPUT)util/ctype.o | 340 | LIB_OBJS += $(OUTPUT)util/ctype.o |
339 | LIB_OBJS += $(OUTPUT)util/db-export.o | 341 | LIB_OBJS += $(OUTPUT)util/db-export.o |
340 | LIB_OBJS += $(OUTPUT)util/pmu.o | 342 | LIB_OBJS += $(OUTPUT)util/pmu.o |
341 | LIB_OBJS += $(OUTPUT)util/environment.o | 343 | LIB_OBJS += $(OUTPUT)util/environment.o |
342 | LIB_OBJS += $(OUTPUT)util/event.o | 344 | LIB_OBJS += $(OUTPUT)util/event.o |
343 | LIB_OBJS += $(OUTPUT)util/evlist.o | 345 | LIB_OBJS += $(OUTPUT)util/evlist.o |
344 | LIB_OBJS += $(OUTPUT)util/evsel.o | 346 | LIB_OBJS += $(OUTPUT)util/evsel.o |
345 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o | 347 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o |
346 | LIB_OBJS += $(OUTPUT)util/find_next_bit.o | 348 | LIB_OBJS += $(OUTPUT)util/find_next_bit.o |
347 | LIB_OBJS += $(OUTPUT)util/help.o | 349 | LIB_OBJS += $(OUTPUT)util/help.o |
348 | LIB_OBJS += $(OUTPUT)util/kallsyms.o | 350 | LIB_OBJS += $(OUTPUT)util/kallsyms.o |
349 | LIB_OBJS += $(OUTPUT)util/levenshtein.o | 351 | LIB_OBJS += $(OUTPUT)util/levenshtein.o |
350 | LIB_OBJS += $(OUTPUT)util/parse-options.o | 352 | LIB_OBJS += $(OUTPUT)util/parse-options.o |
351 | LIB_OBJS += $(OUTPUT)util/parse-events.o | 353 | LIB_OBJS += $(OUTPUT)util/parse-events.o |
352 | LIB_OBJS += $(OUTPUT)util/path.o | 354 | LIB_OBJS += $(OUTPUT)util/path.o |
353 | LIB_OBJS += $(OUTPUT)util/rbtree.o | 355 | LIB_OBJS += $(OUTPUT)util/rbtree.o |
354 | LIB_OBJS += $(OUTPUT)util/bitmap.o | 356 | LIB_OBJS += $(OUTPUT)util/bitmap.o |
355 | LIB_OBJS += $(OUTPUT)util/hweight.o | 357 | LIB_OBJS += $(OUTPUT)util/hweight.o |
356 | LIB_OBJS += $(OUTPUT)util/run-command.o | 358 | LIB_OBJS += $(OUTPUT)util/run-command.o |
357 | LIB_OBJS += $(OUTPUT)util/quote.o | 359 | LIB_OBJS += $(OUTPUT)util/quote.o |
358 | LIB_OBJS += $(OUTPUT)util/strbuf.o | 360 | LIB_OBJS += $(OUTPUT)util/strbuf.o |
359 | LIB_OBJS += $(OUTPUT)util/string.o | 361 | LIB_OBJS += $(OUTPUT)util/string.o |
360 | LIB_OBJS += $(OUTPUT)util/strlist.o | 362 | LIB_OBJS += $(OUTPUT)util/strlist.o |
361 | LIB_OBJS += $(OUTPUT)util/strfilter.o | 363 | LIB_OBJS += $(OUTPUT)util/strfilter.o |
362 | LIB_OBJS += $(OUTPUT)util/top.o | 364 | LIB_OBJS += $(OUTPUT)util/top.o |
363 | LIB_OBJS += $(OUTPUT)util/usage.o | 365 | LIB_OBJS += $(OUTPUT)util/usage.o |
364 | LIB_OBJS += $(OUTPUT)util/wrapper.o | 366 | LIB_OBJS += $(OUTPUT)util/wrapper.o |
365 | LIB_OBJS += $(OUTPUT)util/sigchain.o | 367 | LIB_OBJS += $(OUTPUT)util/sigchain.o |
366 | LIB_OBJS += $(OUTPUT)util/dso.o | 368 | LIB_OBJS += $(OUTPUT)util/dso.o |
367 | LIB_OBJS += $(OUTPUT)util/symbol.o | 369 | LIB_OBJS += $(OUTPUT)util/symbol.o |
368 | LIB_OBJS += $(OUTPUT)util/symbol-elf.o | 370 | LIB_OBJS += $(OUTPUT)util/symbol-elf.o |
369 | LIB_OBJS += $(OUTPUT)util/color.o | 371 | LIB_OBJS += $(OUTPUT)util/color.o |
370 | LIB_OBJS += $(OUTPUT)util/pager.o | 372 | LIB_OBJS += $(OUTPUT)util/pager.o |
371 | LIB_OBJS += $(OUTPUT)util/header.o | 373 | LIB_OBJS += $(OUTPUT)util/header.o |
372 | LIB_OBJS += $(OUTPUT)util/callchain.o | 374 | LIB_OBJS += $(OUTPUT)util/callchain.o |
373 | LIB_OBJS += $(OUTPUT)util/values.o | 375 | LIB_OBJS += $(OUTPUT)util/values.o |
374 | LIB_OBJS += $(OUTPUT)util/debug.o | 376 | LIB_OBJS += $(OUTPUT)util/debug.o |
375 | LIB_OBJS += $(OUTPUT)util/machine.o | 377 | LIB_OBJS += $(OUTPUT)util/machine.o |
376 | LIB_OBJS += $(OUTPUT)util/map.o | 378 | LIB_OBJS += $(OUTPUT)util/map.o |
377 | LIB_OBJS += $(OUTPUT)util/pstack.o | 379 | LIB_OBJS += $(OUTPUT)util/pstack.o |
378 | LIB_OBJS += $(OUTPUT)util/session.o | 380 | LIB_OBJS += $(OUTPUT)util/session.o |
379 | LIB_OBJS += $(OUTPUT)util/ordered-events.o | 381 | LIB_OBJS += $(OUTPUT)util/ordered-events.o |
380 | LIB_OBJS += $(OUTPUT)util/comm.o | 382 | LIB_OBJS += $(OUTPUT)util/comm.o |
381 | LIB_OBJS += $(OUTPUT)util/thread.o | 383 | LIB_OBJS += $(OUTPUT)util/thread.o |
382 | LIB_OBJS += $(OUTPUT)util/thread_map.o | 384 | LIB_OBJS += $(OUTPUT)util/thread_map.o |
383 | LIB_OBJS += $(OUTPUT)util/trace-event-parse.o | 385 | LIB_OBJS += $(OUTPUT)util/trace-event-parse.o |
384 | LIB_OBJS += $(OUTPUT)util/parse-events-flex.o | 386 | LIB_OBJS += $(OUTPUT)util/parse-events-flex.o |
385 | LIB_OBJS += $(OUTPUT)util/parse-events-bison.o | 387 | LIB_OBJS += $(OUTPUT)util/parse-events-bison.o |
386 | LIB_OBJS += $(OUTPUT)util/pmu-flex.o | 388 | LIB_OBJS += $(OUTPUT)util/pmu-flex.o |
387 | LIB_OBJS += $(OUTPUT)util/pmu-bison.o | 389 | LIB_OBJS += $(OUTPUT)util/pmu-bison.o |
388 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o | 390 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o |
389 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o | 391 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o |
390 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o | 392 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o |
391 | LIB_OBJS += $(OUTPUT)util/trace-event.o | 393 | LIB_OBJS += $(OUTPUT)util/trace-event.o |
392 | LIB_OBJS += $(OUTPUT)util/svghelper.o | 394 | LIB_OBJS += $(OUTPUT)util/svghelper.o |
393 | LIB_OBJS += $(OUTPUT)util/sort.o | 395 | LIB_OBJS += $(OUTPUT)util/sort.o |
394 | LIB_OBJS += $(OUTPUT)util/hist.o | 396 | LIB_OBJS += $(OUTPUT)util/hist.o |
395 | LIB_OBJS += $(OUTPUT)util/probe-event.o | 397 | LIB_OBJS += $(OUTPUT)util/probe-event.o |
396 | LIB_OBJS += $(OUTPUT)util/util.o | 398 | LIB_OBJS += $(OUTPUT)util/util.o |
397 | LIB_OBJS += $(OUTPUT)util/xyarray.o | 399 | LIB_OBJS += $(OUTPUT)util/xyarray.o |
398 | LIB_OBJS += $(OUTPUT)util/cpumap.o | 400 | LIB_OBJS += $(OUTPUT)util/cpumap.o |
399 | LIB_OBJS += $(OUTPUT)util/cgroup.o | 401 | LIB_OBJS += $(OUTPUT)util/cgroup.o |
400 | LIB_OBJS += $(OUTPUT)util/target.o | 402 | LIB_OBJS += $(OUTPUT)util/target.o |
401 | LIB_OBJS += $(OUTPUT)util/rblist.o | 403 | LIB_OBJS += $(OUTPUT)util/rblist.o |
402 | LIB_OBJS += $(OUTPUT)util/intlist.o | 404 | LIB_OBJS += $(OUTPUT)util/intlist.o |
403 | LIB_OBJS += $(OUTPUT)util/vdso.o | 405 | LIB_OBJS += $(OUTPUT)util/vdso.o |
404 | LIB_OBJS += $(OUTPUT)util/stat.o | 406 | LIB_OBJS += $(OUTPUT)util/stat.o |
405 | LIB_OBJS += $(OUTPUT)util/record.o | 407 | LIB_OBJS += $(OUTPUT)util/record.o |
406 | LIB_OBJS += $(OUTPUT)util/srcline.o | 408 | LIB_OBJS += $(OUTPUT)util/srcline.o |
407 | LIB_OBJS += $(OUTPUT)util/data.o | 409 | LIB_OBJS += $(OUTPUT)util/data.o |
408 | LIB_OBJS += $(OUTPUT)util/tsc.o | 410 | LIB_OBJS += $(OUTPUT)util/tsc.o |
409 | LIB_OBJS += $(OUTPUT)util/cloexec.o | 411 | LIB_OBJS += $(OUTPUT)util/cloexec.o |
410 | LIB_OBJS += $(OUTPUT)util/thread-stack.o | 412 | LIB_OBJS += $(OUTPUT)util/thread-stack.o |
411 | 413 | ||
412 | LIB_OBJS += $(OUTPUT)ui/setup.o | 414 | LIB_OBJS += $(OUTPUT)ui/setup.o |
413 | LIB_OBJS += $(OUTPUT)ui/helpline.o | 415 | LIB_OBJS += $(OUTPUT)ui/helpline.o |
414 | LIB_OBJS += $(OUTPUT)ui/progress.o | 416 | LIB_OBJS += $(OUTPUT)ui/progress.o |
415 | LIB_OBJS += $(OUTPUT)ui/util.o | 417 | LIB_OBJS += $(OUTPUT)ui/util.o |
416 | LIB_OBJS += $(OUTPUT)ui/hist.o | 418 | LIB_OBJS += $(OUTPUT)ui/hist.o |
417 | LIB_OBJS += $(OUTPUT)ui/stdio/hist.o | 419 | LIB_OBJS += $(OUTPUT)ui/stdio/hist.o |
418 | 420 | ||
419 | LIB_OBJS += $(OUTPUT)arch/common.o | 421 | LIB_OBJS += $(OUTPUT)arch/common.o |
420 | 422 | ||
421 | LIB_OBJS += $(OUTPUT)tests/parse-events.o | 423 | LIB_OBJS += $(OUTPUT)tests/parse-events.o |
422 | LIB_OBJS += $(OUTPUT)tests/dso-data.o | 424 | LIB_OBJS += $(OUTPUT)tests/dso-data.o |
423 | LIB_OBJS += $(OUTPUT)tests/attr.o | 425 | LIB_OBJS += $(OUTPUT)tests/attr.o |
424 | LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o | 426 | LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o |
425 | LIB_OBJS += $(OUTPUT)tests/open-syscall.o | 427 | LIB_OBJS += $(OUTPUT)tests/open-syscall.o |
426 | LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o | 428 | LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o |
427 | LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o | 429 | LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o |
428 | LIB_OBJS += $(OUTPUT)tests/mmap-basic.o | 430 | LIB_OBJS += $(OUTPUT)tests/mmap-basic.o |
429 | LIB_OBJS += $(OUTPUT)tests/perf-record.o | 431 | LIB_OBJS += $(OUTPUT)tests/perf-record.o |
430 | LIB_OBJS += $(OUTPUT)tests/rdpmc.o | 432 | LIB_OBJS += $(OUTPUT)tests/rdpmc.o |
431 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o | 433 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o |
432 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o | 434 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o |
433 | LIB_OBJS += $(OUTPUT)tests/fdarray.o | 435 | LIB_OBJS += $(OUTPUT)tests/fdarray.o |
434 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 436 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
435 | LIB_OBJS += $(OUTPUT)tests/hists_common.o | 437 | LIB_OBJS += $(OUTPUT)tests/hists_common.o |
436 | LIB_OBJS += $(OUTPUT)tests/hists_link.o | 438 | LIB_OBJS += $(OUTPUT)tests/hists_link.o |
437 | LIB_OBJS += $(OUTPUT)tests/hists_filter.o | 439 | LIB_OBJS += $(OUTPUT)tests/hists_filter.o |
438 | LIB_OBJS += $(OUTPUT)tests/hists_output.o | 440 | LIB_OBJS += $(OUTPUT)tests/hists_output.o |
439 | LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o | 441 | LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o |
440 | LIB_OBJS += $(OUTPUT)tests/python-use.o | 442 | LIB_OBJS += $(OUTPUT)tests/python-use.o |
441 | LIB_OBJS += $(OUTPUT)tests/bp_signal.o | 443 | LIB_OBJS += $(OUTPUT)tests/bp_signal.o |
442 | LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o | 444 | LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o |
443 | LIB_OBJS += $(OUTPUT)tests/task-exit.o | 445 | LIB_OBJS += $(OUTPUT)tests/task-exit.o |
444 | LIB_OBJS += $(OUTPUT)tests/sw-clock.o | 446 | LIB_OBJS += $(OUTPUT)tests/sw-clock.o |
445 | ifeq ($(ARCH),x86) | 447 | ifeq ($(ARCH),x86) |
446 | LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o | 448 | LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o |
447 | endif | 449 | endif |
448 | LIB_OBJS += $(OUTPUT)tests/code-reading.o | 450 | LIB_OBJS += $(OUTPUT)tests/code-reading.o |
449 | LIB_OBJS += $(OUTPUT)tests/sample-parsing.o | 451 | LIB_OBJS += $(OUTPUT)tests/sample-parsing.o |
450 | LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o | 452 | LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o |
451 | ifndef NO_DWARF_UNWIND | 453 | ifndef NO_DWARF_UNWIND |
452 | ifeq ($(ARCH),$(filter $(ARCH),x86 arm)) | 454 | ifeq ($(ARCH),$(filter $(ARCH),x86 arm)) |
453 | LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o | 455 | LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o |
454 | endif | 456 | endif |
455 | endif | 457 | endif |
456 | LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o | 458 | LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o |
457 | LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o | 459 | LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o |
458 | LIB_OBJS += $(OUTPUT)tests/switch-tracking.o | 460 | LIB_OBJS += $(OUTPUT)tests/switch-tracking.o |
459 | 461 | ||
460 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o | 462 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o |
461 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | 463 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o |
462 | # Benchmark modules | 464 | # Benchmark modules |
463 | BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o | 465 | BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o |
464 | BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o | 466 | BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o |
465 | ifeq ($(RAW_ARCH),x86_64) | 467 | ifeq ($(ARCH), x86) |
468 | ifeq ($(IS_64_BIT), 1) | ||
466 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o | 469 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o |
467 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o | 470 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o |
468 | endif | 471 | endif |
472 | endif | ||
469 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o | 473 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o |
470 | BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o | 474 | BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o |
471 | BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o | 475 | BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o |
472 | BUILTIN_OBJS += $(OUTPUT)bench/futex-requeue.o | 476 | BUILTIN_OBJS += $(OUTPUT)bench/futex-requeue.o |
473 | 477 | ||
474 | BUILTIN_OBJS += $(OUTPUT)builtin-diff.o | 478 | BUILTIN_OBJS += $(OUTPUT)builtin-diff.o |
475 | BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o | 479 | BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o |
476 | BUILTIN_OBJS += $(OUTPUT)builtin-help.o | 480 | BUILTIN_OBJS += $(OUTPUT)builtin-help.o |
477 | BUILTIN_OBJS += $(OUTPUT)builtin-sched.o | 481 | BUILTIN_OBJS += $(OUTPUT)builtin-sched.o |
478 | BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o | 482 | BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o |
479 | BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o | 483 | BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o |
480 | BUILTIN_OBJS += $(OUTPUT)builtin-list.o | 484 | BUILTIN_OBJS += $(OUTPUT)builtin-list.o |
481 | BUILTIN_OBJS += $(OUTPUT)builtin-record.o | 485 | BUILTIN_OBJS += $(OUTPUT)builtin-record.o |
482 | BUILTIN_OBJS += $(OUTPUT)builtin-report.o | 486 | BUILTIN_OBJS += $(OUTPUT)builtin-report.o |
483 | BUILTIN_OBJS += $(OUTPUT)builtin-stat.o | 487 | BUILTIN_OBJS += $(OUTPUT)builtin-stat.o |
484 | BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o | 488 | BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o |
485 | BUILTIN_OBJS += $(OUTPUT)builtin-top.o | 489 | BUILTIN_OBJS += $(OUTPUT)builtin-top.o |
486 | BUILTIN_OBJS += $(OUTPUT)builtin-script.o | 490 | BUILTIN_OBJS += $(OUTPUT)builtin-script.o |
487 | BUILTIN_OBJS += $(OUTPUT)builtin-probe.o | 491 | BUILTIN_OBJS += $(OUTPUT)builtin-probe.o |
488 | BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o | 492 | BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o |
489 | BUILTIN_OBJS += $(OUTPUT)builtin-lock.o | 493 | BUILTIN_OBJS += $(OUTPUT)builtin-lock.o |
490 | BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o | 494 | BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o |
491 | BUILTIN_OBJS += $(OUTPUT)builtin-inject.o | 495 | BUILTIN_OBJS += $(OUTPUT)builtin-inject.o |
492 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o | 496 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o |
493 | BUILTIN_OBJS += $(OUTPUT)builtin-mem.o | 497 | BUILTIN_OBJS += $(OUTPUT)builtin-mem.o |
494 | 498 | ||
495 | PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT) | 499 | PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT) |
496 | 500 | ||
497 | # We choose to avoid "if .. else if .. else .. endif endif" | 501 | # We choose to avoid "if .. else if .. else .. endif endif" |
498 | # because maintaining the nesting to match is a pain. If | 502 | # because maintaining the nesting to match is a pain. If |
499 | # we had "elif" things would have been much nicer... | 503 | # we had "elif" things would have been much nicer... |
500 | 504 | ||
501 | -include arch/$(ARCH)/Makefile | 505 | -include arch/$(ARCH)/Makefile |
502 | 506 | ||
503 | ifneq ($(OUTPUT),) | 507 | ifneq ($(OUTPUT),) |
504 | CFLAGS += -I$(OUTPUT) | 508 | CFLAGS += -I$(OUTPUT) |
505 | endif | 509 | endif |
506 | 510 | ||
507 | ifdef NO_LIBELF | 511 | ifdef NO_LIBELF |
508 | # Remove ELF/DWARF dependent codes | 512 | # Remove ELF/DWARF dependent codes |
509 | LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS)) | 513 | LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS)) |
510 | LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS)) | 514 | LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS)) |
511 | LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS)) | 515 | LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS)) |
512 | LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS)) | 516 | LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS)) |
513 | 517 | ||
514 | BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS)) | 518 | BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS)) |
515 | 519 | ||
516 | # Use minimal symbol handling | 520 | # Use minimal symbol handling |
517 | LIB_OBJS += $(OUTPUT)util/symbol-minimal.o | 521 | LIB_OBJS += $(OUTPUT)util/symbol-minimal.o |
518 | 522 | ||
519 | else # NO_LIBELF | 523 | else # NO_LIBELF |
520 | ifndef NO_DWARF | 524 | ifndef NO_DWARF |
521 | LIB_OBJS += $(OUTPUT)util/probe-finder.o | 525 | LIB_OBJS += $(OUTPUT)util/probe-finder.o |
522 | LIB_OBJS += $(OUTPUT)util/dwarf-aux.o | 526 | LIB_OBJS += $(OUTPUT)util/dwarf-aux.o |
523 | endif # NO_DWARF | 527 | endif # NO_DWARF |
524 | endif # NO_LIBELF | 528 | endif # NO_LIBELF |
525 | 529 | ||
526 | ifndef NO_LIBDW_DWARF_UNWIND | 530 | ifndef NO_LIBDW_DWARF_UNWIND |
527 | LIB_OBJS += $(OUTPUT)util/unwind-libdw.o | 531 | LIB_OBJS += $(OUTPUT)util/unwind-libdw.o |
528 | LIB_H += util/unwind-libdw.h | 532 | LIB_H += util/unwind-libdw.h |
529 | endif | 533 | endif |
530 | 534 | ||
531 | ifndef NO_LIBUNWIND | 535 | ifndef NO_LIBUNWIND |
532 | LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o | 536 | LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o |
533 | endif | 537 | endif |
534 | LIB_OBJS += $(OUTPUT)tests/keep-tracking.o | 538 | LIB_OBJS += $(OUTPUT)tests/keep-tracking.o |
535 | 539 | ||
536 | ifndef NO_LIBAUDIT | 540 | ifndef NO_LIBAUDIT |
537 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | 541 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o |
538 | endif | 542 | endif |
539 | 543 | ||
540 | ifndef NO_SLANG | 544 | ifndef NO_SLANG |
541 | LIB_OBJS += $(OUTPUT)ui/browser.o | 545 | LIB_OBJS += $(OUTPUT)ui/browser.o |
542 | LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o | 546 | LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o |
543 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o | 547 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o |
544 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o | 548 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o |
545 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o | 549 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o |
546 | LIB_OBJS += $(OUTPUT)ui/browsers/header.o | 550 | LIB_OBJS += $(OUTPUT)ui/browsers/header.o |
547 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o | 551 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o |
548 | LIB_OBJS += $(OUTPUT)ui/tui/util.o | 552 | LIB_OBJS += $(OUTPUT)ui/tui/util.o |
549 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o | 553 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o |
550 | LIB_OBJS += $(OUTPUT)ui/tui/progress.o | 554 | LIB_OBJS += $(OUTPUT)ui/tui/progress.o |
551 | LIB_H += ui/tui/tui.h | 555 | LIB_H += ui/tui/tui.h |
552 | LIB_H += ui/browser.h | 556 | LIB_H += ui/browser.h |
553 | LIB_H += ui/browsers/map.h | 557 | LIB_H += ui/browsers/map.h |
554 | LIB_H += ui/keysyms.h | 558 | LIB_H += ui/keysyms.h |
555 | LIB_H += ui/libslang.h | 559 | LIB_H += ui/libslang.h |
556 | endif | 560 | endif |
557 | 561 | ||
558 | ifndef NO_GTK2 | 562 | ifndef NO_GTK2 |
559 | ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so | 563 | ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so |
560 | 564 | ||
561 | GTK_OBJS += $(OUTPUT)ui/gtk/browser.o | 565 | GTK_OBJS += $(OUTPUT)ui/gtk/browser.o |
562 | GTK_OBJS += $(OUTPUT)ui/gtk/hists.o | 566 | GTK_OBJS += $(OUTPUT)ui/gtk/hists.o |
563 | GTK_OBJS += $(OUTPUT)ui/gtk/setup.o | 567 | GTK_OBJS += $(OUTPUT)ui/gtk/setup.o |
564 | GTK_OBJS += $(OUTPUT)ui/gtk/util.o | 568 | GTK_OBJS += $(OUTPUT)ui/gtk/util.o |
565 | GTK_OBJS += $(OUTPUT)ui/gtk/helpline.o | 569 | GTK_OBJS += $(OUTPUT)ui/gtk/helpline.o |
566 | GTK_OBJS += $(OUTPUT)ui/gtk/progress.o | 570 | GTK_OBJS += $(OUTPUT)ui/gtk/progress.o |
567 | GTK_OBJS += $(OUTPUT)ui/gtk/annotate.o | 571 | GTK_OBJS += $(OUTPUT)ui/gtk/annotate.o |
568 | 572 | ||
569 | install-gtk: $(OUTPUT)libperf-gtk.so | 573 | install-gtk: $(OUTPUT)libperf-gtk.so |
570 | $(call QUIET_INSTALL, 'GTK UI') \ | 574 | $(call QUIET_INSTALL, 'GTK UI') \ |
571 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \ | 575 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \ |
572 | $(INSTALL) $(OUTPUT)libperf-gtk.so '$(DESTDIR_SQ)$(libdir_SQ)' | 576 | $(INSTALL) $(OUTPUT)libperf-gtk.so '$(DESTDIR_SQ)$(libdir_SQ)' |
573 | endif | 577 | endif |
574 | 578 | ||
575 | ifndef NO_LIBPERL | 579 | ifndef NO_LIBPERL |
576 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o | 580 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o |
577 | LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o | 581 | LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o |
578 | endif | 582 | endif |
579 | 583 | ||
580 | ifndef NO_LIBPYTHON | 584 | ifndef NO_LIBPYTHON |
581 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o | 585 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o |
582 | LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o | 586 | LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o |
583 | endif | 587 | endif |
584 | 588 | ||
585 | ifeq ($(NO_PERF_REGS),0) | 589 | ifeq ($(NO_PERF_REGS),0) |
586 | ifeq ($(ARCH),x86) | 590 | ifeq ($(ARCH),x86) |
587 | LIB_H += arch/x86/include/perf_regs.h | 591 | LIB_H += arch/x86/include/perf_regs.h |
588 | endif | 592 | endif |
589 | LIB_OBJS += $(OUTPUT)util/perf_regs.o | 593 | LIB_OBJS += $(OUTPUT)util/perf_regs.o |
590 | endif | 594 | endif |
591 | 595 | ||
592 | ifndef NO_LIBNUMA | 596 | ifndef NO_LIBNUMA |
593 | BUILTIN_OBJS += $(OUTPUT)bench/numa.o | 597 | BUILTIN_OBJS += $(OUTPUT)bench/numa.o |
594 | endif | 598 | endif |
595 | 599 | ||
596 | ifndef NO_ZLIB | 600 | ifndef NO_ZLIB |
597 | LIB_OBJS += $(OUTPUT)util/zlib.o | 601 | LIB_OBJS += $(OUTPUT)util/zlib.o |
598 | endif | 602 | endif |
599 | 603 | ||
600 | ifdef ASCIIDOC8 | 604 | ifdef ASCIIDOC8 |
601 | export ASCIIDOC8 | 605 | export ASCIIDOC8 |
602 | endif | 606 | endif |
603 | 607 | ||
604 | LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group | 608 | LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group |
605 | 609 | ||
606 | export INSTALL SHELL_PATH | 610 | export INSTALL SHELL_PATH |
607 | 611 | ||
608 | ### Build rules | 612 | ### Build rules |
609 | 613 | ||
610 | SHELL = $(SHELL_PATH) | 614 | SHELL = $(SHELL_PATH) |
611 | 615 | ||
612 | all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) | 616 | all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) |
613 | 617 | ||
614 | please_set_SHELL_PATH_to_a_more_modern_shell: | 618 | please_set_SHELL_PATH_to_a_more_modern_shell: |
615 | @$$(:) | 619 | @$$(:) |
616 | 620 | ||
617 | shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell | 621 | shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell |
618 | 622 | ||
619 | strip: $(PROGRAMS) $(OUTPUT)perf | 623 | strip: $(PROGRAMS) $(OUTPUT)perf |
620 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf | 624 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf |
621 | 625 | ||
622 | $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS | 626 | $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
623 | $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \ | 627 | $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \ |
624 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 628 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
625 | $(CFLAGS) -c $(filter %.c,$^) -o $@ | 629 | $(CFLAGS) -c $(filter %.c,$^) -o $@ |
626 | 630 | ||
627 | $(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) | 631 | $(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) |
628 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \ | 632 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \ |
629 | $(BUILTIN_OBJS) $(LIBS) -o $@ | 633 | $(BUILTIN_OBJS) $(LIBS) -o $@ |
630 | 634 | ||
631 | $(GTK_OBJS): $(OUTPUT)%.o: %.c $(LIB_H) | 635 | $(GTK_OBJS): $(OUTPUT)%.o: %.c $(LIB_H) |
632 | $(QUIET_CC)$(CC) -o $@ -c -fPIC $(CFLAGS) $(GTK_CFLAGS) $< | 636 | $(QUIET_CC)$(CC) -o $@ -c -fPIC $(CFLAGS) $(GTK_CFLAGS) $< |
633 | 637 | ||
634 | $(OUTPUT)libperf-gtk.so: $(GTK_OBJS) $(PERFLIBS) | 638 | $(OUTPUT)libperf-gtk.so: $(GTK_OBJS) $(PERFLIBS) |
635 | $(QUIET_LINK)$(CC) -o $@ -shared $(LDFLAGS) $(filter %.o,$^) $(GTK_LIBS) | 639 | $(QUIET_LINK)$(CC) -o $@ -shared $(LDFLAGS) $(filter %.o,$^) $(GTK_LIBS) |
636 | 640 | ||
637 | $(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS | 641 | $(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
638 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | 642 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ |
639 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 643 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
640 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ | 644 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ |
641 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< | 645 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< |
642 | 646 | ||
643 | $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS | 647 | $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
644 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | 648 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ |
645 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 649 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
646 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ | 650 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ |
647 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< | 651 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< |
648 | 652 | ||
649 | $(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt | 653 | $(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt |
650 | 654 | ||
651 | $(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) | 655 | $(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) |
652 | $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ | 656 | $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ |
653 | 657 | ||
654 | $(SCRIPTS) : % : %.sh | 658 | $(SCRIPTS) : % : %.sh |
655 | $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@' | 659 | $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@' |
656 | 660 | ||
657 | # These can record PERF_VERSION | 661 | # These can record PERF_VERSION |
658 | $(OUTPUT)perf.o perf.spec \ | 662 | $(OUTPUT)perf.o perf.spec \ |
659 | $(SCRIPTS) \ | 663 | $(SCRIPTS) \ |
660 | : $(OUTPUT)PERF-VERSION-FILE | 664 | : $(OUTPUT)PERF-VERSION-FILE |
661 | 665 | ||
662 | .SUFFIXES: | 666 | .SUFFIXES: |
663 | 667 | ||
664 | # | 668 | # |
665 | # If a target does not match any of the later rules then prefix it by $(OUTPUT) | 669 | # If a target does not match any of the later rules then prefix it by $(OUTPUT) |
666 | # This makes targets like 'make O=/tmp/perf perf.o' work in a natural way. | 670 | # This makes targets like 'make O=/tmp/perf perf.o' work in a natural way. |
667 | # | 671 | # |
668 | ifneq ($(OUTPUT),) | 672 | ifneq ($(OUTPUT),) |
669 | %.o: $(OUTPUT)%.o | 673 | %.o: $(OUTPUT)%.o |
670 | @echo " # Redirected target $@ => $(OUTPUT)$@" | 674 | @echo " # Redirected target $@ => $(OUTPUT)$@" |
671 | util/%.o: $(OUTPUT)util/%.o | 675 | util/%.o: $(OUTPUT)util/%.o |
672 | @echo " # Redirected target $@ => $(OUTPUT)$@" | 676 | @echo " # Redirected target $@ => $(OUTPUT)$@" |
673 | bench/%.o: $(OUTPUT)bench/%.o | 677 | bench/%.o: $(OUTPUT)bench/%.o |
674 | @echo " # Redirected target $@ => $(OUTPUT)$@" | 678 | @echo " # Redirected target $@ => $(OUTPUT)$@" |
675 | tests/%.o: $(OUTPUT)tests/%.o | 679 | tests/%.o: $(OUTPUT)tests/%.o |
676 | @echo " # Redirected target $@ => $(OUTPUT)$@" | 680 | @echo " # Redirected target $@ => $(OUTPUT)$@" |
677 | endif | 681 | endif |
678 | 682 | ||
679 | # These two need to be here so that when O= is not used they take precedence | 683 | # These two need to be here so that when O= is not used they take precedence |
680 | # over the general rule for .o | 684 | # over the general rule for .o |
681 | 685 | ||
682 | $(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS | 686 | $(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS |
683 | $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $< | 687 | $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $< |
684 | 688 | ||
685 | $(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS | 689 | $(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS |
686 | $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $< | 690 | $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $< |
687 | 691 | ||
688 | $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS | 692 | $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS |
689 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | 693 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< |
690 | $(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS | 694 | $(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS |
691 | $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $< | 695 | $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $< |
692 | $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS | 696 | $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS |
693 | $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $< | 697 | $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $< |
694 | $(OUTPUT)%.o: %.S | 698 | $(OUTPUT)%.o: %.S |
695 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | 699 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< |
696 | $(OUTPUT)%.s: %.S | 700 | $(OUTPUT)%.s: %.S |
697 | $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $< | 701 | $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $< |
698 | 702 | ||
699 | $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS | 703 | $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS |
700 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | 704 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ |
701 | '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ | 705 | '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ |
702 | '-DPREFIX="$(prefix_SQ)"' \ | 706 | '-DPREFIX="$(prefix_SQ)"' \ |
703 | $< | 707 | $< |
704 | 708 | ||
705 | $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS | 709 | $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS |
706 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | 710 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ |
707 | '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \ | 711 | '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \ |
708 | $< | 712 | $< |
709 | 713 | ||
710 | $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS | 714 | $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS |
711 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | 715 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ |
712 | -DPYTHONPATH='"$(OUTPUT)python"' \ | 716 | -DPYTHONPATH='"$(OUTPUT)python"' \ |
713 | -DPYTHON='"$(PYTHON_WORD)"' \ | 717 | -DPYTHON='"$(PYTHON_WORD)"' \ |
714 | $< | 718 | $< |
715 | 719 | ||
716 | $(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c | 720 | $(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c |
717 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $< | 721 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $< |
718 | 722 | ||
719 | $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS | 723 | $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS |
720 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 724 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
721 | 725 | ||
722 | $(OUTPUT)ui/setup.o: ui/setup.c $(OUTPUT)PERF-CFLAGS | 726 | $(OUTPUT)ui/setup.o: ui/setup.c $(OUTPUT)PERF-CFLAGS |
723 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DLIBDIR='"$(libdir_SQ)"' $< | 727 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DLIBDIR='"$(libdir_SQ)"' $< |
724 | 728 | ||
725 | $(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS | 729 | $(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS |
726 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 730 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
727 | 731 | ||
728 | $(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS | 732 | $(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS |
729 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 733 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
730 | 734 | ||
731 | $(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS | 735 | $(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS |
732 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 736 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
733 | 737 | ||
734 | $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS | 738 | $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS |
735 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 739 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
736 | 740 | ||
737 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS | 741 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS |
738 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 742 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
739 | 743 | ||
740 | $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS | 744 | $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS |
741 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | 745 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< |
742 | 746 | ||
743 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 747 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
748 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | ||
749 | |||
750 | $(OUTPUT)util/hweight.o: ../../lib/hweight.c $(OUTPUT)PERF-CFLAGS | ||
744 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 751 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
745 | 752 | ||
746 | $(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c $(OUTPUT)PERF-CFLAGS | 753 | $(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c $(OUTPUT)PERF-CFLAGS |
747 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 754 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
748 | 755 | ||
749 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS | 756 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS |
750 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $< | 757 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $< |
751 | 758 | ||
752 | $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS | 759 | $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS |
753 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $< | 760 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $< |
754 | 761 | ||
755 | $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS | 762 | $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS |
756 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $< | 763 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $< |
757 | 764 | ||
758 | $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS | 765 | $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS |
759 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | 766 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< |
760 | 767 | ||
761 | $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS | 768 | $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS |
762 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< | 769 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< |
763 | 770 | ||
764 | $(OUTPUT)perf-%: %.o $(PERFLIBS) | 771 | $(OUTPUT)perf-%: %.o $(PERFLIBS) |
765 | $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS) | 772 | $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS) |
766 | 773 | ||
767 | ifndef NO_PERF_READ_VDSO32 | 774 | ifndef NO_PERF_READ_VDSO32 |
768 | $(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c | 775 | $(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c |
769 | $(QUIET_CC)$(CC) -m32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c | 776 | $(QUIET_CC)$(CC) -m32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c |
770 | endif | 777 | endif |
771 | 778 | ||
772 | ifndef NO_PERF_READ_VDSOX32 | 779 | ifndef NO_PERF_READ_VDSOX32 |
773 | $(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c | 780 | $(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c |
774 | $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c | 781 | $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c |
775 | endif | 782 | endif |
776 | 783 | ||
777 | $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) | 784 | $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) |
778 | $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) | 785 | $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) |
779 | 786 | ||
780 | # we compile into subdirectories. if the target directory is not the source directory, they might not exists. So | 787 | # we compile into subdirectories. if the target directory is not the source directory, they might not exists. So |
781 | # we depend the various files onto their directories. | 788 | # we depend the various files onto their directories. |
782 | DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS) | 789 | DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS) |
783 | DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h | 790 | DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h |
784 | # no need to add flex objects, because they depend on bison ones | 791 | # no need to add flex objects, because they depend on bison ones |
785 | DIRECTORY_DEPS += $(OUTPUT)util/parse-events-bison.c | 792 | DIRECTORY_DEPS += $(OUTPUT)util/parse-events-bison.c |
786 | DIRECTORY_DEPS += $(OUTPUT)util/pmu-bison.c | 793 | DIRECTORY_DEPS += $(OUTPUT)util/pmu-bison.c |
787 | 794 | ||
788 | OUTPUT_DIRECTORIES := $(sort $(dir $(DIRECTORY_DEPS))) | 795 | OUTPUT_DIRECTORIES := $(sort $(dir $(DIRECTORY_DEPS))) |
789 | 796 | ||
790 | $(DIRECTORY_DEPS): | $(OUTPUT_DIRECTORIES) | 797 | $(DIRECTORY_DEPS): | $(OUTPUT_DIRECTORIES) |
791 | # In the second step, we make a rule to actually create these directories | 798 | # In the second step, we make a rule to actually create these directories |
792 | $(OUTPUT_DIRECTORIES): | 799 | $(OUTPUT_DIRECTORIES): |
793 | $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null | 800 | $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null |
794 | 801 | ||
795 | $(LIB_FILE): $(LIB_OBJS) | 802 | $(LIB_FILE): $(LIB_OBJS) |
796 | $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) | 803 | $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) |
797 | 804 | ||
798 | # libtraceevent.a | 805 | # libtraceevent.a |
799 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) | 806 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) |
800 | 807 | ||
801 | LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT) | 808 | LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT) |
802 | LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)" | 809 | LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)" |
803 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) | 810 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) |
804 | 811 | ||
805 | $(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS | 812 | $(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS |
806 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins | 813 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins |
807 | 814 | ||
808 | $(LIBTRACEEVENT)-clean: | 815 | $(LIBTRACEEVENT)-clean: |
809 | $(call QUIET_CLEAN, libtraceevent) | 816 | $(call QUIET_CLEAN, libtraceevent) |
810 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null | 817 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null |
811 | 818 | ||
812 | install-traceevent-plugins: $(LIBTRACEEVENT) | 819 | install-traceevent-plugins: $(LIBTRACEEVENT) |
813 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins | 820 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins |
814 | 821 | ||
815 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch]) | 822 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch]) |
816 | 823 | ||
817 | # if subdir is set, we've been called from above so target has been built | 824 | # if subdir is set, we've been called from above so target has been built |
818 | # already | 825 | # already |
819 | $(LIBAPIKFS): $(LIBAPIKFS_SOURCES) | 826 | $(LIBAPIKFS): $(LIBAPIKFS_SOURCES) |
820 | ifeq ($(subdir),) | 827 | ifeq ($(subdir),) |
821 | $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a | 828 | $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a |
822 | endif | 829 | endif |
823 | 830 | ||
824 | $(LIBAPIKFS)-clean: | 831 | $(LIBAPIKFS)-clean: |
825 | ifeq ($(subdir),) | 832 | ifeq ($(subdir),) |
826 | $(call QUIET_CLEAN, libapikfs) | 833 | $(call QUIET_CLEAN, libapikfs) |
827 | @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null | 834 | @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null |
828 | endif | 835 | endif |
829 | 836 | ||
830 | help: | 837 | help: |
831 | @echo 'Perf make targets:' | 838 | @echo 'Perf make targets:' |
832 | @echo ' doc - make *all* documentation (see below)' | 839 | @echo ' doc - make *all* documentation (see below)' |
833 | @echo ' man - make manpage documentation (access with man <foo>)' | 840 | @echo ' man - make manpage documentation (access with man <foo>)' |
834 | @echo ' html - make html documentation' | 841 | @echo ' html - make html documentation' |
835 | @echo ' info - make GNU info documentation (access with info <foo>)' | 842 | @echo ' info - make GNU info documentation (access with info <foo>)' |
836 | @echo ' pdf - make pdf documentation' | 843 | @echo ' pdf - make pdf documentation' |
837 | @echo ' TAGS - use etags to make tag information for source browsing' | 844 | @echo ' TAGS - use etags to make tag information for source browsing' |
838 | @echo ' tags - use ctags to make tag information for source browsing' | 845 | @echo ' tags - use ctags to make tag information for source browsing' |
839 | @echo ' cscope - use cscope to make interactive browsing database' | 846 | @echo ' cscope - use cscope to make interactive browsing database' |
840 | @echo '' | 847 | @echo '' |
841 | @echo 'Perf install targets:' | 848 | @echo 'Perf install targets:' |
842 | @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed' | 849 | @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed' |
843 | @echo ' HINT: use "prefix" or "DESTDIR" to install to a particular' | 850 | @echo ' HINT: use "prefix" or "DESTDIR" to install to a particular' |
844 | @echo ' path like "make prefix=/usr/local install install-doc"' | 851 | @echo ' path like "make prefix=/usr/local install install-doc"' |
845 | @echo ' install - install compiled binaries' | 852 | @echo ' install - install compiled binaries' |
846 | @echo ' install-doc - install *all* documentation' | 853 | @echo ' install-doc - install *all* documentation' |
847 | @echo ' install-man - install manpage documentation' | 854 | @echo ' install-man - install manpage documentation' |
848 | @echo ' install-html - install html documentation' | 855 | @echo ' install-html - install html documentation' |
849 | @echo ' install-info - install GNU info documentation' | 856 | @echo ' install-info - install GNU info documentation' |
850 | @echo ' install-pdf - install pdf documentation' | 857 | @echo ' install-pdf - install pdf documentation' |
851 | @echo '' | 858 | @echo '' |
852 | @echo ' quick-install-doc - alias for quick-install-man' | 859 | @echo ' quick-install-doc - alias for quick-install-man' |
853 | @echo ' quick-install-man - install the documentation quickly' | 860 | @echo ' quick-install-man - install the documentation quickly' |
854 | @echo ' quick-install-html - install the html documentation quickly' | 861 | @echo ' quick-install-html - install the html documentation quickly' |
855 | @echo '' | 862 | @echo '' |
856 | @echo 'Perf maintainer targets:' | 863 | @echo 'Perf maintainer targets:' |
857 | @echo ' clean - clean all binary objects and build output' | 864 | @echo ' clean - clean all binary objects and build output' |
858 | 865 | ||
859 | 866 | ||
860 | DOC_TARGETS := doc man html info pdf | 867 | DOC_TARGETS := doc man html info pdf |
861 | 868 | ||
862 | INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man | 869 | INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man |
863 | INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html | 870 | INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html |
864 | 871 | ||
865 | # 'make doc' should call 'make -C Documentation all' | 872 | # 'make doc' should call 'make -C Documentation all' |
866 | $(DOC_TARGETS): | 873 | $(DOC_TARGETS): |
867 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) | 874 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) |
868 | 875 | ||
869 | TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol | 876 | TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol |
870 | TAG_FILES= ../../include/uapi/linux/perf_event.h | 877 | TAG_FILES= ../../include/uapi/linux/perf_event.h |
871 | 878 | ||
872 | TAGS: | 879 | TAGS: |
873 | $(QUIET_GEN)$(RM) TAGS; \ | 880 | $(QUIET_GEN)$(RM) TAGS; \ |
874 | $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES) | 881 | $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES) |
875 | 882 | ||
876 | tags: | 883 | tags: |
877 | $(QUIET_GEN)$(RM) tags; \ | 884 | $(QUIET_GEN)$(RM) tags; \ |
878 | $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES) | 885 | $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES) |
879 | 886 | ||
880 | cscope: | 887 | cscope: |
881 | $(QUIET_GEN)$(RM) cscope*; \ | 888 | $(QUIET_GEN)$(RM) cscope*; \ |
882 | $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES) | 889 | $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES) |
883 | 890 | ||
884 | ### Detect prefix changes | 891 | ### Detect prefix changes |
885 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ | 892 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ |
886 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ) | 893 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ) |
887 | 894 | ||
888 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS | 895 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS |
889 | @FLAGS='$(TRACK_CFLAGS)'; \ | 896 | @FLAGS='$(TRACK_CFLAGS)'; \ |
890 | if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \ | 897 | if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \ |
891 | echo 1>&2 " FLAGS: * new build flags or prefix"; \ | 898 | echo 1>&2 " FLAGS: * new build flags or prefix"; \ |
892 | echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ | 899 | echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ |
893 | fi | 900 | fi |
894 | 901 | ||
895 | ### Testing rules | 902 | ### Testing rules |
896 | 903 | ||
897 | # GNU make supports exporting all variables by "export" without parameters. | 904 | # GNU make supports exporting all variables by "export" without parameters. |
898 | # However, the environment gets quite big, and some programs have problems | 905 | # However, the environment gets quite big, and some programs have problems |
899 | # with that. | 906 | # with that. |
900 | 907 | ||
901 | check: $(OUTPUT)common-cmds.h | 908 | check: $(OUTPUT)common-cmds.h |
902 | if sparse; \ | 909 | if sparse; \ |
903 | then \ | 910 | then \ |
904 | for i in *.c */*.c; \ | 911 | for i in *.c */*.c; \ |
905 | do \ | 912 | do \ |
906 | sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ | 913 | sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ |
907 | done; \ | 914 | done; \ |
908 | else \ | 915 | else \ |
909 | exit 1; \ | 916 | exit 1; \ |
910 | fi | 917 | fi |
911 | 918 | ||
912 | ### Installation rules | 919 | ### Installation rules |
913 | 920 | ||
914 | install-gtk: | 921 | install-gtk: |
915 | 922 | ||
916 | install-bin: all install-gtk | 923 | install-bin: all install-gtk |
917 | $(call QUIET_INSTALL, binaries) \ | 924 | $(call QUIET_INSTALL, binaries) \ |
918 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \ | 925 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \ |
919 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \ | 926 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \ |
920 | $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace' | 927 | $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace' |
921 | ifndef NO_PERF_READ_VDSO32 | 928 | ifndef NO_PERF_READ_VDSO32 |
922 | $(call QUIET_INSTALL, perf-read-vdso32) \ | 929 | $(call QUIET_INSTALL, perf-read-vdso32) \ |
923 | $(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)'; | 930 | $(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)'; |
924 | endif | 931 | endif |
925 | ifndef NO_PERF_READ_VDSOX32 | 932 | ifndef NO_PERF_READ_VDSOX32 |
926 | $(call QUIET_INSTALL, perf-read-vdsox32) \ | 933 | $(call QUIET_INSTALL, perf-read-vdsox32) \ |
927 | $(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)'; | 934 | $(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)'; |
928 | endif | 935 | endif |
929 | $(call QUIET_INSTALL, libexec) \ | 936 | $(call QUIET_INSTALL, libexec) \ |
930 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 937 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
931 | $(call QUIET_INSTALL, perf-archive) \ | 938 | $(call QUIET_INSTALL, perf-archive) \ |
932 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 939 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
933 | $(call QUIET_INSTALL, perf-with-kcore) \ | 940 | $(call QUIET_INSTALL, perf-with-kcore) \ |
934 | $(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 941 | $(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
935 | ifndef NO_LIBPERL | 942 | ifndef NO_LIBPERL |
936 | $(call QUIET_INSTALL, perl-scripts) \ | 943 | $(call QUIET_INSTALL, perl-scripts) \ |
937 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ | 944 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ |
938 | $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ | 945 | $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ |
939 | $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \ | 946 | $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \ |
940 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \ | 947 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \ |
941 | $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' | 948 | $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' |
942 | endif | 949 | endif |
943 | ifndef NO_LIBPYTHON | 950 | ifndef NO_LIBPYTHON |
944 | $(call QUIET_INSTALL, python-scripts) \ | 951 | $(call QUIET_INSTALL, python-scripts) \ |
945 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \ | 952 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \ |
946 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'; \ | 953 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'; \ |
947 | $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \ | 954 | $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \ |
948 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \ | 955 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \ |
949 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' | 956 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
950 | endif | 957 | endif |
951 | $(call QUIET_INSTALL, perf_completion-script) \ | 958 | $(call QUIET_INSTALL, perf_completion-script) \ |
952 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ | 959 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ |
953 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' | 960 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' |
954 | $(call QUIET_INSTALL, tests) \ | 961 | $(call QUIET_INSTALL, tests) \ |
955 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 962 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
956 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 963 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
957 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ | 964 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ |
958 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 965 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
959 | 966 | ||
960 | install: install-bin try-install-man install-traceevent-plugins | 967 | install: install-bin try-install-man install-traceevent-plugins |
961 | 968 | ||
962 | install-python_ext: | 969 | install-python_ext: |
963 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | 970 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' |
964 | 971 | ||
965 | # 'make install-doc' should call 'make -C Documentation install' | 972 | # 'make install-doc' should call 'make -C Documentation install' |
966 | $(INSTALL_DOC_TARGETS): | 973 | $(INSTALL_DOC_TARGETS): |
967 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=) | 974 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=) |
968 | 975 | ||
969 | ### Cleaning rules | 976 | ### Cleaning rules |
970 | 977 | ||
971 | # | 978 | # |
972 | # This is here, not in config/Makefile, because config/Makefile does | 979 | # This is here, not in config/Makefile, because config/Makefile does |
973 | # not get included for the clean target: | 980 | # not get included for the clean target: |
974 | # | 981 | # |
975 | config-clean: | 982 | config-clean: |
976 | $(call QUIET_CLEAN, config) | 983 | $(call QUIET_CLEAN, config) |
977 | @$(MAKE) -C config/feature-checks clean >/dev/null | 984 | @$(MAKE) -C config/feature-checks clean >/dev/null |
978 | 985 | ||
979 | clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean | 986 | clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean |
980 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) | 987 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) |
981 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 | 988 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 |
982 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* | 989 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* |
983 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean | 990 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean |
984 | $(python-clean) | 991 | $(python-clean) |
985 | 992 | ||
986 | # | 993 | # |
987 | # Trick: if ../../.git does not exist - we are building out of tree for example, | 994 | # Trick: if ../../.git does not exist - we are building out of tree for example, |
988 | # then force version regeneration: | 995 | # then force version regeneration: |
989 | # | 996 | # |
990 | ifeq ($(wildcard ../../.git/HEAD),) | 997 | ifeq ($(wildcard ../../.git/HEAD),) |
991 | GIT-HEAD-PHONY = ../../.git/HEAD | 998 | GIT-HEAD-PHONY = ../../.git/HEAD |
992 | else | 999 | else |
993 | GIT-HEAD-PHONY = | 1000 | GIT-HEAD-PHONY = |
994 | endif | 1001 | endif |
995 | 1002 | ||
996 | .PHONY: all install clean config-clean strip install-gtk | 1003 | .PHONY: all install clean config-clean strip install-gtk |
997 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell | 1004 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell |
998 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope .FORCE-PERF-CFLAGS | 1005 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope .FORCE-PERF-CFLAGS |
999 | 1006 |
tools/perf/arch/powerpc/util/skip-callchain-idx.c
1 | /* | 1 | /* |
2 | * Use DWARF Debug information to skip unnecessary callchain entries. | 2 | * Use DWARF Debug information to skip unnecessary callchain entries. |
3 | * | 3 | * |
4 | * Copyright (C) 2014 Sukadev Bhattiprolu, IBM Corporation. | 4 | * Copyright (C) 2014 Sukadev Bhattiprolu, IBM Corporation. |
5 | * Copyright (C) 2014 Ulrich Weigand, IBM Corporation. | 5 | * Copyright (C) 2014 Ulrich Weigand, IBM Corporation. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | #include <inttypes.h> | 12 | #include <inttypes.h> |
13 | #include <dwarf.h> | 13 | #include <dwarf.h> |
14 | #include <elfutils/libdwfl.h> | 14 | #include <elfutils/libdwfl.h> |
15 | 15 | ||
16 | #include "util/thread.h" | 16 | #include "util/thread.h" |
17 | #include "util/callchain.h" | 17 | #include "util/callchain.h" |
18 | #include "util/debug.h" | 18 | #include "util/debug.h" |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * When saving the callchain on Power, the kernel conservatively saves | 21 | * When saving the callchain on Power, the kernel conservatively saves |
22 | * excess entries in the callchain. A few of these entries are needed | 22 | * excess entries in the callchain. A few of these entries are needed |
23 | * in some cases but not others. If the unnecessary entries are not | 23 | * in some cases but not others. If the unnecessary entries are not |
24 | * ignored, we end up with duplicate arcs in the call-graphs. Use | 24 | * ignored, we end up with duplicate arcs in the call-graphs. Use |
25 | * DWARF debug information to skip over any unnecessary callchain | 25 | * DWARF debug information to skip over any unnecessary callchain |
26 | * entries. | 26 | * entries. |
27 | * | 27 | * |
28 | * See function header for arch_adjust_callchain() below for more details. | 28 | * See function header for arch_adjust_callchain() below for more details. |
29 | * | 29 | * |
30 | * The libdwfl code in this file is based on code from elfutils | 30 | * The libdwfl code in this file is based on code from elfutils |
31 | * (libdwfl/argp-std.c, libdwfl/tests/addrcfi.c, etc). | 31 | * (libdwfl/argp-std.c, libdwfl/tests/addrcfi.c, etc). |
32 | */ | 32 | */ |
33 | static char *debuginfo_path; | 33 | static char *debuginfo_path; |
34 | 34 | ||
35 | static const Dwfl_Callbacks offline_callbacks = { | 35 | static const Dwfl_Callbacks offline_callbacks = { |
36 | .debuginfo_path = &debuginfo_path, | 36 | .debuginfo_path = &debuginfo_path, |
37 | .find_debuginfo = dwfl_standard_find_debuginfo, | 37 | .find_debuginfo = dwfl_standard_find_debuginfo, |
38 | .section_address = dwfl_offline_section_address, | 38 | .section_address = dwfl_offline_section_address, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Use the DWARF expression for the Call-frame-address and determine | 43 | * Use the DWARF expression for the Call-frame-address and determine |
44 | * if return address is in LR and if a new frame was allocated. | 44 | * if return address is in LR and if a new frame was allocated. |
45 | */ | 45 | */ |
46 | static int check_return_reg(int ra_regno, Dwarf_Frame *frame) | 46 | static int check_return_reg(int ra_regno, Dwarf_Frame *frame) |
47 | { | 47 | { |
48 | Dwarf_Op ops_mem[2]; | 48 | Dwarf_Op ops_mem[2]; |
49 | Dwarf_Op dummy; | 49 | Dwarf_Op dummy; |
50 | Dwarf_Op *ops = &dummy; | 50 | Dwarf_Op *ops = &dummy; |
51 | size_t nops; | 51 | size_t nops; |
52 | int result; | 52 | int result; |
53 | 53 | ||
54 | result = dwarf_frame_register(frame, ra_regno, ops_mem, &ops, &nops); | 54 | result = dwarf_frame_register(frame, ra_regno, ops_mem, &ops, &nops); |
55 | if (result < 0) { | 55 | if (result < 0) { |
56 | pr_debug("dwarf_frame_register() %s\n", dwarf_errmsg(-1)); | 56 | pr_debug("dwarf_frame_register() %s\n", dwarf_errmsg(-1)); |
57 | return -1; | 57 | return -1; |
58 | } | 58 | } |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Check if return address is on the stack. | 61 | * Check if return address is on the stack. |
62 | */ | 62 | */ |
63 | if (nops != 0 || ops != NULL) | 63 | if (nops != 0 || ops != NULL) |
64 | return 0; | 64 | return 0; |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Return address is in LR. Check if a frame was allocated | 67 | * Return address is in LR. Check if a frame was allocated |
68 | * but not-yet used. | 68 | * but not-yet used. |
69 | */ | 69 | */ |
70 | result = dwarf_frame_cfa(frame, &ops, &nops); | 70 | result = dwarf_frame_cfa(frame, &ops, &nops); |
71 | if (result < 0) { | 71 | if (result < 0) { |
72 | pr_debug("dwarf_frame_cfa() returns %d, %s\n", result, | 72 | pr_debug("dwarf_frame_cfa() returns %d, %s\n", result, |
73 | dwarf_errmsg(-1)); | 73 | dwarf_errmsg(-1)); |
74 | return -1; | 74 | return -1; |
75 | } | 75 | } |
76 | 76 | ||
77 | /* | 77 | /* |
78 | * If call frame address is in r1, no new frame was allocated. | 78 | * If call frame address is in r1, no new frame was allocated. |
79 | */ | 79 | */ |
80 | if (nops == 1 && ops[0].atom == DW_OP_bregx && ops[0].number == 1 && | 80 | if (nops == 1 && ops[0].atom == DW_OP_bregx && ops[0].number == 1 && |
81 | ops[0].number2 == 0) | 81 | ops[0].number2 == 0) |
82 | return 1; | 82 | return 1; |
83 | 83 | ||
84 | /* | 84 | /* |
85 | * A new frame was allocated but has not yet been used. | 85 | * A new frame was allocated but has not yet been used. |
86 | */ | 86 | */ |
87 | return 2; | 87 | return 2; |
88 | } | 88 | } |
89 | 89 | ||
90 | /* | 90 | /* |
91 | * Get the DWARF frame from the .eh_frame section. | 91 | * Get the DWARF frame from the .eh_frame section. |
92 | */ | 92 | */ |
93 | static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc) | 93 | static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc) |
94 | { | 94 | { |
95 | int result; | 95 | int result; |
96 | Dwarf_Addr bias; | 96 | Dwarf_Addr bias; |
97 | Dwarf_CFI *cfi; | 97 | Dwarf_CFI *cfi; |
98 | Dwarf_Frame *frame; | 98 | Dwarf_Frame *frame; |
99 | 99 | ||
100 | cfi = dwfl_module_eh_cfi(mod, &bias); | 100 | cfi = dwfl_module_eh_cfi(mod, &bias); |
101 | if (!cfi) { | 101 | if (!cfi) { |
102 | pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1)); | 102 | pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1)); |
103 | return NULL; | 103 | return NULL; |
104 | } | 104 | } |
105 | 105 | ||
106 | result = dwarf_cfi_addrframe(cfi, pc, &frame); | 106 | result = dwarf_cfi_addrframe(cfi, pc-bias, &frame); |
107 | if (result) { | 107 | if (result) { |
108 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); | 108 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); |
109 | return NULL; | 109 | return NULL; |
110 | } | 110 | } |
111 | 111 | ||
112 | return frame; | 112 | return frame; |
113 | } | 113 | } |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Get the DWARF frame from the .debug_frame section. | 116 | * Get the DWARF frame from the .debug_frame section. |
117 | */ | 117 | */ |
118 | static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc) | 118 | static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc) |
119 | { | 119 | { |
120 | Dwarf_CFI *cfi; | 120 | Dwarf_CFI *cfi; |
121 | Dwarf_Addr bias; | 121 | Dwarf_Addr bias; |
122 | Dwarf_Frame *frame; | 122 | Dwarf_Frame *frame; |
123 | int result; | 123 | int result; |
124 | 124 | ||
125 | cfi = dwfl_module_dwarf_cfi(mod, &bias); | 125 | cfi = dwfl_module_dwarf_cfi(mod, &bias); |
126 | if (!cfi) { | 126 | if (!cfi) { |
127 | pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1)); | 127 | pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1)); |
128 | return NULL; | 128 | return NULL; |
129 | } | 129 | } |
130 | 130 | ||
131 | result = dwarf_cfi_addrframe(cfi, pc, &frame); | 131 | result = dwarf_cfi_addrframe(cfi, pc-bias, &frame); |
132 | if (result) { | 132 | if (result) { |
133 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); | 133 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); |
134 | return NULL; | 134 | return NULL; |
135 | } | 135 | } |
136 | 136 | ||
137 | return frame; | 137 | return frame; |
138 | } | 138 | } |
139 | 139 | ||
140 | /* | 140 | /* |
141 | * Return: | 141 | * Return: |
142 | * 0 if return address for the program counter @pc is on stack | 142 | * 0 if return address for the program counter @pc is on stack |
143 | * 1 if return address is in LR and no new stack frame was allocated | 143 | * 1 if return address is in LR and no new stack frame was allocated |
144 | * 2 if return address is in LR and a new frame was allocated (but not | 144 | * 2 if return address is in LR and a new frame was allocated (but not |
145 | * yet used) | 145 | * yet used) |
146 | * -1 in case of errors | 146 | * -1 in case of errors |
147 | */ | 147 | */ |
148 | static int check_return_addr(struct dso *dso, Dwarf_Addr pc) | 148 | static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc) |
149 | { | 149 | { |
150 | int rc = -1; | 150 | int rc = -1; |
151 | Dwfl *dwfl; | 151 | Dwfl *dwfl; |
152 | Dwfl_Module *mod; | 152 | Dwfl_Module *mod; |
153 | Dwarf_Frame *frame; | 153 | Dwarf_Frame *frame; |
154 | int ra_regno; | 154 | int ra_regno; |
155 | Dwarf_Addr start = pc; | 155 | Dwarf_Addr start = pc; |
156 | Dwarf_Addr end = pc; | 156 | Dwarf_Addr end = pc; |
157 | bool signalp; | 157 | bool signalp; |
158 | const char *exec_file = dso->long_name; | ||
158 | 159 | ||
159 | dwfl = dso->dwfl; | 160 | dwfl = dso->dwfl; |
160 | 161 | ||
161 | if (!dwfl) { | 162 | if (!dwfl) { |
162 | dwfl = dwfl_begin(&offline_callbacks); | 163 | dwfl = dwfl_begin(&offline_callbacks); |
163 | if (!dwfl) { | 164 | if (!dwfl) { |
164 | pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1)); | 165 | pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1)); |
165 | return -1; | 166 | return -1; |
166 | } | 167 | } |
167 | 168 | ||
168 | if (dwfl_report_offline(dwfl, "", dso->long_name, -1) == NULL) { | 169 | mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1, |
169 | pr_debug("dwfl_report_offline() failed %s\n", | 170 | map_start, false); |
171 | if (!mod) { | ||
172 | pr_debug("dwfl_report_elf() failed %s\n", | ||
170 | dwarf_errmsg(-1)); | 173 | dwarf_errmsg(-1)); |
171 | /* | 174 | /* |
172 | * We normally cache the DWARF debug info and never | 175 | * We normally cache the DWARF debug info and never |
173 | * call dwfl_end(). But to prevent fd leak, free in | 176 | * call dwfl_end(). But to prevent fd leak, free in |
174 | * case of error. | 177 | * case of error. |
175 | */ | 178 | */ |
176 | dwfl_end(dwfl); | 179 | dwfl_end(dwfl); |
177 | goto out; | 180 | goto out; |
178 | } | 181 | } |
179 | dso->dwfl = dwfl; | 182 | dso->dwfl = dwfl; |
180 | } | 183 | } |
181 | 184 | ||
182 | mod = dwfl_addrmodule(dwfl, pc); | 185 | mod = dwfl_addrmodule(dwfl, pc); |
183 | if (!mod) { | 186 | if (!mod) { |
184 | pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1)); | 187 | pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1)); |
185 | goto out; | 188 | goto out; |
186 | } | 189 | } |
187 | 190 | ||
188 | /* | 191 | /* |
189 | * To work with split debug info files (eg: glibc), check both | 192 | * To work with split debug info files (eg: glibc), check both |
190 | * .eh_frame and .debug_frame sections of the ELF header. | 193 | * .eh_frame and .debug_frame sections of the ELF header. |
191 | */ | 194 | */ |
192 | frame = get_eh_frame(mod, pc); | 195 | frame = get_eh_frame(mod, pc); |
193 | if (!frame) { | 196 | if (!frame) { |
194 | frame = get_dwarf_frame(mod, pc); | 197 | frame = get_dwarf_frame(mod, pc); |
195 | if (!frame) | 198 | if (!frame) |
196 | goto out; | 199 | goto out; |
197 | } | 200 | } |
198 | 201 | ||
199 | ra_regno = dwarf_frame_info(frame, &start, &end, &signalp); | 202 | ra_regno = dwarf_frame_info(frame, &start, &end, &signalp); |
200 | if (ra_regno < 0) { | 203 | if (ra_regno < 0) { |
201 | pr_debug("Return address register unavailable: %s\n", | 204 | pr_debug("Return address register unavailable: %s\n", |
202 | dwarf_errmsg(-1)); | 205 | dwarf_errmsg(-1)); |
203 | goto out; | 206 | goto out; |
204 | } | 207 | } |
205 | 208 | ||
206 | rc = check_return_reg(ra_regno, frame); | 209 | rc = check_return_reg(ra_regno, frame); |
207 | 210 | ||
208 | out: | 211 | out: |
209 | return rc; | 212 | return rc; |
210 | } | 213 | } |
211 | 214 | ||
212 | /* | 215 | /* |
213 | * The callchain saved by the kernel always includes the link register (LR). | 216 | * The callchain saved by the kernel always includes the link register (LR). |
214 | * | 217 | * |
215 | * 0: PERF_CONTEXT_USER | 218 | * 0: PERF_CONTEXT_USER |
216 | * 1: Program counter (Next instruction pointer) | 219 | * 1: Program counter (Next instruction pointer) |
217 | * 2: LR value | 220 | * 2: LR value |
218 | * 3: Caller's caller | 221 | * 3: Caller's caller |
219 | * 4: ... | 222 | * 4: ... |
220 | * | 223 | * |
221 | * The value in LR is only needed when it holds a return address. If the | 224 | * The value in LR is only needed when it holds a return address. If the |
222 | * return address is on the stack, we should ignore the LR value. | 225 | * return address is on the stack, we should ignore the LR value. |
223 | * | 226 | * |
224 | * Further, when the return address is in the LR, if a new frame was just | 227 | * Further, when the return address is in the LR, if a new frame was just |
225 | * allocated but the LR was not saved into it, then the LR contains the | 228 | * allocated but the LR was not saved into it, then the LR contains the |
226 | * caller, slot 4: contains the caller's caller and the contents of slot 3: | 229 | * caller, slot 4: contains the caller's caller and the contents of slot 3: |
227 | * (chain->ips[3]) is undefined and must be ignored. | 230 | * (chain->ips[3]) is undefined and must be ignored. |
228 | * | 231 | * |
229 | * Use DWARF debug information to determine if any entries need to be skipped. | 232 | * Use DWARF debug information to determine if any entries need to be skipped. |
230 | * | 233 | * |
231 | * Return: | 234 | * Return: |
232 | * index: of callchain entry that needs to be ignored (if any) | 235 | * index: of callchain entry that needs to be ignored (if any) |
233 | * -1 if no entry needs to be ignored or in case of errors | 236 | * -1 if no entry needs to be ignored or in case of errors |
234 | */ | 237 | */ |
235 | int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) | 238 | int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) |
236 | { | 239 | { |
237 | struct addr_location al; | 240 | struct addr_location al; |
238 | struct dso *dso = NULL; | 241 | struct dso *dso = NULL; |
239 | int rc; | 242 | int rc; |
240 | u64 ip; | 243 | u64 ip; |
241 | u64 skip_slot = -1; | 244 | u64 skip_slot = -1; |
242 | 245 | ||
243 | if (chain->nr < 3) | 246 | if (chain->nr < 3) |
244 | return skip_slot; | 247 | return skip_slot; |
245 | 248 | ||
246 | ip = chain->ips[2]; | 249 | ip = chain->ips[2]; |
247 | 250 | ||
248 | thread__find_addr_location(thread, PERF_RECORD_MISC_USER, | 251 | thread__find_addr_location(thread, PERF_RECORD_MISC_USER, |
249 | MAP__FUNCTION, ip, &al); | 252 | MAP__FUNCTION, ip, &al); |
250 | 253 | ||
251 | if (al.map) | 254 | if (al.map) |
252 | dso = al.map->dso; | 255 | dso = al.map->dso; |
253 | 256 | ||
254 | if (!dso) { | 257 | if (!dso) { |
255 | pr_debug("%" PRIx64 " dso is NULL\n", ip); | 258 | pr_debug("%" PRIx64 " dso is NULL\n", ip); |
256 | return skip_slot; | 259 | return skip_slot; |
257 | } | 260 | } |
258 | 261 | ||
259 | rc = check_return_addr(dso, ip); | 262 | rc = check_return_addr(dso, al.map->start, ip); |
260 | 263 | ||
261 | pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n", | 264 | pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n", |
262 | dso->long_name, chain->nr, ip, rc); | 265 | dso->long_name, al.sym->name, ip, rc); |
263 | 266 | ||
264 | if (rc == 0) { | 267 | if (rc == 0) { |
265 | /* | 268 | /* |
266 | * Return address on stack. Ignore LR value in callchain | 269 | * Return address on stack. Ignore LR value in callchain |
267 | */ | 270 | */ |
268 | skip_slot = 2; | 271 | skip_slot = 2; |
269 | } else if (rc == 2) { | 272 | } else if (rc == 2) { |
270 | /* | 273 | /* |
271 | * New frame allocated but return address still in LR. | 274 | * New frame allocated but return address still in LR. |
272 | * Ignore the caller's caller entry in callchain. | 275 | * Ignore the caller's caller entry in callchain. |
273 | */ | 276 | */ |
274 | skip_slot = 3; | 277 | skip_slot = 3; |
275 | } | 278 | } |
276 | return skip_slot; | 279 | return skip_slot; |
277 | } | 280 | } |
278 | 281 |
tools/perf/bench/sched-pipe.c
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * sched-pipe.c | 3 | * sched-pipe.c |
4 | * | 4 | * |
5 | * pipe: Benchmark for pipe() | 5 | * pipe: Benchmark for pipe() |
6 | * | 6 | * |
7 | * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> | 7 | * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> |
8 | * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c | 8 | * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c |
9 | * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | 9 | * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> |
10 | */ | 10 | */ |
11 | #include "../perf.h" | 11 | #include "../perf.h" |
12 | #include "../util/util.h" | 12 | #include "../util/util.h" |
13 | #include "../util/parse-options.h" | 13 | #include "../util/parse-options.h" |
14 | #include "../builtin.h" | 14 | #include "../builtin.h" |
15 | #include "bench.h" | 15 | #include "bench.h" |
16 | 16 | ||
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | #include <stdio.h> | 18 | #include <stdio.h> |
19 | #include <stdlib.h> | 19 | #include <stdlib.h> |
20 | #include <signal.h> | 20 | #include <signal.h> |
21 | #include <sys/wait.h> | 21 | #include <sys/wait.h> |
22 | #include <linux/unistd.h> | ||
23 | #include <string.h> | 22 | #include <string.h> |
24 | #include <errno.h> | 23 | #include <errno.h> |
25 | #include <assert.h> | 24 | #include <assert.h> |
26 | #include <sys/time.h> | 25 | #include <sys/time.h> |
27 | #include <sys/types.h> | 26 | #include <sys/types.h> |
27 | #include <sys/syscall.h> | ||
28 | 28 | ||
29 | #include <pthread.h> | 29 | #include <pthread.h> |
30 | 30 | ||
31 | struct thread_data { | 31 | struct thread_data { |
32 | int nr; | 32 | int nr; |
33 | int pipe_read; | 33 | int pipe_read; |
34 | int pipe_write; | 34 | int pipe_write; |
35 | pthread_t pthread; | 35 | pthread_t pthread; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | #define LOOPS_DEFAULT 1000000 | 38 | #define LOOPS_DEFAULT 1000000 |
39 | static int loops = LOOPS_DEFAULT; | 39 | static int loops = LOOPS_DEFAULT; |
40 | 40 | ||
41 | /* Use processes by default: */ | 41 | /* Use processes by default: */ |
42 | static bool threaded; | 42 | static bool threaded; |
43 | 43 | ||
44 | static const struct option options[] = { | 44 | static const struct option options[] = { |
45 | OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), | 45 | OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), |
46 | OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"), | 46 | OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"), |
47 | OPT_END() | 47 | OPT_END() |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static const char * const bench_sched_pipe_usage[] = { | 50 | static const char * const bench_sched_pipe_usage[] = { |
51 | "perf bench sched pipe <options>", | 51 | "perf bench sched pipe <options>", |
52 | NULL | 52 | NULL |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static void *worker_thread(void *__tdata) | 55 | static void *worker_thread(void *__tdata) |
56 | { | 56 | { |
57 | struct thread_data *td = __tdata; | 57 | struct thread_data *td = __tdata; |
58 | int m = 0, i; | 58 | int m = 0, i; |
59 | int ret; | 59 | int ret; |
60 | 60 | ||
61 | for (i = 0; i < loops; i++) { | 61 | for (i = 0; i < loops; i++) { |
62 | if (!td->nr) { | 62 | if (!td->nr) { |
63 | ret = read(td->pipe_read, &m, sizeof(int)); | 63 | ret = read(td->pipe_read, &m, sizeof(int)); |
64 | BUG_ON(ret != sizeof(int)); | 64 | BUG_ON(ret != sizeof(int)); |
65 | ret = write(td->pipe_write, &m, sizeof(int)); | 65 | ret = write(td->pipe_write, &m, sizeof(int)); |
66 | BUG_ON(ret != sizeof(int)); | 66 | BUG_ON(ret != sizeof(int)); |
67 | } else { | 67 | } else { |
68 | ret = write(td->pipe_write, &m, sizeof(int)); | 68 | ret = write(td->pipe_write, &m, sizeof(int)); |
69 | BUG_ON(ret != sizeof(int)); | 69 | BUG_ON(ret != sizeof(int)); |
70 | ret = read(td->pipe_read, &m, sizeof(int)); | 70 | ret = read(td->pipe_read, &m, sizeof(int)); |
71 | BUG_ON(ret != sizeof(int)); | 71 | BUG_ON(ret != sizeof(int)); |
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
75 | return NULL; | 75 | return NULL; |
76 | } | 76 | } |
77 | 77 | ||
78 | int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused) | 78 | int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused) |
79 | { | 79 | { |
80 | struct thread_data threads[2], *td; | 80 | struct thread_data threads[2], *td; |
81 | int pipe_1[2], pipe_2[2]; | 81 | int pipe_1[2], pipe_2[2]; |
82 | struct timeval start, stop, diff; | 82 | struct timeval start, stop, diff; |
83 | unsigned long long result_usec = 0; | 83 | unsigned long long result_usec = 0; |
84 | int nr_threads = 2; | 84 | int nr_threads = 2; |
85 | int t; | 85 | int t; |
86 | 86 | ||
87 | /* | 87 | /* |
88 | * why does "ret" exist? | 88 | * why does "ret" exist? |
89 | * discarding returned value of read(), write() | 89 | * discarding returned value of read(), write() |
90 | * causes error in building environment for perf | 90 | * causes error in building environment for perf |
91 | */ | 91 | */ |
92 | int __maybe_unused ret, wait_stat; | 92 | int __maybe_unused ret, wait_stat; |
93 | pid_t pid, retpid __maybe_unused; | 93 | pid_t pid, retpid __maybe_unused; |
94 | 94 | ||
95 | argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0); | 95 | argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0); |
96 | 96 | ||
97 | BUG_ON(pipe(pipe_1)); | 97 | BUG_ON(pipe(pipe_1)); |
98 | BUG_ON(pipe(pipe_2)); | 98 | BUG_ON(pipe(pipe_2)); |
99 | 99 | ||
100 | gettimeofday(&start, NULL); | 100 | gettimeofday(&start, NULL); |
101 | 101 | ||
102 | for (t = 0; t < nr_threads; t++) { | 102 | for (t = 0; t < nr_threads; t++) { |
103 | td = threads + t; | 103 | td = threads + t; |
104 | 104 | ||
105 | td->nr = t; | 105 | td->nr = t; |
106 | 106 | ||
107 | if (t == 0) { | 107 | if (t == 0) { |
108 | td->pipe_read = pipe_1[0]; | 108 | td->pipe_read = pipe_1[0]; |
109 | td->pipe_write = pipe_2[1]; | 109 | td->pipe_write = pipe_2[1]; |
110 | } else { | 110 | } else { |
111 | td->pipe_write = pipe_1[1]; | 111 | td->pipe_write = pipe_1[1]; |
112 | td->pipe_read = pipe_2[0]; | 112 | td->pipe_read = pipe_2[0]; |
113 | } | 113 | } |
114 | } | 114 | } |
115 | 115 | ||
116 | 116 | ||
117 | if (threaded) { | 117 | if (threaded) { |
118 | 118 | ||
119 | for (t = 0; t < nr_threads; t++) { | 119 | for (t = 0; t < nr_threads; t++) { |
120 | td = threads + t; | 120 | td = threads + t; |
121 | 121 | ||
122 | ret = pthread_create(&td->pthread, NULL, worker_thread, td); | 122 | ret = pthread_create(&td->pthread, NULL, worker_thread, td); |
123 | BUG_ON(ret); | 123 | BUG_ON(ret); |
124 | } | 124 | } |
125 | 125 | ||
126 | for (t = 0; t < nr_threads; t++) { | 126 | for (t = 0; t < nr_threads; t++) { |
127 | td = threads + t; | 127 | td = threads + t; |
128 | 128 | ||
129 | ret = pthread_join(td->pthread, NULL); | 129 | ret = pthread_join(td->pthread, NULL); |
130 | BUG_ON(ret); | 130 | BUG_ON(ret); |
131 | } | 131 | } |
132 | 132 | ||
133 | } else { | 133 | } else { |
134 | pid = fork(); | 134 | pid = fork(); |
135 | assert(pid >= 0); | 135 | assert(pid >= 0); |
136 | 136 | ||
137 | if (!pid) { | 137 | if (!pid) { |
138 | worker_thread(threads + 0); | 138 | worker_thread(threads + 0); |
139 | exit(0); | 139 | exit(0); |
140 | } else { | 140 | } else { |
141 | worker_thread(threads + 1); | 141 | worker_thread(threads + 1); |
142 | } | 142 | } |
143 | 143 | ||
144 | retpid = waitpid(pid, &wait_stat, 0); | 144 | retpid = waitpid(pid, &wait_stat, 0); |
145 | assert((retpid == pid) && WIFEXITED(wait_stat)); | 145 | assert((retpid == pid) && WIFEXITED(wait_stat)); |
146 | } | 146 | } |
147 | 147 | ||
148 | gettimeofday(&stop, NULL); | 148 | gettimeofday(&stop, NULL); |
149 | timersub(&stop, &start, &diff); | 149 | timersub(&stop, &start, &diff); |
150 | 150 | ||
151 | switch (bench_format) { | 151 | switch (bench_format) { |
152 | case BENCH_FORMAT_DEFAULT: | 152 | case BENCH_FORMAT_DEFAULT: |
153 | printf("# Executed %d pipe operations between two %s\n\n", | 153 | printf("# Executed %d pipe operations between two %s\n\n", |
154 | loops, threaded ? "threads" : "processes"); | 154 | loops, threaded ? "threads" : "processes"); |
155 | 155 | ||
156 | result_usec = diff.tv_sec * 1000000; | 156 | result_usec = diff.tv_sec * 1000000; |
157 | result_usec += diff.tv_usec; | 157 | result_usec += diff.tv_usec; |
158 | 158 | ||
159 | printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", | 159 | printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", |
160 | diff.tv_sec, | 160 | diff.tv_sec, |
161 | (unsigned long) (diff.tv_usec/1000)); | 161 | (unsigned long) (diff.tv_usec/1000)); |
162 | 162 | ||
163 | printf(" %14lf usecs/op\n", | 163 | printf(" %14lf usecs/op\n", |
164 | (double)result_usec / (double)loops); | 164 | (double)result_usec / (double)loops); |
165 | printf(" %14d ops/sec\n", | 165 | printf(" %14d ops/sec\n", |
166 | (int)((double)loops / | 166 | (int)((double)loops / |
167 | ((double)result_usec / (double)1000000))); | 167 | ((double)result_usec / (double)1000000))); |
168 | break; | 168 | break; |
169 | 169 | ||
170 | case BENCH_FORMAT_SIMPLE: | 170 | case BENCH_FORMAT_SIMPLE: |
171 | printf("%lu.%03lu\n", | 171 | printf("%lu.%03lu\n", |
172 | diff.tv_sec, | 172 | diff.tv_sec, |
173 | (unsigned long) (diff.tv_usec / 1000)); | 173 | (unsigned long) (diff.tv_usec / 1000)); |
174 | break; | 174 | break; |
175 | 175 | ||
176 | default: | 176 | default: |
177 | /* reaching here is something disaster */ | 177 | /* reaching here is something disaster */ |
178 | fprintf(stderr, "Unknown format:%d\n", bench_format); | 178 | fprintf(stderr, "Unknown format:%d\n", bench_format); |
179 | exit(1); | 179 | exit(1); |
180 | break; | 180 | break; |
181 | } | 181 | } |
182 | 182 | ||
183 | return 0; | 183 | return 0; |
184 | } | 184 | } |
tools/perf/builtin-top.c
1 | /* | 1 | /* |
2 | * builtin-top.c | 2 | * builtin-top.c |
3 | * | 3 | * |
4 | * Builtin top command: Display a continuously updated profile of | 4 | * Builtin top command: Display a continuously updated profile of |
5 | * any workload, CPU or specific PID. | 5 | * any workload, CPU or specific PID. |
6 | * | 6 | * |
7 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> | 7 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> |
8 | * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 8 | * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
9 | * | 9 | * |
10 | * Improvements and fixes by: | 10 | * Improvements and fixes by: |
11 | * | 11 | * |
12 | * Arjan van de Ven <arjan@linux.intel.com> | 12 | * Arjan van de Ven <arjan@linux.intel.com> |
13 | * Yanmin Zhang <yanmin.zhang@intel.com> | 13 | * Yanmin Zhang <yanmin.zhang@intel.com> |
14 | * Wu Fengguang <fengguang.wu@intel.com> | 14 | * Wu Fengguang <fengguang.wu@intel.com> |
15 | * Mike Galbraith <efault@gmx.de> | 15 | * Mike Galbraith <efault@gmx.de> |
16 | * Paul Mackerras <paulus@samba.org> | 16 | * Paul Mackerras <paulus@samba.org> |
17 | * | 17 | * |
18 | * Released under the GPL v2. (and only v2, not any later version) | 18 | * Released under the GPL v2. (and only v2, not any later version) |
19 | */ | 19 | */ |
20 | #include "builtin.h" | 20 | #include "builtin.h" |
21 | 21 | ||
22 | #include "perf.h" | 22 | #include "perf.h" |
23 | 23 | ||
24 | #include "util/annotate.h" | 24 | #include "util/annotate.h" |
25 | #include "util/cache.h" | 25 | #include "util/cache.h" |
26 | #include "util/color.h" | 26 | #include "util/color.h" |
27 | #include "util/evlist.h" | 27 | #include "util/evlist.h" |
28 | #include "util/evsel.h" | 28 | #include "util/evsel.h" |
29 | #include "util/machine.h" | 29 | #include "util/machine.h" |
30 | #include "util/session.h" | 30 | #include "util/session.h" |
31 | #include "util/symbol.h" | 31 | #include "util/symbol.h" |
32 | #include "util/thread.h" | 32 | #include "util/thread.h" |
33 | #include "util/thread_map.h" | 33 | #include "util/thread_map.h" |
34 | #include "util/top.h" | 34 | #include "util/top.h" |
35 | #include "util/util.h" | 35 | #include "util/util.h" |
36 | #include <linux/rbtree.h> | 36 | #include <linux/rbtree.h> |
37 | #include "util/parse-options.h" | 37 | #include "util/parse-options.h" |
38 | #include "util/parse-events.h" | 38 | #include "util/parse-events.h" |
39 | #include "util/cpumap.h" | 39 | #include "util/cpumap.h" |
40 | #include "util/xyarray.h" | 40 | #include "util/xyarray.h" |
41 | #include "util/sort.h" | 41 | #include "util/sort.h" |
42 | #include "util/intlist.h" | 42 | #include "util/intlist.h" |
43 | #include "arch/common.h" | 43 | #include "arch/common.h" |
44 | 44 | ||
45 | #include "util/debug.h" | 45 | #include "util/debug.h" |
46 | 46 | ||
47 | #include <assert.h> | 47 | #include <assert.h> |
48 | #include <elf.h> | 48 | #include <elf.h> |
49 | #include <fcntl.h> | 49 | #include <fcntl.h> |
50 | 50 | ||
51 | #include <stdio.h> | 51 | #include <stdio.h> |
52 | #include <termios.h> | 52 | #include <termios.h> |
53 | #include <unistd.h> | 53 | #include <unistd.h> |
54 | #include <inttypes.h> | 54 | #include <inttypes.h> |
55 | 55 | ||
56 | #include <errno.h> | 56 | #include <errno.h> |
57 | #include <time.h> | 57 | #include <time.h> |
58 | #include <sched.h> | 58 | #include <sched.h> |
59 | 59 | ||
60 | #include <sys/syscall.h> | 60 | #include <sys/syscall.h> |
61 | #include <sys/ioctl.h> | 61 | #include <sys/ioctl.h> |
62 | #include <poll.h> | 62 | #include <poll.h> |
63 | #include <sys/prctl.h> | 63 | #include <sys/prctl.h> |
64 | #include <sys/wait.h> | 64 | #include <sys/wait.h> |
65 | #include <sys/uio.h> | 65 | #include <sys/uio.h> |
66 | #include <sys/utsname.h> | 66 | #include <sys/utsname.h> |
67 | #include <sys/mman.h> | 67 | #include <sys/mman.h> |
68 | 68 | ||
69 | #include <linux/unistd.h> | ||
70 | #include <linux/types.h> | 69 | #include <linux/types.h> |
71 | 70 | ||
72 | static volatile int done; | 71 | static volatile int done; |
73 | 72 | ||
74 | #define HEADER_LINE_NR 5 | 73 | #define HEADER_LINE_NR 5 |
75 | 74 | ||
76 | static void perf_top__update_print_entries(struct perf_top *top) | 75 | static void perf_top__update_print_entries(struct perf_top *top) |
77 | { | 76 | { |
78 | top->print_entries = top->winsize.ws_row - HEADER_LINE_NR; | 77 | top->print_entries = top->winsize.ws_row - HEADER_LINE_NR; |
79 | } | 78 | } |
80 | 79 | ||
81 | static void perf_top__sig_winch(int sig __maybe_unused, | 80 | static void perf_top__sig_winch(int sig __maybe_unused, |
82 | siginfo_t *info __maybe_unused, void *arg) | 81 | siginfo_t *info __maybe_unused, void *arg) |
83 | { | 82 | { |
84 | struct perf_top *top = arg; | 83 | struct perf_top *top = arg; |
85 | 84 | ||
86 | get_term_dimensions(&top->winsize); | 85 | get_term_dimensions(&top->winsize); |
87 | perf_top__update_print_entries(top); | 86 | perf_top__update_print_entries(top); |
88 | } | 87 | } |
89 | 88 | ||
90 | static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) | 89 | static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) |
91 | { | 90 | { |
92 | struct symbol *sym; | 91 | struct symbol *sym; |
93 | struct annotation *notes; | 92 | struct annotation *notes; |
94 | struct map *map; | 93 | struct map *map; |
95 | int err = -1; | 94 | int err = -1; |
96 | 95 | ||
97 | if (!he || !he->ms.sym) | 96 | if (!he || !he->ms.sym) |
98 | return -1; | 97 | return -1; |
99 | 98 | ||
100 | sym = he->ms.sym; | 99 | sym = he->ms.sym; |
101 | map = he->ms.map; | 100 | map = he->ms.map; |
102 | 101 | ||
103 | /* | 102 | /* |
104 | * We can't annotate with just /proc/kallsyms | 103 | * We can't annotate with just /proc/kallsyms |
105 | */ | 104 | */ |
106 | if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && | 105 | if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && |
107 | !dso__is_kcore(map->dso)) { | 106 | !dso__is_kcore(map->dso)) { |
108 | pr_err("Can't annotate %s: No vmlinux file was found in the " | 107 | pr_err("Can't annotate %s: No vmlinux file was found in the " |
109 | "path\n", sym->name); | 108 | "path\n", sym->name); |
110 | sleep(1); | 109 | sleep(1); |
111 | return -1; | 110 | return -1; |
112 | } | 111 | } |
113 | 112 | ||
114 | notes = symbol__annotation(sym); | 113 | notes = symbol__annotation(sym); |
115 | if (notes->src != NULL) { | 114 | if (notes->src != NULL) { |
116 | pthread_mutex_lock(¬es->lock); | 115 | pthread_mutex_lock(¬es->lock); |
117 | goto out_assign; | 116 | goto out_assign; |
118 | } | 117 | } |
119 | 118 | ||
120 | pthread_mutex_lock(¬es->lock); | 119 | pthread_mutex_lock(¬es->lock); |
121 | 120 | ||
122 | if (symbol__alloc_hist(sym) < 0) { | 121 | if (symbol__alloc_hist(sym) < 0) { |
123 | pthread_mutex_unlock(¬es->lock); | 122 | pthread_mutex_unlock(¬es->lock); |
124 | pr_err("Not enough memory for annotating '%s' symbol!\n", | 123 | pr_err("Not enough memory for annotating '%s' symbol!\n", |
125 | sym->name); | 124 | sym->name); |
126 | sleep(1); | 125 | sleep(1); |
127 | return err; | 126 | return err; |
128 | } | 127 | } |
129 | 128 | ||
130 | err = symbol__annotate(sym, map, 0); | 129 | err = symbol__annotate(sym, map, 0); |
131 | if (err == 0) { | 130 | if (err == 0) { |
132 | out_assign: | 131 | out_assign: |
133 | top->sym_filter_entry = he; | 132 | top->sym_filter_entry = he; |
134 | } | 133 | } |
135 | 134 | ||
136 | pthread_mutex_unlock(¬es->lock); | 135 | pthread_mutex_unlock(¬es->lock); |
137 | return err; | 136 | return err; |
138 | } | 137 | } |
139 | 138 | ||
140 | static void __zero_source_counters(struct hist_entry *he) | 139 | static void __zero_source_counters(struct hist_entry *he) |
141 | { | 140 | { |
142 | struct symbol *sym = he->ms.sym; | 141 | struct symbol *sym = he->ms.sym; |
143 | symbol__annotate_zero_histograms(sym); | 142 | symbol__annotate_zero_histograms(sym); |
144 | } | 143 | } |
145 | 144 | ||
146 | static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) | 145 | static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) |
147 | { | 146 | { |
148 | struct utsname uts; | 147 | struct utsname uts; |
149 | int err = uname(&uts); | 148 | int err = uname(&uts); |
150 | 149 | ||
151 | ui__warning("Out of bounds address found:\n\n" | 150 | ui__warning("Out of bounds address found:\n\n" |
152 | "Addr: %" PRIx64 "\n" | 151 | "Addr: %" PRIx64 "\n" |
153 | "DSO: %s %c\n" | 152 | "DSO: %s %c\n" |
154 | "Map: %" PRIx64 "-%" PRIx64 "\n" | 153 | "Map: %" PRIx64 "-%" PRIx64 "\n" |
155 | "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n" | 154 | "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n" |
156 | "Arch: %s\n" | 155 | "Arch: %s\n" |
157 | "Kernel: %s\n" | 156 | "Kernel: %s\n" |
158 | "Tools: %s\n\n" | 157 | "Tools: %s\n\n" |
159 | "Not all samples will be on the annotation output.\n\n" | 158 | "Not all samples will be on the annotation output.\n\n" |
160 | "Please report to linux-kernel@vger.kernel.org\n", | 159 | "Please report to linux-kernel@vger.kernel.org\n", |
161 | ip, map->dso->long_name, dso__symtab_origin(map->dso), | 160 | ip, map->dso->long_name, dso__symtab_origin(map->dso), |
162 | map->start, map->end, sym->start, sym->end, | 161 | map->start, map->end, sym->start, sym->end, |
163 | sym->binding == STB_GLOBAL ? 'g' : | 162 | sym->binding == STB_GLOBAL ? 'g' : |
164 | sym->binding == STB_LOCAL ? 'l' : 'w', sym->name, | 163 | sym->binding == STB_LOCAL ? 'l' : 'w', sym->name, |
165 | err ? "[unknown]" : uts.machine, | 164 | err ? "[unknown]" : uts.machine, |
166 | err ? "[unknown]" : uts.release, perf_version_string); | 165 | err ? "[unknown]" : uts.release, perf_version_string); |
167 | if (use_browser <= 0) | 166 | if (use_browser <= 0) |
168 | sleep(5); | 167 | sleep(5); |
169 | 168 | ||
170 | map->erange_warned = true; | 169 | map->erange_warned = true; |
171 | } | 170 | } |
172 | 171 | ||
173 | static void perf_top__record_precise_ip(struct perf_top *top, | 172 | static void perf_top__record_precise_ip(struct perf_top *top, |
174 | struct hist_entry *he, | 173 | struct hist_entry *he, |
175 | int counter, u64 ip) | 174 | int counter, u64 ip) |
176 | { | 175 | { |
177 | struct annotation *notes; | 176 | struct annotation *notes; |
178 | struct symbol *sym; | 177 | struct symbol *sym; |
179 | int err = 0; | 178 | int err = 0; |
180 | 179 | ||
181 | if (he == NULL || he->ms.sym == NULL || | 180 | if (he == NULL || he->ms.sym == NULL || |
182 | ((top->sym_filter_entry == NULL || | 181 | ((top->sym_filter_entry == NULL || |
183 | top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) | 182 | top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) |
184 | return; | 183 | return; |
185 | 184 | ||
186 | sym = he->ms.sym; | 185 | sym = he->ms.sym; |
187 | notes = symbol__annotation(sym); | 186 | notes = symbol__annotation(sym); |
188 | 187 | ||
189 | if (pthread_mutex_trylock(¬es->lock)) | 188 | if (pthread_mutex_trylock(¬es->lock)) |
190 | return; | 189 | return; |
191 | 190 | ||
192 | ip = he->ms.map->map_ip(he->ms.map, ip); | 191 | ip = he->ms.map->map_ip(he->ms.map, ip); |
193 | 192 | ||
194 | if (ui__has_annotation()) | 193 | if (ui__has_annotation()) |
195 | err = hist_entry__inc_addr_samples(he, counter, ip); | 194 | err = hist_entry__inc_addr_samples(he, counter, ip); |
196 | 195 | ||
197 | pthread_mutex_unlock(¬es->lock); | 196 | pthread_mutex_unlock(¬es->lock); |
198 | 197 | ||
199 | /* | 198 | /* |
200 | * This function is now called with he->hists->lock held. | 199 | * This function is now called with he->hists->lock held. |
201 | * Release it before going to sleep. | 200 | * Release it before going to sleep. |
202 | */ | 201 | */ |
203 | pthread_mutex_unlock(&he->hists->lock); | 202 | pthread_mutex_unlock(&he->hists->lock); |
204 | 203 | ||
205 | if (err == -ERANGE && !he->ms.map->erange_warned) | 204 | if (err == -ERANGE && !he->ms.map->erange_warned) |
206 | ui__warn_map_erange(he->ms.map, sym, ip); | 205 | ui__warn_map_erange(he->ms.map, sym, ip); |
207 | else if (err == -ENOMEM) { | 206 | else if (err == -ENOMEM) { |
208 | pr_err("Not enough memory for annotating '%s' symbol!\n", | 207 | pr_err("Not enough memory for annotating '%s' symbol!\n", |
209 | sym->name); | 208 | sym->name); |
210 | sleep(1); | 209 | sleep(1); |
211 | } | 210 | } |
212 | 211 | ||
213 | pthread_mutex_lock(&he->hists->lock); | 212 | pthread_mutex_lock(&he->hists->lock); |
214 | } | 213 | } |
215 | 214 | ||
216 | static void perf_top__show_details(struct perf_top *top) | 215 | static void perf_top__show_details(struct perf_top *top) |
217 | { | 216 | { |
218 | struct hist_entry *he = top->sym_filter_entry; | 217 | struct hist_entry *he = top->sym_filter_entry; |
219 | struct annotation *notes; | 218 | struct annotation *notes; |
220 | struct symbol *symbol; | 219 | struct symbol *symbol; |
221 | int more; | 220 | int more; |
222 | 221 | ||
223 | if (!he) | 222 | if (!he) |
224 | return; | 223 | return; |
225 | 224 | ||
226 | symbol = he->ms.sym; | 225 | symbol = he->ms.sym; |
227 | notes = symbol__annotation(symbol); | 226 | notes = symbol__annotation(symbol); |
228 | 227 | ||
229 | pthread_mutex_lock(¬es->lock); | 228 | pthread_mutex_lock(¬es->lock); |
230 | 229 | ||
231 | if (notes->src == NULL) | 230 | if (notes->src == NULL) |
232 | goto out_unlock; | 231 | goto out_unlock; |
233 | 232 | ||
234 | printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); | 233 | printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); |
235 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); | 234 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); |
236 | 235 | ||
237 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, | 236 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, |
238 | 0, top->sym_pcnt_filter, top->print_entries, 4); | 237 | 0, top->sym_pcnt_filter, top->print_entries, 4); |
239 | if (top->zero) | 238 | if (top->zero) |
240 | symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); | 239 | symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); |
241 | else | 240 | else |
242 | symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); | 241 | symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); |
243 | if (more != 0) | 242 | if (more != 0) |
244 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); | 243 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); |
245 | out_unlock: | 244 | out_unlock: |
246 | pthread_mutex_unlock(¬es->lock); | 245 | pthread_mutex_unlock(¬es->lock); |
247 | } | 246 | } |
248 | 247 | ||
249 | static void perf_top__print_sym_table(struct perf_top *top) | 248 | static void perf_top__print_sym_table(struct perf_top *top) |
250 | { | 249 | { |
251 | char bf[160]; | 250 | char bf[160]; |
252 | int printed = 0; | 251 | int printed = 0; |
253 | const int win_width = top->winsize.ws_col - 1; | 252 | const int win_width = top->winsize.ws_col - 1; |
254 | struct hists *hists = evsel__hists(top->sym_evsel); | 253 | struct hists *hists = evsel__hists(top->sym_evsel); |
255 | 254 | ||
256 | puts(CONSOLE_CLEAR); | 255 | puts(CONSOLE_CLEAR); |
257 | 256 | ||
258 | perf_top__header_snprintf(top, bf, sizeof(bf)); | 257 | perf_top__header_snprintf(top, bf, sizeof(bf)); |
259 | printf("%s\n", bf); | 258 | printf("%s\n", bf); |
260 | 259 | ||
261 | perf_top__reset_sample_counters(top); | 260 | perf_top__reset_sample_counters(top); |
262 | 261 | ||
263 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 262 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
264 | 263 | ||
265 | if (hists->stats.nr_lost_warned != | 264 | if (hists->stats.nr_lost_warned != |
266 | hists->stats.nr_events[PERF_RECORD_LOST]) { | 265 | hists->stats.nr_events[PERF_RECORD_LOST]) { |
267 | hists->stats.nr_lost_warned = | 266 | hists->stats.nr_lost_warned = |
268 | hists->stats.nr_events[PERF_RECORD_LOST]; | 267 | hists->stats.nr_events[PERF_RECORD_LOST]; |
269 | color_fprintf(stdout, PERF_COLOR_RED, | 268 | color_fprintf(stdout, PERF_COLOR_RED, |
270 | "WARNING: LOST %d chunks, Check IO/CPU overload", | 269 | "WARNING: LOST %d chunks, Check IO/CPU overload", |
271 | hists->stats.nr_lost_warned); | 270 | hists->stats.nr_lost_warned); |
272 | ++printed; | 271 | ++printed; |
273 | } | 272 | } |
274 | 273 | ||
275 | if (top->sym_filter_entry) { | 274 | if (top->sym_filter_entry) { |
276 | perf_top__show_details(top); | 275 | perf_top__show_details(top); |
277 | return; | 276 | return; |
278 | } | 277 | } |
279 | 278 | ||
280 | if (top->zero) { | 279 | if (top->zero) { |
281 | hists__delete_entries(hists); | 280 | hists__delete_entries(hists); |
282 | } else { | 281 | } else { |
283 | hists__decay_entries(hists, top->hide_user_symbols, | 282 | hists__decay_entries(hists, top->hide_user_symbols, |
284 | top->hide_kernel_symbols); | 283 | top->hide_kernel_symbols); |
285 | } | 284 | } |
286 | 285 | ||
287 | hists__collapse_resort(hists, NULL); | 286 | hists__collapse_resort(hists, NULL); |
288 | hists__output_resort(hists, NULL); | 287 | hists__output_resort(hists, NULL); |
289 | 288 | ||
290 | hists__output_recalc_col_len(hists, top->print_entries - printed); | 289 | hists__output_recalc_col_len(hists, top->print_entries - printed); |
291 | putchar('\n'); | 290 | putchar('\n'); |
292 | hists__fprintf(hists, false, top->print_entries - printed, win_width, | 291 | hists__fprintf(hists, false, top->print_entries - printed, win_width, |
293 | top->min_percent, stdout); | 292 | top->min_percent, stdout); |
294 | } | 293 | } |
295 | 294 | ||
296 | static void prompt_integer(int *target, const char *msg) | 295 | static void prompt_integer(int *target, const char *msg) |
297 | { | 296 | { |
298 | char *buf = malloc(0), *p; | 297 | char *buf = malloc(0), *p; |
299 | size_t dummy = 0; | 298 | size_t dummy = 0; |
300 | int tmp; | 299 | int tmp; |
301 | 300 | ||
302 | fprintf(stdout, "\n%s: ", msg); | 301 | fprintf(stdout, "\n%s: ", msg); |
303 | if (getline(&buf, &dummy, stdin) < 0) | 302 | if (getline(&buf, &dummy, stdin) < 0) |
304 | return; | 303 | return; |
305 | 304 | ||
306 | p = strchr(buf, '\n'); | 305 | p = strchr(buf, '\n'); |
307 | if (p) | 306 | if (p) |
308 | *p = 0; | 307 | *p = 0; |
309 | 308 | ||
310 | p = buf; | 309 | p = buf; |
311 | while(*p) { | 310 | while(*p) { |
312 | if (!isdigit(*p)) | 311 | if (!isdigit(*p)) |
313 | goto out_free; | 312 | goto out_free; |
314 | p++; | 313 | p++; |
315 | } | 314 | } |
316 | tmp = strtoul(buf, NULL, 10); | 315 | tmp = strtoul(buf, NULL, 10); |
317 | *target = tmp; | 316 | *target = tmp; |
318 | out_free: | 317 | out_free: |
319 | free(buf); | 318 | free(buf); |
320 | } | 319 | } |
321 | 320 | ||
322 | static void prompt_percent(int *target, const char *msg) | 321 | static void prompt_percent(int *target, const char *msg) |
323 | { | 322 | { |
324 | int tmp = 0; | 323 | int tmp = 0; |
325 | 324 | ||
326 | prompt_integer(&tmp, msg); | 325 | prompt_integer(&tmp, msg); |
327 | if (tmp >= 0 && tmp <= 100) | 326 | if (tmp >= 0 && tmp <= 100) |
328 | *target = tmp; | 327 | *target = tmp; |
329 | } | 328 | } |
330 | 329 | ||
331 | static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) | 330 | static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) |
332 | { | 331 | { |
333 | char *buf = malloc(0), *p; | 332 | char *buf = malloc(0), *p; |
334 | struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; | 333 | struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; |
335 | struct hists *hists = evsel__hists(top->sym_evsel); | 334 | struct hists *hists = evsel__hists(top->sym_evsel); |
336 | struct rb_node *next; | 335 | struct rb_node *next; |
337 | size_t dummy = 0; | 336 | size_t dummy = 0; |
338 | 337 | ||
339 | /* zero counters of active symbol */ | 338 | /* zero counters of active symbol */ |
340 | if (syme) { | 339 | if (syme) { |
341 | __zero_source_counters(syme); | 340 | __zero_source_counters(syme); |
342 | top->sym_filter_entry = NULL; | 341 | top->sym_filter_entry = NULL; |
343 | } | 342 | } |
344 | 343 | ||
345 | fprintf(stdout, "\n%s: ", msg); | 344 | fprintf(stdout, "\n%s: ", msg); |
346 | if (getline(&buf, &dummy, stdin) < 0) | 345 | if (getline(&buf, &dummy, stdin) < 0) |
347 | goto out_free; | 346 | goto out_free; |
348 | 347 | ||
349 | p = strchr(buf, '\n'); | 348 | p = strchr(buf, '\n'); |
350 | if (p) | 349 | if (p) |
351 | *p = 0; | 350 | *p = 0; |
352 | 351 | ||
353 | next = rb_first(&hists->entries); | 352 | next = rb_first(&hists->entries); |
354 | while (next) { | 353 | while (next) { |
355 | n = rb_entry(next, struct hist_entry, rb_node); | 354 | n = rb_entry(next, struct hist_entry, rb_node); |
356 | if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { | 355 | if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { |
357 | found = n; | 356 | found = n; |
358 | break; | 357 | break; |
359 | } | 358 | } |
360 | next = rb_next(&n->rb_node); | 359 | next = rb_next(&n->rb_node); |
361 | } | 360 | } |
362 | 361 | ||
363 | if (!found) { | 362 | if (!found) { |
364 | fprintf(stderr, "Sorry, %s is not active.\n", buf); | 363 | fprintf(stderr, "Sorry, %s is not active.\n", buf); |
365 | sleep(1); | 364 | sleep(1); |
366 | } else | 365 | } else |
367 | perf_top__parse_source(top, found); | 366 | perf_top__parse_source(top, found); |
368 | 367 | ||
369 | out_free: | 368 | out_free: |
370 | free(buf); | 369 | free(buf); |
371 | } | 370 | } |
372 | 371 | ||
373 | static void perf_top__print_mapped_keys(struct perf_top *top) | 372 | static void perf_top__print_mapped_keys(struct perf_top *top) |
374 | { | 373 | { |
375 | char *name = NULL; | 374 | char *name = NULL; |
376 | 375 | ||
377 | if (top->sym_filter_entry) { | 376 | if (top->sym_filter_entry) { |
378 | struct symbol *sym = top->sym_filter_entry->ms.sym; | 377 | struct symbol *sym = top->sym_filter_entry->ms.sym; |
379 | name = sym->name; | 378 | name = sym->name; |
380 | } | 379 | } |
381 | 380 | ||
382 | fprintf(stdout, "\nMapped keys:\n"); | 381 | fprintf(stdout, "\nMapped keys:\n"); |
383 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); | 382 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); |
384 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); | 383 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); |
385 | 384 | ||
386 | if (top->evlist->nr_entries > 1) | 385 | if (top->evlist->nr_entries > 1) |
387 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", perf_evsel__name(top->sym_evsel)); | 386 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", perf_evsel__name(top->sym_evsel)); |
388 | 387 | ||
389 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); | 388 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); |
390 | 389 | ||
391 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); | 390 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); |
392 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); | 391 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); |
393 | fprintf(stdout, "\t[S] stop annotation.\n"); | 392 | fprintf(stdout, "\t[S] stop annotation.\n"); |
394 | 393 | ||
395 | fprintf(stdout, | 394 | fprintf(stdout, |
396 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", | 395 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", |
397 | top->hide_kernel_symbols ? "yes" : "no"); | 396 | top->hide_kernel_symbols ? "yes" : "no"); |
398 | fprintf(stdout, | 397 | fprintf(stdout, |
399 | "\t[U] hide user symbols. \t(%s)\n", | 398 | "\t[U] hide user symbols. \t(%s)\n", |
400 | top->hide_user_symbols ? "yes" : "no"); | 399 | top->hide_user_symbols ? "yes" : "no"); |
401 | fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0); | 400 | fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0); |
402 | fprintf(stdout, "\t[qQ] quit.\n"); | 401 | fprintf(stdout, "\t[qQ] quit.\n"); |
403 | } | 402 | } |
404 | 403 | ||
405 | static int perf_top__key_mapped(struct perf_top *top, int c) | 404 | static int perf_top__key_mapped(struct perf_top *top, int c) |
406 | { | 405 | { |
407 | switch (c) { | 406 | switch (c) { |
408 | case 'd': | 407 | case 'd': |
409 | case 'e': | 408 | case 'e': |
410 | case 'f': | 409 | case 'f': |
411 | case 'z': | 410 | case 'z': |
412 | case 'q': | 411 | case 'q': |
413 | case 'Q': | 412 | case 'Q': |
414 | case 'K': | 413 | case 'K': |
415 | case 'U': | 414 | case 'U': |
416 | case 'F': | 415 | case 'F': |
417 | case 's': | 416 | case 's': |
418 | case 'S': | 417 | case 'S': |
419 | return 1; | 418 | return 1; |
420 | case 'E': | 419 | case 'E': |
421 | return top->evlist->nr_entries > 1 ? 1 : 0; | 420 | return top->evlist->nr_entries > 1 ? 1 : 0; |
422 | default: | 421 | default: |
423 | break; | 422 | break; |
424 | } | 423 | } |
425 | 424 | ||
426 | return 0; | 425 | return 0; |
427 | } | 426 | } |
428 | 427 | ||
429 | static bool perf_top__handle_keypress(struct perf_top *top, int c) | 428 | static bool perf_top__handle_keypress(struct perf_top *top, int c) |
430 | { | 429 | { |
431 | bool ret = true; | 430 | bool ret = true; |
432 | 431 | ||
433 | if (!perf_top__key_mapped(top, c)) { | 432 | if (!perf_top__key_mapped(top, c)) { |
434 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 433 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
435 | struct termios save; | 434 | struct termios save; |
436 | 435 | ||
437 | perf_top__print_mapped_keys(top); | 436 | perf_top__print_mapped_keys(top); |
438 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); | 437 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); |
439 | fflush(stdout); | 438 | fflush(stdout); |
440 | 439 | ||
441 | set_term_quiet_input(&save); | 440 | set_term_quiet_input(&save); |
442 | 441 | ||
443 | poll(&stdin_poll, 1, -1); | 442 | poll(&stdin_poll, 1, -1); |
444 | c = getc(stdin); | 443 | c = getc(stdin); |
445 | 444 | ||
446 | tcsetattr(0, TCSAFLUSH, &save); | 445 | tcsetattr(0, TCSAFLUSH, &save); |
447 | if (!perf_top__key_mapped(top, c)) | 446 | if (!perf_top__key_mapped(top, c)) |
448 | return ret; | 447 | return ret; |
449 | } | 448 | } |
450 | 449 | ||
451 | switch (c) { | 450 | switch (c) { |
452 | case 'd': | 451 | case 'd': |
453 | prompt_integer(&top->delay_secs, "Enter display delay"); | 452 | prompt_integer(&top->delay_secs, "Enter display delay"); |
454 | if (top->delay_secs < 1) | 453 | if (top->delay_secs < 1) |
455 | top->delay_secs = 1; | 454 | top->delay_secs = 1; |
456 | break; | 455 | break; |
457 | case 'e': | 456 | case 'e': |
458 | prompt_integer(&top->print_entries, "Enter display entries (lines)"); | 457 | prompt_integer(&top->print_entries, "Enter display entries (lines)"); |
459 | if (top->print_entries == 0) { | 458 | if (top->print_entries == 0) { |
460 | struct sigaction act = { | 459 | struct sigaction act = { |
461 | .sa_sigaction = perf_top__sig_winch, | 460 | .sa_sigaction = perf_top__sig_winch, |
462 | .sa_flags = SA_SIGINFO, | 461 | .sa_flags = SA_SIGINFO, |
463 | }; | 462 | }; |
464 | perf_top__sig_winch(SIGWINCH, NULL, top); | 463 | perf_top__sig_winch(SIGWINCH, NULL, top); |
465 | sigaction(SIGWINCH, &act, NULL); | 464 | sigaction(SIGWINCH, &act, NULL); |
466 | } else { | 465 | } else { |
467 | signal(SIGWINCH, SIG_DFL); | 466 | signal(SIGWINCH, SIG_DFL); |
468 | } | 467 | } |
469 | break; | 468 | break; |
470 | case 'E': | 469 | case 'E': |
471 | if (top->evlist->nr_entries > 1) { | 470 | if (top->evlist->nr_entries > 1) { |
472 | /* Select 0 as the default event: */ | 471 | /* Select 0 as the default event: */ |
473 | int counter = 0; | 472 | int counter = 0; |
474 | 473 | ||
475 | fprintf(stderr, "\nAvailable events:"); | 474 | fprintf(stderr, "\nAvailable events:"); |
476 | 475 | ||
477 | evlist__for_each(top->evlist, top->sym_evsel) | 476 | evlist__for_each(top->evlist, top->sym_evsel) |
478 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); | 477 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); |
479 | 478 | ||
480 | prompt_integer(&counter, "Enter details event counter"); | 479 | prompt_integer(&counter, "Enter details event counter"); |
481 | 480 | ||
482 | if (counter >= top->evlist->nr_entries) { | 481 | if (counter >= top->evlist->nr_entries) { |
483 | top->sym_evsel = perf_evlist__first(top->evlist); | 482 | top->sym_evsel = perf_evlist__first(top->evlist); |
484 | fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel)); | 483 | fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel)); |
485 | sleep(1); | 484 | sleep(1); |
486 | break; | 485 | break; |
487 | } | 486 | } |
488 | evlist__for_each(top->evlist, top->sym_evsel) | 487 | evlist__for_each(top->evlist, top->sym_evsel) |
489 | if (top->sym_evsel->idx == counter) | 488 | if (top->sym_evsel->idx == counter) |
490 | break; | 489 | break; |
491 | } else | 490 | } else |
492 | top->sym_evsel = perf_evlist__first(top->evlist); | 491 | top->sym_evsel = perf_evlist__first(top->evlist); |
493 | break; | 492 | break; |
494 | case 'f': | 493 | case 'f': |
495 | prompt_integer(&top->count_filter, "Enter display event count filter"); | 494 | prompt_integer(&top->count_filter, "Enter display event count filter"); |
496 | break; | 495 | break; |
497 | case 'F': | 496 | case 'F': |
498 | prompt_percent(&top->sym_pcnt_filter, | 497 | prompt_percent(&top->sym_pcnt_filter, |
499 | "Enter details display event filter (percent)"); | 498 | "Enter details display event filter (percent)"); |
500 | break; | 499 | break; |
501 | case 'K': | 500 | case 'K': |
502 | top->hide_kernel_symbols = !top->hide_kernel_symbols; | 501 | top->hide_kernel_symbols = !top->hide_kernel_symbols; |
503 | break; | 502 | break; |
504 | case 'q': | 503 | case 'q': |
505 | case 'Q': | 504 | case 'Q': |
506 | printf("exiting.\n"); | 505 | printf("exiting.\n"); |
507 | if (top->dump_symtab) | 506 | if (top->dump_symtab) |
508 | perf_session__fprintf_dsos(top->session, stderr); | 507 | perf_session__fprintf_dsos(top->session, stderr); |
509 | ret = false; | 508 | ret = false; |
510 | break; | 509 | break; |
511 | case 's': | 510 | case 's': |
512 | perf_top__prompt_symbol(top, "Enter details symbol"); | 511 | perf_top__prompt_symbol(top, "Enter details symbol"); |
513 | break; | 512 | break; |
514 | case 'S': | 513 | case 'S': |
515 | if (!top->sym_filter_entry) | 514 | if (!top->sym_filter_entry) |
516 | break; | 515 | break; |
517 | else { | 516 | else { |
518 | struct hist_entry *syme = top->sym_filter_entry; | 517 | struct hist_entry *syme = top->sym_filter_entry; |
519 | 518 | ||
520 | top->sym_filter_entry = NULL; | 519 | top->sym_filter_entry = NULL; |
521 | __zero_source_counters(syme); | 520 | __zero_source_counters(syme); |
522 | } | 521 | } |
523 | break; | 522 | break; |
524 | case 'U': | 523 | case 'U': |
525 | top->hide_user_symbols = !top->hide_user_symbols; | 524 | top->hide_user_symbols = !top->hide_user_symbols; |
526 | break; | 525 | break; |
527 | case 'z': | 526 | case 'z': |
528 | top->zero = !top->zero; | 527 | top->zero = !top->zero; |
529 | break; | 528 | break; |
530 | default: | 529 | default: |
531 | break; | 530 | break; |
532 | } | 531 | } |
533 | 532 | ||
534 | return ret; | 533 | return ret; |
535 | } | 534 | } |
536 | 535 | ||
537 | static void perf_top__sort_new_samples(void *arg) | 536 | static void perf_top__sort_new_samples(void *arg) |
538 | { | 537 | { |
539 | struct perf_top *t = arg; | 538 | struct perf_top *t = arg; |
540 | struct hists *hists; | 539 | struct hists *hists; |
541 | 540 | ||
542 | perf_top__reset_sample_counters(t); | 541 | perf_top__reset_sample_counters(t); |
543 | 542 | ||
544 | if (t->evlist->selected != NULL) | 543 | if (t->evlist->selected != NULL) |
545 | t->sym_evsel = t->evlist->selected; | 544 | t->sym_evsel = t->evlist->selected; |
546 | 545 | ||
547 | hists = evsel__hists(t->sym_evsel); | 546 | hists = evsel__hists(t->sym_evsel); |
548 | 547 | ||
549 | if (t->zero) { | 548 | if (t->zero) { |
550 | hists__delete_entries(hists); | 549 | hists__delete_entries(hists); |
551 | } else { | 550 | } else { |
552 | hists__decay_entries(hists, t->hide_user_symbols, | 551 | hists__decay_entries(hists, t->hide_user_symbols, |
553 | t->hide_kernel_symbols); | 552 | t->hide_kernel_symbols); |
554 | } | 553 | } |
555 | 554 | ||
556 | hists__collapse_resort(hists, NULL); | 555 | hists__collapse_resort(hists, NULL); |
557 | hists__output_resort(hists, NULL); | 556 | hists__output_resort(hists, NULL); |
558 | } | 557 | } |
559 | 558 | ||
560 | static void *display_thread_tui(void *arg) | 559 | static void *display_thread_tui(void *arg) |
561 | { | 560 | { |
562 | struct perf_evsel *pos; | 561 | struct perf_evsel *pos; |
563 | struct perf_top *top = arg; | 562 | struct perf_top *top = arg; |
564 | const char *help = "For a higher level overview, try: perf top --sort comm,dso"; | 563 | const char *help = "For a higher level overview, try: perf top --sort comm,dso"; |
565 | struct hist_browser_timer hbt = { | 564 | struct hist_browser_timer hbt = { |
566 | .timer = perf_top__sort_new_samples, | 565 | .timer = perf_top__sort_new_samples, |
567 | .arg = top, | 566 | .arg = top, |
568 | .refresh = top->delay_secs, | 567 | .refresh = top->delay_secs, |
569 | }; | 568 | }; |
570 | 569 | ||
571 | perf_top__sort_new_samples(top); | 570 | perf_top__sort_new_samples(top); |
572 | 571 | ||
573 | /* | 572 | /* |
574 | * Initialize the uid_filter_str, in the future the TUI will allow | 573 | * Initialize the uid_filter_str, in the future the TUI will allow |
575 | * Zooming in/out UIDs. For now juse use whatever the user passed | 574 | * Zooming in/out UIDs. For now juse use whatever the user passed |
576 | * via --uid. | 575 | * via --uid. |
577 | */ | 576 | */ |
578 | evlist__for_each(top->evlist, pos) { | 577 | evlist__for_each(top->evlist, pos) { |
579 | struct hists *hists = evsel__hists(pos); | 578 | struct hists *hists = evsel__hists(pos); |
580 | hists->uid_filter_str = top->record_opts.target.uid_str; | 579 | hists->uid_filter_str = top->record_opts.target.uid_str; |
581 | } | 580 | } |
582 | 581 | ||
583 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, | 582 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, |
584 | &top->session->header.env); | 583 | &top->session->header.env); |
585 | 584 | ||
586 | done = 1; | 585 | done = 1; |
587 | return NULL; | 586 | return NULL; |
588 | } | 587 | } |
589 | 588 | ||
590 | static void display_sig(int sig __maybe_unused) | 589 | static void display_sig(int sig __maybe_unused) |
591 | { | 590 | { |
592 | done = 1; | 591 | done = 1; |
593 | } | 592 | } |
594 | 593 | ||
595 | static void display_setup_sig(void) | 594 | static void display_setup_sig(void) |
596 | { | 595 | { |
597 | signal(SIGSEGV, display_sig); | 596 | signal(SIGSEGV, display_sig); |
598 | signal(SIGFPE, display_sig); | 597 | signal(SIGFPE, display_sig); |
599 | signal(SIGINT, display_sig); | 598 | signal(SIGINT, display_sig); |
600 | signal(SIGQUIT, display_sig); | 599 | signal(SIGQUIT, display_sig); |
601 | signal(SIGTERM, display_sig); | 600 | signal(SIGTERM, display_sig); |
602 | } | 601 | } |
603 | 602 | ||
604 | static void *display_thread(void *arg) | 603 | static void *display_thread(void *arg) |
605 | { | 604 | { |
606 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 605 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
607 | struct termios save; | 606 | struct termios save; |
608 | struct perf_top *top = arg; | 607 | struct perf_top *top = arg; |
609 | int delay_msecs, c; | 608 | int delay_msecs, c; |
610 | 609 | ||
611 | display_setup_sig(); | 610 | display_setup_sig(); |
612 | pthread__unblock_sigwinch(); | 611 | pthread__unblock_sigwinch(); |
613 | repeat: | 612 | repeat: |
614 | delay_msecs = top->delay_secs * 1000; | 613 | delay_msecs = top->delay_secs * 1000; |
615 | set_term_quiet_input(&save); | 614 | set_term_quiet_input(&save); |
616 | /* trash return*/ | 615 | /* trash return*/ |
617 | getc(stdin); | 616 | getc(stdin); |
618 | 617 | ||
619 | while (!done) { | 618 | while (!done) { |
620 | perf_top__print_sym_table(top); | 619 | perf_top__print_sym_table(top); |
621 | /* | 620 | /* |
622 | * Either timeout expired or we got an EINTR due to SIGWINCH, | 621 | * Either timeout expired or we got an EINTR due to SIGWINCH, |
623 | * refresh screen in both cases. | 622 | * refresh screen in both cases. |
624 | */ | 623 | */ |
625 | switch (poll(&stdin_poll, 1, delay_msecs)) { | 624 | switch (poll(&stdin_poll, 1, delay_msecs)) { |
626 | case 0: | 625 | case 0: |
627 | continue; | 626 | continue; |
628 | case -1: | 627 | case -1: |
629 | if (errno == EINTR) | 628 | if (errno == EINTR) |
630 | continue; | 629 | continue; |
631 | /* Fall trhu */ | 630 | /* Fall trhu */ |
632 | default: | 631 | default: |
633 | c = getc(stdin); | 632 | c = getc(stdin); |
634 | tcsetattr(0, TCSAFLUSH, &save); | 633 | tcsetattr(0, TCSAFLUSH, &save); |
635 | 634 | ||
636 | if (perf_top__handle_keypress(top, c)) | 635 | if (perf_top__handle_keypress(top, c)) |
637 | goto repeat; | 636 | goto repeat; |
638 | done = 1; | 637 | done = 1; |
639 | } | 638 | } |
640 | } | 639 | } |
641 | 640 | ||
642 | tcsetattr(0, TCSAFLUSH, &save); | 641 | tcsetattr(0, TCSAFLUSH, &save); |
643 | return NULL; | 642 | return NULL; |
644 | } | 643 | } |
645 | 644 | ||
646 | static int symbol_filter(struct map *map, struct symbol *sym) | 645 | static int symbol_filter(struct map *map, struct symbol *sym) |
647 | { | 646 | { |
648 | const char *name = sym->name; | 647 | const char *name = sym->name; |
649 | 648 | ||
650 | if (!map->dso->kernel) | 649 | if (!map->dso->kernel) |
651 | return 0; | 650 | return 0; |
652 | /* | 651 | /* |
653 | * ppc64 uses function descriptors and appends a '.' to the | 652 | * ppc64 uses function descriptors and appends a '.' to the |
654 | * start of every instruction address. Remove it. | 653 | * start of every instruction address. Remove it. |
655 | */ | 654 | */ |
656 | if (name[0] == '.') | 655 | if (name[0] == '.') |
657 | name++; | 656 | name++; |
658 | 657 | ||
659 | if (!strcmp(name, "_text") || | 658 | if (!strcmp(name, "_text") || |
660 | !strcmp(name, "_etext") || | 659 | !strcmp(name, "_etext") || |
661 | !strcmp(name, "_sinittext") || | 660 | !strcmp(name, "_sinittext") || |
662 | !strncmp("init_module", name, 11) || | 661 | !strncmp("init_module", name, 11) || |
663 | !strncmp("cleanup_module", name, 14) || | 662 | !strncmp("cleanup_module", name, 14) || |
664 | strstr(name, "_text_start") || | 663 | strstr(name, "_text_start") || |
665 | strstr(name, "_text_end")) | 664 | strstr(name, "_text_end")) |
666 | return 1; | 665 | return 1; |
667 | 666 | ||
668 | if (symbol__is_idle(sym)) | 667 | if (symbol__is_idle(sym)) |
669 | sym->ignore = true; | 668 | sym->ignore = true; |
670 | 669 | ||
671 | return 0; | 670 | return 0; |
672 | } | 671 | } |
673 | 672 | ||
674 | static int hist_iter__top_callback(struct hist_entry_iter *iter, | 673 | static int hist_iter__top_callback(struct hist_entry_iter *iter, |
675 | struct addr_location *al, bool single, | 674 | struct addr_location *al, bool single, |
676 | void *arg) | 675 | void *arg) |
677 | { | 676 | { |
678 | struct perf_top *top = arg; | 677 | struct perf_top *top = arg; |
679 | struct hist_entry *he = iter->he; | 678 | struct hist_entry *he = iter->he; |
680 | struct perf_evsel *evsel = iter->evsel; | 679 | struct perf_evsel *evsel = iter->evsel; |
681 | 680 | ||
682 | if (sort__has_sym && single) { | 681 | if (sort__has_sym && single) { |
683 | u64 ip = al->addr; | 682 | u64 ip = al->addr; |
684 | 683 | ||
685 | if (al->map) | 684 | if (al->map) |
686 | ip = al->map->unmap_ip(al->map, ip); | 685 | ip = al->map->unmap_ip(al->map, ip); |
687 | 686 | ||
688 | perf_top__record_precise_ip(top, he, evsel->idx, ip); | 687 | perf_top__record_precise_ip(top, he, evsel->idx, ip); |
689 | } | 688 | } |
690 | 689 | ||
691 | return 0; | 690 | return 0; |
692 | } | 691 | } |
693 | 692 | ||
694 | static void perf_event__process_sample(struct perf_tool *tool, | 693 | static void perf_event__process_sample(struct perf_tool *tool, |
695 | const union perf_event *event, | 694 | const union perf_event *event, |
696 | struct perf_evsel *evsel, | 695 | struct perf_evsel *evsel, |
697 | struct perf_sample *sample, | 696 | struct perf_sample *sample, |
698 | struct machine *machine) | 697 | struct machine *machine) |
699 | { | 698 | { |
700 | struct perf_top *top = container_of(tool, struct perf_top, tool); | 699 | struct perf_top *top = container_of(tool, struct perf_top, tool); |
701 | struct addr_location al; | 700 | struct addr_location al; |
702 | int err; | 701 | int err; |
703 | 702 | ||
704 | if (!machine && perf_guest) { | 703 | if (!machine && perf_guest) { |
705 | static struct intlist *seen; | 704 | static struct intlist *seen; |
706 | 705 | ||
707 | if (!seen) | 706 | if (!seen) |
708 | seen = intlist__new(NULL); | 707 | seen = intlist__new(NULL); |
709 | 708 | ||
710 | if (!intlist__has_entry(seen, sample->pid)) { | 709 | if (!intlist__has_entry(seen, sample->pid)) { |
711 | pr_err("Can't find guest [%d]'s kernel information\n", | 710 | pr_err("Can't find guest [%d]'s kernel information\n", |
712 | sample->pid); | 711 | sample->pid); |
713 | intlist__add(seen, sample->pid); | 712 | intlist__add(seen, sample->pid); |
714 | } | 713 | } |
715 | return; | 714 | return; |
716 | } | 715 | } |
717 | 716 | ||
718 | if (!machine) { | 717 | if (!machine) { |
719 | pr_err("%u unprocessable samples recorded.\r", | 718 | pr_err("%u unprocessable samples recorded.\r", |
720 | top->session->stats.nr_unprocessable_samples++); | 719 | top->session->stats.nr_unprocessable_samples++); |
721 | return; | 720 | return; |
722 | } | 721 | } |
723 | 722 | ||
724 | if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) | 723 | if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) |
725 | top->exact_samples++; | 724 | top->exact_samples++; |
726 | 725 | ||
727 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) | 726 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) |
728 | return; | 727 | return; |
729 | 728 | ||
730 | if (!top->kptr_restrict_warned && | 729 | if (!top->kptr_restrict_warned && |
731 | symbol_conf.kptr_restrict && | 730 | symbol_conf.kptr_restrict && |
732 | al.cpumode == PERF_RECORD_MISC_KERNEL) { | 731 | al.cpumode == PERF_RECORD_MISC_KERNEL) { |
733 | ui__warning( | 732 | ui__warning( |
734 | "Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" | 733 | "Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" |
735 | "Check /proc/sys/kernel/kptr_restrict.\n\n" | 734 | "Check /proc/sys/kernel/kptr_restrict.\n\n" |
736 | "Kernel%s samples will not be resolved.\n", | 735 | "Kernel%s samples will not be resolved.\n", |
737 | !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ? | 736 | !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ? |
738 | " modules" : ""); | 737 | " modules" : ""); |
739 | if (use_browser <= 0) | 738 | if (use_browser <= 0) |
740 | sleep(5); | 739 | sleep(5); |
741 | top->kptr_restrict_warned = true; | 740 | top->kptr_restrict_warned = true; |
742 | } | 741 | } |
743 | 742 | ||
744 | if (al.sym == NULL) { | 743 | if (al.sym == NULL) { |
745 | const char *msg = "Kernel samples will not be resolved.\n"; | 744 | const char *msg = "Kernel samples will not be resolved.\n"; |
746 | /* | 745 | /* |
747 | * As we do lazy loading of symtabs we only will know if the | 746 | * As we do lazy loading of symtabs we only will know if the |
748 | * specified vmlinux file is invalid when we actually have a | 747 | * specified vmlinux file is invalid when we actually have a |
749 | * hit in kernel space and then try to load it. So if we get | 748 | * hit in kernel space and then try to load it. So if we get |
750 | * here and there are _no_ symbols in the DSO backing the | 749 | * here and there are _no_ symbols in the DSO backing the |
751 | * kernel map, bail out. | 750 | * kernel map, bail out. |
752 | * | 751 | * |
753 | * We may never get here, for instance, if we use -K/ | 752 | * We may never get here, for instance, if we use -K/ |
754 | * --hide-kernel-symbols, even if the user specifies an | 753 | * --hide-kernel-symbols, even if the user specifies an |
755 | * invalid --vmlinux ;-) | 754 | * invalid --vmlinux ;-) |
756 | */ | 755 | */ |
757 | if (!top->kptr_restrict_warned && !top->vmlinux_warned && | 756 | if (!top->kptr_restrict_warned && !top->vmlinux_warned && |
758 | al.map == machine->vmlinux_maps[MAP__FUNCTION] && | 757 | al.map == machine->vmlinux_maps[MAP__FUNCTION] && |
759 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { | 758 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { |
760 | if (symbol_conf.vmlinux_name) { | 759 | if (symbol_conf.vmlinux_name) { |
761 | ui__warning("The %s file can't be used.\n%s", | 760 | ui__warning("The %s file can't be used.\n%s", |
762 | symbol_conf.vmlinux_name, msg); | 761 | symbol_conf.vmlinux_name, msg); |
763 | } else { | 762 | } else { |
764 | ui__warning("A vmlinux file was not found.\n%s", | 763 | ui__warning("A vmlinux file was not found.\n%s", |
765 | msg); | 764 | msg); |
766 | } | 765 | } |
767 | 766 | ||
768 | if (use_browser <= 0) | 767 | if (use_browser <= 0) |
769 | sleep(5); | 768 | sleep(5); |
770 | top->vmlinux_warned = true; | 769 | top->vmlinux_warned = true; |
771 | } | 770 | } |
772 | } | 771 | } |
773 | 772 | ||
774 | if (al.sym == NULL || !al.sym->ignore) { | 773 | if (al.sym == NULL || !al.sym->ignore) { |
775 | struct hists *hists = evsel__hists(evsel); | 774 | struct hists *hists = evsel__hists(evsel); |
776 | struct hist_entry_iter iter = { | 775 | struct hist_entry_iter iter = { |
777 | .add_entry_cb = hist_iter__top_callback, | 776 | .add_entry_cb = hist_iter__top_callback, |
778 | }; | 777 | }; |
779 | 778 | ||
780 | if (symbol_conf.cumulate_callchain) | 779 | if (symbol_conf.cumulate_callchain) |
781 | iter.ops = &hist_iter_cumulative; | 780 | iter.ops = &hist_iter_cumulative; |
782 | else | 781 | else |
783 | iter.ops = &hist_iter_normal; | 782 | iter.ops = &hist_iter_normal; |
784 | 783 | ||
785 | pthread_mutex_lock(&hists->lock); | 784 | pthread_mutex_lock(&hists->lock); |
786 | 785 | ||
787 | err = hist_entry_iter__add(&iter, &al, evsel, sample, | 786 | err = hist_entry_iter__add(&iter, &al, evsel, sample, |
788 | top->max_stack, top); | 787 | top->max_stack, top); |
789 | if (err < 0) | 788 | if (err < 0) |
790 | pr_err("Problem incrementing symbol period, skipping event\n"); | 789 | pr_err("Problem incrementing symbol period, skipping event\n"); |
791 | 790 | ||
792 | pthread_mutex_unlock(&hists->lock); | 791 | pthread_mutex_unlock(&hists->lock); |
793 | } | 792 | } |
794 | 793 | ||
795 | return; | 794 | return; |
796 | } | 795 | } |
797 | 796 | ||
798 | static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | 797 | static void perf_top__mmap_read_idx(struct perf_top *top, int idx) |
799 | { | 798 | { |
800 | struct perf_sample sample; | 799 | struct perf_sample sample; |
801 | struct perf_evsel *evsel; | 800 | struct perf_evsel *evsel; |
802 | struct perf_session *session = top->session; | 801 | struct perf_session *session = top->session; |
803 | union perf_event *event; | 802 | union perf_event *event; |
804 | struct machine *machine; | 803 | struct machine *machine; |
805 | u8 origin; | 804 | u8 origin; |
806 | int ret; | 805 | int ret; |
807 | 806 | ||
808 | while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { | 807 | while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { |
809 | ret = perf_evlist__parse_sample(top->evlist, event, &sample); | 808 | ret = perf_evlist__parse_sample(top->evlist, event, &sample); |
810 | if (ret) { | 809 | if (ret) { |
811 | pr_err("Can't parse sample, err = %d\n", ret); | 810 | pr_err("Can't parse sample, err = %d\n", ret); |
812 | goto next_event; | 811 | goto next_event; |
813 | } | 812 | } |
814 | 813 | ||
815 | evsel = perf_evlist__id2evsel(session->evlist, sample.id); | 814 | evsel = perf_evlist__id2evsel(session->evlist, sample.id); |
816 | assert(evsel != NULL); | 815 | assert(evsel != NULL); |
817 | 816 | ||
818 | origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 817 | origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
819 | 818 | ||
820 | if (event->header.type == PERF_RECORD_SAMPLE) | 819 | if (event->header.type == PERF_RECORD_SAMPLE) |
821 | ++top->samples; | 820 | ++top->samples; |
822 | 821 | ||
823 | switch (origin) { | 822 | switch (origin) { |
824 | case PERF_RECORD_MISC_USER: | 823 | case PERF_RECORD_MISC_USER: |
825 | ++top->us_samples; | 824 | ++top->us_samples; |
826 | if (top->hide_user_symbols) | 825 | if (top->hide_user_symbols) |
827 | goto next_event; | 826 | goto next_event; |
828 | machine = &session->machines.host; | 827 | machine = &session->machines.host; |
829 | break; | 828 | break; |
830 | case PERF_RECORD_MISC_KERNEL: | 829 | case PERF_RECORD_MISC_KERNEL: |
831 | ++top->kernel_samples; | 830 | ++top->kernel_samples; |
832 | if (top->hide_kernel_symbols) | 831 | if (top->hide_kernel_symbols) |
833 | goto next_event; | 832 | goto next_event; |
834 | machine = &session->machines.host; | 833 | machine = &session->machines.host; |
835 | break; | 834 | break; |
836 | case PERF_RECORD_MISC_GUEST_KERNEL: | 835 | case PERF_RECORD_MISC_GUEST_KERNEL: |
837 | ++top->guest_kernel_samples; | 836 | ++top->guest_kernel_samples; |
838 | machine = perf_session__find_machine(session, | 837 | machine = perf_session__find_machine(session, |
839 | sample.pid); | 838 | sample.pid); |
840 | break; | 839 | break; |
841 | case PERF_RECORD_MISC_GUEST_USER: | 840 | case PERF_RECORD_MISC_GUEST_USER: |
842 | ++top->guest_us_samples; | 841 | ++top->guest_us_samples; |
843 | /* | 842 | /* |
844 | * TODO: we don't process guest user from host side | 843 | * TODO: we don't process guest user from host side |
845 | * except simple counting. | 844 | * except simple counting. |
846 | */ | 845 | */ |
847 | /* Fall thru */ | 846 | /* Fall thru */ |
848 | default: | 847 | default: |
849 | goto next_event; | 848 | goto next_event; |
850 | } | 849 | } |
851 | 850 | ||
852 | 851 | ||
853 | if (event->header.type == PERF_RECORD_SAMPLE) { | 852 | if (event->header.type == PERF_RECORD_SAMPLE) { |
854 | perf_event__process_sample(&top->tool, event, evsel, | 853 | perf_event__process_sample(&top->tool, event, evsel, |
855 | &sample, machine); | 854 | &sample, machine); |
856 | } else if (event->header.type < PERF_RECORD_MAX) { | 855 | } else if (event->header.type < PERF_RECORD_MAX) { |
857 | hists__inc_nr_events(evsel__hists(evsel), event->header.type); | 856 | hists__inc_nr_events(evsel__hists(evsel), event->header.type); |
858 | machine__process_event(machine, event, &sample); | 857 | machine__process_event(machine, event, &sample); |
859 | } else | 858 | } else |
860 | ++session->stats.nr_unknown_events; | 859 | ++session->stats.nr_unknown_events; |
861 | next_event: | 860 | next_event: |
862 | perf_evlist__mmap_consume(top->evlist, idx); | 861 | perf_evlist__mmap_consume(top->evlist, idx); |
863 | } | 862 | } |
864 | } | 863 | } |
865 | 864 | ||
866 | static void perf_top__mmap_read(struct perf_top *top) | 865 | static void perf_top__mmap_read(struct perf_top *top) |
867 | { | 866 | { |
868 | int i; | 867 | int i; |
869 | 868 | ||
870 | for (i = 0; i < top->evlist->nr_mmaps; i++) | 869 | for (i = 0; i < top->evlist->nr_mmaps; i++) |
871 | perf_top__mmap_read_idx(top, i); | 870 | perf_top__mmap_read_idx(top, i); |
872 | } | 871 | } |
873 | 872 | ||
874 | static int perf_top__start_counters(struct perf_top *top) | 873 | static int perf_top__start_counters(struct perf_top *top) |
875 | { | 874 | { |
876 | char msg[512]; | 875 | char msg[512]; |
877 | struct perf_evsel *counter; | 876 | struct perf_evsel *counter; |
878 | struct perf_evlist *evlist = top->evlist; | 877 | struct perf_evlist *evlist = top->evlist; |
879 | struct record_opts *opts = &top->record_opts; | 878 | struct record_opts *opts = &top->record_opts; |
880 | 879 | ||
881 | perf_evlist__config(evlist, opts); | 880 | perf_evlist__config(evlist, opts); |
882 | 881 | ||
883 | evlist__for_each(evlist, counter) { | 882 | evlist__for_each(evlist, counter) { |
884 | try_again: | 883 | try_again: |
885 | if (perf_evsel__open(counter, top->evlist->cpus, | 884 | if (perf_evsel__open(counter, top->evlist->cpus, |
886 | top->evlist->threads) < 0) { | 885 | top->evlist->threads) < 0) { |
887 | if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { | 886 | if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { |
888 | if (verbose) | 887 | if (verbose) |
889 | ui__warning("%s\n", msg); | 888 | ui__warning("%s\n", msg); |
890 | goto try_again; | 889 | goto try_again; |
891 | } | 890 | } |
892 | 891 | ||
893 | perf_evsel__open_strerror(counter, &opts->target, | 892 | perf_evsel__open_strerror(counter, &opts->target, |
894 | errno, msg, sizeof(msg)); | 893 | errno, msg, sizeof(msg)); |
895 | ui__error("%s\n", msg); | 894 | ui__error("%s\n", msg); |
896 | goto out_err; | 895 | goto out_err; |
897 | } | 896 | } |
898 | } | 897 | } |
899 | 898 | ||
900 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { | 899 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { |
901 | ui__error("Failed to mmap with %d (%s)\n", | 900 | ui__error("Failed to mmap with %d (%s)\n", |
902 | errno, strerror_r(errno, msg, sizeof(msg))); | 901 | errno, strerror_r(errno, msg, sizeof(msg))); |
903 | goto out_err; | 902 | goto out_err; |
904 | } | 903 | } |
905 | 904 | ||
906 | return 0; | 905 | return 0; |
907 | 906 | ||
908 | out_err: | 907 | out_err: |
909 | return -1; | 908 | return -1; |
910 | } | 909 | } |
911 | 910 | ||
912 | static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) | 911 | static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) |
913 | { | 912 | { |
914 | if (!sort__has_sym) { | 913 | if (!sort__has_sym) { |
915 | if (symbol_conf.use_callchain) { | 914 | if (symbol_conf.use_callchain) { |
916 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); | 915 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); |
917 | return -EINVAL; | 916 | return -EINVAL; |
918 | } | 917 | } |
919 | } else if (callchain_param.mode != CHAIN_NONE) { | 918 | } else if (callchain_param.mode != CHAIN_NONE) { |
920 | if (callchain_register_param(&callchain_param) < 0) { | 919 | if (callchain_register_param(&callchain_param) < 0) { |
921 | ui__error("Can't register callchain params.\n"); | 920 | ui__error("Can't register callchain params.\n"); |
922 | return -EINVAL; | 921 | return -EINVAL; |
923 | } | 922 | } |
924 | } | 923 | } |
925 | 924 | ||
926 | return 0; | 925 | return 0; |
927 | } | 926 | } |
928 | 927 | ||
929 | static int __cmd_top(struct perf_top *top) | 928 | static int __cmd_top(struct perf_top *top) |
930 | { | 929 | { |
931 | struct record_opts *opts = &top->record_opts; | 930 | struct record_opts *opts = &top->record_opts; |
932 | pthread_t thread; | 931 | pthread_t thread; |
933 | int ret; | 932 | int ret; |
934 | 933 | ||
935 | top->session = perf_session__new(NULL, false, NULL); | 934 | top->session = perf_session__new(NULL, false, NULL); |
936 | if (top->session == NULL) | 935 | if (top->session == NULL) |
937 | return -1; | 936 | return -1; |
938 | 937 | ||
939 | machines__set_symbol_filter(&top->session->machines, symbol_filter); | 938 | machines__set_symbol_filter(&top->session->machines, symbol_filter); |
940 | 939 | ||
941 | if (!objdump_path) { | 940 | if (!objdump_path) { |
942 | ret = perf_session_env__lookup_objdump(&top->session->header.env); | 941 | ret = perf_session_env__lookup_objdump(&top->session->header.env); |
943 | if (ret) | 942 | if (ret) |
944 | goto out_delete; | 943 | goto out_delete; |
945 | } | 944 | } |
946 | 945 | ||
947 | ret = perf_top__setup_sample_type(top); | 946 | ret = perf_top__setup_sample_type(top); |
948 | if (ret) | 947 | if (ret) |
949 | goto out_delete; | 948 | goto out_delete; |
950 | 949 | ||
951 | machine__synthesize_threads(&top->session->machines.host, &opts->target, | 950 | machine__synthesize_threads(&top->session->machines.host, &opts->target, |
952 | top->evlist->threads, false); | 951 | top->evlist->threads, false); |
953 | ret = perf_top__start_counters(top); | 952 | ret = perf_top__start_counters(top); |
954 | if (ret) | 953 | if (ret) |
955 | goto out_delete; | 954 | goto out_delete; |
956 | 955 | ||
957 | top->session->evlist = top->evlist; | 956 | top->session->evlist = top->evlist; |
958 | perf_session__set_id_hdr_size(top->session); | 957 | perf_session__set_id_hdr_size(top->session); |
959 | 958 | ||
960 | /* | 959 | /* |
961 | * When perf is starting the traced process, all the events (apart from | 960 | * When perf is starting the traced process, all the events (apart from |
962 | * group members) have enable_on_exec=1 set, so don't spoil it by | 961 | * group members) have enable_on_exec=1 set, so don't spoil it by |
963 | * prematurely enabling them. | 962 | * prematurely enabling them. |
964 | * | 963 | * |
965 | * XXX 'top' still doesn't start workloads like record, trace, but should, | 964 | * XXX 'top' still doesn't start workloads like record, trace, but should, |
966 | * so leave the check here. | 965 | * so leave the check here. |
967 | */ | 966 | */ |
968 | if (!target__none(&opts->target)) | 967 | if (!target__none(&opts->target)) |
969 | perf_evlist__enable(top->evlist); | 968 | perf_evlist__enable(top->evlist); |
970 | 969 | ||
971 | /* Wait for a minimal set of events before starting the snapshot */ | 970 | /* Wait for a minimal set of events before starting the snapshot */ |
972 | perf_evlist__poll(top->evlist, 100); | 971 | perf_evlist__poll(top->evlist, 100); |
973 | 972 | ||
974 | perf_top__mmap_read(top); | 973 | perf_top__mmap_read(top); |
975 | 974 | ||
976 | ret = -1; | 975 | ret = -1; |
977 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : | 976 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
978 | display_thread), top)) { | 977 | display_thread), top)) { |
979 | ui__error("Could not create display thread.\n"); | 978 | ui__error("Could not create display thread.\n"); |
980 | goto out_delete; | 979 | goto out_delete; |
981 | } | 980 | } |
982 | 981 | ||
983 | if (top->realtime_prio) { | 982 | if (top->realtime_prio) { |
984 | struct sched_param param; | 983 | struct sched_param param; |
985 | 984 | ||
986 | param.sched_priority = top->realtime_prio; | 985 | param.sched_priority = top->realtime_prio; |
987 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 986 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
988 | ui__error("Could not set realtime priority.\n"); | 987 | ui__error("Could not set realtime priority.\n"); |
989 | goto out_join; | 988 | goto out_join; |
990 | } | 989 | } |
991 | } | 990 | } |
992 | 991 | ||
993 | while (!done) { | 992 | while (!done) { |
994 | u64 hits = top->samples; | 993 | u64 hits = top->samples; |
995 | 994 | ||
996 | perf_top__mmap_read(top); | 995 | perf_top__mmap_read(top); |
997 | 996 | ||
998 | if (hits == top->samples) | 997 | if (hits == top->samples) |
999 | ret = perf_evlist__poll(top->evlist, 100); | 998 | ret = perf_evlist__poll(top->evlist, 100); |
1000 | } | 999 | } |
1001 | 1000 | ||
1002 | ret = 0; | 1001 | ret = 0; |
1003 | out_join: | 1002 | out_join: |
1004 | pthread_join(thread, NULL); | 1003 | pthread_join(thread, NULL); |
1005 | out_delete: | 1004 | out_delete: |
1006 | perf_session__delete(top->session); | 1005 | perf_session__delete(top->session); |
1007 | top->session = NULL; | 1006 | top->session = NULL; |
1008 | 1007 | ||
1009 | return ret; | 1008 | return ret; |
1010 | } | 1009 | } |
1011 | 1010 | ||
1012 | static int | 1011 | static int |
1013 | callchain_opt(const struct option *opt, const char *arg, int unset) | 1012 | callchain_opt(const struct option *opt, const char *arg, int unset) |
1014 | { | 1013 | { |
1015 | symbol_conf.use_callchain = true; | 1014 | symbol_conf.use_callchain = true; |
1016 | return record_callchain_opt(opt, arg, unset); | 1015 | return record_callchain_opt(opt, arg, unset); |
1017 | } | 1016 | } |
1018 | 1017 | ||
1019 | static int | 1018 | static int |
1020 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1019 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
1021 | { | 1020 | { |
1022 | symbol_conf.use_callchain = true; | 1021 | symbol_conf.use_callchain = true; |
1023 | return record_parse_callchain_opt(opt, arg, unset); | 1022 | return record_parse_callchain_opt(opt, arg, unset); |
1024 | } | 1023 | } |
1025 | 1024 | ||
1026 | static int perf_top_config(const char *var, const char *value, void *cb) | 1025 | static int perf_top_config(const char *var, const char *value, void *cb) |
1027 | { | 1026 | { |
1028 | if (!strcmp(var, "top.call-graph")) | 1027 | if (!strcmp(var, "top.call-graph")) |
1029 | var = "call-graph.record-mode"; /* fall-through */ | 1028 | var = "call-graph.record-mode"; /* fall-through */ |
1030 | if (!strcmp(var, "top.children")) { | 1029 | if (!strcmp(var, "top.children")) { |
1031 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); | 1030 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); |
1032 | return 0; | 1031 | return 0; |
1033 | } | 1032 | } |
1034 | 1033 | ||
1035 | return perf_default_config(var, value, cb); | 1034 | return perf_default_config(var, value, cb); |
1036 | } | 1035 | } |
1037 | 1036 | ||
1038 | static int | 1037 | static int |
1039 | parse_percent_limit(const struct option *opt, const char *arg, | 1038 | parse_percent_limit(const struct option *opt, const char *arg, |
1040 | int unset __maybe_unused) | 1039 | int unset __maybe_unused) |
1041 | { | 1040 | { |
1042 | struct perf_top *top = opt->value; | 1041 | struct perf_top *top = opt->value; |
1043 | 1042 | ||
1044 | top->min_percent = strtof(arg, NULL); | 1043 | top->min_percent = strtof(arg, NULL); |
1045 | return 0; | 1044 | return 0; |
1046 | } | 1045 | } |
1047 | 1046 | ||
1048 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1047 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
1049 | { | 1048 | { |
1050 | char errbuf[BUFSIZ]; | 1049 | char errbuf[BUFSIZ]; |
1051 | struct perf_top top = { | 1050 | struct perf_top top = { |
1052 | .count_filter = 5, | 1051 | .count_filter = 5, |
1053 | .delay_secs = 2, | 1052 | .delay_secs = 2, |
1054 | .record_opts = { | 1053 | .record_opts = { |
1055 | .mmap_pages = UINT_MAX, | 1054 | .mmap_pages = UINT_MAX, |
1056 | .user_freq = UINT_MAX, | 1055 | .user_freq = UINT_MAX, |
1057 | .user_interval = ULLONG_MAX, | 1056 | .user_interval = ULLONG_MAX, |
1058 | .freq = 4000, /* 4 KHz */ | 1057 | .freq = 4000, /* 4 KHz */ |
1059 | .target = { | 1058 | .target = { |
1060 | .uses_mmap = true, | 1059 | .uses_mmap = true, |
1061 | }, | 1060 | }, |
1062 | }, | 1061 | }, |
1063 | .max_stack = PERF_MAX_STACK_DEPTH, | 1062 | .max_stack = PERF_MAX_STACK_DEPTH, |
1064 | .sym_pcnt_filter = 5, | 1063 | .sym_pcnt_filter = 5, |
1065 | }; | 1064 | }; |
1066 | struct record_opts *opts = &top.record_opts; | 1065 | struct record_opts *opts = &top.record_opts; |
1067 | struct target *target = &opts->target; | 1066 | struct target *target = &opts->target; |
1068 | const struct option options[] = { | 1067 | const struct option options[] = { |
1069 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1068 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
1070 | "event selector. use 'perf list' to list available events", | 1069 | "event selector. use 'perf list' to list available events", |
1071 | parse_events_option), | 1070 | parse_events_option), |
1072 | OPT_U64('c', "count", &opts->user_interval, "event period to sample"), | 1071 | OPT_U64('c', "count", &opts->user_interval, "event period to sample"), |
1073 | OPT_STRING('p', "pid", &target->pid, "pid", | 1072 | OPT_STRING('p', "pid", &target->pid, "pid", |
1074 | "profile events on existing process id"), | 1073 | "profile events on existing process id"), |
1075 | OPT_STRING('t', "tid", &target->tid, "tid", | 1074 | OPT_STRING('t', "tid", &target->tid, "tid", |
1076 | "profile events on existing thread id"), | 1075 | "profile events on existing thread id"), |
1077 | OPT_BOOLEAN('a', "all-cpus", &target->system_wide, | 1076 | OPT_BOOLEAN('a', "all-cpus", &target->system_wide, |
1078 | "system-wide collection from all CPUs"), | 1077 | "system-wide collection from all CPUs"), |
1079 | OPT_STRING('C', "cpu", &target->cpu_list, "cpu", | 1078 | OPT_STRING('C', "cpu", &target->cpu_list, "cpu", |
1080 | "list of cpus to monitor"), | 1079 | "list of cpus to monitor"), |
1081 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1080 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1082 | "file", "vmlinux pathname"), | 1081 | "file", "vmlinux pathname"), |
1083 | OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux, | 1082 | OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux, |
1084 | "don't load vmlinux even if found"), | 1083 | "don't load vmlinux even if found"), |
1085 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, | 1084 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, |
1086 | "hide kernel symbols"), | 1085 | "hide kernel symbols"), |
1087 | OPT_CALLBACK('m', "mmap-pages", &opts->mmap_pages, "pages", | 1086 | OPT_CALLBACK('m', "mmap-pages", &opts->mmap_pages, "pages", |
1088 | "number of mmap data pages", | 1087 | "number of mmap data pages", |
1089 | perf_evlist__parse_mmap_pages), | 1088 | perf_evlist__parse_mmap_pages), |
1090 | OPT_INTEGER('r', "realtime", &top.realtime_prio, | 1089 | OPT_INTEGER('r', "realtime", &top.realtime_prio, |
1091 | "collect data with this RT SCHED_FIFO priority"), | 1090 | "collect data with this RT SCHED_FIFO priority"), |
1092 | OPT_INTEGER('d', "delay", &top.delay_secs, | 1091 | OPT_INTEGER('d', "delay", &top.delay_secs, |
1093 | "number of seconds to delay between refreshes"), | 1092 | "number of seconds to delay between refreshes"), |
1094 | OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab, | 1093 | OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab, |
1095 | "dump the symbol table used for profiling"), | 1094 | "dump the symbol table used for profiling"), |
1096 | OPT_INTEGER('f', "count-filter", &top.count_filter, | 1095 | OPT_INTEGER('f', "count-filter", &top.count_filter, |
1097 | "only display functions with more events than this"), | 1096 | "only display functions with more events than this"), |
1098 | OPT_BOOLEAN(0, "group", &opts->group, | 1097 | OPT_BOOLEAN(0, "group", &opts->group, |
1099 | "put the counters into a counter group"), | 1098 | "put the counters into a counter group"), |
1100 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, | 1099 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, |
1101 | "child tasks do not inherit counters"), | 1100 | "child tasks do not inherit counters"), |
1102 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", | 1101 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", |
1103 | "symbol to annotate"), | 1102 | "symbol to annotate"), |
1104 | OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), | 1103 | OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), |
1105 | OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"), | 1104 | OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"), |
1106 | OPT_INTEGER('E', "entries", &top.print_entries, | 1105 | OPT_INTEGER('E', "entries", &top.print_entries, |
1107 | "display this many functions"), | 1106 | "display this many functions"), |
1108 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, | 1107 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, |
1109 | "hide user symbols"), | 1108 | "hide user symbols"), |
1110 | OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"), | 1109 | OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"), |
1111 | OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"), | 1110 | OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"), |
1112 | OPT_INCR('v', "verbose", &verbose, | 1111 | OPT_INCR('v', "verbose", &verbose, |
1113 | "be more verbose (show counter open errors, etc)"), | 1112 | "be more verbose (show counter open errors, etc)"), |
1114 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 1113 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
1115 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..." | 1114 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..." |
1116 | " Please refer the man page for the complete list."), | 1115 | " Please refer the man page for the complete list."), |
1117 | OPT_STRING(0, "fields", &field_order, "key[,keys...]", | 1116 | OPT_STRING(0, "fields", &field_order, "key[,keys...]", |
1118 | "output field(s): overhead, period, sample plus all of sort keys"), | 1117 | "output field(s): overhead, period, sample plus all of sort keys"), |
1119 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1118 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1120 | "Show a column with the number of samples"), | 1119 | "Show a column with the number of samples"), |
1121 | OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, | 1120 | OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, |
1122 | NULL, "enables call-graph recording", | 1121 | NULL, "enables call-graph recording", |
1123 | &callchain_opt), | 1122 | &callchain_opt), |
1124 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | 1123 | OPT_CALLBACK(0, "call-graph", &top.record_opts, |
1125 | "mode[,dump_size]", record_callchain_help, | 1124 | "mode[,dump_size]", record_callchain_help, |
1126 | &parse_callchain_opt), | 1125 | &parse_callchain_opt), |
1127 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, | 1126 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, |
1128 | "Accumulate callchains of children and show total overhead as well"), | 1127 | "Accumulate callchains of children and show total overhead as well"), |
1129 | OPT_INTEGER(0, "max-stack", &top.max_stack, | 1128 | OPT_INTEGER(0, "max-stack", &top.max_stack, |
1130 | "Set the maximum stack depth when parsing the callchain. " | 1129 | "Set the maximum stack depth when parsing the callchain. " |
1131 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 1130 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), |
1132 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 1131 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
1133 | "ignore callees of these functions in call graphs", | 1132 | "ignore callees of these functions in call graphs", |
1134 | report_parse_ignore_callees_opt), | 1133 | report_parse_ignore_callees_opt), |
1135 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 1134 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
1136 | "Show a column with the sum of periods"), | 1135 | "Show a column with the sum of periods"), |
1137 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 1136 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
1138 | "only consider symbols in these dsos"), | 1137 | "only consider symbols in these dsos"), |
1139 | OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]", | 1138 | OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]", |
1140 | "only consider symbols in these comms"), | 1139 | "only consider symbols in these comms"), |
1141 | OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 1140 | OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
1142 | "only consider these symbols"), | 1141 | "only consider these symbols"), |
1143 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, | 1142 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, |
1144 | "Interleave source code with assembly code (default)"), | 1143 | "Interleave source code with assembly code (default)"), |
1145 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | 1144 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, |
1146 | "Display raw encoding of assembly instructions (default)"), | 1145 | "Display raw encoding of assembly instructions (default)"), |
1147 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, | 1146 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, |
1148 | "Enable kernel symbol demangling"), | 1147 | "Enable kernel symbol demangling"), |
1149 | OPT_STRING(0, "objdump", &objdump_path, "path", | 1148 | OPT_STRING(0, "objdump", &objdump_path, "path", |
1150 | "objdump binary to use for disassembly and annotations"), | 1149 | "objdump binary to use for disassembly and annotations"), |
1151 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1150 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
1152 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1151 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
1153 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), | 1152 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), |
1154 | OPT_CALLBACK(0, "percent-limit", &top, "percent", | 1153 | OPT_CALLBACK(0, "percent-limit", &top, "percent", |
1155 | "Don't show entries under that percent", parse_percent_limit), | 1154 | "Don't show entries under that percent", parse_percent_limit), |
1156 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", | 1155 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", |
1157 | "How to display percentage of filtered entries", parse_filter_percentage), | 1156 | "How to display percentage of filtered entries", parse_filter_percentage), |
1158 | OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, | 1157 | OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, |
1159 | "width[,width...]", | 1158 | "width[,width...]", |
1160 | "don't try to adjust column width, use these fixed values"), | 1159 | "don't try to adjust column width, use these fixed values"), |
1161 | OPT_END() | 1160 | OPT_END() |
1162 | }; | 1161 | }; |
1163 | const char * const top_usage[] = { | 1162 | const char * const top_usage[] = { |
1164 | "perf top [<options>]", | 1163 | "perf top [<options>]", |
1165 | NULL | 1164 | NULL |
1166 | }; | 1165 | }; |
1167 | int status = hists__init(); | 1166 | int status = hists__init(); |
1168 | 1167 | ||
1169 | if (status < 0) | 1168 | if (status < 0) |
1170 | return status; | 1169 | return status; |
1171 | 1170 | ||
1172 | top.evlist = perf_evlist__new(); | 1171 | top.evlist = perf_evlist__new(); |
1173 | if (top.evlist == NULL) | 1172 | if (top.evlist == NULL) |
1174 | return -ENOMEM; | 1173 | return -ENOMEM; |
1175 | 1174 | ||
1176 | perf_config(perf_top_config, &top); | 1175 | perf_config(perf_top_config, &top); |
1177 | 1176 | ||
1178 | argc = parse_options(argc, argv, options, top_usage, 0); | 1177 | argc = parse_options(argc, argv, options, top_usage, 0); |
1179 | if (argc) | 1178 | if (argc) |
1180 | usage_with_options(top_usage, options); | 1179 | usage_with_options(top_usage, options); |
1181 | 1180 | ||
1182 | sort__mode = SORT_MODE__TOP; | 1181 | sort__mode = SORT_MODE__TOP; |
1183 | /* display thread wants entries to be collapsed in a different tree */ | 1182 | /* display thread wants entries to be collapsed in a different tree */ |
1184 | sort__need_collapse = 1; | 1183 | sort__need_collapse = 1; |
1185 | 1184 | ||
1186 | if (setup_sorting() < 0) { | 1185 | if (setup_sorting() < 0) { |
1187 | if (sort_order) | 1186 | if (sort_order) |
1188 | parse_options_usage(top_usage, options, "s", 1); | 1187 | parse_options_usage(top_usage, options, "s", 1); |
1189 | if (field_order) | 1188 | if (field_order) |
1190 | parse_options_usage(sort_order ? NULL : top_usage, | 1189 | parse_options_usage(sort_order ? NULL : top_usage, |
1191 | options, "fields", 0); | 1190 | options, "fields", 0); |
1192 | goto out_delete_evlist; | 1191 | goto out_delete_evlist; |
1193 | } | 1192 | } |
1194 | 1193 | ||
1195 | if (top.use_stdio) | 1194 | if (top.use_stdio) |
1196 | use_browser = 0; | 1195 | use_browser = 0; |
1197 | else if (top.use_tui) | 1196 | else if (top.use_tui) |
1198 | use_browser = 1; | 1197 | use_browser = 1; |
1199 | 1198 | ||
1200 | setup_browser(false); | 1199 | setup_browser(false); |
1201 | 1200 | ||
1202 | status = target__validate(target); | 1201 | status = target__validate(target); |
1203 | if (status) { | 1202 | if (status) { |
1204 | target__strerror(target, status, errbuf, BUFSIZ); | 1203 | target__strerror(target, status, errbuf, BUFSIZ); |
1205 | ui__warning("%s\n", errbuf); | 1204 | ui__warning("%s\n", errbuf); |
1206 | } | 1205 | } |
1207 | 1206 | ||
1208 | status = target__parse_uid(target); | 1207 | status = target__parse_uid(target); |
1209 | if (status) { | 1208 | if (status) { |
1210 | int saved_errno = errno; | 1209 | int saved_errno = errno; |
1211 | 1210 | ||
1212 | target__strerror(target, status, errbuf, BUFSIZ); | 1211 | target__strerror(target, status, errbuf, BUFSIZ); |
1213 | ui__error("%s\n", errbuf); | 1212 | ui__error("%s\n", errbuf); |
1214 | 1213 | ||
1215 | status = -saved_errno; | 1214 | status = -saved_errno; |
1216 | goto out_delete_evlist; | 1215 | goto out_delete_evlist; |
1217 | } | 1216 | } |
1218 | 1217 | ||
1219 | if (target__none(target)) | 1218 | if (target__none(target)) |
1220 | target->system_wide = true; | 1219 | target->system_wide = true; |
1221 | 1220 | ||
1222 | if (perf_evlist__create_maps(top.evlist, target) < 0) | 1221 | if (perf_evlist__create_maps(top.evlist, target) < 0) |
1223 | usage_with_options(top_usage, options); | 1222 | usage_with_options(top_usage, options); |
1224 | 1223 | ||
1225 | if (!top.evlist->nr_entries && | 1224 | if (!top.evlist->nr_entries && |
1226 | perf_evlist__add_default(top.evlist) < 0) { | 1225 | perf_evlist__add_default(top.evlist) < 0) { |
1227 | ui__error("Not enough memory for event selector list\n"); | 1226 | ui__error("Not enough memory for event selector list\n"); |
1228 | goto out_delete_evlist; | 1227 | goto out_delete_evlist; |
1229 | } | 1228 | } |
1230 | 1229 | ||
1231 | symbol_conf.nr_events = top.evlist->nr_entries; | 1230 | symbol_conf.nr_events = top.evlist->nr_entries; |
1232 | 1231 | ||
1233 | if (top.delay_secs < 1) | 1232 | if (top.delay_secs < 1) |
1234 | top.delay_secs = 1; | 1233 | top.delay_secs = 1; |
1235 | 1234 | ||
1236 | if (record_opts__config(opts)) { | 1235 | if (record_opts__config(opts)) { |
1237 | status = -EINVAL; | 1236 | status = -EINVAL; |
1238 | goto out_delete_evlist; | 1237 | goto out_delete_evlist; |
1239 | } | 1238 | } |
1240 | 1239 | ||
1241 | top.sym_evsel = perf_evlist__first(top.evlist); | 1240 | top.sym_evsel = perf_evlist__first(top.evlist); |
1242 | 1241 | ||
1243 | if (!symbol_conf.use_callchain) { | 1242 | if (!symbol_conf.use_callchain) { |
1244 | symbol_conf.cumulate_callchain = false; | 1243 | symbol_conf.cumulate_callchain = false; |
1245 | perf_hpp__cancel_cumulate(); | 1244 | perf_hpp__cancel_cumulate(); |
1246 | } | 1245 | } |
1247 | 1246 | ||
1248 | symbol_conf.priv_size = sizeof(struct annotation); | 1247 | symbol_conf.priv_size = sizeof(struct annotation); |
1249 | 1248 | ||
1250 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | 1249 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1251 | if (symbol__init(NULL) < 0) | 1250 | if (symbol__init(NULL) < 0) |
1252 | return -1; | 1251 | return -1; |
1253 | 1252 | ||
1254 | sort__setup_elide(stdout); | 1253 | sort__setup_elide(stdout); |
1255 | 1254 | ||
1256 | get_term_dimensions(&top.winsize); | 1255 | get_term_dimensions(&top.winsize); |
1257 | if (top.print_entries == 0) { | 1256 | if (top.print_entries == 0) { |
1258 | struct sigaction act = { | 1257 | struct sigaction act = { |
1259 | .sa_sigaction = perf_top__sig_winch, | 1258 | .sa_sigaction = perf_top__sig_winch, |
1260 | .sa_flags = SA_SIGINFO, | 1259 | .sa_flags = SA_SIGINFO, |
1261 | }; | 1260 | }; |
1262 | perf_top__update_print_entries(&top); | 1261 | perf_top__update_print_entries(&top); |
1263 | sigaction(SIGWINCH, &act, NULL); | 1262 | sigaction(SIGWINCH, &act, NULL); |
1264 | } | 1263 | } |
1265 | 1264 | ||
1266 | status = __cmd_top(&top); | 1265 | status = __cmd_top(&top); |
1267 | 1266 | ||
1268 | out_delete_evlist: | 1267 | out_delete_evlist: |
1269 | perf_evlist__delete(top.evlist); | 1268 | perf_evlist__delete(top.evlist); |
1270 | 1269 | ||
1271 | return status; | 1270 | return status; |
1272 | } | 1271 | } |
1273 | 1272 |
tools/perf/config/Makefile
1 | 1 | ||
2 | ifeq ($(src-perf),) | 2 | ifeq ($(src-perf),) |
3 | src-perf := $(srctree)/tools/perf | 3 | src-perf := $(srctree)/tools/perf |
4 | endif | 4 | endif |
5 | 5 | ||
6 | ifeq ($(obj-perf),) | 6 | ifeq ($(obj-perf),) |
7 | obj-perf := $(OUTPUT) | 7 | obj-perf := $(OUTPUT) |
8 | endif | 8 | endif |
9 | 9 | ||
10 | ifneq ($(obj-perf),) | 10 | ifneq ($(obj-perf),) |
11 | obj-perf := $(abspath $(obj-perf))/ | 11 | obj-perf := $(abspath $(obj-perf))/ |
12 | endif | 12 | endif |
13 | 13 | ||
14 | LIB_INCLUDE := $(srctree)/tools/lib/ | 14 | LIB_INCLUDE := $(srctree)/tools/lib/ |
15 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) | 15 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) |
16 | 16 | ||
17 | include $(src-perf)/config/Makefile.arch | 17 | include $(src-perf)/config/Makefile.arch |
18 | 18 | ||
19 | NO_PERF_REGS := 1 | 19 | NO_PERF_REGS := 1 |
20 | 20 | ||
21 | # Additional ARCH settings for x86 | 21 | # Additional ARCH settings for x86 |
22 | ifeq ($(ARCH),x86) | 22 | ifeq ($(ARCH),x86) |
23 | ifeq (${IS_X86_64}, 1) | 23 | ifeq (${IS_64_BIT}, 1) |
24 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT | 24 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT |
25 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | 25 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S |
26 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | 26 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 |
27 | else | 27 | else |
28 | LIBUNWIND_LIBS = -lunwind -lunwind-x86 | 28 | LIBUNWIND_LIBS = -lunwind -lunwind-x86 |
29 | endif | 29 | endif |
30 | NO_PERF_REGS := 0 | 30 | NO_PERF_REGS := 0 |
31 | endif | 31 | endif |
32 | 32 | ||
33 | ifeq ($(ARCH),arm) | 33 | ifeq ($(ARCH),arm) |
34 | NO_PERF_REGS := 0 | 34 | NO_PERF_REGS := 0 |
35 | LIBUNWIND_LIBS = -lunwind -lunwind-arm | 35 | LIBUNWIND_LIBS = -lunwind -lunwind-arm |
36 | endif | 36 | endif |
37 | 37 | ||
38 | ifeq ($(ARCH),arm64) | 38 | ifeq ($(ARCH),arm64) |
39 | NO_PERF_REGS := 0 | 39 | NO_PERF_REGS := 0 |
40 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 | 40 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 |
41 | endif | 41 | endif |
42 | 42 | ||
43 | # So far there's only x86 and arm libdw unwind support merged in perf. | 43 | # So far there's only x86 and arm libdw unwind support merged in perf. |
44 | # Disable it on all other architectures in case libdw unwind | 44 | # Disable it on all other architectures in case libdw unwind |
45 | # support is detected in system. Add supported architectures | 45 | # support is detected in system. Add supported architectures |
46 | # to the check. | 46 | # to the check. |
47 | ifneq ($(ARCH),$(filter $(ARCH),x86 arm)) | 47 | ifneq ($(ARCH),$(filter $(ARCH),x86 arm)) |
48 | NO_LIBDW_DWARF_UNWIND := 1 | 48 | NO_LIBDW_DWARF_UNWIND := 1 |
49 | endif | 49 | endif |
50 | 50 | ||
51 | ifeq ($(LIBUNWIND_LIBS),) | 51 | ifeq ($(LIBUNWIND_LIBS),) |
52 | NO_LIBUNWIND := 1 | 52 | NO_LIBUNWIND := 1 |
53 | else | 53 | else |
54 | # | 54 | # |
55 | # For linking with debug library, run like: | 55 | # For linking with debug library, run like: |
56 | # | 56 | # |
57 | # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ | 57 | # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ |
58 | # | 58 | # |
59 | ifdef LIBUNWIND_DIR | 59 | ifdef LIBUNWIND_DIR |
60 | LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include | 60 | LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include |
61 | LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib | 61 | LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib |
62 | endif | 62 | endif |
63 | LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) | 63 | LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) |
64 | 64 | ||
65 | # Set per-feature check compilation flags | 65 | # Set per-feature check compilation flags |
66 | FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS) | 66 | FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS) |
67 | FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) | 67 | FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) |
68 | FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS) | 68 | FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS) |
69 | FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) | 69 | FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) |
70 | endif | 70 | endif |
71 | 71 | ||
72 | ifeq ($(NO_PERF_REGS),0) | 72 | ifeq ($(NO_PERF_REGS),0) |
73 | CFLAGS += -DHAVE_PERF_REGS_SUPPORT | 73 | CFLAGS += -DHAVE_PERF_REGS_SUPPORT |
74 | endif | 74 | endif |
75 | 75 | ||
76 | ifndef NO_LIBELF | 76 | ifndef NO_LIBELF |
77 | # for linking with debug library, run like: | 77 | # for linking with debug library, run like: |
78 | # make DEBUG=1 LIBDW_DIR=/opt/libdw/ | 78 | # make DEBUG=1 LIBDW_DIR=/opt/libdw/ |
79 | ifdef LIBDW_DIR | 79 | ifdef LIBDW_DIR |
80 | LIBDW_CFLAGS := -I$(LIBDW_DIR)/include | 80 | LIBDW_CFLAGS := -I$(LIBDW_DIR)/include |
81 | LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib | 81 | LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib |
82 | endif | 82 | endif |
83 | FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS) | 83 | FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS) |
84 | FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw | 84 | FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw |
85 | endif | 85 | endif |
86 | 86 | ||
87 | # include ARCH specific config | 87 | # include ARCH specific config |
88 | -include $(src-perf)/arch/$(ARCH)/Makefile | 88 | -include $(src-perf)/arch/$(ARCH)/Makefile |
89 | 89 | ||
90 | include $(src-perf)/config/utilities.mak | 90 | include $(src-perf)/config/utilities.mak |
91 | 91 | ||
92 | ifeq ($(call get-executable,$(FLEX)),) | 92 | ifeq ($(call get-executable,$(FLEX)),) |
93 | dummy := $(error Error: $(FLEX) is missing on this system, please install it) | 93 | dummy := $(error Error: $(FLEX) is missing on this system, please install it) |
94 | endif | 94 | endif |
95 | 95 | ||
96 | ifeq ($(call get-executable,$(BISON)),) | 96 | ifeq ($(call get-executable,$(BISON)),) |
97 | dummy := $(error Error: $(BISON) is missing on this system, please install it) | 97 | dummy := $(error Error: $(BISON) is missing on this system, please install it) |
98 | endif | 98 | endif |
99 | 99 | ||
100 | # Treat warnings as errors unless directed not to | 100 | # Treat warnings as errors unless directed not to |
101 | ifneq ($(WERROR),0) | 101 | ifneq ($(WERROR),0) |
102 | CFLAGS += -Werror | 102 | CFLAGS += -Werror |
103 | endif | 103 | endif |
104 | 104 | ||
105 | ifndef DEBUG | 105 | ifndef DEBUG |
106 | DEBUG := 0 | 106 | DEBUG := 0 |
107 | endif | 107 | endif |
108 | 108 | ||
109 | ifeq ($(DEBUG),0) | 109 | ifeq ($(DEBUG),0) |
110 | CFLAGS += -O6 | 110 | CFLAGS += -O6 |
111 | endif | 111 | endif |
112 | 112 | ||
113 | ifdef PARSER_DEBUG | 113 | ifdef PARSER_DEBUG |
114 | PARSER_DEBUG_BISON := -t | 114 | PARSER_DEBUG_BISON := -t |
115 | PARSER_DEBUG_FLEX := -d | 115 | PARSER_DEBUG_FLEX := -d |
116 | CFLAGS += -DPARSER_DEBUG | 116 | CFLAGS += -DPARSER_DEBUG |
117 | endif | 117 | endif |
118 | 118 | ||
119 | ifndef NO_LIBPYTHON | 119 | ifndef NO_LIBPYTHON |
120 | # Try different combinations to accommodate systems that only have | 120 | # Try different combinations to accommodate systems that only have |
121 | # python[2][-config] in weird combinations but always preferring | 121 | # python[2][-config] in weird combinations but always preferring |
122 | # python2 and python2-config as per pep-0394. If we catch a | 122 | # python2 and python2-config as per pep-0394. If we catch a |
123 | # python[-config] in version 3, the version check will kill it. | 123 | # python[-config] in version 3, the version check will kill it. |
124 | PYTHON2 := $(if $(call get-executable,python2),python2,python) | 124 | PYTHON2 := $(if $(call get-executable,python2),python2,python) |
125 | override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2)) | 125 | override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2)) |
126 | PYTHON2_CONFIG := \ | 126 | PYTHON2_CONFIG := \ |
127 | $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config) | 127 | $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config) |
128 | override PYTHON_CONFIG := \ | 128 | override PYTHON_CONFIG := \ |
129 | $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG)) | 129 | $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG)) |
130 | 130 | ||
131 | PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) | 131 | PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) |
132 | 132 | ||
133 | PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) | 133 | PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) |
134 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | 134 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) |
135 | 135 | ||
136 | FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) | 136 | FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) |
137 | FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS) | 137 | FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS) |
138 | FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS) | 138 | FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS) |
139 | FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) | 139 | FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) |
140 | endif | 140 | endif |
141 | 141 | ||
142 | CFLAGS += -fno-omit-frame-pointer | 142 | CFLAGS += -fno-omit-frame-pointer |
143 | CFLAGS += -ggdb3 | 143 | CFLAGS += -ggdb3 |
144 | CFLAGS += -funwind-tables | 144 | CFLAGS += -funwind-tables |
145 | CFLAGS += -Wall | 145 | CFLAGS += -Wall |
146 | CFLAGS += -Wextra | 146 | CFLAGS += -Wextra |
147 | CFLAGS += -std=gnu99 | 147 | CFLAGS += -std=gnu99 |
148 | 148 | ||
149 | # Enforce a non-executable stack, as we may regress (again) in the future by | 149 | # Enforce a non-executable stack, as we may regress (again) in the future by |
150 | # adding assembler files missing the .GNU-stack linker note. | 150 | # adding assembler files missing the .GNU-stack linker note. |
151 | LDFLAGS += -Wl,-z,noexecstack | 151 | LDFLAGS += -Wl,-z,noexecstack |
152 | 152 | ||
153 | EXTLIBS = -lpthread -lrt -lm -ldl | 153 | EXTLIBS = -lpthread -lrt -lm -ldl |
154 | 154 | ||
155 | ifneq ($(OUTPUT),) | 155 | ifneq ($(OUTPUT),) |
156 | OUTPUT_FEATURES = $(OUTPUT)config/feature-checks/ | 156 | OUTPUT_FEATURES = $(OUTPUT)config/feature-checks/ |
157 | $(shell mkdir -p $(OUTPUT_FEATURES)) | 157 | $(shell mkdir -p $(OUTPUT_FEATURES)) |
158 | endif | 158 | endif |
159 | 159 | ||
160 | feature_check = $(eval $(feature_check_code)) | 160 | feature_check = $(eval $(feature_check_code)) |
161 | define feature_check_code | 161 | define feature_check_code |
162 | feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) | 162 | feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) |
163 | endef | 163 | endef |
164 | 164 | ||
165 | feature_set = $(eval $(feature_set_code)) | 165 | feature_set = $(eval $(feature_set_code)) |
166 | define feature_set_code | 166 | define feature_set_code |
167 | feature-$(1) := 1 | 167 | feature-$(1) := 1 |
168 | endef | 168 | endef |
169 | 169 | ||
170 | # | 170 | # |
171 | # Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output: | 171 | # Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output: |
172 | # | 172 | # |
173 | 173 | ||
174 | # | 174 | # |
175 | # Note that this is not a complete list of all feature tests, just | 175 | # Note that this is not a complete list of all feature tests, just |
176 | # those that are typically built on a fully configured system. | 176 | # those that are typically built on a fully configured system. |
177 | # | 177 | # |
178 | # [ Feature tests not mentioned here have to be built explicitly in | 178 | # [ Feature tests not mentioned here have to be built explicitly in |
179 | # the rule that uses them - an example for that is the 'bionic' | 179 | # the rule that uses them - an example for that is the 'bionic' |
180 | # feature check. ] | 180 | # feature check. ] |
181 | # | 181 | # |
182 | CORE_FEATURE_TESTS = \ | 182 | CORE_FEATURE_TESTS = \ |
183 | backtrace \ | 183 | backtrace \ |
184 | dwarf \ | 184 | dwarf \ |
185 | fortify-source \ | 185 | fortify-source \ |
186 | sync-compare-and-swap \ | 186 | sync-compare-and-swap \ |
187 | glibc \ | 187 | glibc \ |
188 | gtk2 \ | 188 | gtk2 \ |
189 | gtk2-infobar \ | 189 | gtk2-infobar \ |
190 | libaudit \ | 190 | libaudit \ |
191 | libbfd \ | 191 | libbfd \ |
192 | libelf \ | 192 | libelf \ |
193 | libelf-getphdrnum \ | 193 | libelf-getphdrnum \ |
194 | libelf-mmap \ | 194 | libelf-mmap \ |
195 | libnuma \ | 195 | libnuma \ |
196 | libperl \ | 196 | libperl \ |
197 | libpython \ | 197 | libpython \ |
198 | libpython-version \ | 198 | libpython-version \ |
199 | libslang \ | 199 | libslang \ |
200 | libunwind \ | 200 | libunwind \ |
201 | stackprotector-all \ | 201 | stackprotector-all \ |
202 | timerfd \ | 202 | timerfd \ |
203 | libdw-dwarf-unwind \ | 203 | libdw-dwarf-unwind \ |
204 | zlib | 204 | zlib |
205 | 205 | ||
206 | LIB_FEATURE_TESTS = \ | 206 | LIB_FEATURE_TESTS = \ |
207 | dwarf \ | 207 | dwarf \ |
208 | glibc \ | 208 | glibc \ |
209 | gtk2 \ | 209 | gtk2 \ |
210 | libaudit \ | 210 | libaudit \ |
211 | libbfd \ | 211 | libbfd \ |
212 | libelf \ | 212 | libelf \ |
213 | libnuma \ | 213 | libnuma \ |
214 | libperl \ | 214 | libperl \ |
215 | libpython \ | 215 | libpython \ |
216 | libslang \ | 216 | libslang \ |
217 | libunwind \ | 217 | libunwind \ |
218 | libdw-dwarf-unwind \ | 218 | libdw-dwarf-unwind \ |
219 | zlib | 219 | zlib |
220 | 220 | ||
221 | VF_FEATURE_TESTS = \ | 221 | VF_FEATURE_TESTS = \ |
222 | backtrace \ | 222 | backtrace \ |
223 | fortify-source \ | 223 | fortify-source \ |
224 | sync-compare-and-swap \ | 224 | sync-compare-and-swap \ |
225 | gtk2-infobar \ | 225 | gtk2-infobar \ |
226 | libelf-getphdrnum \ | 226 | libelf-getphdrnum \ |
227 | libelf-mmap \ | 227 | libelf-mmap \ |
228 | libpython-version \ | 228 | libpython-version \ |
229 | stackprotector-all \ | 229 | stackprotector-all \ |
230 | timerfd \ | 230 | timerfd \ |
231 | libunwind-debug-frame \ | 231 | libunwind-debug-frame \ |
232 | bionic \ | 232 | bionic \ |
233 | liberty \ | 233 | liberty \ |
234 | liberty-z \ | 234 | liberty-z \ |
235 | cplus-demangle \ | 235 | cplus-demangle \ |
236 | compile-32 \ | 236 | compile-32 \ |
237 | compile-x32 | 237 | compile-x32 |
238 | 238 | ||
239 | # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features. | 239 | # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features. |
240 | # If in the future we need per-feature checks/flags for features not | 240 | # If in the future we need per-feature checks/flags for features not |
241 | # mentioned in this list we need to refactor this ;-). | 241 | # mentioned in this list we need to refactor this ;-). |
242 | set_test_all_flags = $(eval $(set_test_all_flags_code)) | 242 | set_test_all_flags = $(eval $(set_test_all_flags_code)) |
243 | define set_test_all_flags_code | 243 | define set_test_all_flags_code |
244 | FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1)) | 244 | FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1)) |
245 | FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1)) | 245 | FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1)) |
246 | endef | 246 | endef |
247 | 247 | ||
248 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat))) | 248 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat))) |
249 | 249 | ||
250 | # | 250 | # |
251 | # Special fast-path for the 'all features are available' case: | 251 | # Special fast-path for the 'all features are available' case: |
252 | # | 252 | # |
253 | $(call feature_check,all,$(MSG)) | 253 | $(call feature_check,all,$(MSG)) |
254 | 254 | ||
255 | # | 255 | # |
256 | # Just in case the build freshly failed, make sure we print the | 256 | # Just in case the build freshly failed, make sure we print the |
257 | # feature matrix: | 257 | # feature matrix: |
258 | # | 258 | # |
259 | ifeq ($(feature-all), 1) | 259 | ifeq ($(feature-all), 1) |
260 | # | 260 | # |
261 | # test-all.c passed - just set all the core feature flags to 1: | 261 | # test-all.c passed - just set all the core feature flags to 1: |
262 | # | 262 | # |
263 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) | 263 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) |
264 | else | 264 | else |
265 | $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(addsuffix .bin,$(CORE_FEATURE_TESTS)) >/dev/null 2>&1) | 265 | $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(addsuffix .bin,$(CORE_FEATURE_TESTS)) >/dev/null 2>&1) |
266 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) | 266 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) |
267 | endif | 267 | endif |
268 | 268 | ||
269 | ifeq ($(feature-stackprotector-all), 1) | 269 | ifeq ($(feature-stackprotector-all), 1) |
270 | CFLAGS += -fstack-protector-all | 270 | CFLAGS += -fstack-protector-all |
271 | endif | 271 | endif |
272 | 272 | ||
273 | ifeq ($(DEBUG),0) | 273 | ifeq ($(DEBUG),0) |
274 | ifeq ($(feature-fortify-source), 1) | 274 | ifeq ($(feature-fortify-source), 1) |
275 | CFLAGS += -D_FORTIFY_SOURCE=2 | 275 | CFLAGS += -D_FORTIFY_SOURCE=2 |
276 | endif | 276 | endif |
277 | endif | 277 | endif |
278 | 278 | ||
279 | CFLAGS += -I$(src-perf)/util/include | 279 | CFLAGS += -I$(src-perf)/util/include |
280 | CFLAGS += -I$(src-perf)/arch/$(ARCH)/include | 280 | CFLAGS += -I$(src-perf)/arch/$(ARCH)/include |
281 | CFLAGS += -I$(srctree)/tools/include/ | 281 | CFLAGS += -I$(srctree)/tools/include/ |
282 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi | 282 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi |
283 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include | 283 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include |
284 | CFLAGS += -I$(srctree)/include/uapi | 284 | CFLAGS += -I$(srctree)/include/uapi |
285 | CFLAGS += -I$(srctree)/include | 285 | CFLAGS += -I$(srctree)/include |
286 | 286 | ||
287 | # $(obj-perf) for generated common-cmds.h | 287 | # $(obj-perf) for generated common-cmds.h |
288 | # $(obj-perf)/util for generated bison/flex headers | 288 | # $(obj-perf)/util for generated bison/flex headers |
289 | ifneq ($(OUTPUT),) | 289 | ifneq ($(OUTPUT),) |
290 | CFLAGS += -I$(obj-perf)/util | 290 | CFLAGS += -I$(obj-perf)/util |
291 | CFLAGS += -I$(obj-perf) | 291 | CFLAGS += -I$(obj-perf) |
292 | endif | 292 | endif |
293 | 293 | ||
294 | CFLAGS += -I$(src-perf)/util | 294 | CFLAGS += -I$(src-perf)/util |
295 | CFLAGS += -I$(src-perf) | 295 | CFLAGS += -I$(src-perf) |
296 | CFLAGS += -I$(LIB_INCLUDE) | 296 | CFLAGS += -I$(LIB_INCLUDE) |
297 | 297 | ||
298 | CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | 298 | CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE |
299 | 299 | ||
300 | ifeq ($(feature-sync-compare-and-swap), 1) | 300 | ifeq ($(feature-sync-compare-and-swap), 1) |
301 | CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT | 301 | CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT |
302 | endif | 302 | endif |
303 | 303 | ||
304 | ifndef NO_BIONIC | 304 | ifndef NO_BIONIC |
305 | $(call feature_check,bionic) | 305 | $(call feature_check,bionic) |
306 | ifeq ($(feature-bionic), 1) | 306 | ifeq ($(feature-bionic), 1) |
307 | BIONIC := 1 | 307 | BIONIC := 1 |
308 | EXTLIBS := $(filter-out -lrt,$(EXTLIBS)) | 308 | EXTLIBS := $(filter-out -lrt,$(EXTLIBS)) |
309 | EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) | 309 | EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) |
310 | endif | 310 | endif |
311 | endif | 311 | endif |
312 | 312 | ||
313 | ifdef NO_LIBELF | 313 | ifdef NO_LIBELF |
314 | NO_DWARF := 1 | 314 | NO_DWARF := 1 |
315 | NO_DEMANGLE := 1 | 315 | NO_DEMANGLE := 1 |
316 | NO_LIBUNWIND := 1 | 316 | NO_LIBUNWIND := 1 |
317 | NO_LIBDW_DWARF_UNWIND := 1 | 317 | NO_LIBDW_DWARF_UNWIND := 1 |
318 | else | 318 | else |
319 | ifeq ($(feature-libelf), 0) | 319 | ifeq ($(feature-libelf), 0) |
320 | ifeq ($(feature-glibc), 1) | 320 | ifeq ($(feature-glibc), 1) |
321 | LIBC_SUPPORT := 1 | 321 | LIBC_SUPPORT := 1 |
322 | endif | 322 | endif |
323 | ifeq ($(BIONIC),1) | 323 | ifeq ($(BIONIC),1) |
324 | LIBC_SUPPORT := 1 | 324 | LIBC_SUPPORT := 1 |
325 | endif | 325 | endif |
326 | ifeq ($(LIBC_SUPPORT),1) | 326 | ifeq ($(LIBC_SUPPORT),1) |
327 | msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev); | 327 | msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev); |
328 | 328 | ||
329 | NO_LIBELF := 1 | 329 | NO_LIBELF := 1 |
330 | NO_DWARF := 1 | 330 | NO_DWARF := 1 |
331 | NO_DEMANGLE := 1 | 331 | NO_DEMANGLE := 1 |
332 | NO_LIBUNWIND := 1 | 332 | NO_LIBUNWIND := 1 |
333 | NO_LIBDW_DWARF_UNWIND := 1 | 333 | NO_LIBDW_DWARF_UNWIND := 1 |
334 | else | 334 | else |
335 | ifneq ($(filter s% -static%,$(LDFLAGS),),) | 335 | ifneq ($(filter s% -static%,$(LDFLAGS),),) |
336 | msg := $(error No static glibc found, please install glibc-static); | 336 | msg := $(error No static glibc found, please install glibc-static); |
337 | else | 337 | else |
338 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]); | 338 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]); |
339 | endif | 339 | endif |
340 | endif | 340 | endif |
341 | else | 341 | else |
342 | ifndef NO_LIBDW_DWARF_UNWIND | 342 | ifndef NO_LIBDW_DWARF_UNWIND |
343 | ifneq ($(feature-libdw-dwarf-unwind),1) | 343 | ifneq ($(feature-libdw-dwarf-unwind),1) |
344 | NO_LIBDW_DWARF_UNWIND := 1 | 344 | NO_LIBDW_DWARF_UNWIND := 1 |
345 | msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR); | 345 | msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR); |
346 | endif | 346 | endif |
347 | endif | 347 | endif |
348 | ifneq ($(feature-dwarf), 1) | 348 | ifneq ($(feature-dwarf), 1) |
349 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | 349 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); |
350 | NO_DWARF := 1 | 350 | NO_DWARF := 1 |
351 | endif # Dwarf support | 351 | endif # Dwarf support |
352 | endif # libelf support | 352 | endif # libelf support |
353 | endif # NO_LIBELF | 353 | endif # NO_LIBELF |
354 | 354 | ||
355 | ifndef NO_LIBELF | 355 | ifndef NO_LIBELF |
356 | CFLAGS += -DHAVE_LIBELF_SUPPORT | 356 | CFLAGS += -DHAVE_LIBELF_SUPPORT |
357 | EXTLIBS += -lelf | 357 | EXTLIBS += -lelf |
358 | 358 | ||
359 | ifeq ($(feature-libelf-mmap), 1) | 359 | ifeq ($(feature-libelf-mmap), 1) |
360 | CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT | 360 | CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT |
361 | endif | 361 | endif |
362 | 362 | ||
363 | ifeq ($(feature-libelf-getphdrnum), 1) | 363 | ifeq ($(feature-libelf-getphdrnum), 1) |
364 | CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT | 364 | CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT |
365 | endif | 365 | endif |
366 | 366 | ||
367 | # include ARCH specific config | 367 | # include ARCH specific config |
368 | -include $(src-perf)/arch/$(ARCH)/Makefile | 368 | -include $(src-perf)/arch/$(ARCH)/Makefile |
369 | 369 | ||
370 | ifndef NO_DWARF | 370 | ifndef NO_DWARF |
371 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | 371 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) |
372 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | 372 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); |
373 | NO_DWARF := 1 | 373 | NO_DWARF := 1 |
374 | else | 374 | else |
375 | CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS) | 375 | CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS) |
376 | LDFLAGS += $(LIBDW_LDFLAGS) | 376 | LDFLAGS += $(LIBDW_LDFLAGS) |
377 | EXTLIBS += -ldw | 377 | EXTLIBS += -ldw |
378 | endif # PERF_HAVE_DWARF_REGS | 378 | endif # PERF_HAVE_DWARF_REGS |
379 | endif # NO_DWARF | 379 | endif # NO_DWARF |
380 | endif # NO_LIBELF | 380 | endif # NO_LIBELF |
381 | 381 | ||
382 | ifeq ($(ARCH),powerpc) | 382 | ifeq ($(ARCH),powerpc) |
383 | ifndef NO_DWARF | 383 | ifndef NO_DWARF |
384 | CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX | 384 | CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX |
385 | endif | 385 | endif |
386 | endif | 386 | endif |
387 | 387 | ||
388 | ifndef NO_LIBUNWIND | 388 | ifndef NO_LIBUNWIND |
389 | ifneq ($(feature-libunwind), 1) | 389 | ifneq ($(feature-libunwind), 1) |
390 | msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); | 390 | msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); |
391 | NO_LIBUNWIND := 1 | 391 | NO_LIBUNWIND := 1 |
392 | endif | 392 | endif |
393 | endif | 393 | endif |
394 | 394 | ||
395 | dwarf-post-unwind := 1 | 395 | dwarf-post-unwind := 1 |
396 | dwarf-post-unwind-text := BUG | 396 | dwarf-post-unwind-text := BUG |
397 | 397 | ||
398 | # setup DWARF post unwinder | 398 | # setup DWARF post unwinder |
399 | ifdef NO_LIBUNWIND | 399 | ifdef NO_LIBUNWIND |
400 | ifdef NO_LIBDW_DWARF_UNWIND | 400 | ifdef NO_LIBDW_DWARF_UNWIND |
401 | msg := $(warning Disabling post unwind, no support found.); | 401 | msg := $(warning Disabling post unwind, no support found.); |
402 | dwarf-post-unwind := 0 | 402 | dwarf-post-unwind := 0 |
403 | else | 403 | else |
404 | dwarf-post-unwind-text := libdw | 404 | dwarf-post-unwind-text := libdw |
405 | endif | 405 | endif |
406 | else | 406 | else |
407 | dwarf-post-unwind-text := libunwind | 407 | dwarf-post-unwind-text := libunwind |
408 | # Enable libunwind support by default. | 408 | # Enable libunwind support by default. |
409 | ifndef NO_LIBDW_DWARF_UNWIND | 409 | ifndef NO_LIBDW_DWARF_UNWIND |
410 | NO_LIBDW_DWARF_UNWIND := 1 | 410 | NO_LIBDW_DWARF_UNWIND := 1 |
411 | endif | 411 | endif |
412 | endif | 412 | endif |
413 | 413 | ||
414 | ifeq ($(dwarf-post-unwind),1) | 414 | ifeq ($(dwarf-post-unwind),1) |
415 | CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT | 415 | CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT |
416 | else | 416 | else |
417 | NO_DWARF_UNWIND := 1 | 417 | NO_DWARF_UNWIND := 1 |
418 | endif | 418 | endif |
419 | 419 | ||
420 | ifndef NO_LIBUNWIND | 420 | ifndef NO_LIBUNWIND |
421 | ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) | 421 | ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) |
422 | $(call feature_check,libunwind-debug-frame) | 422 | $(call feature_check,libunwind-debug-frame) |
423 | ifneq ($(feature-libunwind-debug-frame), 1) | 423 | ifneq ($(feature-libunwind-debug-frame), 1) |
424 | msg := $(warning No debug_frame support found in libunwind); | 424 | msg := $(warning No debug_frame support found in libunwind); |
425 | CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME | 425 | CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME |
426 | endif | 426 | endif |
427 | else | 427 | else |
428 | # non-ARM has no dwarf_find_debug_frame() function: | 428 | # non-ARM has no dwarf_find_debug_frame() function: |
429 | CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME | 429 | CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME |
430 | endif | 430 | endif |
431 | CFLAGS += -DHAVE_LIBUNWIND_SUPPORT | 431 | CFLAGS += -DHAVE_LIBUNWIND_SUPPORT |
432 | EXTLIBS += $(LIBUNWIND_LIBS) | 432 | EXTLIBS += $(LIBUNWIND_LIBS) |
433 | CFLAGS += $(LIBUNWIND_CFLAGS) | 433 | CFLAGS += $(LIBUNWIND_CFLAGS) |
434 | LDFLAGS += $(LIBUNWIND_LDFLAGS) | 434 | LDFLAGS += $(LIBUNWIND_LDFLAGS) |
435 | endif | 435 | endif |
436 | 436 | ||
437 | ifndef NO_LIBAUDIT | 437 | ifndef NO_LIBAUDIT |
438 | ifneq ($(feature-libaudit), 1) | 438 | ifneq ($(feature-libaudit), 1) |
439 | msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); | 439 | msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); |
440 | NO_LIBAUDIT := 1 | 440 | NO_LIBAUDIT := 1 |
441 | else | 441 | else |
442 | CFLAGS += -DHAVE_LIBAUDIT_SUPPORT | 442 | CFLAGS += -DHAVE_LIBAUDIT_SUPPORT |
443 | EXTLIBS += -laudit | 443 | EXTLIBS += -laudit |
444 | endif | 444 | endif |
445 | endif | 445 | endif |
446 | 446 | ||
447 | ifdef NO_NEWT | 447 | ifdef NO_NEWT |
448 | NO_SLANG=1 | 448 | NO_SLANG=1 |
449 | endif | 449 | endif |
450 | 450 | ||
451 | ifndef NO_SLANG | 451 | ifndef NO_SLANG |
452 | ifneq ($(feature-libslang), 1) | 452 | ifneq ($(feature-libslang), 1) |
453 | msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); | 453 | msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); |
454 | NO_SLANG := 1 | 454 | NO_SLANG := 1 |
455 | else | 455 | else |
456 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h | 456 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h |
457 | CFLAGS += -I/usr/include/slang | 457 | CFLAGS += -I/usr/include/slang |
458 | CFLAGS += -DHAVE_SLANG_SUPPORT | 458 | CFLAGS += -DHAVE_SLANG_SUPPORT |
459 | EXTLIBS += -lslang | 459 | EXTLIBS += -lslang |
460 | endif | 460 | endif |
461 | endif | 461 | endif |
462 | 462 | ||
463 | ifndef NO_GTK2 | 463 | ifndef NO_GTK2 |
464 | FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) | 464 | FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) |
465 | ifneq ($(feature-gtk2), 1) | 465 | ifneq ($(feature-gtk2), 1) |
466 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); | 466 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); |
467 | NO_GTK2 := 1 | 467 | NO_GTK2 := 1 |
468 | else | 468 | else |
469 | ifeq ($(feature-gtk2-infobar), 1) | 469 | ifeq ($(feature-gtk2-infobar), 1) |
470 | GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT | 470 | GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT |
471 | endif | 471 | endif |
472 | CFLAGS += -DHAVE_GTK2_SUPPORT | 472 | CFLAGS += -DHAVE_GTK2_SUPPORT |
473 | GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null) | 473 | GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null) |
474 | GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null) | 474 | GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null) |
475 | EXTLIBS += -ldl | 475 | EXTLIBS += -ldl |
476 | endif | 476 | endif |
477 | endif | 477 | endif |
478 | 478 | ||
479 | grep-libs = $(filter -l%,$(1)) | 479 | grep-libs = $(filter -l%,$(1)) |
480 | strip-libs = $(filter-out -l%,$(1)) | 480 | strip-libs = $(filter-out -l%,$(1)) |
481 | 481 | ||
482 | ifdef NO_LIBPERL | 482 | ifdef NO_LIBPERL |
483 | CFLAGS += -DNO_LIBPERL | 483 | CFLAGS += -DNO_LIBPERL |
484 | else | 484 | else |
485 | PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) | 485 | PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) |
486 | PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) | 486 | PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) |
487 | PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) | 487 | PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) |
488 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | 488 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` |
489 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) | 489 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) |
490 | 490 | ||
491 | ifneq ($(feature-libperl), 1) | 491 | ifneq ($(feature-libperl), 1) |
492 | CFLAGS += -DNO_LIBPERL | 492 | CFLAGS += -DNO_LIBPERL |
493 | NO_LIBPERL := 1 | 493 | NO_LIBPERL := 1 |
494 | msg := $(warning Missing perl devel files. Disabling perl scripting support, consider installing perl-ExtUtils-Embed); | 494 | msg := $(warning Missing perl devel files. Disabling perl scripting support, consider installing perl-ExtUtils-Embed); |
495 | else | 495 | else |
496 | LDFLAGS += $(PERL_EMBED_LDFLAGS) | 496 | LDFLAGS += $(PERL_EMBED_LDFLAGS) |
497 | EXTLIBS += $(PERL_EMBED_LIBADD) | 497 | EXTLIBS += $(PERL_EMBED_LIBADD) |
498 | endif | 498 | endif |
499 | endif | 499 | endif |
500 | 500 | ||
501 | ifeq ($(feature-timerfd), 1) | 501 | ifeq ($(feature-timerfd), 1) |
502 | CFLAGS += -DHAVE_TIMERFD_SUPPORT | 502 | CFLAGS += -DHAVE_TIMERFD_SUPPORT |
503 | else | 503 | else |
504 | msg := $(warning No timerfd support. Disables 'perf kvm stat live'); | 504 | msg := $(warning No timerfd support. Disables 'perf kvm stat live'); |
505 | endif | 505 | endif |
506 | 506 | ||
507 | disable-python = $(eval $(disable-python_code)) | 507 | disable-python = $(eval $(disable-python_code)) |
508 | define disable-python_code | 508 | define disable-python_code |
509 | CFLAGS += -DNO_LIBPYTHON | 509 | CFLAGS += -DNO_LIBPYTHON |
510 | $(if $(1),$(warning No $(1) was found)) | 510 | $(if $(1),$(warning No $(1) was found)) |
511 | $(warning Python support will not be built) | 511 | $(warning Python support will not be built) |
512 | NO_LIBPYTHON := 1 | 512 | NO_LIBPYTHON := 1 |
513 | endef | 513 | endef |
514 | 514 | ||
515 | ifdef NO_LIBPYTHON | 515 | ifdef NO_LIBPYTHON |
516 | $(call disable-python) | 516 | $(call disable-python) |
517 | else | 517 | else |
518 | 518 | ||
519 | ifndef PYTHON | 519 | ifndef PYTHON |
520 | $(call disable-python,python interpreter) | 520 | $(call disable-python,python interpreter) |
521 | else | 521 | else |
522 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 522 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) |
523 | 523 | ||
524 | ifndef PYTHON_CONFIG | 524 | ifndef PYTHON_CONFIG |
525 | $(call disable-python,python-config tool) | 525 | $(call disable-python,python-config tool) |
526 | else | 526 | else |
527 | 527 | ||
528 | PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) | 528 | PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) |
529 | 529 | ||
530 | PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) | 530 | PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) |
531 | PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) | 531 | PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) |
532 | PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) | 532 | PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) |
533 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | 533 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) |
534 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | 534 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) |
535 | 535 | ||
536 | ifneq ($(feature-libpython), 1) | 536 | ifneq ($(feature-libpython), 1) |
537 | $(call disable-python,Python.h (for Python 2.x)) | 537 | $(call disable-python,Python.h (for Python 2.x)) |
538 | else | 538 | else |
539 | 539 | ||
540 | ifneq ($(feature-libpython-version), 1) | 540 | ifneq ($(feature-libpython-version), 1) |
541 | $(warning Python 3 is not yet supported; please set) | 541 | $(warning Python 3 is not yet supported; please set) |
542 | $(warning PYTHON and/or PYTHON_CONFIG appropriately.) | 542 | $(warning PYTHON and/or PYTHON_CONFIG appropriately.) |
543 | $(warning If you also have Python 2 installed, then) | 543 | $(warning If you also have Python 2 installed, then) |
544 | $(warning try something like:) | 544 | $(warning try something like:) |
545 | $(warning $(and ,)) | 545 | $(warning $(and ,)) |
546 | $(warning $(and ,) make PYTHON=python2) | 546 | $(warning $(and ,) make PYTHON=python2) |
547 | $(warning $(and ,)) | 547 | $(warning $(and ,)) |
548 | $(warning Otherwise, disable Python support entirely:) | 548 | $(warning Otherwise, disable Python support entirely:) |
549 | $(warning $(and ,)) | 549 | $(warning $(and ,)) |
550 | $(warning $(and ,) make NO_LIBPYTHON=1) | 550 | $(warning $(and ,) make NO_LIBPYTHON=1) |
551 | $(warning $(and ,)) | 551 | $(warning $(and ,)) |
552 | $(error $(and ,)) | 552 | $(error $(and ,)) |
553 | else | 553 | else |
554 | LDFLAGS += $(PYTHON_EMBED_LDFLAGS) | 554 | LDFLAGS += $(PYTHON_EMBED_LDFLAGS) |
555 | EXTLIBS += $(PYTHON_EMBED_LIBADD) | 555 | EXTLIBS += $(PYTHON_EMBED_LIBADD) |
556 | LANG_BINDINGS += $(obj-perf)python/perf.so | 556 | LANG_BINDINGS += $(obj-perf)python/perf.so |
557 | endif | 557 | endif |
558 | endif | 558 | endif |
559 | endif | 559 | endif |
560 | endif | 560 | endif |
561 | endif | 561 | endif |
562 | 562 | ||
563 | ifeq ($(feature-libbfd), 1) | 563 | ifeq ($(feature-libbfd), 1) |
564 | EXTLIBS += -lbfd | 564 | EXTLIBS += -lbfd |
565 | 565 | ||
566 | # call all detections now so we get correct | 566 | # call all detections now so we get correct |
567 | # status in VF output | 567 | # status in VF output |
568 | $(call feature_check,liberty) | 568 | $(call feature_check,liberty) |
569 | $(call feature_check,liberty-z) | 569 | $(call feature_check,liberty-z) |
570 | $(call feature_check,cplus-demangle) | 570 | $(call feature_check,cplus-demangle) |
571 | 571 | ||
572 | ifeq ($(feature-liberty), 1) | 572 | ifeq ($(feature-liberty), 1) |
573 | EXTLIBS += -liberty | 573 | EXTLIBS += -liberty |
574 | else | 574 | else |
575 | ifeq ($(feature-liberty-z), 1) | 575 | ifeq ($(feature-liberty-z), 1) |
576 | EXTLIBS += -liberty -lz | 576 | EXTLIBS += -liberty -lz |
577 | endif | 577 | endif |
578 | endif | 578 | endif |
579 | endif | 579 | endif |
580 | 580 | ||
581 | ifdef NO_DEMANGLE | 581 | ifdef NO_DEMANGLE |
582 | CFLAGS += -DNO_DEMANGLE | 582 | CFLAGS += -DNO_DEMANGLE |
583 | else | 583 | else |
584 | ifdef HAVE_CPLUS_DEMANGLE_SUPPORT | 584 | ifdef HAVE_CPLUS_DEMANGLE_SUPPORT |
585 | EXTLIBS += -liberty | 585 | EXTLIBS += -liberty |
586 | CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT | 586 | CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT |
587 | else | 587 | else |
588 | ifneq ($(feature-libbfd), 1) | 588 | ifneq ($(feature-libbfd), 1) |
589 | ifneq ($(feature-liberty), 1) | 589 | ifneq ($(feature-liberty), 1) |
590 | ifneq ($(feature-liberty-z), 1) | 590 | ifneq ($(feature-liberty-z), 1) |
591 | # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT | 591 | # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT |
592 | # or any of 'bfd iberty z' trinity | 592 | # or any of 'bfd iberty z' trinity |
593 | ifeq ($(feature-cplus-demangle), 1) | 593 | ifeq ($(feature-cplus-demangle), 1) |
594 | EXTLIBS += -liberty | 594 | EXTLIBS += -liberty |
595 | CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT | 595 | CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT |
596 | else | 596 | else |
597 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) | 597 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) |
598 | CFLAGS += -DNO_DEMANGLE | 598 | CFLAGS += -DNO_DEMANGLE |
599 | endif | 599 | endif |
600 | endif | 600 | endif |
601 | endif | 601 | endif |
602 | endif | 602 | endif |
603 | endif | 603 | endif |
604 | endif | 604 | endif |
605 | 605 | ||
606 | ifneq ($(filter -lbfd,$(EXTLIBS)),) | 606 | ifneq ($(filter -lbfd,$(EXTLIBS)),) |
607 | CFLAGS += -DHAVE_LIBBFD_SUPPORT | 607 | CFLAGS += -DHAVE_LIBBFD_SUPPORT |
608 | endif | 608 | endif |
609 | 609 | ||
610 | ifndef NO_ZLIB | 610 | ifndef NO_ZLIB |
611 | ifeq ($(feature-zlib), 1) | 611 | ifeq ($(feature-zlib), 1) |
612 | CFLAGS += -DHAVE_ZLIB_SUPPORT | 612 | CFLAGS += -DHAVE_ZLIB_SUPPORT |
613 | EXTLIBS += -lz | 613 | EXTLIBS += -lz |
614 | else | 614 | else |
615 | NO_ZLIB := 1 | 615 | NO_ZLIB := 1 |
616 | endif | 616 | endif |
617 | endif | 617 | endif |
618 | 618 | ||
619 | ifndef NO_BACKTRACE | 619 | ifndef NO_BACKTRACE |
620 | ifeq ($(feature-backtrace), 1) | 620 | ifeq ($(feature-backtrace), 1) |
621 | CFLAGS += -DHAVE_BACKTRACE_SUPPORT | 621 | CFLAGS += -DHAVE_BACKTRACE_SUPPORT |
622 | endif | 622 | endif |
623 | endif | 623 | endif |
624 | 624 | ||
625 | ifndef NO_LIBNUMA | 625 | ifndef NO_LIBNUMA |
626 | ifeq ($(feature-libnuma), 0) | 626 | ifeq ($(feature-libnuma), 0) |
627 | msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev); | 627 | msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev); |
628 | NO_LIBNUMA := 1 | 628 | NO_LIBNUMA := 1 |
629 | else | 629 | else |
630 | CFLAGS += -DHAVE_LIBNUMA_SUPPORT | 630 | CFLAGS += -DHAVE_LIBNUMA_SUPPORT |
631 | EXTLIBS += -lnuma | 631 | EXTLIBS += -lnuma |
632 | endif | 632 | endif |
633 | endif | 633 | endif |
634 | 634 | ||
635 | ifdef HAVE_KVM_STAT_SUPPORT | 635 | ifdef HAVE_KVM_STAT_SUPPORT |
636 | CFLAGS += -DHAVE_KVM_STAT_SUPPORT | 636 | CFLAGS += -DHAVE_KVM_STAT_SUPPORT |
637 | endif | 637 | endif |
638 | 638 | ||
639 | ifeq (${IS_64_BIT}, 1) | 639 | ifeq (${IS_64_BIT}, 1) |
640 | ifndef NO_PERF_READ_VDSO32 | 640 | ifndef NO_PERF_READ_VDSO32 |
641 | $(call feature_check,compile-32) | 641 | $(call feature_check,compile-32) |
642 | ifeq ($(feature-compile-32), 1) | 642 | ifeq ($(feature-compile-32), 1) |
643 | CFLAGS += -DHAVE_PERF_READ_VDSO32 | 643 | CFLAGS += -DHAVE_PERF_READ_VDSO32 |
644 | else | 644 | else |
645 | NO_PERF_READ_VDSO32 := 1 | 645 | NO_PERF_READ_VDSO32 := 1 |
646 | endif | 646 | endif |
647 | endif | 647 | endif |
648 | ifneq (${IS_X86_64}, 1) | 648 | ifneq (${IS_X86_64}, 1) |
649 | NO_PERF_READ_VDSOX32 := 1 | 649 | NO_PERF_READ_VDSOX32 := 1 |
650 | endif | 650 | endif |
651 | ifndef NO_PERF_READ_VDSOX32 | 651 | ifndef NO_PERF_READ_VDSOX32 |
652 | $(call feature_check,compile-x32) | 652 | $(call feature_check,compile-x32) |
653 | ifeq ($(feature-compile-x32), 1) | 653 | ifeq ($(feature-compile-x32), 1) |
654 | CFLAGS += -DHAVE_PERF_READ_VDSOX32 | 654 | CFLAGS += -DHAVE_PERF_READ_VDSOX32 |
655 | else | 655 | else |
656 | NO_PERF_READ_VDSOX32 := 1 | 656 | NO_PERF_READ_VDSOX32 := 1 |
657 | endif | 657 | endif |
658 | endif | 658 | endif |
659 | else | 659 | else |
660 | NO_PERF_READ_VDSO32 := 1 | 660 | NO_PERF_READ_VDSO32 := 1 |
661 | NO_PERF_READ_VDSOX32 := 1 | 661 | NO_PERF_READ_VDSOX32 := 1 |
662 | endif | 662 | endif |
663 | 663 | ||
664 | # Among the variables below, these: | 664 | # Among the variables below, these: |
665 | # perfexecdir | 665 | # perfexecdir |
666 | # template_dir | 666 | # template_dir |
667 | # mandir | 667 | # mandir |
668 | # infodir | 668 | # infodir |
669 | # htmldir | 669 | # htmldir |
670 | # ETC_PERFCONFIG (but not sysconfdir) | 670 | # ETC_PERFCONFIG (but not sysconfdir) |
671 | # can be specified as a relative path some/where/else; | 671 | # can be specified as a relative path some/where/else; |
672 | # this is interpreted as relative to $(prefix) and "perf" at | 672 | # this is interpreted as relative to $(prefix) and "perf" at |
673 | # runtime figures out where they are based on the path to the executable. | 673 | # runtime figures out where they are based on the path to the executable. |
674 | # This can help installing the suite in a relocatable way. | 674 | # This can help installing the suite in a relocatable way. |
675 | 675 | ||
676 | # Make the path relative to DESTDIR, not to prefix | 676 | # Make the path relative to DESTDIR, not to prefix |
677 | ifndef DESTDIR | 677 | ifndef DESTDIR |
678 | prefix ?= $(HOME) | 678 | prefix ?= $(HOME) |
679 | endif | 679 | endif |
680 | bindir_relative = bin | 680 | bindir_relative = bin |
681 | bindir = $(prefix)/$(bindir_relative) | 681 | bindir = $(prefix)/$(bindir_relative) |
682 | mandir = share/man | 682 | mandir = share/man |
683 | infodir = share/info | 683 | infodir = share/info |
684 | perfexecdir = libexec/perf-core | 684 | perfexecdir = libexec/perf-core |
685 | sharedir = $(prefix)/share | 685 | sharedir = $(prefix)/share |
686 | template_dir = share/perf-core/templates | 686 | template_dir = share/perf-core/templates |
687 | htmldir = share/doc/perf-doc | 687 | htmldir = share/doc/perf-doc |
688 | ifeq ($(prefix),/usr) | 688 | ifeq ($(prefix),/usr) |
689 | sysconfdir = /etc | 689 | sysconfdir = /etc |
690 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig | 690 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig |
691 | else | 691 | else |
692 | sysconfdir = $(prefix)/etc | 692 | sysconfdir = $(prefix)/etc |
693 | ETC_PERFCONFIG = etc/perfconfig | 693 | ETC_PERFCONFIG = etc/perfconfig |
694 | endif | 694 | endif |
695 | ifndef lib | 695 | ifndef lib |
696 | ifeq ($(IS_X86_64),1) | 696 | ifeq ($(IS_X86_64),1) |
697 | lib = lib64 | 697 | lib = lib64 |
698 | else | 698 | else |
699 | lib = lib | 699 | lib = lib |
700 | endif | 700 | endif |
701 | endif # lib | 701 | endif # lib |
702 | libdir = $(prefix)/$(lib) | 702 | libdir = $(prefix)/$(lib) |
703 | 703 | ||
704 | # Shell quote (do not use $(call) to accommodate ancient setups); | 704 | # Shell quote (do not use $(call) to accommodate ancient setups); |
705 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) | 705 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) |
706 | DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) | 706 | DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) |
707 | bindir_SQ = $(subst ','\'',$(bindir)) | 707 | bindir_SQ = $(subst ','\'',$(bindir)) |
708 | mandir_SQ = $(subst ','\'',$(mandir)) | 708 | mandir_SQ = $(subst ','\'',$(mandir)) |
709 | infodir_SQ = $(subst ','\'',$(infodir)) | 709 | infodir_SQ = $(subst ','\'',$(infodir)) |
710 | perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) | 710 | perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) |
711 | template_dir_SQ = $(subst ','\'',$(template_dir)) | 711 | template_dir_SQ = $(subst ','\'',$(template_dir)) |
712 | htmldir_SQ = $(subst ','\'',$(htmldir)) | 712 | htmldir_SQ = $(subst ','\'',$(htmldir)) |
713 | prefix_SQ = $(subst ','\'',$(prefix)) | 713 | prefix_SQ = $(subst ','\'',$(prefix)) |
714 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) | 714 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) |
715 | libdir_SQ = $(subst ','\'',$(libdir)) | 715 | libdir_SQ = $(subst ','\'',$(libdir)) |
716 | 716 | ||
717 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) | 717 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) |
718 | perfexec_instdir = $(perfexecdir) | 718 | perfexec_instdir = $(perfexecdir) |
719 | else | 719 | else |
720 | perfexec_instdir = $(prefix)/$(perfexecdir) | 720 | perfexec_instdir = $(prefix)/$(perfexecdir) |
721 | endif | 721 | endif |
722 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | 722 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) |
723 | 723 | ||
724 | # If we install to $(HOME) we keep the traceevent default: | 724 | # If we install to $(HOME) we keep the traceevent default: |
725 | # $(HOME)/.traceevent/plugins | 725 | # $(HOME)/.traceevent/plugins |
726 | # Otherwise we install plugins into the global $(libdir). | 726 | # Otherwise we install plugins into the global $(libdir). |
727 | ifdef DESTDIR | 727 | ifdef DESTDIR |
728 | plugindir=$(libdir)/traceevent/plugins | 728 | plugindir=$(libdir)/traceevent/plugins |
729 | plugindir_SQ= $(subst ','\'',$(plugindir)) | 729 | plugindir_SQ= $(subst ','\'',$(plugindir)) |
730 | endif | 730 | endif |
731 | 731 | ||
732 | # | 732 | # |
733 | # Print the result of the feature test: | 733 | # Print the result of the feature test: |
734 | # | 734 | # |
735 | feature_print_status = $(eval $(feature_print_status_code)) $(info $(MSG)) | 735 | feature_print_status = $(eval $(feature_print_status_code)) $(info $(MSG)) |
736 | 736 | ||
737 | define feature_print_status_code | 737 | define feature_print_status_code |
738 | ifeq ($(feature-$(1)), 1) | 738 | ifeq ($(feature-$(1)), 1) |
739 | MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1)) | 739 | MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1)) |
740 | else | 740 | else |
741 | MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1)) | 741 | MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1)) |
742 | endif | 742 | endif |
743 | endef | 743 | endef |
744 | 744 | ||
745 | feature_print_var = $(eval $(feature_print_var_code)) $(info $(MSG)) | 745 | feature_print_var = $(eval $(feature_print_var_code)) $(info $(MSG)) |
746 | define feature_print_var_code | 746 | define feature_print_var_code |
747 | MSG = $(shell printf '...%30s: %s' $(1) $($(1))) | 747 | MSG = $(shell printf '...%30s: %s' $(1) $($(1))) |
748 | endef | 748 | endef |
749 | 749 | ||
750 | feature_print_text = $(eval $(feature_print_text_code)) $(info $(MSG)) | 750 | feature_print_text = $(eval $(feature_print_text_code)) $(info $(MSG)) |
751 | define feature_print_text_code | 751 | define feature_print_text_code |
752 | MSG = $(shell printf '...%30s: %s' $(1) $(2)) | 752 | MSG = $(shell printf '...%30s: %s' $(1) $(2)) |
753 | endef | 753 | endef |
754 | 754 | ||
755 | PERF_FEATURES := $(foreach feat,$(LIB_FEATURE_TESTS),feature-$(feat)($(feature-$(feat)))) | 755 | PERF_FEATURES := $(foreach feat,$(LIB_FEATURE_TESTS),feature-$(feat)($(feature-$(feat)))) |
756 | PERF_FEATURES_FILE := $(shell touch $(OUTPUT)PERF-FEATURES; cat $(OUTPUT)PERF-FEATURES) | 756 | PERF_FEATURES_FILE := $(shell touch $(OUTPUT)PERF-FEATURES; cat $(OUTPUT)PERF-FEATURES) |
757 | 757 | ||
758 | ifeq ($(dwarf-post-unwind),1) | 758 | ifeq ($(dwarf-post-unwind),1) |
759 | PERF_FEATURES += dwarf-post-unwind($(dwarf-post-unwind-text)) | 759 | PERF_FEATURES += dwarf-post-unwind($(dwarf-post-unwind-text)) |
760 | endif | 760 | endif |
761 | 761 | ||
762 | # The $(display_lib) controls the default detection message | 762 | # The $(display_lib) controls the default detection message |
763 | # output. It's set if: | 763 | # output. It's set if: |
764 | # - detected features differes from stored features from | 764 | # - detected features differes from stored features from |
765 | # last build (in PERF-FEATURES file) | 765 | # last build (in PERF-FEATURES file) |
766 | # - one of the $(LIB_FEATURE_TESTS) is not detected | 766 | # - one of the $(LIB_FEATURE_TESTS) is not detected |
767 | # - VF is enabled | 767 | # - VF is enabled |
768 | 768 | ||
769 | ifneq ("$(PERF_FEATURES)","$(PERF_FEATURES_FILE)") | 769 | ifneq ("$(PERF_FEATURES)","$(PERF_FEATURES_FILE)") |
770 | $(shell echo "$(PERF_FEATURES)" > $(OUTPUT)PERF-FEATURES) | 770 | $(shell echo "$(PERF_FEATURES)" > $(OUTPUT)PERF-FEATURES) |
771 | display_lib := 1 | 771 | display_lib := 1 |
772 | endif | 772 | endif |
773 | 773 | ||
774 | feature_check = $(eval $(feature_check_code)) | 774 | feature_check = $(eval $(feature_check_code)) |
775 | define feature_check_code | 775 | define feature_check_code |
776 | ifneq ($(feature-$(1)), 1) | 776 | ifneq ($(feature-$(1)), 1) |
777 | display_lib := 1 | 777 | display_lib := 1 |
778 | endif | 778 | endif |
779 | endef | 779 | endef |
780 | 780 | ||
781 | $(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_check,$(feat))) | 781 | $(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_check,$(feat))) |
782 | 782 | ||
783 | ifeq ($(VF),1) | 783 | ifeq ($(VF),1) |
784 | display_lib := 1 | 784 | display_lib := 1 |
785 | display_vf := 1 | 785 | display_vf := 1 |
786 | endif | 786 | endif |
787 | 787 | ||
788 | ifeq ($(display_lib),1) | 788 | ifeq ($(display_lib),1) |
789 | $(info ) | 789 | $(info ) |
790 | $(info Auto-detecting system features:) | 790 | $(info Auto-detecting system features:) |
791 | $(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_print_status,$(feat),)) | 791 | $(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_print_status,$(feat),)) |
792 | 792 | ||
793 | ifeq ($(dwarf-post-unwind),1) | 793 | ifeq ($(dwarf-post-unwind),1) |
794 | $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text)) | 794 | $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text)) |
795 | endif | 795 | endif |
796 | endif | 796 | endif |
797 | 797 | ||
798 | ifeq ($(display_vf),1) | 798 | ifeq ($(display_vf),1) |
799 | $(foreach feat,$(VF_FEATURE_TESTS),$(call feature_print_status,$(feat),)) | 799 | $(foreach feat,$(VF_FEATURE_TESTS),$(call feature_print_status,$(feat),)) |
800 | $(info ) | 800 | $(info ) |
801 | $(call feature_print_var,prefix) | 801 | $(call feature_print_var,prefix) |
802 | $(call feature_print_var,bindir) | 802 | $(call feature_print_var,bindir) |
803 | $(call feature_print_var,libdir) | 803 | $(call feature_print_var,libdir) |
804 | $(call feature_print_var,sysconfdir) | 804 | $(call feature_print_var,sysconfdir) |
805 | $(call feature_print_var,LIBUNWIND_DIR) | 805 | $(call feature_print_var,LIBUNWIND_DIR) |
806 | $(call feature_print_var,LIBDW_DIR) | 806 | $(call feature_print_var,LIBDW_DIR) |
807 | endif | 807 | endif |
808 | 808 | ||
809 | ifeq ($(display_lib),1) | 809 | ifeq ($(display_lib),1) |
810 | $(info ) | 810 | $(info ) |
811 | endif | 811 | endif |
812 | 812 |
tools/perf/config/Makefile.arch
1 | 1 | ||
2 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 2 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
3 | 3 | ||
4 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | 4 | RAW_ARCH := $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ |
5 | -e s/arm.*/arm/ -e s/sa110/arm/ \ | 5 | -e s/arm.*/arm/ -e s/sa110/arm/ \ |
6 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ | 6 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ |
7 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | 7 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ |
8 | -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ | 8 | -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ |
9 | -e s/tile.*/tile/ ) | 9 | -e s/tile.*/tile/ ) |
10 | 10 | ||
11 | # Additional ARCH settings for x86 | 11 | # Additional ARCH settings for x86 |
12 | ifeq ($(ARCH),i386) | 12 | ifeq ($(RAW_ARCH),i386) |
13 | override ARCH := x86 | 13 | ARCH ?= x86 |
14 | endif | 14 | endif |
15 | 15 | ||
16 | ifeq ($(ARCH),x86_64) | 16 | ifeq ($(RAW_ARCH),x86_64) |
17 | override ARCH := x86 | 17 | ARCH ?= x86 |
18 | IS_X86_64 := 0 | 18 | |
19 | ifeq (, $(findstring m32,$(CFLAGS))) | 19 | ifneq (, $(findstring m32,$(CFLAGS))) |
20 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) | 20 | RAW_ARCH := x86_32 |
21 | RAW_ARCH := x86_64 | ||
22 | endif | 21 | endif |
23 | endif | 22 | endif |
24 | 23 | ||
25 | ifeq (${IS_X86_64}, 1) | 24 | ARCH ?= $(RAW_ARCH) |
25 | |||
26 | LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) | ||
27 | ifeq ($(LP64), 1) | ||
26 | IS_64_BIT := 1 | 28 | IS_64_BIT := 1 |
27 | else ifeq ($(ARCH),x86) | ||
28 | IS_64_BIT := 0 | ||
29 | else | 29 | else |
tools/perf/perf-sys.h
1 | #ifndef _PERF_SYS_H | 1 | #ifndef _PERF_SYS_H |
2 | #define _PERF_SYS_H | 2 | #define _PERF_SYS_H |
3 | 3 | ||
4 | #include <unistd.h> | 4 | #include <unistd.h> |
5 | #include <sys/types.h> | 5 | #include <sys/types.h> |
6 | #include <sys/syscall.h> | 6 | #include <sys/syscall.h> |
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include <linux/perf_event.h> | 8 | #include <linux/perf_event.h> |
9 | #include <asm/unistd.h> | ||
10 | 9 | ||
11 | #if defined(__i386__) | 10 | #if defined(__i386__) |
12 | #define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") | 11 | #define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") |
13 | #define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") | 12 | #define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") |
14 | #define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") | 13 | #define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") |
15 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); | 14 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); |
16 | #define CPUINFO_PROC {"model name"} | 15 | #define CPUINFO_PROC {"model name"} |
17 | #ifndef __NR_perf_event_open | 16 | #ifndef __NR_perf_event_open |
18 | # define __NR_perf_event_open 336 | 17 | # define __NR_perf_event_open 336 |
19 | #endif | 18 | #endif |
20 | #ifndef __NR_futex | 19 | #ifndef __NR_futex |
21 | # define __NR_futex 240 | 20 | # define __NR_futex 240 |
22 | #endif | 21 | #endif |
23 | #ifndef __NR_gettid | 22 | #ifndef __NR_gettid |
24 | # define __NR_gettid 224 | 23 | # define __NR_gettid 224 |
25 | #endif | 24 | #endif |
26 | #endif | 25 | #endif |
27 | 26 | ||
28 | #if defined(__x86_64__) | 27 | #if defined(__x86_64__) |
29 | #define mb() asm volatile("mfence" ::: "memory") | 28 | #define mb() asm volatile("mfence" ::: "memory") |
30 | #define wmb() asm volatile("sfence" ::: "memory") | 29 | #define wmb() asm volatile("sfence" ::: "memory") |
31 | #define rmb() asm volatile("lfence" ::: "memory") | 30 | #define rmb() asm volatile("lfence" ::: "memory") |
32 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); | 31 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); |
33 | #define CPUINFO_PROC {"model name"} | 32 | #define CPUINFO_PROC {"model name"} |
34 | #ifndef __NR_perf_event_open | 33 | #ifndef __NR_perf_event_open |
35 | # define __NR_perf_event_open 298 | 34 | # define __NR_perf_event_open 298 |
36 | #endif | 35 | #endif |
37 | #ifndef __NR_futex | 36 | #ifndef __NR_futex |
38 | # define __NR_futex 202 | 37 | # define __NR_futex 202 |
39 | #endif | 38 | #endif |
40 | #ifndef __NR_gettid | 39 | #ifndef __NR_gettid |
41 | # define __NR_gettid 186 | 40 | # define __NR_gettid 186 |
42 | #endif | 41 | #endif |
43 | #endif | 42 | #endif |
44 | 43 | ||
45 | #ifdef __powerpc__ | 44 | #ifdef __powerpc__ |
46 | #include "../../arch/powerpc/include/uapi/asm/unistd.h" | 45 | #include "../../arch/powerpc/include/uapi/asm/unistd.h" |
47 | #define mb() asm volatile ("sync" ::: "memory") | 46 | #define mb() asm volatile ("sync" ::: "memory") |
48 | #define wmb() asm volatile ("sync" ::: "memory") | 47 | #define wmb() asm volatile ("sync" ::: "memory") |
49 | #define rmb() asm volatile ("sync" ::: "memory") | 48 | #define rmb() asm volatile ("sync" ::: "memory") |
50 | #define CPUINFO_PROC {"cpu"} | 49 | #define CPUINFO_PROC {"cpu"} |
51 | #endif | 50 | #endif |
52 | 51 | ||
53 | #ifdef __s390__ | 52 | #ifdef __s390__ |
54 | #define mb() asm volatile("bcr 15,0" ::: "memory") | 53 | #define mb() asm volatile("bcr 15,0" ::: "memory") |
55 | #define wmb() asm volatile("bcr 15,0" ::: "memory") | 54 | #define wmb() asm volatile("bcr 15,0" ::: "memory") |
56 | #define rmb() asm volatile("bcr 15,0" ::: "memory") | 55 | #define rmb() asm volatile("bcr 15,0" ::: "memory") |
57 | #define CPUINFO_PROC {"vendor_id"} | 56 | #define CPUINFO_PROC {"vendor_id"} |
58 | #endif | 57 | #endif |
59 | 58 | ||
60 | #ifdef __sh__ | 59 | #ifdef __sh__ |
61 | #if defined(__SH4A__) || defined(__SH5__) | 60 | #if defined(__SH4A__) || defined(__SH5__) |
62 | # define mb() asm volatile("synco" ::: "memory") | 61 | # define mb() asm volatile("synco" ::: "memory") |
63 | # define wmb() asm volatile("synco" ::: "memory") | 62 | # define wmb() asm volatile("synco" ::: "memory") |
64 | # define rmb() asm volatile("synco" ::: "memory") | 63 | # define rmb() asm volatile("synco" ::: "memory") |
65 | #else | 64 | #else |
66 | # define mb() asm volatile("" ::: "memory") | 65 | # define mb() asm volatile("" ::: "memory") |
67 | # define wmb() asm volatile("" ::: "memory") | 66 | # define wmb() asm volatile("" ::: "memory") |
68 | # define rmb() asm volatile("" ::: "memory") | 67 | # define rmb() asm volatile("" ::: "memory") |
69 | #endif | 68 | #endif |
70 | #define CPUINFO_PROC {"cpu type"} | 69 | #define CPUINFO_PROC {"cpu type"} |
71 | #endif | 70 | #endif |
72 | 71 | ||
73 | #ifdef __hppa__ | 72 | #ifdef __hppa__ |
74 | #define mb() asm volatile("" ::: "memory") | 73 | #define mb() asm volatile("" ::: "memory") |
75 | #define wmb() asm volatile("" ::: "memory") | 74 | #define wmb() asm volatile("" ::: "memory") |
76 | #define rmb() asm volatile("" ::: "memory") | 75 | #define rmb() asm volatile("" ::: "memory") |
77 | #define CPUINFO_PROC {"cpu"} | 76 | #define CPUINFO_PROC {"cpu"} |
78 | #endif | 77 | #endif |
79 | 78 | ||
80 | #ifdef __sparc__ | 79 | #ifdef __sparc__ |
81 | #ifdef __LP64__ | 80 | #ifdef __LP64__ |
82 | #define mb() asm volatile("ba,pt %%xcc, 1f\n" \ | 81 | #define mb() asm volatile("ba,pt %%xcc, 1f\n" \ |
83 | "membar #StoreLoad\n" \ | 82 | "membar #StoreLoad\n" \ |
84 | "1:\n":::"memory") | 83 | "1:\n":::"memory") |
85 | #else | 84 | #else |
86 | #define mb() asm volatile("":::"memory") | 85 | #define mb() asm volatile("":::"memory") |
87 | #endif | 86 | #endif |
88 | #define wmb() asm volatile("":::"memory") | 87 | #define wmb() asm volatile("":::"memory") |
89 | #define rmb() asm volatile("":::"memory") | 88 | #define rmb() asm volatile("":::"memory") |
90 | #define CPUINFO_PROC {"cpu"} | 89 | #define CPUINFO_PROC {"cpu"} |
91 | #endif | 90 | #endif |
92 | 91 | ||
93 | #ifdef __alpha__ | 92 | #ifdef __alpha__ |
94 | #define mb() asm volatile("mb" ::: "memory") | 93 | #define mb() asm volatile("mb" ::: "memory") |
95 | #define wmb() asm volatile("wmb" ::: "memory") | 94 | #define wmb() asm volatile("wmb" ::: "memory") |
96 | #define rmb() asm volatile("mb" ::: "memory") | 95 | #define rmb() asm volatile("mb" ::: "memory") |
97 | #define CPUINFO_PROC {"cpu model"} | 96 | #define CPUINFO_PROC {"cpu model"} |
98 | #endif | 97 | #endif |
99 | 98 | ||
100 | #ifdef __ia64__ | 99 | #ifdef __ia64__ |
101 | #define mb() asm volatile ("mf" ::: "memory") | 100 | #define mb() asm volatile ("mf" ::: "memory") |
102 | #define wmb() asm volatile ("mf" ::: "memory") | 101 | #define wmb() asm volatile ("mf" ::: "memory") |
103 | #define rmb() asm volatile ("mf" ::: "memory") | 102 | #define rmb() asm volatile ("mf" ::: "memory") |
104 | #define cpu_relax() asm volatile ("hint @pause" ::: "memory") | 103 | #define cpu_relax() asm volatile ("hint @pause" ::: "memory") |
105 | #define CPUINFO_PROC {"model name"} | 104 | #define CPUINFO_PROC {"model name"} |
106 | #endif | 105 | #endif |
107 | 106 | ||
108 | #ifdef __arm__ | 107 | #ifdef __arm__ |
109 | /* | 108 | /* |
110 | * Use the __kuser_memory_barrier helper in the CPU helper page. See | 109 | * Use the __kuser_memory_barrier helper in the CPU helper page. See |
111 | * arch/arm/kernel/entry-armv.S in the kernel source for details. | 110 | * arch/arm/kernel/entry-armv.S in the kernel source for details. |
112 | */ | 111 | */ |
113 | #define mb() ((void(*)(void))0xffff0fa0)() | 112 | #define mb() ((void(*)(void))0xffff0fa0)() |
114 | #define wmb() ((void(*)(void))0xffff0fa0)() | 113 | #define wmb() ((void(*)(void))0xffff0fa0)() |
115 | #define rmb() ((void(*)(void))0xffff0fa0)() | 114 | #define rmb() ((void(*)(void))0xffff0fa0)() |
116 | #define CPUINFO_PROC {"model name", "Processor"} | 115 | #define CPUINFO_PROC {"model name", "Processor"} |
117 | #endif | 116 | #endif |
118 | 117 | ||
119 | #ifdef __aarch64__ | 118 | #ifdef __aarch64__ |
120 | #define mb() asm volatile("dmb ish" ::: "memory") | 119 | #define mb() asm volatile("dmb ish" ::: "memory") |
121 | #define wmb() asm volatile("dmb ishst" ::: "memory") | 120 | #define wmb() asm volatile("dmb ishst" ::: "memory") |
122 | #define rmb() asm volatile("dmb ishld" ::: "memory") | 121 | #define rmb() asm volatile("dmb ishld" ::: "memory") |
123 | #define cpu_relax() asm volatile("yield" ::: "memory") | 122 | #define cpu_relax() asm volatile("yield" ::: "memory") |
124 | #endif | 123 | #endif |
125 | 124 | ||
126 | #ifdef __mips__ | 125 | #ifdef __mips__ |
127 | #define mb() asm volatile( \ | 126 | #define mb() asm volatile( \ |
128 | ".set mips2\n\t" \ | 127 | ".set mips2\n\t" \ |
129 | "sync\n\t" \ | 128 | "sync\n\t" \ |
130 | ".set mips0" \ | 129 | ".set mips0" \ |
131 | : /* no output */ \ | 130 | : /* no output */ \ |
132 | : /* no input */ \ | 131 | : /* no input */ \ |
133 | : "memory") | 132 | : "memory") |
134 | #define wmb() mb() | 133 | #define wmb() mb() |
135 | #define rmb() mb() | 134 | #define rmb() mb() |
136 | #define CPUINFO_PROC {"cpu model"} | 135 | #define CPUINFO_PROC {"cpu model"} |
137 | #endif | 136 | #endif |
138 | 137 | ||
139 | #ifdef __arc__ | 138 | #ifdef __arc__ |
140 | #define mb() asm volatile("" ::: "memory") | 139 | #define mb() asm volatile("" ::: "memory") |
141 | #define wmb() asm volatile("" ::: "memory") | 140 | #define wmb() asm volatile("" ::: "memory") |
142 | #define rmb() asm volatile("" ::: "memory") | 141 | #define rmb() asm volatile("" ::: "memory") |
143 | #define CPUINFO_PROC {"Processor"} | 142 | #define CPUINFO_PROC {"Processor"} |
144 | #endif | 143 | #endif |
145 | 144 | ||
146 | #ifdef __metag__ | 145 | #ifdef __metag__ |
147 | #define mb() asm volatile("" ::: "memory") | 146 | #define mb() asm volatile("" ::: "memory") |
148 | #define wmb() asm volatile("" ::: "memory") | 147 | #define wmb() asm volatile("" ::: "memory") |
149 | #define rmb() asm volatile("" ::: "memory") | 148 | #define rmb() asm volatile("" ::: "memory") |
150 | #define CPUINFO_PROC {"CPU"} | 149 | #define CPUINFO_PROC {"CPU"} |
151 | #endif | 150 | #endif |
152 | 151 | ||
153 | #ifdef __xtensa__ | 152 | #ifdef __xtensa__ |
154 | #define mb() asm volatile("memw" ::: "memory") | 153 | #define mb() asm volatile("memw" ::: "memory") |
155 | #define wmb() asm volatile("memw" ::: "memory") | 154 | #define wmb() asm volatile("memw" ::: "memory") |
156 | #define rmb() asm volatile("" ::: "memory") | 155 | #define rmb() asm volatile("" ::: "memory") |
157 | #define CPUINFO_PROC {"core ID"} | 156 | #define CPUINFO_PROC {"core ID"} |
158 | #endif | 157 | #endif |
159 | 158 | ||
160 | #ifdef __tile__ | 159 | #ifdef __tile__ |
161 | #define mb() asm volatile ("mf" ::: "memory") | 160 | #define mb() asm volatile ("mf" ::: "memory") |
162 | #define wmb() asm volatile ("mf" ::: "memory") | 161 | #define wmb() asm volatile ("mf" ::: "memory") |
163 | #define rmb() asm volatile ("mf" ::: "memory") | 162 | #define rmb() asm volatile ("mf" ::: "memory") |
164 | #define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory") | 163 | #define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory") |
165 | #define CPUINFO_PROC {"model name"} | 164 | #define CPUINFO_PROC {"model name"} |
166 | #endif | 165 | #endif |
167 | 166 | ||
168 | #define barrier() asm volatile ("" ::: "memory") | 167 | #define barrier() asm volatile ("" ::: "memory") |
169 | 168 | ||
170 | #ifndef cpu_relax | 169 | #ifndef cpu_relax |
171 | #define cpu_relax() barrier() | 170 | #define cpu_relax() barrier() |
172 | #endif | 171 | #endif |
173 | 172 | ||
174 | static inline int | 173 | static inline int |
175 | sys_perf_event_open(struct perf_event_attr *attr, | 174 | sys_perf_event_open(struct perf_event_attr *attr, |
176 | pid_t pid, int cpu, int group_fd, | 175 | pid_t pid, int cpu, int group_fd, |
177 | unsigned long flags) | 176 | unsigned long flags) |
178 | { | 177 | { |
179 | int fd; | 178 | int fd; |
180 | 179 | ||
181 | fd = syscall(__NR_perf_event_open, attr, pid, cpu, | 180 | fd = syscall(__NR_perf_event_open, attr, pid, cpu, |
182 | group_fd, flags); | 181 | group_fd, flags); |
183 | 182 | ||
184 | #ifdef HAVE_ATTR_TEST | 183 | #ifdef HAVE_ATTR_TEST |
185 | if (unlikely(test_attr__enabled)) | 184 | if (unlikely(test_attr__enabled)) |
186 | test_attr__open(attr, pid, cpu, fd, group_fd, flags); | 185 | test_attr__open(attr, pid, cpu, fd, group_fd, flags); |
187 | #endif | 186 | #endif |
188 | return fd; | 187 | return fd; |
189 | } | 188 | } |
190 | 189 | ||
191 | #endif /* _PERF_SYS_H */ | 190 | #endif /* _PERF_SYS_H */ |
192 | 191 |
tools/perf/tests/dwarf-unwind.c
1 | #include <linux/compiler.h> | 1 | #include <linux/compiler.h> |
2 | #include <linux/types.h> | 2 | #include <linux/types.h> |
3 | #include <unistd.h> | 3 | #include <unistd.h> |
4 | #include "tests.h" | 4 | #include "tests.h" |
5 | #include "debug.h" | 5 | #include "debug.h" |
6 | #include "machine.h" | 6 | #include "machine.h" |
7 | #include "event.h" | 7 | #include "event.h" |
8 | #include "unwind.h" | 8 | #include "unwind.h" |
9 | #include "perf_regs.h" | 9 | #include "perf_regs.h" |
10 | #include "map.h" | 10 | #include "map.h" |
11 | #include "thread.h" | 11 | #include "thread.h" |
12 | #include "callchain.h" | 12 | #include "callchain.h" |
13 | 13 | ||
14 | /* For bsearch. We try to unwind functions in shared object. */ | ||
15 | #include <stdlib.h> | ||
16 | |||
14 | static int mmap_handler(struct perf_tool *tool __maybe_unused, | 17 | static int mmap_handler(struct perf_tool *tool __maybe_unused, |
15 | union perf_event *event, | 18 | union perf_event *event, |
16 | struct perf_sample *sample __maybe_unused, | 19 | struct perf_sample *sample __maybe_unused, |
17 | struct machine *machine) | 20 | struct machine *machine) |
18 | { | 21 | { |
19 | return machine__process_mmap2_event(machine, event, NULL); | 22 | return machine__process_mmap2_event(machine, event, NULL); |
20 | } | 23 | } |
21 | 24 | ||
22 | static int init_live_machine(struct machine *machine) | 25 | static int init_live_machine(struct machine *machine) |
23 | { | 26 | { |
24 | union perf_event event; | 27 | union perf_event event; |
25 | pid_t pid = getpid(); | 28 | pid_t pid = getpid(); |
26 | 29 | ||
27 | return perf_event__synthesize_mmap_events(NULL, &event, pid, pid, | 30 | return perf_event__synthesize_mmap_events(NULL, &event, pid, pid, |
28 | mmap_handler, machine, true); | 31 | mmap_handler, machine, true); |
29 | } | 32 | } |
30 | 33 | ||
31 | #define MAX_STACK 6 | 34 | #define MAX_STACK 8 |
32 | 35 | ||
33 | static int unwind_entry(struct unwind_entry *entry, void *arg) | 36 | static int unwind_entry(struct unwind_entry *entry, void *arg) |
34 | { | 37 | { |
35 | unsigned long *cnt = (unsigned long *) arg; | 38 | unsigned long *cnt = (unsigned long *) arg; |
36 | char *symbol = entry->sym ? entry->sym->name : NULL; | 39 | char *symbol = entry->sym ? entry->sym->name : NULL; |
37 | static const char *funcs[MAX_STACK] = { | 40 | static const char *funcs[MAX_STACK] = { |
38 | "test__arch_unwind_sample", | 41 | "test__arch_unwind_sample", |
39 | "unwind_thread", | 42 | "unwind_thread", |
43 | "compare", | ||
44 | "bsearch", | ||
40 | "krava_3", | 45 | "krava_3", |
41 | "krava_2", | 46 | "krava_2", |
42 | "krava_1", | 47 | "krava_1", |
43 | "test__dwarf_unwind" | 48 | "test__dwarf_unwind" |
44 | }; | 49 | }; |
45 | 50 | ||
46 | if (*cnt >= MAX_STACK) { | 51 | if (*cnt >= MAX_STACK) { |
47 | pr_debug("failed: crossed the max stack value %d\n", MAX_STACK); | 52 | pr_debug("failed: crossed the max stack value %d\n", MAX_STACK); |
48 | return -1; | 53 | return -1; |
49 | } | 54 | } |
50 | 55 | ||
51 | if (!symbol) { | 56 | if (!symbol) { |
52 | pr_debug("failed: got unresolved address 0x%" PRIx64 "\n", | 57 | pr_debug("failed: got unresolved address 0x%" PRIx64 "\n", |
53 | entry->ip); | 58 | entry->ip); |
54 | return -1; | 59 | return -1; |
55 | } | 60 | } |
56 | 61 | ||
57 | pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip); | 62 | pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip); |
58 | return strcmp((const char *) symbol, funcs[(*cnt)++]); | 63 | return strcmp((const char *) symbol, funcs[(*cnt)++]); |
59 | } | 64 | } |
60 | 65 | ||
61 | __attribute__ ((noinline)) | 66 | __attribute__ ((noinline)) |
62 | static int unwind_thread(struct thread *thread) | 67 | static int unwind_thread(struct thread *thread) |
63 | { | 68 | { |
64 | struct perf_sample sample; | 69 | struct perf_sample sample; |
65 | unsigned long cnt = 0; | 70 | unsigned long cnt = 0; |
66 | int err = -1; | 71 | int err = -1; |
67 | 72 | ||
68 | memset(&sample, 0, sizeof(sample)); | 73 | memset(&sample, 0, sizeof(sample)); |
69 | 74 | ||
70 | if (test__arch_unwind_sample(&sample, thread)) { | 75 | if (test__arch_unwind_sample(&sample, thread)) { |
71 | pr_debug("failed to get unwind sample\n"); | 76 | pr_debug("failed to get unwind sample\n"); |
72 | goto out; | 77 | goto out; |
73 | } | 78 | } |
74 | 79 | ||
75 | err = unwind__get_entries(unwind_entry, &cnt, thread, | 80 | err = unwind__get_entries(unwind_entry, &cnt, thread, |
76 | &sample, MAX_STACK); | 81 | &sample, MAX_STACK); |
77 | if (err) | 82 | if (err) |
78 | pr_debug("unwind failed\n"); | 83 | pr_debug("unwind failed\n"); |
79 | else if (cnt != MAX_STACK) { | 84 | else if (cnt != MAX_STACK) { |
80 | pr_debug("got wrong number of stack entries %lu != %d\n", | 85 | pr_debug("got wrong number of stack entries %lu != %d\n", |
81 | cnt, MAX_STACK); | 86 | cnt, MAX_STACK); |
82 | err = -1; | 87 | err = -1; |
83 | } | 88 | } |
84 | 89 | ||
85 | out: | 90 | out: |
86 | free(sample.user_stack.data); | 91 | free(sample.user_stack.data); |
87 | free(sample.user_regs.regs); | 92 | free(sample.user_regs.regs); |
88 | return err; | 93 | return err; |
89 | } | 94 | } |
90 | 95 | ||
96 | static int global_unwind_retval = -INT_MAX; | ||
97 | |||
91 | __attribute__ ((noinline)) | 98 | __attribute__ ((noinline)) |
99 | static int compare(void *p1, void *p2) | ||
100 | { | ||
101 | /* Any possible value should be 'thread' */ | ||
102 | struct thread *thread = *(struct thread **)p1; | ||
103 | |||
104 | if (global_unwind_retval == -INT_MAX) | ||
105 | global_unwind_retval = unwind_thread(thread); | ||
106 | |||
107 | return p1 - p2; | ||
108 | } | ||
109 | |||
110 | __attribute__ ((noinline)) | ||
92 | static int krava_3(struct thread *thread) | 111 | static int krava_3(struct thread *thread) |
93 | { | 112 | { |
94 | return unwind_thread(thread); | 113 | struct thread *array[2] = {thread, thread}; |
114 | void *fp = &bsearch; | ||
115 | /* | ||
116 | * make _bsearch a volatile function pointer to | ||
117 | * prevent potential optimization, which may expand | ||
118 | * bsearch and call compare directly from this function, | ||
119 | * instead of libc shared object. | ||
120 | */ | ||
121 | void *(*volatile _bsearch)(void *, void *, size_t, | ||
122 | size_t, int (*)(void *, void *)); | ||
123 | |||
124 | _bsearch = fp; | ||
125 | _bsearch(array, &thread, 2, sizeof(struct thread **), compare); | ||
126 | return global_unwind_retval; | ||
95 | } | 127 | } |
96 | 128 | ||
97 | __attribute__ ((noinline)) | 129 | __attribute__ ((noinline)) |
98 | static int krava_2(struct thread *thread) | 130 | static int krava_2(struct thread *thread) |
99 | { | 131 | { |
100 | return krava_3(thread); | 132 | return krava_3(thread); |
101 | } | 133 | } |
102 | 134 | ||
103 | __attribute__ ((noinline)) | 135 | __attribute__ ((noinline)) |
104 | static int krava_1(struct thread *thread) | 136 | static int krava_1(struct thread *thread) |
105 | { | 137 | { |
106 | return krava_2(thread); | 138 | return krava_2(thread); |
107 | } | 139 | } |
108 | 140 | ||
109 | int test__dwarf_unwind(void) | 141 | int test__dwarf_unwind(void) |
110 | { | 142 | { |
111 | struct machines machines; | 143 | struct machines machines; |
112 | struct machine *machine; | 144 | struct machine *machine; |
113 | struct thread *thread; | 145 | struct thread *thread; |
114 | int err = -1; | 146 | int err = -1; |
115 | 147 | ||
116 | machines__init(&machines); | 148 | machines__init(&machines); |
117 | 149 | ||
118 | machine = machines__find(&machines, HOST_KERNEL_ID); | 150 | machine = machines__find(&machines, HOST_KERNEL_ID); |
119 | if (!machine) { | 151 | if (!machine) { |
120 | pr_err("Could not get machine\n"); | 152 | pr_err("Could not get machine\n"); |
121 | return -1; | 153 | return -1; |
122 | } | 154 | } |
123 | 155 | ||
124 | callchain_param.record_mode = CALLCHAIN_DWARF; | 156 | callchain_param.record_mode = CALLCHAIN_DWARF; |
125 | 157 | ||
126 | if (init_live_machine(machine)) { | 158 | if (init_live_machine(machine)) { |
127 | pr_err("Could not init machine\n"); | 159 | pr_err("Could not init machine\n"); |
128 | goto out; | 160 | goto out; |
129 | } | 161 | } |
130 | 162 | ||
131 | if (verbose > 1) | 163 | if (verbose > 1) |
132 | machine__fprintf(machine, stderr); | 164 | machine__fprintf(machine, stderr); |
133 | 165 | ||
134 | thread = machine__find_thread(machine, getpid(), getpid()); | 166 | thread = machine__find_thread(machine, getpid(), getpid()); |
135 | if (!thread) { | 167 | if (!thread) { |
136 | pr_err("Could not get thread\n"); | 168 | pr_err("Could not get thread\n"); |
137 | goto out; | 169 | goto out; |
138 | } | 170 | } |
139 | 171 | ||
140 | err = krava_1(thread); | 172 | err = krava_1(thread); |
141 | 173 | ||
142 | out: | 174 | out: |
143 | machine__delete_threads(machine); | 175 | machine__delete_threads(machine); |
144 | machine__exit(machine); | 176 | machine__exit(machine); |
145 | machines__exit(&machines); | 177 | machines__exit(&machines); |
146 | return err; | 178 | return err; |
147 | } | 179 | } |
148 | 180 |
tools/perf/util/annotate.h
1 | #ifndef __PERF_ANNOTATE_H | 1 | #ifndef __PERF_ANNOTATE_H |
2 | #define __PERF_ANNOTATE_H | 2 | #define __PERF_ANNOTATE_H |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <stdint.h> | 5 | #include <stdint.h> |
6 | #include <linux/types.h> | 6 | #include <linux/types.h> |
7 | #include "symbol.h" | 7 | #include "symbol.h" |
8 | #include "hist.h" | 8 | #include "hist.h" |
9 | #include "sort.h" | 9 | #include "sort.h" |
10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
11 | #include <linux/rbtree.h> | 11 | #include <linux/rbtree.h> |
12 | #include <pthread.h> | 12 | #include <pthread.h> |
13 | 13 | ||
14 | struct ins; | 14 | struct ins; |
15 | 15 | ||
16 | struct ins_operands { | 16 | struct ins_operands { |
17 | char *raw; | 17 | char *raw; |
18 | struct { | 18 | struct { |
19 | char *raw; | 19 | char *raw; |
20 | char *name; | 20 | char *name; |
21 | u64 addr; | 21 | u64 addr; |
22 | u64 offset; | 22 | u64 offset; |
23 | } target; | 23 | } target; |
24 | union { | 24 | union { |
25 | struct { | 25 | struct { |
26 | char *raw; | 26 | char *raw; |
27 | char *name; | 27 | char *name; |
28 | u64 addr; | 28 | u64 addr; |
29 | } source; | 29 | } source; |
30 | struct { | 30 | struct { |
31 | struct ins *ins; | 31 | struct ins *ins; |
32 | struct ins_operands *ops; | 32 | struct ins_operands *ops; |
33 | } locked; | 33 | } locked; |
34 | }; | 34 | }; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct ins_ops { | 37 | struct ins_ops { |
38 | void (*free)(struct ins_operands *ops); | 38 | void (*free)(struct ins_operands *ops); |
39 | int (*parse)(struct ins_operands *ops); | 39 | int (*parse)(struct ins_operands *ops); |
40 | int (*scnprintf)(struct ins *ins, char *bf, size_t size, | 40 | int (*scnprintf)(struct ins *ins, char *bf, size_t size, |
41 | struct ins_operands *ops); | 41 | struct ins_operands *ops); |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct ins { | 44 | struct ins { |
45 | const char *name; | 45 | const char *name; |
46 | struct ins_ops *ops; | 46 | struct ins_ops *ops; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | bool ins__is_jump(const struct ins *ins); | 49 | bool ins__is_jump(const struct ins *ins); |
50 | bool ins__is_call(const struct ins *ins); | 50 | bool ins__is_call(const struct ins *ins); |
51 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); | 51 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); |
52 | 52 | ||
53 | struct annotation; | 53 | struct annotation; |
54 | 54 | ||
55 | struct disasm_line { | 55 | struct disasm_line { |
56 | struct list_head node; | 56 | struct list_head node; |
57 | s64 offset; | 57 | s64 offset; |
58 | char *line; | 58 | char *line; |
59 | char *name; | 59 | char *name; |
60 | struct ins *ins; | 60 | struct ins *ins; |
61 | int line_nr; | 61 | int line_nr; |
62 | struct ins_operands ops; | 62 | struct ins_operands ops; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static inline bool disasm_line__has_offset(const struct disasm_line *dl) | 65 | static inline bool disasm_line__has_offset(const struct disasm_line *dl) |
66 | { | 66 | { |
67 | return dl->ops.target.offset != UINT64_MAX; | 67 | return dl->ops.target.offset != UINT64_MAX; |
68 | } | 68 | } |
69 | 69 | ||
70 | void disasm_line__free(struct disasm_line *dl); | 70 | void disasm_line__free(struct disasm_line *dl); |
71 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); | 71 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); |
72 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 72 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
73 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 73 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
74 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | 74 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, |
75 | s64 end, const char **path); | 75 | s64 end, const char **path); |
76 | 76 | ||
77 | struct sym_hist { | 77 | struct sym_hist { |
78 | u64 sum; | 78 | u64 sum; |
79 | u64 addr[0]; | 79 | u64 addr[0]; |
80 | }; | 80 | }; |
81 | 81 | ||
82 | struct source_line_percent { | 82 | struct source_line_percent { |
83 | double percent; | 83 | double percent; |
84 | double percent_sum; | 84 | double percent_sum; |
85 | }; | 85 | }; |
86 | 86 | ||
87 | struct source_line { | 87 | struct source_line { |
88 | struct rb_node node; | 88 | struct rb_node node; |
89 | char *path; | 89 | char *path; |
90 | int nr_pcnt; | 90 | int nr_pcnt; |
91 | struct source_line_percent p[1]; | 91 | struct source_line_percent p[1]; |
92 | }; | 92 | }; |
93 | 93 | ||
94 | /** struct annotated_source - symbols with hits have this attached as in sannotation | 94 | /** struct annotated_source - symbols with hits have this attached as in sannotation |
95 | * | 95 | * |
96 | * @histogram: Array of addr hit histograms per event being monitored | 96 | * @histogram: Array of addr hit histograms per event being monitored |
97 | * @lines: If 'print_lines' is specified, per source code line percentages | 97 | * @lines: If 'print_lines' is specified, per source code line percentages |
98 | * @source: source parsed from a disassembler like objdump -dS | 98 | * @source: source parsed from a disassembler like objdump -dS |
99 | * | 99 | * |
100 | * lines is allocated, percentages calculated and all sorted by percentage | 100 | * lines is allocated, percentages calculated and all sorted by percentage |
101 | * when the annotation is about to be presented, so the percentages are for | 101 | * when the annotation is about to be presented, so the percentages are for |
102 | * one of the entries in the histogram array, i.e. for the event/counter being | 102 | * one of the entries in the histogram array, i.e. for the event/counter being |
103 | * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate | 103 | * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate |
104 | * returns. | 104 | * returns. |
105 | */ | 105 | */ |
106 | struct annotated_source { | 106 | struct annotated_source { |
107 | struct list_head source; | 107 | struct list_head source; |
108 | struct source_line *lines; | 108 | struct source_line *lines; |
109 | int nr_histograms; | 109 | int nr_histograms; |
110 | int sizeof_sym_hist; | 110 | int sizeof_sym_hist; |
111 | struct sym_hist histograms[0]; | 111 | struct sym_hist histograms[0]; |
112 | }; | 112 | }; |
113 | 113 | ||
114 | struct annotation { | 114 | struct annotation { |
115 | pthread_mutex_t lock; | 115 | pthread_mutex_t lock; |
116 | struct annotated_source *src; | 116 | struct annotated_source *src; |
117 | }; | 117 | }; |
118 | 118 | ||
119 | struct sannotation { | ||
120 | struct annotation annotation; | ||
121 | struct symbol symbol; | ||
122 | }; | ||
123 | |||
124 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) | 119 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) |
125 | { | 120 | { |
126 | return (((void *)¬es->src->histograms) + | 121 | return (((void *)¬es->src->histograms) + |
127 | (notes->src->sizeof_sym_hist * idx)); | 122 | (notes->src->sizeof_sym_hist * idx)); |
128 | } | 123 | } |
129 | 124 | ||
130 | static inline struct annotation *symbol__annotation(struct symbol *sym) | 125 | static inline struct annotation *symbol__annotation(struct symbol *sym) |
131 | { | 126 | { |
132 | struct sannotation *a = container_of(sym, struct sannotation, symbol); | 127 | return (void *)sym - symbol_conf.priv_size; |
133 | return &a->annotation; | ||
134 | } | 128 | } |
135 | 129 | ||
136 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); | 130 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); |
137 | 131 | ||
138 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | 132 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); |
139 | 133 | ||
140 | int symbol__alloc_hist(struct symbol *sym); | 134 | int symbol__alloc_hist(struct symbol *sym); |
141 | void symbol__annotate_zero_histograms(struct symbol *sym); | 135 | void symbol__annotate_zero_histograms(struct symbol *sym); |
142 | 136 | ||
143 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); | 137 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); |
144 | 138 | ||
145 | int hist_entry__annotate(struct hist_entry *he, size_t privsize); | 139 | int hist_entry__annotate(struct hist_entry *he, size_t privsize); |
146 | 140 | ||
147 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); | 141 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); |
148 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 142 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
149 | struct perf_evsel *evsel, bool full_paths, | 143 | struct perf_evsel *evsel, bool full_paths, |
150 | int min_pcnt, int max_lines, int context); | 144 | int min_pcnt, int max_lines, int context); |
151 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | 145 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); |
152 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 146 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
153 | void disasm__purge(struct list_head *head); | 147 | void disasm__purge(struct list_head *head); |
154 | 148 | ||
155 | bool ui__has_annotation(void); | 149 | bool ui__has_annotation(void); |
156 | 150 | ||
157 | int symbol__tty_annotate(struct symbol *sym, struct map *map, | 151 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
158 | struct perf_evsel *evsel, bool print_lines, | 152 | struct perf_evsel *evsel, bool print_lines, |
159 | bool full_paths, int min_pcnt, int max_lines); | 153 | bool full_paths, int min_pcnt, int max_lines); |
160 | 154 | ||
161 | #ifdef HAVE_SLANG_SUPPORT | 155 | #ifdef HAVE_SLANG_SUPPORT |
162 | int symbol__tui_annotate(struct symbol *sym, struct map *map, | 156 | int symbol__tui_annotate(struct symbol *sym, struct map *map, |
163 | struct perf_evsel *evsel, | 157 | struct perf_evsel *evsel, |
164 | struct hist_browser_timer *hbt); | 158 | struct hist_browser_timer *hbt); |
165 | #else | 159 | #else |
166 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | 160 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, |
167 | struct map *map __maybe_unused, | 161 | struct map *map __maybe_unused, |
168 | struct perf_evsel *evsel __maybe_unused, | 162 | struct perf_evsel *evsel __maybe_unused, |
169 | struct hist_browser_timer *hbt | 163 | struct hist_browser_timer *hbt |
170 | __maybe_unused) | 164 | __maybe_unused) |
171 | { | 165 | { |
172 | return 0; | 166 | return 0; |
173 | } | 167 | } |
174 | #endif | 168 | #endif |
175 | 169 | ||
176 | extern const char *disassembler_style; | 170 | extern const char *disassembler_style; |
177 | 171 | ||
178 | #endif /* __PERF_ANNOTATE_H */ | 172 | #endif /* __PERF_ANNOTATE_H */ |
179 | 173 |
tools/perf/util/cache.h
1 | #ifndef __PERF_CACHE_H | 1 | #ifndef __PERF_CACHE_H |
2 | #define __PERF_CACHE_H | 2 | #define __PERF_CACHE_H |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include "util.h" | 5 | #include "util.h" |
6 | #include "strbuf.h" | 6 | #include "strbuf.h" |
7 | #include "../perf.h" | 7 | #include "../perf.h" |
8 | #include "../ui/ui.h" | 8 | #include "../ui/ui.h" |
9 | 9 | ||
10 | #define CMD_EXEC_PATH "--exec-path" | 10 | #define CMD_EXEC_PATH "--exec-path" |
11 | #define CMD_PERF_DIR "--perf-dir=" | 11 | #define CMD_PERF_DIR "--perf-dir=" |
12 | #define CMD_WORK_TREE "--work-tree=" | 12 | #define CMD_WORK_TREE "--work-tree=" |
13 | #define CMD_DEBUGFS_DIR "--debugfs-dir=" | 13 | #define CMD_DEBUGFS_DIR "--debugfs-dir=" |
14 | 14 | ||
15 | #define PERF_DIR_ENVIRONMENT "PERF_DIR" | 15 | #define PERF_DIR_ENVIRONMENT "PERF_DIR" |
16 | #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" | 16 | #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" |
17 | #define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" | 17 | #define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" |
18 | #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" | 18 | #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" |
19 | #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" | 19 | #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" |
20 | 20 | ||
21 | typedef int (*config_fn_t)(const char *, const char *, void *); | 21 | typedef int (*config_fn_t)(const char *, const char *, void *); |
22 | extern int perf_default_config(const char *, const char *, void *); | 22 | extern int perf_default_config(const char *, const char *, void *); |
23 | extern int perf_config(config_fn_t fn, void *); | 23 | extern int perf_config(config_fn_t fn, void *); |
24 | extern int perf_config_int(const char *, const char *); | 24 | extern int perf_config_int(const char *, const char *); |
25 | extern u64 perf_config_u64(const char *, const char *); | 25 | extern u64 perf_config_u64(const char *, const char *); |
26 | extern int perf_config_bool(const char *, const char *); | 26 | extern int perf_config_bool(const char *, const char *); |
27 | extern int config_error_nonbool(const char *); | 27 | extern int config_error_nonbool(const char *); |
28 | extern const char *perf_config_dirname(const char *, const char *); | 28 | extern const char *perf_config_dirname(const char *, const char *); |
29 | 29 | ||
30 | /* pager.c */ | 30 | /* pager.c */ |
31 | extern void setup_pager(void); | 31 | extern void setup_pager(void); |
32 | extern const char *pager_program; | 32 | extern const char *pager_program; |
33 | extern int pager_in_use(void); | 33 | extern int pager_in_use(void); |
34 | extern int pager_use_color; | 34 | extern int pager_use_color; |
35 | 35 | ||
36 | char *alias_lookup(const char *alias); | 36 | char *alias_lookup(const char *alias); |
37 | int split_cmdline(char *cmdline, const char ***argv); | 37 | int split_cmdline(char *cmdline, const char ***argv); |
38 | 38 | ||
39 | #define alloc_nr(x) (((x)+16)*3/2) | 39 | #define alloc_nr(x) (((x)+16)*3/2) |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Realloc the buffer pointed at by variable 'x' so that it can hold | 42 | * Realloc the buffer pointed at by variable 'x' so that it can hold |
43 | * at least 'nr' entries; the number of entries currently allocated | 43 | * at least 'nr' entries; the number of entries currently allocated |
44 | * is 'alloc', using the standard growing factor alloc_nr() macro. | 44 | * is 'alloc', using the standard growing factor alloc_nr() macro. |
45 | * | 45 | * |
46 | * DO NOT USE any expression with side-effect for 'x' or 'alloc'. | 46 | * DO NOT USE any expression with side-effect for 'x' or 'alloc'. |
47 | */ | 47 | */ |
48 | #define ALLOC_GROW(x, nr, alloc) \ | 48 | #define ALLOC_GROW(x, nr, alloc) \ |
49 | do { \ | 49 | do { \ |
50 | if ((nr) > alloc) { \ | 50 | if ((nr) > alloc) { \ |
51 | if (alloc_nr(alloc) < (nr)) \ | 51 | if (alloc_nr(alloc) < (nr)) \ |
52 | alloc = (nr); \ | 52 | alloc = (nr); \ |
53 | else \ | 53 | else \ |
54 | alloc = alloc_nr(alloc); \ | 54 | alloc = alloc_nr(alloc); \ |
55 | x = xrealloc((x), alloc * sizeof(*(x))); \ | 55 | x = xrealloc((x), alloc * sizeof(*(x))); \ |
56 | } \ | 56 | } \ |
57 | } while(0) | 57 | } while(0) |
58 | 58 | ||
59 | 59 | ||
60 | static inline int is_absolute_path(const char *path) | 60 | static inline int is_absolute_path(const char *path) |
61 | { | 61 | { |
62 | return path[0] == '/'; | 62 | return path[0] == '/'; |
63 | } | 63 | } |
64 | 64 | ||
65 | const char *make_nonrelative_path(const char *path); | 65 | const char *make_nonrelative_path(const char *path); |
66 | char *strip_path_suffix(const char *path, const char *suffix); | 66 | char *strip_path_suffix(const char *path, const char *suffix); |
67 | 67 | ||
68 | extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); | 68 | extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); |
69 | extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); | 69 | extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); |
70 | 70 | ||
71 | extern char *perf_pathdup(const char *fmt, ...) | 71 | extern char *perf_pathdup(const char *fmt, ...) |
72 | __attribute__((format (printf, 1, 2))); | 72 | __attribute__((format (printf, 1, 2))); |
73 | 73 | ||
74 | #ifndef __UCLIBC__ | ||
74 | /* Matches the libc/libbsd function attribute so we declare this unconditionally: */ | 75 | /* Matches the libc/libbsd function attribute so we declare this unconditionally: */ |
75 | extern size_t strlcpy(char *dest, const char *src, size_t size); | 76 | extern size_t strlcpy(char *dest, const char *src, size_t size); |
77 | #endif | ||
76 | 78 | ||
77 | #endif /* __PERF_CACHE_H */ | 79 | #endif /* __PERF_CACHE_H */ |
78 | 80 |
tools/perf/util/hweight.c
1 | #include <linux/bitops.h> | File was deleted | |
2 | |||
3 | /** | ||
4 | * hweightN - returns the hamming weight of a N-bit word | ||
5 | * @x: the word to weigh | ||
6 | * | ||
7 | * The Hamming Weight of a number is the total number of bits set in it. | ||
8 | */ | ||
9 | |||
10 | unsigned int hweight32(unsigned int w) | ||
11 | { | ||
12 | unsigned int res = w - ((w >> 1) & 0x55555555); | ||
13 | res = (res & 0x33333333) + ((res >> 2) & 0x33333333); | ||
14 | res = (res + (res >> 4)) & 0x0F0F0F0F; | ||
15 | res = res + (res >> 8); | ||
16 | return (res + (res >> 16)) & 0x000000FF; | ||
17 | } | ||
18 | |||
19 | unsigned long hweight64(__u64 w) | ||
20 | { | ||
21 | #if BITS_PER_LONG == 32 | ||
22 | return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w); | ||
23 | #elif BITS_PER_LONG == 64 | ||
24 | __u64 res = w - ((w >> 1) & 0x5555555555555555ul); | ||
25 | res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); | ||
26 | res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful; | ||
27 | res = res + (res >> 8); | ||
28 | res = res + (res >> 16); | ||
29 | return (res + (res >> 32)) & 0x00000000000000FFul; | ||
30 | #endif | ||
31 | } | ||
32 | 1 | #include <linux/bitops.h> |
tools/perf/util/include/asm/hweight.h
1 | #ifndef PERF_HWEIGHT_H | File was deleted | |
2 | #define PERF_HWEIGHT_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | unsigned int hweight32(unsigned int w); | ||
6 | unsigned long hweight64(__u64 w); | ||
7 | |||
8 | #endif /* PERF_HWEIGHT_H */ | ||
9 | 1 | #ifndef PERF_HWEIGHT_H |
tools/perf/util/machine.c
1 | #include "callchain.h" | 1 | #include "callchain.h" |
2 | #include "debug.h" | 2 | #include "debug.h" |
3 | #include "event.h" | 3 | #include "event.h" |
4 | #include "evsel.h" | 4 | #include "evsel.h" |
5 | #include "hist.h" | 5 | #include "hist.h" |
6 | #include "machine.h" | 6 | #include "machine.h" |
7 | #include "map.h" | 7 | #include "map.h" |
8 | #include "sort.h" | 8 | #include "sort.h" |
9 | #include "strlist.h" | 9 | #include "strlist.h" |
10 | #include "thread.h" | 10 | #include "thread.h" |
11 | #include "vdso.h" | 11 | #include "vdso.h" |
12 | #include <stdbool.h> | 12 | #include <stdbool.h> |
13 | #include <symbol/kallsyms.h> | 13 | #include <symbol/kallsyms.h> |
14 | #include "unwind.h" | 14 | #include "unwind.h" |
15 | #include "linux/hash.h" | 15 | #include "linux/hash.h" |
16 | 16 | ||
17 | static void dsos__init(struct dsos *dsos) | 17 | static void dsos__init(struct dsos *dsos) |
18 | { | 18 | { |
19 | INIT_LIST_HEAD(&dsos->head); | 19 | INIT_LIST_HEAD(&dsos->head); |
20 | dsos->root = RB_ROOT; | 20 | dsos->root = RB_ROOT; |
21 | } | 21 | } |
22 | 22 | ||
23 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 23 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
24 | { | 24 | { |
25 | map_groups__init(&machine->kmaps, machine); | 25 | map_groups__init(&machine->kmaps, machine); |
26 | RB_CLEAR_NODE(&machine->rb_node); | 26 | RB_CLEAR_NODE(&machine->rb_node); |
27 | dsos__init(&machine->user_dsos); | 27 | dsos__init(&machine->user_dsos); |
28 | dsos__init(&machine->kernel_dsos); | 28 | dsos__init(&machine->kernel_dsos); |
29 | 29 | ||
30 | machine->threads = RB_ROOT; | 30 | machine->threads = RB_ROOT; |
31 | INIT_LIST_HEAD(&machine->dead_threads); | 31 | INIT_LIST_HEAD(&machine->dead_threads); |
32 | machine->last_match = NULL; | 32 | machine->last_match = NULL; |
33 | 33 | ||
34 | machine->vdso_info = NULL; | 34 | machine->vdso_info = NULL; |
35 | 35 | ||
36 | machine->pid = pid; | 36 | machine->pid = pid; |
37 | 37 | ||
38 | machine->symbol_filter = NULL; | 38 | machine->symbol_filter = NULL; |
39 | machine->id_hdr_size = 0; | 39 | machine->id_hdr_size = 0; |
40 | machine->comm_exec = false; | 40 | machine->comm_exec = false; |
41 | machine->kernel_start = 0; | 41 | machine->kernel_start = 0; |
42 | 42 | ||
43 | machine->root_dir = strdup(root_dir); | 43 | machine->root_dir = strdup(root_dir); |
44 | if (machine->root_dir == NULL) | 44 | if (machine->root_dir == NULL) |
45 | return -ENOMEM; | 45 | return -ENOMEM; |
46 | 46 | ||
47 | if (pid != HOST_KERNEL_ID) { | 47 | if (pid != HOST_KERNEL_ID) { |
48 | struct thread *thread = machine__findnew_thread(machine, -1, | 48 | struct thread *thread = machine__findnew_thread(machine, -1, |
49 | pid); | 49 | pid); |
50 | char comm[64]; | 50 | char comm[64]; |
51 | 51 | ||
52 | if (thread == NULL) | 52 | if (thread == NULL) |
53 | return -ENOMEM; | 53 | return -ENOMEM; |
54 | 54 | ||
55 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); | 55 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); |
56 | thread__set_comm(thread, comm, 0); | 56 | thread__set_comm(thread, comm, 0); |
57 | } | 57 | } |
58 | 58 | ||
59 | machine->current_tid = NULL; | 59 | machine->current_tid = NULL; |
60 | 60 | ||
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
64 | struct machine *machine__new_host(void) | 64 | struct machine *machine__new_host(void) |
65 | { | 65 | { |
66 | struct machine *machine = malloc(sizeof(*machine)); | 66 | struct machine *machine = malloc(sizeof(*machine)); |
67 | 67 | ||
68 | if (machine != NULL) { | 68 | if (machine != NULL) { |
69 | machine__init(machine, "", HOST_KERNEL_ID); | 69 | machine__init(machine, "", HOST_KERNEL_ID); |
70 | 70 | ||
71 | if (machine__create_kernel_maps(machine) < 0) | 71 | if (machine__create_kernel_maps(machine) < 0) |
72 | goto out_delete; | 72 | goto out_delete; |
73 | } | 73 | } |
74 | 74 | ||
75 | return machine; | 75 | return machine; |
76 | out_delete: | 76 | out_delete: |
77 | free(machine); | 77 | free(machine); |
78 | return NULL; | 78 | return NULL; |
79 | } | 79 | } |
80 | 80 | ||
81 | static void dsos__delete(struct dsos *dsos) | 81 | static void dsos__delete(struct dsos *dsos) |
82 | { | 82 | { |
83 | struct dso *pos, *n; | 83 | struct dso *pos, *n; |
84 | 84 | ||
85 | list_for_each_entry_safe(pos, n, &dsos->head, node) { | 85 | list_for_each_entry_safe(pos, n, &dsos->head, node) { |
86 | RB_CLEAR_NODE(&pos->rb_node); | 86 | RB_CLEAR_NODE(&pos->rb_node); |
87 | list_del(&pos->node); | 87 | list_del(&pos->node); |
88 | dso__delete(pos); | 88 | dso__delete(pos); |
89 | } | 89 | } |
90 | } | 90 | } |
91 | 91 | ||
92 | void machine__delete_dead_threads(struct machine *machine) | 92 | void machine__delete_dead_threads(struct machine *machine) |
93 | { | 93 | { |
94 | struct thread *n, *t; | 94 | struct thread *n, *t; |
95 | 95 | ||
96 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { | 96 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { |
97 | list_del(&t->node); | 97 | list_del(&t->node); |
98 | thread__delete(t); | 98 | thread__delete(t); |
99 | } | 99 | } |
100 | } | 100 | } |
101 | 101 | ||
102 | void machine__delete_threads(struct machine *machine) | 102 | void machine__delete_threads(struct machine *machine) |
103 | { | 103 | { |
104 | struct rb_node *nd = rb_first(&machine->threads); | 104 | struct rb_node *nd = rb_first(&machine->threads); |
105 | 105 | ||
106 | while (nd) { | 106 | while (nd) { |
107 | struct thread *t = rb_entry(nd, struct thread, rb_node); | 107 | struct thread *t = rb_entry(nd, struct thread, rb_node); |
108 | 108 | ||
109 | rb_erase(&t->rb_node, &machine->threads); | 109 | rb_erase(&t->rb_node, &machine->threads); |
110 | nd = rb_next(nd); | 110 | nd = rb_next(nd); |
111 | thread__delete(t); | 111 | thread__delete(t); |
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | void machine__exit(struct machine *machine) | 115 | void machine__exit(struct machine *machine) |
116 | { | 116 | { |
117 | map_groups__exit(&machine->kmaps); | 117 | map_groups__exit(&machine->kmaps); |
118 | dsos__delete(&machine->user_dsos); | 118 | dsos__delete(&machine->user_dsos); |
119 | dsos__delete(&machine->kernel_dsos); | 119 | dsos__delete(&machine->kernel_dsos); |
120 | vdso__exit(machine); | 120 | vdso__exit(machine); |
121 | zfree(&machine->root_dir); | 121 | zfree(&machine->root_dir); |
122 | zfree(&machine->current_tid); | 122 | zfree(&machine->current_tid); |
123 | } | 123 | } |
124 | 124 | ||
125 | void machine__delete(struct machine *machine) | 125 | void machine__delete(struct machine *machine) |
126 | { | 126 | { |
127 | machine__exit(machine); | 127 | machine__exit(machine); |
128 | free(machine); | 128 | free(machine); |
129 | } | 129 | } |
130 | 130 | ||
131 | void machines__init(struct machines *machines) | 131 | void machines__init(struct machines *machines) |
132 | { | 132 | { |
133 | machine__init(&machines->host, "", HOST_KERNEL_ID); | 133 | machine__init(&machines->host, "", HOST_KERNEL_ID); |
134 | machines->guests = RB_ROOT; | 134 | machines->guests = RB_ROOT; |
135 | machines->symbol_filter = NULL; | 135 | machines->symbol_filter = NULL; |
136 | } | 136 | } |
137 | 137 | ||
138 | void machines__exit(struct machines *machines) | 138 | void machines__exit(struct machines *machines) |
139 | { | 139 | { |
140 | machine__exit(&machines->host); | 140 | machine__exit(&machines->host); |
141 | /* XXX exit guest */ | 141 | /* XXX exit guest */ |
142 | } | 142 | } |
143 | 143 | ||
144 | struct machine *machines__add(struct machines *machines, pid_t pid, | 144 | struct machine *machines__add(struct machines *machines, pid_t pid, |
145 | const char *root_dir) | 145 | const char *root_dir) |
146 | { | 146 | { |
147 | struct rb_node **p = &machines->guests.rb_node; | 147 | struct rb_node **p = &machines->guests.rb_node; |
148 | struct rb_node *parent = NULL; | 148 | struct rb_node *parent = NULL; |
149 | struct machine *pos, *machine = malloc(sizeof(*machine)); | 149 | struct machine *pos, *machine = malloc(sizeof(*machine)); |
150 | 150 | ||
151 | if (machine == NULL) | 151 | if (machine == NULL) |
152 | return NULL; | 152 | return NULL; |
153 | 153 | ||
154 | if (machine__init(machine, root_dir, pid) != 0) { | 154 | if (machine__init(machine, root_dir, pid) != 0) { |
155 | free(machine); | 155 | free(machine); |
156 | return NULL; | 156 | return NULL; |
157 | } | 157 | } |
158 | 158 | ||
159 | machine->symbol_filter = machines->symbol_filter; | 159 | machine->symbol_filter = machines->symbol_filter; |
160 | 160 | ||
161 | while (*p != NULL) { | 161 | while (*p != NULL) { |
162 | parent = *p; | 162 | parent = *p; |
163 | pos = rb_entry(parent, struct machine, rb_node); | 163 | pos = rb_entry(parent, struct machine, rb_node); |
164 | if (pid < pos->pid) | 164 | if (pid < pos->pid) |
165 | p = &(*p)->rb_left; | 165 | p = &(*p)->rb_left; |
166 | else | 166 | else |
167 | p = &(*p)->rb_right; | 167 | p = &(*p)->rb_right; |
168 | } | 168 | } |
169 | 169 | ||
170 | rb_link_node(&machine->rb_node, parent, p); | 170 | rb_link_node(&machine->rb_node, parent, p); |
171 | rb_insert_color(&machine->rb_node, &machines->guests); | 171 | rb_insert_color(&machine->rb_node, &machines->guests); |
172 | 172 | ||
173 | return machine; | 173 | return machine; |
174 | } | 174 | } |
175 | 175 | ||
176 | void machines__set_symbol_filter(struct machines *machines, | 176 | void machines__set_symbol_filter(struct machines *machines, |
177 | symbol_filter_t symbol_filter) | 177 | symbol_filter_t symbol_filter) |
178 | { | 178 | { |
179 | struct rb_node *nd; | 179 | struct rb_node *nd; |
180 | 180 | ||
181 | machines->symbol_filter = symbol_filter; | 181 | machines->symbol_filter = symbol_filter; |
182 | machines->host.symbol_filter = symbol_filter; | 182 | machines->host.symbol_filter = symbol_filter; |
183 | 183 | ||
184 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | 184 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
185 | struct machine *machine = rb_entry(nd, struct machine, rb_node); | 185 | struct machine *machine = rb_entry(nd, struct machine, rb_node); |
186 | 186 | ||
187 | machine->symbol_filter = symbol_filter; | 187 | machine->symbol_filter = symbol_filter; |
188 | } | 188 | } |
189 | } | 189 | } |
190 | 190 | ||
191 | void machines__set_comm_exec(struct machines *machines, bool comm_exec) | 191 | void machines__set_comm_exec(struct machines *machines, bool comm_exec) |
192 | { | 192 | { |
193 | struct rb_node *nd; | 193 | struct rb_node *nd; |
194 | 194 | ||
195 | machines->host.comm_exec = comm_exec; | 195 | machines->host.comm_exec = comm_exec; |
196 | 196 | ||
197 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | 197 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
198 | struct machine *machine = rb_entry(nd, struct machine, rb_node); | 198 | struct machine *machine = rb_entry(nd, struct machine, rb_node); |
199 | 199 | ||
200 | machine->comm_exec = comm_exec; | 200 | machine->comm_exec = comm_exec; |
201 | } | 201 | } |
202 | } | 202 | } |
203 | 203 | ||
204 | struct machine *machines__find(struct machines *machines, pid_t pid) | 204 | struct machine *machines__find(struct machines *machines, pid_t pid) |
205 | { | 205 | { |
206 | struct rb_node **p = &machines->guests.rb_node; | 206 | struct rb_node **p = &machines->guests.rb_node; |
207 | struct rb_node *parent = NULL; | 207 | struct rb_node *parent = NULL; |
208 | struct machine *machine; | 208 | struct machine *machine; |
209 | struct machine *default_machine = NULL; | 209 | struct machine *default_machine = NULL; |
210 | 210 | ||
211 | if (pid == HOST_KERNEL_ID) | 211 | if (pid == HOST_KERNEL_ID) |
212 | return &machines->host; | 212 | return &machines->host; |
213 | 213 | ||
214 | while (*p != NULL) { | 214 | while (*p != NULL) { |
215 | parent = *p; | 215 | parent = *p; |
216 | machine = rb_entry(parent, struct machine, rb_node); | 216 | machine = rb_entry(parent, struct machine, rb_node); |
217 | if (pid < machine->pid) | 217 | if (pid < machine->pid) |
218 | p = &(*p)->rb_left; | 218 | p = &(*p)->rb_left; |
219 | else if (pid > machine->pid) | 219 | else if (pid > machine->pid) |
220 | p = &(*p)->rb_right; | 220 | p = &(*p)->rb_right; |
221 | else | 221 | else |
222 | return machine; | 222 | return machine; |
223 | if (!machine->pid) | 223 | if (!machine->pid) |
224 | default_machine = machine; | 224 | default_machine = machine; |
225 | } | 225 | } |
226 | 226 | ||
227 | return default_machine; | 227 | return default_machine; |
228 | } | 228 | } |
229 | 229 | ||
230 | struct machine *machines__findnew(struct machines *machines, pid_t pid) | 230 | struct machine *machines__findnew(struct machines *machines, pid_t pid) |
231 | { | 231 | { |
232 | char path[PATH_MAX]; | 232 | char path[PATH_MAX]; |
233 | const char *root_dir = ""; | 233 | const char *root_dir = ""; |
234 | struct machine *machine = machines__find(machines, pid); | 234 | struct machine *machine = machines__find(machines, pid); |
235 | 235 | ||
236 | if (machine && (machine->pid == pid)) | 236 | if (machine && (machine->pid == pid)) |
237 | goto out; | 237 | goto out; |
238 | 238 | ||
239 | if ((pid != HOST_KERNEL_ID) && | 239 | if ((pid != HOST_KERNEL_ID) && |
240 | (pid != DEFAULT_GUEST_KERNEL_ID) && | 240 | (pid != DEFAULT_GUEST_KERNEL_ID) && |
241 | (symbol_conf.guestmount)) { | 241 | (symbol_conf.guestmount)) { |
242 | sprintf(path, "%s/%d", symbol_conf.guestmount, pid); | 242 | sprintf(path, "%s/%d", symbol_conf.guestmount, pid); |
243 | if (access(path, R_OK)) { | 243 | if (access(path, R_OK)) { |
244 | static struct strlist *seen; | 244 | static struct strlist *seen; |
245 | 245 | ||
246 | if (!seen) | 246 | if (!seen) |
247 | seen = strlist__new(true, NULL); | 247 | seen = strlist__new(true, NULL); |
248 | 248 | ||
249 | if (!strlist__has_entry(seen, path)) { | 249 | if (!strlist__has_entry(seen, path)) { |
250 | pr_err("Can't access file %s\n", path); | 250 | pr_err("Can't access file %s\n", path); |
251 | strlist__add(seen, path); | 251 | strlist__add(seen, path); |
252 | } | 252 | } |
253 | machine = NULL; | 253 | machine = NULL; |
254 | goto out; | 254 | goto out; |
255 | } | 255 | } |
256 | root_dir = path; | 256 | root_dir = path; |
257 | } | 257 | } |
258 | 258 | ||
259 | machine = machines__add(machines, pid, root_dir); | 259 | machine = machines__add(machines, pid, root_dir); |
260 | out: | 260 | out: |
261 | return machine; | 261 | return machine; |
262 | } | 262 | } |
263 | 263 | ||
264 | void machines__process_guests(struct machines *machines, | 264 | void machines__process_guests(struct machines *machines, |
265 | machine__process_t process, void *data) | 265 | machine__process_t process, void *data) |
266 | { | 266 | { |
267 | struct rb_node *nd; | 267 | struct rb_node *nd; |
268 | 268 | ||
269 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | 269 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
270 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 270 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
271 | process(pos, data); | 271 | process(pos, data); |
272 | } | 272 | } |
273 | } | 273 | } |
274 | 274 | ||
275 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size) | 275 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size) |
276 | { | 276 | { |
277 | if (machine__is_host(machine)) | 277 | if (machine__is_host(machine)) |
278 | snprintf(bf, size, "[%s]", "kernel.kallsyms"); | 278 | snprintf(bf, size, "[%s]", "kernel.kallsyms"); |
279 | else if (machine__is_default_guest(machine)) | 279 | else if (machine__is_default_guest(machine)) |
280 | snprintf(bf, size, "[%s]", "guest.kernel.kallsyms"); | 280 | snprintf(bf, size, "[%s]", "guest.kernel.kallsyms"); |
281 | else { | 281 | else { |
282 | snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", | 282 | snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", |
283 | machine->pid); | 283 | machine->pid); |
284 | } | 284 | } |
285 | 285 | ||
286 | return bf; | 286 | return bf; |
287 | } | 287 | } |
288 | 288 | ||
289 | void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) | 289 | void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) |
290 | { | 290 | { |
291 | struct rb_node *node; | 291 | struct rb_node *node; |
292 | struct machine *machine; | 292 | struct machine *machine; |
293 | 293 | ||
294 | machines->host.id_hdr_size = id_hdr_size; | 294 | machines->host.id_hdr_size = id_hdr_size; |
295 | 295 | ||
296 | for (node = rb_first(&machines->guests); node; node = rb_next(node)) { | 296 | for (node = rb_first(&machines->guests); node; node = rb_next(node)) { |
297 | machine = rb_entry(node, struct machine, rb_node); | 297 | machine = rb_entry(node, struct machine, rb_node); |
298 | machine->id_hdr_size = id_hdr_size; | 298 | machine->id_hdr_size = id_hdr_size; |
299 | } | 299 | } |
300 | 300 | ||
301 | return; | 301 | return; |
302 | } | 302 | } |
303 | 303 | ||
304 | static void machine__update_thread_pid(struct machine *machine, | 304 | static void machine__update_thread_pid(struct machine *machine, |
305 | struct thread *th, pid_t pid) | 305 | struct thread *th, pid_t pid) |
306 | { | 306 | { |
307 | struct thread *leader; | 307 | struct thread *leader; |
308 | 308 | ||
309 | if (pid == th->pid_ || pid == -1 || th->pid_ != -1) | 309 | if (pid == th->pid_ || pid == -1 || th->pid_ != -1) |
310 | return; | 310 | return; |
311 | 311 | ||
312 | th->pid_ = pid; | 312 | th->pid_ = pid; |
313 | 313 | ||
314 | if (th->pid_ == th->tid) | 314 | if (th->pid_ == th->tid) |
315 | return; | 315 | return; |
316 | 316 | ||
317 | leader = machine__findnew_thread(machine, th->pid_, th->pid_); | 317 | leader = machine__findnew_thread(machine, th->pid_, th->pid_); |
318 | if (!leader) | 318 | if (!leader) |
319 | goto out_err; | 319 | goto out_err; |
320 | 320 | ||
321 | if (!leader->mg) | 321 | if (!leader->mg) |
322 | leader->mg = map_groups__new(machine); | 322 | leader->mg = map_groups__new(machine); |
323 | 323 | ||
324 | if (!leader->mg) | 324 | if (!leader->mg) |
325 | goto out_err; | 325 | goto out_err; |
326 | 326 | ||
327 | if (th->mg == leader->mg) | 327 | if (th->mg == leader->mg) |
328 | return; | 328 | return; |
329 | 329 | ||
330 | if (th->mg) { | 330 | if (th->mg) { |
331 | /* | 331 | /* |
332 | * Maps are created from MMAP events which provide the pid and | 332 | * Maps are created from MMAP events which provide the pid and |
333 | * tid. Consequently there never should be any maps on a thread | 333 | * tid. Consequently there never should be any maps on a thread |
334 | * with an unknown pid. Just print an error if there are. | 334 | * with an unknown pid. Just print an error if there are. |
335 | */ | 335 | */ |
336 | if (!map_groups__empty(th->mg)) | 336 | if (!map_groups__empty(th->mg)) |
337 | pr_err("Discarding thread maps for %d:%d\n", | 337 | pr_err("Discarding thread maps for %d:%d\n", |
338 | th->pid_, th->tid); | 338 | th->pid_, th->tid); |
339 | map_groups__delete(th->mg); | 339 | map_groups__delete(th->mg); |
340 | } | 340 | } |
341 | 341 | ||
342 | th->mg = map_groups__get(leader->mg); | 342 | th->mg = map_groups__get(leader->mg); |
343 | 343 | ||
344 | return; | 344 | return; |
345 | 345 | ||
346 | out_err: | 346 | out_err: |
347 | pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); | 347 | pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); |
348 | } | 348 | } |
349 | 349 | ||
350 | static struct thread *__machine__findnew_thread(struct machine *machine, | 350 | static struct thread *__machine__findnew_thread(struct machine *machine, |
351 | pid_t pid, pid_t tid, | 351 | pid_t pid, pid_t tid, |
352 | bool create) | 352 | bool create) |
353 | { | 353 | { |
354 | struct rb_node **p = &machine->threads.rb_node; | 354 | struct rb_node **p = &machine->threads.rb_node; |
355 | struct rb_node *parent = NULL; | 355 | struct rb_node *parent = NULL; |
356 | struct thread *th; | 356 | struct thread *th; |
357 | 357 | ||
358 | /* | 358 | /* |
359 | * Front-end cache - TID lookups come in blocks, | 359 | * Front-end cache - TID lookups come in blocks, |
360 | * so most of the time we dont have to look up | 360 | * so most of the time we dont have to look up |
361 | * the full rbtree: | 361 | * the full rbtree: |
362 | */ | 362 | */ |
363 | th = machine->last_match; | 363 | th = machine->last_match; |
364 | if (th && th->tid == tid) { | 364 | if (th && th->tid == tid) { |
365 | machine__update_thread_pid(machine, th, pid); | 365 | machine__update_thread_pid(machine, th, pid); |
366 | return th; | 366 | return th; |
367 | } | 367 | } |
368 | 368 | ||
369 | while (*p != NULL) { | 369 | while (*p != NULL) { |
370 | parent = *p; | 370 | parent = *p; |
371 | th = rb_entry(parent, struct thread, rb_node); | 371 | th = rb_entry(parent, struct thread, rb_node); |
372 | 372 | ||
373 | if (th->tid == tid) { | 373 | if (th->tid == tid) { |
374 | machine->last_match = th; | 374 | machine->last_match = th; |
375 | machine__update_thread_pid(machine, th, pid); | 375 | machine__update_thread_pid(machine, th, pid); |
376 | return th; | 376 | return th; |
377 | } | 377 | } |
378 | 378 | ||
379 | if (tid < th->tid) | 379 | if (tid < th->tid) |
380 | p = &(*p)->rb_left; | 380 | p = &(*p)->rb_left; |
381 | else | 381 | else |
382 | p = &(*p)->rb_right; | 382 | p = &(*p)->rb_right; |
383 | } | 383 | } |
384 | 384 | ||
385 | if (!create) | 385 | if (!create) |
386 | return NULL; | 386 | return NULL; |
387 | 387 | ||
388 | th = thread__new(pid, tid); | 388 | th = thread__new(pid, tid); |
389 | if (th != NULL) { | 389 | if (th != NULL) { |
390 | rb_link_node(&th->rb_node, parent, p); | 390 | rb_link_node(&th->rb_node, parent, p); |
391 | rb_insert_color(&th->rb_node, &machine->threads); | 391 | rb_insert_color(&th->rb_node, &machine->threads); |
392 | machine->last_match = th; | ||
393 | 392 | ||
394 | /* | 393 | /* |
395 | * We have to initialize map_groups separately | 394 | * We have to initialize map_groups separately |
396 | * after rb tree is updated. | 395 | * after rb tree is updated. |
397 | * | 396 | * |
398 | * The reason is that we call machine__findnew_thread | 397 | * The reason is that we call machine__findnew_thread |
399 | * within thread__init_map_groups to find the thread | 398 | * within thread__init_map_groups to find the thread |
400 | * leader and that would screwed the rb tree. | 399 | * leader and that would screwed the rb tree. |
401 | */ | 400 | */ |
402 | if (thread__init_map_groups(th, machine)) { | 401 | if (thread__init_map_groups(th, machine)) { |
402 | rb_erase(&th->rb_node, &machine->threads); | ||
403 | thread__delete(th); | 403 | thread__delete(th); |
404 | return NULL; | 404 | return NULL; |
405 | } | 405 | } |
406 | |||
407 | machine->last_match = th; | ||
406 | } | 408 | } |
407 | 409 | ||
408 | return th; | 410 | return th; |
409 | } | 411 | } |
410 | 412 | ||
411 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, | 413 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, |
412 | pid_t tid) | 414 | pid_t tid) |
413 | { | 415 | { |
414 | return __machine__findnew_thread(machine, pid, tid, true); | 416 | return __machine__findnew_thread(machine, pid, tid, true); |
415 | } | 417 | } |
416 | 418 | ||
417 | struct thread *machine__find_thread(struct machine *machine, pid_t pid, | 419 | struct thread *machine__find_thread(struct machine *machine, pid_t pid, |
418 | pid_t tid) | 420 | pid_t tid) |
419 | { | 421 | { |
420 | return __machine__findnew_thread(machine, pid, tid, false); | 422 | return __machine__findnew_thread(machine, pid, tid, false); |
421 | } | 423 | } |
422 | 424 | ||
423 | struct comm *machine__thread_exec_comm(struct machine *machine, | 425 | struct comm *machine__thread_exec_comm(struct machine *machine, |
424 | struct thread *thread) | 426 | struct thread *thread) |
425 | { | 427 | { |
426 | if (machine->comm_exec) | 428 | if (machine->comm_exec) |
427 | return thread__exec_comm(thread); | 429 | return thread__exec_comm(thread); |
428 | else | 430 | else |
429 | return thread__comm(thread); | 431 | return thread__comm(thread); |
430 | } | 432 | } |
431 | 433 | ||
432 | int machine__process_comm_event(struct machine *machine, union perf_event *event, | 434 | int machine__process_comm_event(struct machine *machine, union perf_event *event, |
433 | struct perf_sample *sample) | 435 | struct perf_sample *sample) |
434 | { | 436 | { |
435 | struct thread *thread = machine__findnew_thread(machine, | 437 | struct thread *thread = machine__findnew_thread(machine, |
436 | event->comm.pid, | 438 | event->comm.pid, |
437 | event->comm.tid); | 439 | event->comm.tid); |
438 | bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; | 440 | bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; |
439 | 441 | ||
440 | if (exec) | 442 | if (exec) |
441 | machine->comm_exec = true; | 443 | machine->comm_exec = true; |
442 | 444 | ||
443 | if (dump_trace) | 445 | if (dump_trace) |
444 | perf_event__fprintf_comm(event, stdout); | 446 | perf_event__fprintf_comm(event, stdout); |
445 | 447 | ||
446 | if (thread == NULL || | 448 | if (thread == NULL || |
447 | __thread__set_comm(thread, event->comm.comm, sample->time, exec)) { | 449 | __thread__set_comm(thread, event->comm.comm, sample->time, exec)) { |
448 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); | 450 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); |
449 | return -1; | 451 | return -1; |
450 | } | 452 | } |
451 | 453 | ||
452 | return 0; | 454 | return 0; |
453 | } | 455 | } |
454 | 456 | ||
455 | int machine__process_lost_event(struct machine *machine __maybe_unused, | 457 | int machine__process_lost_event(struct machine *machine __maybe_unused, |
456 | union perf_event *event, struct perf_sample *sample __maybe_unused) | 458 | union perf_event *event, struct perf_sample *sample __maybe_unused) |
457 | { | 459 | { |
458 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", | 460 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", |
459 | event->lost.id, event->lost.lost); | 461 | event->lost.id, event->lost.lost); |
460 | return 0; | 462 | return 0; |
461 | } | 463 | } |
462 | 464 | ||
463 | struct map *machine__new_module(struct machine *machine, u64 start, | 465 | struct map *machine__new_module(struct machine *machine, u64 start, |
464 | const char *filename) | 466 | const char *filename) |
465 | { | 467 | { |
466 | struct map *map; | 468 | struct map *map; |
467 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); | 469 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); |
468 | bool compressed; | 470 | bool compressed; |
469 | 471 | ||
470 | if (dso == NULL) | 472 | if (dso == NULL) |
471 | return NULL; | 473 | return NULL; |
472 | 474 | ||
473 | map = map__new2(start, dso, MAP__FUNCTION); | 475 | map = map__new2(start, dso, MAP__FUNCTION); |
474 | if (map == NULL) | 476 | if (map == NULL) |
475 | return NULL; | 477 | return NULL; |
476 | 478 | ||
477 | if (machine__is_host(machine)) | 479 | if (machine__is_host(machine)) |
478 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | 480 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; |
479 | else | 481 | else |
480 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | 482 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; |
481 | 483 | ||
482 | /* _KMODULE_COMP should be next to _KMODULE */ | 484 | /* _KMODULE_COMP should be next to _KMODULE */ |
483 | if (is_kernel_module(filename, &compressed) && compressed) | 485 | if (is_kernel_module(filename, &compressed) && compressed) |
484 | dso->symtab_type++; | 486 | dso->symtab_type++; |
485 | 487 | ||
486 | map_groups__insert(&machine->kmaps, map); | 488 | map_groups__insert(&machine->kmaps, map); |
487 | return map; | 489 | return map; |
488 | } | 490 | } |
489 | 491 | ||
490 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) | 492 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) |
491 | { | 493 | { |
492 | struct rb_node *nd; | 494 | struct rb_node *nd; |
493 | size_t ret = __dsos__fprintf(&machines->host.kernel_dsos.head, fp) + | 495 | size_t ret = __dsos__fprintf(&machines->host.kernel_dsos.head, fp) + |
494 | __dsos__fprintf(&machines->host.user_dsos.head, fp); | 496 | __dsos__fprintf(&machines->host.user_dsos.head, fp); |
495 | 497 | ||
496 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | 498 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
497 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 499 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
498 | ret += __dsos__fprintf(&pos->kernel_dsos.head, fp); | 500 | ret += __dsos__fprintf(&pos->kernel_dsos.head, fp); |
499 | ret += __dsos__fprintf(&pos->user_dsos.head, fp); | 501 | ret += __dsos__fprintf(&pos->user_dsos.head, fp); |
500 | } | 502 | } |
501 | 503 | ||
502 | return ret; | 504 | return ret; |
503 | } | 505 | } |
504 | 506 | ||
505 | size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, | 507 | size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, |
506 | bool (skip)(struct dso *dso, int parm), int parm) | 508 | bool (skip)(struct dso *dso, int parm), int parm) |
507 | { | 509 | { |
508 | return __dsos__fprintf_buildid(&m->kernel_dsos.head, fp, skip, parm) + | 510 | return __dsos__fprintf_buildid(&m->kernel_dsos.head, fp, skip, parm) + |
509 | __dsos__fprintf_buildid(&m->user_dsos.head, fp, skip, parm); | 511 | __dsos__fprintf_buildid(&m->user_dsos.head, fp, skip, parm); |
510 | } | 512 | } |
511 | 513 | ||
512 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, | 514 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, |
513 | bool (skip)(struct dso *dso, int parm), int parm) | 515 | bool (skip)(struct dso *dso, int parm), int parm) |
514 | { | 516 | { |
515 | struct rb_node *nd; | 517 | struct rb_node *nd; |
516 | size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); | 518 | size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); |
517 | 519 | ||
518 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | 520 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
519 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 521 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
520 | ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); | 522 | ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); |
521 | } | 523 | } |
522 | return ret; | 524 | return ret; |
523 | } | 525 | } |
524 | 526 | ||
525 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) | 527 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) |
526 | { | 528 | { |
527 | int i; | 529 | int i; |
528 | size_t printed = 0; | 530 | size_t printed = 0; |
529 | struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; | 531 | struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; |
530 | 532 | ||
531 | if (kdso->has_build_id) { | 533 | if (kdso->has_build_id) { |
532 | char filename[PATH_MAX]; | 534 | char filename[PATH_MAX]; |
533 | if (dso__build_id_filename(kdso, filename, sizeof(filename))) | 535 | if (dso__build_id_filename(kdso, filename, sizeof(filename))) |
534 | printed += fprintf(fp, "[0] %s\n", filename); | 536 | printed += fprintf(fp, "[0] %s\n", filename); |
535 | } | 537 | } |
536 | 538 | ||
537 | for (i = 0; i < vmlinux_path__nr_entries; ++i) | 539 | for (i = 0; i < vmlinux_path__nr_entries; ++i) |
538 | printed += fprintf(fp, "[%d] %s\n", | 540 | printed += fprintf(fp, "[%d] %s\n", |
539 | i + kdso->has_build_id, vmlinux_path[i]); | 541 | i + kdso->has_build_id, vmlinux_path[i]); |
540 | 542 | ||
541 | return printed; | 543 | return printed; |
542 | } | 544 | } |
543 | 545 | ||
544 | size_t machine__fprintf(struct machine *machine, FILE *fp) | 546 | size_t machine__fprintf(struct machine *machine, FILE *fp) |
545 | { | 547 | { |
546 | size_t ret = 0; | 548 | size_t ret = 0; |
547 | struct rb_node *nd; | 549 | struct rb_node *nd; |
548 | 550 | ||
549 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | 551 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { |
550 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | 552 | struct thread *pos = rb_entry(nd, struct thread, rb_node); |
551 | 553 | ||
552 | ret += thread__fprintf(pos, fp); | 554 | ret += thread__fprintf(pos, fp); |
553 | } | 555 | } |
554 | 556 | ||
555 | return ret; | 557 | return ret; |
556 | } | 558 | } |
557 | 559 | ||
558 | static struct dso *machine__get_kernel(struct machine *machine) | 560 | static struct dso *machine__get_kernel(struct machine *machine) |
559 | { | 561 | { |
560 | const char *vmlinux_name = NULL; | 562 | const char *vmlinux_name = NULL; |
561 | struct dso *kernel; | 563 | struct dso *kernel; |
562 | 564 | ||
563 | if (machine__is_host(machine)) { | 565 | if (machine__is_host(machine)) { |
564 | vmlinux_name = symbol_conf.vmlinux_name; | 566 | vmlinux_name = symbol_conf.vmlinux_name; |
565 | if (!vmlinux_name) | 567 | if (!vmlinux_name) |
566 | vmlinux_name = "[kernel.kallsyms]"; | 568 | vmlinux_name = "[kernel.kallsyms]"; |
567 | 569 | ||
568 | kernel = dso__kernel_findnew(machine, vmlinux_name, | 570 | kernel = dso__kernel_findnew(machine, vmlinux_name, |
569 | "[kernel]", | 571 | "[kernel]", |
570 | DSO_TYPE_KERNEL); | 572 | DSO_TYPE_KERNEL); |
571 | } else { | 573 | } else { |
572 | char bf[PATH_MAX]; | 574 | char bf[PATH_MAX]; |
573 | 575 | ||
574 | if (machine__is_default_guest(machine)) | 576 | if (machine__is_default_guest(machine)) |
575 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | 577 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; |
576 | if (!vmlinux_name) | 578 | if (!vmlinux_name) |
577 | vmlinux_name = machine__mmap_name(machine, bf, | 579 | vmlinux_name = machine__mmap_name(machine, bf, |
578 | sizeof(bf)); | 580 | sizeof(bf)); |
579 | 581 | ||
580 | kernel = dso__kernel_findnew(machine, vmlinux_name, | 582 | kernel = dso__kernel_findnew(machine, vmlinux_name, |
581 | "[guest.kernel]", | 583 | "[guest.kernel]", |
582 | DSO_TYPE_GUEST_KERNEL); | 584 | DSO_TYPE_GUEST_KERNEL); |
583 | } | 585 | } |
584 | 586 | ||
585 | if (kernel != NULL && (!kernel->has_build_id)) | 587 | if (kernel != NULL && (!kernel->has_build_id)) |
586 | dso__read_running_kernel_build_id(kernel, machine); | 588 | dso__read_running_kernel_build_id(kernel, machine); |
587 | 589 | ||
588 | return kernel; | 590 | return kernel; |
589 | } | 591 | } |
590 | 592 | ||
591 | struct process_args { | 593 | struct process_args { |
592 | u64 start; | 594 | u64 start; |
593 | }; | 595 | }; |
594 | 596 | ||
595 | static void machine__get_kallsyms_filename(struct machine *machine, char *buf, | 597 | static void machine__get_kallsyms_filename(struct machine *machine, char *buf, |
596 | size_t bufsz) | 598 | size_t bufsz) |
597 | { | 599 | { |
598 | if (machine__is_default_guest(machine)) | 600 | if (machine__is_default_guest(machine)) |
599 | scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms); | 601 | scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms); |
600 | else | 602 | else |
601 | scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); | 603 | scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); |
602 | } | 604 | } |
603 | 605 | ||
604 | const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; | 606 | const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; |
605 | 607 | ||
606 | /* Figure out the start address of kernel map from /proc/kallsyms. | 608 | /* Figure out the start address of kernel map from /proc/kallsyms. |
607 | * Returns the name of the start symbol in *symbol_name. Pass in NULL as | 609 | * Returns the name of the start symbol in *symbol_name. Pass in NULL as |
608 | * symbol_name if it's not that important. | 610 | * symbol_name if it's not that important. |
609 | */ | 611 | */ |
610 | static u64 machine__get_running_kernel_start(struct machine *machine, | 612 | static u64 machine__get_running_kernel_start(struct machine *machine, |
611 | const char **symbol_name) | 613 | const char **symbol_name) |
612 | { | 614 | { |
613 | char filename[PATH_MAX]; | 615 | char filename[PATH_MAX]; |
614 | int i; | 616 | int i; |
615 | const char *name; | 617 | const char *name; |
616 | u64 addr = 0; | 618 | u64 addr = 0; |
617 | 619 | ||
618 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); | 620 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); |
619 | 621 | ||
620 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 622 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
621 | return 0; | 623 | return 0; |
622 | 624 | ||
623 | for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { | 625 | for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { |
624 | addr = kallsyms__get_function_start(filename, name); | 626 | addr = kallsyms__get_function_start(filename, name); |
625 | if (addr) | 627 | if (addr) |
626 | break; | 628 | break; |
627 | } | 629 | } |
628 | 630 | ||
629 | if (symbol_name) | 631 | if (symbol_name) |
630 | *symbol_name = name; | 632 | *symbol_name = name; |
631 | 633 | ||
632 | return addr; | 634 | return addr; |
633 | } | 635 | } |
634 | 636 | ||
635 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | 637 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) |
636 | { | 638 | { |
637 | enum map_type type; | 639 | enum map_type type; |
638 | u64 start = machine__get_running_kernel_start(machine, NULL); | 640 | u64 start = machine__get_running_kernel_start(machine, NULL); |
639 | 641 | ||
640 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 642 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
641 | struct kmap *kmap; | 643 | struct kmap *kmap; |
642 | 644 | ||
643 | machine->vmlinux_maps[type] = map__new2(start, kernel, type); | 645 | machine->vmlinux_maps[type] = map__new2(start, kernel, type); |
644 | if (machine->vmlinux_maps[type] == NULL) | 646 | if (machine->vmlinux_maps[type] == NULL) |
645 | return -1; | 647 | return -1; |
646 | 648 | ||
647 | machine->vmlinux_maps[type]->map_ip = | 649 | machine->vmlinux_maps[type]->map_ip = |
648 | machine->vmlinux_maps[type]->unmap_ip = | 650 | machine->vmlinux_maps[type]->unmap_ip = |
649 | identity__map_ip; | 651 | identity__map_ip; |
650 | kmap = map__kmap(machine->vmlinux_maps[type]); | 652 | kmap = map__kmap(machine->vmlinux_maps[type]); |
651 | kmap->kmaps = &machine->kmaps; | 653 | kmap->kmaps = &machine->kmaps; |
652 | map_groups__insert(&machine->kmaps, | 654 | map_groups__insert(&machine->kmaps, |
653 | machine->vmlinux_maps[type]); | 655 | machine->vmlinux_maps[type]); |
654 | } | 656 | } |
655 | 657 | ||
656 | return 0; | 658 | return 0; |
657 | } | 659 | } |
658 | 660 | ||
659 | void machine__destroy_kernel_maps(struct machine *machine) | 661 | void machine__destroy_kernel_maps(struct machine *machine) |
660 | { | 662 | { |
661 | enum map_type type; | 663 | enum map_type type; |
662 | 664 | ||
663 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 665 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
664 | struct kmap *kmap; | 666 | struct kmap *kmap; |
665 | 667 | ||
666 | if (machine->vmlinux_maps[type] == NULL) | 668 | if (machine->vmlinux_maps[type] == NULL) |
667 | continue; | 669 | continue; |
668 | 670 | ||
669 | kmap = map__kmap(machine->vmlinux_maps[type]); | 671 | kmap = map__kmap(machine->vmlinux_maps[type]); |
670 | map_groups__remove(&machine->kmaps, | 672 | map_groups__remove(&machine->kmaps, |
671 | machine->vmlinux_maps[type]); | 673 | machine->vmlinux_maps[type]); |
672 | if (kmap->ref_reloc_sym) { | 674 | if (kmap->ref_reloc_sym) { |
673 | /* | 675 | /* |
674 | * ref_reloc_sym is shared among all maps, so free just | 676 | * ref_reloc_sym is shared among all maps, so free just |
675 | * on one of them. | 677 | * on one of them. |
676 | */ | 678 | */ |
677 | if (type == MAP__FUNCTION) { | 679 | if (type == MAP__FUNCTION) { |
678 | zfree((char **)&kmap->ref_reloc_sym->name); | 680 | zfree((char **)&kmap->ref_reloc_sym->name); |
679 | zfree(&kmap->ref_reloc_sym); | 681 | zfree(&kmap->ref_reloc_sym); |
680 | } else | 682 | } else |
681 | kmap->ref_reloc_sym = NULL; | 683 | kmap->ref_reloc_sym = NULL; |
682 | } | 684 | } |
683 | 685 | ||
684 | map__delete(machine->vmlinux_maps[type]); | 686 | map__delete(machine->vmlinux_maps[type]); |
685 | machine->vmlinux_maps[type] = NULL; | 687 | machine->vmlinux_maps[type] = NULL; |
686 | } | 688 | } |
687 | } | 689 | } |
688 | 690 | ||
689 | int machines__create_guest_kernel_maps(struct machines *machines) | 691 | int machines__create_guest_kernel_maps(struct machines *machines) |
690 | { | 692 | { |
691 | int ret = 0; | 693 | int ret = 0; |
692 | struct dirent **namelist = NULL; | 694 | struct dirent **namelist = NULL; |
693 | int i, items = 0; | 695 | int i, items = 0; |
694 | char path[PATH_MAX]; | 696 | char path[PATH_MAX]; |
695 | pid_t pid; | 697 | pid_t pid; |
696 | char *endp; | 698 | char *endp; |
697 | 699 | ||
698 | if (symbol_conf.default_guest_vmlinux_name || | 700 | if (symbol_conf.default_guest_vmlinux_name || |
699 | symbol_conf.default_guest_modules || | 701 | symbol_conf.default_guest_modules || |
700 | symbol_conf.default_guest_kallsyms) { | 702 | symbol_conf.default_guest_kallsyms) { |
701 | machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); | 703 | machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); |
702 | } | 704 | } |
703 | 705 | ||
704 | if (symbol_conf.guestmount) { | 706 | if (symbol_conf.guestmount) { |
705 | items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); | 707 | items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); |
706 | if (items <= 0) | 708 | if (items <= 0) |
707 | return -ENOENT; | 709 | return -ENOENT; |
708 | for (i = 0; i < items; i++) { | 710 | for (i = 0; i < items; i++) { |
709 | if (!isdigit(namelist[i]->d_name[0])) { | 711 | if (!isdigit(namelist[i]->d_name[0])) { |
710 | /* Filter out . and .. */ | 712 | /* Filter out . and .. */ |
711 | continue; | 713 | continue; |
712 | } | 714 | } |
713 | pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); | 715 | pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); |
714 | if ((*endp != '\0') || | 716 | if ((*endp != '\0') || |
715 | (endp == namelist[i]->d_name) || | 717 | (endp == namelist[i]->d_name) || |
716 | (errno == ERANGE)) { | 718 | (errno == ERANGE)) { |
717 | pr_debug("invalid directory (%s). Skipping.\n", | 719 | pr_debug("invalid directory (%s). Skipping.\n", |
718 | namelist[i]->d_name); | 720 | namelist[i]->d_name); |
719 | continue; | 721 | continue; |
720 | } | 722 | } |
721 | sprintf(path, "%s/%s/proc/kallsyms", | 723 | sprintf(path, "%s/%s/proc/kallsyms", |
722 | symbol_conf.guestmount, | 724 | symbol_conf.guestmount, |
723 | namelist[i]->d_name); | 725 | namelist[i]->d_name); |
724 | ret = access(path, R_OK); | 726 | ret = access(path, R_OK); |
725 | if (ret) { | 727 | if (ret) { |
726 | pr_debug("Can't access file %s\n", path); | 728 | pr_debug("Can't access file %s\n", path); |
727 | goto failure; | 729 | goto failure; |
728 | } | 730 | } |
729 | machines__create_kernel_maps(machines, pid); | 731 | machines__create_kernel_maps(machines, pid); |
730 | } | 732 | } |
731 | failure: | 733 | failure: |
732 | free(namelist); | 734 | free(namelist); |
733 | } | 735 | } |
734 | 736 | ||
735 | return ret; | 737 | return ret; |
736 | } | 738 | } |
737 | 739 | ||
738 | void machines__destroy_kernel_maps(struct machines *machines) | 740 | void machines__destroy_kernel_maps(struct machines *machines) |
739 | { | 741 | { |
740 | struct rb_node *next = rb_first(&machines->guests); | 742 | struct rb_node *next = rb_first(&machines->guests); |
741 | 743 | ||
742 | machine__destroy_kernel_maps(&machines->host); | 744 | machine__destroy_kernel_maps(&machines->host); |
743 | 745 | ||
744 | while (next) { | 746 | while (next) { |
745 | struct machine *pos = rb_entry(next, struct machine, rb_node); | 747 | struct machine *pos = rb_entry(next, struct machine, rb_node); |
746 | 748 | ||
747 | next = rb_next(&pos->rb_node); | 749 | next = rb_next(&pos->rb_node); |
748 | rb_erase(&pos->rb_node, &machines->guests); | 750 | rb_erase(&pos->rb_node, &machines->guests); |
749 | machine__delete(pos); | 751 | machine__delete(pos); |
750 | } | 752 | } |
751 | } | 753 | } |
752 | 754 | ||
753 | int machines__create_kernel_maps(struct machines *machines, pid_t pid) | 755 | int machines__create_kernel_maps(struct machines *machines, pid_t pid) |
754 | { | 756 | { |
755 | struct machine *machine = machines__findnew(machines, pid); | 757 | struct machine *machine = machines__findnew(machines, pid); |
756 | 758 | ||
757 | if (machine == NULL) | 759 | if (machine == NULL) |
758 | return -1; | 760 | return -1; |
759 | 761 | ||
760 | return machine__create_kernel_maps(machine); | 762 | return machine__create_kernel_maps(machine); |
761 | } | 763 | } |
762 | 764 | ||
763 | int machine__load_kallsyms(struct machine *machine, const char *filename, | 765 | int machine__load_kallsyms(struct machine *machine, const char *filename, |
764 | enum map_type type, symbol_filter_t filter) | 766 | enum map_type type, symbol_filter_t filter) |
765 | { | 767 | { |
766 | struct map *map = machine->vmlinux_maps[type]; | 768 | struct map *map = machine->vmlinux_maps[type]; |
767 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | 769 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); |
768 | 770 | ||
769 | if (ret > 0) { | 771 | if (ret > 0) { |
770 | dso__set_loaded(map->dso, type); | 772 | dso__set_loaded(map->dso, type); |
771 | /* | 773 | /* |
772 | * Since /proc/kallsyms will have multiple sessions for the | 774 | * Since /proc/kallsyms will have multiple sessions for the |
773 | * kernel, with modules between them, fixup the end of all | 775 | * kernel, with modules between them, fixup the end of all |
774 | * sections. | 776 | * sections. |
775 | */ | 777 | */ |
776 | __map_groups__fixup_end(&machine->kmaps, type); | 778 | __map_groups__fixup_end(&machine->kmaps, type); |
777 | } | 779 | } |
778 | 780 | ||
779 | return ret; | 781 | return ret; |
780 | } | 782 | } |
781 | 783 | ||
782 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | 784 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
783 | symbol_filter_t filter) | 785 | symbol_filter_t filter) |
784 | { | 786 | { |
785 | struct map *map = machine->vmlinux_maps[type]; | 787 | struct map *map = machine->vmlinux_maps[type]; |
786 | int ret = dso__load_vmlinux_path(map->dso, map, filter); | 788 | int ret = dso__load_vmlinux_path(map->dso, map, filter); |
787 | 789 | ||
788 | if (ret > 0) | 790 | if (ret > 0) |
789 | dso__set_loaded(map->dso, type); | 791 | dso__set_loaded(map->dso, type); |
790 | 792 | ||
791 | return ret; | 793 | return ret; |
792 | } | 794 | } |
793 | 795 | ||
794 | static void map_groups__fixup_end(struct map_groups *mg) | 796 | static void map_groups__fixup_end(struct map_groups *mg) |
795 | { | 797 | { |
796 | int i; | 798 | int i; |
797 | for (i = 0; i < MAP__NR_TYPES; ++i) | 799 | for (i = 0; i < MAP__NR_TYPES; ++i) |
798 | __map_groups__fixup_end(mg, i); | 800 | __map_groups__fixup_end(mg, i); |
799 | } | 801 | } |
800 | 802 | ||
801 | static char *get_kernel_version(const char *root_dir) | 803 | static char *get_kernel_version(const char *root_dir) |
802 | { | 804 | { |
803 | char version[PATH_MAX]; | 805 | char version[PATH_MAX]; |
804 | FILE *file; | 806 | FILE *file; |
805 | char *name, *tmp; | 807 | char *name, *tmp; |
806 | const char *prefix = "Linux version "; | 808 | const char *prefix = "Linux version "; |
807 | 809 | ||
808 | sprintf(version, "%s/proc/version", root_dir); | 810 | sprintf(version, "%s/proc/version", root_dir); |
809 | file = fopen(version, "r"); | 811 | file = fopen(version, "r"); |
810 | if (!file) | 812 | if (!file) |
811 | return NULL; | 813 | return NULL; |
812 | 814 | ||
813 | version[0] = '\0'; | 815 | version[0] = '\0'; |
814 | tmp = fgets(version, sizeof(version), file); | 816 | tmp = fgets(version, sizeof(version), file); |
815 | fclose(file); | 817 | fclose(file); |
816 | 818 | ||
817 | name = strstr(version, prefix); | 819 | name = strstr(version, prefix); |
818 | if (!name) | 820 | if (!name) |
819 | return NULL; | 821 | return NULL; |
820 | name += strlen(prefix); | 822 | name += strlen(prefix); |
821 | tmp = strchr(name, ' '); | 823 | tmp = strchr(name, ' '); |
822 | if (tmp) | 824 | if (tmp) |
823 | *tmp = '\0'; | 825 | *tmp = '\0'; |
824 | 826 | ||
825 | return strdup(name); | 827 | return strdup(name); |
826 | } | 828 | } |
827 | 829 | ||
828 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | 830 | static int map_groups__set_modules_path_dir(struct map_groups *mg, |
829 | const char *dir_name, int depth) | 831 | const char *dir_name, int depth) |
830 | { | 832 | { |
831 | struct dirent *dent; | 833 | struct dirent *dent; |
832 | DIR *dir = opendir(dir_name); | 834 | DIR *dir = opendir(dir_name); |
833 | int ret = 0; | 835 | int ret = 0; |
834 | 836 | ||
835 | if (!dir) { | 837 | if (!dir) { |
836 | pr_debug("%s: cannot open %s dir\n", __func__, dir_name); | 838 | pr_debug("%s: cannot open %s dir\n", __func__, dir_name); |
837 | return -1; | 839 | return -1; |
838 | } | 840 | } |
839 | 841 | ||
840 | while ((dent = readdir(dir)) != NULL) { | 842 | while ((dent = readdir(dir)) != NULL) { |
841 | char path[PATH_MAX]; | 843 | char path[PATH_MAX]; |
842 | struct stat st; | 844 | struct stat st; |
843 | 845 | ||
844 | /*sshfs might return bad dent->d_type, so we have to stat*/ | 846 | /*sshfs might return bad dent->d_type, so we have to stat*/ |
845 | snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); | 847 | snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); |
846 | if (stat(path, &st)) | 848 | if (stat(path, &st)) |
847 | continue; | 849 | continue; |
848 | 850 | ||
849 | if (S_ISDIR(st.st_mode)) { | 851 | if (S_ISDIR(st.st_mode)) { |
850 | if (!strcmp(dent->d_name, ".") || | 852 | if (!strcmp(dent->d_name, ".") || |
851 | !strcmp(dent->d_name, "..")) | 853 | !strcmp(dent->d_name, "..")) |
852 | continue; | 854 | continue; |
853 | 855 | ||
854 | /* Do not follow top-level source and build symlinks */ | 856 | /* Do not follow top-level source and build symlinks */ |
855 | if (depth == 0) { | 857 | if (depth == 0) { |
856 | if (!strcmp(dent->d_name, "source") || | 858 | if (!strcmp(dent->d_name, "source") || |
857 | !strcmp(dent->d_name, "build")) | 859 | !strcmp(dent->d_name, "build")) |
858 | continue; | 860 | continue; |
859 | } | 861 | } |
860 | 862 | ||
861 | ret = map_groups__set_modules_path_dir(mg, path, | 863 | ret = map_groups__set_modules_path_dir(mg, path, |
862 | depth + 1); | 864 | depth + 1); |
863 | if (ret < 0) | 865 | if (ret < 0) |
864 | goto out; | 866 | goto out; |
865 | } else { | 867 | } else { |
866 | char *dot = strrchr(dent->d_name, '.'), | 868 | char *dot = strrchr(dent->d_name, '.'), |
867 | dso_name[PATH_MAX]; | 869 | dso_name[PATH_MAX]; |
868 | struct map *map; | 870 | struct map *map; |
869 | char *long_name; | 871 | char *long_name; |
870 | 872 | ||
871 | if (dot == NULL) | 873 | if (dot == NULL) |
872 | continue; | 874 | continue; |
873 | 875 | ||
874 | /* On some system, modules are compressed like .ko.gz */ | 876 | /* On some system, modules are compressed like .ko.gz */ |
875 | if (is_supported_compression(dot + 1) && | 877 | if (is_supported_compression(dot + 1) && |
876 | is_kmodule_extension(dot - 2)) | 878 | is_kmodule_extension(dot - 2)) |
877 | dot -= 3; | 879 | dot -= 3; |
878 | 880 | ||
879 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | 881 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", |
880 | (int)(dot - dent->d_name), dent->d_name); | 882 | (int)(dot - dent->d_name), dent->d_name); |
881 | 883 | ||
882 | strxfrchar(dso_name, '-', '_'); | 884 | strxfrchar(dso_name, '-', '_'); |
883 | map = map_groups__find_by_name(mg, MAP__FUNCTION, | 885 | map = map_groups__find_by_name(mg, MAP__FUNCTION, |
884 | dso_name); | 886 | dso_name); |
885 | if (map == NULL) | 887 | if (map == NULL) |
886 | continue; | 888 | continue; |
887 | 889 | ||
888 | long_name = strdup(path); | 890 | long_name = strdup(path); |
889 | if (long_name == NULL) { | 891 | if (long_name == NULL) { |
890 | ret = -1; | 892 | ret = -1; |
891 | goto out; | 893 | goto out; |
892 | } | 894 | } |
893 | dso__set_long_name(map->dso, long_name, true); | 895 | dso__set_long_name(map->dso, long_name, true); |
894 | dso__kernel_module_get_build_id(map->dso, ""); | 896 | dso__kernel_module_get_build_id(map->dso, ""); |
895 | } | 897 | } |
896 | } | 898 | } |
897 | 899 | ||
898 | out: | 900 | out: |
899 | closedir(dir); | 901 | closedir(dir); |
900 | return ret; | 902 | return ret; |
901 | } | 903 | } |
902 | 904 | ||
903 | static int machine__set_modules_path(struct machine *machine) | 905 | static int machine__set_modules_path(struct machine *machine) |
904 | { | 906 | { |
905 | char *version; | 907 | char *version; |
906 | char modules_path[PATH_MAX]; | 908 | char modules_path[PATH_MAX]; |
907 | 909 | ||
908 | version = get_kernel_version(machine->root_dir); | 910 | version = get_kernel_version(machine->root_dir); |
909 | if (!version) | 911 | if (!version) |
910 | return -1; | 912 | return -1; |
911 | 913 | ||
912 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s", | 914 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s", |
913 | machine->root_dir, version); | 915 | machine->root_dir, version); |
914 | free(version); | 916 | free(version); |
915 | 917 | ||
916 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0); | 918 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0); |
917 | } | 919 | } |
918 | 920 | ||
919 | static int machine__create_module(void *arg, const char *name, u64 start) | 921 | static int machine__create_module(void *arg, const char *name, u64 start) |
920 | { | 922 | { |
921 | struct machine *machine = arg; | 923 | struct machine *machine = arg; |
922 | struct map *map; | 924 | struct map *map; |
923 | 925 | ||
924 | map = machine__new_module(machine, start, name); | 926 | map = machine__new_module(machine, start, name); |
925 | if (map == NULL) | 927 | if (map == NULL) |
926 | return -1; | 928 | return -1; |
927 | 929 | ||
928 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); | 930 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); |
929 | 931 | ||
930 | return 0; | 932 | return 0; |
931 | } | 933 | } |
932 | 934 | ||
933 | static int machine__create_modules(struct machine *machine) | 935 | static int machine__create_modules(struct machine *machine) |
934 | { | 936 | { |
935 | const char *modules; | 937 | const char *modules; |
936 | char path[PATH_MAX]; | 938 | char path[PATH_MAX]; |
937 | 939 | ||
938 | if (machine__is_default_guest(machine)) { | 940 | if (machine__is_default_guest(machine)) { |
939 | modules = symbol_conf.default_guest_modules; | 941 | modules = symbol_conf.default_guest_modules; |
940 | } else { | 942 | } else { |
941 | snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir); | 943 | snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir); |
942 | modules = path; | 944 | modules = path; |
943 | } | 945 | } |
944 | 946 | ||
945 | if (symbol__restricted_filename(modules, "/proc/modules")) | 947 | if (symbol__restricted_filename(modules, "/proc/modules")) |
946 | return -1; | 948 | return -1; |
947 | 949 | ||
948 | if (modules__parse(modules, machine, machine__create_module)) | 950 | if (modules__parse(modules, machine, machine__create_module)) |
949 | return -1; | 951 | return -1; |
950 | 952 | ||
951 | if (!machine__set_modules_path(machine)) | 953 | if (!machine__set_modules_path(machine)) |
952 | return 0; | 954 | return 0; |
953 | 955 | ||
954 | pr_debug("Problems setting modules path maps, continuing anyway...\n"); | 956 | pr_debug("Problems setting modules path maps, continuing anyway...\n"); |
955 | 957 | ||
956 | return 0; | 958 | return 0; |
957 | } | 959 | } |
958 | 960 | ||
959 | int machine__create_kernel_maps(struct machine *machine) | 961 | int machine__create_kernel_maps(struct machine *machine) |
960 | { | 962 | { |
961 | struct dso *kernel = machine__get_kernel(machine); | 963 | struct dso *kernel = machine__get_kernel(machine); |
962 | const char *name; | 964 | const char *name; |
963 | u64 addr = machine__get_running_kernel_start(machine, &name); | 965 | u64 addr = machine__get_running_kernel_start(machine, &name); |
964 | if (!addr) | 966 | if (!addr) |
965 | return -1; | 967 | return -1; |
966 | 968 | ||
967 | if (kernel == NULL || | 969 | if (kernel == NULL || |
968 | __machine__create_kernel_maps(machine, kernel) < 0) | 970 | __machine__create_kernel_maps(machine, kernel) < 0) |
969 | return -1; | 971 | return -1; |
970 | 972 | ||
971 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { | 973 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { |
972 | if (machine__is_host(machine)) | 974 | if (machine__is_host(machine)) |
973 | pr_debug("Problems creating module maps, " | 975 | pr_debug("Problems creating module maps, " |
974 | "continuing anyway...\n"); | 976 | "continuing anyway...\n"); |
975 | else | 977 | else |
976 | pr_debug("Problems creating module maps for guest %d, " | 978 | pr_debug("Problems creating module maps for guest %d, " |
977 | "continuing anyway...\n", machine->pid); | 979 | "continuing anyway...\n", machine->pid); |
978 | } | 980 | } |
979 | 981 | ||
980 | /* | 982 | /* |
981 | * Now that we have all the maps created, just set the ->end of them: | 983 | * Now that we have all the maps created, just set the ->end of them: |
982 | */ | 984 | */ |
983 | map_groups__fixup_end(&machine->kmaps); | 985 | map_groups__fixup_end(&machine->kmaps); |
984 | 986 | ||
985 | if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, | 987 | if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, |
986 | addr)) { | 988 | addr)) { |
987 | machine__destroy_kernel_maps(machine); | 989 | machine__destroy_kernel_maps(machine); |
988 | return -1; | 990 | return -1; |
989 | } | 991 | } |
990 | 992 | ||
991 | return 0; | 993 | return 0; |
992 | } | 994 | } |
993 | 995 | ||
994 | static void machine__set_kernel_mmap_len(struct machine *machine, | 996 | static void machine__set_kernel_mmap_len(struct machine *machine, |
995 | union perf_event *event) | 997 | union perf_event *event) |
996 | { | 998 | { |
997 | int i; | 999 | int i; |
998 | 1000 | ||
999 | for (i = 0; i < MAP__NR_TYPES; i++) { | 1001 | for (i = 0; i < MAP__NR_TYPES; i++) { |
1000 | machine->vmlinux_maps[i]->start = event->mmap.start; | 1002 | machine->vmlinux_maps[i]->start = event->mmap.start; |
1001 | machine->vmlinux_maps[i]->end = (event->mmap.start + | 1003 | machine->vmlinux_maps[i]->end = (event->mmap.start + |
1002 | event->mmap.len); | 1004 | event->mmap.len); |
1003 | /* | 1005 | /* |
1004 | * Be a bit paranoid here, some perf.data file came with | 1006 | * Be a bit paranoid here, some perf.data file came with |
1005 | * a zero sized synthesized MMAP event for the kernel. | 1007 | * a zero sized synthesized MMAP event for the kernel. |
1006 | */ | 1008 | */ |
1007 | if (machine->vmlinux_maps[i]->end == 0) | 1009 | if (machine->vmlinux_maps[i]->end == 0) |
1008 | machine->vmlinux_maps[i]->end = ~0ULL; | 1010 | machine->vmlinux_maps[i]->end = ~0ULL; |
1009 | } | 1011 | } |
1010 | } | 1012 | } |
1011 | 1013 | ||
1012 | static bool machine__uses_kcore(struct machine *machine) | 1014 | static bool machine__uses_kcore(struct machine *machine) |
1013 | { | 1015 | { |
1014 | struct dso *dso; | 1016 | struct dso *dso; |
1015 | 1017 | ||
1016 | list_for_each_entry(dso, &machine->kernel_dsos.head, node) { | 1018 | list_for_each_entry(dso, &machine->kernel_dsos.head, node) { |
1017 | if (dso__is_kcore(dso)) | 1019 | if (dso__is_kcore(dso)) |
1018 | return true; | 1020 | return true; |
1019 | } | 1021 | } |
1020 | 1022 | ||
1021 | return false; | 1023 | return false; |
1022 | } | 1024 | } |
1023 | 1025 | ||
1024 | static int machine__process_kernel_mmap_event(struct machine *machine, | 1026 | static int machine__process_kernel_mmap_event(struct machine *machine, |
1025 | union perf_event *event) | 1027 | union perf_event *event) |
1026 | { | 1028 | { |
1027 | struct map *map; | 1029 | struct map *map; |
1028 | char kmmap_prefix[PATH_MAX]; | 1030 | char kmmap_prefix[PATH_MAX]; |
1029 | enum dso_kernel_type kernel_type; | 1031 | enum dso_kernel_type kernel_type; |
1030 | bool is_kernel_mmap; | 1032 | bool is_kernel_mmap; |
1031 | 1033 | ||
1032 | /* If we have maps from kcore then we do not need or want any others */ | 1034 | /* If we have maps from kcore then we do not need or want any others */ |
1033 | if (machine__uses_kcore(machine)) | 1035 | if (machine__uses_kcore(machine)) |
1034 | return 0; | 1036 | return 0; |
1035 | 1037 | ||
1036 | machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); | 1038 | machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); |
1037 | if (machine__is_host(machine)) | 1039 | if (machine__is_host(machine)) |
1038 | kernel_type = DSO_TYPE_KERNEL; | 1040 | kernel_type = DSO_TYPE_KERNEL; |
1039 | else | 1041 | else |
1040 | kernel_type = DSO_TYPE_GUEST_KERNEL; | 1042 | kernel_type = DSO_TYPE_GUEST_KERNEL; |
1041 | 1043 | ||
1042 | is_kernel_mmap = memcmp(event->mmap.filename, | 1044 | is_kernel_mmap = memcmp(event->mmap.filename, |
1043 | kmmap_prefix, | 1045 | kmmap_prefix, |
1044 | strlen(kmmap_prefix) - 1) == 0; | 1046 | strlen(kmmap_prefix) - 1) == 0; |
1045 | if (event->mmap.filename[0] == '/' || | 1047 | if (event->mmap.filename[0] == '/' || |
1046 | (!is_kernel_mmap && event->mmap.filename[0] == '[')) { | 1048 | (!is_kernel_mmap && event->mmap.filename[0] == '[')) { |
1047 | 1049 | ||
1048 | char short_module_name[1024]; | 1050 | char short_module_name[1024]; |
1049 | char *name, *dot; | 1051 | char *name, *dot; |
1050 | 1052 | ||
1051 | if (event->mmap.filename[0] == '/') { | 1053 | if (event->mmap.filename[0] == '/') { |
1052 | name = strrchr(event->mmap.filename, '/'); | 1054 | name = strrchr(event->mmap.filename, '/'); |
1053 | if (name == NULL) | 1055 | if (name == NULL) |
1054 | goto out_problem; | 1056 | goto out_problem; |
1055 | 1057 | ||
1056 | ++name; /* skip / */ | 1058 | ++name; /* skip / */ |
1057 | dot = strrchr(name, '.'); | 1059 | dot = strrchr(name, '.'); |
1058 | if (dot == NULL) | 1060 | if (dot == NULL) |
1059 | goto out_problem; | 1061 | goto out_problem; |
1060 | /* On some system, modules are compressed like .ko.gz */ | 1062 | /* On some system, modules are compressed like .ko.gz */ |
1061 | if (is_supported_compression(dot + 1)) | 1063 | if (is_supported_compression(dot + 1)) |
1062 | dot -= 3; | 1064 | dot -= 3; |
1063 | if (!is_kmodule_extension(dot + 1)) | 1065 | if (!is_kmodule_extension(dot + 1)) |
1064 | goto out_problem; | 1066 | goto out_problem; |
1065 | snprintf(short_module_name, sizeof(short_module_name), | 1067 | snprintf(short_module_name, sizeof(short_module_name), |
1066 | "[%.*s]", (int)(dot - name), name); | 1068 | "[%.*s]", (int)(dot - name), name); |
1067 | strxfrchar(short_module_name, '-', '_'); | 1069 | strxfrchar(short_module_name, '-', '_'); |
1068 | } else | 1070 | } else |
1069 | strcpy(short_module_name, event->mmap.filename); | 1071 | strcpy(short_module_name, event->mmap.filename); |
1070 | 1072 | ||
1071 | map = machine__new_module(machine, event->mmap.start, | 1073 | map = machine__new_module(machine, event->mmap.start, |
1072 | event->mmap.filename); | 1074 | event->mmap.filename); |
1073 | if (map == NULL) | 1075 | if (map == NULL) |
1074 | goto out_problem; | 1076 | goto out_problem; |
1075 | 1077 | ||
1076 | name = strdup(short_module_name); | 1078 | name = strdup(short_module_name); |
1077 | if (name == NULL) | 1079 | if (name == NULL) |
1078 | goto out_problem; | 1080 | goto out_problem; |
1079 | 1081 | ||
1080 | dso__set_short_name(map->dso, name, true); | 1082 | dso__set_short_name(map->dso, name, true); |
1081 | map->end = map->start + event->mmap.len; | 1083 | map->end = map->start + event->mmap.len; |
1082 | } else if (is_kernel_mmap) { | 1084 | } else if (is_kernel_mmap) { |
1083 | const char *symbol_name = (event->mmap.filename + | 1085 | const char *symbol_name = (event->mmap.filename + |
1084 | strlen(kmmap_prefix)); | 1086 | strlen(kmmap_prefix)); |
1085 | /* | 1087 | /* |
1086 | * Should be there already, from the build-id table in | 1088 | * Should be there already, from the build-id table in |
1087 | * the header. | 1089 | * the header. |
1088 | */ | 1090 | */ |
1089 | struct dso *kernel = NULL; | 1091 | struct dso *kernel = NULL; |
1090 | struct dso *dso; | 1092 | struct dso *dso; |
1091 | 1093 | ||
1092 | list_for_each_entry(dso, &machine->kernel_dsos.head, node) { | 1094 | list_for_each_entry(dso, &machine->kernel_dsos.head, node) { |
1093 | if (is_kernel_module(dso->long_name, NULL)) | 1095 | if (is_kernel_module(dso->long_name, NULL)) |
1094 | continue; | 1096 | continue; |
1095 | 1097 | ||
1096 | kernel = dso; | 1098 | kernel = dso; |
1097 | break; | 1099 | break; |
1098 | } | 1100 | } |
1099 | 1101 | ||
1100 | if (kernel == NULL) | 1102 | if (kernel == NULL) |
1101 | kernel = __dsos__findnew(&machine->kernel_dsos, | 1103 | kernel = __dsos__findnew(&machine->kernel_dsos, |
1102 | kmmap_prefix); | 1104 | kmmap_prefix); |
1103 | if (kernel == NULL) | 1105 | if (kernel == NULL) |
1104 | goto out_problem; | 1106 | goto out_problem; |
1105 | 1107 | ||
1106 | kernel->kernel = kernel_type; | 1108 | kernel->kernel = kernel_type; |
1107 | if (__machine__create_kernel_maps(machine, kernel) < 0) | 1109 | if (__machine__create_kernel_maps(machine, kernel) < 0) |
1108 | goto out_problem; | 1110 | goto out_problem; |
1109 | 1111 | ||
1110 | if (strstr(kernel->long_name, "vmlinux")) | 1112 | if (strstr(kernel->long_name, "vmlinux")) |
1111 | dso__set_short_name(kernel, "[kernel.vmlinux]", false); | 1113 | dso__set_short_name(kernel, "[kernel.vmlinux]", false); |
1112 | 1114 | ||
1113 | machine__set_kernel_mmap_len(machine, event); | 1115 | machine__set_kernel_mmap_len(machine, event); |
1114 | 1116 | ||
1115 | /* | 1117 | /* |
1116 | * Avoid using a zero address (kptr_restrict) for the ref reloc | 1118 | * Avoid using a zero address (kptr_restrict) for the ref reloc |
1117 | * symbol. Effectively having zero here means that at record | 1119 | * symbol. Effectively having zero here means that at record |
1118 | * time /proc/sys/kernel/kptr_restrict was non zero. | 1120 | * time /proc/sys/kernel/kptr_restrict was non zero. |
1119 | */ | 1121 | */ |
1120 | if (event->mmap.pgoff != 0) { | 1122 | if (event->mmap.pgoff != 0) { |
1121 | maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, | 1123 | maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, |
1122 | symbol_name, | 1124 | symbol_name, |
1123 | event->mmap.pgoff); | 1125 | event->mmap.pgoff); |
1124 | } | 1126 | } |
1125 | 1127 | ||
1126 | if (machine__is_default_guest(machine)) { | 1128 | if (machine__is_default_guest(machine)) { |
1127 | /* | 1129 | /* |
1128 | * preload dso of guest kernel and modules | 1130 | * preload dso of guest kernel and modules |
1129 | */ | 1131 | */ |
1130 | dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION], | 1132 | dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION], |
1131 | NULL); | 1133 | NULL); |
1132 | } | 1134 | } |
1133 | } | 1135 | } |
1134 | return 0; | 1136 | return 0; |
1135 | out_problem: | 1137 | out_problem: |
1136 | return -1; | 1138 | return -1; |
1137 | } | 1139 | } |
1138 | 1140 | ||
1139 | int machine__process_mmap2_event(struct machine *machine, | 1141 | int machine__process_mmap2_event(struct machine *machine, |
1140 | union perf_event *event, | 1142 | union perf_event *event, |
1141 | struct perf_sample *sample __maybe_unused) | 1143 | struct perf_sample *sample __maybe_unused) |
1142 | { | 1144 | { |
1143 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 1145 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
1144 | struct thread *thread; | 1146 | struct thread *thread; |
1145 | struct map *map; | 1147 | struct map *map; |
1146 | enum map_type type; | 1148 | enum map_type type; |
1147 | int ret = 0; | 1149 | int ret = 0; |
1148 | 1150 | ||
1149 | if (dump_trace) | 1151 | if (dump_trace) |
1150 | perf_event__fprintf_mmap2(event, stdout); | 1152 | perf_event__fprintf_mmap2(event, stdout); |
1151 | 1153 | ||
1152 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || | 1154 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || |
1153 | cpumode == PERF_RECORD_MISC_KERNEL) { | 1155 | cpumode == PERF_RECORD_MISC_KERNEL) { |
1154 | ret = machine__process_kernel_mmap_event(machine, event); | 1156 | ret = machine__process_kernel_mmap_event(machine, event); |
1155 | if (ret < 0) | 1157 | if (ret < 0) |
1156 | goto out_problem; | 1158 | goto out_problem; |
1157 | return 0; | 1159 | return 0; |
1158 | } | 1160 | } |
1159 | 1161 | ||
1160 | thread = machine__findnew_thread(machine, event->mmap2.pid, | 1162 | thread = machine__findnew_thread(machine, event->mmap2.pid, |
1161 | event->mmap2.tid); | 1163 | event->mmap2.tid); |
1162 | if (thread == NULL) | 1164 | if (thread == NULL) |
1163 | goto out_problem; | 1165 | goto out_problem; |
1164 | 1166 | ||
1165 | if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) | 1167 | if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) |
1166 | type = MAP__VARIABLE; | 1168 | type = MAP__VARIABLE; |
1167 | else | 1169 | else |
1168 | type = MAP__FUNCTION; | 1170 | type = MAP__FUNCTION; |
1169 | 1171 | ||
1170 | map = map__new(machine, event->mmap2.start, | 1172 | map = map__new(machine, event->mmap2.start, |
1171 | event->mmap2.len, event->mmap2.pgoff, | 1173 | event->mmap2.len, event->mmap2.pgoff, |
1172 | event->mmap2.pid, event->mmap2.maj, | 1174 | event->mmap2.pid, event->mmap2.maj, |
1173 | event->mmap2.min, event->mmap2.ino, | 1175 | event->mmap2.min, event->mmap2.ino, |
1174 | event->mmap2.ino_generation, | 1176 | event->mmap2.ino_generation, |
1175 | event->mmap2.prot, | 1177 | event->mmap2.prot, |
1176 | event->mmap2.flags, | 1178 | event->mmap2.flags, |
1177 | event->mmap2.filename, type, thread); | 1179 | event->mmap2.filename, type, thread); |
1178 | 1180 | ||
1179 | if (map == NULL) | 1181 | if (map == NULL) |
1180 | goto out_problem; | 1182 | goto out_problem; |
1181 | 1183 | ||
1182 | thread__insert_map(thread, map); | 1184 | thread__insert_map(thread, map); |
1183 | return 0; | 1185 | return 0; |
1184 | 1186 | ||
1185 | out_problem: | 1187 | out_problem: |
1186 | dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n"); | 1188 | dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n"); |
1187 | return 0; | 1189 | return 0; |
1188 | } | 1190 | } |
1189 | 1191 | ||
1190 | int machine__process_mmap_event(struct machine *machine, union perf_event *event, | 1192 | int machine__process_mmap_event(struct machine *machine, union perf_event *event, |
1191 | struct perf_sample *sample __maybe_unused) | 1193 | struct perf_sample *sample __maybe_unused) |
1192 | { | 1194 | { |
1193 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 1195 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
1194 | struct thread *thread; | 1196 | struct thread *thread; |
1195 | struct map *map; | 1197 | struct map *map; |
1196 | enum map_type type; | 1198 | enum map_type type; |
1197 | int ret = 0; | 1199 | int ret = 0; |
1198 | 1200 | ||
1199 | if (dump_trace) | 1201 | if (dump_trace) |
1200 | perf_event__fprintf_mmap(event, stdout); | 1202 | perf_event__fprintf_mmap(event, stdout); |
1201 | 1203 | ||
1202 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || | 1204 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || |
1203 | cpumode == PERF_RECORD_MISC_KERNEL) { | 1205 | cpumode == PERF_RECORD_MISC_KERNEL) { |
1204 | ret = machine__process_kernel_mmap_event(machine, event); | 1206 | ret = machine__process_kernel_mmap_event(machine, event); |
1205 | if (ret < 0) | 1207 | if (ret < 0) |
1206 | goto out_problem; | 1208 | goto out_problem; |
1207 | return 0; | 1209 | return 0; |
1208 | } | 1210 | } |
1209 | 1211 | ||
1210 | thread = machine__findnew_thread(machine, event->mmap.pid, | 1212 | thread = machine__findnew_thread(machine, event->mmap.pid, |
1211 | event->mmap.tid); | 1213 | event->mmap.tid); |
1212 | if (thread == NULL) | 1214 | if (thread == NULL) |
1213 | goto out_problem; | 1215 | goto out_problem; |
1214 | 1216 | ||
1215 | if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) | 1217 | if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) |
1216 | type = MAP__VARIABLE; | 1218 | type = MAP__VARIABLE; |
1217 | else | 1219 | else |
1218 | type = MAP__FUNCTION; | 1220 | type = MAP__FUNCTION; |
1219 | 1221 | ||
1220 | map = map__new(machine, event->mmap.start, | 1222 | map = map__new(machine, event->mmap.start, |
1221 | event->mmap.len, event->mmap.pgoff, | 1223 | event->mmap.len, event->mmap.pgoff, |
1222 | event->mmap.pid, 0, 0, 0, 0, 0, 0, | 1224 | event->mmap.pid, 0, 0, 0, 0, 0, 0, |
1223 | event->mmap.filename, | 1225 | event->mmap.filename, |
1224 | type, thread); | 1226 | type, thread); |
1225 | 1227 | ||
1226 | if (map == NULL) | 1228 | if (map == NULL) |
1227 | goto out_problem; | 1229 | goto out_problem; |
1228 | 1230 | ||
1229 | thread__insert_map(thread, map); | 1231 | thread__insert_map(thread, map); |
1230 | return 0; | 1232 | return 0; |
1231 | 1233 | ||
1232 | out_problem: | 1234 | out_problem: |
1233 | dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); | 1235 | dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); |
1234 | return 0; | 1236 | return 0; |
1235 | } | 1237 | } |
1236 | 1238 | ||
1237 | static void machine__remove_thread(struct machine *machine, struct thread *th) | 1239 | static void machine__remove_thread(struct machine *machine, struct thread *th) |
1238 | { | 1240 | { |
1239 | machine->last_match = NULL; | 1241 | machine->last_match = NULL; |
1240 | rb_erase(&th->rb_node, &machine->threads); | 1242 | rb_erase(&th->rb_node, &machine->threads); |
1241 | /* | 1243 | /* |
1242 | * We may have references to this thread, for instance in some hist_entry | 1244 | * We may have references to this thread, for instance in some hist_entry |
1243 | * instances, so just move them to a separate list. | 1245 | * instances, so just move them to a separate list. |
1244 | */ | 1246 | */ |
1245 | list_add_tail(&th->node, &machine->dead_threads); | 1247 | list_add_tail(&th->node, &machine->dead_threads); |
1246 | } | 1248 | } |
1247 | 1249 | ||
1248 | int machine__process_fork_event(struct machine *machine, union perf_event *event, | 1250 | int machine__process_fork_event(struct machine *machine, union perf_event *event, |
1249 | struct perf_sample *sample) | 1251 | struct perf_sample *sample) |
1250 | { | 1252 | { |
1251 | struct thread *thread = machine__find_thread(machine, | 1253 | struct thread *thread = machine__find_thread(machine, |
1252 | event->fork.pid, | 1254 | event->fork.pid, |
1253 | event->fork.tid); | 1255 | event->fork.tid); |
1254 | struct thread *parent = machine__findnew_thread(machine, | 1256 | struct thread *parent = machine__findnew_thread(machine, |
1255 | event->fork.ppid, | 1257 | event->fork.ppid, |
1256 | event->fork.ptid); | 1258 | event->fork.ptid); |
1257 | 1259 | ||
1258 | /* if a thread currently exists for the thread id remove it */ | 1260 | /* if a thread currently exists for the thread id remove it */ |
1259 | if (thread != NULL) | 1261 | if (thread != NULL) |
1260 | machine__remove_thread(machine, thread); | 1262 | machine__remove_thread(machine, thread); |
1261 | 1263 | ||
1262 | thread = machine__findnew_thread(machine, event->fork.pid, | 1264 | thread = machine__findnew_thread(machine, event->fork.pid, |
1263 | event->fork.tid); | 1265 | event->fork.tid); |
1264 | if (dump_trace) | 1266 | if (dump_trace) |
1265 | perf_event__fprintf_task(event, stdout); | 1267 | perf_event__fprintf_task(event, stdout); |
1266 | 1268 | ||
1267 | if (thread == NULL || parent == NULL || | 1269 | if (thread == NULL || parent == NULL || |
1268 | thread__fork(thread, parent, sample->time) < 0) { | 1270 | thread__fork(thread, parent, sample->time) < 0) { |
1269 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); | 1271 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); |
1270 | return -1; | 1272 | return -1; |
1271 | } | 1273 | } |
1272 | 1274 | ||
1273 | return 0; | 1275 | return 0; |
1274 | } | 1276 | } |
1275 | 1277 | ||
1276 | int machine__process_exit_event(struct machine *machine, union perf_event *event, | 1278 | int machine__process_exit_event(struct machine *machine, union perf_event *event, |
1277 | struct perf_sample *sample __maybe_unused) | 1279 | struct perf_sample *sample __maybe_unused) |
1278 | { | 1280 | { |
1279 | struct thread *thread = machine__find_thread(machine, | 1281 | struct thread *thread = machine__find_thread(machine, |
1280 | event->fork.pid, | 1282 | event->fork.pid, |
1281 | event->fork.tid); | 1283 | event->fork.tid); |
1282 | 1284 | ||
1283 | if (dump_trace) | 1285 | if (dump_trace) |
1284 | perf_event__fprintf_task(event, stdout); | 1286 | perf_event__fprintf_task(event, stdout); |
1285 | 1287 | ||
1286 | if (thread != NULL) | 1288 | if (thread != NULL) |
1287 | thread__exited(thread); | 1289 | thread__exited(thread); |
1288 | 1290 | ||
1289 | return 0; | 1291 | return 0; |
1290 | } | 1292 | } |
1291 | 1293 | ||
1292 | int machine__process_event(struct machine *machine, union perf_event *event, | 1294 | int machine__process_event(struct machine *machine, union perf_event *event, |
1293 | struct perf_sample *sample) | 1295 | struct perf_sample *sample) |
1294 | { | 1296 | { |
1295 | int ret; | 1297 | int ret; |
1296 | 1298 | ||
1297 | switch (event->header.type) { | 1299 | switch (event->header.type) { |
1298 | case PERF_RECORD_COMM: | 1300 | case PERF_RECORD_COMM: |
1299 | ret = machine__process_comm_event(machine, event, sample); break; | 1301 | ret = machine__process_comm_event(machine, event, sample); break; |
1300 | case PERF_RECORD_MMAP: | 1302 | case PERF_RECORD_MMAP: |
1301 | ret = machine__process_mmap_event(machine, event, sample); break; | 1303 | ret = machine__process_mmap_event(machine, event, sample); break; |
1302 | case PERF_RECORD_MMAP2: | 1304 | case PERF_RECORD_MMAP2: |
1303 | ret = machine__process_mmap2_event(machine, event, sample); break; | 1305 | ret = machine__process_mmap2_event(machine, event, sample); break; |
1304 | case PERF_RECORD_FORK: | 1306 | case PERF_RECORD_FORK: |
1305 | ret = machine__process_fork_event(machine, event, sample); break; | 1307 | ret = machine__process_fork_event(machine, event, sample); break; |
1306 | case PERF_RECORD_EXIT: | 1308 | case PERF_RECORD_EXIT: |
1307 | ret = machine__process_exit_event(machine, event, sample); break; | 1309 | ret = machine__process_exit_event(machine, event, sample); break; |
1308 | case PERF_RECORD_LOST: | 1310 | case PERF_RECORD_LOST: |
1309 | ret = machine__process_lost_event(machine, event, sample); break; | 1311 | ret = machine__process_lost_event(machine, event, sample); break; |
1310 | default: | 1312 | default: |
1311 | ret = -1; | 1313 | ret = -1; |
1312 | break; | 1314 | break; |
1313 | } | 1315 | } |
1314 | 1316 | ||
1315 | return ret; | 1317 | return ret; |
1316 | } | 1318 | } |
1317 | 1319 | ||
1318 | static bool symbol__match_regex(struct symbol *sym, regex_t *regex) | 1320 | static bool symbol__match_regex(struct symbol *sym, regex_t *regex) |
1319 | { | 1321 | { |
1320 | if (sym->name && !regexec(regex, sym->name, 0, NULL, 0)) | 1322 | if (sym->name && !regexec(regex, sym->name, 0, NULL, 0)) |
1321 | return 1; | 1323 | return 1; |
1322 | return 0; | 1324 | return 0; |
1323 | } | 1325 | } |
1324 | 1326 | ||
1325 | static void ip__resolve_ams(struct thread *thread, | 1327 | static void ip__resolve_ams(struct thread *thread, |
1326 | struct addr_map_symbol *ams, | 1328 | struct addr_map_symbol *ams, |
1327 | u64 ip) | 1329 | u64 ip) |
1328 | { | 1330 | { |
1329 | struct addr_location al; | 1331 | struct addr_location al; |
1330 | 1332 | ||
1331 | memset(&al, 0, sizeof(al)); | 1333 | memset(&al, 0, sizeof(al)); |
1332 | /* | 1334 | /* |
1333 | * We cannot use the header.misc hint to determine whether a | 1335 | * We cannot use the header.misc hint to determine whether a |
1334 | * branch stack address is user, kernel, guest, hypervisor. | 1336 | * branch stack address is user, kernel, guest, hypervisor. |
1335 | * Branches may straddle the kernel/user/hypervisor boundaries. | 1337 | * Branches may straddle the kernel/user/hypervisor boundaries. |
1336 | * Thus, we have to try consecutively until we find a match | 1338 | * Thus, we have to try consecutively until we find a match |
1337 | * or else, the symbol is unknown | 1339 | * or else, the symbol is unknown |
1338 | */ | 1340 | */ |
1339 | thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al); | 1341 | thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al); |
1340 | 1342 | ||
1341 | ams->addr = ip; | 1343 | ams->addr = ip; |
1342 | ams->al_addr = al.addr; | 1344 | ams->al_addr = al.addr; |
1343 | ams->sym = al.sym; | 1345 | ams->sym = al.sym; |
1344 | ams->map = al.map; | 1346 | ams->map = al.map; |
1345 | } | 1347 | } |
1346 | 1348 | ||
1347 | static void ip__resolve_data(struct thread *thread, | 1349 | static void ip__resolve_data(struct thread *thread, |
1348 | u8 m, struct addr_map_symbol *ams, u64 addr) | 1350 | u8 m, struct addr_map_symbol *ams, u64 addr) |
1349 | { | 1351 | { |
1350 | struct addr_location al; | 1352 | struct addr_location al; |
1351 | 1353 | ||
1352 | memset(&al, 0, sizeof(al)); | 1354 | memset(&al, 0, sizeof(al)); |
1353 | 1355 | ||
1354 | thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al); | 1356 | thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al); |
1355 | if (al.map == NULL) { | 1357 | if (al.map == NULL) { |
1356 | /* | 1358 | /* |
1357 | * some shared data regions have execute bit set which puts | 1359 | * some shared data regions have execute bit set which puts |
1358 | * their mapping in the MAP__FUNCTION type array. | 1360 | * their mapping in the MAP__FUNCTION type array. |
1359 | * Check there as a fallback option before dropping the sample. | 1361 | * Check there as a fallback option before dropping the sample. |
1360 | */ | 1362 | */ |
1361 | thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al); | 1363 | thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al); |
1362 | } | 1364 | } |
1363 | 1365 | ||
1364 | ams->addr = addr; | 1366 | ams->addr = addr; |
1365 | ams->al_addr = al.addr; | 1367 | ams->al_addr = al.addr; |
1366 | ams->sym = al.sym; | 1368 | ams->sym = al.sym; |
1367 | ams->map = al.map; | 1369 | ams->map = al.map; |
1368 | } | 1370 | } |
1369 | 1371 | ||
1370 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, | 1372 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, |
1371 | struct addr_location *al) | 1373 | struct addr_location *al) |
1372 | { | 1374 | { |
1373 | struct mem_info *mi = zalloc(sizeof(*mi)); | 1375 | struct mem_info *mi = zalloc(sizeof(*mi)); |
1374 | 1376 | ||
1375 | if (!mi) | 1377 | if (!mi) |
1376 | return NULL; | 1378 | return NULL; |
1377 | 1379 | ||
1378 | ip__resolve_ams(al->thread, &mi->iaddr, sample->ip); | 1380 | ip__resolve_ams(al->thread, &mi->iaddr, sample->ip); |
1379 | ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr); | 1381 | ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr); |
1380 | mi->data_src.val = sample->data_src; | 1382 | mi->data_src.val = sample->data_src; |
1381 | 1383 | ||
1382 | return mi; | 1384 | return mi; |
1383 | } | 1385 | } |
1384 | 1386 | ||
1385 | static int add_callchain_ip(struct thread *thread, | 1387 | static int add_callchain_ip(struct thread *thread, |
1386 | struct symbol **parent, | 1388 | struct symbol **parent, |
1387 | struct addr_location *root_al, | 1389 | struct addr_location *root_al, |
1388 | bool branch_history, | 1390 | bool branch_history, |
1389 | u64 ip) | 1391 | u64 ip) |
1390 | { | 1392 | { |
1391 | struct addr_location al; | 1393 | struct addr_location al; |
1392 | 1394 | ||
1393 | al.filtered = 0; | 1395 | al.filtered = 0; |
1394 | al.sym = NULL; | 1396 | al.sym = NULL; |
1395 | if (branch_history) | 1397 | if (branch_history) |
1396 | thread__find_cpumode_addr_location(thread, MAP__FUNCTION, | 1398 | thread__find_cpumode_addr_location(thread, MAP__FUNCTION, |
1397 | ip, &al); | 1399 | ip, &al); |
1398 | else { | 1400 | else { |
1399 | u8 cpumode = PERF_RECORD_MISC_USER; | 1401 | u8 cpumode = PERF_RECORD_MISC_USER; |
1400 | 1402 | ||
1401 | if (ip >= PERF_CONTEXT_MAX) { | 1403 | if (ip >= PERF_CONTEXT_MAX) { |
1402 | switch (ip) { | 1404 | switch (ip) { |
1403 | case PERF_CONTEXT_HV: | 1405 | case PERF_CONTEXT_HV: |
1404 | cpumode = PERF_RECORD_MISC_HYPERVISOR; | 1406 | cpumode = PERF_RECORD_MISC_HYPERVISOR; |
1405 | break; | 1407 | break; |
1406 | case PERF_CONTEXT_KERNEL: | 1408 | case PERF_CONTEXT_KERNEL: |
1407 | cpumode = PERF_RECORD_MISC_KERNEL; | 1409 | cpumode = PERF_RECORD_MISC_KERNEL; |
1408 | break; | 1410 | break; |
1409 | case PERF_CONTEXT_USER: | 1411 | case PERF_CONTEXT_USER: |
1410 | cpumode = PERF_RECORD_MISC_USER; | 1412 | cpumode = PERF_RECORD_MISC_USER; |
1411 | break; | 1413 | break; |
1412 | default: | 1414 | default: |
1413 | pr_debug("invalid callchain context: " | 1415 | pr_debug("invalid callchain context: " |
1414 | "%"PRId64"\n", (s64) ip); | 1416 | "%"PRId64"\n", (s64) ip); |
1415 | /* | 1417 | /* |
1416 | * It seems the callchain is corrupted. | 1418 | * It seems the callchain is corrupted. |
1417 | * Discard all. | 1419 | * Discard all. |
1418 | */ | 1420 | */ |
1419 | callchain_cursor_reset(&callchain_cursor); | 1421 | callchain_cursor_reset(&callchain_cursor); |
1420 | return 1; | 1422 | return 1; |
1421 | } | 1423 | } |
1422 | return 0; | 1424 | return 0; |
1423 | } | 1425 | } |
1424 | thread__find_addr_location(thread, cpumode, MAP__FUNCTION, | 1426 | thread__find_addr_location(thread, cpumode, MAP__FUNCTION, |
1425 | ip, &al); | 1427 | ip, &al); |
1426 | } | 1428 | } |
1427 | 1429 | ||
1428 | if (al.sym != NULL) { | 1430 | if (al.sym != NULL) { |
1429 | if (sort__has_parent && !*parent && | 1431 | if (sort__has_parent && !*parent && |
1430 | symbol__match_regex(al.sym, &parent_regex)) | 1432 | symbol__match_regex(al.sym, &parent_regex)) |
1431 | *parent = al.sym; | 1433 | *parent = al.sym; |
1432 | else if (have_ignore_callees && root_al && | 1434 | else if (have_ignore_callees && root_al && |
1433 | symbol__match_regex(al.sym, &ignore_callees_regex)) { | 1435 | symbol__match_regex(al.sym, &ignore_callees_regex)) { |
1434 | /* Treat this symbol as the root, | 1436 | /* Treat this symbol as the root, |
1435 | forgetting its callees. */ | 1437 | forgetting its callees. */ |
1436 | *root_al = al; | 1438 | *root_al = al; |
1437 | callchain_cursor_reset(&callchain_cursor); | 1439 | callchain_cursor_reset(&callchain_cursor); |
1438 | } | 1440 | } |
1439 | } | 1441 | } |
1440 | 1442 | ||
1441 | return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); | 1443 | return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); |
1442 | } | 1444 | } |
1443 | 1445 | ||
1444 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | 1446 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, |
1445 | struct addr_location *al) | 1447 | struct addr_location *al) |
1446 | { | 1448 | { |
1447 | unsigned int i; | 1449 | unsigned int i; |
1448 | const struct branch_stack *bs = sample->branch_stack; | 1450 | const struct branch_stack *bs = sample->branch_stack; |
1449 | struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info)); | 1451 | struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info)); |
1450 | 1452 | ||
1451 | if (!bi) | 1453 | if (!bi) |
1452 | return NULL; | 1454 | return NULL; |
1453 | 1455 | ||
1454 | for (i = 0; i < bs->nr; i++) { | 1456 | for (i = 0; i < bs->nr; i++) { |
1455 | ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to); | 1457 | ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to); |
1456 | ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from); | 1458 | ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from); |
1457 | bi[i].flags = bs->entries[i].flags; | 1459 | bi[i].flags = bs->entries[i].flags; |
1458 | } | 1460 | } |
1459 | return bi; | 1461 | return bi; |
1460 | } | 1462 | } |
1461 | 1463 | ||
1462 | #define CHASHSZ 127 | 1464 | #define CHASHSZ 127 |
1463 | #define CHASHBITS 7 | 1465 | #define CHASHBITS 7 |
1464 | #define NO_ENTRY 0xff | 1466 | #define NO_ENTRY 0xff |
1465 | 1467 | ||
1466 | #define PERF_MAX_BRANCH_DEPTH 127 | 1468 | #define PERF_MAX_BRANCH_DEPTH 127 |
1467 | 1469 | ||
1468 | /* Remove loops. */ | 1470 | /* Remove loops. */ |
1469 | static int remove_loops(struct branch_entry *l, int nr) | 1471 | static int remove_loops(struct branch_entry *l, int nr) |
1470 | { | 1472 | { |
1471 | int i, j, off; | 1473 | int i, j, off; |
1472 | unsigned char chash[CHASHSZ]; | 1474 | unsigned char chash[CHASHSZ]; |
1473 | 1475 | ||
1474 | memset(chash, NO_ENTRY, sizeof(chash)); | 1476 | memset(chash, NO_ENTRY, sizeof(chash)); |
1475 | 1477 | ||
1476 | BUG_ON(PERF_MAX_BRANCH_DEPTH > 255); | 1478 | BUG_ON(PERF_MAX_BRANCH_DEPTH > 255); |
1477 | 1479 | ||
1478 | for (i = 0; i < nr; i++) { | 1480 | for (i = 0; i < nr; i++) { |
1479 | int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ; | 1481 | int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ; |
1480 | 1482 | ||
1481 | /* no collision handling for now */ | 1483 | /* no collision handling for now */ |
1482 | if (chash[h] == NO_ENTRY) { | 1484 | if (chash[h] == NO_ENTRY) { |
1483 | chash[h] = i; | 1485 | chash[h] = i; |
1484 | } else if (l[chash[h]].from == l[i].from) { | 1486 | } else if (l[chash[h]].from == l[i].from) { |
1485 | bool is_loop = true; | 1487 | bool is_loop = true; |
1486 | /* check if it is a real loop */ | 1488 | /* check if it is a real loop */ |
1487 | off = 0; | 1489 | off = 0; |
1488 | for (j = chash[h]; j < i && i + off < nr; j++, off++) | 1490 | for (j = chash[h]; j < i && i + off < nr; j++, off++) |
1489 | if (l[j].from != l[i + off].from) { | 1491 | if (l[j].from != l[i + off].from) { |
1490 | is_loop = false; | 1492 | is_loop = false; |
1491 | break; | 1493 | break; |
1492 | } | 1494 | } |
1493 | if (is_loop) { | 1495 | if (is_loop) { |
1494 | memmove(l + i, l + i + off, | 1496 | memmove(l + i, l + i + off, |
1495 | (nr - (i + off)) * sizeof(*l)); | 1497 | (nr - (i + off)) * sizeof(*l)); |
1496 | nr -= off; | 1498 | nr -= off; |
1497 | } | 1499 | } |
1498 | } | 1500 | } |
1499 | } | 1501 | } |
1500 | return nr; | 1502 | return nr; |
1501 | } | 1503 | } |
1502 | 1504 | ||
1503 | static int thread__resolve_callchain_sample(struct thread *thread, | 1505 | static int thread__resolve_callchain_sample(struct thread *thread, |
1504 | struct ip_callchain *chain, | 1506 | struct ip_callchain *chain, |
1505 | struct branch_stack *branch, | 1507 | struct branch_stack *branch, |
1506 | struct symbol **parent, | 1508 | struct symbol **parent, |
1507 | struct addr_location *root_al, | 1509 | struct addr_location *root_al, |
1508 | int max_stack) | 1510 | int max_stack) |
1509 | { | 1511 | { |
1510 | int chain_nr = min(max_stack, (int)chain->nr); | 1512 | int chain_nr = min(max_stack, (int)chain->nr); |
1511 | int i, j, err; | 1513 | int i, j, err; |
1512 | int skip_idx = -1; | 1514 | int skip_idx = -1; |
1513 | int first_call = 0; | 1515 | int first_call = 0; |
1514 | 1516 | ||
1515 | /* | 1517 | /* |
1516 | * Based on DWARF debug information, some architectures skip | 1518 | * Based on DWARF debug information, some architectures skip |
1517 | * a callchain entry saved by the kernel. | 1519 | * a callchain entry saved by the kernel. |
1518 | */ | 1520 | */ |
1519 | if (chain->nr < PERF_MAX_STACK_DEPTH) | 1521 | if (chain->nr < PERF_MAX_STACK_DEPTH) |
1520 | skip_idx = arch_skip_callchain_idx(thread, chain); | 1522 | skip_idx = arch_skip_callchain_idx(thread, chain); |
1521 | 1523 | ||
1522 | callchain_cursor_reset(&callchain_cursor); | 1524 | callchain_cursor_reset(&callchain_cursor); |
1523 | 1525 | ||
1524 | /* | 1526 | /* |
1525 | * Add branches to call stack for easier browsing. This gives | 1527 | * Add branches to call stack for easier browsing. This gives |
1526 | * more context for a sample than just the callers. | 1528 | * more context for a sample than just the callers. |
1527 | * | 1529 | * |
1528 | * This uses individual histograms of paths compared to the | 1530 | * This uses individual histograms of paths compared to the |
1529 | * aggregated histograms the normal LBR mode uses. | 1531 | * aggregated histograms the normal LBR mode uses. |
1530 | * | 1532 | * |
1531 | * Limitations for now: | 1533 | * Limitations for now: |
1532 | * - No extra filters | 1534 | * - No extra filters |
1533 | * - No annotations (should annotate somehow) | 1535 | * - No annotations (should annotate somehow) |
1534 | */ | 1536 | */ |
1535 | 1537 | ||
1536 | if (branch && callchain_param.branch_callstack) { | 1538 | if (branch && callchain_param.branch_callstack) { |
1537 | int nr = min(max_stack, (int)branch->nr); | 1539 | int nr = min(max_stack, (int)branch->nr); |
1538 | struct branch_entry be[nr]; | 1540 | struct branch_entry be[nr]; |
1539 | 1541 | ||
1540 | if (branch->nr > PERF_MAX_BRANCH_DEPTH) { | 1542 | if (branch->nr > PERF_MAX_BRANCH_DEPTH) { |
1541 | pr_warning("corrupted branch chain. skipping...\n"); | 1543 | pr_warning("corrupted branch chain. skipping...\n"); |
1542 | goto check_calls; | 1544 | goto check_calls; |
1543 | } | 1545 | } |
1544 | 1546 | ||
1545 | for (i = 0; i < nr; i++) { | 1547 | for (i = 0; i < nr; i++) { |
1546 | if (callchain_param.order == ORDER_CALLEE) { | 1548 | if (callchain_param.order == ORDER_CALLEE) { |
1547 | be[i] = branch->entries[i]; | 1549 | be[i] = branch->entries[i]; |
1548 | /* | 1550 | /* |
1549 | * Check for overlap into the callchain. | 1551 | * Check for overlap into the callchain. |
1550 | * The return address is one off compared to | 1552 | * The return address is one off compared to |
1551 | * the branch entry. To adjust for this | 1553 | * the branch entry. To adjust for this |
1552 | * assume the calling instruction is not longer | 1554 | * assume the calling instruction is not longer |
1553 | * than 8 bytes. | 1555 | * than 8 bytes. |
1554 | */ | 1556 | */ |
1555 | if (i == skip_idx || | 1557 | if (i == skip_idx || |
1556 | chain->ips[first_call] >= PERF_CONTEXT_MAX) | 1558 | chain->ips[first_call] >= PERF_CONTEXT_MAX) |
1557 | first_call++; | 1559 | first_call++; |
1558 | else if (be[i].from < chain->ips[first_call] && | 1560 | else if (be[i].from < chain->ips[first_call] && |
1559 | be[i].from >= chain->ips[first_call] - 8) | 1561 | be[i].from >= chain->ips[first_call] - 8) |
1560 | first_call++; | 1562 | first_call++; |
1561 | } else | 1563 | } else |
1562 | be[i] = branch->entries[branch->nr - i - 1]; | 1564 | be[i] = branch->entries[branch->nr - i - 1]; |
1563 | } | 1565 | } |
1564 | 1566 | ||
1565 | nr = remove_loops(be, nr); | 1567 | nr = remove_loops(be, nr); |
1566 | 1568 | ||
1567 | for (i = 0; i < nr; i++) { | 1569 | for (i = 0; i < nr; i++) { |
1568 | err = add_callchain_ip(thread, parent, root_al, | 1570 | err = add_callchain_ip(thread, parent, root_al, |
1569 | true, be[i].to); | 1571 | true, be[i].to); |
1570 | if (!err) | 1572 | if (!err) |
1571 | err = add_callchain_ip(thread, parent, root_al, | 1573 | err = add_callchain_ip(thread, parent, root_al, |
1572 | true, be[i].from); | 1574 | true, be[i].from); |
1573 | if (err == -EINVAL) | 1575 | if (err == -EINVAL) |
1574 | break; | 1576 | break; |
1575 | if (err) | 1577 | if (err) |
1576 | return err; | 1578 | return err; |
1577 | } | 1579 | } |
1578 | chain_nr -= nr; | 1580 | chain_nr -= nr; |
1579 | } | 1581 | } |
1580 | 1582 | ||
1581 | check_calls: | 1583 | check_calls: |
1582 | if (chain->nr > PERF_MAX_STACK_DEPTH) { | 1584 | if (chain->nr > PERF_MAX_STACK_DEPTH) { |
1583 | pr_warning("corrupted callchain. skipping...\n"); | 1585 | pr_warning("corrupted callchain. skipping...\n"); |
1584 | return 0; | 1586 | return 0; |
1585 | } | 1587 | } |
1586 | 1588 | ||
1587 | for (i = first_call; i < chain_nr; i++) { | 1589 | for (i = first_call; i < chain_nr; i++) { |
1588 | u64 ip; | 1590 | u64 ip; |
1589 | 1591 | ||
1590 | if (callchain_param.order == ORDER_CALLEE) | 1592 | if (callchain_param.order == ORDER_CALLEE) |
1591 | j = i; | 1593 | j = i; |
1592 | else | 1594 | else |
1593 | j = chain->nr - i - 1; | 1595 | j = chain->nr - i - 1; |
1594 | 1596 | ||
1595 | #ifdef HAVE_SKIP_CALLCHAIN_IDX | 1597 | #ifdef HAVE_SKIP_CALLCHAIN_IDX |
1596 | if (j == skip_idx) | 1598 | if (j == skip_idx) |
1597 | continue; | 1599 | continue; |
1598 | #endif | 1600 | #endif |
1599 | ip = chain->ips[j]; | 1601 | ip = chain->ips[j]; |
1600 | 1602 | ||
1601 | err = add_callchain_ip(thread, parent, root_al, false, ip); | 1603 | err = add_callchain_ip(thread, parent, root_al, false, ip); |
1602 | 1604 | ||
1603 | if (err) | 1605 | if (err) |
1604 | return (err < 0) ? err : 0; | 1606 | return (err < 0) ? err : 0; |
1605 | } | 1607 | } |
1606 | 1608 | ||
1607 | return 0; | 1609 | return 0; |
1608 | } | 1610 | } |
1609 | 1611 | ||
1610 | static int unwind_entry(struct unwind_entry *entry, void *arg) | 1612 | static int unwind_entry(struct unwind_entry *entry, void *arg) |
1611 | { | 1613 | { |
1612 | struct callchain_cursor *cursor = arg; | 1614 | struct callchain_cursor *cursor = arg; |
1613 | return callchain_cursor_append(cursor, entry->ip, | 1615 | return callchain_cursor_append(cursor, entry->ip, |
1614 | entry->map, entry->sym); | 1616 | entry->map, entry->sym); |
1615 | } | 1617 | } |
1616 | 1618 | ||
1617 | int thread__resolve_callchain(struct thread *thread, | 1619 | int thread__resolve_callchain(struct thread *thread, |
1618 | struct perf_evsel *evsel, | 1620 | struct perf_evsel *evsel, |
1619 | struct perf_sample *sample, | 1621 | struct perf_sample *sample, |
1620 | struct symbol **parent, | 1622 | struct symbol **parent, |
1621 | struct addr_location *root_al, | 1623 | struct addr_location *root_al, |
1622 | int max_stack) | 1624 | int max_stack) |
1623 | { | 1625 | { |
1624 | int ret = thread__resolve_callchain_sample(thread, sample->callchain, | 1626 | int ret = thread__resolve_callchain_sample(thread, sample->callchain, |
1625 | sample->branch_stack, | 1627 | sample->branch_stack, |
1626 | parent, root_al, max_stack); | 1628 | parent, root_al, max_stack); |
1627 | if (ret) | 1629 | if (ret) |
1628 | return ret; | 1630 | return ret; |
1629 | 1631 | ||
1630 | /* Can we do dwarf post unwind? */ | 1632 | /* Can we do dwarf post unwind? */ |
1631 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | 1633 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && |
1632 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | 1634 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) |
1633 | return 0; | 1635 | return 0; |
1634 | 1636 | ||
1635 | /* Bail out if nothing was captured. */ | 1637 | /* Bail out if nothing was captured. */ |
1636 | if ((!sample->user_regs.regs) || | 1638 | if ((!sample->user_regs.regs) || |
1637 | (!sample->user_stack.size)) | 1639 | (!sample->user_stack.size)) |
1638 | return 0; | 1640 | return 0; |
1639 | 1641 | ||
1640 | return unwind__get_entries(unwind_entry, &callchain_cursor, | 1642 | return unwind__get_entries(unwind_entry, &callchain_cursor, |
1641 | thread, sample, max_stack); | 1643 | thread, sample, max_stack); |
1642 | 1644 | ||
1643 | } | 1645 | } |
1644 | 1646 | ||
1645 | int machine__for_each_thread(struct machine *machine, | 1647 | int machine__for_each_thread(struct machine *machine, |
1646 | int (*fn)(struct thread *thread, void *p), | 1648 | int (*fn)(struct thread *thread, void *p), |
1647 | void *priv) | 1649 | void *priv) |
1648 | { | 1650 | { |
1649 | struct rb_node *nd; | 1651 | struct rb_node *nd; |
1650 | struct thread *thread; | 1652 | struct thread *thread; |
1651 | int rc = 0; | 1653 | int rc = 0; |
1652 | 1654 | ||
1653 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | 1655 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { |
1654 | thread = rb_entry(nd, struct thread, rb_node); | 1656 | thread = rb_entry(nd, struct thread, rb_node); |
1655 | rc = fn(thread, priv); | 1657 | rc = fn(thread, priv); |
1656 | if (rc != 0) | 1658 | if (rc != 0) |
1657 | return rc; | 1659 | return rc; |
1658 | } | 1660 | } |
1659 | 1661 | ||
1660 | list_for_each_entry(thread, &machine->dead_threads, node) { | 1662 | list_for_each_entry(thread, &machine->dead_threads, node) { |
1661 | rc = fn(thread, priv); | 1663 | rc = fn(thread, priv); |
1662 | if (rc != 0) | 1664 | if (rc != 0) |
1663 | return rc; | 1665 | return rc; |
1664 | } | 1666 | } |
1665 | return rc; | 1667 | return rc; |
1666 | } | 1668 | } |
1667 | 1669 | ||
1668 | int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, | 1670 | int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, |
1669 | struct target *target, struct thread_map *threads, | 1671 | struct target *target, struct thread_map *threads, |
1670 | perf_event__handler_t process, bool data_mmap) | 1672 | perf_event__handler_t process, bool data_mmap) |
1671 | { | 1673 | { |
1672 | if (target__has_task(target)) | 1674 | if (target__has_task(target)) |
1673 | return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); | 1675 | return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); |
1674 | else if (target__has_cpu(target)) | 1676 | else if (target__has_cpu(target)) |
1675 | return perf_event__synthesize_threads(tool, process, machine, data_mmap); | 1677 | return perf_event__synthesize_threads(tool, process, machine, data_mmap); |
1676 | /* command specified */ | 1678 | /* command specified */ |
1677 | return 0; | 1679 | return 0; |
1678 | } | 1680 | } |
1679 | 1681 | ||
1680 | pid_t machine__get_current_tid(struct machine *machine, int cpu) | 1682 | pid_t machine__get_current_tid(struct machine *machine, int cpu) |
1681 | { | 1683 | { |
1682 | if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid) | 1684 | if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid) |
1683 | return -1; | 1685 | return -1; |
1684 | 1686 | ||
1685 | return machine->current_tid[cpu]; | 1687 | return machine->current_tid[cpu]; |
1686 | } | 1688 | } |
1687 | 1689 | ||
1688 | int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, | 1690 | int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, |
1689 | pid_t tid) | 1691 | pid_t tid) |
1690 | { | 1692 | { |
1691 | struct thread *thread; | 1693 | struct thread *thread; |
1692 | 1694 | ||
1693 | if (cpu < 0) | 1695 | if (cpu < 0) |
1694 | return -EINVAL; | 1696 | return -EINVAL; |
1695 | 1697 | ||
1696 | if (!machine->current_tid) { | 1698 | if (!machine->current_tid) { |
1697 | int i; | 1699 | int i; |
1698 | 1700 | ||
1699 | machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t)); | 1701 | machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t)); |
1700 | if (!machine->current_tid) | 1702 | if (!machine->current_tid) |
1701 | return -ENOMEM; | 1703 | return -ENOMEM; |
1702 | for (i = 0; i < MAX_NR_CPUS; i++) | 1704 | for (i = 0; i < MAX_NR_CPUS; i++) |
1703 | machine->current_tid[i] = -1; | 1705 | machine->current_tid[i] = -1; |
1704 | } | 1706 | } |
1705 | 1707 | ||
1706 | if (cpu >= MAX_NR_CPUS) { | 1708 | if (cpu >= MAX_NR_CPUS) { |
1707 | pr_err("Requested CPU %d too large. ", cpu); | 1709 | pr_err("Requested CPU %d too large. ", cpu); |
1708 | pr_err("Consider raising MAX_NR_CPUS\n"); | 1710 | pr_err("Consider raising MAX_NR_CPUS\n"); |
1709 | return -EINVAL; | 1711 | return -EINVAL; |
1710 | } | 1712 | } |
1711 | 1713 | ||
1712 | machine->current_tid[cpu] = tid; | 1714 | machine->current_tid[cpu] = tid; |
1713 | 1715 | ||
1714 | thread = machine__findnew_thread(machine, pid, tid); | 1716 | thread = machine__findnew_thread(machine, pid, tid); |
1715 | if (!thread) | 1717 | if (!thread) |
1716 | return -ENOMEM; | 1718 | return -ENOMEM; |
1717 | 1719 | ||
1718 | thread->cpu = cpu; | 1720 | thread->cpu = cpu; |
1719 | 1721 | ||
1720 | return 0; | 1722 | return 0; |
1721 | } | 1723 | } |
1722 | 1724 | ||
1723 | int machine__get_kernel_start(struct machine *machine) | 1725 | int machine__get_kernel_start(struct machine *machine) |
1724 | { | 1726 | { |
1725 | struct map *map = machine__kernel_map(machine, MAP__FUNCTION); | 1727 | struct map *map = machine__kernel_map(machine, MAP__FUNCTION); |
1726 | int err = 0; | 1728 | int err = 0; |
1727 | 1729 | ||
1728 | /* | 1730 | /* |
1729 | * The only addresses above 2^63 are kernel addresses of a 64-bit | 1731 | * The only addresses above 2^63 are kernel addresses of a 64-bit |
1730 | * kernel. Note that addresses are unsigned so that on a 32-bit system | 1732 | * kernel. Note that addresses are unsigned so that on a 32-bit system |
1731 | * all addresses including kernel addresses are less than 2^32. In | 1733 | * all addresses including kernel addresses are less than 2^32. In |
1732 | * that case (32-bit system), if the kernel mapping is unknown, all | 1734 | * that case (32-bit system), if the kernel mapping is unknown, all |
1733 | * addresses will be assumed to be in user space - see | 1735 | * addresses will be assumed to be in user space - see |
1734 | * machine__kernel_ip(). | 1736 | * machine__kernel_ip(). |
1735 | */ | 1737 | */ |
1736 | machine->kernel_start = 1ULL << 63; | 1738 | machine->kernel_start = 1ULL << 63; |
1737 | if (map) { | 1739 | if (map) { |
1738 | err = map__load(map, machine->symbol_filter); | 1740 | err = map__load(map, machine->symbol_filter); |
1739 | if (map->start) | 1741 | if (map->start) |
1740 | machine->kernel_start = map->start; | 1742 | machine->kernel_start = map->start; |
1741 | } | 1743 | } |
1742 | return err; | 1744 | return err; |
1743 | } | 1745 | } |
tools/perf/util/probe-event.c
1 | /* | 1 | /* |
2 | * probe-event.c : perf-probe definition to probe_events format converter | 2 | * probe-event.c : perf-probe definition to probe_events format converter |
3 | * | 3 | * |
4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> | 4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sys/utsname.h> | 22 | #include <sys/utsname.h> |
23 | #include <sys/types.h> | 23 | #include <sys/types.h> |
24 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
26 | #include <errno.h> | 26 | #include <errno.h> |
27 | #include <stdio.h> | 27 | #include <stdio.h> |
28 | #include <unistd.h> | 28 | #include <unistd.h> |
29 | #include <stdlib.h> | 29 | #include <stdlib.h> |
30 | #include <string.h> | 30 | #include <string.h> |
31 | #include <stdarg.h> | 31 | #include <stdarg.h> |
32 | #include <limits.h> | 32 | #include <limits.h> |
33 | #include <elf.h> | 33 | #include <elf.h> |
34 | 34 | ||
35 | #include "util.h" | 35 | #include "util.h" |
36 | #include "event.h" | 36 | #include "event.h" |
37 | #include "strlist.h" | 37 | #include "strlist.h" |
38 | #include "debug.h" | 38 | #include "debug.h" |
39 | #include "cache.h" | 39 | #include "cache.h" |
40 | #include "color.h" | 40 | #include "color.h" |
41 | #include "symbol.h" | 41 | #include "symbol.h" |
42 | #include "thread.h" | 42 | #include "thread.h" |
43 | #include <api/fs/debugfs.h> | 43 | #include <api/fs/debugfs.h> |
44 | #include "trace-event.h" /* For __maybe_unused */ | 44 | #include "trace-event.h" /* For __maybe_unused */ |
45 | #include "probe-event.h" | 45 | #include "probe-event.h" |
46 | #include "probe-finder.h" | 46 | #include "probe-finder.h" |
47 | #include "session.h" | 47 | #include "session.h" |
48 | 48 | ||
49 | #define MAX_CMDLEN 256 | 49 | #define MAX_CMDLEN 256 |
50 | #define PERFPROBE_GROUP "probe" | 50 | #define PERFPROBE_GROUP "probe" |
51 | 51 | ||
52 | bool probe_event_dry_run; /* Dry run flag */ | 52 | bool probe_event_dry_run; /* Dry run flag */ |
53 | 53 | ||
54 | #define semantic_error(msg ...) pr_err("Semantic error :" msg) | 54 | #define semantic_error(msg ...) pr_err("Semantic error :" msg) |
55 | 55 | ||
56 | /* If there is no space to write, returns -E2BIG. */ | 56 | /* If there is no space to write, returns -E2BIG. */ |
57 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 57 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
58 | __attribute__((format(printf, 3, 4))); | 58 | __attribute__((format(printf, 3, 4))); |
59 | 59 | ||
60 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 60 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
61 | { | 61 | { |
62 | int ret; | 62 | int ret; |
63 | va_list ap; | 63 | va_list ap; |
64 | va_start(ap, format); | 64 | va_start(ap, format); |
65 | ret = vsnprintf(str, size, format, ap); | 65 | ret = vsnprintf(str, size, format, ap); |
66 | va_end(ap); | 66 | va_end(ap); |
67 | if (ret >= (int)size) | 67 | if (ret >= (int)size) |
68 | ret = -E2BIG; | 68 | ret = -E2BIG; |
69 | return ret; | 69 | return ret; |
70 | } | 70 | } |
71 | 71 | ||
72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
73 | static void clear_probe_trace_event(struct probe_trace_event *tev); | 73 | static void clear_probe_trace_event(struct probe_trace_event *tev); |
74 | static struct machine *host_machine; | 74 | static struct machine *host_machine; |
75 | 75 | ||
76 | /* Initialize symbol maps and path of vmlinux/modules */ | 76 | /* Initialize symbol maps and path of vmlinux/modules */ |
77 | static int init_symbol_maps(bool user_only) | 77 | static int init_symbol_maps(bool user_only) |
78 | { | 78 | { |
79 | int ret; | 79 | int ret; |
80 | 80 | ||
81 | symbol_conf.sort_by_name = true; | 81 | symbol_conf.sort_by_name = true; |
82 | ret = symbol__init(NULL); | 82 | ret = symbol__init(NULL); |
83 | if (ret < 0) { | 83 | if (ret < 0) { |
84 | pr_debug("Failed to init symbol map.\n"); | 84 | pr_debug("Failed to init symbol map.\n"); |
85 | goto out; | 85 | goto out; |
86 | } | 86 | } |
87 | 87 | ||
88 | if (host_machine || user_only) /* already initialized */ | 88 | if (host_machine || user_only) /* already initialized */ |
89 | return 0; | 89 | return 0; |
90 | 90 | ||
91 | if (symbol_conf.vmlinux_name) | 91 | if (symbol_conf.vmlinux_name) |
92 | pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); | 92 | pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); |
93 | 93 | ||
94 | host_machine = machine__new_host(); | 94 | host_machine = machine__new_host(); |
95 | if (!host_machine) { | 95 | if (!host_machine) { |
96 | pr_debug("machine__new_host() failed.\n"); | 96 | pr_debug("machine__new_host() failed.\n"); |
97 | symbol__exit(); | 97 | symbol__exit(); |
98 | ret = -1; | 98 | ret = -1; |
99 | } | 99 | } |
100 | out: | 100 | out: |
101 | if (ret < 0) | 101 | if (ret < 0) |
102 | pr_warning("Failed to init vmlinux path.\n"); | 102 | pr_warning("Failed to init vmlinux path.\n"); |
103 | return ret; | 103 | return ret; |
104 | } | 104 | } |
105 | 105 | ||
106 | static void exit_symbol_maps(void) | 106 | static void exit_symbol_maps(void) |
107 | { | 107 | { |
108 | if (host_machine) { | 108 | if (host_machine) { |
109 | machine__delete(host_machine); | 109 | machine__delete(host_machine); |
110 | host_machine = NULL; | 110 | host_machine = NULL; |
111 | } | 111 | } |
112 | symbol__exit(); | 112 | symbol__exit(); |
113 | } | 113 | } |
114 | 114 | ||
115 | static struct symbol *__find_kernel_function_by_name(const char *name, | 115 | static struct symbol *__find_kernel_function_by_name(const char *name, |
116 | struct map **mapp) | 116 | struct map **mapp) |
117 | { | 117 | { |
118 | return machine__find_kernel_function_by_name(host_machine, name, mapp, | 118 | return machine__find_kernel_function_by_name(host_machine, name, mapp, |
119 | NULL); | 119 | NULL); |
120 | } | 120 | } |
121 | 121 | ||
122 | static struct symbol *__find_kernel_function(u64 addr, struct map **mapp) | 122 | static struct symbol *__find_kernel_function(u64 addr, struct map **mapp) |
123 | { | 123 | { |
124 | return machine__find_kernel_function(host_machine, addr, mapp, NULL); | 124 | return machine__find_kernel_function(host_machine, addr, mapp, NULL); |
125 | } | 125 | } |
126 | 126 | ||
127 | static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) | 127 | static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) |
128 | { | 128 | { |
129 | /* kmap->ref_reloc_sym should be set if host_machine is initialized */ | 129 | /* kmap->ref_reloc_sym should be set if host_machine is initialized */ |
130 | struct kmap *kmap; | 130 | struct kmap *kmap; |
131 | 131 | ||
132 | if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0) | 132 | if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0) |
133 | return NULL; | 133 | return NULL; |
134 | 134 | ||
135 | kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); | 135 | kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); |
136 | return kmap->ref_reloc_sym; | 136 | return kmap->ref_reloc_sym; |
137 | } | 137 | } |
138 | 138 | ||
139 | static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) | 139 | static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) |
140 | { | 140 | { |
141 | struct ref_reloc_sym *reloc_sym; | 141 | struct ref_reloc_sym *reloc_sym; |
142 | struct symbol *sym; | 142 | struct symbol *sym; |
143 | struct map *map; | 143 | struct map *map; |
144 | 144 | ||
145 | /* ref_reloc_sym is just a label. Need a special fix*/ | 145 | /* ref_reloc_sym is just a label. Need a special fix*/ |
146 | reloc_sym = kernel_get_ref_reloc_sym(); | 146 | reloc_sym = kernel_get_ref_reloc_sym(); |
147 | if (reloc_sym && strcmp(name, reloc_sym->name) == 0) | 147 | if (reloc_sym && strcmp(name, reloc_sym->name) == 0) |
148 | return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; | 148 | return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; |
149 | else { | 149 | else { |
150 | sym = __find_kernel_function_by_name(name, &map); | 150 | sym = __find_kernel_function_by_name(name, &map); |
151 | if (sym) | 151 | if (sym) |
152 | return map->unmap_ip(map, sym->start) - | 152 | return map->unmap_ip(map, sym->start) - |
153 | (reloc) ? 0 : map->reloc; | 153 | (reloc) ? 0 : map->reloc; |
154 | } | 154 | } |
155 | return 0; | 155 | return 0; |
156 | } | 156 | } |
157 | 157 | ||
158 | static struct map *kernel_get_module_map(const char *module) | 158 | static struct map *kernel_get_module_map(const char *module) |
159 | { | 159 | { |
160 | struct rb_node *nd; | 160 | struct rb_node *nd; |
161 | struct map_groups *grp = &host_machine->kmaps; | 161 | struct map_groups *grp = &host_machine->kmaps; |
162 | 162 | ||
163 | /* A file path -- this is an offline module */ | 163 | /* A file path -- this is an offline module */ |
164 | if (module && strchr(module, '/')) | 164 | if (module && strchr(module, '/')) |
165 | return machine__new_module(host_machine, 0, module); | 165 | return machine__new_module(host_machine, 0, module); |
166 | 166 | ||
167 | if (!module) | 167 | if (!module) |
168 | module = "kernel"; | 168 | module = "kernel"; |
169 | 169 | ||
170 | for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { | 170 | for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { |
171 | struct map *pos = rb_entry(nd, struct map, rb_node); | 171 | struct map *pos = rb_entry(nd, struct map, rb_node); |
172 | if (strncmp(pos->dso->short_name + 1, module, | 172 | if (strncmp(pos->dso->short_name + 1, module, |
173 | pos->dso->short_name_len - 2) == 0) { | 173 | pos->dso->short_name_len - 2) == 0) { |
174 | return pos; | 174 | return pos; |
175 | } | 175 | } |
176 | } | 176 | } |
177 | return NULL; | 177 | return NULL; |
178 | } | 178 | } |
179 | 179 | ||
180 | static struct dso *kernel_get_module_dso(const char *module) | 180 | static struct dso *kernel_get_module_dso(const char *module) |
181 | { | 181 | { |
182 | struct dso *dso; | 182 | struct dso *dso; |
183 | struct map *map; | 183 | struct map *map; |
184 | const char *vmlinux_name; | 184 | const char *vmlinux_name; |
185 | 185 | ||
186 | if (module) { | 186 | if (module) { |
187 | list_for_each_entry(dso, &host_machine->kernel_dsos.head, | 187 | list_for_each_entry(dso, &host_machine->kernel_dsos.head, |
188 | node) { | 188 | node) { |
189 | if (strncmp(dso->short_name + 1, module, | 189 | if (strncmp(dso->short_name + 1, module, |
190 | dso->short_name_len - 2) == 0) | 190 | dso->short_name_len - 2) == 0) |
191 | goto found; | 191 | goto found; |
192 | } | 192 | } |
193 | pr_debug("Failed to find module %s.\n", module); | 193 | pr_debug("Failed to find module %s.\n", module); |
194 | return NULL; | 194 | return NULL; |
195 | } | 195 | } |
196 | 196 | ||
197 | map = host_machine->vmlinux_maps[MAP__FUNCTION]; | 197 | map = host_machine->vmlinux_maps[MAP__FUNCTION]; |
198 | dso = map->dso; | 198 | dso = map->dso; |
199 | 199 | ||
200 | vmlinux_name = symbol_conf.vmlinux_name; | 200 | vmlinux_name = symbol_conf.vmlinux_name; |
201 | if (vmlinux_name) { | 201 | if (vmlinux_name) { |
202 | if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) | 202 | if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) |
203 | return NULL; | 203 | return NULL; |
204 | } else { | 204 | } else { |
205 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { | 205 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { |
206 | pr_debug("Failed to load kernel map.\n"); | 206 | pr_debug("Failed to load kernel map.\n"); |
207 | return NULL; | 207 | return NULL; |
208 | } | 208 | } |
209 | } | 209 | } |
210 | found: | 210 | found: |
211 | return dso; | 211 | return dso; |
212 | } | 212 | } |
213 | 213 | ||
214 | const char *kernel_get_module_path(const char *module) | 214 | const char *kernel_get_module_path(const char *module) |
215 | { | 215 | { |
216 | struct dso *dso = kernel_get_module_dso(module); | 216 | struct dso *dso = kernel_get_module_dso(module); |
217 | return (dso) ? dso->long_name : NULL; | 217 | return (dso) ? dso->long_name : NULL; |
218 | } | 218 | } |
219 | 219 | ||
220 | static int convert_exec_to_group(const char *exec, char **result) | 220 | static int convert_exec_to_group(const char *exec, char **result) |
221 | { | 221 | { |
222 | char *ptr1, *ptr2, *exec_copy; | 222 | char *ptr1, *ptr2, *exec_copy; |
223 | char buf[64]; | 223 | char buf[64]; |
224 | int ret; | 224 | int ret; |
225 | 225 | ||
226 | exec_copy = strdup(exec); | 226 | exec_copy = strdup(exec); |
227 | if (!exec_copy) | 227 | if (!exec_copy) |
228 | return -ENOMEM; | 228 | return -ENOMEM; |
229 | 229 | ||
230 | ptr1 = basename(exec_copy); | 230 | ptr1 = basename(exec_copy); |
231 | if (!ptr1) { | 231 | if (!ptr1) { |
232 | ret = -EINVAL; | 232 | ret = -EINVAL; |
233 | goto out; | 233 | goto out; |
234 | } | 234 | } |
235 | 235 | ||
236 | ptr2 = strpbrk(ptr1, "-._"); | 236 | ptr2 = strpbrk(ptr1, "-._"); |
237 | if (ptr2) | 237 | if (ptr2) |
238 | *ptr2 = '\0'; | 238 | *ptr2 = '\0'; |
239 | ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); | 239 | ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); |
240 | if (ret < 0) | 240 | if (ret < 0) |
241 | goto out; | 241 | goto out; |
242 | 242 | ||
243 | *result = strdup(buf); | 243 | *result = strdup(buf); |
244 | ret = *result ? 0 : -ENOMEM; | 244 | ret = *result ? 0 : -ENOMEM; |
245 | 245 | ||
246 | out: | 246 | out: |
247 | free(exec_copy); | 247 | free(exec_copy); |
248 | return ret; | 248 | return ret; |
249 | } | 249 | } |
250 | 250 | ||
251 | static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) | 251 | static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) |
252 | { | 252 | { |
253 | int i; | 253 | int i; |
254 | 254 | ||
255 | for (i = 0; i < ntevs; i++) | 255 | for (i = 0; i < ntevs; i++) |
256 | clear_probe_trace_event(tevs + i); | 256 | clear_probe_trace_event(tevs + i); |
257 | } | 257 | } |
258 | 258 | ||
259 | #ifdef HAVE_DWARF_SUPPORT | 259 | #ifdef HAVE_DWARF_SUPPORT |
260 | 260 | ||
261 | /* Open new debuginfo of given module */ | 261 | /* Open new debuginfo of given module */ |
262 | static struct debuginfo *open_debuginfo(const char *module, bool silent) | 262 | static struct debuginfo *open_debuginfo(const char *module, bool silent) |
263 | { | 263 | { |
264 | const char *path = module; | 264 | const char *path = module; |
265 | struct debuginfo *ret; | 265 | struct debuginfo *ret; |
266 | 266 | ||
267 | if (!module || !strchr(module, '/')) { | 267 | if (!module || !strchr(module, '/')) { |
268 | path = kernel_get_module_path(module); | 268 | path = kernel_get_module_path(module); |
269 | if (!path) { | 269 | if (!path) { |
270 | if (!silent) | 270 | if (!silent) |
271 | pr_err("Failed to find path of %s module.\n", | 271 | pr_err("Failed to find path of %s module.\n", |
272 | module ?: "kernel"); | 272 | module ?: "kernel"); |
273 | return NULL; | 273 | return NULL; |
274 | } | 274 | } |
275 | } | 275 | } |
276 | ret = debuginfo__new(path); | 276 | ret = debuginfo__new(path); |
277 | if (!ret && !silent) { | 277 | if (!ret && !silent) { |
278 | pr_warning("The %s file has no debug information.\n", path); | 278 | pr_warning("The %s file has no debug information.\n", path); |
279 | if (!module || !strtailcmp(path, ".ko")) | 279 | if (!module || !strtailcmp(path, ".ko")) |
280 | pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, "); | 280 | pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, "); |
281 | else | 281 | else |
282 | pr_warning("Rebuild with -g, "); | 282 | pr_warning("Rebuild with -g, "); |
283 | pr_warning("or install an appropriate debuginfo package.\n"); | 283 | pr_warning("or install an appropriate debuginfo package.\n"); |
284 | } | 284 | } |
285 | return ret; | 285 | return ret; |
286 | } | 286 | } |
287 | 287 | ||
288 | 288 | ||
289 | static int get_text_start_address(const char *exec, unsigned long *address) | 289 | static int get_text_start_address(const char *exec, unsigned long *address) |
290 | { | 290 | { |
291 | Elf *elf; | 291 | Elf *elf; |
292 | GElf_Ehdr ehdr; | 292 | GElf_Ehdr ehdr; |
293 | GElf_Shdr shdr; | 293 | GElf_Shdr shdr; |
294 | int fd, ret = -ENOENT; | 294 | int fd, ret = -ENOENT; |
295 | 295 | ||
296 | fd = open(exec, O_RDONLY); | 296 | fd = open(exec, O_RDONLY); |
297 | if (fd < 0) | 297 | if (fd < 0) |
298 | return -errno; | 298 | return -errno; |
299 | 299 | ||
300 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 300 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
301 | if (elf == NULL) | 301 | if (elf == NULL) |
302 | return -EINVAL; | 302 | return -EINVAL; |
303 | 303 | ||
304 | if (gelf_getehdr(elf, &ehdr) == NULL) | 304 | if (gelf_getehdr(elf, &ehdr) == NULL) |
305 | goto out; | 305 | goto out; |
306 | 306 | ||
307 | if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) | 307 | if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) |
308 | goto out; | 308 | goto out; |
309 | 309 | ||
310 | *address = shdr.sh_addr - shdr.sh_offset; | 310 | *address = shdr.sh_addr - shdr.sh_offset; |
311 | ret = 0; | 311 | ret = 0; |
312 | out: | 312 | out: |
313 | elf_end(elf); | 313 | elf_end(elf); |
314 | return ret; | 314 | return ret; |
315 | } | 315 | } |
316 | 316 | ||
317 | /* | 317 | /* |
318 | * Convert trace point to probe point with debuginfo | 318 | * Convert trace point to probe point with debuginfo |
319 | */ | 319 | */ |
320 | static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, | 320 | static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, |
321 | struct perf_probe_point *pp, | 321 | struct perf_probe_point *pp, |
322 | bool is_kprobe) | 322 | bool is_kprobe) |
323 | { | 323 | { |
324 | struct debuginfo *dinfo = NULL; | 324 | struct debuginfo *dinfo = NULL; |
325 | unsigned long stext = 0; | 325 | unsigned long stext = 0; |
326 | u64 addr = tp->address; | 326 | u64 addr = tp->address; |
327 | int ret = -ENOENT; | 327 | int ret = -ENOENT; |
328 | 328 | ||
329 | /* convert the address to dwarf address */ | 329 | /* convert the address to dwarf address */ |
330 | if (!is_kprobe) { | 330 | if (!is_kprobe) { |
331 | if (!addr) { | 331 | if (!addr) { |
332 | ret = -EINVAL; | 332 | ret = -EINVAL; |
333 | goto error; | 333 | goto error; |
334 | } | 334 | } |
335 | ret = get_text_start_address(tp->module, &stext); | 335 | ret = get_text_start_address(tp->module, &stext); |
336 | if (ret < 0) | 336 | if (ret < 0) |
337 | goto error; | 337 | goto error; |
338 | addr += stext; | 338 | addr += stext; |
339 | } else { | 339 | } else { |
340 | addr = kernel_get_symbol_address_by_name(tp->symbol, false); | 340 | addr = kernel_get_symbol_address_by_name(tp->symbol, false); |
341 | if (addr == 0) | 341 | if (addr == 0) |
342 | goto error; | 342 | goto error; |
343 | addr += tp->offset; | 343 | addr += tp->offset; |
344 | } | 344 | } |
345 | 345 | ||
346 | pr_debug("try to find information at %" PRIx64 " in %s\n", addr, | 346 | pr_debug("try to find information at %" PRIx64 " in %s\n", addr, |
347 | tp->module ? : "kernel"); | 347 | tp->module ? : "kernel"); |
348 | 348 | ||
349 | dinfo = open_debuginfo(tp->module, verbose == 0); | 349 | dinfo = open_debuginfo(tp->module, verbose == 0); |
350 | if (dinfo) { | 350 | if (dinfo) { |
351 | ret = debuginfo__find_probe_point(dinfo, | 351 | ret = debuginfo__find_probe_point(dinfo, |
352 | (unsigned long)addr, pp); | 352 | (unsigned long)addr, pp); |
353 | debuginfo__delete(dinfo); | 353 | debuginfo__delete(dinfo); |
354 | } else | 354 | } else |
355 | ret = -ENOENT; | 355 | ret = -ENOENT; |
356 | 356 | ||
357 | if (ret > 0) { | 357 | if (ret > 0) { |
358 | pp->retprobe = tp->retprobe; | 358 | pp->retprobe = tp->retprobe; |
359 | return 0; | 359 | return 0; |
360 | } | 360 | } |
361 | error: | 361 | error: |
362 | pr_debug("Failed to find corresponding probes from debuginfo.\n"); | 362 | pr_debug("Failed to find corresponding probes from debuginfo.\n"); |
363 | return ret ? : -ENOENT; | 363 | return ret ? : -ENOENT; |
364 | } | 364 | } |
365 | 365 | ||
366 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | 366 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, |
367 | int ntevs, const char *exec) | 367 | int ntevs, const char *exec) |
368 | { | 368 | { |
369 | int i, ret = 0; | 369 | int i, ret = 0; |
370 | unsigned long stext = 0; | 370 | unsigned long stext = 0; |
371 | 371 | ||
372 | if (!exec) | 372 | if (!exec) |
373 | return 0; | 373 | return 0; |
374 | 374 | ||
375 | ret = get_text_start_address(exec, &stext); | 375 | ret = get_text_start_address(exec, &stext); |
376 | if (ret < 0) | 376 | if (ret < 0) |
377 | return ret; | 377 | return ret; |
378 | 378 | ||
379 | for (i = 0; i < ntevs && ret >= 0; i++) { | 379 | for (i = 0; i < ntevs && ret >= 0; i++) { |
380 | /* point.address is the addres of point.symbol + point.offset */ | 380 | /* point.address is the addres of point.symbol + point.offset */ |
381 | tevs[i].point.address -= stext; | 381 | tevs[i].point.address -= stext; |
382 | tevs[i].point.module = strdup(exec); | 382 | tevs[i].point.module = strdup(exec); |
383 | if (!tevs[i].point.module) { | 383 | if (!tevs[i].point.module) { |
384 | ret = -ENOMEM; | 384 | ret = -ENOMEM; |
385 | break; | 385 | break; |
386 | } | 386 | } |
387 | tevs[i].uprobes = true; | 387 | tevs[i].uprobes = true; |
388 | } | 388 | } |
389 | 389 | ||
390 | return ret; | 390 | return ret; |
391 | } | 391 | } |
392 | 392 | ||
393 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | 393 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, |
394 | int ntevs, const char *module) | 394 | int ntevs, const char *module) |
395 | { | 395 | { |
396 | int i, ret = 0; | 396 | int i, ret = 0; |
397 | char *tmp; | 397 | char *tmp; |
398 | 398 | ||
399 | if (!module) | 399 | if (!module) |
400 | return 0; | 400 | return 0; |
401 | 401 | ||
402 | tmp = strrchr(module, '/'); | 402 | tmp = strrchr(module, '/'); |
403 | if (tmp) { | 403 | if (tmp) { |
404 | /* This is a module path -- get the module name */ | 404 | /* This is a module path -- get the module name */ |
405 | module = strdup(tmp + 1); | 405 | module = strdup(tmp + 1); |
406 | if (!module) | 406 | if (!module) |
407 | return -ENOMEM; | 407 | return -ENOMEM; |
408 | tmp = strchr(module, '.'); | 408 | tmp = strchr(module, '.'); |
409 | if (tmp) | 409 | if (tmp) |
410 | *tmp = '\0'; | 410 | *tmp = '\0'; |
411 | tmp = (char *)module; /* For free() */ | 411 | tmp = (char *)module; /* For free() */ |
412 | } | 412 | } |
413 | 413 | ||
414 | for (i = 0; i < ntevs; i++) { | 414 | for (i = 0; i < ntevs; i++) { |
415 | tevs[i].point.module = strdup(module); | 415 | tevs[i].point.module = strdup(module); |
416 | if (!tevs[i].point.module) { | 416 | if (!tevs[i].point.module) { |
417 | ret = -ENOMEM; | 417 | ret = -ENOMEM; |
418 | break; | 418 | break; |
419 | } | 419 | } |
420 | } | 420 | } |
421 | 421 | ||
422 | free(tmp); | 422 | free(tmp); |
423 | return ret; | 423 | return ret; |
424 | } | 424 | } |
425 | 425 | ||
426 | /* Post processing the probe events */ | 426 | /* Post processing the probe events */ |
427 | static int post_process_probe_trace_events(struct probe_trace_event *tevs, | 427 | static int post_process_probe_trace_events(struct probe_trace_event *tevs, |
428 | int ntevs, const char *module, | 428 | int ntevs, const char *module, |
429 | bool uprobe) | 429 | bool uprobe) |
430 | { | 430 | { |
431 | struct ref_reloc_sym *reloc_sym; | 431 | struct ref_reloc_sym *reloc_sym; |
432 | char *tmp; | 432 | char *tmp; |
433 | int i; | 433 | int i; |
434 | 434 | ||
435 | if (uprobe) | 435 | if (uprobe) |
436 | return add_exec_to_probe_trace_events(tevs, ntevs, module); | 436 | return add_exec_to_probe_trace_events(tevs, ntevs, module); |
437 | 437 | ||
438 | /* Note that currently ref_reloc_sym based probe is not for drivers */ | 438 | /* Note that currently ref_reloc_sym based probe is not for drivers */ |
439 | if (module) | 439 | if (module) |
440 | return add_module_to_probe_trace_events(tevs, ntevs, module); | 440 | return add_module_to_probe_trace_events(tevs, ntevs, module); |
441 | 441 | ||
442 | reloc_sym = kernel_get_ref_reloc_sym(); | 442 | reloc_sym = kernel_get_ref_reloc_sym(); |
443 | if (!reloc_sym) { | 443 | if (!reloc_sym) { |
444 | pr_warning("Relocated base symbol is not found!\n"); | 444 | pr_warning("Relocated base symbol is not found!\n"); |
445 | return -EINVAL; | 445 | return -EINVAL; |
446 | } | 446 | } |
447 | 447 | ||
448 | for (i = 0; i < ntevs; i++) { | 448 | for (i = 0; i < ntevs; i++) { |
449 | if (tevs[i].point.address) { | 449 | if (tevs[i].point.address) { |
450 | tmp = strdup(reloc_sym->name); | 450 | tmp = strdup(reloc_sym->name); |
451 | if (!tmp) | 451 | if (!tmp) |
452 | return -ENOMEM; | 452 | return -ENOMEM; |
453 | free(tevs[i].point.symbol); | 453 | free(tevs[i].point.symbol); |
454 | tevs[i].point.symbol = tmp; | 454 | tevs[i].point.symbol = tmp; |
455 | tevs[i].point.offset = tevs[i].point.address - | 455 | tevs[i].point.offset = tevs[i].point.address - |
456 | reloc_sym->unrelocated_addr; | 456 | reloc_sym->unrelocated_addr; |
457 | } | 457 | } |
458 | } | 458 | } |
459 | return 0; | 459 | return 0; |
460 | } | 460 | } |
461 | 461 | ||
462 | /* Try to find perf_probe_event with debuginfo */ | 462 | /* Try to find perf_probe_event with debuginfo */ |
463 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 463 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
464 | struct probe_trace_event **tevs, | 464 | struct probe_trace_event **tevs, |
465 | int max_tevs, const char *target) | 465 | int max_tevs, const char *target) |
466 | { | 466 | { |
467 | bool need_dwarf = perf_probe_event_need_dwarf(pev); | 467 | bool need_dwarf = perf_probe_event_need_dwarf(pev); |
468 | struct debuginfo *dinfo; | 468 | struct debuginfo *dinfo; |
469 | int ntevs, ret = 0; | 469 | int ntevs, ret = 0; |
470 | 470 | ||
471 | dinfo = open_debuginfo(target, !need_dwarf); | 471 | dinfo = open_debuginfo(target, !need_dwarf); |
472 | 472 | ||
473 | if (!dinfo) { | 473 | if (!dinfo) { |
474 | if (need_dwarf) | 474 | if (need_dwarf) |
475 | return -ENOENT; | 475 | return -ENOENT; |
476 | pr_debug("Could not open debuginfo. Try to use symbols.\n"); | 476 | pr_debug("Could not open debuginfo. Try to use symbols.\n"); |
477 | return 0; | 477 | return 0; |
478 | } | 478 | } |
479 | 479 | ||
480 | pr_debug("Try to find probe point from debuginfo.\n"); | 480 | pr_debug("Try to find probe point from debuginfo.\n"); |
481 | /* Searching trace events corresponding to a probe event */ | 481 | /* Searching trace events corresponding to a probe event */ |
482 | ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); | 482 | ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); |
483 | 483 | ||
484 | debuginfo__delete(dinfo); | 484 | debuginfo__delete(dinfo); |
485 | 485 | ||
486 | if (ntevs > 0) { /* Succeeded to find trace events */ | 486 | if (ntevs > 0) { /* Succeeded to find trace events */ |
487 | pr_debug("Found %d probe_trace_events.\n", ntevs); | 487 | pr_debug("Found %d probe_trace_events.\n", ntevs); |
488 | ret = post_process_probe_trace_events(*tevs, ntevs, | 488 | ret = post_process_probe_trace_events(*tevs, ntevs, |
489 | target, pev->uprobes); | 489 | target, pev->uprobes); |
490 | if (ret < 0) { | 490 | if (ret < 0) { |
491 | clear_probe_trace_events(*tevs, ntevs); | 491 | clear_probe_trace_events(*tevs, ntevs); |
492 | zfree(tevs); | 492 | zfree(tevs); |
493 | } | 493 | } |
494 | return ret < 0 ? ret : ntevs; | 494 | return ret < 0 ? ret : ntevs; |
495 | } | 495 | } |
496 | 496 | ||
497 | if (ntevs == 0) { /* No error but failed to find probe point. */ | 497 | if (ntevs == 0) { /* No error but failed to find probe point. */ |
498 | pr_warning("Probe point '%s' not found in debuginfo.\n", | 498 | pr_warning("Probe point '%s' not found in debuginfo.\n", |
499 | synthesize_perf_probe_point(&pev->point)); | 499 | synthesize_perf_probe_point(&pev->point)); |
500 | if (need_dwarf) | 500 | if (need_dwarf) |
501 | return -ENOENT; | 501 | return -ENOENT; |
502 | return 0; | 502 | return 0; |
503 | } | 503 | } |
504 | /* Error path : ntevs < 0 */ | 504 | /* Error path : ntevs < 0 */ |
505 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); | 505 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); |
506 | if (ntevs == -EBADF) { | 506 | if (ntevs == -EBADF) { |
507 | pr_warning("Warning: No dwarf info found in the vmlinux - " | 507 | pr_warning("Warning: No dwarf info found in the vmlinux - " |
508 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); | 508 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); |
509 | if (!need_dwarf) { | 509 | if (!need_dwarf) { |
510 | pr_debug("Trying to use symbols.\n"); | 510 | pr_debug("Trying to use symbols.\n"); |
511 | return 0; | 511 | return 0; |
512 | } | 512 | } |
513 | } | 513 | } |
514 | return ntevs; | 514 | return ntevs; |
515 | } | 515 | } |
516 | 516 | ||
517 | /* | 517 | /* |
518 | * Find a src file from a DWARF tag path. Prepend optional source path prefix | 518 | * Find a src file from a DWARF tag path. Prepend optional source path prefix |
519 | * and chop off leading directories that do not exist. Result is passed back as | 519 | * and chop off leading directories that do not exist. Result is passed back as |
520 | * a newly allocated path on success. | 520 | * a newly allocated path on success. |
521 | * Return 0 if file was found and readable, -errno otherwise. | 521 | * Return 0 if file was found and readable, -errno otherwise. |
522 | */ | 522 | */ |
523 | static int get_real_path(const char *raw_path, const char *comp_dir, | 523 | static int get_real_path(const char *raw_path, const char *comp_dir, |
524 | char **new_path) | 524 | char **new_path) |
525 | { | 525 | { |
526 | const char *prefix = symbol_conf.source_prefix; | 526 | const char *prefix = symbol_conf.source_prefix; |
527 | 527 | ||
528 | if (!prefix) { | 528 | if (!prefix) { |
529 | if (raw_path[0] != '/' && comp_dir) | 529 | if (raw_path[0] != '/' && comp_dir) |
530 | /* If not an absolute path, try to use comp_dir */ | 530 | /* If not an absolute path, try to use comp_dir */ |
531 | prefix = comp_dir; | 531 | prefix = comp_dir; |
532 | else { | 532 | else { |
533 | if (access(raw_path, R_OK) == 0) { | 533 | if (access(raw_path, R_OK) == 0) { |
534 | *new_path = strdup(raw_path); | 534 | *new_path = strdup(raw_path); |
535 | return 0; | 535 | return 0; |
536 | } else | 536 | } else |
537 | return -errno; | 537 | return -errno; |
538 | } | 538 | } |
539 | } | 539 | } |
540 | 540 | ||
541 | *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); | 541 | *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); |
542 | if (!*new_path) | 542 | if (!*new_path) |
543 | return -ENOMEM; | 543 | return -ENOMEM; |
544 | 544 | ||
545 | for (;;) { | 545 | for (;;) { |
546 | sprintf(*new_path, "%s/%s", prefix, raw_path); | 546 | sprintf(*new_path, "%s/%s", prefix, raw_path); |
547 | 547 | ||
548 | if (access(*new_path, R_OK) == 0) | 548 | if (access(*new_path, R_OK) == 0) |
549 | return 0; | 549 | return 0; |
550 | 550 | ||
551 | if (!symbol_conf.source_prefix) | 551 | if (!symbol_conf.source_prefix) |
552 | /* In case of searching comp_dir, don't retry */ | 552 | /* In case of searching comp_dir, don't retry */ |
553 | return -errno; | 553 | return -errno; |
554 | 554 | ||
555 | switch (errno) { | 555 | switch (errno) { |
556 | case ENAMETOOLONG: | 556 | case ENAMETOOLONG: |
557 | case ENOENT: | 557 | case ENOENT: |
558 | case EROFS: | 558 | case EROFS: |
559 | case EFAULT: | 559 | case EFAULT: |
560 | raw_path = strchr(++raw_path, '/'); | 560 | raw_path = strchr(++raw_path, '/'); |
561 | if (!raw_path) { | 561 | if (!raw_path) { |
562 | zfree(new_path); | 562 | zfree(new_path); |
563 | return -ENOENT; | 563 | return -ENOENT; |
564 | } | 564 | } |
565 | continue; | 565 | continue; |
566 | 566 | ||
567 | default: | 567 | default: |
568 | zfree(new_path); | 568 | zfree(new_path); |
569 | return -errno; | 569 | return -errno; |
570 | } | 570 | } |
571 | } | 571 | } |
572 | } | 572 | } |
573 | 573 | ||
574 | #define LINEBUF_SIZE 256 | 574 | #define LINEBUF_SIZE 256 |
575 | #define NR_ADDITIONAL_LINES 2 | 575 | #define NR_ADDITIONAL_LINES 2 |
576 | 576 | ||
577 | static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) | 577 | static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) |
578 | { | 578 | { |
579 | char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE]; | 579 | char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE]; |
580 | const char *color = show_num ? "" : PERF_COLOR_BLUE; | 580 | const char *color = show_num ? "" : PERF_COLOR_BLUE; |
581 | const char *prefix = NULL; | 581 | const char *prefix = NULL; |
582 | 582 | ||
583 | do { | 583 | do { |
584 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) | 584 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) |
585 | goto error; | 585 | goto error; |
586 | if (skip) | 586 | if (skip) |
587 | continue; | 587 | continue; |
588 | if (!prefix) { | 588 | if (!prefix) { |
589 | prefix = show_num ? "%7d " : " "; | 589 | prefix = show_num ? "%7d " : " "; |
590 | color_fprintf(stdout, color, prefix, l); | 590 | color_fprintf(stdout, color, prefix, l); |
591 | } | 591 | } |
592 | color_fprintf(stdout, color, "%s", buf); | 592 | color_fprintf(stdout, color, "%s", buf); |
593 | 593 | ||
594 | } while (strchr(buf, '\n') == NULL); | 594 | } while (strchr(buf, '\n') == NULL); |
595 | 595 | ||
596 | return 1; | 596 | return 1; |
597 | error: | 597 | error: |
598 | if (ferror(fp)) { | 598 | if (ferror(fp)) { |
599 | pr_warning("File read error: %s\n", | 599 | pr_warning("File read error: %s\n", |
600 | strerror_r(errno, sbuf, sizeof(sbuf))); | 600 | strerror_r(errno, sbuf, sizeof(sbuf))); |
601 | return -1; | 601 | return -1; |
602 | } | 602 | } |
603 | return 0; | 603 | return 0; |
604 | } | 604 | } |
605 | 605 | ||
606 | static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) | 606 | static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) |
607 | { | 607 | { |
608 | int rv = __show_one_line(fp, l, skip, show_num); | 608 | int rv = __show_one_line(fp, l, skip, show_num); |
609 | if (rv == 0) { | 609 | if (rv == 0) { |
610 | pr_warning("Source file is shorter than expected.\n"); | 610 | pr_warning("Source file is shorter than expected.\n"); |
611 | rv = -1; | 611 | rv = -1; |
612 | } | 612 | } |
613 | return rv; | 613 | return rv; |
614 | } | 614 | } |
615 | 615 | ||
616 | #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) | 616 | #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) |
617 | #define show_one_line(f,l) _show_one_line(f,l,false,false) | 617 | #define show_one_line(f,l) _show_one_line(f,l,false,false) |
618 | #define skip_one_line(f,l) _show_one_line(f,l,true,false) | 618 | #define skip_one_line(f,l) _show_one_line(f,l,true,false) |
619 | #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) | 619 | #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) |
620 | 620 | ||
621 | /* | 621 | /* |
622 | * Show line-range always requires debuginfo to find source file and | 622 | * Show line-range always requires debuginfo to find source file and |
623 | * line number. | 623 | * line number. |
624 | */ | 624 | */ |
625 | static int __show_line_range(struct line_range *lr, const char *module) | 625 | static int __show_line_range(struct line_range *lr, const char *module) |
626 | { | 626 | { |
627 | int l = 1; | 627 | int l = 1; |
628 | struct int_node *ln; | 628 | struct int_node *ln; |
629 | struct debuginfo *dinfo; | 629 | struct debuginfo *dinfo; |
630 | FILE *fp; | 630 | FILE *fp; |
631 | int ret; | 631 | int ret; |
632 | char *tmp; | 632 | char *tmp; |
633 | char sbuf[STRERR_BUFSIZE]; | 633 | char sbuf[STRERR_BUFSIZE]; |
634 | 634 | ||
635 | /* Search a line range */ | 635 | /* Search a line range */ |
636 | dinfo = open_debuginfo(module, false); | 636 | dinfo = open_debuginfo(module, false); |
637 | if (!dinfo) | 637 | if (!dinfo) |
638 | return -ENOENT; | 638 | return -ENOENT; |
639 | 639 | ||
640 | ret = debuginfo__find_line_range(dinfo, lr); | 640 | ret = debuginfo__find_line_range(dinfo, lr); |
641 | debuginfo__delete(dinfo); | 641 | debuginfo__delete(dinfo); |
642 | if (ret == 0 || ret == -ENOENT) { | 642 | if (ret == 0 || ret == -ENOENT) { |
643 | pr_warning("Specified source line is not found.\n"); | 643 | pr_warning("Specified source line is not found.\n"); |
644 | return -ENOENT; | 644 | return -ENOENT; |
645 | } else if (ret < 0) { | 645 | } else if (ret < 0) { |
646 | pr_warning("Debuginfo analysis failed.\n"); | 646 | pr_warning("Debuginfo analysis failed.\n"); |
647 | return ret; | 647 | return ret; |
648 | } | 648 | } |
649 | 649 | ||
650 | /* Convert source file path */ | 650 | /* Convert source file path */ |
651 | tmp = lr->path; | 651 | tmp = lr->path; |
652 | ret = get_real_path(tmp, lr->comp_dir, &lr->path); | 652 | ret = get_real_path(tmp, lr->comp_dir, &lr->path); |
653 | free(tmp); /* Free old path */ | 653 | free(tmp); /* Free old path */ |
654 | if (ret < 0) { | 654 | if (ret < 0) { |
655 | pr_warning("Failed to find source file path.\n"); | 655 | pr_warning("Failed to find source file path.\n"); |
656 | return ret; | 656 | return ret; |
657 | } | 657 | } |
658 | 658 | ||
659 | setup_pager(); | 659 | setup_pager(); |
660 | 660 | ||
661 | if (lr->function) | 661 | if (lr->function) |
662 | fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, | 662 | fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, |
663 | lr->start - lr->offset); | 663 | lr->start - lr->offset); |
664 | else | 664 | else |
665 | fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); | 665 | fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); |
666 | 666 | ||
667 | fp = fopen(lr->path, "r"); | 667 | fp = fopen(lr->path, "r"); |
668 | if (fp == NULL) { | 668 | if (fp == NULL) { |
669 | pr_warning("Failed to open %s: %s\n", lr->path, | 669 | pr_warning("Failed to open %s: %s\n", lr->path, |
670 | strerror_r(errno, sbuf, sizeof(sbuf))); | 670 | strerror_r(errno, sbuf, sizeof(sbuf))); |
671 | return -errno; | 671 | return -errno; |
672 | } | 672 | } |
673 | /* Skip to starting line number */ | 673 | /* Skip to starting line number */ |
674 | while (l < lr->start) { | 674 | while (l < lr->start) { |
675 | ret = skip_one_line(fp, l++); | 675 | ret = skip_one_line(fp, l++); |
676 | if (ret < 0) | 676 | if (ret < 0) |
677 | goto end; | 677 | goto end; |
678 | } | 678 | } |
679 | 679 | ||
680 | intlist__for_each(ln, lr->line_list) { | 680 | intlist__for_each(ln, lr->line_list) { |
681 | for (; ln->i > l; l++) { | 681 | for (; ln->i > l; l++) { |
682 | ret = show_one_line(fp, l - lr->offset); | 682 | ret = show_one_line(fp, l - lr->offset); |
683 | if (ret < 0) | 683 | if (ret < 0) |
684 | goto end; | 684 | goto end; |
685 | } | 685 | } |
686 | ret = show_one_line_with_num(fp, l++ - lr->offset); | 686 | ret = show_one_line_with_num(fp, l++ - lr->offset); |
687 | if (ret < 0) | 687 | if (ret < 0) |
688 | goto end; | 688 | goto end; |
689 | } | 689 | } |
690 | 690 | ||
691 | if (lr->end == INT_MAX) | 691 | if (lr->end == INT_MAX) |
692 | lr->end = l + NR_ADDITIONAL_LINES; | 692 | lr->end = l + NR_ADDITIONAL_LINES; |
693 | while (l <= lr->end) { | 693 | while (l <= lr->end) { |
694 | ret = show_one_line_or_eof(fp, l++ - lr->offset); | 694 | ret = show_one_line_or_eof(fp, l++ - lr->offset); |
695 | if (ret <= 0) | 695 | if (ret <= 0) |
696 | break; | 696 | break; |
697 | } | 697 | } |
698 | end: | 698 | end: |
699 | fclose(fp); | 699 | fclose(fp); |
700 | return ret; | 700 | return ret; |
701 | } | 701 | } |
702 | 702 | ||
703 | int show_line_range(struct line_range *lr, const char *module, bool user) | 703 | int show_line_range(struct line_range *lr, const char *module, bool user) |
704 | { | 704 | { |
705 | int ret; | 705 | int ret; |
706 | 706 | ||
707 | ret = init_symbol_maps(user); | 707 | ret = init_symbol_maps(user); |
708 | if (ret < 0) | 708 | if (ret < 0) |
709 | return ret; | 709 | return ret; |
710 | ret = __show_line_range(lr, module); | 710 | ret = __show_line_range(lr, module); |
711 | exit_symbol_maps(); | 711 | exit_symbol_maps(); |
712 | 712 | ||
713 | return ret; | 713 | return ret; |
714 | } | 714 | } |
715 | 715 | ||
716 | static int show_available_vars_at(struct debuginfo *dinfo, | 716 | static int show_available_vars_at(struct debuginfo *dinfo, |
717 | struct perf_probe_event *pev, | 717 | struct perf_probe_event *pev, |
718 | int max_vls, struct strfilter *_filter, | 718 | int max_vls, struct strfilter *_filter, |
719 | bool externs) | 719 | bool externs) |
720 | { | 720 | { |
721 | char *buf; | 721 | char *buf; |
722 | int ret, i, nvars; | 722 | int ret, i, nvars; |
723 | struct str_node *node; | 723 | struct str_node *node; |
724 | struct variable_list *vls = NULL, *vl; | 724 | struct variable_list *vls = NULL, *vl; |
725 | const char *var; | 725 | const char *var; |
726 | 726 | ||
727 | buf = synthesize_perf_probe_point(&pev->point); | 727 | buf = synthesize_perf_probe_point(&pev->point); |
728 | if (!buf) | 728 | if (!buf) |
729 | return -EINVAL; | 729 | return -EINVAL; |
730 | pr_debug("Searching variables at %s\n", buf); | 730 | pr_debug("Searching variables at %s\n", buf); |
731 | 731 | ||
732 | ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, | 732 | ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, |
733 | max_vls, externs); | 733 | max_vls, externs); |
734 | if (ret <= 0) { | 734 | if (ret <= 0) { |
735 | if (ret == 0 || ret == -ENOENT) { | 735 | if (ret == 0 || ret == -ENOENT) { |
736 | pr_err("Failed to find the address of %s\n", buf); | 736 | pr_err("Failed to find the address of %s\n", buf); |
737 | ret = -ENOENT; | 737 | ret = -ENOENT; |
738 | } else | 738 | } else |
739 | pr_warning("Debuginfo analysis failed.\n"); | 739 | pr_warning("Debuginfo analysis failed.\n"); |
740 | goto end; | 740 | goto end; |
741 | } | 741 | } |
742 | 742 | ||
743 | /* Some variables are found */ | 743 | /* Some variables are found */ |
744 | fprintf(stdout, "Available variables at %s\n", buf); | 744 | fprintf(stdout, "Available variables at %s\n", buf); |
745 | for (i = 0; i < ret; i++) { | 745 | for (i = 0; i < ret; i++) { |
746 | vl = &vls[i]; | 746 | vl = &vls[i]; |
747 | /* | 747 | /* |
748 | * A probe point might be converted to | 748 | * A probe point might be converted to |
749 | * several trace points. | 749 | * several trace points. |
750 | */ | 750 | */ |
751 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, | 751 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, |
752 | vl->point.offset); | 752 | vl->point.offset); |
753 | zfree(&vl->point.symbol); | 753 | zfree(&vl->point.symbol); |
754 | nvars = 0; | 754 | nvars = 0; |
755 | if (vl->vars) { | 755 | if (vl->vars) { |
756 | strlist__for_each(node, vl->vars) { | 756 | strlist__for_each(node, vl->vars) { |
757 | var = strchr(node->s, '\t') + 1; | 757 | var = strchr(node->s, '\t') + 1; |
758 | if (strfilter__compare(_filter, var)) { | 758 | if (strfilter__compare(_filter, var)) { |
759 | fprintf(stdout, "\t\t%s\n", node->s); | 759 | fprintf(stdout, "\t\t%s\n", node->s); |
760 | nvars++; | 760 | nvars++; |
761 | } | 761 | } |
762 | } | 762 | } |
763 | strlist__delete(vl->vars); | 763 | strlist__delete(vl->vars); |
764 | } | 764 | } |
765 | if (nvars == 0) | 765 | if (nvars == 0) |
766 | fprintf(stdout, "\t\t(No matched variables)\n"); | 766 | fprintf(stdout, "\t\t(No matched variables)\n"); |
767 | } | 767 | } |
768 | free(vls); | 768 | free(vls); |
769 | end: | 769 | end: |
770 | free(buf); | 770 | free(buf); |
771 | return ret; | 771 | return ret; |
772 | } | 772 | } |
773 | 773 | ||
774 | /* Show available variables on given probe point */ | 774 | /* Show available variables on given probe point */ |
775 | int show_available_vars(struct perf_probe_event *pevs, int npevs, | 775 | int show_available_vars(struct perf_probe_event *pevs, int npevs, |
776 | int max_vls, const char *module, | 776 | int max_vls, const char *module, |
777 | struct strfilter *_filter, bool externs) | 777 | struct strfilter *_filter, bool externs) |
778 | { | 778 | { |
779 | int i, ret = 0; | 779 | int i, ret = 0; |
780 | struct debuginfo *dinfo; | 780 | struct debuginfo *dinfo; |
781 | 781 | ||
782 | ret = init_symbol_maps(pevs->uprobes); | 782 | ret = init_symbol_maps(pevs->uprobes); |
783 | if (ret < 0) | 783 | if (ret < 0) |
784 | return ret; | 784 | return ret; |
785 | 785 | ||
786 | dinfo = open_debuginfo(module, false); | 786 | dinfo = open_debuginfo(module, false); |
787 | if (!dinfo) { | 787 | if (!dinfo) { |
788 | ret = -ENOENT; | 788 | ret = -ENOENT; |
789 | goto out; | 789 | goto out; |
790 | } | 790 | } |
791 | 791 | ||
792 | setup_pager(); | 792 | setup_pager(); |
793 | 793 | ||
794 | for (i = 0; i < npevs && ret >= 0; i++) | 794 | for (i = 0; i < npevs && ret >= 0; i++) |
795 | ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, | 795 | ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, |
796 | externs); | 796 | externs); |
797 | 797 | ||
798 | debuginfo__delete(dinfo); | 798 | debuginfo__delete(dinfo); |
799 | out: | 799 | out: |
800 | exit_symbol_maps(); | 800 | exit_symbol_maps(); |
801 | return ret; | 801 | return ret; |
802 | } | 802 | } |
803 | 803 | ||
804 | #else /* !HAVE_DWARF_SUPPORT */ | 804 | #else /* !HAVE_DWARF_SUPPORT */ |
805 | 805 | ||
806 | static int | 806 | static int |
807 | find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, | 807 | find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, |
808 | struct perf_probe_point *pp __maybe_unused, | 808 | struct perf_probe_point *pp __maybe_unused, |
809 | bool is_kprobe __maybe_unused) | 809 | bool is_kprobe __maybe_unused) |
810 | { | 810 | { |
811 | return -ENOSYS; | 811 | return -ENOSYS; |
812 | } | 812 | } |
813 | 813 | ||
814 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 814 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
815 | struct probe_trace_event **tevs __maybe_unused, | 815 | struct probe_trace_event **tevs __maybe_unused, |
816 | int max_tevs __maybe_unused, | 816 | int max_tevs __maybe_unused, |
817 | const char *target __maybe_unused) | 817 | const char *target __maybe_unused) |
818 | { | 818 | { |
819 | if (perf_probe_event_need_dwarf(pev)) { | 819 | if (perf_probe_event_need_dwarf(pev)) { |
820 | pr_warning("Debuginfo-analysis is not supported.\n"); | 820 | pr_warning("Debuginfo-analysis is not supported.\n"); |
821 | return -ENOSYS; | 821 | return -ENOSYS; |
822 | } | 822 | } |
823 | 823 | ||
824 | return 0; | 824 | return 0; |
825 | } | 825 | } |
826 | 826 | ||
827 | int show_line_range(struct line_range *lr __maybe_unused, | 827 | int show_line_range(struct line_range *lr __maybe_unused, |
828 | const char *module __maybe_unused, | 828 | const char *module __maybe_unused, |
829 | bool user __maybe_unused) | 829 | bool user __maybe_unused) |
830 | { | 830 | { |
831 | pr_warning("Debuginfo-analysis is not supported.\n"); | 831 | pr_warning("Debuginfo-analysis is not supported.\n"); |
832 | return -ENOSYS; | 832 | return -ENOSYS; |
833 | } | 833 | } |
834 | 834 | ||
835 | int show_available_vars(struct perf_probe_event *pevs __maybe_unused, | 835 | int show_available_vars(struct perf_probe_event *pevs __maybe_unused, |
836 | int npevs __maybe_unused, int max_vls __maybe_unused, | 836 | int npevs __maybe_unused, int max_vls __maybe_unused, |
837 | const char *module __maybe_unused, | 837 | const char *module __maybe_unused, |
838 | struct strfilter *filter __maybe_unused, | 838 | struct strfilter *filter __maybe_unused, |
839 | bool externs __maybe_unused) | 839 | bool externs __maybe_unused) |
840 | { | 840 | { |
841 | pr_warning("Debuginfo-analysis is not supported.\n"); | 841 | pr_warning("Debuginfo-analysis is not supported.\n"); |
842 | return -ENOSYS; | 842 | return -ENOSYS; |
843 | } | 843 | } |
844 | #endif | 844 | #endif |
845 | 845 | ||
846 | void line_range__clear(struct line_range *lr) | 846 | void line_range__clear(struct line_range *lr) |
847 | { | 847 | { |
848 | free(lr->function); | 848 | free(lr->function); |
849 | free(lr->file); | 849 | free(lr->file); |
850 | free(lr->path); | 850 | free(lr->path); |
851 | free(lr->comp_dir); | 851 | free(lr->comp_dir); |
852 | intlist__delete(lr->line_list); | 852 | intlist__delete(lr->line_list); |
853 | memset(lr, 0, sizeof(*lr)); | 853 | memset(lr, 0, sizeof(*lr)); |
854 | } | 854 | } |
855 | 855 | ||
856 | int line_range__init(struct line_range *lr) | 856 | int line_range__init(struct line_range *lr) |
857 | { | 857 | { |
858 | memset(lr, 0, sizeof(*lr)); | 858 | memset(lr, 0, sizeof(*lr)); |
859 | lr->line_list = intlist__new(NULL); | 859 | lr->line_list = intlist__new(NULL); |
860 | if (!lr->line_list) | 860 | if (!lr->line_list) |
861 | return -ENOMEM; | 861 | return -ENOMEM; |
862 | else | 862 | else |
863 | return 0; | 863 | return 0; |
864 | } | 864 | } |
865 | 865 | ||
866 | static int parse_line_num(char **ptr, int *val, const char *what) | 866 | static int parse_line_num(char **ptr, int *val, const char *what) |
867 | { | 867 | { |
868 | const char *start = *ptr; | 868 | const char *start = *ptr; |
869 | 869 | ||
870 | errno = 0; | 870 | errno = 0; |
871 | *val = strtol(*ptr, ptr, 0); | 871 | *val = strtol(*ptr, ptr, 0); |
872 | if (errno || *ptr == start) { | 872 | if (errno || *ptr == start) { |
873 | semantic_error("'%s' is not a valid number.\n", what); | 873 | semantic_error("'%s' is not a valid number.\n", what); |
874 | return -EINVAL; | 874 | return -EINVAL; |
875 | } | 875 | } |
876 | return 0; | 876 | return 0; |
877 | } | 877 | } |
878 | 878 | ||
879 | /* | 879 | /* |
880 | * Stuff 'lr' according to the line range described by 'arg'. | 880 | * Stuff 'lr' according to the line range described by 'arg'. |
881 | * The line range syntax is described by: | 881 | * The line range syntax is described by: |
882 | * | 882 | * |
883 | * SRC[:SLN[+NUM|-ELN]] | 883 | * SRC[:SLN[+NUM|-ELN]] |
884 | * FNC[@SRC][:SLN[+NUM|-ELN]] | 884 | * FNC[@SRC][:SLN[+NUM|-ELN]] |
885 | */ | 885 | */ |
886 | int parse_line_range_desc(const char *arg, struct line_range *lr) | 886 | int parse_line_range_desc(const char *arg, struct line_range *lr) |
887 | { | 887 | { |
888 | char *range, *file, *name = strdup(arg); | 888 | char *range, *file, *name = strdup(arg); |
889 | int err; | 889 | int err; |
890 | 890 | ||
891 | if (!name) | 891 | if (!name) |
892 | return -ENOMEM; | 892 | return -ENOMEM; |
893 | 893 | ||
894 | lr->start = 0; | 894 | lr->start = 0; |
895 | lr->end = INT_MAX; | 895 | lr->end = INT_MAX; |
896 | 896 | ||
897 | range = strchr(name, ':'); | 897 | range = strchr(name, ':'); |
898 | if (range) { | 898 | if (range) { |
899 | *range++ = '\0'; | 899 | *range++ = '\0'; |
900 | 900 | ||
901 | err = parse_line_num(&range, &lr->start, "start line"); | 901 | err = parse_line_num(&range, &lr->start, "start line"); |
902 | if (err) | 902 | if (err) |
903 | goto err; | 903 | goto err; |
904 | 904 | ||
905 | if (*range == '+' || *range == '-') { | 905 | if (*range == '+' || *range == '-') { |
906 | const char c = *range++; | 906 | const char c = *range++; |
907 | 907 | ||
908 | err = parse_line_num(&range, &lr->end, "end line"); | 908 | err = parse_line_num(&range, &lr->end, "end line"); |
909 | if (err) | 909 | if (err) |
910 | goto err; | 910 | goto err; |
911 | 911 | ||
912 | if (c == '+') { | 912 | if (c == '+') { |
913 | lr->end += lr->start; | 913 | lr->end += lr->start; |
914 | /* | 914 | /* |
915 | * Adjust the number of lines here. | 915 | * Adjust the number of lines here. |
916 | * If the number of lines == 1, the | 916 | * If the number of lines == 1, the |
917 | * the end of line should be equal to | 917 | * the end of line should be equal to |
918 | * the start of line. | 918 | * the start of line. |
919 | */ | 919 | */ |
920 | lr->end--; | 920 | lr->end--; |
921 | } | 921 | } |
922 | } | 922 | } |
923 | 923 | ||
924 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); | 924 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); |
925 | 925 | ||
926 | err = -EINVAL; | 926 | err = -EINVAL; |
927 | if (lr->start > lr->end) { | 927 | if (lr->start > lr->end) { |
928 | semantic_error("Start line must be smaller" | 928 | semantic_error("Start line must be smaller" |
929 | " than end line.\n"); | 929 | " than end line.\n"); |
930 | goto err; | 930 | goto err; |
931 | } | 931 | } |
932 | if (*range != '\0') { | 932 | if (*range != '\0') { |
933 | semantic_error("Tailing with invalid str '%s'.\n", range); | 933 | semantic_error("Tailing with invalid str '%s'.\n", range); |
934 | goto err; | 934 | goto err; |
935 | } | 935 | } |
936 | } | 936 | } |
937 | 937 | ||
938 | file = strchr(name, '@'); | 938 | file = strchr(name, '@'); |
939 | if (file) { | 939 | if (file) { |
940 | *file = '\0'; | 940 | *file = '\0'; |
941 | lr->file = strdup(++file); | 941 | lr->file = strdup(++file); |
942 | if (lr->file == NULL) { | 942 | if (lr->file == NULL) { |
943 | err = -ENOMEM; | 943 | err = -ENOMEM; |
944 | goto err; | 944 | goto err; |
945 | } | 945 | } |
946 | lr->function = name; | 946 | lr->function = name; |
947 | } else if (strchr(name, '.')) | 947 | } else if (strchr(name, '.')) |
948 | lr->file = name; | 948 | lr->file = name; |
949 | else | 949 | else |
950 | lr->function = name; | 950 | lr->function = name; |
951 | 951 | ||
952 | return 0; | 952 | return 0; |
953 | err: | 953 | err: |
954 | free(name); | 954 | free(name); |
955 | return err; | 955 | return err; |
956 | } | 956 | } |
957 | 957 | ||
958 | /* Check the name is good for event/group */ | 958 | /* Check the name is good for event/group */ |
959 | static bool check_event_name(const char *name) | 959 | static bool check_event_name(const char *name) |
960 | { | 960 | { |
961 | if (!isalpha(*name) && *name != '_') | 961 | if (!isalpha(*name) && *name != '_') |
962 | return false; | 962 | return false; |
963 | while (*++name != '\0') { | 963 | while (*++name != '\0') { |
964 | if (!isalpha(*name) && !isdigit(*name) && *name != '_') | 964 | if (!isalpha(*name) && !isdigit(*name) && *name != '_') |
965 | return false; | 965 | return false; |
966 | } | 966 | } |
967 | return true; | 967 | return true; |
968 | } | 968 | } |
969 | 969 | ||
970 | /* Parse probepoint definition. */ | 970 | /* Parse probepoint definition. */ |
971 | static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | 971 | static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) |
972 | { | 972 | { |
973 | struct perf_probe_point *pp = &pev->point; | 973 | struct perf_probe_point *pp = &pev->point; |
974 | char *ptr, *tmp; | 974 | char *ptr, *tmp; |
975 | char c, nc = 0; | 975 | char c, nc = 0; |
976 | /* | 976 | /* |
977 | * <Syntax> | 977 | * <Syntax> |
978 | * perf probe [EVENT=]SRC[:LN|;PTN] | 978 | * perf probe [EVENT=]SRC[:LN|;PTN] |
979 | * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] | 979 | * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] |
980 | * | 980 | * |
981 | * TODO:Group name support | 981 | * TODO:Group name support |
982 | */ | 982 | */ |
983 | 983 | ||
984 | ptr = strpbrk(arg, ";=@+%"); | 984 | ptr = strpbrk(arg, ";=@+%"); |
985 | if (ptr && *ptr == '=') { /* Event name */ | 985 | if (ptr && *ptr == '=') { /* Event name */ |
986 | *ptr = '\0'; | 986 | *ptr = '\0'; |
987 | tmp = ptr + 1; | 987 | tmp = ptr + 1; |
988 | if (strchr(arg, ':')) { | 988 | if (strchr(arg, ':')) { |
989 | semantic_error("Group name is not supported yet.\n"); | 989 | semantic_error("Group name is not supported yet.\n"); |
990 | return -ENOTSUP; | 990 | return -ENOTSUP; |
991 | } | 991 | } |
992 | if (!check_event_name(arg)) { | 992 | if (!check_event_name(arg)) { |
993 | semantic_error("%s is bad for event name -it must " | 993 | semantic_error("%s is bad for event name -it must " |
994 | "follow C symbol-naming rule.\n", arg); | 994 | "follow C symbol-naming rule.\n", arg); |
995 | return -EINVAL; | 995 | return -EINVAL; |
996 | } | 996 | } |
997 | pev->event = strdup(arg); | 997 | pev->event = strdup(arg); |
998 | if (pev->event == NULL) | 998 | if (pev->event == NULL) |
999 | return -ENOMEM; | 999 | return -ENOMEM; |
1000 | pev->group = NULL; | 1000 | pev->group = NULL; |
1001 | arg = tmp; | 1001 | arg = tmp; |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | ptr = strpbrk(arg, ";:+@%"); | 1004 | ptr = strpbrk(arg, ";:+@%"); |
1005 | if (ptr) { | 1005 | if (ptr) { |
1006 | nc = *ptr; | 1006 | nc = *ptr; |
1007 | *ptr++ = '\0'; | 1007 | *ptr++ = '\0'; |
1008 | } | 1008 | } |
1009 | 1009 | ||
1010 | tmp = strdup(arg); | 1010 | tmp = strdup(arg); |
1011 | if (tmp == NULL) | 1011 | if (tmp == NULL) |
1012 | return -ENOMEM; | 1012 | return -ENOMEM; |
1013 | 1013 | ||
1014 | /* Check arg is function or file and copy it */ | 1014 | /* Check arg is function or file and copy it */ |
1015 | if (strchr(tmp, '.')) /* File */ | 1015 | if (strchr(tmp, '.')) /* File */ |
1016 | pp->file = tmp; | 1016 | pp->file = tmp; |
1017 | else /* Function */ | 1017 | else /* Function */ |
1018 | pp->function = tmp; | 1018 | pp->function = tmp; |
1019 | 1019 | ||
1020 | /* Parse other options */ | 1020 | /* Parse other options */ |
1021 | while (ptr) { | 1021 | while (ptr) { |
1022 | arg = ptr; | 1022 | arg = ptr; |
1023 | c = nc; | 1023 | c = nc; |
1024 | if (c == ';') { /* Lazy pattern must be the last part */ | 1024 | if (c == ';') { /* Lazy pattern must be the last part */ |
1025 | pp->lazy_line = strdup(arg); | 1025 | pp->lazy_line = strdup(arg); |
1026 | if (pp->lazy_line == NULL) | 1026 | if (pp->lazy_line == NULL) |
1027 | return -ENOMEM; | 1027 | return -ENOMEM; |
1028 | break; | 1028 | break; |
1029 | } | 1029 | } |
1030 | ptr = strpbrk(arg, ";:+@%"); | 1030 | ptr = strpbrk(arg, ";:+@%"); |
1031 | if (ptr) { | 1031 | if (ptr) { |
1032 | nc = *ptr; | 1032 | nc = *ptr; |
1033 | *ptr++ = '\0'; | 1033 | *ptr++ = '\0'; |
1034 | } | 1034 | } |
1035 | switch (c) { | 1035 | switch (c) { |
1036 | case ':': /* Line number */ | 1036 | case ':': /* Line number */ |
1037 | pp->line = strtoul(arg, &tmp, 0); | 1037 | pp->line = strtoul(arg, &tmp, 0); |
1038 | if (*tmp != '\0') { | 1038 | if (*tmp != '\0') { |
1039 | semantic_error("There is non-digit char" | 1039 | semantic_error("There is non-digit char" |
1040 | " in line number.\n"); | 1040 | " in line number.\n"); |
1041 | return -EINVAL; | 1041 | return -EINVAL; |
1042 | } | 1042 | } |
1043 | break; | 1043 | break; |
1044 | case '+': /* Byte offset from a symbol */ | 1044 | case '+': /* Byte offset from a symbol */ |
1045 | pp->offset = strtoul(arg, &tmp, 0); | 1045 | pp->offset = strtoul(arg, &tmp, 0); |
1046 | if (*tmp != '\0') { | 1046 | if (*tmp != '\0') { |
1047 | semantic_error("There is non-digit character" | 1047 | semantic_error("There is non-digit character" |
1048 | " in offset.\n"); | 1048 | " in offset.\n"); |
1049 | return -EINVAL; | 1049 | return -EINVAL; |
1050 | } | 1050 | } |
1051 | break; | 1051 | break; |
1052 | case '@': /* File name */ | 1052 | case '@': /* File name */ |
1053 | if (pp->file) { | 1053 | if (pp->file) { |
1054 | semantic_error("SRC@SRC is not allowed.\n"); | 1054 | semantic_error("SRC@SRC is not allowed.\n"); |
1055 | return -EINVAL; | 1055 | return -EINVAL; |
1056 | } | 1056 | } |
1057 | pp->file = strdup(arg); | 1057 | pp->file = strdup(arg); |
1058 | if (pp->file == NULL) | 1058 | if (pp->file == NULL) |
1059 | return -ENOMEM; | 1059 | return -ENOMEM; |
1060 | break; | 1060 | break; |
1061 | case '%': /* Probe places */ | 1061 | case '%': /* Probe places */ |
1062 | if (strcmp(arg, "return") == 0) { | 1062 | if (strcmp(arg, "return") == 0) { |
1063 | pp->retprobe = 1; | 1063 | pp->retprobe = 1; |
1064 | } else { /* Others not supported yet */ | 1064 | } else { /* Others not supported yet */ |
1065 | semantic_error("%%%s is not supported.\n", arg); | 1065 | semantic_error("%%%s is not supported.\n", arg); |
1066 | return -ENOTSUP; | 1066 | return -ENOTSUP; |
1067 | } | 1067 | } |
1068 | break; | 1068 | break; |
1069 | default: /* Buggy case */ | 1069 | default: /* Buggy case */ |
1070 | pr_err("This program has a bug at %s:%d.\n", | 1070 | pr_err("This program has a bug at %s:%d.\n", |
1071 | __FILE__, __LINE__); | 1071 | __FILE__, __LINE__); |
1072 | return -ENOTSUP; | 1072 | return -ENOTSUP; |
1073 | break; | 1073 | break; |
1074 | } | 1074 | } |
1075 | } | 1075 | } |
1076 | 1076 | ||
1077 | /* Exclusion check */ | 1077 | /* Exclusion check */ |
1078 | if (pp->lazy_line && pp->line) { | 1078 | if (pp->lazy_line && pp->line) { |
1079 | semantic_error("Lazy pattern can't be used with" | 1079 | semantic_error("Lazy pattern can't be used with" |
1080 | " line number.\n"); | 1080 | " line number.\n"); |
1081 | return -EINVAL; | 1081 | return -EINVAL; |
1082 | } | 1082 | } |
1083 | 1083 | ||
1084 | if (pp->lazy_line && pp->offset) { | 1084 | if (pp->lazy_line && pp->offset) { |
1085 | semantic_error("Lazy pattern can't be used with offset.\n"); | 1085 | semantic_error("Lazy pattern can't be used with offset.\n"); |
1086 | return -EINVAL; | 1086 | return -EINVAL; |
1087 | } | 1087 | } |
1088 | 1088 | ||
1089 | if (pp->line && pp->offset) { | 1089 | if (pp->line && pp->offset) { |
1090 | semantic_error("Offset can't be used with line number.\n"); | 1090 | semantic_error("Offset can't be used with line number.\n"); |
1091 | return -EINVAL; | 1091 | return -EINVAL; |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { | 1094 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { |
1095 | semantic_error("File always requires line number or " | 1095 | semantic_error("File always requires line number or " |
1096 | "lazy pattern.\n"); | 1096 | "lazy pattern.\n"); |
1097 | return -EINVAL; | 1097 | return -EINVAL; |
1098 | } | 1098 | } |
1099 | 1099 | ||
1100 | if (pp->offset && !pp->function) { | 1100 | if (pp->offset && !pp->function) { |
1101 | semantic_error("Offset requires an entry function.\n"); | 1101 | semantic_error("Offset requires an entry function.\n"); |
1102 | return -EINVAL; | 1102 | return -EINVAL; |
1103 | } | 1103 | } |
1104 | 1104 | ||
1105 | if (pp->retprobe && !pp->function) { | 1105 | if (pp->retprobe && !pp->function) { |
1106 | semantic_error("Return probe requires an entry function.\n"); | 1106 | semantic_error("Return probe requires an entry function.\n"); |
1107 | return -EINVAL; | 1107 | return -EINVAL; |
1108 | } | 1108 | } |
1109 | 1109 | ||
1110 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { | 1110 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { |
1111 | semantic_error("Offset/Line/Lazy pattern can't be used with " | 1111 | semantic_error("Offset/Line/Lazy pattern can't be used with " |
1112 | "return probe.\n"); | 1112 | "return probe.\n"); |
1113 | return -EINVAL; | 1113 | return -EINVAL; |
1114 | } | 1114 | } |
1115 | 1115 | ||
1116 | pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", | 1116 | pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", |
1117 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, | 1117 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, |
1118 | pp->lazy_line); | 1118 | pp->lazy_line); |
1119 | return 0; | 1119 | return 0; |
1120 | } | 1120 | } |
1121 | 1121 | ||
1122 | /* Parse perf-probe event argument */ | 1122 | /* Parse perf-probe event argument */ |
1123 | static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) | 1123 | static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) |
1124 | { | 1124 | { |
1125 | char *tmp, *goodname; | 1125 | char *tmp, *goodname; |
1126 | struct perf_probe_arg_field **fieldp; | 1126 | struct perf_probe_arg_field **fieldp; |
1127 | 1127 | ||
1128 | pr_debug("parsing arg: %s into ", str); | 1128 | pr_debug("parsing arg: %s into ", str); |
1129 | 1129 | ||
1130 | tmp = strchr(str, '='); | 1130 | tmp = strchr(str, '='); |
1131 | if (tmp) { | 1131 | if (tmp) { |
1132 | arg->name = strndup(str, tmp - str); | 1132 | arg->name = strndup(str, tmp - str); |
1133 | if (arg->name == NULL) | 1133 | if (arg->name == NULL) |
1134 | return -ENOMEM; | 1134 | return -ENOMEM; |
1135 | pr_debug("name:%s ", arg->name); | 1135 | pr_debug("name:%s ", arg->name); |
1136 | str = tmp + 1; | 1136 | str = tmp + 1; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | tmp = strchr(str, ':'); | 1139 | tmp = strchr(str, ':'); |
1140 | if (tmp) { /* Type setting */ | 1140 | if (tmp) { /* Type setting */ |
1141 | *tmp = '\0'; | 1141 | *tmp = '\0'; |
1142 | arg->type = strdup(tmp + 1); | 1142 | arg->type = strdup(tmp + 1); |
1143 | if (arg->type == NULL) | 1143 | if (arg->type == NULL) |
1144 | return -ENOMEM; | 1144 | return -ENOMEM; |
1145 | pr_debug("type:%s ", arg->type); | 1145 | pr_debug("type:%s ", arg->type); |
1146 | } | 1146 | } |
1147 | 1147 | ||
1148 | tmp = strpbrk(str, "-.["); | 1148 | tmp = strpbrk(str, "-.["); |
1149 | if (!is_c_varname(str) || !tmp) { | 1149 | if (!is_c_varname(str) || !tmp) { |
1150 | /* A variable, register, symbol or special value */ | 1150 | /* A variable, register, symbol or special value */ |
1151 | arg->var = strdup(str); | 1151 | arg->var = strdup(str); |
1152 | if (arg->var == NULL) | 1152 | if (arg->var == NULL) |
1153 | return -ENOMEM; | 1153 | return -ENOMEM; |
1154 | pr_debug("%s\n", arg->var); | 1154 | pr_debug("%s\n", arg->var); |
1155 | return 0; | 1155 | return 0; |
1156 | } | 1156 | } |
1157 | 1157 | ||
1158 | /* Structure fields or array element */ | 1158 | /* Structure fields or array element */ |
1159 | arg->var = strndup(str, tmp - str); | 1159 | arg->var = strndup(str, tmp - str); |
1160 | if (arg->var == NULL) | 1160 | if (arg->var == NULL) |
1161 | return -ENOMEM; | 1161 | return -ENOMEM; |
1162 | goodname = arg->var; | 1162 | goodname = arg->var; |
1163 | pr_debug("%s, ", arg->var); | 1163 | pr_debug("%s, ", arg->var); |
1164 | fieldp = &arg->field; | 1164 | fieldp = &arg->field; |
1165 | 1165 | ||
1166 | do { | 1166 | do { |
1167 | *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); | 1167 | *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); |
1168 | if (*fieldp == NULL) | 1168 | if (*fieldp == NULL) |
1169 | return -ENOMEM; | 1169 | return -ENOMEM; |
1170 | if (*tmp == '[') { /* Array */ | 1170 | if (*tmp == '[') { /* Array */ |
1171 | str = tmp; | 1171 | str = tmp; |
1172 | (*fieldp)->index = strtol(str + 1, &tmp, 0); | 1172 | (*fieldp)->index = strtol(str + 1, &tmp, 0); |
1173 | (*fieldp)->ref = true; | 1173 | (*fieldp)->ref = true; |
1174 | if (*tmp != ']' || tmp == str + 1) { | 1174 | if (*tmp != ']' || tmp == str + 1) { |
1175 | semantic_error("Array index must be a" | 1175 | semantic_error("Array index must be a" |
1176 | " number.\n"); | 1176 | " number.\n"); |
1177 | return -EINVAL; | 1177 | return -EINVAL; |
1178 | } | 1178 | } |
1179 | tmp++; | 1179 | tmp++; |
1180 | if (*tmp == '\0') | 1180 | if (*tmp == '\0') |
1181 | tmp = NULL; | 1181 | tmp = NULL; |
1182 | } else { /* Structure */ | 1182 | } else { /* Structure */ |
1183 | if (*tmp == '.') { | 1183 | if (*tmp == '.') { |
1184 | str = tmp + 1; | 1184 | str = tmp + 1; |
1185 | (*fieldp)->ref = false; | 1185 | (*fieldp)->ref = false; |
1186 | } else if (tmp[1] == '>') { | 1186 | } else if (tmp[1] == '>') { |
1187 | str = tmp + 2; | 1187 | str = tmp + 2; |
1188 | (*fieldp)->ref = true; | 1188 | (*fieldp)->ref = true; |
1189 | } else { | 1189 | } else { |
1190 | semantic_error("Argument parse error: %s\n", | 1190 | semantic_error("Argument parse error: %s\n", |
1191 | str); | 1191 | str); |
1192 | return -EINVAL; | 1192 | return -EINVAL; |
1193 | } | 1193 | } |
1194 | tmp = strpbrk(str, "-.["); | 1194 | tmp = strpbrk(str, "-.["); |
1195 | } | 1195 | } |
1196 | if (tmp) { | 1196 | if (tmp) { |
1197 | (*fieldp)->name = strndup(str, tmp - str); | 1197 | (*fieldp)->name = strndup(str, tmp - str); |
1198 | if ((*fieldp)->name == NULL) | 1198 | if ((*fieldp)->name == NULL) |
1199 | return -ENOMEM; | 1199 | return -ENOMEM; |
1200 | if (*str != '[') | 1200 | if (*str != '[') |
1201 | goodname = (*fieldp)->name; | 1201 | goodname = (*fieldp)->name; |
1202 | pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); | 1202 | pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); |
1203 | fieldp = &(*fieldp)->next; | 1203 | fieldp = &(*fieldp)->next; |
1204 | } | 1204 | } |
1205 | } while (tmp); | 1205 | } while (tmp); |
1206 | (*fieldp)->name = strdup(str); | 1206 | (*fieldp)->name = strdup(str); |
1207 | if ((*fieldp)->name == NULL) | 1207 | if ((*fieldp)->name == NULL) |
1208 | return -ENOMEM; | 1208 | return -ENOMEM; |
1209 | if (*str != '[') | 1209 | if (*str != '[') |
1210 | goodname = (*fieldp)->name; | 1210 | goodname = (*fieldp)->name; |
1211 | pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); | 1211 | pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); |
1212 | 1212 | ||
1213 | /* If no name is specified, set the last field name (not array index)*/ | 1213 | /* If no name is specified, set the last field name (not array index)*/ |
1214 | if (!arg->name) { | 1214 | if (!arg->name) { |
1215 | arg->name = strdup(goodname); | 1215 | arg->name = strdup(goodname); |
1216 | if (arg->name == NULL) | 1216 | if (arg->name == NULL) |
1217 | return -ENOMEM; | 1217 | return -ENOMEM; |
1218 | } | 1218 | } |
1219 | return 0; | 1219 | return 0; |
1220 | } | 1220 | } |
1221 | 1221 | ||
1222 | /* Parse perf-probe event command */ | 1222 | /* Parse perf-probe event command */ |
1223 | int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) | 1223 | int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) |
1224 | { | 1224 | { |
1225 | char **argv; | 1225 | char **argv; |
1226 | int argc, i, ret = 0; | 1226 | int argc, i, ret = 0; |
1227 | 1227 | ||
1228 | argv = argv_split(cmd, &argc); | 1228 | argv = argv_split(cmd, &argc); |
1229 | if (!argv) { | 1229 | if (!argv) { |
1230 | pr_debug("Failed to split arguments.\n"); | 1230 | pr_debug("Failed to split arguments.\n"); |
1231 | return -ENOMEM; | 1231 | return -ENOMEM; |
1232 | } | 1232 | } |
1233 | if (argc - 1 > MAX_PROBE_ARGS) { | 1233 | if (argc - 1 > MAX_PROBE_ARGS) { |
1234 | semantic_error("Too many probe arguments (%d).\n", argc - 1); | 1234 | semantic_error("Too many probe arguments (%d).\n", argc - 1); |
1235 | ret = -ERANGE; | 1235 | ret = -ERANGE; |
1236 | goto out; | 1236 | goto out; |
1237 | } | 1237 | } |
1238 | /* Parse probe point */ | 1238 | /* Parse probe point */ |
1239 | ret = parse_perf_probe_point(argv[0], pev); | 1239 | ret = parse_perf_probe_point(argv[0], pev); |
1240 | if (ret < 0) | 1240 | if (ret < 0) |
1241 | goto out; | 1241 | goto out; |
1242 | 1242 | ||
1243 | /* Copy arguments and ensure return probe has no C argument */ | 1243 | /* Copy arguments and ensure return probe has no C argument */ |
1244 | pev->nargs = argc - 1; | 1244 | pev->nargs = argc - 1; |
1245 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 1245 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
1246 | if (pev->args == NULL) { | 1246 | if (pev->args == NULL) { |
1247 | ret = -ENOMEM; | 1247 | ret = -ENOMEM; |
1248 | goto out; | 1248 | goto out; |
1249 | } | 1249 | } |
1250 | for (i = 0; i < pev->nargs && ret >= 0; i++) { | 1250 | for (i = 0; i < pev->nargs && ret >= 0; i++) { |
1251 | ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); | 1251 | ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); |
1252 | if (ret >= 0 && | 1252 | if (ret >= 0 && |
1253 | is_c_varname(pev->args[i].var) && pev->point.retprobe) { | 1253 | is_c_varname(pev->args[i].var) && pev->point.retprobe) { |
1254 | semantic_error("You can't specify local variable for" | 1254 | semantic_error("You can't specify local variable for" |
1255 | " kretprobe.\n"); | 1255 | " kretprobe.\n"); |
1256 | ret = -EINVAL; | 1256 | ret = -EINVAL; |
1257 | } | 1257 | } |
1258 | } | 1258 | } |
1259 | out: | 1259 | out: |
1260 | argv_free(argv); | 1260 | argv_free(argv); |
1261 | 1261 | ||
1262 | return ret; | 1262 | return ret; |
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | /* Return true if this perf_probe_event requires debuginfo */ | 1265 | /* Return true if this perf_probe_event requires debuginfo */ |
1266 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | 1266 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) |
1267 | { | 1267 | { |
1268 | int i; | 1268 | int i; |
1269 | 1269 | ||
1270 | if (pev->point.file || pev->point.line || pev->point.lazy_line) | 1270 | if (pev->point.file || pev->point.line || pev->point.lazy_line) |
1271 | return true; | 1271 | return true; |
1272 | 1272 | ||
1273 | for (i = 0; i < pev->nargs; i++) | 1273 | for (i = 0; i < pev->nargs; i++) |
1274 | if (is_c_varname(pev->args[i].var)) | 1274 | if (is_c_varname(pev->args[i].var)) |
1275 | return true; | 1275 | return true; |
1276 | 1276 | ||
1277 | return false; | 1277 | return false; |
1278 | } | 1278 | } |
1279 | 1279 | ||
1280 | /* Parse probe_events event into struct probe_point */ | 1280 | /* Parse probe_events event into struct probe_point */ |
1281 | static int parse_probe_trace_command(const char *cmd, | 1281 | static int parse_probe_trace_command(const char *cmd, |
1282 | struct probe_trace_event *tev) | 1282 | struct probe_trace_event *tev) |
1283 | { | 1283 | { |
1284 | struct probe_trace_point *tp = &tev->point; | 1284 | struct probe_trace_point *tp = &tev->point; |
1285 | char pr; | 1285 | char pr; |
1286 | char *p; | 1286 | char *p; |
1287 | char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str; | 1287 | char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str; |
1288 | int ret, i, argc; | 1288 | int ret, i, argc; |
1289 | char **argv; | 1289 | char **argv; |
1290 | 1290 | ||
1291 | pr_debug("Parsing probe_events: %s\n", cmd); | 1291 | pr_debug("Parsing probe_events: %s\n", cmd); |
1292 | argv = argv_split(cmd, &argc); | 1292 | argv = argv_split(cmd, &argc); |
1293 | if (!argv) { | 1293 | if (!argv) { |
1294 | pr_debug("Failed to split arguments.\n"); | 1294 | pr_debug("Failed to split arguments.\n"); |
1295 | return -ENOMEM; | 1295 | return -ENOMEM; |
1296 | } | 1296 | } |
1297 | if (argc < 2) { | 1297 | if (argc < 2) { |
1298 | semantic_error("Too few probe arguments.\n"); | 1298 | semantic_error("Too few probe arguments.\n"); |
1299 | ret = -ERANGE; | 1299 | ret = -ERANGE; |
1300 | goto out; | 1300 | goto out; |
1301 | } | 1301 | } |
1302 | 1302 | ||
1303 | /* Scan event and group name. */ | 1303 | /* Scan event and group name. */ |
1304 | argv0_str = strdup(argv[0]); | 1304 | argv0_str = strdup(argv[0]); |
1305 | if (argv0_str == NULL) { | 1305 | if (argv0_str == NULL) { |
1306 | ret = -ENOMEM; | 1306 | ret = -ENOMEM; |
1307 | goto out; | 1307 | goto out; |
1308 | } | 1308 | } |
1309 | fmt1_str = strtok_r(argv0_str, ":", &fmt); | 1309 | fmt1_str = strtok_r(argv0_str, ":", &fmt); |
1310 | fmt2_str = strtok_r(NULL, "/", &fmt); | 1310 | fmt2_str = strtok_r(NULL, "/", &fmt); |
1311 | fmt3_str = strtok_r(NULL, " \t", &fmt); | 1311 | fmt3_str = strtok_r(NULL, " \t", &fmt); |
1312 | if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL | 1312 | if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL |
1313 | || fmt3_str == NULL) { | 1313 | || fmt3_str == NULL) { |
1314 | semantic_error("Failed to parse event name: %s\n", argv[0]); | 1314 | semantic_error("Failed to parse event name: %s\n", argv[0]); |
1315 | ret = -EINVAL; | 1315 | ret = -EINVAL; |
1316 | goto out; | 1316 | goto out; |
1317 | } | 1317 | } |
1318 | pr = fmt1_str[0]; | 1318 | pr = fmt1_str[0]; |
1319 | tev->group = strdup(fmt2_str); | 1319 | tev->group = strdup(fmt2_str); |
1320 | tev->event = strdup(fmt3_str); | 1320 | tev->event = strdup(fmt3_str); |
1321 | if (tev->group == NULL || tev->event == NULL) { | 1321 | if (tev->group == NULL || tev->event == NULL) { |
1322 | ret = -ENOMEM; | 1322 | ret = -ENOMEM; |
1323 | goto out; | 1323 | goto out; |
1324 | } | 1324 | } |
1325 | pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); | 1325 | pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); |
1326 | 1326 | ||
1327 | tp->retprobe = (pr == 'r'); | 1327 | tp->retprobe = (pr == 'r'); |
1328 | 1328 | ||
1329 | /* Scan module name(if there), function name and offset */ | 1329 | /* Scan module name(if there), function name and offset */ |
1330 | p = strchr(argv[1], ':'); | 1330 | p = strchr(argv[1], ':'); |
1331 | if (p) { | 1331 | if (p) { |
1332 | tp->module = strndup(argv[1], p - argv[1]); | 1332 | tp->module = strndup(argv[1], p - argv[1]); |
1333 | p++; | 1333 | p++; |
1334 | } else | 1334 | } else |
1335 | p = argv[1]; | 1335 | p = argv[1]; |
1336 | fmt1_str = strtok_r(p, "+", &fmt); | 1336 | fmt1_str = strtok_r(p, "+", &fmt); |
1337 | if (fmt1_str[0] == '0') /* only the address started with 0x */ | 1337 | if (fmt1_str[0] == '0') /* only the address started with 0x */ |
1338 | tp->address = strtoul(fmt1_str, NULL, 0); | 1338 | tp->address = strtoul(fmt1_str, NULL, 0); |
1339 | else { | 1339 | else { |
1340 | /* Only the symbol-based probe has offset */ | 1340 | /* Only the symbol-based probe has offset */ |
1341 | tp->symbol = strdup(fmt1_str); | 1341 | tp->symbol = strdup(fmt1_str); |
1342 | if (tp->symbol == NULL) { | 1342 | if (tp->symbol == NULL) { |
1343 | ret = -ENOMEM; | 1343 | ret = -ENOMEM; |
1344 | goto out; | 1344 | goto out; |
1345 | } | 1345 | } |
1346 | fmt2_str = strtok_r(NULL, "", &fmt); | 1346 | fmt2_str = strtok_r(NULL, "", &fmt); |
1347 | if (fmt2_str == NULL) | 1347 | if (fmt2_str == NULL) |
1348 | tp->offset = 0; | 1348 | tp->offset = 0; |
1349 | else | 1349 | else |
1350 | tp->offset = strtoul(fmt2_str, NULL, 10); | 1350 | tp->offset = strtoul(fmt2_str, NULL, 10); |
1351 | } | 1351 | } |
1352 | 1352 | ||
1353 | tev->nargs = argc - 2; | 1353 | tev->nargs = argc - 2; |
1354 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | 1354 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); |
1355 | if (tev->args == NULL) { | 1355 | if (tev->args == NULL) { |
1356 | ret = -ENOMEM; | 1356 | ret = -ENOMEM; |
1357 | goto out; | 1357 | goto out; |
1358 | } | 1358 | } |
1359 | for (i = 0; i < tev->nargs; i++) { | 1359 | for (i = 0; i < tev->nargs; i++) { |
1360 | p = strchr(argv[i + 2], '='); | 1360 | p = strchr(argv[i + 2], '='); |
1361 | if (p) /* We don't need which register is assigned. */ | 1361 | if (p) /* We don't need which register is assigned. */ |
1362 | *p++ = '\0'; | 1362 | *p++ = '\0'; |
1363 | else | 1363 | else |
1364 | p = argv[i + 2]; | 1364 | p = argv[i + 2]; |
1365 | tev->args[i].name = strdup(argv[i + 2]); | 1365 | tev->args[i].name = strdup(argv[i + 2]); |
1366 | /* TODO: parse regs and offset */ | 1366 | /* TODO: parse regs and offset */ |
1367 | tev->args[i].value = strdup(p); | 1367 | tev->args[i].value = strdup(p); |
1368 | if (tev->args[i].name == NULL || tev->args[i].value == NULL) { | 1368 | if (tev->args[i].name == NULL || tev->args[i].value == NULL) { |
1369 | ret = -ENOMEM; | 1369 | ret = -ENOMEM; |
1370 | goto out; | 1370 | goto out; |
1371 | } | 1371 | } |
1372 | } | 1372 | } |
1373 | ret = 0; | 1373 | ret = 0; |
1374 | out: | 1374 | out: |
1375 | free(argv0_str); | 1375 | free(argv0_str); |
1376 | argv_free(argv); | 1376 | argv_free(argv); |
1377 | return ret; | 1377 | return ret; |
1378 | } | 1378 | } |
1379 | 1379 | ||
1380 | /* Compose only probe arg */ | 1380 | /* Compose only probe arg */ |
1381 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | 1381 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) |
1382 | { | 1382 | { |
1383 | struct perf_probe_arg_field *field = pa->field; | 1383 | struct perf_probe_arg_field *field = pa->field; |
1384 | int ret; | 1384 | int ret; |
1385 | char *tmp = buf; | 1385 | char *tmp = buf; |
1386 | 1386 | ||
1387 | if (pa->name && pa->var) | 1387 | if (pa->name && pa->var) |
1388 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); | 1388 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); |
1389 | else | 1389 | else |
1390 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); | 1390 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); |
1391 | if (ret <= 0) | 1391 | if (ret <= 0) |
1392 | goto error; | 1392 | goto error; |
1393 | tmp += ret; | 1393 | tmp += ret; |
1394 | len -= ret; | 1394 | len -= ret; |
1395 | 1395 | ||
1396 | while (field) { | 1396 | while (field) { |
1397 | if (field->name[0] == '[') | 1397 | if (field->name[0] == '[') |
1398 | ret = e_snprintf(tmp, len, "%s", field->name); | 1398 | ret = e_snprintf(tmp, len, "%s", field->name); |
1399 | else | 1399 | else |
1400 | ret = e_snprintf(tmp, len, "%s%s", | 1400 | ret = e_snprintf(tmp, len, "%s%s", |
1401 | field->ref ? "->" : ".", field->name); | 1401 | field->ref ? "->" : ".", field->name); |
1402 | if (ret <= 0) | 1402 | if (ret <= 0) |
1403 | goto error; | 1403 | goto error; |
1404 | tmp += ret; | 1404 | tmp += ret; |
1405 | len -= ret; | 1405 | len -= ret; |
1406 | field = field->next; | 1406 | field = field->next; |
1407 | } | 1407 | } |
1408 | 1408 | ||
1409 | if (pa->type) { | 1409 | if (pa->type) { |
1410 | ret = e_snprintf(tmp, len, ":%s", pa->type); | 1410 | ret = e_snprintf(tmp, len, ":%s", pa->type); |
1411 | if (ret <= 0) | 1411 | if (ret <= 0) |
1412 | goto error; | 1412 | goto error; |
1413 | tmp += ret; | 1413 | tmp += ret; |
1414 | len -= ret; | 1414 | len -= ret; |
1415 | } | 1415 | } |
1416 | 1416 | ||
1417 | return tmp - buf; | 1417 | return tmp - buf; |
1418 | error: | 1418 | error: |
1419 | pr_debug("Failed to synthesize perf probe argument: %d\n", ret); | 1419 | pr_debug("Failed to synthesize perf probe argument: %d\n", ret); |
1420 | return ret; | 1420 | return ret; |
1421 | } | 1421 | } |
1422 | 1422 | ||
1423 | /* Compose only probe point (not argument) */ | 1423 | /* Compose only probe point (not argument) */ |
1424 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | 1424 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
1425 | { | 1425 | { |
1426 | char *buf, *tmp; | 1426 | char *buf, *tmp; |
1427 | char offs[32] = "", line[32] = "", file[32] = ""; | 1427 | char offs[32] = "", line[32] = "", file[32] = ""; |
1428 | int ret, len; | 1428 | int ret, len; |
1429 | 1429 | ||
1430 | buf = zalloc(MAX_CMDLEN); | 1430 | buf = zalloc(MAX_CMDLEN); |
1431 | if (buf == NULL) { | 1431 | if (buf == NULL) { |
1432 | ret = -ENOMEM; | 1432 | ret = -ENOMEM; |
1433 | goto error; | 1433 | goto error; |
1434 | } | 1434 | } |
1435 | if (pp->offset) { | 1435 | if (pp->offset) { |
1436 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); | 1436 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); |
1437 | if (ret <= 0) | 1437 | if (ret <= 0) |
1438 | goto error; | 1438 | goto error; |
1439 | } | 1439 | } |
1440 | if (pp->line) { | 1440 | if (pp->line) { |
1441 | ret = e_snprintf(line, 32, ":%d", pp->line); | 1441 | ret = e_snprintf(line, 32, ":%d", pp->line); |
1442 | if (ret <= 0) | 1442 | if (ret <= 0) |
1443 | goto error; | 1443 | goto error; |
1444 | } | 1444 | } |
1445 | if (pp->file) { | 1445 | if (pp->file) { |
1446 | tmp = pp->file; | 1446 | tmp = pp->file; |
1447 | len = strlen(tmp); | 1447 | len = strlen(tmp); |
1448 | if (len > 30) { | 1448 | if (len > 30) { |
1449 | tmp = strchr(pp->file + len - 30, '/'); | 1449 | tmp = strchr(pp->file + len - 30, '/'); |
1450 | tmp = tmp ? tmp + 1 : pp->file + len - 30; | 1450 | tmp = tmp ? tmp + 1 : pp->file + len - 30; |
1451 | } | 1451 | } |
1452 | ret = e_snprintf(file, 32, "@%s", tmp); | 1452 | ret = e_snprintf(file, 32, "@%s", tmp); |
1453 | if (ret <= 0) | 1453 | if (ret <= 0) |
1454 | goto error; | 1454 | goto error; |
1455 | } | 1455 | } |
1456 | 1456 | ||
1457 | if (pp->function) | 1457 | if (pp->function) |
1458 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, | 1458 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, |
1459 | offs, pp->retprobe ? "%return" : "", line, | 1459 | offs, pp->retprobe ? "%return" : "", line, |
1460 | file); | 1460 | file); |
1461 | else | 1461 | else |
1462 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); | 1462 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); |
1463 | if (ret <= 0) | 1463 | if (ret <= 0) |
1464 | goto error; | 1464 | goto error; |
1465 | 1465 | ||
1466 | return buf; | 1466 | return buf; |
1467 | error: | 1467 | error: |
1468 | pr_debug("Failed to synthesize perf probe point: %d\n", ret); | 1468 | pr_debug("Failed to synthesize perf probe point: %d\n", ret); |
1469 | free(buf); | 1469 | free(buf); |
1470 | return NULL; | 1470 | return NULL; |
1471 | } | 1471 | } |
1472 | 1472 | ||
1473 | #if 0 | 1473 | #if 0 |
1474 | char *synthesize_perf_probe_command(struct perf_probe_event *pev) | 1474 | char *synthesize_perf_probe_command(struct perf_probe_event *pev) |
1475 | { | 1475 | { |
1476 | char *buf; | 1476 | char *buf; |
1477 | int i, len, ret; | 1477 | int i, len, ret; |
1478 | 1478 | ||
1479 | buf = synthesize_perf_probe_point(&pev->point); | 1479 | buf = synthesize_perf_probe_point(&pev->point); |
1480 | if (!buf) | 1480 | if (!buf) |
1481 | return NULL; | 1481 | return NULL; |
1482 | 1482 | ||
1483 | len = strlen(buf); | 1483 | len = strlen(buf); |
1484 | for (i = 0; i < pev->nargs; i++) { | 1484 | for (i = 0; i < pev->nargs; i++) { |
1485 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", | 1485 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", |
1486 | pev->args[i].name); | 1486 | pev->args[i].name); |
1487 | if (ret <= 0) { | 1487 | if (ret <= 0) { |
1488 | free(buf); | 1488 | free(buf); |
1489 | return NULL; | 1489 | return NULL; |
1490 | } | 1490 | } |
1491 | len += ret; | 1491 | len += ret; |
1492 | } | 1492 | } |
1493 | 1493 | ||
1494 | return buf; | 1494 | return buf; |
1495 | } | 1495 | } |
1496 | #endif | 1496 | #endif |
1497 | 1497 | ||
1498 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, | 1498 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, |
1499 | char **buf, size_t *buflen, | 1499 | char **buf, size_t *buflen, |
1500 | int depth) | 1500 | int depth) |
1501 | { | 1501 | { |
1502 | int ret; | 1502 | int ret; |
1503 | if (ref->next) { | 1503 | if (ref->next) { |
1504 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, | 1504 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, |
1505 | buflen, depth + 1); | 1505 | buflen, depth + 1); |
1506 | if (depth < 0) | 1506 | if (depth < 0) |
1507 | goto out; | 1507 | goto out; |
1508 | } | 1508 | } |
1509 | 1509 | ||
1510 | ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); | 1510 | ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); |
1511 | if (ret < 0) | 1511 | if (ret < 0) |
1512 | depth = ret; | 1512 | depth = ret; |
1513 | else { | 1513 | else { |
1514 | *buf += ret; | 1514 | *buf += ret; |
1515 | *buflen -= ret; | 1515 | *buflen -= ret; |
1516 | } | 1516 | } |
1517 | out: | 1517 | out: |
1518 | return depth; | 1518 | return depth; |
1519 | 1519 | ||
1520 | } | 1520 | } |
1521 | 1521 | ||
1522 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, | 1522 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, |
1523 | char *buf, size_t buflen) | 1523 | char *buf, size_t buflen) |
1524 | { | 1524 | { |
1525 | struct probe_trace_arg_ref *ref = arg->ref; | 1525 | struct probe_trace_arg_ref *ref = arg->ref; |
1526 | int ret, depth = 0; | 1526 | int ret, depth = 0; |
1527 | char *tmp = buf; | 1527 | char *tmp = buf; |
1528 | 1528 | ||
1529 | /* Argument name or separator */ | 1529 | /* Argument name or separator */ |
1530 | if (arg->name) | 1530 | if (arg->name) |
1531 | ret = e_snprintf(buf, buflen, " %s=", arg->name); | 1531 | ret = e_snprintf(buf, buflen, " %s=", arg->name); |
1532 | else | 1532 | else |
1533 | ret = e_snprintf(buf, buflen, " "); | 1533 | ret = e_snprintf(buf, buflen, " "); |
1534 | if (ret < 0) | 1534 | if (ret < 0) |
1535 | return ret; | 1535 | return ret; |
1536 | buf += ret; | 1536 | buf += ret; |
1537 | buflen -= ret; | 1537 | buflen -= ret; |
1538 | 1538 | ||
1539 | /* Special case: @XXX */ | 1539 | /* Special case: @XXX */ |
1540 | if (arg->value[0] == '@' && arg->ref) | 1540 | if (arg->value[0] == '@' && arg->ref) |
1541 | ref = ref->next; | 1541 | ref = ref->next; |
1542 | 1542 | ||
1543 | /* Dereferencing arguments */ | 1543 | /* Dereferencing arguments */ |
1544 | if (ref) { | 1544 | if (ref) { |
1545 | depth = __synthesize_probe_trace_arg_ref(ref, &buf, | 1545 | depth = __synthesize_probe_trace_arg_ref(ref, &buf, |
1546 | &buflen, 1); | 1546 | &buflen, 1); |
1547 | if (depth < 0) | 1547 | if (depth < 0) |
1548 | return depth; | 1548 | return depth; |
1549 | } | 1549 | } |
1550 | 1550 | ||
1551 | /* Print argument value */ | 1551 | /* Print argument value */ |
1552 | if (arg->value[0] == '@' && arg->ref) | 1552 | if (arg->value[0] == '@' && arg->ref) |
1553 | ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, | 1553 | ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, |
1554 | arg->ref->offset); | 1554 | arg->ref->offset); |
1555 | else | 1555 | else |
1556 | ret = e_snprintf(buf, buflen, "%s", arg->value); | 1556 | ret = e_snprintf(buf, buflen, "%s", arg->value); |
1557 | if (ret < 0) | 1557 | if (ret < 0) |
1558 | return ret; | 1558 | return ret; |
1559 | buf += ret; | 1559 | buf += ret; |
1560 | buflen -= ret; | 1560 | buflen -= ret; |
1561 | 1561 | ||
1562 | /* Closing */ | 1562 | /* Closing */ |
1563 | while (depth--) { | 1563 | while (depth--) { |
1564 | ret = e_snprintf(buf, buflen, ")"); | 1564 | ret = e_snprintf(buf, buflen, ")"); |
1565 | if (ret < 0) | 1565 | if (ret < 0) |
1566 | return ret; | 1566 | return ret; |
1567 | buf += ret; | 1567 | buf += ret; |
1568 | buflen -= ret; | 1568 | buflen -= ret; |
1569 | } | 1569 | } |
1570 | /* Print argument type */ | 1570 | /* Print argument type */ |
1571 | if (arg->type) { | 1571 | if (arg->type) { |
1572 | ret = e_snprintf(buf, buflen, ":%s", arg->type); | 1572 | ret = e_snprintf(buf, buflen, ":%s", arg->type); |
1573 | if (ret <= 0) | 1573 | if (ret <= 0) |
1574 | return ret; | 1574 | return ret; |
1575 | buf += ret; | 1575 | buf += ret; |
1576 | } | 1576 | } |
1577 | 1577 | ||
1578 | return buf - tmp; | 1578 | return buf - tmp; |
1579 | } | 1579 | } |
1580 | 1580 | ||
1581 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) | 1581 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) |
1582 | { | 1582 | { |
1583 | struct probe_trace_point *tp = &tev->point; | 1583 | struct probe_trace_point *tp = &tev->point; |
1584 | char *buf; | 1584 | char *buf; |
1585 | int i, len, ret; | 1585 | int i, len, ret; |
1586 | 1586 | ||
1587 | buf = zalloc(MAX_CMDLEN); | 1587 | buf = zalloc(MAX_CMDLEN); |
1588 | if (buf == NULL) | 1588 | if (buf == NULL) |
1589 | return NULL; | 1589 | return NULL; |
1590 | 1590 | ||
1591 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', | 1591 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', |
1592 | tev->group, tev->event); | 1592 | tev->group, tev->event); |
1593 | if (len <= 0) | 1593 | if (len <= 0) |
1594 | goto error; | 1594 | goto error; |
1595 | 1595 | ||
1596 | /* Uprobes must have tp->address and tp->module */ | 1596 | /* Uprobes must have tp->address and tp->module */ |
1597 | if (tev->uprobes && (!tp->address || !tp->module)) | 1597 | if (tev->uprobes && (!tp->address || !tp->module)) |
1598 | goto error; | 1598 | goto error; |
1599 | 1599 | ||
1600 | /* Use the tp->address for uprobes */ | 1600 | /* Use the tp->address for uprobes */ |
1601 | if (tev->uprobes) | 1601 | if (tev->uprobes) |
1602 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", | 1602 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", |
1603 | tp->module, tp->address); | 1603 | tp->module, tp->address); |
1604 | else | 1604 | else |
1605 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", | 1605 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", |
1606 | tp->module ?: "", tp->module ? ":" : "", | 1606 | tp->module ?: "", tp->module ? ":" : "", |
1607 | tp->symbol, tp->offset); | 1607 | tp->symbol, tp->offset); |
1608 | 1608 | ||
1609 | if (ret <= 0) | 1609 | if (ret <= 0) |
1610 | goto error; | 1610 | goto error; |
1611 | len += ret; | 1611 | len += ret; |
1612 | 1612 | ||
1613 | for (i = 0; i < tev->nargs; i++) { | 1613 | for (i = 0; i < tev->nargs; i++) { |
1614 | ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, | 1614 | ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, |
1615 | MAX_CMDLEN - len); | 1615 | MAX_CMDLEN - len); |
1616 | if (ret <= 0) | 1616 | if (ret <= 0) |
1617 | goto error; | 1617 | goto error; |
1618 | len += ret; | 1618 | len += ret; |
1619 | } | 1619 | } |
1620 | 1620 | ||
1621 | return buf; | 1621 | return buf; |
1622 | error: | 1622 | error: |
1623 | free(buf); | 1623 | free(buf); |
1624 | return NULL; | 1624 | return NULL; |
1625 | } | 1625 | } |
1626 | 1626 | ||
1627 | static int find_perf_probe_point_from_map(struct probe_trace_point *tp, | 1627 | static int find_perf_probe_point_from_map(struct probe_trace_point *tp, |
1628 | struct perf_probe_point *pp, | 1628 | struct perf_probe_point *pp, |
1629 | bool is_kprobe) | 1629 | bool is_kprobe) |
1630 | { | 1630 | { |
1631 | struct symbol *sym = NULL; | 1631 | struct symbol *sym = NULL; |
1632 | struct map *map; | 1632 | struct map *map; |
1633 | u64 addr; | 1633 | u64 addr; |
1634 | int ret = -ENOENT; | 1634 | int ret = -ENOENT; |
1635 | 1635 | ||
1636 | if (!is_kprobe) { | 1636 | if (!is_kprobe) { |
1637 | map = dso__new_map(tp->module); | 1637 | map = dso__new_map(tp->module); |
1638 | if (!map) | 1638 | if (!map) |
1639 | goto out; | 1639 | goto out; |
1640 | addr = tp->address; | 1640 | addr = tp->address; |
1641 | sym = map__find_symbol(map, addr, NULL); | 1641 | sym = map__find_symbol(map, addr, NULL); |
1642 | } else { | 1642 | } else { |
1643 | addr = kernel_get_symbol_address_by_name(tp->symbol, true); | 1643 | addr = kernel_get_symbol_address_by_name(tp->symbol, true); |
1644 | if (addr) { | 1644 | if (addr) { |
1645 | addr += tp->offset; | 1645 | addr += tp->offset; |
1646 | sym = __find_kernel_function(addr, &map); | 1646 | sym = __find_kernel_function(addr, &map); |
1647 | } | 1647 | } |
1648 | } | 1648 | } |
1649 | if (!sym) | 1649 | if (!sym) |
1650 | goto out; | 1650 | goto out; |
1651 | 1651 | ||
1652 | pp->retprobe = tp->retprobe; | 1652 | pp->retprobe = tp->retprobe; |
1653 | pp->offset = addr - map->unmap_ip(map, sym->start); | 1653 | pp->offset = addr - map->unmap_ip(map, sym->start); |
1654 | pp->function = strdup(sym->name); | 1654 | pp->function = strdup(sym->name); |
1655 | ret = pp->function ? 0 : -ENOMEM; | 1655 | ret = pp->function ? 0 : -ENOMEM; |
1656 | 1656 | ||
1657 | out: | 1657 | out: |
1658 | if (map && !is_kprobe) { | 1658 | if (map && !is_kprobe) { |
1659 | dso__delete(map->dso); | 1659 | dso__delete(map->dso); |
1660 | map__delete(map); | 1660 | map__delete(map); |
1661 | } | 1661 | } |
1662 | 1662 | ||
1663 | return ret; | 1663 | return ret; |
1664 | } | 1664 | } |
1665 | 1665 | ||
1666 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | 1666 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, |
1667 | struct perf_probe_point *pp, | 1667 | struct perf_probe_point *pp, |
1668 | bool is_kprobe) | 1668 | bool is_kprobe) |
1669 | { | 1669 | { |
1670 | char buf[128]; | 1670 | char buf[128]; |
1671 | int ret; | 1671 | int ret; |
1672 | 1672 | ||
1673 | ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe); | 1673 | ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe); |
1674 | if (!ret) | 1674 | if (!ret) |
1675 | return 0; | 1675 | return 0; |
1676 | ret = find_perf_probe_point_from_map(tp, pp, is_kprobe); | 1676 | ret = find_perf_probe_point_from_map(tp, pp, is_kprobe); |
1677 | if (!ret) | 1677 | if (!ret) |
1678 | return 0; | 1678 | return 0; |
1679 | 1679 | ||
1680 | pr_debug("Failed to find probe point from both of dwarf and map.\n"); | 1680 | pr_debug("Failed to find probe point from both of dwarf and map.\n"); |
1681 | 1681 | ||
1682 | if (tp->symbol) { | 1682 | if (tp->symbol) { |
1683 | pp->function = strdup(tp->symbol); | 1683 | pp->function = strdup(tp->symbol); |
1684 | pp->offset = tp->offset; | 1684 | pp->offset = tp->offset; |
1685 | } else if (!tp->module && !is_kprobe) { | 1685 | } else if (!tp->module && !is_kprobe) { |
1686 | ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address); | 1686 | ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address); |
1687 | if (ret < 0) | 1687 | if (ret < 0) |
1688 | return ret; | 1688 | return ret; |
1689 | pp->function = strdup(buf); | 1689 | pp->function = strdup(buf); |
1690 | pp->offset = 0; | 1690 | pp->offset = 0; |
1691 | } | 1691 | } |
1692 | if (pp->function == NULL) | 1692 | if (pp->function == NULL) |
1693 | return -ENOMEM; | 1693 | return -ENOMEM; |
1694 | 1694 | ||
1695 | pp->retprobe = tp->retprobe; | 1695 | pp->retprobe = tp->retprobe; |
1696 | 1696 | ||
1697 | return 0; | 1697 | return 0; |
1698 | } | 1698 | } |
1699 | 1699 | ||
1700 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, | 1700 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, |
1701 | struct perf_probe_event *pev, bool is_kprobe) | 1701 | struct perf_probe_event *pev, bool is_kprobe) |
1702 | { | 1702 | { |
1703 | char buf[64] = ""; | 1703 | char buf[64] = ""; |
1704 | int i, ret; | 1704 | int i, ret; |
1705 | 1705 | ||
1706 | /* Convert event/group name */ | 1706 | /* Convert event/group name */ |
1707 | pev->event = strdup(tev->event); | 1707 | pev->event = strdup(tev->event); |
1708 | pev->group = strdup(tev->group); | 1708 | pev->group = strdup(tev->group); |
1709 | if (pev->event == NULL || pev->group == NULL) | 1709 | if (pev->event == NULL || pev->group == NULL) |
1710 | return -ENOMEM; | 1710 | return -ENOMEM; |
1711 | 1711 | ||
1712 | /* Convert trace_point to probe_point */ | 1712 | /* Convert trace_point to probe_point */ |
1713 | ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe); | 1713 | ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe); |
1714 | if (ret < 0) | 1714 | if (ret < 0) |
1715 | return ret; | 1715 | return ret; |
1716 | 1716 | ||
1717 | /* Convert trace_arg to probe_arg */ | 1717 | /* Convert trace_arg to probe_arg */ |
1718 | pev->nargs = tev->nargs; | 1718 | pev->nargs = tev->nargs; |
1719 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 1719 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
1720 | if (pev->args == NULL) | 1720 | if (pev->args == NULL) |
1721 | return -ENOMEM; | 1721 | return -ENOMEM; |
1722 | for (i = 0; i < tev->nargs && ret >= 0; i++) { | 1722 | for (i = 0; i < tev->nargs && ret >= 0; i++) { |
1723 | if (tev->args[i].name) | 1723 | if (tev->args[i].name) |
1724 | pev->args[i].name = strdup(tev->args[i].name); | 1724 | pev->args[i].name = strdup(tev->args[i].name); |
1725 | else { | 1725 | else { |
1726 | ret = synthesize_probe_trace_arg(&tev->args[i], | 1726 | ret = synthesize_probe_trace_arg(&tev->args[i], |
1727 | buf, 64); | 1727 | buf, 64); |
1728 | pev->args[i].name = strdup(buf); | 1728 | pev->args[i].name = strdup(buf); |
1729 | } | 1729 | } |
1730 | if (pev->args[i].name == NULL && ret >= 0) | 1730 | if (pev->args[i].name == NULL && ret >= 0) |
1731 | ret = -ENOMEM; | 1731 | ret = -ENOMEM; |
1732 | } | 1732 | } |
1733 | 1733 | ||
1734 | if (ret < 0) | 1734 | if (ret < 0) |
1735 | clear_perf_probe_event(pev); | 1735 | clear_perf_probe_event(pev); |
1736 | 1736 | ||
1737 | return ret; | 1737 | return ret; |
1738 | } | 1738 | } |
1739 | 1739 | ||
1740 | void clear_perf_probe_event(struct perf_probe_event *pev) | 1740 | void clear_perf_probe_event(struct perf_probe_event *pev) |
1741 | { | 1741 | { |
1742 | struct perf_probe_point *pp = &pev->point; | 1742 | struct perf_probe_point *pp = &pev->point; |
1743 | struct perf_probe_arg_field *field, *next; | 1743 | struct perf_probe_arg_field *field, *next; |
1744 | int i; | 1744 | int i; |
1745 | 1745 | ||
1746 | free(pev->event); | 1746 | free(pev->event); |
1747 | free(pev->group); | 1747 | free(pev->group); |
1748 | free(pp->file); | 1748 | free(pp->file); |
1749 | free(pp->function); | 1749 | free(pp->function); |
1750 | free(pp->lazy_line); | 1750 | free(pp->lazy_line); |
1751 | 1751 | ||
1752 | for (i = 0; i < pev->nargs; i++) { | 1752 | for (i = 0; i < pev->nargs; i++) { |
1753 | free(pev->args[i].name); | 1753 | free(pev->args[i].name); |
1754 | free(pev->args[i].var); | 1754 | free(pev->args[i].var); |
1755 | free(pev->args[i].type); | 1755 | free(pev->args[i].type); |
1756 | field = pev->args[i].field; | 1756 | field = pev->args[i].field; |
1757 | while (field) { | 1757 | while (field) { |
1758 | next = field->next; | 1758 | next = field->next; |
1759 | zfree(&field->name); | 1759 | zfree(&field->name); |
1760 | free(field); | 1760 | free(field); |
1761 | field = next; | 1761 | field = next; |
1762 | } | 1762 | } |
1763 | } | 1763 | } |
1764 | free(pev->args); | 1764 | free(pev->args); |
1765 | memset(pev, 0, sizeof(*pev)); | 1765 | memset(pev, 0, sizeof(*pev)); |
1766 | } | 1766 | } |
1767 | 1767 | ||
1768 | static void clear_probe_trace_event(struct probe_trace_event *tev) | 1768 | static void clear_probe_trace_event(struct probe_trace_event *tev) |
1769 | { | 1769 | { |
1770 | struct probe_trace_arg_ref *ref, *next; | 1770 | struct probe_trace_arg_ref *ref, *next; |
1771 | int i; | 1771 | int i; |
1772 | 1772 | ||
1773 | free(tev->event); | 1773 | free(tev->event); |
1774 | free(tev->group); | 1774 | free(tev->group); |
1775 | free(tev->point.symbol); | 1775 | free(tev->point.symbol); |
1776 | free(tev->point.module); | 1776 | free(tev->point.module); |
1777 | for (i = 0; i < tev->nargs; i++) { | 1777 | for (i = 0; i < tev->nargs; i++) { |
1778 | free(tev->args[i].name); | 1778 | free(tev->args[i].name); |
1779 | free(tev->args[i].value); | 1779 | free(tev->args[i].value); |
1780 | free(tev->args[i].type); | 1780 | free(tev->args[i].type); |
1781 | ref = tev->args[i].ref; | 1781 | ref = tev->args[i].ref; |
1782 | while (ref) { | 1782 | while (ref) { |
1783 | next = ref->next; | 1783 | next = ref->next; |
1784 | free(ref); | 1784 | free(ref); |
1785 | ref = next; | 1785 | ref = next; |
1786 | } | 1786 | } |
1787 | } | 1787 | } |
1788 | free(tev->args); | 1788 | free(tev->args); |
1789 | memset(tev, 0, sizeof(*tev)); | 1789 | memset(tev, 0, sizeof(*tev)); |
1790 | } | 1790 | } |
1791 | 1791 | ||
1792 | static void print_open_warning(int err, bool is_kprobe) | 1792 | static void print_open_warning(int err, bool is_kprobe) |
1793 | { | 1793 | { |
1794 | char sbuf[STRERR_BUFSIZE]; | 1794 | char sbuf[STRERR_BUFSIZE]; |
1795 | 1795 | ||
1796 | if (err == -ENOENT) { | 1796 | if (err == -ENOENT) { |
1797 | const char *config; | 1797 | const char *config; |
1798 | 1798 | ||
1799 | if (!is_kprobe) | 1799 | if (!is_kprobe) |
1800 | config = "CONFIG_UPROBE_EVENTS"; | 1800 | config = "CONFIG_UPROBE_EVENTS"; |
1801 | else | 1801 | else |
1802 | config = "CONFIG_KPROBE_EVENTS"; | 1802 | config = "CONFIG_KPROBE_EVENTS"; |
1803 | 1803 | ||
1804 | pr_warning("%cprobe_events file does not exist" | 1804 | pr_warning("%cprobe_events file does not exist" |
1805 | " - please rebuild kernel with %s.\n", | 1805 | " - please rebuild kernel with %s.\n", |
1806 | is_kprobe ? 'k' : 'u', config); | 1806 | is_kprobe ? 'k' : 'u', config); |
1807 | } else if (err == -ENOTSUP) | 1807 | } else if (err == -ENOTSUP) |
1808 | pr_warning("Debugfs is not mounted.\n"); | 1808 | pr_warning("Debugfs is not mounted.\n"); |
1809 | else | 1809 | else |
1810 | pr_warning("Failed to open %cprobe_events: %s\n", | 1810 | pr_warning("Failed to open %cprobe_events: %s\n", |
1811 | is_kprobe ? 'k' : 'u', | 1811 | is_kprobe ? 'k' : 'u', |
1812 | strerror_r(-err, sbuf, sizeof(sbuf))); | 1812 | strerror_r(-err, sbuf, sizeof(sbuf))); |
1813 | } | 1813 | } |
1814 | 1814 | ||
1815 | static void print_both_open_warning(int kerr, int uerr) | 1815 | static void print_both_open_warning(int kerr, int uerr) |
1816 | { | 1816 | { |
1817 | /* Both kprobes and uprobes are disabled, warn it. */ | 1817 | /* Both kprobes and uprobes are disabled, warn it. */ |
1818 | if (kerr == -ENOTSUP && uerr == -ENOTSUP) | 1818 | if (kerr == -ENOTSUP && uerr == -ENOTSUP) |
1819 | pr_warning("Debugfs is not mounted.\n"); | 1819 | pr_warning("Debugfs is not mounted.\n"); |
1820 | else if (kerr == -ENOENT && uerr == -ENOENT) | 1820 | else if (kerr == -ENOENT && uerr == -ENOENT) |
1821 | pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " | 1821 | pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " |
1822 | "or/and CONFIG_UPROBE_EVENTS.\n"); | 1822 | "or/and CONFIG_UPROBE_EVENTS.\n"); |
1823 | else { | 1823 | else { |
1824 | char sbuf[STRERR_BUFSIZE]; | 1824 | char sbuf[STRERR_BUFSIZE]; |
1825 | pr_warning("Failed to open kprobe events: %s.\n", | 1825 | pr_warning("Failed to open kprobe events: %s.\n", |
1826 | strerror_r(-kerr, sbuf, sizeof(sbuf))); | 1826 | strerror_r(-kerr, sbuf, sizeof(sbuf))); |
1827 | pr_warning("Failed to open uprobe events: %s.\n", | 1827 | pr_warning("Failed to open uprobe events: %s.\n", |
1828 | strerror_r(-uerr, sbuf, sizeof(sbuf))); | 1828 | strerror_r(-uerr, sbuf, sizeof(sbuf))); |
1829 | } | 1829 | } |
1830 | } | 1830 | } |
1831 | 1831 | ||
1832 | static int open_probe_events(const char *trace_file, bool readwrite) | 1832 | static int open_probe_events(const char *trace_file, bool readwrite) |
1833 | { | 1833 | { |
1834 | char buf[PATH_MAX]; | 1834 | char buf[PATH_MAX]; |
1835 | const char *__debugfs; | 1835 | const char *__debugfs; |
1836 | int ret; | 1836 | int ret; |
1837 | 1837 | ||
1838 | __debugfs = debugfs_find_mountpoint(); | 1838 | __debugfs = debugfs_find_mountpoint(); |
1839 | if (__debugfs == NULL) | 1839 | if (__debugfs == NULL) |
1840 | return -ENOTSUP; | 1840 | return -ENOTSUP; |
1841 | 1841 | ||
1842 | ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); | 1842 | ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); |
1843 | if (ret >= 0) { | 1843 | if (ret >= 0) { |
1844 | pr_debug("Opening %s write=%d\n", buf, readwrite); | 1844 | pr_debug("Opening %s write=%d\n", buf, readwrite); |
1845 | if (readwrite && !probe_event_dry_run) | 1845 | if (readwrite && !probe_event_dry_run) |
1846 | ret = open(buf, O_RDWR, O_APPEND); | 1846 | ret = open(buf, O_RDWR, O_APPEND); |
1847 | else | 1847 | else |
1848 | ret = open(buf, O_RDONLY, 0); | 1848 | ret = open(buf, O_RDONLY, 0); |
1849 | 1849 | ||
1850 | if (ret < 0) | 1850 | if (ret < 0) |
1851 | ret = -errno; | 1851 | ret = -errno; |
1852 | } | 1852 | } |
1853 | return ret; | 1853 | return ret; |
1854 | } | 1854 | } |
1855 | 1855 | ||
1856 | static int open_kprobe_events(bool readwrite) | 1856 | static int open_kprobe_events(bool readwrite) |
1857 | { | 1857 | { |
1858 | return open_probe_events("tracing/kprobe_events", readwrite); | 1858 | return open_probe_events("tracing/kprobe_events", readwrite); |
1859 | } | 1859 | } |
1860 | 1860 | ||
1861 | static int open_uprobe_events(bool readwrite) | 1861 | static int open_uprobe_events(bool readwrite) |
1862 | { | 1862 | { |
1863 | return open_probe_events("tracing/uprobe_events", readwrite); | 1863 | return open_probe_events("tracing/uprobe_events", readwrite); |
1864 | } | 1864 | } |
1865 | 1865 | ||
1866 | /* Get raw string list of current kprobe_events or uprobe_events */ | 1866 | /* Get raw string list of current kprobe_events or uprobe_events */ |
1867 | static struct strlist *get_probe_trace_command_rawlist(int fd) | 1867 | static struct strlist *get_probe_trace_command_rawlist(int fd) |
1868 | { | 1868 | { |
1869 | int ret, idx; | 1869 | int ret, idx; |
1870 | FILE *fp; | 1870 | FILE *fp; |
1871 | char buf[MAX_CMDLEN]; | 1871 | char buf[MAX_CMDLEN]; |
1872 | char *p; | 1872 | char *p; |
1873 | struct strlist *sl; | 1873 | struct strlist *sl; |
1874 | 1874 | ||
1875 | sl = strlist__new(true, NULL); | 1875 | sl = strlist__new(true, NULL); |
1876 | 1876 | ||
1877 | fp = fdopen(dup(fd), "r"); | 1877 | fp = fdopen(dup(fd), "r"); |
1878 | while (!feof(fp)) { | 1878 | while (!feof(fp)) { |
1879 | p = fgets(buf, MAX_CMDLEN, fp); | 1879 | p = fgets(buf, MAX_CMDLEN, fp); |
1880 | if (!p) | 1880 | if (!p) |
1881 | break; | 1881 | break; |
1882 | 1882 | ||
1883 | idx = strlen(p) - 1; | 1883 | idx = strlen(p) - 1; |
1884 | if (p[idx] == '\n') | 1884 | if (p[idx] == '\n') |
1885 | p[idx] = '\0'; | 1885 | p[idx] = '\0'; |
1886 | ret = strlist__add(sl, buf); | 1886 | ret = strlist__add(sl, buf); |
1887 | if (ret < 0) { | 1887 | if (ret < 0) { |
1888 | pr_debug("strlist__add failed (%d)\n", ret); | 1888 | pr_debug("strlist__add failed (%d)\n", ret); |
1889 | strlist__delete(sl); | 1889 | strlist__delete(sl); |
1890 | return NULL; | 1890 | return NULL; |
1891 | } | 1891 | } |
1892 | } | 1892 | } |
1893 | fclose(fp); | 1893 | fclose(fp); |
1894 | 1894 | ||
1895 | return sl; | 1895 | return sl; |
1896 | } | 1896 | } |
1897 | 1897 | ||
1898 | /* Show an event */ | 1898 | /* Show an event */ |
1899 | static int show_perf_probe_event(struct perf_probe_event *pev, | 1899 | static int show_perf_probe_event(struct perf_probe_event *pev, |
1900 | const char *module) | 1900 | const char *module) |
1901 | { | 1901 | { |
1902 | int i, ret; | 1902 | int i, ret; |
1903 | char buf[128]; | 1903 | char buf[128]; |
1904 | char *place; | 1904 | char *place; |
1905 | 1905 | ||
1906 | /* Synthesize only event probe point */ | 1906 | /* Synthesize only event probe point */ |
1907 | place = synthesize_perf_probe_point(&pev->point); | 1907 | place = synthesize_perf_probe_point(&pev->point); |
1908 | if (!place) | 1908 | if (!place) |
1909 | return -EINVAL; | 1909 | return -EINVAL; |
1910 | 1910 | ||
1911 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); | 1911 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); |
1912 | if (ret < 0) | 1912 | if (ret < 0) |
1913 | return ret; | 1913 | return ret; |
1914 | 1914 | ||
1915 | pr_info(" %-20s (on %s", buf, place); | 1915 | pr_info(" %-20s (on %s", buf, place); |
1916 | if (module) | 1916 | if (module) |
1917 | pr_info(" in %s", module); | 1917 | pr_info(" in %s", module); |
1918 | 1918 | ||
1919 | if (pev->nargs > 0) { | 1919 | if (pev->nargs > 0) { |
1920 | pr_info(" with"); | 1920 | pr_info(" with"); |
1921 | for (i = 0; i < pev->nargs; i++) { | 1921 | for (i = 0; i < pev->nargs; i++) { |
1922 | ret = synthesize_perf_probe_arg(&pev->args[i], | 1922 | ret = synthesize_perf_probe_arg(&pev->args[i], |
1923 | buf, 128); | 1923 | buf, 128); |
1924 | if (ret < 0) | 1924 | if (ret < 0) |
1925 | break; | 1925 | break; |
1926 | pr_info(" %s", buf); | 1926 | pr_info(" %s", buf); |
1927 | } | 1927 | } |
1928 | } | 1928 | } |
1929 | pr_info(")\n"); | 1929 | pr_info(")\n"); |
1930 | free(place); | 1930 | free(place); |
1931 | return ret; | 1931 | return ret; |
1932 | } | 1932 | } |
1933 | 1933 | ||
1934 | static int __show_perf_probe_events(int fd, bool is_kprobe) | 1934 | static int __show_perf_probe_events(int fd, bool is_kprobe) |
1935 | { | 1935 | { |
1936 | int ret = 0; | 1936 | int ret = 0; |
1937 | struct probe_trace_event tev; | 1937 | struct probe_trace_event tev; |
1938 | struct perf_probe_event pev; | 1938 | struct perf_probe_event pev; |
1939 | struct strlist *rawlist; | 1939 | struct strlist *rawlist; |
1940 | struct str_node *ent; | 1940 | struct str_node *ent; |
1941 | 1941 | ||
1942 | memset(&tev, 0, sizeof(tev)); | 1942 | memset(&tev, 0, sizeof(tev)); |
1943 | memset(&pev, 0, sizeof(pev)); | 1943 | memset(&pev, 0, sizeof(pev)); |
1944 | 1944 | ||
1945 | rawlist = get_probe_trace_command_rawlist(fd); | 1945 | rawlist = get_probe_trace_command_rawlist(fd); |
1946 | if (!rawlist) | 1946 | if (!rawlist) |
1947 | return -ENOMEM; | 1947 | return -ENOMEM; |
1948 | 1948 | ||
1949 | strlist__for_each(ent, rawlist) { | 1949 | strlist__for_each(ent, rawlist) { |
1950 | ret = parse_probe_trace_command(ent->s, &tev); | 1950 | ret = parse_probe_trace_command(ent->s, &tev); |
1951 | if (ret >= 0) { | 1951 | if (ret >= 0) { |
1952 | ret = convert_to_perf_probe_event(&tev, &pev, | 1952 | ret = convert_to_perf_probe_event(&tev, &pev, |
1953 | is_kprobe); | 1953 | is_kprobe); |
1954 | if (ret >= 0) | 1954 | if (ret >= 0) |
1955 | ret = show_perf_probe_event(&pev, | 1955 | ret = show_perf_probe_event(&pev, |
1956 | tev.point.module); | 1956 | tev.point.module); |
1957 | } | 1957 | } |
1958 | clear_perf_probe_event(&pev); | 1958 | clear_perf_probe_event(&pev); |
1959 | clear_probe_trace_event(&tev); | 1959 | clear_probe_trace_event(&tev); |
1960 | if (ret < 0) | 1960 | if (ret < 0) |
1961 | break; | 1961 | break; |
1962 | } | 1962 | } |
1963 | strlist__delete(rawlist); | 1963 | strlist__delete(rawlist); |
1964 | 1964 | ||
1965 | return ret; | 1965 | return ret; |
1966 | } | 1966 | } |
1967 | 1967 | ||
1968 | /* List up current perf-probe events */ | 1968 | /* List up current perf-probe events */ |
1969 | int show_perf_probe_events(void) | 1969 | int show_perf_probe_events(void) |
1970 | { | 1970 | { |
1971 | int kp_fd, up_fd, ret; | 1971 | int kp_fd, up_fd, ret; |
1972 | 1972 | ||
1973 | setup_pager(); | 1973 | setup_pager(); |
1974 | 1974 | ||
1975 | ret = init_symbol_maps(false); | 1975 | ret = init_symbol_maps(false); |
1976 | if (ret < 0) | 1976 | if (ret < 0) |
1977 | return ret; | 1977 | return ret; |
1978 | 1978 | ||
1979 | kp_fd = open_kprobe_events(false); | 1979 | kp_fd = open_kprobe_events(false); |
1980 | if (kp_fd >= 0) { | 1980 | if (kp_fd >= 0) { |
1981 | ret = __show_perf_probe_events(kp_fd, true); | 1981 | ret = __show_perf_probe_events(kp_fd, true); |
1982 | close(kp_fd); | 1982 | close(kp_fd); |
1983 | if (ret < 0) | 1983 | if (ret < 0) |
1984 | goto out; | 1984 | goto out; |
1985 | } | 1985 | } |
1986 | 1986 | ||
1987 | up_fd = open_uprobe_events(false); | 1987 | up_fd = open_uprobe_events(false); |
1988 | if (kp_fd < 0 && up_fd < 0) { | 1988 | if (kp_fd < 0 && up_fd < 0) { |
1989 | print_both_open_warning(kp_fd, up_fd); | 1989 | print_both_open_warning(kp_fd, up_fd); |
1990 | ret = kp_fd; | 1990 | ret = kp_fd; |
1991 | goto out; | 1991 | goto out; |
1992 | } | 1992 | } |
1993 | 1993 | ||
1994 | if (up_fd >= 0) { | 1994 | if (up_fd >= 0) { |
1995 | ret = __show_perf_probe_events(up_fd, false); | 1995 | ret = __show_perf_probe_events(up_fd, false); |
1996 | close(up_fd); | 1996 | close(up_fd); |
1997 | } | 1997 | } |
1998 | out: | 1998 | out: |
1999 | exit_symbol_maps(); | 1999 | exit_symbol_maps(); |
2000 | return ret; | 2000 | return ret; |
2001 | } | 2001 | } |
2002 | 2002 | ||
2003 | /* Get current perf-probe event names */ | 2003 | /* Get current perf-probe event names */ |
2004 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) | 2004 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) |
2005 | { | 2005 | { |
2006 | char buf[128]; | 2006 | char buf[128]; |
2007 | struct strlist *sl, *rawlist; | 2007 | struct strlist *sl, *rawlist; |
2008 | struct str_node *ent; | 2008 | struct str_node *ent; |
2009 | struct probe_trace_event tev; | 2009 | struct probe_trace_event tev; |
2010 | int ret = 0; | 2010 | int ret = 0; |
2011 | 2011 | ||
2012 | memset(&tev, 0, sizeof(tev)); | 2012 | memset(&tev, 0, sizeof(tev)); |
2013 | rawlist = get_probe_trace_command_rawlist(fd); | 2013 | rawlist = get_probe_trace_command_rawlist(fd); |
2014 | if (!rawlist) | 2014 | if (!rawlist) |
2015 | return NULL; | 2015 | return NULL; |
2016 | sl = strlist__new(true, NULL); | 2016 | sl = strlist__new(true, NULL); |
2017 | strlist__for_each(ent, rawlist) { | 2017 | strlist__for_each(ent, rawlist) { |
2018 | ret = parse_probe_trace_command(ent->s, &tev); | 2018 | ret = parse_probe_trace_command(ent->s, &tev); |
2019 | if (ret < 0) | 2019 | if (ret < 0) |
2020 | break; | 2020 | break; |
2021 | if (include_group) { | 2021 | if (include_group) { |
2022 | ret = e_snprintf(buf, 128, "%s:%s", tev.group, | 2022 | ret = e_snprintf(buf, 128, "%s:%s", tev.group, |
2023 | tev.event); | 2023 | tev.event); |
2024 | if (ret >= 0) | 2024 | if (ret >= 0) |
2025 | ret = strlist__add(sl, buf); | 2025 | ret = strlist__add(sl, buf); |
2026 | } else | 2026 | } else |
2027 | ret = strlist__add(sl, tev.event); | 2027 | ret = strlist__add(sl, tev.event); |
2028 | clear_probe_trace_event(&tev); | 2028 | clear_probe_trace_event(&tev); |
2029 | if (ret < 0) | 2029 | if (ret < 0) |
2030 | break; | 2030 | break; |
2031 | } | 2031 | } |
2032 | strlist__delete(rawlist); | 2032 | strlist__delete(rawlist); |
2033 | 2033 | ||
2034 | if (ret < 0) { | 2034 | if (ret < 0) { |
2035 | strlist__delete(sl); | 2035 | strlist__delete(sl); |
2036 | return NULL; | 2036 | return NULL; |
2037 | } | 2037 | } |
2038 | return sl; | 2038 | return sl; |
2039 | } | 2039 | } |
2040 | 2040 | ||
2041 | static int write_probe_trace_event(int fd, struct probe_trace_event *tev) | 2041 | static int write_probe_trace_event(int fd, struct probe_trace_event *tev) |
2042 | { | 2042 | { |
2043 | int ret = 0; | 2043 | int ret = 0; |
2044 | char *buf = synthesize_probe_trace_command(tev); | 2044 | char *buf = synthesize_probe_trace_command(tev); |
2045 | char sbuf[STRERR_BUFSIZE]; | 2045 | char sbuf[STRERR_BUFSIZE]; |
2046 | 2046 | ||
2047 | if (!buf) { | 2047 | if (!buf) { |
2048 | pr_debug("Failed to synthesize probe trace event.\n"); | 2048 | pr_debug("Failed to synthesize probe trace event.\n"); |
2049 | return -EINVAL; | 2049 | return -EINVAL; |
2050 | } | 2050 | } |
2051 | 2051 | ||
2052 | pr_debug("Writing event: %s\n", buf); | 2052 | pr_debug("Writing event: %s\n", buf); |
2053 | if (!probe_event_dry_run) { | 2053 | if (!probe_event_dry_run) { |
2054 | ret = write(fd, buf, strlen(buf)); | 2054 | ret = write(fd, buf, strlen(buf)); |
2055 | if (ret <= 0) | 2055 | if (ret <= 0) { |
2056 | ret = -errno; | ||
2056 | pr_warning("Failed to write event: %s\n", | 2057 | pr_warning("Failed to write event: %s\n", |
2057 | strerror_r(errno, sbuf, sizeof(sbuf))); | 2058 | strerror_r(errno, sbuf, sizeof(sbuf))); |
2059 | } | ||
2058 | } | 2060 | } |
2059 | free(buf); | 2061 | free(buf); |
2060 | return ret; | 2062 | return ret; |
2061 | } | 2063 | } |
2062 | 2064 | ||
2063 | static int get_new_event_name(char *buf, size_t len, const char *base, | 2065 | static int get_new_event_name(char *buf, size_t len, const char *base, |
2064 | struct strlist *namelist, bool allow_suffix) | 2066 | struct strlist *namelist, bool allow_suffix) |
2065 | { | 2067 | { |
2066 | int i, ret; | 2068 | int i, ret; |
2067 | 2069 | ||
2068 | /* Try no suffix */ | 2070 | /* Try no suffix */ |
2069 | ret = e_snprintf(buf, len, "%s", base); | 2071 | ret = e_snprintf(buf, len, "%s", base); |
2070 | if (ret < 0) { | 2072 | if (ret < 0) { |
2071 | pr_debug("snprintf() failed: %d\n", ret); | 2073 | pr_debug("snprintf() failed: %d\n", ret); |
2072 | return ret; | 2074 | return ret; |
2073 | } | 2075 | } |
2074 | if (!strlist__has_entry(namelist, buf)) | 2076 | if (!strlist__has_entry(namelist, buf)) |
2075 | return 0; | 2077 | return 0; |
2076 | 2078 | ||
2077 | if (!allow_suffix) { | 2079 | if (!allow_suffix) { |
2078 | pr_warning("Error: event \"%s\" already exists. " | 2080 | pr_warning("Error: event \"%s\" already exists. " |
2079 | "(Use -f to force duplicates.)\n", base); | 2081 | "(Use -f to force duplicates.)\n", base); |
2080 | return -EEXIST; | 2082 | return -EEXIST; |
2081 | } | 2083 | } |
2082 | 2084 | ||
2083 | /* Try to add suffix */ | 2085 | /* Try to add suffix */ |
2084 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | 2086 | for (i = 1; i < MAX_EVENT_INDEX; i++) { |
2085 | ret = e_snprintf(buf, len, "%s_%d", base, i); | 2087 | ret = e_snprintf(buf, len, "%s_%d", base, i); |
2086 | if (ret < 0) { | 2088 | if (ret < 0) { |
2087 | pr_debug("snprintf() failed: %d\n", ret); | 2089 | pr_debug("snprintf() failed: %d\n", ret); |
2088 | return ret; | 2090 | return ret; |
2089 | } | 2091 | } |
2090 | if (!strlist__has_entry(namelist, buf)) | 2092 | if (!strlist__has_entry(namelist, buf)) |
2091 | break; | 2093 | break; |
2092 | } | 2094 | } |
2093 | if (i == MAX_EVENT_INDEX) { | 2095 | if (i == MAX_EVENT_INDEX) { |
2094 | pr_warning("Too many events are on the same function.\n"); | 2096 | pr_warning("Too many events are on the same function.\n"); |
2095 | ret = -ERANGE; | 2097 | ret = -ERANGE; |
2096 | } | 2098 | } |
2097 | 2099 | ||
2098 | return ret; | 2100 | return ret; |
2099 | } | 2101 | } |
2100 | 2102 | ||
2101 | static int __add_probe_trace_events(struct perf_probe_event *pev, | 2103 | static int __add_probe_trace_events(struct perf_probe_event *pev, |
2102 | struct probe_trace_event *tevs, | 2104 | struct probe_trace_event *tevs, |
2103 | int ntevs, bool allow_suffix) | 2105 | int ntevs, bool allow_suffix) |
2104 | { | 2106 | { |
2105 | int i, fd, ret; | 2107 | int i, fd, ret; |
2106 | struct probe_trace_event *tev = NULL; | 2108 | struct probe_trace_event *tev = NULL; |
2107 | char buf[64]; | 2109 | char buf[64]; |
2108 | const char *event, *group; | 2110 | const char *event, *group; |
2109 | struct strlist *namelist; | 2111 | struct strlist *namelist; |
2110 | 2112 | ||
2111 | if (pev->uprobes) | 2113 | if (pev->uprobes) |
2112 | fd = open_uprobe_events(true); | 2114 | fd = open_uprobe_events(true); |
2113 | else | 2115 | else |
2114 | fd = open_kprobe_events(true); | 2116 | fd = open_kprobe_events(true); |
2115 | 2117 | ||
2116 | if (fd < 0) { | 2118 | if (fd < 0) { |
2117 | print_open_warning(fd, !pev->uprobes); | 2119 | print_open_warning(fd, !pev->uprobes); |
2118 | return fd; | 2120 | return fd; |
2119 | } | 2121 | } |
2120 | 2122 | ||
2121 | /* Get current event names */ | 2123 | /* Get current event names */ |
2122 | namelist = get_probe_trace_event_names(fd, false); | 2124 | namelist = get_probe_trace_event_names(fd, false); |
2123 | if (!namelist) { | 2125 | if (!namelist) { |
2124 | pr_debug("Failed to get current event list.\n"); | 2126 | pr_debug("Failed to get current event list.\n"); |
2125 | return -EIO; | 2127 | return -EIO; |
2126 | } | 2128 | } |
2127 | 2129 | ||
2128 | ret = 0; | 2130 | ret = 0; |
2129 | pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); | 2131 | pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); |
2130 | for (i = 0; i < ntevs; i++) { | 2132 | for (i = 0; i < ntevs; i++) { |
2131 | tev = &tevs[i]; | 2133 | tev = &tevs[i]; |
2132 | if (pev->event) | 2134 | if (pev->event) |
2133 | event = pev->event; | 2135 | event = pev->event; |
2134 | else | 2136 | else |
2135 | if (pev->point.function) | 2137 | if (pev->point.function) |
2136 | event = pev->point.function; | 2138 | event = pev->point.function; |
2137 | else | 2139 | else |
2138 | event = tev->point.symbol; | 2140 | event = tev->point.symbol; |
2139 | if (pev->group) | 2141 | if (pev->group) |
2140 | group = pev->group; | 2142 | group = pev->group; |
2141 | else | 2143 | else |
2142 | group = PERFPROBE_GROUP; | 2144 | group = PERFPROBE_GROUP; |
2143 | 2145 | ||
2144 | /* Get an unused new event name */ | 2146 | /* Get an unused new event name */ |
2145 | ret = get_new_event_name(buf, 64, event, | 2147 | ret = get_new_event_name(buf, 64, event, |
2146 | namelist, allow_suffix); | 2148 | namelist, allow_suffix); |
2147 | if (ret < 0) | 2149 | if (ret < 0) |
2148 | break; | 2150 | break; |
2149 | event = buf; | 2151 | event = buf; |
2150 | 2152 | ||
2151 | tev->event = strdup(event); | 2153 | tev->event = strdup(event); |
2152 | tev->group = strdup(group); | 2154 | tev->group = strdup(group); |
2153 | if (tev->event == NULL || tev->group == NULL) { | 2155 | if (tev->event == NULL || tev->group == NULL) { |
2154 | ret = -ENOMEM; | 2156 | ret = -ENOMEM; |
2155 | break; | 2157 | break; |
2156 | } | 2158 | } |
2157 | ret = write_probe_trace_event(fd, tev); | 2159 | ret = write_probe_trace_event(fd, tev); |
2158 | if (ret < 0) | 2160 | if (ret < 0) |
2159 | break; | 2161 | break; |
2160 | /* Add added event name to namelist */ | 2162 | /* Add added event name to namelist */ |
2161 | strlist__add(namelist, event); | 2163 | strlist__add(namelist, event); |
2162 | 2164 | ||
2163 | /* Trick here - save current event/group */ | 2165 | /* Trick here - save current event/group */ |
2164 | event = pev->event; | 2166 | event = pev->event; |
2165 | group = pev->group; | 2167 | group = pev->group; |
2166 | pev->event = tev->event; | 2168 | pev->event = tev->event; |
2167 | pev->group = tev->group; | 2169 | pev->group = tev->group; |
2168 | show_perf_probe_event(pev, tev->point.module); | 2170 | show_perf_probe_event(pev, tev->point.module); |
2169 | /* Trick here - restore current event/group */ | 2171 | /* Trick here - restore current event/group */ |
2170 | pev->event = (char *)event; | 2172 | pev->event = (char *)event; |
2171 | pev->group = (char *)group; | 2173 | pev->group = (char *)group; |
2172 | 2174 | ||
2173 | /* | 2175 | /* |
2174 | * Probes after the first probe which comes from same | 2176 | * Probes after the first probe which comes from same |
2175 | * user input are always allowed to add suffix, because | 2177 | * user input are always allowed to add suffix, because |
2176 | * there might be several addresses corresponding to | 2178 | * there might be several addresses corresponding to |
2177 | * one code line. | 2179 | * one code line. |
2178 | */ | 2180 | */ |
2179 | allow_suffix = true; | 2181 | allow_suffix = true; |
2180 | } | 2182 | } |
2181 | 2183 | ||
2182 | if (ret >= 0) { | 2184 | if (ret >= 0) { |
2183 | /* Show how to use the event. */ | 2185 | /* Show how to use the event. */ |
2184 | pr_info("\nYou can now use it in all perf tools, such as:\n\n"); | 2186 | pr_info("\nYou can now use it in all perf tools, such as:\n\n"); |
2185 | pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, | 2187 | pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, |
2186 | tev->event); | 2188 | tev->event); |
2187 | } | 2189 | } |
2188 | 2190 | ||
2189 | strlist__delete(namelist); | 2191 | strlist__delete(namelist); |
2190 | close(fd); | 2192 | close(fd); |
2191 | return ret; | 2193 | return ret; |
2192 | } | 2194 | } |
2193 | 2195 | ||
2194 | static char *looking_function_name; | 2196 | static char *looking_function_name; |
2195 | static int num_matched_functions; | 2197 | static int num_matched_functions; |
2196 | 2198 | ||
2197 | static int probe_function_filter(struct map *map __maybe_unused, | 2199 | static int probe_function_filter(struct map *map __maybe_unused, |
2198 | struct symbol *sym) | 2200 | struct symbol *sym) |
2199 | { | 2201 | { |
2200 | if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && | 2202 | if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && |
2201 | strcmp(looking_function_name, sym->name) == 0) { | 2203 | strcmp(looking_function_name, sym->name) == 0) { |
2202 | num_matched_functions++; | 2204 | num_matched_functions++; |
2203 | return 0; | 2205 | return 0; |
2204 | } | 2206 | } |
2205 | return 1; | 2207 | return 1; |
2206 | } | 2208 | } |
2207 | 2209 | ||
2208 | #define strdup_or_goto(str, label) \ | 2210 | #define strdup_or_goto(str, label) \ |
2209 | ({ char *__p = strdup(str); if (!__p) goto label; __p; }) | 2211 | ({ char *__p = strdup(str); if (!__p) goto label; __p; }) |
2210 | 2212 | ||
2211 | /* | 2213 | /* |
2212 | * Find probe function addresses from map. | 2214 | * Find probe function addresses from map. |
2213 | * Return an error or the number of found probe_trace_event | 2215 | * Return an error or the number of found probe_trace_event |
2214 | */ | 2216 | */ |
2215 | static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | 2217 | static int find_probe_trace_events_from_map(struct perf_probe_event *pev, |
2216 | struct probe_trace_event **tevs, | 2218 | struct probe_trace_event **tevs, |
2217 | int max_tevs, const char *target) | 2219 | int max_tevs, const char *target) |
2218 | { | 2220 | { |
2219 | struct map *map = NULL; | 2221 | struct map *map = NULL; |
2220 | struct kmap *kmap = NULL; | 2222 | struct kmap *kmap = NULL; |
2221 | struct ref_reloc_sym *reloc_sym = NULL; | 2223 | struct ref_reloc_sym *reloc_sym = NULL; |
2222 | struct symbol *sym; | 2224 | struct symbol *sym; |
2223 | struct rb_node *nd; | 2225 | struct rb_node *nd; |
2224 | struct probe_trace_event *tev; | 2226 | struct probe_trace_event *tev; |
2225 | struct perf_probe_point *pp = &pev->point; | 2227 | struct perf_probe_point *pp = &pev->point; |
2226 | struct probe_trace_point *tp; | 2228 | struct probe_trace_point *tp; |
2227 | int ret, i; | 2229 | int ret, i; |
2228 | 2230 | ||
2229 | /* Init maps of given executable or kernel */ | 2231 | /* Init maps of given executable or kernel */ |
2230 | if (pev->uprobes) | 2232 | if (pev->uprobes) |
2231 | map = dso__new_map(target); | 2233 | map = dso__new_map(target); |
2232 | else | 2234 | else |
2233 | map = kernel_get_module_map(target); | 2235 | map = kernel_get_module_map(target); |
2234 | if (!map) { | 2236 | if (!map) { |
2235 | ret = -EINVAL; | 2237 | ret = -EINVAL; |
2236 | goto out; | 2238 | goto out; |
2237 | } | 2239 | } |
2238 | 2240 | ||
2239 | /* | 2241 | /* |
2240 | * Load matched symbols: Since the different local symbols may have | 2242 | * Load matched symbols: Since the different local symbols may have |
2241 | * same name but different addresses, this lists all the symbols. | 2243 | * same name but different addresses, this lists all the symbols. |
2242 | */ | 2244 | */ |
2243 | num_matched_functions = 0; | 2245 | num_matched_functions = 0; |
2244 | looking_function_name = pp->function; | 2246 | looking_function_name = pp->function; |
2245 | ret = map__load(map, probe_function_filter); | 2247 | ret = map__load(map, probe_function_filter); |
2246 | if (ret || num_matched_functions == 0) { | 2248 | if (ret || num_matched_functions == 0) { |
2247 | pr_err("Failed to find symbol %s in %s\n", pp->function, | 2249 | pr_err("Failed to find symbol %s in %s\n", pp->function, |
2248 | target ? : "kernel"); | 2250 | target ? : "kernel"); |
2249 | ret = -ENOENT; | 2251 | ret = -ENOENT; |
2250 | goto out; | 2252 | goto out; |
2251 | } else if (num_matched_functions > max_tevs) { | 2253 | } else if (num_matched_functions > max_tevs) { |
2252 | pr_err("Too many functions matched in %s\n", | 2254 | pr_err("Too many functions matched in %s\n", |
2253 | target ? : "kernel"); | 2255 | target ? : "kernel"); |
2254 | ret = -E2BIG; | 2256 | ret = -E2BIG; |
2255 | goto out; | 2257 | goto out; |
2256 | } | 2258 | } |
2257 | 2259 | ||
2258 | if (!pev->uprobes) { | 2260 | if (!pev->uprobes) { |
2259 | kmap = map__kmap(map); | 2261 | kmap = map__kmap(map); |
2260 | reloc_sym = kmap->ref_reloc_sym; | 2262 | reloc_sym = kmap->ref_reloc_sym; |
2261 | if (!reloc_sym) { | 2263 | if (!reloc_sym) { |
2262 | pr_warning("Relocated base symbol is not found!\n"); | 2264 | pr_warning("Relocated base symbol is not found!\n"); |
2263 | ret = -EINVAL; | 2265 | ret = -EINVAL; |
2264 | goto out; | 2266 | goto out; |
2265 | } | 2267 | } |
2266 | } | 2268 | } |
2267 | 2269 | ||
2268 | /* Setup result trace-probe-events */ | 2270 | /* Setup result trace-probe-events */ |
2269 | *tevs = zalloc(sizeof(*tev) * num_matched_functions); | 2271 | *tevs = zalloc(sizeof(*tev) * num_matched_functions); |
2270 | if (!*tevs) { | 2272 | if (!*tevs) { |
2271 | ret = -ENOMEM; | 2273 | ret = -ENOMEM; |
2272 | goto out; | 2274 | goto out; |
2273 | } | 2275 | } |
2274 | 2276 | ||
2275 | ret = 0; | 2277 | ret = 0; |
2276 | map__for_each_symbol(map, sym, nd) { | 2278 | map__for_each_symbol(map, sym, nd) { |
2277 | tev = (*tevs) + ret; | 2279 | tev = (*tevs) + ret; |
2278 | tp = &tev->point; | 2280 | tp = &tev->point; |
2279 | if (ret == num_matched_functions) { | 2281 | if (ret == num_matched_functions) { |
2280 | pr_warning("Too many symbols are listed. Skip it.\n"); | 2282 | pr_warning("Too many symbols are listed. Skip it.\n"); |
2281 | break; | 2283 | break; |
2282 | } | 2284 | } |
2283 | ret++; | 2285 | ret++; |
2284 | 2286 | ||
2285 | if (pp->offset > sym->end - sym->start) { | 2287 | if (pp->offset > sym->end - sym->start) { |
2286 | pr_warning("Offset %ld is bigger than the size of %s\n", | 2288 | pr_warning("Offset %ld is bigger than the size of %s\n", |
2287 | pp->offset, sym->name); | 2289 | pp->offset, sym->name); |
2288 | ret = -ENOENT; | 2290 | ret = -ENOENT; |
2289 | goto err_out; | 2291 | goto err_out; |
2290 | } | 2292 | } |
2291 | /* Add one probe point */ | 2293 | /* Add one probe point */ |
2292 | tp->address = map->unmap_ip(map, sym->start) + pp->offset; | 2294 | tp->address = map->unmap_ip(map, sym->start) + pp->offset; |
2293 | if (reloc_sym) { | 2295 | if (reloc_sym) { |
2294 | tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); | 2296 | tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); |
2295 | tp->offset = tp->address - reloc_sym->addr; | 2297 | tp->offset = tp->address - reloc_sym->addr; |
2296 | } else { | 2298 | } else { |
2297 | tp->symbol = strdup_or_goto(sym->name, nomem_out); | 2299 | tp->symbol = strdup_or_goto(sym->name, nomem_out); |
2298 | tp->offset = pp->offset; | 2300 | tp->offset = pp->offset; |
2299 | } | 2301 | } |
2300 | tp->retprobe = pp->retprobe; | 2302 | tp->retprobe = pp->retprobe; |
2301 | if (target) | 2303 | if (target) |
2302 | tev->point.module = strdup_or_goto(target, nomem_out); | 2304 | tev->point.module = strdup_or_goto(target, nomem_out); |
2303 | tev->uprobes = pev->uprobes; | 2305 | tev->uprobes = pev->uprobes; |
2304 | tev->nargs = pev->nargs; | 2306 | tev->nargs = pev->nargs; |
2305 | if (tev->nargs) { | 2307 | if (tev->nargs) { |
2306 | tev->args = zalloc(sizeof(struct probe_trace_arg) * | 2308 | tev->args = zalloc(sizeof(struct probe_trace_arg) * |
2307 | tev->nargs); | 2309 | tev->nargs); |
2308 | if (tev->args == NULL) | 2310 | if (tev->args == NULL) |
2309 | goto nomem_out; | 2311 | goto nomem_out; |
2310 | } | 2312 | } |
2311 | for (i = 0; i < tev->nargs; i++) { | 2313 | for (i = 0; i < tev->nargs; i++) { |
2312 | if (pev->args[i].name) | 2314 | if (pev->args[i].name) |
2313 | tev->args[i].name = | 2315 | tev->args[i].name = |
2314 | strdup_or_goto(pev->args[i].name, | 2316 | strdup_or_goto(pev->args[i].name, |
2315 | nomem_out); | 2317 | nomem_out); |
2316 | 2318 | ||
2317 | tev->args[i].value = strdup_or_goto(pev->args[i].var, | 2319 | tev->args[i].value = strdup_or_goto(pev->args[i].var, |
2318 | nomem_out); | 2320 | nomem_out); |
2319 | if (pev->args[i].type) | 2321 | if (pev->args[i].type) |
2320 | tev->args[i].type = | 2322 | tev->args[i].type = |
2321 | strdup_or_goto(pev->args[i].type, | 2323 | strdup_or_goto(pev->args[i].type, |
2322 | nomem_out); | 2324 | nomem_out); |
2323 | } | 2325 | } |
2324 | } | 2326 | } |
2325 | 2327 | ||
2326 | out: | 2328 | out: |
2327 | if (map && pev->uprobes) { | 2329 | if (map && pev->uprobes) { |
2328 | /* Only when using uprobe(exec) map needs to be released */ | 2330 | /* Only when using uprobe(exec) map needs to be released */ |
2329 | dso__delete(map->dso); | 2331 | dso__delete(map->dso); |
2330 | map__delete(map); | 2332 | map__delete(map); |
2331 | } | 2333 | } |
2332 | return ret; | 2334 | return ret; |
2333 | 2335 | ||
2334 | nomem_out: | 2336 | nomem_out: |
2335 | ret = -ENOMEM; | 2337 | ret = -ENOMEM; |
2336 | err_out: | 2338 | err_out: |
2337 | clear_probe_trace_events(*tevs, num_matched_functions); | 2339 | clear_probe_trace_events(*tevs, num_matched_functions); |
2338 | zfree(tevs); | 2340 | zfree(tevs); |
2339 | goto out; | 2341 | goto out; |
2340 | } | 2342 | } |
2341 | 2343 | ||
2342 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, | 2344 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, |
2343 | struct probe_trace_event **tevs, | 2345 | struct probe_trace_event **tevs, |
2344 | int max_tevs, const char *target) | 2346 | int max_tevs, const char *target) |
2345 | { | 2347 | { |
2346 | int ret; | 2348 | int ret; |
2347 | 2349 | ||
2348 | if (pev->uprobes && !pev->group) { | 2350 | if (pev->uprobes && !pev->group) { |
2349 | /* Replace group name if not given */ | 2351 | /* Replace group name if not given */ |
2350 | ret = convert_exec_to_group(target, &pev->group); | 2352 | ret = convert_exec_to_group(target, &pev->group); |
2351 | if (ret != 0) { | 2353 | if (ret != 0) { |
2352 | pr_warning("Failed to make a group name.\n"); | 2354 | pr_warning("Failed to make a group name.\n"); |
2353 | return ret; | 2355 | return ret; |
2354 | } | 2356 | } |
2355 | } | 2357 | } |
2356 | 2358 | ||
2357 | /* Convert perf_probe_event with debuginfo */ | 2359 | /* Convert perf_probe_event with debuginfo */ |
2358 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); | 2360 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); |
2359 | if (ret != 0) | 2361 | if (ret != 0) |
2360 | return ret; /* Found in debuginfo or got an error */ | 2362 | return ret; /* Found in debuginfo or got an error */ |
2361 | 2363 | ||
2362 | return find_probe_trace_events_from_map(pev, tevs, max_tevs, target); | 2364 | return find_probe_trace_events_from_map(pev, tevs, max_tevs, target); |
2363 | } | 2365 | } |
2364 | 2366 | ||
2365 | struct __event_package { | 2367 | struct __event_package { |
2366 | struct perf_probe_event *pev; | 2368 | struct perf_probe_event *pev; |
2367 | struct probe_trace_event *tevs; | 2369 | struct probe_trace_event *tevs; |
2368 | int ntevs; | 2370 | int ntevs; |
2369 | }; | 2371 | }; |
2370 | 2372 | ||
2371 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | 2373 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, |
2372 | int max_tevs, const char *target, bool force_add) | 2374 | int max_tevs, const char *target, bool force_add) |
2373 | { | 2375 | { |
2374 | int i, j, ret; | 2376 | int i, j, ret; |
2375 | struct __event_package *pkgs; | 2377 | struct __event_package *pkgs; |
2376 | 2378 | ||
2377 | ret = 0; | 2379 | ret = 0; |
2378 | pkgs = zalloc(sizeof(struct __event_package) * npevs); | 2380 | pkgs = zalloc(sizeof(struct __event_package) * npevs); |
2379 | 2381 | ||
2380 | if (pkgs == NULL) | 2382 | if (pkgs == NULL) |
2381 | return -ENOMEM; | 2383 | return -ENOMEM; |
2382 | 2384 | ||
2383 | ret = init_symbol_maps(pevs->uprobes); | 2385 | ret = init_symbol_maps(pevs->uprobes); |
2384 | if (ret < 0) { | 2386 | if (ret < 0) { |
2385 | free(pkgs); | 2387 | free(pkgs); |
2386 | return ret; | 2388 | return ret; |
2387 | } | 2389 | } |
2388 | 2390 | ||
2389 | /* Loop 1: convert all events */ | 2391 | /* Loop 1: convert all events */ |
2390 | for (i = 0; i < npevs; i++) { | 2392 | for (i = 0; i < npevs; i++) { |
2391 | pkgs[i].pev = &pevs[i]; | 2393 | pkgs[i].pev = &pevs[i]; |
2392 | /* Convert with or without debuginfo */ | 2394 | /* Convert with or without debuginfo */ |
2393 | ret = convert_to_probe_trace_events(pkgs[i].pev, | 2395 | ret = convert_to_probe_trace_events(pkgs[i].pev, |
2394 | &pkgs[i].tevs, | 2396 | &pkgs[i].tevs, |
2395 | max_tevs, | 2397 | max_tevs, |
2396 | target); | 2398 | target); |
2397 | if (ret < 0) | 2399 | if (ret < 0) |
2398 | goto end; | 2400 | goto end; |
2399 | pkgs[i].ntevs = ret; | 2401 | pkgs[i].ntevs = ret; |
2400 | } | 2402 | } |
2401 | 2403 | ||
2402 | /* Loop 2: add all events */ | 2404 | /* Loop 2: add all events */ |
2403 | for (i = 0; i < npevs; i++) { | 2405 | for (i = 0; i < npevs; i++) { |
2404 | ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, | 2406 | ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, |
2405 | pkgs[i].ntevs, force_add); | 2407 | pkgs[i].ntevs, force_add); |
2406 | if (ret < 0) | 2408 | if (ret < 0) |
2407 | break; | 2409 | break; |
2408 | } | 2410 | } |
2409 | end: | 2411 | end: |
2410 | /* Loop 3: cleanup and free trace events */ | 2412 | /* Loop 3: cleanup and free trace events */ |
2411 | for (i = 0; i < npevs; i++) { | 2413 | for (i = 0; i < npevs; i++) { |
2412 | for (j = 0; j < pkgs[i].ntevs; j++) | 2414 | for (j = 0; j < pkgs[i].ntevs; j++) |
2413 | clear_probe_trace_event(&pkgs[i].tevs[j]); | 2415 | clear_probe_trace_event(&pkgs[i].tevs[j]); |
2414 | zfree(&pkgs[i].tevs); | 2416 | zfree(&pkgs[i].tevs); |
2415 | } | 2417 | } |
2416 | free(pkgs); | 2418 | free(pkgs); |
2417 | exit_symbol_maps(); | 2419 | exit_symbol_maps(); |
2418 | 2420 | ||
2419 | return ret; | 2421 | return ret; |
2420 | } | 2422 | } |
2421 | 2423 | ||
2422 | static int __del_trace_probe_event(int fd, struct str_node *ent) | 2424 | static int __del_trace_probe_event(int fd, struct str_node *ent) |
2423 | { | 2425 | { |
2424 | char *p; | 2426 | char *p; |
2425 | char buf[128]; | 2427 | char buf[128]; |
2426 | int ret; | 2428 | int ret; |
2427 | 2429 | ||
2428 | /* Convert from perf-probe event to trace-probe event */ | 2430 | /* Convert from perf-probe event to trace-probe event */ |
2429 | ret = e_snprintf(buf, 128, "-:%s", ent->s); | 2431 | ret = e_snprintf(buf, 128, "-:%s", ent->s); |
2430 | if (ret < 0) | 2432 | if (ret < 0) |
2431 | goto error; | 2433 | goto error; |
2432 | 2434 | ||
2433 | p = strchr(buf + 2, ':'); | 2435 | p = strchr(buf + 2, ':'); |
2434 | if (!p) { | 2436 | if (!p) { |
2435 | pr_debug("Internal error: %s should have ':' but not.\n", | 2437 | pr_debug("Internal error: %s should have ':' but not.\n", |
2436 | ent->s); | 2438 | ent->s); |
2437 | ret = -ENOTSUP; | 2439 | ret = -ENOTSUP; |
2438 | goto error; | 2440 | goto error; |
2439 | } | 2441 | } |
2440 | *p = '/'; | 2442 | *p = '/'; |
2441 | 2443 | ||
2442 | pr_debug("Writing event: %s\n", buf); | 2444 | pr_debug("Writing event: %s\n", buf); |
2443 | ret = write(fd, buf, strlen(buf)); | 2445 | ret = write(fd, buf, strlen(buf)); |
2444 | if (ret < 0) { | 2446 | if (ret < 0) { |
2445 | ret = -errno; | 2447 | ret = -errno; |
2446 | goto error; | 2448 | goto error; |
2447 | } | 2449 | } |
2448 | 2450 | ||
2449 | pr_info("Removed event: %s\n", ent->s); | 2451 | pr_info("Removed event: %s\n", ent->s); |
2450 | return 0; | 2452 | return 0; |
2451 | error: | 2453 | error: |
2452 | pr_warning("Failed to delete event: %s\n", | 2454 | pr_warning("Failed to delete event: %s\n", |
2453 | strerror_r(-ret, buf, sizeof(buf))); | 2455 | strerror_r(-ret, buf, sizeof(buf))); |
2454 | return ret; | 2456 | return ret; |
2455 | } | 2457 | } |
2456 | 2458 | ||
2457 | static int del_trace_probe_event(int fd, const char *buf, | 2459 | static int del_trace_probe_event(int fd, const char *buf, |
2458 | struct strlist *namelist) | 2460 | struct strlist *namelist) |
2459 | { | 2461 | { |
2460 | struct str_node *ent, *n; | 2462 | struct str_node *ent, *n; |
2461 | int ret = -1; | 2463 | int ret = -1; |
2462 | 2464 | ||
2463 | if (strpbrk(buf, "*?")) { /* Glob-exp */ | 2465 | if (strpbrk(buf, "*?")) { /* Glob-exp */ |
2464 | strlist__for_each_safe(ent, n, namelist) | 2466 | strlist__for_each_safe(ent, n, namelist) |
2465 | if (strglobmatch(ent->s, buf)) { | 2467 | if (strglobmatch(ent->s, buf)) { |
2466 | ret = __del_trace_probe_event(fd, ent); | 2468 | ret = __del_trace_probe_event(fd, ent); |
2467 | if (ret < 0) | 2469 | if (ret < 0) |
2468 | break; | 2470 | break; |
2469 | strlist__remove(namelist, ent); | 2471 | strlist__remove(namelist, ent); |
2470 | } | 2472 | } |
2471 | } else { | 2473 | } else { |
2472 | ent = strlist__find(namelist, buf); | 2474 | ent = strlist__find(namelist, buf); |
2473 | if (ent) { | 2475 | if (ent) { |
2474 | ret = __del_trace_probe_event(fd, ent); | 2476 | ret = __del_trace_probe_event(fd, ent); |
2475 | if (ret >= 0) | 2477 | if (ret >= 0) |
2476 | strlist__remove(namelist, ent); | 2478 | strlist__remove(namelist, ent); |
2477 | } | 2479 | } |
2478 | } | 2480 | } |
2479 | 2481 | ||
2480 | return ret; | 2482 | return ret; |
2481 | } | 2483 | } |
2482 | 2484 | ||
2483 | int del_perf_probe_events(struct strlist *dellist) | 2485 | int del_perf_probe_events(struct strlist *dellist) |
2484 | { | 2486 | { |
2485 | int ret = -1, ufd = -1, kfd = -1; | 2487 | int ret = -1, ufd = -1, kfd = -1; |
2486 | char buf[128]; | 2488 | char buf[128]; |
2487 | const char *group, *event; | 2489 | const char *group, *event; |
2488 | char *p, *str; | 2490 | char *p, *str; |
2489 | struct str_node *ent; | 2491 | struct str_node *ent; |
2490 | struct strlist *namelist = NULL, *unamelist = NULL; | 2492 | struct strlist *namelist = NULL, *unamelist = NULL; |
2491 | 2493 | ||
2492 | /* Get current event names */ | 2494 | /* Get current event names */ |
2493 | kfd = open_kprobe_events(true); | 2495 | kfd = open_kprobe_events(true); |
2494 | if (kfd >= 0) | 2496 | if (kfd >= 0) |
2495 | namelist = get_probe_trace_event_names(kfd, true); | 2497 | namelist = get_probe_trace_event_names(kfd, true); |
2496 | 2498 | ||
2497 | ufd = open_uprobe_events(true); | 2499 | ufd = open_uprobe_events(true); |
2498 | if (ufd >= 0) | 2500 | if (ufd >= 0) |
2499 | unamelist = get_probe_trace_event_names(ufd, true); | 2501 | unamelist = get_probe_trace_event_names(ufd, true); |
2500 | 2502 | ||
2501 | if (kfd < 0 && ufd < 0) { | 2503 | if (kfd < 0 && ufd < 0) { |
2502 | print_both_open_warning(kfd, ufd); | 2504 | print_both_open_warning(kfd, ufd); |
2503 | goto error; | 2505 | goto error; |
2504 | } | 2506 | } |
2505 | 2507 | ||
2506 | if (namelist == NULL && unamelist == NULL) | 2508 | if (namelist == NULL && unamelist == NULL) |
2507 | goto error; | 2509 | goto error; |
2508 | 2510 | ||
2509 | strlist__for_each(ent, dellist) { | 2511 | strlist__for_each(ent, dellist) { |
2510 | str = strdup(ent->s); | 2512 | str = strdup(ent->s); |
2511 | if (str == NULL) { | 2513 | if (str == NULL) { |
2512 | ret = -ENOMEM; | 2514 | ret = -ENOMEM; |
2513 | goto error; | 2515 | goto error; |
2514 | } | 2516 | } |
2515 | pr_debug("Parsing: %s\n", str); | 2517 | pr_debug("Parsing: %s\n", str); |
2516 | p = strchr(str, ':'); | 2518 | p = strchr(str, ':'); |
2517 | if (p) { | 2519 | if (p) { |
2518 | group = str; | 2520 | group = str; |
2519 | *p = '\0'; | 2521 | *p = '\0'; |
2520 | event = p + 1; | 2522 | event = p + 1; |
2521 | } else { | 2523 | } else { |
2522 | group = "*"; | 2524 | group = "*"; |
2523 | event = str; | 2525 | event = str; |
2524 | } | 2526 | } |
2525 | 2527 | ||
2526 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | 2528 | ret = e_snprintf(buf, 128, "%s:%s", group, event); |
2527 | if (ret < 0) { | 2529 | if (ret < 0) { |
2528 | pr_err("Failed to copy event."); | 2530 | pr_err("Failed to copy event."); |
2529 | free(str); | 2531 | free(str); |
2530 | goto error; | 2532 | goto error; |
2531 | } | 2533 | } |
2532 | 2534 | ||
2533 | pr_debug("Group: %s, Event: %s\n", group, event); | 2535 | pr_debug("Group: %s, Event: %s\n", group, event); |
2534 | 2536 | ||
2535 | if (namelist) | 2537 | if (namelist) |
2536 | ret = del_trace_probe_event(kfd, buf, namelist); | 2538 | ret = del_trace_probe_event(kfd, buf, namelist); |
2537 | 2539 | ||
2538 | if (unamelist && ret != 0) | 2540 | if (unamelist && ret != 0) |
2539 | ret = del_trace_probe_event(ufd, buf, unamelist); | 2541 | ret = del_trace_probe_event(ufd, buf, unamelist); |
2540 | 2542 | ||
2541 | if (ret != 0) | 2543 | if (ret != 0) |
2542 | pr_info("Info: Event \"%s\" does not exist.\n", buf); | 2544 | pr_info("Info: Event \"%s\" does not exist.\n", buf); |
2543 | 2545 | ||
2544 | free(str); | 2546 | free(str); |
2545 | } | 2547 | } |
2546 | 2548 | ||
2547 | error: | 2549 | error: |
2548 | if (kfd >= 0) { | 2550 | if (kfd >= 0) { |
2549 | strlist__delete(namelist); | 2551 | strlist__delete(namelist); |
2550 | close(kfd); | 2552 | close(kfd); |
2551 | } | 2553 | } |
2552 | 2554 | ||
2553 | if (ufd >= 0) { | 2555 | if (ufd >= 0) { |
2554 | strlist__delete(unamelist); | 2556 | strlist__delete(unamelist); |
2555 | close(ufd); | 2557 | close(ufd); |
2556 | } | 2558 | } |
2557 | 2559 | ||
2558 | return ret; | 2560 | return ret; |
2559 | } | 2561 | } |
2560 | 2562 | ||
2561 | /* TODO: don't use a global variable for filter ... */ | 2563 | /* TODO: don't use a global variable for filter ... */ |
2562 | static struct strfilter *available_func_filter; | 2564 | static struct strfilter *available_func_filter; |
2563 | 2565 | ||
2564 | /* | 2566 | /* |
2565 | * If a symbol corresponds to a function with global binding and | 2567 | * If a symbol corresponds to a function with global binding and |
2566 | * matches filter return 0. For all others return 1. | 2568 | * matches filter return 0. For all others return 1. |
2567 | */ | 2569 | */ |
2568 | static int filter_available_functions(struct map *map __maybe_unused, | 2570 | static int filter_available_functions(struct map *map __maybe_unused, |
2569 | struct symbol *sym) | 2571 | struct symbol *sym) |
2570 | { | 2572 | { |
2571 | if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && | 2573 | if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && |
2572 | strfilter__compare(available_func_filter, sym->name)) | 2574 | strfilter__compare(available_func_filter, sym->name)) |
2573 | return 0; | 2575 | return 0; |
2574 | return 1; | 2576 | return 1; |
2575 | } | 2577 | } |
2576 | 2578 | ||
2577 | int show_available_funcs(const char *target, struct strfilter *_filter, | 2579 | int show_available_funcs(const char *target, struct strfilter *_filter, |
2578 | bool user) | 2580 | bool user) |
2579 | { | 2581 | { |
2580 | struct map *map; | 2582 | struct map *map; |
2581 | int ret; | 2583 | int ret; |
2582 | 2584 | ||
2583 | ret = init_symbol_maps(user); | 2585 | ret = init_symbol_maps(user); |
2584 | if (ret < 0) | 2586 | if (ret < 0) |
2585 | return ret; | 2587 | return ret; |
2586 | 2588 | ||
2587 | /* Get a symbol map */ | 2589 | /* Get a symbol map */ |
2588 | if (user) | 2590 | if (user) |
2589 | map = dso__new_map(target); | 2591 | map = dso__new_map(target); |
2590 | else | 2592 | else |
2591 | map = kernel_get_module_map(target); | 2593 | map = kernel_get_module_map(target); |
2592 | if (!map) { | 2594 | if (!map) { |
2593 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); | 2595 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); |
2594 | return -EINVAL; | 2596 | return -EINVAL; |
2595 | } | 2597 | } |
2596 | 2598 | ||
2597 | /* Load symbols with given filter */ | 2599 | /* Load symbols with given filter */ |
2598 | available_func_filter = _filter; | 2600 | available_func_filter = _filter; |
2599 | if (map__load(map, filter_available_functions)) { | 2601 | if (map__load(map, filter_available_functions)) { |
2600 | pr_err("Failed to load symbols in %s\n", (target) ? : "kernel"); | 2602 | pr_err("Failed to load symbols in %s\n", (target) ? : "kernel"); |
2601 | goto end; | 2603 | goto end; |
2602 | } | 2604 | } |
2603 | if (!dso__sorted_by_name(map->dso, map->type)) | 2605 | if (!dso__sorted_by_name(map->dso, map->type)) |
2604 | dso__sort_by_name(map->dso, map->type); | 2606 | dso__sort_by_name(map->dso, map->type); |
2605 | 2607 | ||
2606 | /* Show all (filtered) symbols */ | 2608 | /* Show all (filtered) symbols */ |
2607 | setup_pager(); | 2609 | setup_pager(); |
2608 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); | 2610 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); |
2609 | end: | 2611 | end: |
2610 | if (user) { | 2612 | if (user) { |
2611 | dso__delete(map->dso); | 2613 | dso__delete(map->dso); |
2612 | map__delete(map); | 2614 | map__delete(map); |
2613 | } | 2615 | } |
2614 | exit_symbol_maps(); | 2616 | exit_symbol_maps(); |
2615 | 2617 | ||
2616 | return ret; | 2618 | return ret; |
2617 | } | 2619 | } |
2618 | 2620 | ||
2619 | 2621 |
tools/perf/util/python-ext-sources
1 | # | 1 | # |
2 | # List of files needed by perf python extension | 2 | # List of files needed by perf python extension |
3 | # | 3 | # |
4 | # Each source file must be placed on its own line so that it can be | 4 | # Each source file must be placed on its own line so that it can be |
5 | # processed by Makefile and util/setup.py accordingly. | 5 | # processed by Makefile and util/setup.py accordingly. |
6 | # | 6 | # |
7 | 7 | ||
8 | util/python.c | 8 | util/python.c |
9 | util/ctype.c | 9 | util/ctype.c |
10 | util/evlist.c | 10 | util/evlist.c |
11 | util/evsel.c | 11 | util/evsel.c |
12 | util/cpumap.c | 12 | util/cpumap.c |
13 | util/hweight.c | 13 | ../../lib/hweight.c |
14 | util/thread_map.c | 14 | util/thread_map.c |
15 | util/util.c | 15 | util/util.c |
16 | util/xyarray.c | 16 | util/xyarray.c |
17 | util/cgroup.c | 17 | util/cgroup.c |
18 | util/rblist.c | 18 | util/rblist.c |
19 | util/strlist.c | 19 | util/strlist.c |
20 | ../lib/api/fs/fs.c | 20 | ../lib/api/fs/fs.c |
21 | util/trace-event.c | 21 | util/trace-event.c |
22 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
23 | 23 |
tools/perf/util/unwind-libunwind.c
1 | /* | 1 | /* |
2 | * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. | 2 | * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. |
3 | * | 3 | * |
4 | * Lots of this code have been borrowed or heavily inspired from parts of | 4 | * Lots of this code have been borrowed or heavily inspired from parts of |
5 | * the libunwind 0.99 code which are (amongst other contributors I may have | 5 | * the libunwind 0.99 code which are (amongst other contributors I may have |
6 | * forgotten): | 6 | * forgotten): |
7 | * | 7 | * |
8 | * Copyright (C) 2002-2007 Hewlett-Packard Co | 8 | * Copyright (C) 2002-2007 Hewlett-Packard Co |
9 | * Contributed by David Mosberger-Tang <davidm@hpl.hp.com> | 9 | * Contributed by David Mosberger-Tang <davidm@hpl.hp.com> |
10 | * | 10 | * |
11 | * And the bugs have been added by: | 11 | * And the bugs have been added by: |
12 | * | 12 | * |
13 | * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com> | 13 | * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com> |
14 | * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com> | 14 | * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com> |
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <elf.h> | 18 | #include <elf.h> |
19 | #include <gelf.h> | 19 | #include <gelf.h> |
20 | #include <fcntl.h> | 20 | #include <fcntl.h> |
21 | #include <string.h> | 21 | #include <string.h> |
22 | #include <unistd.h> | 22 | #include <unistd.h> |
23 | #include <sys/mman.h> | 23 | #include <sys/mman.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <libunwind.h> | 25 | #include <libunwind.h> |
26 | #include <libunwind-ptrace.h> | 26 | #include <libunwind-ptrace.h> |
27 | #include "callchain.h" | 27 | #include "callchain.h" |
28 | #include "thread.h" | 28 | #include "thread.h" |
29 | #include "session.h" | 29 | #include "session.h" |
30 | #include "perf_regs.h" | 30 | #include "perf_regs.h" |
31 | #include "unwind.h" | 31 | #include "unwind.h" |
32 | #include "symbol.h" | 32 | #include "symbol.h" |
33 | #include "util.h" | 33 | #include "util.h" |
34 | #include "debug.h" | 34 | #include "debug.h" |
35 | 35 | ||
36 | extern int | 36 | extern int |
37 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | 37 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, |
38 | unw_word_t ip, | 38 | unw_word_t ip, |
39 | unw_dyn_info_t *di, | 39 | unw_dyn_info_t *di, |
40 | unw_proc_info_t *pi, | 40 | unw_proc_info_t *pi, |
41 | int need_unwind_info, void *arg); | 41 | int need_unwind_info, void *arg); |
42 | 42 | ||
43 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | 43 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) |
44 | 44 | ||
45 | extern int | 45 | extern int |
46 | UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, | 46 | UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, |
47 | unw_word_t ip, | 47 | unw_word_t ip, |
48 | unw_word_t segbase, | 48 | unw_word_t segbase, |
49 | const char *obj_name, unw_word_t start, | 49 | const char *obj_name, unw_word_t start, |
50 | unw_word_t end); | 50 | unw_word_t end); |
51 | 51 | ||
52 | #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) | 52 | #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) |
53 | 53 | ||
54 | #define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ | 54 | #define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ |
55 | #define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ | 55 | #define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ |
56 | 56 | ||
57 | /* Pointer-encoding formats: */ | 57 | /* Pointer-encoding formats: */ |
58 | #define DW_EH_PE_omit 0xff | 58 | #define DW_EH_PE_omit 0xff |
59 | #define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ | 59 | #define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ |
60 | #define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ | 60 | #define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ |
61 | #define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ | 61 | #define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ |
62 | #define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ | 62 | #define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ |
63 | #define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ | 63 | #define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ |
64 | 64 | ||
65 | /* Pointer-encoding application: */ | 65 | /* Pointer-encoding application: */ |
66 | #define DW_EH_PE_absptr 0x00 /* absolute value */ | 66 | #define DW_EH_PE_absptr 0x00 /* absolute value */ |
67 | #define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ | 67 | #define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * The following are not documented by LSB v1.3, yet they are used by | 70 | * The following are not documented by LSB v1.3, yet they are used by |
71 | * GCC, presumably they aren't documented by LSB since they aren't | 71 | * GCC, presumably they aren't documented by LSB since they aren't |
72 | * used on Linux: | 72 | * used on Linux: |
73 | */ | 73 | */ |
74 | #define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ | 74 | #define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ |
75 | #define DW_EH_PE_aligned 0x50 /* aligned pointer */ | 75 | #define DW_EH_PE_aligned 0x50 /* aligned pointer */ |
76 | 76 | ||
77 | /* Flags intentionaly not handled, since they're not needed: | 77 | /* Flags intentionaly not handled, since they're not needed: |
78 | * #define DW_EH_PE_indirect 0x80 | 78 | * #define DW_EH_PE_indirect 0x80 |
79 | * #define DW_EH_PE_uleb128 0x01 | 79 | * #define DW_EH_PE_uleb128 0x01 |
80 | * #define DW_EH_PE_udata2 0x02 | 80 | * #define DW_EH_PE_udata2 0x02 |
81 | * #define DW_EH_PE_sleb128 0x09 | 81 | * #define DW_EH_PE_sleb128 0x09 |
82 | * #define DW_EH_PE_sdata2 0x0a | 82 | * #define DW_EH_PE_sdata2 0x0a |
83 | * #define DW_EH_PE_textrel 0x20 | 83 | * #define DW_EH_PE_textrel 0x20 |
84 | * #define DW_EH_PE_datarel 0x30 | 84 | * #define DW_EH_PE_datarel 0x30 |
85 | */ | 85 | */ |
86 | 86 | ||
87 | struct unwind_info { | 87 | struct unwind_info { |
88 | struct perf_sample *sample; | 88 | struct perf_sample *sample; |
89 | struct machine *machine; | 89 | struct machine *machine; |
90 | struct thread *thread; | 90 | struct thread *thread; |
91 | }; | 91 | }; |
92 | 92 | ||
93 | #define dw_read(ptr, type, end) ({ \ | 93 | #define dw_read(ptr, type, end) ({ \ |
94 | type *__p = (type *) ptr; \ | 94 | type *__p = (type *) ptr; \ |
95 | type __v; \ | 95 | type __v; \ |
96 | if ((__p + 1) > (type *) end) \ | 96 | if ((__p + 1) > (type *) end) \ |
97 | return -EINVAL; \ | 97 | return -EINVAL; \ |
98 | __v = *__p++; \ | 98 | __v = *__p++; \ |
99 | ptr = (typeof(ptr)) __p; \ | 99 | ptr = (typeof(ptr)) __p; \ |
100 | __v; \ | 100 | __v; \ |
101 | }) | 101 | }) |
102 | 102 | ||
103 | static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, | 103 | static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, |
104 | u8 encoding) | 104 | u8 encoding) |
105 | { | 105 | { |
106 | u8 *cur = *p; | 106 | u8 *cur = *p; |
107 | *val = 0; | 107 | *val = 0; |
108 | 108 | ||
109 | switch (encoding) { | 109 | switch (encoding) { |
110 | case DW_EH_PE_omit: | 110 | case DW_EH_PE_omit: |
111 | *val = 0; | 111 | *val = 0; |
112 | goto out; | 112 | goto out; |
113 | case DW_EH_PE_ptr: | 113 | case DW_EH_PE_ptr: |
114 | *val = dw_read(cur, unsigned long, end); | 114 | *val = dw_read(cur, unsigned long, end); |
115 | goto out; | 115 | goto out; |
116 | default: | 116 | default: |
117 | break; | 117 | break; |
118 | } | 118 | } |
119 | 119 | ||
120 | switch (encoding & DW_EH_PE_APPL_MASK) { | 120 | switch (encoding & DW_EH_PE_APPL_MASK) { |
121 | case DW_EH_PE_absptr: | 121 | case DW_EH_PE_absptr: |
122 | break; | 122 | break; |
123 | case DW_EH_PE_pcrel: | 123 | case DW_EH_PE_pcrel: |
124 | *val = (unsigned long) cur; | 124 | *val = (unsigned long) cur; |
125 | break; | 125 | break; |
126 | default: | 126 | default: |
127 | return -EINVAL; | 127 | return -EINVAL; |
128 | } | 128 | } |
129 | 129 | ||
130 | if ((encoding & 0x07) == 0x00) | 130 | if ((encoding & 0x07) == 0x00) |
131 | encoding |= DW_EH_PE_udata4; | 131 | encoding |= DW_EH_PE_udata4; |
132 | 132 | ||
133 | switch (encoding & DW_EH_PE_FORMAT_MASK) { | 133 | switch (encoding & DW_EH_PE_FORMAT_MASK) { |
134 | case DW_EH_PE_sdata4: | 134 | case DW_EH_PE_sdata4: |
135 | *val += dw_read(cur, s32, end); | 135 | *val += dw_read(cur, s32, end); |
136 | break; | 136 | break; |
137 | case DW_EH_PE_udata4: | 137 | case DW_EH_PE_udata4: |
138 | *val += dw_read(cur, u32, end); | 138 | *val += dw_read(cur, u32, end); |
139 | break; | 139 | break; |
140 | case DW_EH_PE_sdata8: | 140 | case DW_EH_PE_sdata8: |
141 | *val += dw_read(cur, s64, end); | 141 | *val += dw_read(cur, s64, end); |
142 | break; | 142 | break; |
143 | case DW_EH_PE_udata8: | 143 | case DW_EH_PE_udata8: |
144 | *val += dw_read(cur, u64, end); | 144 | *val += dw_read(cur, u64, end); |
145 | break; | 145 | break; |
146 | default: | 146 | default: |
147 | return -EINVAL; | 147 | return -EINVAL; |
148 | } | 148 | } |
149 | 149 | ||
150 | out: | 150 | out: |
151 | *p = cur; | 151 | *p = cur; |
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | #define dw_read_encoded_value(ptr, end, enc) ({ \ | 155 | #define dw_read_encoded_value(ptr, end, enc) ({ \ |
156 | u64 __v; \ | 156 | u64 __v; \ |
157 | if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ | 157 | if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ |
158 | return -EINVAL; \ | 158 | return -EINVAL; \ |
159 | } \ | 159 | } \ |
160 | __v; \ | 160 | __v; \ |
161 | }) | 161 | }) |
162 | 162 | ||
163 | static u64 elf_section_offset(int fd, const char *name) | 163 | static u64 elf_section_offset(int fd, const char *name) |
164 | { | 164 | { |
165 | Elf *elf; | 165 | Elf *elf; |
166 | GElf_Ehdr ehdr; | 166 | GElf_Ehdr ehdr; |
167 | GElf_Shdr shdr; | 167 | GElf_Shdr shdr; |
168 | u64 offset = 0; | 168 | u64 offset = 0; |
169 | 169 | ||
170 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 170 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
171 | if (elf == NULL) | 171 | if (elf == NULL) |
172 | return 0; | 172 | return 0; |
173 | 173 | ||
174 | do { | 174 | do { |
175 | if (gelf_getehdr(elf, &ehdr) == NULL) | 175 | if (gelf_getehdr(elf, &ehdr) == NULL) |
176 | break; | 176 | break; |
177 | 177 | ||
178 | if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) | 178 | if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) |
179 | break; | 179 | break; |
180 | 180 | ||
181 | offset = shdr.sh_offset; | 181 | offset = shdr.sh_offset; |
182 | } while (0); | 182 | } while (0); |
183 | 183 | ||
184 | elf_end(elf); | 184 | elf_end(elf); |
185 | return offset; | 185 | return offset; |
186 | } | 186 | } |
187 | 187 | ||
188 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | ||
189 | static int elf_is_exec(int fd, const char *name) | ||
190 | { | ||
191 | Elf *elf; | ||
192 | GElf_Ehdr ehdr; | ||
193 | int retval = 0; | ||
194 | |||
195 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
196 | if (elf == NULL) | ||
197 | return 0; | ||
198 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
199 | goto out; | ||
200 | |||
201 | retval = (ehdr.e_type == ET_EXEC); | ||
202 | |||
203 | out: | ||
204 | elf_end(elf); | ||
205 | pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); | ||
206 | return retval; | ||
207 | } | ||
208 | #endif | ||
209 | |||
188 | struct table_entry { | 210 | struct table_entry { |
189 | u32 start_ip_offset; | 211 | u32 start_ip_offset; |
190 | u32 fde_offset; | 212 | u32 fde_offset; |
191 | }; | 213 | }; |
192 | 214 | ||
193 | struct eh_frame_hdr { | 215 | struct eh_frame_hdr { |
194 | unsigned char version; | 216 | unsigned char version; |
195 | unsigned char eh_frame_ptr_enc; | 217 | unsigned char eh_frame_ptr_enc; |
196 | unsigned char fde_count_enc; | 218 | unsigned char fde_count_enc; |
197 | unsigned char table_enc; | 219 | unsigned char table_enc; |
198 | 220 | ||
199 | /* | 221 | /* |
200 | * The rest of the header is variable-length and consists of the | 222 | * The rest of the header is variable-length and consists of the |
201 | * following members: | 223 | * following members: |
202 | * | 224 | * |
203 | * encoded_t eh_frame_ptr; | 225 | * encoded_t eh_frame_ptr; |
204 | * encoded_t fde_count; | 226 | * encoded_t fde_count; |
205 | */ | 227 | */ |
206 | 228 | ||
207 | /* A single encoded pointer should not be more than 8 bytes. */ | 229 | /* A single encoded pointer should not be more than 8 bytes. */ |
208 | u64 enc[2]; | 230 | u64 enc[2]; |
209 | 231 | ||
210 | /* | 232 | /* |
211 | * struct { | 233 | * struct { |
212 | * encoded_t start_ip; | 234 | * encoded_t start_ip; |
213 | * encoded_t fde_addr; | 235 | * encoded_t fde_addr; |
214 | * } binary_search_table[fde_count]; | 236 | * } binary_search_table[fde_count]; |
215 | */ | 237 | */ |
216 | char data[0]; | 238 | char data[0]; |
217 | } __packed; | 239 | } __packed; |
218 | 240 | ||
219 | static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, | 241 | static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, |
220 | u64 offset, u64 *table_data, u64 *segbase, | 242 | u64 offset, u64 *table_data, u64 *segbase, |
221 | u64 *fde_count) | 243 | u64 *fde_count) |
222 | { | 244 | { |
223 | struct eh_frame_hdr hdr; | 245 | struct eh_frame_hdr hdr; |
224 | u8 *enc = (u8 *) &hdr.enc; | 246 | u8 *enc = (u8 *) &hdr.enc; |
225 | u8 *end = (u8 *) &hdr.data; | 247 | u8 *end = (u8 *) &hdr.data; |
226 | ssize_t r; | 248 | ssize_t r; |
227 | 249 | ||
228 | r = dso__data_read_offset(dso, machine, offset, | 250 | r = dso__data_read_offset(dso, machine, offset, |
229 | (u8 *) &hdr, sizeof(hdr)); | 251 | (u8 *) &hdr, sizeof(hdr)); |
230 | if (r != sizeof(hdr)) | 252 | if (r != sizeof(hdr)) |
231 | return -EINVAL; | 253 | return -EINVAL; |
232 | 254 | ||
233 | /* We dont need eh_frame_ptr, just skip it. */ | 255 | /* We dont need eh_frame_ptr, just skip it. */ |
234 | dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); | 256 | dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); |
235 | 257 | ||
236 | *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); | 258 | *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); |
237 | *segbase = offset; | 259 | *segbase = offset; |
238 | *table_data = (enc - (u8 *) &hdr) + offset; | 260 | *table_data = (enc - (u8 *) &hdr) + offset; |
239 | return 0; | 261 | return 0; |
240 | } | 262 | } |
241 | 263 | ||
242 | static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, | 264 | static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, |
243 | u64 *table_data, u64 *segbase, | 265 | u64 *table_data, u64 *segbase, |
244 | u64 *fde_count) | 266 | u64 *fde_count) |
245 | { | 267 | { |
246 | int ret = -EINVAL, fd; | 268 | int ret = -EINVAL, fd; |
247 | u64 offset; | 269 | u64 offset; |
248 | 270 | ||
249 | fd = dso__data_fd(dso, machine); | 271 | fd = dso__data_fd(dso, machine); |
250 | if (fd < 0) | 272 | if (fd < 0) |
251 | return -EINVAL; | 273 | return -EINVAL; |
252 | 274 | ||
253 | /* Check the .eh_frame section for unwinding info */ | 275 | /* Check the .eh_frame section for unwinding info */ |
254 | offset = elf_section_offset(fd, ".eh_frame_hdr"); | 276 | offset = elf_section_offset(fd, ".eh_frame_hdr"); |
255 | 277 | ||
256 | if (offset) | 278 | if (offset) |
257 | ret = unwind_spec_ehframe(dso, machine, offset, | 279 | ret = unwind_spec_ehframe(dso, machine, offset, |
258 | table_data, segbase, | 280 | table_data, segbase, |
259 | fde_count); | 281 | fde_count); |
260 | 282 | ||
261 | return ret; | 283 | return ret; |
262 | } | 284 | } |
263 | 285 | ||
264 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | 286 | #ifndef NO_LIBUNWIND_DEBUG_FRAME |
265 | static int read_unwind_spec_debug_frame(struct dso *dso, | 287 | static int read_unwind_spec_debug_frame(struct dso *dso, |
266 | struct machine *machine, u64 *offset) | 288 | struct machine *machine, u64 *offset) |
267 | { | 289 | { |
268 | int fd = dso__data_fd(dso, machine); | 290 | int fd = dso__data_fd(dso, machine); |
269 | 291 | ||
270 | if (fd < 0) | 292 | if (fd < 0) |
271 | return -EINVAL; | 293 | return -EINVAL; |
272 | 294 | ||
273 | /* Check the .debug_frame section for unwinding info */ | 295 | /* Check the .debug_frame section for unwinding info */ |
274 | *offset = elf_section_offset(fd, ".debug_frame"); | 296 | *offset = elf_section_offset(fd, ".debug_frame"); |
275 | 297 | ||
276 | if (*offset) | 298 | if (*offset) |
277 | return 0; | 299 | return 0; |
278 | 300 | ||
279 | return -EINVAL; | 301 | return -EINVAL; |
280 | } | 302 | } |
281 | #endif | 303 | #endif |
282 | 304 | ||
283 | static struct map *find_map(unw_word_t ip, struct unwind_info *ui) | 305 | static struct map *find_map(unw_word_t ip, struct unwind_info *ui) |
284 | { | 306 | { |
285 | struct addr_location al; | 307 | struct addr_location al; |
286 | 308 | ||
287 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, | 309 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, |
288 | MAP__FUNCTION, ip, &al); | 310 | MAP__FUNCTION, ip, &al); |
289 | return al.map; | 311 | return al.map; |
290 | } | 312 | } |
291 | 313 | ||
292 | static int | 314 | static int |
293 | find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | 315 | find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, |
294 | int need_unwind_info, void *arg) | 316 | int need_unwind_info, void *arg) |
295 | { | 317 | { |
296 | struct unwind_info *ui = arg; | 318 | struct unwind_info *ui = arg; |
297 | struct map *map; | 319 | struct map *map; |
298 | unw_dyn_info_t di; | 320 | unw_dyn_info_t di; |
299 | u64 table_data, segbase, fde_count; | 321 | u64 table_data, segbase, fde_count; |
300 | 322 | ||
301 | map = find_map(ip, ui); | 323 | map = find_map(ip, ui); |
302 | if (!map || !map->dso) | 324 | if (!map || !map->dso) |
303 | return -EINVAL; | 325 | return -EINVAL; |
304 | 326 | ||
305 | pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); | 327 | pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); |
306 | 328 | ||
307 | /* Check the .eh_frame section for unwinding info */ | 329 | /* Check the .eh_frame section for unwinding info */ |
308 | if (!read_unwind_spec_eh_frame(map->dso, ui->machine, | 330 | if (!read_unwind_spec_eh_frame(map->dso, ui->machine, |
309 | &table_data, &segbase, &fde_count)) { | 331 | &table_data, &segbase, &fde_count)) { |
310 | memset(&di, 0, sizeof(di)); | 332 | memset(&di, 0, sizeof(di)); |
311 | di.format = UNW_INFO_FORMAT_REMOTE_TABLE; | 333 | di.format = UNW_INFO_FORMAT_REMOTE_TABLE; |
312 | di.start_ip = map->start; | 334 | di.start_ip = map->start; |
313 | di.end_ip = map->end; | 335 | di.end_ip = map->end; |
314 | di.u.rti.segbase = map->start + segbase; | 336 | di.u.rti.segbase = map->start + segbase; |
315 | di.u.rti.table_data = map->start + table_data; | 337 | di.u.rti.table_data = map->start + table_data; |
316 | di.u.rti.table_len = fde_count * sizeof(struct table_entry) | 338 | di.u.rti.table_len = fde_count * sizeof(struct table_entry) |
317 | / sizeof(unw_word_t); | 339 | / sizeof(unw_word_t); |
318 | return dwarf_search_unwind_table(as, ip, &di, pi, | 340 | return dwarf_search_unwind_table(as, ip, &di, pi, |
319 | need_unwind_info, arg); | 341 | need_unwind_info, arg); |
320 | } | 342 | } |
321 | 343 | ||
322 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | 344 | #ifndef NO_LIBUNWIND_DEBUG_FRAME |
323 | /* Check the .debug_frame section for unwinding info */ | 345 | /* Check the .debug_frame section for unwinding info */ |
324 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | 346 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { |
347 | int fd = dso__data_fd(map->dso, ui->machine); | ||
348 | int is_exec = elf_is_exec(fd, map->dso->name); | ||
349 | unw_word_t base = is_exec ? 0 : map->start; | ||
350 | |||
325 | memset(&di, 0, sizeof(di)); | 351 | memset(&di, 0, sizeof(di)); |
326 | if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, | 352 | if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, |
327 | map->start, map->end)) | 353 | map->start, map->end)) |
328 | return dwarf_search_unwind_table(as, ip, &di, pi, | 354 | return dwarf_search_unwind_table(as, ip, &di, pi, |
329 | need_unwind_info, arg); | 355 | need_unwind_info, arg); |
330 | } | 356 | } |
331 | #endif | 357 | #endif |
332 | 358 | ||
333 | return -EINVAL; | 359 | return -EINVAL; |
334 | } | 360 | } |
335 | 361 | ||
336 | static int access_fpreg(unw_addr_space_t __maybe_unused as, | 362 | static int access_fpreg(unw_addr_space_t __maybe_unused as, |
337 | unw_regnum_t __maybe_unused num, | 363 | unw_regnum_t __maybe_unused num, |
338 | unw_fpreg_t __maybe_unused *val, | 364 | unw_fpreg_t __maybe_unused *val, |
339 | int __maybe_unused __write, | 365 | int __maybe_unused __write, |
340 | void __maybe_unused *arg) | 366 | void __maybe_unused *arg) |
341 | { | 367 | { |
342 | pr_err("unwind: access_fpreg unsupported\n"); | 368 | pr_err("unwind: access_fpreg unsupported\n"); |
343 | return -UNW_EINVAL; | 369 | return -UNW_EINVAL; |
344 | } | 370 | } |
345 | 371 | ||
346 | static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, | 372 | static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, |
347 | unw_word_t __maybe_unused *dil_addr, | 373 | unw_word_t __maybe_unused *dil_addr, |
348 | void __maybe_unused *arg) | 374 | void __maybe_unused *arg) |
349 | { | 375 | { |
350 | return -UNW_ENOINFO; | 376 | return -UNW_ENOINFO; |
351 | } | 377 | } |
352 | 378 | ||
353 | static int resume(unw_addr_space_t __maybe_unused as, | 379 | static int resume(unw_addr_space_t __maybe_unused as, |
354 | unw_cursor_t __maybe_unused *cu, | 380 | unw_cursor_t __maybe_unused *cu, |
355 | void __maybe_unused *arg) | 381 | void __maybe_unused *arg) |
356 | { | 382 | { |
357 | pr_err("unwind: resume unsupported\n"); | 383 | pr_err("unwind: resume unsupported\n"); |
358 | return -UNW_EINVAL; | 384 | return -UNW_EINVAL; |
359 | } | 385 | } |
360 | 386 | ||
361 | static int | 387 | static int |
362 | get_proc_name(unw_addr_space_t __maybe_unused as, | 388 | get_proc_name(unw_addr_space_t __maybe_unused as, |
363 | unw_word_t __maybe_unused addr, | 389 | unw_word_t __maybe_unused addr, |
364 | char __maybe_unused *bufp, size_t __maybe_unused buf_len, | 390 | char __maybe_unused *bufp, size_t __maybe_unused buf_len, |
365 | unw_word_t __maybe_unused *offp, void __maybe_unused *arg) | 391 | unw_word_t __maybe_unused *offp, void __maybe_unused *arg) |
366 | { | 392 | { |
367 | pr_err("unwind: get_proc_name unsupported\n"); | 393 | pr_err("unwind: get_proc_name unsupported\n"); |
368 | return -UNW_EINVAL; | 394 | return -UNW_EINVAL; |
369 | } | 395 | } |
370 | 396 | ||
371 | static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, | 397 | static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, |
372 | unw_word_t *data) | 398 | unw_word_t *data) |
373 | { | 399 | { |
374 | struct addr_location al; | 400 | struct addr_location al; |
375 | ssize_t size; | 401 | ssize_t size; |
376 | 402 | ||
377 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, | 403 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, |
378 | MAP__FUNCTION, addr, &al); | 404 | MAP__FUNCTION, addr, &al); |
379 | if (!al.map) { | 405 | if (!al.map) { |
380 | pr_debug("unwind: no map for %lx\n", (unsigned long)addr); | 406 | pr_debug("unwind: no map for %lx\n", (unsigned long)addr); |
381 | return -1; | 407 | return -1; |
382 | } | 408 | } |
383 | 409 | ||
384 | if (!al.map->dso) | 410 | if (!al.map->dso) |
385 | return -1; | 411 | return -1; |
386 | 412 | ||
387 | size = dso__data_read_addr(al.map->dso, al.map, ui->machine, | 413 | size = dso__data_read_addr(al.map->dso, al.map, ui->machine, |
388 | addr, (u8 *) data, sizeof(*data)); | 414 | addr, (u8 *) data, sizeof(*data)); |
389 | 415 | ||
390 | return !(size == sizeof(*data)); | 416 | return !(size == sizeof(*data)); |
391 | } | 417 | } |
392 | 418 | ||
393 | static int access_mem(unw_addr_space_t __maybe_unused as, | 419 | static int access_mem(unw_addr_space_t __maybe_unused as, |
394 | unw_word_t addr, unw_word_t *valp, | 420 | unw_word_t addr, unw_word_t *valp, |
395 | int __write, void *arg) | 421 | int __write, void *arg) |
396 | { | 422 | { |
397 | struct unwind_info *ui = arg; | 423 | struct unwind_info *ui = arg; |
398 | struct stack_dump *stack = &ui->sample->user_stack; | 424 | struct stack_dump *stack = &ui->sample->user_stack; |
399 | u64 start, end; | 425 | u64 start, end; |
400 | int offset; | 426 | int offset; |
401 | int ret; | 427 | int ret; |
402 | 428 | ||
403 | /* Don't support write, probably not needed. */ | 429 | /* Don't support write, probably not needed. */ |
404 | if (__write || !stack || !ui->sample->user_regs.regs) { | 430 | if (__write || !stack || !ui->sample->user_regs.regs) { |
405 | *valp = 0; | 431 | *valp = 0; |
406 | return 0; | 432 | return 0; |
407 | } | 433 | } |
408 | 434 | ||
409 | ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); | 435 | ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); |
410 | if (ret) | 436 | if (ret) |
411 | return ret; | 437 | return ret; |
412 | 438 | ||
413 | end = start + stack->size; | 439 | end = start + stack->size; |
414 | 440 | ||
415 | /* Check overflow. */ | 441 | /* Check overflow. */ |
416 | if (addr + sizeof(unw_word_t) < addr) | 442 | if (addr + sizeof(unw_word_t) < addr) |
417 | return -EINVAL; | 443 | return -EINVAL; |
418 | 444 | ||
419 | if (addr < start || addr + sizeof(unw_word_t) >= end) { | 445 | if (addr < start || addr + sizeof(unw_word_t) >= end) { |
420 | ret = access_dso_mem(ui, addr, valp); | 446 | ret = access_dso_mem(ui, addr, valp); |
421 | if (ret) { | 447 | if (ret) { |
422 | pr_debug("unwind: access_mem %p not inside range" | 448 | pr_debug("unwind: access_mem %p not inside range" |
423 | " 0x%" PRIx64 "-0x%" PRIx64 "\n", | 449 | " 0x%" PRIx64 "-0x%" PRIx64 "\n", |
424 | (void *) addr, start, end); | 450 | (void *) addr, start, end); |
425 | *valp = 0; | 451 | *valp = 0; |
426 | return ret; | 452 | return ret; |
427 | } | 453 | } |
428 | return 0; | 454 | return 0; |
429 | } | 455 | } |
430 | 456 | ||
431 | offset = addr - start; | 457 | offset = addr - start; |
432 | *valp = *(unw_word_t *)&stack->data[offset]; | 458 | *valp = *(unw_word_t *)&stack->data[offset]; |
433 | pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", | 459 | pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", |
434 | (void *) addr, (unsigned long)*valp, offset); | 460 | (void *) addr, (unsigned long)*valp, offset); |
435 | return 0; | 461 | return 0; |
436 | } | 462 | } |
437 | 463 | ||
438 | static int access_reg(unw_addr_space_t __maybe_unused as, | 464 | static int access_reg(unw_addr_space_t __maybe_unused as, |
439 | unw_regnum_t regnum, unw_word_t *valp, | 465 | unw_regnum_t regnum, unw_word_t *valp, |
440 | int __write, void *arg) | 466 | int __write, void *arg) |
441 | { | 467 | { |
442 | struct unwind_info *ui = arg; | 468 | struct unwind_info *ui = arg; |
443 | int id, ret; | 469 | int id, ret; |
444 | u64 val; | 470 | u64 val; |
445 | 471 | ||
446 | /* Don't support write, I suspect we don't need it. */ | 472 | /* Don't support write, I suspect we don't need it. */ |
447 | if (__write) { | 473 | if (__write) { |
448 | pr_err("unwind: access_reg w %d\n", regnum); | 474 | pr_err("unwind: access_reg w %d\n", regnum); |
449 | return 0; | 475 | return 0; |
450 | } | 476 | } |
451 | 477 | ||
452 | if (!ui->sample->user_regs.regs) { | 478 | if (!ui->sample->user_regs.regs) { |
453 | *valp = 0; | 479 | *valp = 0; |
454 | return 0; | 480 | return 0; |
455 | } | 481 | } |
456 | 482 | ||
457 | id = libunwind__arch_reg_id(regnum); | 483 | id = libunwind__arch_reg_id(regnum); |
458 | if (id < 0) | 484 | if (id < 0) |
459 | return -EINVAL; | 485 | return -EINVAL; |
460 | 486 | ||
461 | ret = perf_reg_value(&val, &ui->sample->user_regs, id); | 487 | ret = perf_reg_value(&val, &ui->sample->user_regs, id); |
462 | if (ret) { | 488 | if (ret) { |
463 | pr_err("unwind: can't read reg %d\n", regnum); | 489 | pr_err("unwind: can't read reg %d\n", regnum); |
464 | return ret; | 490 | return ret; |
465 | } | 491 | } |
466 | 492 | ||
467 | *valp = (unw_word_t) val; | 493 | *valp = (unw_word_t) val; |
468 | pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); | 494 | pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); |
469 | return 0; | 495 | return 0; |
470 | } | 496 | } |
471 | 497 | ||
472 | static void put_unwind_info(unw_addr_space_t __maybe_unused as, | 498 | static void put_unwind_info(unw_addr_space_t __maybe_unused as, |
473 | unw_proc_info_t *pi __maybe_unused, | 499 | unw_proc_info_t *pi __maybe_unused, |
474 | void *arg __maybe_unused) | 500 | void *arg __maybe_unused) |
475 | { | 501 | { |
476 | pr_debug("unwind: put_unwind_info called\n"); | 502 | pr_debug("unwind: put_unwind_info called\n"); |
477 | } | 503 | } |
478 | 504 | ||
479 | static int entry(u64 ip, struct thread *thread, | 505 | static int entry(u64 ip, struct thread *thread, |
480 | unwind_entry_cb_t cb, void *arg) | 506 | unwind_entry_cb_t cb, void *arg) |
481 | { | 507 | { |
482 | struct unwind_entry e; | 508 | struct unwind_entry e; |
483 | struct addr_location al; | 509 | struct addr_location al; |
484 | 510 | ||
485 | thread__find_addr_location(thread, PERF_RECORD_MISC_USER, | 511 | thread__find_addr_location(thread, PERF_RECORD_MISC_USER, |
486 | MAP__FUNCTION, ip, &al); | 512 | MAP__FUNCTION, ip, &al); |
487 | 513 | ||
488 | e.ip = ip; | 514 | e.ip = ip; |
489 | e.map = al.map; | 515 | e.map = al.map; |
490 | e.sym = al.sym; | 516 | e.sym = al.sym; |
491 | 517 | ||
492 | pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", | 518 | pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", |
493 | al.sym ? al.sym->name : "''", | 519 | al.sym ? al.sym->name : "''", |
494 | ip, | 520 | ip, |
495 | al.map ? al.map->map_ip(al.map, ip) : (u64) 0); | 521 | al.map ? al.map->map_ip(al.map, ip) : (u64) 0); |
496 | 522 | ||
497 | return cb(&e, arg); | 523 | return cb(&e, arg); |
498 | } | 524 | } |
499 | 525 | ||
500 | static void display_error(int err) | 526 | static void display_error(int err) |
501 | { | 527 | { |
502 | switch (err) { | 528 | switch (err) { |
503 | case UNW_EINVAL: | 529 | case UNW_EINVAL: |
504 | pr_err("unwind: Only supports local.\n"); | 530 | pr_err("unwind: Only supports local.\n"); |
505 | break; | 531 | break; |
506 | case UNW_EUNSPEC: | 532 | case UNW_EUNSPEC: |
507 | pr_err("unwind: Unspecified error.\n"); | 533 | pr_err("unwind: Unspecified error.\n"); |
508 | break; | 534 | break; |
509 | case UNW_EBADREG: | 535 | case UNW_EBADREG: |
510 | pr_err("unwind: Register unavailable.\n"); | 536 | pr_err("unwind: Register unavailable.\n"); |
511 | break; | 537 | break; |
512 | default: | 538 | default: |
513 | break; | 539 | break; |
514 | } | 540 | } |
515 | } | 541 | } |
516 | 542 | ||
517 | static unw_accessors_t accessors = { | 543 | static unw_accessors_t accessors = { |
518 | .find_proc_info = find_proc_info, | 544 | .find_proc_info = find_proc_info, |
519 | .put_unwind_info = put_unwind_info, | 545 | .put_unwind_info = put_unwind_info, |
520 | .get_dyn_info_list_addr = get_dyn_info_list_addr, | 546 | .get_dyn_info_list_addr = get_dyn_info_list_addr, |
521 | .access_mem = access_mem, | 547 | .access_mem = access_mem, |
522 | .access_reg = access_reg, | 548 | .access_reg = access_reg, |
523 | .access_fpreg = access_fpreg, | 549 | .access_fpreg = access_fpreg, |
524 | .resume = resume, | 550 | .resume = resume, |
525 | .get_proc_name = get_proc_name, | 551 | .get_proc_name = get_proc_name, |
526 | }; | 552 | }; |
527 | 553 | ||
528 | int unwind__prepare_access(struct thread *thread) | 554 | int unwind__prepare_access(struct thread *thread) |
529 | { | 555 | { |
530 | unw_addr_space_t addr_space; | 556 | unw_addr_space_t addr_space; |
531 | 557 | ||
532 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 558 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
533 | return 0; | 559 | return 0; |
534 | 560 | ||
535 | addr_space = unw_create_addr_space(&accessors, 0); | 561 | addr_space = unw_create_addr_space(&accessors, 0); |
536 | if (!addr_space) { | 562 | if (!addr_space) { |
537 | pr_err("unwind: Can't create unwind address space.\n"); | 563 | pr_err("unwind: Can't create unwind address space.\n"); |
538 | return -ENOMEM; | 564 | return -ENOMEM; |
539 | } | 565 | } |
540 | 566 | ||
541 | unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); | 567 | unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); |
542 | thread__set_priv(thread, addr_space); | 568 | thread__set_priv(thread, addr_space); |
543 | 569 | ||
544 | return 0; | 570 | return 0; |
545 | } | 571 | } |
546 | 572 | ||
547 | void unwind__flush_access(struct thread *thread) | 573 | void unwind__flush_access(struct thread *thread) |
548 | { | 574 | { |
549 | unw_addr_space_t addr_space; | 575 | unw_addr_space_t addr_space; |
550 | 576 | ||
551 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 577 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
552 | return; | 578 | return; |
553 | 579 | ||
554 | addr_space = thread__priv(thread); | 580 | addr_space = thread__priv(thread); |
555 | unw_flush_cache(addr_space, 0, 0); | 581 | unw_flush_cache(addr_space, 0, 0); |
556 | } | 582 | } |
557 | 583 | ||
558 | void unwind__finish_access(struct thread *thread) | 584 | void unwind__finish_access(struct thread *thread) |
559 | { | 585 | { |
560 | unw_addr_space_t addr_space; | 586 | unw_addr_space_t addr_space; |
561 | 587 | ||
562 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 588 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
563 | return; | 589 | return; |
564 | 590 | ||
565 | addr_space = thread__priv(thread); | 591 | addr_space = thread__priv(thread); |
566 | unw_destroy_addr_space(addr_space); | 592 | unw_destroy_addr_space(addr_space); |
567 | } | 593 | } |
568 | 594 | ||
569 | static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, | 595 | static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, |
570 | void *arg, int max_stack) | 596 | void *arg, int max_stack) |
571 | { | 597 | { |
572 | unw_addr_space_t addr_space; | 598 | unw_addr_space_t addr_space; |
573 | unw_cursor_t c; | 599 | unw_cursor_t c; |
574 | int ret; | 600 | int ret; |
575 | 601 | ||
576 | addr_space = thread__priv(ui->thread); | 602 | addr_space = thread__priv(ui->thread); |
577 | if (addr_space == NULL) | 603 | if (addr_space == NULL) |
578 | return -1; | 604 | return -1; |
579 | 605 | ||
580 | ret = unw_init_remote(&c, addr_space, ui); | 606 | ret = unw_init_remote(&c, addr_space, ui); |
581 | if (ret) | 607 | if (ret) |
582 | display_error(ret); | 608 | display_error(ret); |
583 | 609 | ||
584 | while (!ret && (unw_step(&c) > 0) && max_stack--) { | 610 | while (!ret && (unw_step(&c) > 0) && max_stack--) { |
585 | unw_word_t ip; | 611 | unw_word_t ip; |
586 | 612 | ||
587 | unw_get_reg(&c, UNW_REG_IP, &ip); | 613 | unw_get_reg(&c, UNW_REG_IP, &ip); |
588 | ret = ip ? entry(ip, ui->thread, cb, arg) : 0; | 614 | ret = ip ? entry(ip, ui->thread, cb, arg) : 0; |
589 | } | 615 | } |
590 | 616 | ||
591 | return ret; | 617 | return ret; |
592 | } | 618 | } |
593 | 619 | ||
594 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | 620 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, |
595 | struct thread *thread, | 621 | struct thread *thread, |
596 | struct perf_sample *data, int max_stack) | 622 | struct perf_sample *data, int max_stack) |
597 | { | 623 | { |
598 | u64 ip; | 624 | u64 ip; |
599 | struct unwind_info ui = { | 625 | struct unwind_info ui = { |
600 | .sample = data, | 626 | .sample = data, |
601 | .thread = thread, | 627 | .thread = thread, |
602 | .machine = thread->mg->machine, | 628 | .machine = thread->mg->machine, |
603 | }; | 629 | }; |
604 | int ret; | 630 | int ret; |
605 | 631 | ||
606 | if (!data->user_regs.regs) | 632 | if (!data->user_regs.regs) |
607 | return -EINVAL; | 633 | return -EINVAL; |
608 | 634 | ||
609 | ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); | 635 | ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); |
610 | if (ret) | 636 | if (ret) |
611 | return ret; | 637 | return ret; |
612 | 638 | ||
613 | ret = entry(ip, thread, cb, arg); | 639 | ret = entry(ip, thread, cb, arg); |
614 | if (ret) | 640 | if (ret) |
615 | return -ENOMEM; | 641 | return -ENOMEM; |
616 | 642 | ||
617 | return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0; | 643 | return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0; |
618 | } | 644 | } |
619 | 645 |