aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorJonathan Corbet <corbet@lwn.net>2016-12-27 14:53:44 -0500
committerJonathan Corbet <corbet@lwn.net>2016-12-27 14:53:44 -0500
commit54ab6db0909061ab7ee07233d3cab86d29f86e6c (patch)
treea7650ab5c0fa3a6a3841de8e8693041b3e009054 /tools/perf/util
parent217e2bfab22e740227df09f22165e834cddd8a3b (diff)
parent7ce7d89f48834cefece7804d38fc5d85382edf77 (diff)
Merge tag 'v4.10-rc1' into docs-next
Linux 4.10-rc1
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/Build7
-rw-r--r--tools/perf/util/annotate.c413
-rw-r--r--tools/perf/util/annotate.h28
-rw-r--r--tools/perf/util/bpf-loader.c33
-rw-r--r--tools/perf/util/c++/Build2
-rw-r--r--tools/perf/util/c++/clang-c.h43
-rw-r--r--tools/perf/util/c++/clang-test.cpp62
-rw-r--r--tools/perf/util/c++/clang.cpp195
-rw-r--r--tools/perf/util/c++/clang.h26
-rw-r--r--tools/perf/util/callchain.c232
-rw-r--r--tools/perf/util/callchain.h29
-rw-r--r--tools/perf/util/config.c20
-rw-r--r--tools/perf/util/config.h4
-rw-r--r--tools/perf/util/event.h3
-rw-r--r--tools/perf/util/evsel.c74
-rw-r--r--tools/perf/util/evsel.h5
-rw-r--r--tools/perf/util/evsel_fprintf.c25
-rw-r--r--tools/perf/util/genelf.c113
-rw-r--r--tools/perf/util/genelf.h5
-rw-r--r--tools/perf/util/header.c19
-rw-r--r--tools/perf/util/hist.c13
-rw-r--r--tools/perf/util/hist.h1
-rw-r--r--tools/perf/util/intel-bts.c9
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c2
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.h1
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c13
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.h6
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-log.c4
-rw-r--r--tools/perf/util/intel-pt.c19
-rw-r--r--tools/perf/util/jitdump.c82
-rw-r--r--tools/perf/util/jitdump.h12
-rw-r--r--tools/perf/util/llvm-utils.c78
-rw-r--r--tools/perf/util/llvm-utils.h6
-rw-r--r--tools/perf/util/machine.c82
-rw-r--r--tools/perf/util/map.c17
-rw-r--r--tools/perf/util/mem-events.c136
-rw-r--r--tools/perf/util/mem-events.h38
-rw-r--r--tools/perf/util/parse-branch-options.c85
-rw-r--r--tools/perf/util/parse-branch-options.h3
-rw-r--r--tools/perf/util/parse-events.c15
-rw-r--r--tools/perf/util/perf-hooks-list.h3
-rw-r--r--tools/perf/util/perf-hooks.c88
-rw-r--r--tools/perf/util/perf-hooks.h39
-rw-r--r--tools/perf/util/pmu.c14
-rw-r--r--tools/perf/util/probe-event.h2
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/quote.c2
-rw-r--r--tools/perf/util/session.c10
-rw-r--r--tools/perf/util/sort.c2
-rw-r--r--tools/perf/util/sort.h1
-rw-r--r--tools/perf/util/string.c21
-rw-r--r--tools/perf/util/symbol.c13
-rw-r--r--tools/perf/util/symbol.h11
-rw-r--r--tools/perf/util/symbol_fprintf.c11
-rw-r--r--tools/perf/util/thread_map.c22
-rw-r--r--tools/perf/util/thread_map.h1
-rw-r--r--tools/perf/util/time-utils.c119
-rw-r--r--tools/perf/util/time-utils.h14
-rw-r--r--tools/perf/util/trace-event-scripting.c39
-rw-r--r--tools/perf/util/unwind-libunwind-local.c4
-rw-r--r--tools/perf/util/util-cxx.h26
-rw-r--r--tools/perf/util/util.c88
-rw-r--r--tools/perf/util/util.h6
-rw-r--r--tools/perf/util/values.c81
-rw-r--r--tools/perf/util/values.h4
65 files changed, 2136 insertions, 446 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index eb60e613d795..3840e3a87057 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -87,6 +87,7 @@ libperf-y += help-unknown-cmd.o
87libperf-y += mem-events.o 87libperf-y += mem-events.o
88libperf-y += vsprintf.o 88libperf-y += vsprintf.o
89libperf-y += drv_configs.o 89libperf-y += drv_configs.o
90libperf-y += time-utils.o
90 91
91libperf-$(CONFIG_LIBBPF) += bpf-loader.o 92libperf-$(CONFIG_LIBBPF) += bpf-loader.o
92libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o 93libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
@@ -120,9 +121,13 @@ libperf-y += demangle-rust.o
120ifdef CONFIG_JITDUMP 121ifdef CONFIG_JITDUMP
121libperf-$(CONFIG_LIBELF) += jitdump.o 122libperf-$(CONFIG_LIBELF) += jitdump.o
122libperf-$(CONFIG_LIBELF) += genelf.o 123libperf-$(CONFIG_LIBELF) += genelf.o
123libperf-$(CONFIG_LIBELF) += genelf_debug.o 124libperf-$(CONFIG_DWARF) += genelf_debug.o
124endif 125endif
125 126
127libperf-y += perf-hooks.o
128
129libperf-$(CONFIG_CXX) += c++/
130
126CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 131CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
127# avoid compiler warnings in 32-bit mode 132# avoid compiler warnings in 32-bit mode
128CFLAGS_genelf_debug.o += -Wno-packed 133CFLAGS_genelf_debug.o += -Wno-packed
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index aeb5a441bd74..06cc04e5806a 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,16 +18,119 @@
18#include "annotate.h" 18#include "annotate.h"
19#include "evsel.h" 19#include "evsel.h"
20#include "block-range.h" 20#include "block-range.h"
21#include "arch/common.h"
21#include <regex.h> 22#include <regex.h>
22#include <pthread.h> 23#include <pthread.h>
23#include <linux/bitops.h> 24#include <linux/bitops.h>
25#include <sys/utsname.h>
24 26
25const char *disassembler_style; 27const char *disassembler_style;
26const char *objdump_path; 28const char *objdump_path;
27static regex_t file_lineno; 29static regex_t file_lineno;
28 30
29static struct ins *ins__find(const char *name); 31static struct ins_ops *ins__find(struct arch *arch, const char *name);
30static int disasm_line__parse(char *line, char **namep, char **rawp); 32static void ins__sort(struct arch *arch);
33static int disasm_line__parse(char *line, const char **namep, char **rawp);
34
35struct arch {
36 const char *name;
37 struct ins *instructions;
38 size_t nr_instructions;
39 size_t nr_instructions_allocated;
40 struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name);
41 bool sorted_instructions;
42 bool initialized;
43 void *priv;
44 int (*init)(struct arch *arch);
45 struct {
46 char comment_char;
47 char skip_functions_char;
48 } objdump;
49};
50
51static struct ins_ops call_ops;
52static struct ins_ops dec_ops;
53static struct ins_ops jump_ops;
54static struct ins_ops mov_ops;
55static struct ins_ops nop_ops;
56static struct ins_ops lock_ops;
57static struct ins_ops ret_ops;
58
59static int arch__grow_instructions(struct arch *arch)
60{
61 struct ins *new_instructions;
62 size_t new_nr_allocated;
63
64 if (arch->nr_instructions_allocated == 0 && arch->instructions)
65 goto grow_from_non_allocated_table;
66
67 new_nr_allocated = arch->nr_instructions_allocated + 128;
68 new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins));
69 if (new_instructions == NULL)
70 return -1;
71
72out_update_instructions:
73 arch->instructions = new_instructions;
74 arch->nr_instructions_allocated = new_nr_allocated;
75 return 0;
76
77grow_from_non_allocated_table:
78 new_nr_allocated = arch->nr_instructions + 128;
79 new_instructions = calloc(new_nr_allocated, sizeof(struct ins));
80 if (new_instructions == NULL)
81 return -1;
82
83 memcpy(new_instructions, arch->instructions, arch->nr_instructions);
84 goto out_update_instructions;
85}
86
87static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops)
88{
89 struct ins *ins;
90
91 if (arch->nr_instructions == arch->nr_instructions_allocated &&
92 arch__grow_instructions(arch))
93 return -1;
94
95 ins = &arch->instructions[arch->nr_instructions];
96 ins->name = strdup(name);
97 if (!ins->name)
98 return -1;
99
100 ins->ops = ops;
101 arch->nr_instructions++;
102
103 ins__sort(arch);
104 return 0;
105}
106
107#include "arch/arm/annotate/instructions.c"
108#include "arch/arm64/annotate/instructions.c"
109#include "arch/x86/annotate/instructions.c"
110#include "arch/powerpc/annotate/instructions.c"
111
112static struct arch architectures[] = {
113 {
114 .name = "arm",
115 .init = arm__annotate_init,
116 },
117 {
118 .name = "arm64",
119 .init = arm64__annotate_init,
120 },
121 {
122 .name = "x86",
123 .instructions = x86__instructions,
124 .nr_instructions = ARRAY_SIZE(x86__instructions),
125 .objdump = {
126 .comment_char = '#',
127 },
128 },
129 {
130 .name = "powerpc",
131 .init = powerpc__annotate_init,
132 },
133};
31 134
32static void ins__delete(struct ins_operands *ops) 135static void ins__delete(struct ins_operands *ops)
33{ 136{
@@ -54,7 +157,7 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size,
54 return ins__raw_scnprintf(ins, bf, size, ops); 157 return ins__raw_scnprintf(ins, bf, size, ops);
55} 158}
56 159
57static int call__parse(struct ins_operands *ops, struct map *map) 160static int call__parse(struct arch *arch, struct ins_operands *ops, struct map *map)
58{ 161{
59 char *endptr, *tok, *name; 162 char *endptr, *tok, *name;
60 163
@@ -66,10 +169,9 @@ static int call__parse(struct ins_operands *ops, struct map *map)
66 169
67 name++; 170 name++;
68 171
69#ifdef __arm__ 172 if (arch->objdump.skip_functions_char &&
70 if (strchr(name, '+')) 173 strchr(name, arch->objdump.skip_functions_char))
71 return -1; 174 return -1;
72#endif
73 175
74 tok = strchr(name, '>'); 176 tok = strchr(name, '>');
75 if (tok == NULL) 177 if (tok == NULL)
@@ -118,16 +220,22 @@ bool ins__is_call(const struct ins *ins)
118 return ins->ops == &call_ops; 220 return ins->ops == &call_ops;
119} 221}
120 222
121static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused) 223static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused)
122{ 224{
123 const char *s = strchr(ops->raw, '+'); 225 const char *s = strchr(ops->raw, '+');
226 const char *c = strchr(ops->raw, ',');
124 227
125 ops->target.addr = strtoull(ops->raw, NULL, 16); 228 if (c++ != NULL)
229 ops->target.addr = strtoull(c, NULL, 16);
230 else
231 ops->target.addr = strtoull(ops->raw, NULL, 16);
126 232
127 if (s++ != NULL) 233 if (s++ != NULL) {
128 ops->target.offset = strtoull(s, NULL, 16); 234 ops->target.offset = strtoull(s, NULL, 16);
129 else 235 ops->target.offset_avail = true;
130 ops->target.offset = UINT64_MAX; 236 } else {
237 ops->target.offset_avail = false;
238 }
131 239
132 return 0; 240 return 0;
133} 241}
@@ -135,6 +243,9 @@ static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused)
135static int jump__scnprintf(struct ins *ins, char *bf, size_t size, 243static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
136 struct ins_operands *ops) 244 struct ins_operands *ops)
137{ 245{
246 if (!ops->target.addr || ops->target.offset < 0)
247 return ins__raw_scnprintf(ins, bf, size, ops);
248
138 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); 249 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
139} 250}
140 251
@@ -173,28 +284,22 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
173 return 0; 284 return 0;
174} 285}
175 286
176static int lock__parse(struct ins_operands *ops, struct map *map) 287static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map)
177{ 288{
178 char *name;
179
180 ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); 289 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
181 if (ops->locked.ops == NULL) 290 if (ops->locked.ops == NULL)
182 return 0; 291 return 0;
183 292
184 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) 293 if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0)
185 goto out_free_ops; 294 goto out_free_ops;
186 295
187 ops->locked.ins = ins__find(name); 296 ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name);
188 free(name);
189 297
190 if (ops->locked.ins == NULL) 298 if (ops->locked.ins.ops == NULL)
191 goto out_free_ops; 299 goto out_free_ops;
192 300
193 if (!ops->locked.ins->ops) 301 if (ops->locked.ins.ops->parse &&
194 return 0; 302 ops->locked.ins.ops->parse(arch, ops->locked.ops, map) < 0)
195
196 if (ops->locked.ins->ops->parse &&
197 ops->locked.ins->ops->parse(ops->locked.ops, map) < 0)
198 goto out_free_ops; 303 goto out_free_ops;
199 304
200 return 0; 305 return 0;
@@ -209,19 +314,19 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
209{ 314{
210 int printed; 315 int printed;
211 316
212 if (ops->locked.ins == NULL) 317 if (ops->locked.ins.ops == NULL)
213 return ins__raw_scnprintf(ins, bf, size, ops); 318 return ins__raw_scnprintf(ins, bf, size, ops);
214 319
215 printed = scnprintf(bf, size, "%-6.6s ", ins->name); 320 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
216 return printed + ins__scnprintf(ops->locked.ins, bf + printed, 321 return printed + ins__scnprintf(&ops->locked.ins, bf + printed,
217 size - printed, ops->locked.ops); 322 size - printed, ops->locked.ops);
218} 323}
219 324
220static void lock__delete(struct ins_operands *ops) 325static void lock__delete(struct ins_operands *ops)
221{ 326{
222 struct ins *ins = ops->locked.ins; 327 struct ins *ins = &ops->locked.ins;
223 328
224 if (ins && ins->ops->free) 329 if (ins->ops && ins->ops->free)
225 ins->ops->free(ops->locked.ops); 330 ins->ops->free(ops->locked.ops);
226 else 331 else
227 ins__delete(ops->locked.ops); 332 ins__delete(ops->locked.ops);
@@ -237,7 +342,7 @@ static struct ins_ops lock_ops = {
237 .scnprintf = lock__scnprintf, 342 .scnprintf = lock__scnprintf,
238}; 343};
239 344
240static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused) 345static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *map __maybe_unused)
241{ 346{
242 char *s = strchr(ops->raw, ','), *target, *comment, prev; 347 char *s = strchr(ops->raw, ','), *target, *comment, prev;
243 348
@@ -252,11 +357,7 @@ static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused)
252 return -1; 357 return -1;
253 358
254 target = ++s; 359 target = ++s;
255#ifdef __arm__ 360 comment = strchr(s, arch->objdump.comment_char);
256 comment = strchr(s, ';');
257#else
258 comment = strchr(s, '#');
259#endif
260 361
261 if (comment != NULL) 362 if (comment != NULL)
262 s = comment - 1; 363 s = comment - 1;
@@ -304,7 +405,7 @@ static struct ins_ops mov_ops = {
304 .scnprintf = mov__scnprintf, 405 .scnprintf = mov__scnprintf,
305}; 406};
306 407
307static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused) 408static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused)
308{ 409{
309 char *target, *comment, *s, prev; 410 char *target, *comment, *s, prev;
310 411
@@ -321,7 +422,7 @@ static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused)
321 if (ops->target.raw == NULL) 422 if (ops->target.raw == NULL)
322 return -1; 423 return -1;
323 424
324 comment = strchr(s, '#'); 425 comment = strchr(s, arch->objdump.comment_char);
325 if (comment == NULL) 426 if (comment == NULL)
326 return 0; 427 return 0;
327 428
@@ -364,99 +465,6 @@ bool ins__is_ret(const struct ins *ins)
364 return ins->ops == &ret_ops; 465 return ins->ops == &ret_ops;
365} 466}
366 467
367static struct ins instructions[] = {
368 { .name = "add", .ops = &mov_ops, },
369 { .name = "addl", .ops = &mov_ops, },
370 { .name = "addq", .ops = &mov_ops, },
371 { .name = "addw", .ops = &mov_ops, },
372 { .name = "and", .ops = &mov_ops, },
373#ifdef __arm__
374 { .name = "b", .ops = &jump_ops, }, // might also be a call
375 { .name = "bcc", .ops = &jump_ops, },
376 { .name = "bcs", .ops = &jump_ops, },
377 { .name = "beq", .ops = &jump_ops, },
378 { .name = "bge", .ops = &jump_ops, },
379 { .name = "bgt", .ops = &jump_ops, },
380 { .name = "bhi", .ops = &jump_ops, },
381 { .name = "bl", .ops = &call_ops, },
382 { .name = "bls", .ops = &jump_ops, },
383 { .name = "blt", .ops = &jump_ops, },
384 { .name = "blx", .ops = &call_ops, },
385 { .name = "bne", .ops = &jump_ops, },
386#endif
387 { .name = "bts", .ops = &mov_ops, },
388 { .name = "call", .ops = &call_ops, },
389 { .name = "callq", .ops = &call_ops, },
390 { .name = "cmp", .ops = &mov_ops, },
391 { .name = "cmpb", .ops = &mov_ops, },
392 { .name = "cmpl", .ops = &mov_ops, },
393 { .name = "cmpq", .ops = &mov_ops, },
394 { .name = "cmpw", .ops = &mov_ops, },
395 { .name = "cmpxch", .ops = &mov_ops, },
396 { .name = "dec", .ops = &dec_ops, },
397 { .name = "decl", .ops = &dec_ops, },
398 { .name = "imul", .ops = &mov_ops, },
399 { .name = "inc", .ops = &dec_ops, },
400 { .name = "incl", .ops = &dec_ops, },
401 { .name = "ja", .ops = &jump_ops, },
402 { .name = "jae", .ops = &jump_ops, },
403 { .name = "jb", .ops = &jump_ops, },
404 { .name = "jbe", .ops = &jump_ops, },
405 { .name = "jc", .ops = &jump_ops, },
406 { .name = "jcxz", .ops = &jump_ops, },
407 { .name = "je", .ops = &jump_ops, },
408 { .name = "jecxz", .ops = &jump_ops, },
409 { .name = "jg", .ops = &jump_ops, },
410 { .name = "jge", .ops = &jump_ops, },
411 { .name = "jl", .ops = &jump_ops, },
412 { .name = "jle", .ops = &jump_ops, },
413 { .name = "jmp", .ops = &jump_ops, },
414 { .name = "jmpq", .ops = &jump_ops, },
415 { .name = "jna", .ops = &jump_ops, },
416 { .name = "jnae", .ops = &jump_ops, },
417 { .name = "jnb", .ops = &jump_ops, },
418 { .name = "jnbe", .ops = &jump_ops, },
419 { .name = "jnc", .ops = &jump_ops, },
420 { .name = "jne", .ops = &jump_ops, },
421 { .name = "jng", .ops = &jump_ops, },
422 { .name = "jnge", .ops = &jump_ops, },
423 { .name = "jnl", .ops = &jump_ops, },
424 { .name = "jnle", .ops = &jump_ops, },
425 { .name = "jno", .ops = &jump_ops, },
426 { .name = "jnp", .ops = &jump_ops, },
427 { .name = "jns", .ops = &jump_ops, },
428 { .name = "jnz", .ops = &jump_ops, },
429 { .name = "jo", .ops = &jump_ops, },
430 { .name = "jp", .ops = &jump_ops, },
431 { .name = "jpe", .ops = &jump_ops, },
432 { .name = "jpo", .ops = &jump_ops, },
433 { .name = "jrcxz", .ops = &jump_ops, },
434 { .name = "js", .ops = &jump_ops, },
435 { .name = "jz", .ops = &jump_ops, },
436 { .name = "lea", .ops = &mov_ops, },
437 { .name = "lock", .ops = &lock_ops, },
438 { .name = "mov", .ops = &mov_ops, },
439 { .name = "movb", .ops = &mov_ops, },
440 { .name = "movdqa",.ops = &mov_ops, },
441 { .name = "movl", .ops = &mov_ops, },
442 { .name = "movq", .ops = &mov_ops, },
443 { .name = "movslq", .ops = &mov_ops, },
444 { .name = "movzbl", .ops = &mov_ops, },
445 { .name = "movzwl", .ops = &mov_ops, },
446 { .name = "nop", .ops = &nop_ops, },
447 { .name = "nopl", .ops = &nop_ops, },
448 { .name = "nopw", .ops = &nop_ops, },
449 { .name = "or", .ops = &mov_ops, },
450 { .name = "orl", .ops = &mov_ops, },
451 { .name = "test", .ops = &mov_ops, },
452 { .name = "testb", .ops = &mov_ops, },
453 { .name = "testl", .ops = &mov_ops, },
454 { .name = "xadd", .ops = &mov_ops, },
455 { .name = "xbeginl", .ops = &jump_ops, },
456 { .name = "xbeginq", .ops = &jump_ops, },
457 { .name = "retq", .ops = &ret_ops, },
458};
459
460static int ins__key_cmp(const void *name, const void *insp) 468static int ins__key_cmp(const void *name, const void *insp)
461{ 469{
462 const struct ins *ins = insp; 470 const struct ins *ins = insp;
@@ -472,24 +480,70 @@ static int ins__cmp(const void *a, const void *b)
472 return strcmp(ia->name, ib->name); 480 return strcmp(ia->name, ib->name);
473} 481}
474 482
475static void ins__sort(void) 483static void ins__sort(struct arch *arch)
476{ 484{
477 const int nmemb = ARRAY_SIZE(instructions); 485 const int nmemb = arch->nr_instructions;
478 486
479 qsort(instructions, nmemb, sizeof(struct ins), ins__cmp); 487 qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
480} 488}
481 489
482static struct ins *ins__find(const char *name) 490static struct ins_ops *__ins__find(struct arch *arch, const char *name)
483{ 491{
484 const int nmemb = ARRAY_SIZE(instructions); 492 struct ins *ins;
493 const int nmemb = arch->nr_instructions;
494
495 if (!arch->sorted_instructions) {
496 ins__sort(arch);
497 arch->sorted_instructions = true;
498 }
499
500 ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp);
501 return ins ? ins->ops : NULL;
502}
503
504static struct ins_ops *ins__find(struct arch *arch, const char *name)
505{
506 struct ins_ops *ops = __ins__find(arch, name);
507
508 if (!ops && arch->associate_instruction_ops)
509 ops = arch->associate_instruction_ops(arch, name);
510
511 return ops;
512}
513
514static int arch__key_cmp(const void *name, const void *archp)
515{
516 const struct arch *arch = archp;
517
518 return strcmp(name, arch->name);
519}
520
521static int arch__cmp(const void *a, const void *b)
522{
523 const struct arch *aa = a;
524 const struct arch *ab = b;
525
526 return strcmp(aa->name, ab->name);
527}
528
529static void arch__sort(void)
530{
531 const int nmemb = ARRAY_SIZE(architectures);
532
533 qsort(architectures, nmemb, sizeof(struct arch), arch__cmp);
534}
535
536static struct arch *arch__find(const char *name)
537{
538 const int nmemb = ARRAY_SIZE(architectures);
485 static bool sorted; 539 static bool sorted;
486 540
487 if (!sorted) { 541 if (!sorted) {
488 ins__sort(); 542 arch__sort();
489 sorted = true; 543 sorted = true;
490 } 544 }
491 545
492 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); 546 return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
493} 547}
494 548
495int symbol__alloc_hist(struct symbol *sym) 549int symbol__alloc_hist(struct symbol *sym)
@@ -593,7 +647,8 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
593 647
594 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 648 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
595 649
596 if (addr < sym->start || addr >= sym->end) { 650 if ((addr < sym->start || addr >= sym->end) &&
651 (addr != sym->end || sym->start != sym->end)) {
597 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", 652 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n",
598 __func__, __LINE__, sym->name, sym->start, addr, sym->end); 653 __func__, __LINE__, sym->name, sym->start, addr, sym->end);
599 return -ERANGE; 654 return -ERANGE;
@@ -709,21 +764,18 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
709 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); 764 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
710} 765}
711 766
712static void disasm_line__init_ins(struct disasm_line *dl, struct map *map) 767static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map)
713{ 768{
714 dl->ins = ins__find(dl->name); 769 dl->ins.ops = ins__find(arch, dl->ins.name);
715
716 if (dl->ins == NULL)
717 return;
718 770
719 if (!dl->ins->ops) 771 if (!dl->ins.ops)
720 return; 772 return;
721 773
722 if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops, map) < 0) 774 if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, map) < 0)
723 dl->ins = NULL; 775 dl->ins.ops = NULL;
724} 776}
725 777
726static int disasm_line__parse(char *line, char **namep, char **rawp) 778static int disasm_line__parse(char *line, const char **namep, char **rawp)
727{ 779{
728 char *name = line, tmp; 780 char *name = line, tmp;
729 781
@@ -756,12 +808,14 @@ static int disasm_line__parse(char *line, char **namep, char **rawp)
756 return 0; 808 return 0;
757 809
758out_free_name: 810out_free_name:
759 zfree(namep); 811 free((void *)namep);
812 *namep = NULL;
760 return -1; 813 return -1;
761} 814}
762 815
763static struct disasm_line *disasm_line__new(s64 offset, char *line, 816static struct disasm_line *disasm_line__new(s64 offset, char *line,
764 size_t privsize, int line_nr, 817 size_t privsize, int line_nr,
818 struct arch *arch,
765 struct map *map) 819 struct map *map)
766{ 820{
767 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); 821 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
@@ -774,10 +828,10 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line,
774 goto out_delete; 828 goto out_delete;
775 829
776 if (offset != -1) { 830 if (offset != -1) {
777 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) 831 if (disasm_line__parse(dl->line, &dl->ins.name, &dl->ops.raw) < 0)
778 goto out_free_line; 832 goto out_free_line;
779 833
780 disasm_line__init_ins(dl, map); 834 disasm_line__init_ins(dl, arch, map);
781 } 835 }
782 } 836 }
783 837
@@ -793,20 +847,21 @@ out_delete:
793void disasm_line__free(struct disasm_line *dl) 847void disasm_line__free(struct disasm_line *dl)
794{ 848{
795 zfree(&dl->line); 849 zfree(&dl->line);
796 zfree(&dl->name); 850 if (dl->ins.ops && dl->ins.ops->free)
797 if (dl->ins && dl->ins->ops->free) 851 dl->ins.ops->free(&dl->ops);
798 dl->ins->ops->free(&dl->ops);
799 else 852 else
800 ins__delete(&dl->ops); 853 ins__delete(&dl->ops);
854 free((void *)dl->ins.name);
855 dl->ins.name = NULL;
801 free(dl); 856 free(dl);
802} 857}
803 858
804int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) 859int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
805{ 860{
806 if (raw || !dl->ins) 861 if (raw || !dl->ins.ops)
807 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw); 862 return scnprintf(bf, size, "%-6.6s %s", dl->ins.name, dl->ops.raw);
808 863
809 return ins__scnprintf(dl->ins, bf, size, &dl->ops); 864 return ins__scnprintf(&dl->ins, bf, size, &dl->ops);
810} 865}
811 866
812static void disasm__add(struct list_head *head, struct disasm_line *line) 867static void disasm__add(struct list_head *head, struct disasm_line *line)
@@ -1087,6 +1142,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
1087 * The ops.raw part will be parsed further according to type of the instruction. 1142 * The ops.raw part will be parsed further according to type of the instruction.
1088 */ 1143 */
1089static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 1144static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1145 struct arch *arch,
1090 FILE *file, size_t privsize, 1146 FILE *file, size_t privsize,
1091 int *line_nr) 1147 int *line_nr)
1092{ 1148{
@@ -1149,19 +1205,21 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1149 parsed_line = tmp2 + 1; 1205 parsed_line = tmp2 + 1;
1150 } 1206 }
1151 1207
1152 dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, map); 1208 dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map);
1153 free(line); 1209 free(line);
1154 (*line_nr)++; 1210 (*line_nr)++;
1155 1211
1156 if (dl == NULL) 1212 if (dl == NULL)
1157 return -1; 1213 return -1;
1158 1214
1159 if (dl->ops.target.offset == UINT64_MAX) 1215 if (!disasm_line__has_offset(dl)) {
1160 dl->ops.target.offset = dl->ops.target.addr - 1216 dl->ops.target.offset = dl->ops.target.addr -
1161 map__rip_2objdump(map, sym->start); 1217 map__rip_2objdump(map, sym->start);
1218 dl->ops.target.offset_avail = true;
1219 }
1162 1220
1163 /* kcore has no symbols, so add the call target name */ 1221 /* kcore has no symbols, so add the call target name */
1164 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { 1222 if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) {
1165 struct addr_map_symbol target = { 1223 struct addr_map_symbol target = {
1166 .map = map, 1224 .map = map,
1167 .addr = dl->ops.target.addr, 1225 .addr = dl->ops.target.addr,
@@ -1191,8 +1249,8 @@ static void delete_last_nop(struct symbol *sym)
1191 while (!list_empty(list)) { 1249 while (!list_empty(list)) {
1192 dl = list_entry(list->prev, struct disasm_line, node); 1250 dl = list_entry(list->prev, struct disasm_line, node);
1193 1251
1194 if (dl->ins && dl->ins->ops) { 1252 if (dl->ins.ops) {
1195 if (dl->ins->ops != &nop_ops) 1253 if (dl->ins.ops != &nop_ops)
1196 return; 1254 return;
1197 } else { 1255 } else {
1198 if (!strstr(dl->line, " nop ") && 1256 if (!strstr(dl->line, " nop ") &&
@@ -1280,10 +1338,23 @@ fallback:
1280 return 0; 1338 return 0;
1281} 1339}
1282 1340
1283int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) 1341static const char *annotate__norm_arch(const char *arch_name)
1342{
1343 struct utsname uts;
1344
1345 if (!arch_name) { /* Assume we are annotating locally. */
1346 if (uname(&uts) < 0)
1347 return NULL;
1348 arch_name = uts.machine;
1349 }
1350 return normalize_arch((char *)arch_name);
1351}
1352
1353int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize)
1284{ 1354{
1285 struct dso *dso = map->dso; 1355 struct dso *dso = map->dso;
1286 char command[PATH_MAX * 2]; 1356 char command[PATH_MAX * 2];
1357 struct arch *arch = NULL;
1287 FILE *file; 1358 FILE *file;
1288 char symfs_filename[PATH_MAX]; 1359 char symfs_filename[PATH_MAX];
1289 struct kcore_extract kce; 1360 struct kcore_extract kce;
@@ -1297,6 +1368,22 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
1297 if (err) 1368 if (err)
1298 return err; 1369 return err;
1299 1370
1371 arch_name = annotate__norm_arch(arch_name);
1372 if (!arch_name)
1373 return -1;
1374
1375 arch = arch__find(arch_name);
1376 if (arch == NULL)
1377 return -ENOTSUP;
1378
1379 if (arch->init) {
1380 err = arch->init(arch);
1381 if (err) {
1382 pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
1383 return err;
1384 }
1385 }
1386
1300 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 1387 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1301 symfs_filename, sym->name, map->unmap_ip(map, sym->start), 1388 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
1302 map->unmap_ip(map, sym->end)); 1389 map->unmap_ip(map, sym->end));
@@ -1395,7 +1482,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
1395 1482
1396 nline = 0; 1483 nline = 0;
1397 while (!feof(file)) { 1484 while (!feof(file)) {
1398 if (symbol__parse_objdump_line(sym, map, file, privsize, 1485 if (symbol__parse_objdump_line(sym, map, arch, file, privsize,
1399 &lineno) < 0) 1486 &lineno) < 0)
1400 break; 1487 break;
1401 nline++; 1488 nline++;
@@ -1764,7 +1851,7 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
1764 if (dl->offset == -1) 1851 if (dl->offset == -1)
1765 return fprintf(fp, "%s\n", dl->line); 1852 return fprintf(fp, "%s\n", dl->line);
1766 1853
1767 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); 1854 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->ins.name);
1768 1855
1769 if (dl->ops.raw[0] != '\0') { 1856 if (dl->ops.raw[0] != '\0') {
1770 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", 1857 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
@@ -1793,7 +1880,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1793 struct rb_root source_line = RB_ROOT; 1880 struct rb_root source_line = RB_ROOT;
1794 u64 len; 1881 u64 len;
1795 1882
1796 if (symbol__disassemble(sym, map, 0) < 0) 1883 if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0) < 0)
1797 return -1; 1884 return -1;
1798 1885
1799 len = symbol__size(sym); 1886 len = symbol__size(sym);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 5bbcec173b82..09776b5af991 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -11,7 +11,12 @@
11#include <linux/rbtree.h> 11#include <linux/rbtree.h>
12#include <pthread.h> 12#include <pthread.h>
13 13
14struct ins; 14struct ins_ops;
15
16struct ins {
17 const char *name;
18 struct ins_ops *ops;
19};
15 20
16struct ins_operands { 21struct ins_operands {
17 char *raw; 22 char *raw;
@@ -19,7 +24,8 @@ struct ins_operands {
19 char *raw; 24 char *raw;
20 char *name; 25 char *name;
21 u64 addr; 26 u64 addr;
22 u64 offset; 27 s64 offset;
28 bool offset_avail;
23 } target; 29 } target;
24 union { 30 union {
25 struct { 31 struct {
@@ -28,24 +34,21 @@ struct ins_operands {
28 u64 addr; 34 u64 addr;
29 } source; 35 } source;
30 struct { 36 struct {
31 struct ins *ins; 37 struct ins ins;
32 struct ins_operands *ops; 38 struct ins_operands *ops;
33 } locked; 39 } locked;
34 }; 40 };
35}; 41};
36 42
43struct arch;
44
37struct ins_ops { 45struct ins_ops {
38 void (*free)(struct ins_operands *ops); 46 void (*free)(struct ins_operands *ops);
39 int (*parse)(struct ins_operands *ops, struct map *map); 47 int (*parse)(struct arch *arch, struct ins_operands *ops, struct map *map);
40 int (*scnprintf)(struct ins *ins, char *bf, size_t size, 48 int (*scnprintf)(struct ins *ins, char *bf, size_t size,
41 struct ins_operands *ops); 49 struct ins_operands *ops);
42}; 50};
43 51
44struct ins {
45 const char *name;
46 struct ins_ops *ops;
47};
48
49bool ins__is_jump(const struct ins *ins); 52bool ins__is_jump(const struct ins *ins);
50bool ins__is_call(const struct ins *ins); 53bool ins__is_call(const struct ins *ins);
51bool ins__is_ret(const struct ins *ins); 54bool ins__is_ret(const struct ins *ins);
@@ -57,8 +60,7 @@ struct disasm_line {
57 struct list_head node; 60 struct list_head node;
58 s64 offset; 61 s64 offset;
59 char *line; 62 char *line;
60 char *name; 63 struct ins ins;
61 struct ins *ins;
62 int line_nr; 64 int line_nr;
63 float ipc; 65 float ipc;
64 u64 cycles; 66 u64 cycles;
@@ -67,7 +69,7 @@ struct disasm_line {
67 69
68static inline bool disasm_line__has_offset(const struct disasm_line *dl) 70static inline bool disasm_line__has_offset(const struct disasm_line *dl)
69{ 71{
70 return dl->ops.target.offset != UINT64_MAX; 72 return dl->ops.target.offset_avail;
71} 73}
72 74
73void disasm_line__free(struct disasm_line *dl); 75void disasm_line__free(struct disasm_line *dl);
@@ -156,7 +158,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
156int symbol__alloc_hist(struct symbol *sym); 158int symbol__alloc_hist(struct symbol *sym);
157void symbol__annotate_zero_histograms(struct symbol *sym); 159void symbol__annotate_zero_histograms(struct symbol *sym);
158 160
159int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize); 161int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize);
160 162
161enum symbol_disassemble_errno { 163enum symbol_disassemble_errno {
162 SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, 164 SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0,
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 2b2c9b82f5ab..36c861103291 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -14,11 +14,11 @@
14#include "debug.h" 14#include "debug.h"
15#include "bpf-loader.h" 15#include "bpf-loader.h"
16#include "bpf-prologue.h" 16#include "bpf-prologue.h"
17#include "llvm-utils.h"
18#include "probe-event.h" 17#include "probe-event.h"
19#include "probe-finder.h" // for MAX_PROBES 18#include "probe-finder.h" // for MAX_PROBES
20#include "parse-events.h" 19#include "parse-events.h"
21#include "llvm-utils.h" 20#include "llvm-utils.h"
21#include "c++/clang-c.h"
22 22
23#define DEFINE_PRINT_FN(name, level) \ 23#define DEFINE_PRINT_FN(name, level) \
24static int libbpf_##name(const char *fmt, ...) \ 24static int libbpf_##name(const char *fmt, ...) \
@@ -86,10 +86,21 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
86 void *obj_buf; 86 void *obj_buf;
87 size_t obj_buf_sz; 87 size_t obj_buf_sz;
88 88
89 err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); 89 perf_clang__init();
90 if (err) 90 err = perf_clang__compile_bpf(filename, &obj_buf, &obj_buf_sz);
91 return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); 91 perf_clang__cleanup();
92 if (err) {
93 pr_warning("bpf: builtin compilation failed: %d, try external compiler\n", err);
94 err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
95 if (err)
96 return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
97 } else
98 pr_debug("bpf: successfull builtin compilation\n");
92 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); 99 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
100
101 if (!IS_ERR(obj) && llvm_param.dump_obj)
102 llvm__dump_obj(filename, obj_buf, obj_buf_sz);
103
93 free(obj_buf); 104 free(obj_buf);
94 } else 105 } else
95 obj = bpf_object__open(filename); 106 obj = bpf_object__open(filename);
@@ -241,7 +252,7 @@ parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev)
241 int err = 0; 252 int err = 0;
242 253
243 if (!text) { 254 if (!text) {
244 pr_debug("No enough memory: dup config_str failed\n"); 255 pr_debug("Not enough memory: dup config_str failed\n");
245 return ERR_PTR(-ENOMEM); 256 return ERR_PTR(-ENOMEM);
246 } 257 }
247 258
@@ -531,7 +542,7 @@ static int map_prologue(struct perf_probe_event *pev, int *mapping,
531 542
532 ptevs = malloc(array_sz); 543 ptevs = malloc(array_sz);
533 if (!ptevs) { 544 if (!ptevs) {
534 pr_debug("No enough memory: alloc ptevs failed\n"); 545 pr_debug("Not enough memory: alloc ptevs failed\n");
535 return -ENOMEM; 546 return -ENOMEM;
536 } 547 }
537 548
@@ -604,13 +615,13 @@ static int hook_load_preprocessor(struct bpf_program *prog)
604 priv->need_prologue = true; 615 priv->need_prologue = true;
605 priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS); 616 priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS);
606 if (!priv->insns_buf) { 617 if (!priv->insns_buf) {
607 pr_debug("No enough memory: alloc insns_buf failed\n"); 618 pr_debug("Not enough memory: alloc insns_buf failed\n");
608 return -ENOMEM; 619 return -ENOMEM;
609 } 620 }
610 621
611 priv->type_mapping = malloc(sizeof(int) * pev->ntevs); 622 priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
612 if (!priv->type_mapping) { 623 if (!priv->type_mapping) {
613 pr_debug("No enough memory: alloc type_mapping failed\n"); 624 pr_debug("Not enough memory: alloc type_mapping failed\n");
614 return -ENOMEM; 625 return -ENOMEM;
615 } 626 }
616 memset(priv->type_mapping, -1, 627 memset(priv->type_mapping, -1,
@@ -864,7 +875,7 @@ bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term)
864 875
865 op->k.array.ranges = memdup(term->array.ranges, memsz); 876 op->k.array.ranges = memdup(term->array.ranges, memsz);
866 if (!op->k.array.ranges) { 877 if (!op->k.array.ranges) {
867 pr_debug("No enough memory to alloc indices for map\n"); 878 pr_debug("Not enough memory to alloc indices for map\n");
868 return -ENOMEM; 879 return -ENOMEM;
869 } 880 }
870 op->key_type = BPF_MAP_KEY_RANGES; 881 op->key_type = BPF_MAP_KEY_RANGES;
@@ -929,7 +940,7 @@ bpf_map_priv__clone(struct bpf_map_priv *priv)
929 940
930 newpriv = zalloc(sizeof(*newpriv)); 941 newpriv = zalloc(sizeof(*newpriv));
931 if (!newpriv) { 942 if (!newpriv) {
932 pr_debug("No enough memory to alloc map private\n"); 943 pr_debug("Not enough memory to alloc map private\n");
933 return NULL; 944 return NULL;
934 } 945 }
935 INIT_LIST_HEAD(&newpriv->ops_list); 946 INIT_LIST_HEAD(&newpriv->ops_list);
@@ -960,7 +971,7 @@ bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op)
960 if (!priv) { 971 if (!priv) {
961 priv = zalloc(sizeof(*priv)); 972 priv = zalloc(sizeof(*priv));
962 if (!priv) { 973 if (!priv) {
963 pr_debug("No enough memory to alloc map private\n"); 974 pr_debug("Not enough memory to alloc map private\n");
964 return -ENOMEM; 975 return -ENOMEM;
965 } 976 }
966 INIT_LIST_HEAD(&priv->ops_list); 977 INIT_LIST_HEAD(&priv->ops_list);
diff --git a/tools/perf/util/c++/Build b/tools/perf/util/c++/Build
new file mode 100644
index 000000000000..988fef1b11d7
--- /dev/null
+++ b/tools/perf/util/c++/Build
@@ -0,0 +1,2 @@
1libperf-$(CONFIG_CLANGLLVM) += clang.o
2libperf-$(CONFIG_CLANGLLVM) += clang-test.o
diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h
new file mode 100644
index 000000000000..0eadd792ab1f
--- /dev/null
+++ b/tools/perf/util/c++/clang-c.h
@@ -0,0 +1,43 @@
1#ifndef PERF_UTIL_CLANG_C_H
2#define PERF_UTIL_CLANG_C_H
3
4#include <stddef.h> /* for size_t */
5#include <util-cxx.h> /* for __maybe_unused */
6
7#ifdef __cplusplus
8extern "C" {
9#endif
10
11#ifdef HAVE_LIBCLANGLLVM_SUPPORT
12extern void perf_clang__init(void);
13extern void perf_clang__cleanup(void);
14
15extern int test__clang_to_IR(void);
16extern int test__clang_to_obj(void);
17
18extern int perf_clang__compile_bpf(const char *filename,
19 void **p_obj_buf,
20 size_t *p_obj_buf_sz);
21#else
22
23
24static inline void perf_clang__init(void) { }
25static inline void perf_clang__cleanup(void) { }
26
27static inline int test__clang_to_IR(void) { return -1; }
28static inline int test__clang_to_obj(void) { return -1;}
29
30static inline int
31perf_clang__compile_bpf(const char *filename __maybe_unused,
32 void **p_obj_buf __maybe_unused,
33 size_t *p_obj_buf_sz __maybe_unused)
34{
35 return -ENOTSUP;
36}
37
38#endif
39
40#ifdef __cplusplus
41}
42#endif
43#endif
diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp
new file mode 100644
index 000000000000..9b11e8c82798
--- /dev/null
+++ b/tools/perf/util/c++/clang-test.cpp
@@ -0,0 +1,62 @@
1#include "clang.h"
2#include "clang-c.h"
3#include "llvm/IR/Function.h"
4#include "llvm/IR/LLVMContext.h"
5
6#include <util-cxx.h>
7#include <tests/llvm.h>
8#include <string>
9
10class perf_clang_scope {
11public:
12 explicit perf_clang_scope() {perf_clang__init();}
13 ~perf_clang_scope() {perf_clang__cleanup();}
14};
15
16static std::unique_ptr<llvm::Module>
17__test__clang_to_IR(void)
18{
19 unsigned int kernel_version;
20
21 if (fetch_kernel_version(&kernel_version, NULL, 0))
22 return std::unique_ptr<llvm::Module>(nullptr);
23
24 std::string cflag_kver("-DLINUX_VERSION_CODE=" +
25 std::to_string(kernel_version));
26
27 std::unique_ptr<llvm::Module> M =
28 perf::getModuleFromSource({cflag_kver.c_str()},
29 "perf-test.c",
30 test_llvm__bpf_base_prog);
31 return M;
32}
33
34extern "C" {
35int test__clang_to_IR(void)
36{
37 perf_clang_scope _scope;
38
39 auto M = __test__clang_to_IR();
40 if (!M)
41 return -1;
42 for (llvm::Function& F : *M)
43 if (F.getName() == "bpf_func__SyS_epoll_wait")
44 return 0;
45 return -1;
46}
47
48int test__clang_to_obj(void)
49{
50 perf_clang_scope _scope;
51
52 auto M = __test__clang_to_IR();
53 if (!M)
54 return -1;
55
56 auto Buffer = perf::getBPFObjectFromModule(&*M);
57 if (!Buffer)
58 return -1;
59 return 0;
60}
61
62}
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp
new file mode 100644
index 000000000000..1e974152cac2
--- /dev/null
+++ b/tools/perf/util/c++/clang.cpp
@@ -0,0 +1,195 @@
1/*
2 * llvm C frontend for perf. Support dynamically compile C file
3 *
4 * Inspired by clang example code:
5 * http://llvm.org/svn/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp
6 *
7 * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com>
8 * Copyright (C) 2016 Huawei Inc.
9 */
10
11#include "clang/CodeGen/CodeGenAction.h"
12#include "clang/Frontend/CompilerInvocation.h"
13#include "clang/Frontend/CompilerInstance.h"
14#include "clang/Frontend/TextDiagnosticPrinter.h"
15#include "clang/Tooling/Tooling.h"
16#include "llvm/IR/LegacyPassManager.h"
17#include "llvm/IR/Module.h"
18#include "llvm/Option/Option.h"
19#include "llvm/Support/FileSystem.h"
20#include "llvm/Support/ManagedStatic.h"
21#include "llvm/Support/TargetRegistry.h"
22#include "llvm/Support/TargetSelect.h"
23#include "llvm/Target/TargetMachine.h"
24#include "llvm/Target/TargetOptions.h"
25#include <memory>
26
27#include "clang.h"
28#include "clang-c.h"
29
30namespace perf {
31
32static std::unique_ptr<llvm::LLVMContext> LLVMCtx;
33
34using namespace clang;
35
36static CompilerInvocation *
37createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path,
38 DiagnosticsEngine& Diags)
39{
40 llvm::opt::ArgStringList CCArgs {
41 "-cc1",
42 "-triple", "bpf-pc-linux",
43 "-fsyntax-only",
44 "-ferror-limit", "19",
45 "-fmessage-length", "127",
46 "-O2",
47 "-nostdsysteminc",
48 "-nobuiltininc",
49 "-vectorize-loops",
50 "-vectorize-slp",
51 "-Wno-unused-value",
52 "-Wno-pointer-sign",
53 "-x", "c"};
54
55 CCArgs.append(CFlags.begin(), CFlags.end());
56 CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs);
57
58 FrontendOptions& Opts = CI->getFrontendOpts();
59 Opts.Inputs.clear();
60 Opts.Inputs.emplace_back(Path, IK_C);
61 return CI;
62}
63
64static std::unique_ptr<llvm::Module>
65getModuleFromSource(llvm::opt::ArgStringList CFlags,
66 StringRef Path, IntrusiveRefCntPtr<vfs::FileSystem> VFS)
67{
68 CompilerInstance Clang;
69 Clang.createDiagnostics();
70
71 Clang.setVirtualFileSystem(&*VFS);
72
73 IntrusiveRefCntPtr<CompilerInvocation> CI =
74 createCompilerInvocation(std::move(CFlags), Path,
75 Clang.getDiagnostics());
76 Clang.setInvocation(&*CI);
77
78 std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx));
79 if (!Clang.ExecuteAction(*Act))
80 return std::unique_ptr<llvm::Module>(nullptr);
81
82 return Act->takeModule();
83}
84
85std::unique_ptr<llvm::Module>
86getModuleFromSource(llvm::opt::ArgStringList CFlags,
87 StringRef Name, StringRef Content)
88{
89 using namespace vfs;
90
91 llvm::IntrusiveRefCntPtr<OverlayFileSystem> OverlayFS(
92 new OverlayFileSystem(getRealFileSystem()));
93 llvm::IntrusiveRefCntPtr<InMemoryFileSystem> MemFS(
94 new InMemoryFileSystem(true));
95
96 /*
97 * pushOverlay helps setting working dir for MemFS. Must call
98 * before addFile.
99 */
100 OverlayFS->pushOverlay(MemFS);
101 MemFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content));
102
103 return getModuleFromSource(std::move(CFlags), Name, OverlayFS);
104}
105
106std::unique_ptr<llvm::Module>
107getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path)
108{
109 IntrusiveRefCntPtr<vfs::FileSystem> VFS(vfs::getRealFileSystem());
110 return getModuleFromSource(std::move(CFlags), Path, VFS);
111}
112
113std::unique_ptr<llvm::SmallVectorImpl<char>>
114getBPFObjectFromModule(llvm::Module *Module)
115{
116 using namespace llvm;
117
118 std::string TargetTriple("bpf-pc-linux");
119 std::string Error;
120 const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error);
121 if (!Target) {
122 llvm::errs() << Error;
123 return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
124 }
125
126 llvm::TargetOptions Opt;
127 TargetMachine *TargetMachine =
128 Target->createTargetMachine(TargetTriple,
129 "generic", "",
130 Opt, Reloc::Static);
131
132 Module->setDataLayout(TargetMachine->createDataLayout());
133 Module->setTargetTriple(TargetTriple);
134
135 std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>());
136 raw_svector_ostream ostream(*Buffer);
137
138 legacy::PassManager PM;
139 if (TargetMachine->addPassesToEmitFile(PM, ostream,
140 TargetMachine::CGFT_ObjectFile)) {
141 llvm::errs() << "TargetMachine can't emit a file of this type\n";
142 return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);;
143 }
144 PM.run(*Module);
145
146 return std::move(Buffer);
147}
148
149}
150
151extern "C" {
152void perf_clang__init(void)
153{
154 perf::LLVMCtx.reset(new llvm::LLVMContext());
155 LLVMInitializeBPFTargetInfo();
156 LLVMInitializeBPFTarget();
157 LLVMInitializeBPFTargetMC();
158 LLVMInitializeBPFAsmPrinter();
159}
160
161void perf_clang__cleanup(void)
162{
163 perf::LLVMCtx.reset(nullptr);
164 llvm::llvm_shutdown();
165}
166
167int perf_clang__compile_bpf(const char *filename,
168 void **p_obj_buf,
169 size_t *p_obj_buf_sz)
170{
171 using namespace perf;
172
173 if (!p_obj_buf || !p_obj_buf_sz)
174 return -EINVAL;
175
176 llvm::opt::ArgStringList CFlags;
177 auto M = getModuleFromSource(std::move(CFlags), filename);
178 if (!M)
179 return -EINVAL;
180 auto O = getBPFObjectFromModule(&*M);
181 if (!O)
182 return -EINVAL;
183
184 size_t size = O->size_in_bytes();
185 void *buffer;
186
187 buffer = malloc(size);
188 if (!buffer)
189 return -ENOMEM;
190 memcpy(buffer, O->data(), size);
191 *p_obj_buf = buffer;
192 *p_obj_buf_sz = size;
193 return 0;
194}
195}
diff --git a/tools/perf/util/c++/clang.h b/tools/perf/util/c++/clang.h
new file mode 100644
index 000000000000..dd8b0427550d
--- /dev/null
+++ b/tools/perf/util/c++/clang.h
@@ -0,0 +1,26 @@
1#ifndef PERF_UTIL_CLANG_H
2#define PERF_UTIL_CLANG_H
3
4#include "llvm/ADT/StringRef.h"
5#include "llvm/IR/LLVMContext.h"
6#include "llvm/IR/Module.h"
7#include "llvm/Option/Option.h"
8#include <memory>
9
10namespace perf {
11
12using namespace llvm;
13
14std::unique_ptr<Module>
15getModuleFromSource(opt::ArgStringList CFlags,
16 StringRef Name, StringRef Content);
17
18std::unique_ptr<Module>
19getModuleFromSource(opt::ArgStringList CFlags,
20 StringRef Path);
21
22std::unique_ptr<llvm::SmallVectorImpl<char>>
23getBPFObjectFromModule(llvm::Module *Module);
24
25}
26#endif
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 07fd30bc2f81..42922512c1c6 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -193,7 +193,6 @@ int perf_callchain_config(const char *var, const char *value)
193 193
194 if (!strcmp(var, "record-mode")) 194 if (!strcmp(var, "record-mode"))
195 return parse_callchain_record_opt(value, &callchain_param); 195 return parse_callchain_record_opt(value, &callchain_param);
196#ifdef HAVE_DWARF_UNWIND_SUPPORT
197 if (!strcmp(var, "dump-size")) { 196 if (!strcmp(var, "dump-size")) {
198 unsigned long size = 0; 197 unsigned long size = 0;
199 int ret; 198 int ret;
@@ -203,7 +202,6 @@ int perf_callchain_config(const char *var, const char *value)
203 202
204 return ret; 203 return ret;
205 } 204 }
206#endif
207 if (!strcmp(var, "print-type")) 205 if (!strcmp(var, "print-type"))
208 return parse_callchain_mode(value); 206 return parse_callchain_mode(value);
209 if (!strcmp(var, "order")) 207 if (!strcmp(var, "order"))
@@ -440,6 +438,21 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
440 call->ip = cursor_node->ip; 438 call->ip = cursor_node->ip;
441 call->ms.sym = cursor_node->sym; 439 call->ms.sym = cursor_node->sym;
442 call->ms.map = cursor_node->map; 440 call->ms.map = cursor_node->map;
441
442 if (cursor_node->branch) {
443 call->branch_count = 1;
444
445 if (cursor_node->branch_flags.predicted)
446 call->predicted_count = 1;
447
448 if (cursor_node->branch_flags.abort)
449 call->abort_count = 1;
450
451 call->cycles_count = cursor_node->branch_flags.cycles;
452 call->iter_count = cursor_node->nr_loop_iter;
453 call->samples_count = cursor_node->samples;
454 }
455
443 list_add_tail(&call->list, &node->val); 456 list_add_tail(&call->list, &node->val);
444 457
445 callchain_cursor_advance(cursor); 458 callchain_cursor_advance(cursor);
@@ -499,8 +512,23 @@ static enum match_result match_chain(struct callchain_cursor_node *node,
499 right = node->ip; 512 right = node->ip;
500 } 513 }
501 514
502 if (left == right) 515 if (left == right) {
516 if (node->branch) {
517 cnode->branch_count++;
518
519 if (node->branch_flags.predicted)
520 cnode->predicted_count++;
521
522 if (node->branch_flags.abort)
523 cnode->abort_count++;
524
525 cnode->cycles_count += node->branch_flags.cycles;
526 cnode->iter_count += node->nr_loop_iter;
527 cnode->samples_count += node->samples;
528 }
529
503 return MATCH_EQ; 530 return MATCH_EQ;
531 }
504 532
505 return left > right ? MATCH_GT : MATCH_LT; 533 return left > right ? MATCH_GT : MATCH_LT;
506} 534}
@@ -730,7 +758,8 @@ merge_chain_branch(struct callchain_cursor *cursor,
730 758
731 list_for_each_entry_safe(list, next_list, &src->val, list) { 759 list_for_each_entry_safe(list, next_list, &src->val, list) {
732 callchain_cursor_append(cursor, list->ip, 760 callchain_cursor_append(cursor, list->ip,
733 list->ms.map, list->ms.sym); 761 list->ms.map, list->ms.sym,
762 false, NULL, 0, 0);
734 list_del(&list->list); 763 list_del(&list->list);
735 free(list); 764 free(list);
736 } 765 }
@@ -767,7 +796,9 @@ int callchain_merge(struct callchain_cursor *cursor,
767} 796}
768 797
769int callchain_cursor_append(struct callchain_cursor *cursor, 798int callchain_cursor_append(struct callchain_cursor *cursor,
770 u64 ip, struct map *map, struct symbol *sym) 799 u64 ip, struct map *map, struct symbol *sym,
800 bool branch, struct branch_flags *flags,
801 int nr_loop_iter, int samples)
771{ 802{
772 struct callchain_cursor_node *node = *cursor->last; 803 struct callchain_cursor_node *node = *cursor->last;
773 804
@@ -782,6 +813,13 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
782 node->ip = ip; 813 node->ip = ip;
783 node->map = map; 814 node->map = map;
784 node->sym = sym; 815 node->sym = sym;
816 node->branch = branch;
817 node->nr_loop_iter = nr_loop_iter;
818 node->samples = samples;
819
820 if (flags)
821 memcpy(&node->branch_flags, flags,
822 sizeof(struct branch_flags));
785 823
786 cursor->nr++; 824 cursor->nr++;
787 825
@@ -939,6 +977,163 @@ int callchain_node__fprintf_value(struct callchain_node *node,
939 return 0; 977 return 0;
940} 978}
941 979
980static void callchain_counts_value(struct callchain_node *node,
981 u64 *branch_count, u64 *predicted_count,
982 u64 *abort_count, u64 *cycles_count)
983{
984 struct callchain_list *clist;
985
986 list_for_each_entry(clist, &node->val, list) {
987 if (branch_count)
988 *branch_count += clist->branch_count;
989
990 if (predicted_count)
991 *predicted_count += clist->predicted_count;
992
993 if (abort_count)
994 *abort_count += clist->abort_count;
995
996 if (cycles_count)
997 *cycles_count += clist->cycles_count;
998 }
999}
1000
1001static int callchain_node_branch_counts_cumul(struct callchain_node *node,
1002 u64 *branch_count,
1003 u64 *predicted_count,
1004 u64 *abort_count,
1005 u64 *cycles_count)
1006{
1007 struct callchain_node *child;
1008 struct rb_node *n;
1009
1010 n = rb_first(&node->rb_root_in);
1011 while (n) {
1012 child = rb_entry(n, struct callchain_node, rb_node_in);
1013 n = rb_next(n);
1014
1015 callchain_node_branch_counts_cumul(child, branch_count,
1016 predicted_count,
1017 abort_count,
1018 cycles_count);
1019
1020 callchain_counts_value(child, branch_count,
1021 predicted_count, abort_count,
1022 cycles_count);
1023 }
1024
1025 return 0;
1026}
1027
1028int callchain_branch_counts(struct callchain_root *root,
1029 u64 *branch_count, u64 *predicted_count,
1030 u64 *abort_count, u64 *cycles_count)
1031{
1032 if (branch_count)
1033 *branch_count = 0;
1034
1035 if (predicted_count)
1036 *predicted_count = 0;
1037
1038 if (abort_count)
1039 *abort_count = 0;
1040
1041 if (cycles_count)
1042 *cycles_count = 0;
1043
1044 return callchain_node_branch_counts_cumul(&root->node,
1045 branch_count,
1046 predicted_count,
1047 abort_count,
1048 cycles_count);
1049}
1050
1051static int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
1052 u64 branch_count, u64 predicted_count,
1053 u64 abort_count, u64 cycles_count,
1054 u64 iter_count, u64 samples_count)
1055{
1056 double predicted_percent = 0.0;
1057 const char *null_str = "";
1058 char iter_str[32];
1059 char *str;
1060 u64 cycles = 0;
1061
1062 if (branch_count == 0) {
1063 if (fp)
1064 return fprintf(fp, " (calltrace)");
1065
1066 return scnprintf(bf, bfsize, " (calltrace)");
1067 }
1068
1069 if (iter_count && samples_count) {
1070 scnprintf(iter_str, sizeof(iter_str),
1071 ", iterations:%" PRId64 "",
1072 iter_count / samples_count);
1073 str = iter_str;
1074 } else
1075 str = (char *)null_str;
1076
1077 predicted_percent = predicted_count * 100.0 / branch_count;
1078 cycles = cycles_count / branch_count;
1079
1080 if ((predicted_percent >= 100.0) && (abort_count == 0)) {
1081 if (fp)
1082 return fprintf(fp, " (cycles:%" PRId64 "%s)",
1083 cycles, str);
1084
1085 return scnprintf(bf, bfsize, " (cycles:%" PRId64 "%s)",
1086 cycles, str);
1087 }
1088
1089 if ((predicted_percent < 100.0) && (abort_count == 0)) {
1090 if (fp)
1091 return fprintf(fp,
1092 " (predicted:%.1f%%, cycles:%" PRId64 "%s)",
1093 predicted_percent, cycles, str);
1094
1095 return scnprintf(bf, bfsize,
1096 " (predicted:%.1f%%, cycles:%" PRId64 "%s)",
1097 predicted_percent, cycles, str);
1098 }
1099
1100 if (fp)
1101 return fprintf(fp,
1102 " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
1103 predicted_percent, abort_count, cycles, str);
1104
1105 return scnprintf(bf, bfsize,
1106 " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
1107 predicted_percent, abort_count, cycles, str);
1108}
1109
1110int callchain_list_counts__printf_value(struct callchain_node *node,
1111 struct callchain_list *clist,
1112 FILE *fp, char *bf, int bfsize)
1113{
1114 u64 branch_count, predicted_count;
1115 u64 abort_count, cycles_count;
1116 u64 iter_count = 0, samples_count = 0;
1117
1118 branch_count = clist->branch_count;
1119 predicted_count = clist->predicted_count;
1120 abort_count = clist->abort_count;
1121 cycles_count = clist->cycles_count;
1122
1123 if (node) {
1124 struct callchain_list *call;
1125
1126 list_for_each_entry(call, &node->val, list) {
1127 iter_count += call->iter_count;
1128 samples_count += call->samples_count;
1129 }
1130 }
1131
1132 return callchain_counts_printf(fp, bf, bfsize, branch_count,
1133 predicted_count, abort_count,
1134 cycles_count, iter_count, samples_count);
1135}
1136
942static void free_callchain_node(struct callchain_node *node) 1137static void free_callchain_node(struct callchain_node *node)
943{ 1138{
944 struct callchain_list *list, *tmp; 1139 struct callchain_list *list, *tmp;
@@ -1039,3 +1234,30 @@ out:
1039 } 1234 }
1040 return -ENOMEM; 1235 return -ENOMEM;
1041} 1236}
1237
1238int callchain_cursor__copy(struct callchain_cursor *dst,
1239 struct callchain_cursor *src)
1240{
1241 int rc = 0;
1242
1243 callchain_cursor_reset(dst);
1244 callchain_cursor_commit(src);
1245
1246 while (true) {
1247 struct callchain_cursor_node *node;
1248
1249 node = callchain_cursor_current(src);
1250 if (node == NULL)
1251 break;
1252
1253 rc = callchain_cursor_append(dst, node->ip, node->map, node->sym,
1254 node->branch, &node->branch_flags,
1255 node->nr_loop_iter, node->samples);
1256 if (rc)
1257 break;
1258
1259 callchain_cursor_advance(src);
1260 }
1261
1262 return rc;
1263}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 13e75549c440..35c8e379530f 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -11,11 +11,7 @@
11 11
12#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace):\n\n" 12#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace):\n\n"
13 13
14#ifdef HAVE_DWARF_UNWIND_SUPPORT
15# define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|dwarf|lbr)\n" 14# define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|dwarf|lbr)\n"
16#else
17# define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|lbr)\n"
18#endif
19 15
20#define RECORD_SIZE_HELP \ 16#define RECORD_SIZE_HELP \
21 HELP_PAD "record_size:\tif record_mode is 'dwarf', max size of stack recording (<bytes>)\n" \ 17 HELP_PAD "record_size:\tif record_mode is 'dwarf', max size of stack recording (<bytes>)\n" \
@@ -115,6 +111,12 @@ struct callchain_list {
115 bool unfolded; 111 bool unfolded;
116 bool has_children; 112 bool has_children;
117 }; 113 };
114 u64 branch_count;
115 u64 predicted_count;
116 u64 abort_count;
117 u64 cycles_count;
118 u64 iter_count;
119 u64 samples_count;
118 char *srcline; 120 char *srcline;
119 struct list_head list; 121 struct list_head list;
120}; 122};
@@ -129,6 +131,10 @@ struct callchain_cursor_node {
129 u64 ip; 131 u64 ip;
130 struct map *map; 132 struct map *map;
131 struct symbol *sym; 133 struct symbol *sym;
134 bool branch;
135 struct branch_flags branch_flags;
136 int nr_loop_iter;
137 int samples;
132 struct callchain_cursor_node *next; 138 struct callchain_cursor_node *next;
133}; 139};
134 140
@@ -183,7 +189,9 @@ static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
183} 189}
184 190
185int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, 191int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
186 struct map *map, struct symbol *sym); 192 struct map *map, struct symbol *sym,
193 bool branch, struct branch_flags *flags,
194 int nr_loop_iter, int samples);
187 195
188/* Close a cursor writing session. Initialize for the reader */ 196/* Close a cursor writing session. Initialize for the reader */
189static inline void callchain_cursor_commit(struct callchain_cursor *cursor) 197static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
@@ -208,6 +216,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
208 cursor->pos++; 216 cursor->pos++;
209} 217}
210 218
219int callchain_cursor__copy(struct callchain_cursor *dst,
220 struct callchain_cursor *src);
221
211struct option; 222struct option;
212struct hist_entry; 223struct hist_entry;
213 224
@@ -261,8 +272,16 @@ char *callchain_node__scnprintf_value(struct callchain_node *node,
261int callchain_node__fprintf_value(struct callchain_node *node, 272int callchain_node__fprintf_value(struct callchain_node *node,
262 FILE *fp, u64 total); 273 FILE *fp, u64 total);
263 274
275int callchain_list_counts__printf_value(struct callchain_node *node,
276 struct callchain_list *clist,
277 FILE *fp, char *bf, int bfsize);
278
264void free_callchain(struct callchain_root *root); 279void free_callchain(struct callchain_root *root);
265void decay_callchain(struct callchain_root *root); 280void decay_callchain(struct callchain_root *root);
266int callchain_node__make_parent_list(struct callchain_node *node); 281int callchain_node__make_parent_list(struct callchain_node *node);
267 282
283int callchain_branch_counts(struct callchain_root *root,
284 u64 *branch_count, u64 *predicted_count,
285 u64 *abort_count, u64 *cycles_count);
286
268#endif /* __PERF_CALLCHAIN_H */ 287#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 18dae745034f..3d906dbbef74 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -594,6 +594,19 @@ static int collect_config(const char *var, const char *value,
594 goto out_free; 594 goto out_free;
595 } 595 }
596 596
597 /* perf_config_set can contain both user and system config items.
598 * So we should know where each value is from.
599 * The classification would be needed when a particular config file
600 * is overwrited by setting feature i.e. set_config().
601 */
602 if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
603 section->from_system_config = true;
604 item->from_system_config = true;
605 } else {
606 section->from_system_config = false;
607 item->from_system_config = false;
608 }
609
597 ret = set_value(item, value); 610 ret = set_value(item, value);
598 return ret; 611 return ret;
599 612
@@ -602,6 +615,13 @@ out_free:
602 return -1; 615 return -1;
603} 616}
604 617
618int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
619 const char *var, const char *value)
620{
621 config_file_name = file_name;
622 return collect_config(var, value, set);
623}
624
605static int perf_config_set__init(struct perf_config_set *set) 625static int perf_config_set__init(struct perf_config_set *set)
606{ 626{
607 int ret = -1; 627 int ret = -1;
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
index 6f813d46045e..1a59a6b43f8b 100644
--- a/tools/perf/util/config.h
+++ b/tools/perf/util/config.h
@@ -7,12 +7,14 @@
7struct perf_config_item { 7struct perf_config_item {
8 char *name; 8 char *name;
9 char *value; 9 char *value;
10 bool from_system_config;
10 struct list_head node; 11 struct list_head node;
11}; 12};
12 13
13struct perf_config_section { 14struct perf_config_section {
14 char *name; 15 char *name;
15 struct list_head items; 16 struct list_head items;
17 bool from_system_config;
16 struct list_head node; 18 struct list_head node;
17}; 19};
18 20
@@ -33,6 +35,8 @@ const char *perf_etc_perfconfig(void);
33 35
34struct perf_config_set *perf_config_set__new(void); 36struct perf_config_set *perf_config_set__new(void);
35void perf_config_set__delete(struct perf_config_set *set); 37void perf_config_set__delete(struct perf_config_set *set);
38int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
39 const char *var, const char *value);
36void perf_config__init(void); 40void perf_config__init(void);
37void perf_config__exit(void); 41void perf_config__exit(void);
38void perf_config__refresh(void); 42void perf_config__refresh(void);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 8d363d5e65a2..c735c53a26f8 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -177,6 +177,8 @@ enum {
177 PERF_IP_FLAG_TRACE_BEGIN |\ 177 PERF_IP_FLAG_TRACE_BEGIN |\
178 PERF_IP_FLAG_TRACE_END) 178 PERF_IP_FLAG_TRACE_END)
179 179
180#define MAX_INSN 16
181
180struct perf_sample { 182struct perf_sample {
181 u64 ip; 183 u64 ip;
182 u32 pid, tid; 184 u32 pid, tid;
@@ -193,6 +195,7 @@ struct perf_sample {
193 u32 flags; 195 u32 flags;
194 u16 insn_len; 196 u16 insn_len;
195 u8 cpumode; 197 u8 cpumode;
198 char insn[MAX_INSN];
196 void *raw_data; 199 void *raw_data;
197 struct ip_callchain *callchain; 200 struct ip_callchain *callchain;
198 struct branch_stack *branch_stack; 201 struct branch_stack *branch_stack;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8bc271141d9d..04e536ae4d88 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -28,6 +28,7 @@
28#include "debug.h" 28#include "debug.h"
29#include "trace-event.h" 29#include "trace-event.h"
30#include "stat.h" 30#include "stat.h"
31#include "util/parse-branch-options.h"
31 32
32static struct { 33static struct {
33 bool sample_id_all; 34 bool sample_id_all;
@@ -708,6 +709,14 @@ static void apply_config_terms(struct perf_evsel *evsel,
708 case PERF_EVSEL__CONFIG_TERM_CALLGRAPH: 709 case PERF_EVSEL__CONFIG_TERM_CALLGRAPH:
709 callgraph_buf = term->val.callgraph; 710 callgraph_buf = term->val.callgraph;
710 break; 711 break;
712 case PERF_EVSEL__CONFIG_TERM_BRANCH:
713 if (term->val.branch && strcmp(term->val.branch, "no")) {
714 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
715 parse_branch_str(term->val.branch,
716 &attr->branch_sample_type);
717 } else
718 perf_evsel__reset_sample_bit(evsel, BRANCH_STACK);
719 break;
711 case PERF_EVSEL__CONFIG_TERM_STACK_USER: 720 case PERF_EVSEL__CONFIG_TERM_STACK_USER:
712 dump_size = term->val.stack_user; 721 dump_size = term->val.stack_user;
713 break; 722 break;
@@ -981,6 +990,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
981 * it overloads any global configuration. 990 * it overloads any global configuration.
982 */ 991 */
983 apply_config_terms(evsel, opts); 992 apply_config_terms(evsel, opts);
993
994 evsel->ignore_missing_thread = opts->ignore_missing_thread;
984} 995}
985 996
986static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 997static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -1410,6 +1421,33 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val,
1410 return fprintf(fp, " %-32s %s\n", name, val); 1421 return fprintf(fp, " %-32s %s\n", name, val);
1411} 1422}
1412 1423
1424static bool ignore_missing_thread(struct perf_evsel *evsel,
1425 struct thread_map *threads,
1426 int thread, int err)
1427{
1428 if (!evsel->ignore_missing_thread)
1429 return false;
1430
1431 /* The system wide setup does not work with threads. */
1432 if (evsel->system_wide)
1433 return false;
1434
1435 /* The -ESRCH is perf event syscall errno for pid's not found. */
1436 if (err != -ESRCH)
1437 return false;
1438
1439 /* If there's only one thread, let it fail. */
1440 if (threads->nr == 1)
1441 return false;
1442
1443 if (thread_map__remove(threads, thread))
1444 return false;
1445
1446 pr_warning("WARNING: Ignored open failure for pid %d\n",
1447 thread_map__pid(threads, thread));
1448 return true;
1449}
1450
1413static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 1451static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
1414 struct thread_map *threads) 1452 struct thread_map *threads)
1415{ 1453{
@@ -1465,29 +1503,47 @@ retry_sample_id:
1465 for (cpu = 0; cpu < cpus->nr; cpu++) { 1503 for (cpu = 0; cpu < cpus->nr; cpu++) {
1466 1504
1467 for (thread = 0; thread < nthreads; thread++) { 1505 for (thread = 0; thread < nthreads; thread++) {
1468 int group_fd; 1506 int fd, group_fd;
1469 1507
1470 if (!evsel->cgrp && !evsel->system_wide) 1508 if (!evsel->cgrp && !evsel->system_wide)
1471 pid = thread_map__pid(threads, thread); 1509 pid = thread_map__pid(threads, thread);
1472 1510
1473 group_fd = get_group_fd(evsel, cpu, thread); 1511 group_fd = get_group_fd(evsel, cpu, thread);
1474retry_open: 1512retry_open:
1475 pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n", 1513 pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx",
1476 pid, cpus->map[cpu], group_fd, flags); 1514 pid, cpus->map[cpu], group_fd, flags);
1477 1515
1478 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 1516 fd = sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu],
1479 pid, 1517 group_fd, flags);
1480 cpus->map[cpu], 1518
1481 group_fd, flags); 1519 FD(evsel, cpu, thread) = fd;
1482 if (FD(evsel, cpu, thread) < 0) { 1520
1521 if (fd < 0) {
1483 err = -errno; 1522 err = -errno;
1484 pr_debug2("sys_perf_event_open failed, error %d\n", 1523
1524 if (ignore_missing_thread(evsel, threads, thread, err)) {
1525 /*
1526 * We just removed 1 thread, so take a step
1527 * back on thread index and lower the upper
1528 * nthreads limit.
1529 */
1530 nthreads--;
1531 thread--;
1532
1533 /* ... and pretend like nothing have happened. */
1534 err = 0;
1535 continue;
1536 }
1537
1538 pr_debug2("\nsys_perf_event_open failed, error %d\n",
1485 err); 1539 err);
1486 goto try_fallback; 1540 goto try_fallback;
1487 } 1541 }
1488 1542
1543 pr_debug2(" = %d\n", fd);
1544
1489 if (evsel->bpf_fd >= 0) { 1545 if (evsel->bpf_fd >= 0) {
1490 int evt_fd = FD(evsel, cpu, thread); 1546 int evt_fd = fd;
1491 int bpf_fd = evsel->bpf_fd; 1547 int bpf_fd = evsel->bpf_fd;
1492 1548
1493 err = ioctl(evt_fd, 1549 err = ioctl(evt_fd,
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b1503b0ecdff..06ef6f29efa1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -47,6 +47,7 @@ enum {
47 PERF_EVSEL__CONFIG_TERM_MAX_STACK, 47 PERF_EVSEL__CONFIG_TERM_MAX_STACK,
48 PERF_EVSEL__CONFIG_TERM_OVERWRITE, 48 PERF_EVSEL__CONFIG_TERM_OVERWRITE,
49 PERF_EVSEL__CONFIG_TERM_DRV_CFG, 49 PERF_EVSEL__CONFIG_TERM_DRV_CFG,
50 PERF_EVSEL__CONFIG_TERM_BRANCH,
50 PERF_EVSEL__CONFIG_TERM_MAX, 51 PERF_EVSEL__CONFIG_TERM_MAX,
51}; 52};
52 53
@@ -63,6 +64,7 @@ struct perf_evsel_config_term {
63 int max_stack; 64 int max_stack;
64 bool inherit; 65 bool inherit;
65 bool overwrite; 66 bool overwrite;
67 char *branch;
66 } val; 68 } val;
67}; 69};
68 70
@@ -118,6 +120,7 @@ struct perf_evsel {
118 bool tracking; 120 bool tracking;
119 bool per_pkg; 121 bool per_pkg;
120 bool precise_max; 122 bool precise_max;
123 bool ignore_missing_thread;
121 /* parse modifier helper */ 124 /* parse modifier helper */
122 int exclude_GH; 125 int exclude_GH;
123 int nr_members; 126 int nr_members;
@@ -389,6 +392,8 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
389#define EVSEL__PRINT_ONELINE (1<<4) 392#define EVSEL__PRINT_ONELINE (1<<4)
390#define EVSEL__PRINT_SRCLINE (1<<5) 393#define EVSEL__PRINT_SRCLINE (1<<5)
391#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) 394#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6)
395#define EVSEL__PRINT_CALLCHAIN_ARROW (1<<7)
396#define EVSEL__PRINT_SKIP_IGNORED (1<<8)
392 397
393struct callchain_cursor; 398struct callchain_cursor;
394 399
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index 662a0a6182e7..6b2925542c0a 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -108,7 +108,10 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
108 int print_oneline = print_opts & EVSEL__PRINT_ONELINE; 108 int print_oneline = print_opts & EVSEL__PRINT_ONELINE;
109 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; 109 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
110 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; 110 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
111 int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW;
112 int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED;
111 char s = print_oneline ? ' ' : '\t'; 113 char s = print_oneline ? ' ' : '\t';
114 bool first = true;
112 115
113 if (sample->callchain) { 116 if (sample->callchain) {
114 struct addr_location node_al; 117 struct addr_location node_al;
@@ -122,8 +125,14 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
122 if (!node) 125 if (!node)
123 break; 126 break;
124 127
128 if (node->sym && node->sym->ignore && print_skip_ignored)
129 goto next;
130
125 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 131 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
126 132
133 if (print_arrow && !first)
134 printed += fprintf(fp, " <-");
135
127 if (print_ip) 136 if (print_ip)
128 printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); 137 printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
129 138
@@ -137,7 +146,8 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
137 146
138 if (print_symoffset) { 147 if (print_symoffset) {
139 printed += __symbol__fprintf_symname_offs(node->sym, &node_al, 148 printed += __symbol__fprintf_symname_offs(node->sym, &node_al,
140 print_unknown_as_addr, fp); 149 print_unknown_as_addr,
150 true, fp);
141 } else { 151 } else {
142 printed += __symbol__fprintf_symname(node->sym, &node_al, 152 printed += __symbol__fprintf_symname(node->sym, &node_al,
143 print_unknown_as_addr, fp); 153 print_unknown_as_addr, fp);
@@ -156,6 +166,16 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
156 if (!print_oneline) 166 if (!print_oneline)
157 printed += fprintf(fp, "\n"); 167 printed += fprintf(fp, "\n");
158 168
169 if (symbol_conf.bt_stop_list &&
170 node->sym &&
171 node->sym->name &&
172 strlist__has_entry(symbol_conf.bt_stop_list,
173 node->sym->name)) {
174 break;
175 }
176
177 first = false;
178next:
159 callchain_cursor_advance(cursor); 179 callchain_cursor_advance(cursor);
160 } 180 }
161 } 181 }
@@ -188,7 +208,8 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
188 printed += fprintf(fp, " "); 208 printed += fprintf(fp, " ");
189 if (print_symoffset) { 209 if (print_symoffset) {
190 printed += __symbol__fprintf_symname_offs(al->sym, al, 210 printed += __symbol__fprintf_symname_offs(al->sym, al,
191 print_unknown_as_addr, fp); 211 print_unknown_as_addr,
212 true, fp);
192 } else { 213 } else {
193 printed += __symbol__fprintf_symname(al->sym, al, 214 printed += __symbol__fprintf_symname(al->sym, al,
194 print_unknown_as_addr, fp); 215 print_unknown_as_addr, fp);
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
index c1ef805c6a8f..c540d47583e7 100644
--- a/tools/perf/util/genelf.c
+++ b/tools/perf/util/genelf.c
@@ -19,12 +19,18 @@
19#include <limits.h> 19#include <limits.h>
20#include <fcntl.h> 20#include <fcntl.h>
21#include <err.h> 21#include <err.h>
22#ifdef HAVE_DWARF_SUPPORT
22#include <dwarf.h> 23#include <dwarf.h>
24#endif
23 25
24#include "perf.h" 26#include "perf.h"
25#include "genelf.h" 27#include "genelf.h"
26#include "../util/jitdump.h" 28#include "../util/jitdump.h"
27 29
30#ifndef NT_GNU_BUILD_ID
31#define NT_GNU_BUILD_ID 3
32#endif
33
28#define JVMTI 34#define JVMTI
29 35
30#define BUILD_ID_URANDOM /* different uuid for each run */ 36#define BUILD_ID_URANDOM /* different uuid for each run */
@@ -67,6 +73,8 @@ static char shd_string_table[] = {
67 '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */ 73 '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
68 '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */ 74 '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
69 '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */ 75 '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
76 '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', '_', 'h', 'd', 'r', 0, /* 90 */
77 '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, /* 104 */
70}; 78};
71 79
72static struct buildid_note { 80static struct buildid_note {
@@ -147,6 +155,86 @@ gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *cod
147} 155}
148#endif 156#endif
149 157
158static int
159jit_add_eh_frame_info(Elf *e, void* unwinding, uint64_t unwinding_header_size,
160 uint64_t unwinding_size, uint64_t base_offset)
161{
162 Elf_Data *d;
163 Elf_Scn *scn;
164 Elf_Shdr *shdr;
165 uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
166
167 /*
168 * setup eh_frame section
169 */
170 scn = elf_newscn(e);
171 if (!scn) {
172 warnx("cannot create section");
173 return -1;
174 }
175
176 d = elf_newdata(scn);
177 if (!d) {
178 warnx("cannot get new data");
179 return -1;
180 }
181
182 d->d_align = 8;
183 d->d_off = 0LL;
184 d->d_buf = unwinding;
185 d->d_type = ELF_T_BYTE;
186 d->d_size = unwinding_table_size;
187 d->d_version = EV_CURRENT;
188
189 shdr = elf_getshdr(scn);
190 if (!shdr) {
191 warnx("cannot get section header");
192 return -1;
193 }
194
195 shdr->sh_name = 104;
196 shdr->sh_type = SHT_PROGBITS;
197 shdr->sh_addr = base_offset;
198 shdr->sh_flags = SHF_ALLOC;
199 shdr->sh_entsize = 0;
200
201 /*
202 * setup eh_frame_hdr section
203 */
204 scn = elf_newscn(e);
205 if (!scn) {
206 warnx("cannot create section");
207 return -1;
208 }
209
210 d = elf_newdata(scn);
211 if (!d) {
212 warnx("cannot get new data");
213 return -1;
214 }
215
216 d->d_align = 4;
217 d->d_off = 0LL;
218 d->d_buf = unwinding + unwinding_table_size;
219 d->d_type = ELF_T_BYTE;
220 d->d_size = unwinding_header_size;
221 d->d_version = EV_CURRENT;
222
223 shdr = elf_getshdr(scn);
224 if (!shdr) {
225 warnx("cannot get section header");
226 return -1;
227 }
228
229 shdr->sh_name = 90;
230 shdr->sh_type = SHT_PROGBITS;
231 shdr->sh_addr = base_offset + unwinding_table_size;
232 shdr->sh_flags = SHF_ALLOC;
233 shdr->sh_entsize = 0;
234
235 return 0;
236}
237
150/* 238/*
151 * fd: file descriptor open for writing for the output file 239 * fd: file descriptor open for writing for the output file
152 * load_addr: code load address (could be zero, just used for buildid) 240 * load_addr: code load address (could be zero, just used for buildid)
@@ -157,13 +245,15 @@ gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *cod
157int 245int
158jit_write_elf(int fd, uint64_t load_addr, const char *sym, 246jit_write_elf(int fd, uint64_t load_addr, const char *sym,
159 const void *code, int csize, 247 const void *code, int csize,
160 void *debug, int nr_debug_entries) 248 void *debug __maybe_unused, int nr_debug_entries __maybe_unused,
249 void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)
161{ 250{
162 Elf *e; 251 Elf *e;
163 Elf_Data *d; 252 Elf_Data *d;
164 Elf_Scn *scn; 253 Elf_Scn *scn;
165 Elf_Ehdr *ehdr; 254 Elf_Ehdr *ehdr;
166 Elf_Shdr *shdr; 255 Elf_Shdr *shdr;
256 uint64_t eh_frame_base_offset;
167 char *strsym = NULL; 257 char *strsym = NULL;
168 int symlen; 258 int symlen;
169 int retval = -1; 259 int retval = -1;
@@ -194,7 +284,7 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
194 ehdr->e_type = ET_DYN; 284 ehdr->e_type = ET_DYN;
195 ehdr->e_entry = GEN_ELF_TEXT_OFFSET; 285 ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
196 ehdr->e_version = EV_CURRENT; 286 ehdr->e_version = EV_CURRENT;
197 ehdr->e_shstrndx= 2; /* shdr index for section name */ 287 ehdr->e_shstrndx= unwinding ? 4 : 2; /* shdr index for section name */
198 288
199 /* 289 /*
200 * setup text section 290 * setup text section
@@ -231,6 +321,18 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
231 shdr->sh_entsize = 0; 321 shdr->sh_entsize = 0;
232 322
233 /* 323 /*
324 * Setup .eh_frame_hdr and .eh_frame
325 */
326 if (unwinding) {
327 eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize);
328 retval = jit_add_eh_frame_info(e, unwinding,
329 unwinding_header_size, unwinding_size,
330 eh_frame_base_offset);
331 if (retval)
332 goto error;
333 }
334
335 /*
234 * setup section headers string table 336 * setup section headers string table
235 */ 337 */
236 scn = elf_newscn(e); 338 scn = elf_newscn(e);
@@ -298,7 +400,7 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
298 shdr->sh_type = SHT_SYMTAB; 400 shdr->sh_type = SHT_SYMTAB;
299 shdr->sh_flags = 0; 401 shdr->sh_flags = 0;
300 shdr->sh_entsize = sizeof(Elf_Sym); 402 shdr->sh_entsize = sizeof(Elf_Sym);
301 shdr->sh_link = 4; /* index of .strtab section */ 403 shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */
302 404
303 /* 405 /*
304 * setup symbols string table 406 * setup symbols string table
@@ -386,11 +488,14 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
386 shdr->sh_size = sizeof(bnote); 488 shdr->sh_size = sizeof(bnote);
387 shdr->sh_entsize = 0; 489 shdr->sh_entsize = 0;
388 490
491#ifdef HAVE_DWARF_SUPPORT
389 if (debug && nr_debug_entries) { 492 if (debug && nr_debug_entries) {
390 retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries); 493 retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
391 if (retval) 494 if (retval)
392 goto error; 495 goto error;
393 } else { 496 } else
497#endif
498 {
394 if (elf_update(e, ELF_C_WRITE) < 0) { 499 if (elf_update(e, ELF_C_WRITE) < 0) {
395 warnx("elf_update 4 failed"); 500 warnx("elf_update 4 failed");
396 goto error; 501 goto error;
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
index 2fbeb59c4bdd..2424bd9862a3 100644
--- a/tools/perf/util/genelf.h
+++ b/tools/perf/util/genelf.h
@@ -3,9 +3,12 @@
3 3
4/* genelf.c */ 4/* genelf.c */
5int jit_write_elf(int fd, uint64_t code_addr, const char *sym, 5int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
6 const void *code, int csize, void *debug, int nr_debug_entries); 6 const void *code, int csize, void *debug, int nr_debug_entries,
7 void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size);
8#ifdef HAVE_DWARF_SUPPORT
7/* genelf_debug.c */ 9/* genelf_debug.c */
8int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries); 10int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries);
11#endif
9 12
10#if defined(__arm__) 13#if defined(__arm__)
11#define GEN_ELF_ARCH EM_ARM 14#define GEN_ELF_ARCH EM_ARM
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 2f3eded54b0c..d89c9c7ef4e5 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2250,11 +2250,28 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
2250 struct header_print_data hd; 2250 struct header_print_data hd;
2251 struct perf_header *header = &session->header; 2251 struct perf_header *header = &session->header;
2252 int fd = perf_data_file__fd(session->file); 2252 int fd = perf_data_file__fd(session->file);
2253 struct stat st;
2254 int ret, bit;
2255
2253 hd.fp = fp; 2256 hd.fp = fp;
2254 hd.full = full; 2257 hd.full = full;
2255 2258
2259 ret = fstat(fd, &st);
2260 if (ret == -1)
2261 return -1;
2262
2263 fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
2264
2256 perf_header__process_sections(header, fd, &hd, 2265 perf_header__process_sections(header, fd, &hd,
2257 perf_file_section__fprintf_info); 2266 perf_file_section__fprintf_info);
2267
2268 fprintf(fp, "# missing features: ");
2269 for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) {
2270 if (bit)
2271 fprintf(fp, "%s ", feat_ops[bit].name);
2272 }
2273
2274 fprintf(fp, "\n");
2258 return 0; 2275 return 0;
2259} 2276}
2260 2277
@@ -2273,7 +2290,7 @@ static int do_write_feat(int fd, struct perf_header *h, int type,
2273 2290
2274 err = feat_ops[type].write(fd, h, evlist); 2291 err = feat_ops[type].write(fd, h, evlist);
2275 if (err < 0) { 2292 if (err < 0) {
2276 pr_debug("failed to write feature %d\n", type); 2293 pr_debug("failed to write feature %s\n", feat_ops[type].name);
2277 2294
2278 /* undo anything written */ 2295 /* undo anything written */
2279 lseek(fd, (*p)->offset, SEEK_SET); 2296 lseek(fd, (*p)->offset, SEEK_SET);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index b02992efb513..6770a9645609 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1195,6 +1195,7 @@ static void hist_entry__check_and_remove_filter(struct hist_entry *he,
1195 case HIST_FILTER__GUEST: 1195 case HIST_FILTER__GUEST:
1196 case HIST_FILTER__HOST: 1196 case HIST_FILTER__HOST:
1197 case HIST_FILTER__SOCKET: 1197 case HIST_FILTER__SOCKET:
1198 case HIST_FILTER__C2C:
1198 default: 1199 default:
1199 return; 1200 return;
1200 } 1201 }
@@ -1600,18 +1601,18 @@ static void hists__hierarchy_output_resort(struct hists *hists,
1600 if (prog) 1601 if (prog)
1601 ui_progress__update(prog, 1); 1602 ui_progress__update(prog, 1);
1602 1603
1604 hists->nr_entries++;
1605 if (!he->filtered) {
1606 hists->nr_non_filtered_entries++;
1607 hists__calc_col_len(hists, he);
1608 }
1609
1603 if (!he->leaf) { 1610 if (!he->leaf) {
1604 hists__hierarchy_output_resort(hists, prog, 1611 hists__hierarchy_output_resort(hists, prog,
1605 &he->hroot_in, 1612 &he->hroot_in,
1606 &he->hroot_out, 1613 &he->hroot_out,
1607 min_callchain_hits, 1614 min_callchain_hits,
1608 use_callchain); 1615 use_callchain);
1609 hists->nr_entries++;
1610 if (!he->filtered) {
1611 hists->nr_non_filtered_entries++;
1612 hists__calc_col_len(hists, he);
1613 }
1614
1615 continue; 1616 continue;
1616 } 1617 }
1617 1618
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 9928fed8bc59..d4b6514eeef5 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -22,6 +22,7 @@ enum hist_filter {
22 HIST_FILTER__GUEST, 22 HIST_FILTER__GUEST,
23 HIST_FILTER__HOST, 23 HIST_FILTER__HOST,
24 HIST_FILTER__SOCKET, 24 HIST_FILTER__SOCKET,
25 HIST_FILTER__C2C,
25}; 26};
26 27
27enum hist_column { 28enum hist_column {
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
index f545ec1e758a..6c2eb5da4afc 100644
--- a/tools/perf/util/intel-bts.c
+++ b/tools/perf/util/intel-bts.c
@@ -295,6 +295,7 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
295 sample.cpu = btsq->cpu; 295 sample.cpu = btsq->cpu;
296 sample.flags = btsq->sample_flags; 296 sample.flags = btsq->sample_flags;
297 sample.insn_len = btsq->intel_pt_insn.length; 297 sample.insn_len = btsq->intel_pt_insn.length;
298 memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ);
298 299
299 if (bts->synth_opts.inject) { 300 if (bts->synth_opts.inject) {
300 event.sample.header.size = bts->branches_event_size; 301 event.sample.header.size = bts->branches_event_size;
@@ -319,15 +320,12 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
319 struct machine *machine = btsq->bts->machine; 320 struct machine *machine = btsq->bts->machine;
320 struct thread *thread; 321 struct thread *thread;
321 struct addr_location al; 322 struct addr_location al;
322 unsigned char buf[1024]; 323 unsigned char buf[INTEL_PT_INSN_BUF_SZ];
323 size_t bufsz;
324 ssize_t len; 324 ssize_t len;
325 int x86_64; 325 int x86_64;
326 uint8_t cpumode; 326 uint8_t cpumode;
327 int err = -1; 327 int err = -1;
328 328
329 bufsz = intel_pt_insn_max_size();
330
331 if (machine__kernel_ip(machine, ip)) 329 if (machine__kernel_ip(machine, ip))
332 cpumode = PERF_RECORD_MISC_KERNEL; 330 cpumode = PERF_RECORD_MISC_KERNEL;
333 else 331 else
@@ -341,7 +339,8 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
341 if (!al.map || !al.map->dso) 339 if (!al.map || !al.map->dso)
342 goto out_put; 340 goto out_put;
343 341
344 len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf, bufsz); 342 len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf,
343 INTEL_PT_INSN_BUF_SZ);
345 if (len <= 0) 344 if (len <= 0)
346 goto out_put; 345 goto out_put;
347 346
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 16c06d3ae577..e4e7dc781d21 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -980,6 +980,8 @@ out:
980out_no_progress: 980out_no_progress:
981 decoder->state.insn_op = intel_pt_insn->op; 981 decoder->state.insn_op = intel_pt_insn->op;
982 decoder->state.insn_len = intel_pt_insn->length; 982 decoder->state.insn_len = intel_pt_insn->length;
983 memcpy(decoder->state.insn, intel_pt_insn->buf,
984 INTEL_PT_INSN_BUF_SZ);
983 985
984 if (decoder->tx_flags & INTEL_PT_IN_TX) 986 if (decoder->tx_flags & INTEL_PT_IN_TX)
985 decoder->state.flags |= INTEL_PT_IN_TX; 987 decoder->state.flags |= INTEL_PT_IN_TX;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
index 89399985fa4d..e90619a43c0c 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
@@ -66,6 +66,7 @@ struct intel_pt_state {
66 uint32_t flags; 66 uint32_t flags;
67 enum intel_pt_insn_op insn_op; 67 enum intel_pt_insn_op insn_op;
68 int insn_len; 68 int insn_len;
69 char insn[INTEL_PT_INSN_BUF_SZ];
69}; 70};
70 71
71struct intel_pt_insn; 72struct intel_pt_insn;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
index d23138c06665..7913363bde5c 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
@@ -27,6 +27,10 @@
27 27
28#include "intel-pt-insn-decoder.h" 28#include "intel-pt-insn-decoder.h"
29 29
30#if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN
31#error Instruction buffer size too small
32#endif
33
30/* Based on branch_type() from perf_event_intel_lbr.c */ 34/* Based on branch_type() from perf_event_intel_lbr.c */
31static void intel_pt_insn_decoder(struct insn *insn, 35static void intel_pt_insn_decoder(struct insn *insn,
32 struct intel_pt_insn *intel_pt_insn) 36 struct intel_pt_insn *intel_pt_insn)
@@ -166,10 +170,10 @@ int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
166 if (!insn_complete(&insn) || insn.length > len) 170 if (!insn_complete(&insn) || insn.length > len)
167 return -1; 171 return -1;
168 intel_pt_insn_decoder(&insn, intel_pt_insn); 172 intel_pt_insn_decoder(&insn, intel_pt_insn);
169 if (insn.length < INTEL_PT_INSN_DBG_BUF_SZ) 173 if (insn.length < INTEL_PT_INSN_BUF_SZ)
170 memcpy(intel_pt_insn->buf, buf, insn.length); 174 memcpy(intel_pt_insn->buf, buf, insn.length);
171 else 175 else
172 memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_DBG_BUF_SZ); 176 memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_BUF_SZ);
173 return 0; 177 return 0;
174} 178}
175 179
@@ -211,11 +215,6 @@ int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
211 return 0; 215 return 0;
212} 216}
213 217
214size_t intel_pt_insn_max_size(void)
215{
216 return MAX_INSN_SIZE;
217}
218
219int intel_pt_insn_type(enum intel_pt_insn_op op) 218int intel_pt_insn_type(enum intel_pt_insn_op op)
220{ 219{
221 switch (op) { 220 switch (op) {
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.h
index b0adbf37323e..37ec5627ae9b 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.h
@@ -20,7 +20,7 @@
20#include <stdint.h> 20#include <stdint.h>
21 21
22#define INTEL_PT_INSN_DESC_MAX 32 22#define INTEL_PT_INSN_DESC_MAX 32
23#define INTEL_PT_INSN_DBG_BUF_SZ 16 23#define INTEL_PT_INSN_BUF_SZ 16
24 24
25enum intel_pt_insn_op { 25enum intel_pt_insn_op {
26 INTEL_PT_OP_OTHER, 26 INTEL_PT_OP_OTHER,
@@ -47,7 +47,7 @@ struct intel_pt_insn {
47 enum intel_pt_insn_branch branch; 47 enum intel_pt_insn_branch branch;
48 int length; 48 int length;
49 int32_t rel; 49 int32_t rel;
50 unsigned char buf[INTEL_PT_INSN_DBG_BUF_SZ]; 50 unsigned char buf[INTEL_PT_INSN_BUF_SZ];
51}; 51};
52 52
53int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64, 53int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
@@ -58,8 +58,6 @@ const char *intel_pt_insn_name(enum intel_pt_insn_op op);
58int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf, 58int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
59 size_t buf_len); 59 size_t buf_len);
60 60
61size_t intel_pt_insn_max_size(void);
62
63int intel_pt_insn_type(enum intel_pt_insn_op op); 61int intel_pt_insn_type(enum intel_pt_insn_op op);
64 62
65#endif 63#endif
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.c b/tools/perf/util/intel-pt-decoder/intel-pt-log.c
index 319bef33a64b..e02bc7b166a0 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-log.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.c
@@ -119,8 +119,8 @@ void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip)
119 if (intel_pt_log_open()) 119 if (intel_pt_log_open())
120 return; 120 return;
121 121
122 if (len > INTEL_PT_INSN_DBG_BUF_SZ) 122 if (len > INTEL_PT_INSN_BUF_SZ)
123 len = INTEL_PT_INSN_DBG_BUF_SZ; 123 len = INTEL_PT_INSN_BUF_SZ;
124 intel_pt_print_data(intel_pt_insn->buf, len, ip, 8); 124 intel_pt_print_data(intel_pt_insn->buf, len, ip, 8);
125 if (intel_pt_insn_desc(intel_pt_insn, desc, INTEL_PT_INSN_DESC_MAX) > 0) 125 if (intel_pt_insn_desc(intel_pt_insn, desc, INTEL_PT_INSN_DESC_MAX) > 0)
126 fprintf(f, "%s\n", desc); 126 fprintf(f, "%s\n", desc);
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index dc041d4368c8..85d5eeb66c75 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -143,6 +143,7 @@ struct intel_pt_queue {
143 u32 flags; 143 u32 flags;
144 u16 insn_len; 144 u16 insn_len;
145 u64 last_insn_cnt; 145 u64 last_insn_cnt;
146 char insn[INTEL_PT_INSN_BUF_SZ];
146}; 147};
147 148
148static void intel_pt_dump(struct intel_pt *pt __maybe_unused, 149static void intel_pt_dump(struct intel_pt *pt __maybe_unused,
@@ -315,6 +316,7 @@ struct intel_pt_cache_entry {
315 enum intel_pt_insn_branch branch; 316 enum intel_pt_insn_branch branch;
316 int length; 317 int length;
317 int32_t rel; 318 int32_t rel;
319 char insn[INTEL_PT_INSN_BUF_SZ];
318}; 320};
319 321
320static int intel_pt_config_div(const char *var, const char *value, void *data) 322static int intel_pt_config_div(const char *var, const char *value, void *data)
@@ -400,6 +402,7 @@ static int intel_pt_cache_add(struct dso *dso, struct machine *machine,
400 e->branch = intel_pt_insn->branch; 402 e->branch = intel_pt_insn->branch;
401 e->length = intel_pt_insn->length; 403 e->length = intel_pt_insn->length;
402 e->rel = intel_pt_insn->rel; 404 e->rel = intel_pt_insn->rel;
405 memcpy(e->insn, intel_pt_insn->buf, INTEL_PT_INSN_BUF_SZ);
403 406
404 err = auxtrace_cache__add(c, offset, &e->entry); 407 err = auxtrace_cache__add(c, offset, &e->entry);
405 if (err) 408 if (err)
@@ -428,8 +431,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
428 struct machine *machine = ptq->pt->machine; 431 struct machine *machine = ptq->pt->machine;
429 struct thread *thread; 432 struct thread *thread;
430 struct addr_location al; 433 struct addr_location al;
431 unsigned char buf[1024]; 434 unsigned char buf[INTEL_PT_INSN_BUF_SZ];
432 size_t bufsz;
433 ssize_t len; 435 ssize_t len;
434 int x86_64; 436 int x86_64;
435 u8 cpumode; 437 u8 cpumode;
@@ -437,11 +439,11 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
437 u64 insn_cnt = 0; 439 u64 insn_cnt = 0;
438 bool one_map = true; 440 bool one_map = true;
439 441
442 intel_pt_insn->length = 0;
443
440 if (to_ip && *ip == to_ip) 444 if (to_ip && *ip == to_ip)
441 goto out_no_cache; 445 goto out_no_cache;
442 446
443 bufsz = intel_pt_insn_max_size();
444
445 if (*ip >= ptq->pt->kernel_start) 447 if (*ip >= ptq->pt->kernel_start)
446 cpumode = PERF_RECORD_MISC_KERNEL; 448 cpumode = PERF_RECORD_MISC_KERNEL;
447 else 449 else
@@ -478,6 +480,8 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
478 intel_pt_insn->branch = e->branch; 480 intel_pt_insn->branch = e->branch;
479 intel_pt_insn->length = e->length; 481 intel_pt_insn->length = e->length;
480 intel_pt_insn->rel = e->rel; 482 intel_pt_insn->rel = e->rel;
483 memcpy(intel_pt_insn->buf, e->insn,
484 INTEL_PT_INSN_BUF_SZ);
481 intel_pt_log_insn_no_data(intel_pt_insn, *ip); 485 intel_pt_log_insn_no_data(intel_pt_insn, *ip);
482 return 0; 486 return 0;
483 } 487 }
@@ -493,7 +497,8 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
493 497
494 while (1) { 498 while (1) {
495 len = dso__data_read_offset(al.map->dso, machine, 499 len = dso__data_read_offset(al.map->dso, machine,
496 offset, buf, bufsz); 500 offset, buf,
501 INTEL_PT_INSN_BUF_SZ);
497 if (len <= 0) 502 if (len <= 0)
498 return -EINVAL; 503 return -EINVAL;
499 504
@@ -900,6 +905,7 @@ static void intel_pt_sample_flags(struct intel_pt_queue *ptq)
900 if (ptq->state->flags & INTEL_PT_IN_TX) 905 if (ptq->state->flags & INTEL_PT_IN_TX)
901 ptq->flags |= PERF_IP_FLAG_IN_TX; 906 ptq->flags |= PERF_IP_FLAG_IN_TX;
902 ptq->insn_len = ptq->state->insn_len; 907 ptq->insn_len = ptq->state->insn_len;
908 memcpy(ptq->insn, ptq->state->insn, INTEL_PT_INSN_BUF_SZ);
903 } 909 }
904} 910}
905 911
@@ -1080,6 +1086,7 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq)
1080 sample.cpu = ptq->cpu; 1086 sample.cpu = ptq->cpu;
1081 sample.flags = ptq->flags; 1087 sample.flags = ptq->flags;
1082 sample.insn_len = ptq->insn_len; 1088 sample.insn_len = ptq->insn_len;
1089 memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
1083 1090
1084 /* 1091 /*
1085 * perf report cannot handle events without a branch stack when using 1092 * perf report cannot handle events without a branch stack when using
@@ -1141,6 +1148,7 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq)
1141 sample.cpu = ptq->cpu; 1148 sample.cpu = ptq->cpu;
1142 sample.flags = ptq->flags; 1149 sample.flags = ptq->flags;
1143 sample.insn_len = ptq->insn_len; 1150 sample.insn_len = ptq->insn_len;
1151 memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
1144 1152
1145 ptq->last_insn_cnt = ptq->state->tot_insn_cnt; 1153 ptq->last_insn_cnt = ptq->state->tot_insn_cnt;
1146 1154
@@ -1203,6 +1211,7 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq)
1203 sample.cpu = ptq->cpu; 1211 sample.cpu = ptq->cpu;
1204 sample.flags = ptq->flags; 1212 sample.flags = ptq->flags;
1205 sample.insn_len = ptq->insn_len; 1213 sample.insn_len = ptq->insn_len;
1214 memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
1206 1215
1207 if (pt->synth_opts.callchain) { 1216 if (pt->synth_opts.callchain) {
1208 thread_stack__sample(ptq->thread, ptq->chain, 1217 thread_stack__sample(ptq->thread, ptq->chain,
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 95f0884aae02..c9a941ef0f6d 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -37,6 +37,10 @@ struct jit_buf_desc {
37 bool needs_bswap; /* handles cross-endianess */ 37 bool needs_bswap; /* handles cross-endianess */
38 bool use_arch_timestamp; 38 bool use_arch_timestamp;
39 void *debug_data; 39 void *debug_data;
40 void *unwinding_data;
41 uint64_t unwinding_size;
42 uint64_t unwinding_mapped_size;
43 uint64_t eh_frame_hdr_size;
40 size_t nr_debug_entries; 44 size_t nr_debug_entries;
41 uint32_t code_load_count; 45 uint32_t code_load_count;
42 u64 bytes_written; 46 u64 bytes_written;
@@ -68,7 +72,10 @@ jit_emit_elf(char *filename,
68 const void *code, 72 const void *code,
69 int csize, 73 int csize,
70 void *debug, 74 void *debug,
71 int nr_debug_entries) 75 int nr_debug_entries,
76 void *unwinding,
77 uint32_t unwinding_header_size,
78 uint32_t unwinding_size)
72{ 79{
73 int ret, fd; 80 int ret, fd;
74 81
@@ -81,7 +88,8 @@ jit_emit_elf(char *filename,
81 return -1; 88 return -1;
82 } 89 }
83 90
84 ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries); 91 ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries,
92 unwinding, unwinding_header_size, unwinding_size);
85 93
86 close(fd); 94 close(fd);
87 95
@@ -172,6 +180,12 @@ jit_open(struct jit_buf_desc *jd, const char *name)
172 header.elf_mach, 180 header.elf_mach,
173 jd->use_arch_timestamp); 181 jd->use_arch_timestamp);
174 182
183 if (header.version > JITHEADER_VERSION) {
184 pr_err("wrong jitdump version %u, expected " STR(JITHEADER_VERSION),
185 header.version);
186 goto error;
187 }
188
175 if (header.flags & JITDUMP_FLAGS_RESERVED) { 189 if (header.flags & JITDUMP_FLAGS_RESERVED) {
176 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", 190 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
177 (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED); 191 (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
@@ -263,8 +277,7 @@ jit_get_next_entry(struct jit_buf_desc *jd)
263 return NULL; 277 return NULL;
264 278
265 if (id >= JIT_CODE_MAX) { 279 if (id >= JIT_CODE_MAX) {
266 pr_warning("next_entry: unknown prefix %d, skipping\n", id); 280 pr_warning("next_entry: unknown record type %d, skipping\n", id);
267 return NULL;
268 } 281 }
269 if (bs > jd->bufsize) { 282 if (bs > jd->bufsize) {
270 void *n; 283 void *n;
@@ -296,6 +309,13 @@ jit_get_next_entry(struct jit_buf_desc *jd)
296 } 309 }
297 } 310 }
298 break; 311 break;
312 case JIT_CODE_UNWINDING_INFO:
313 if (jd->needs_bswap) {
314 jr->unwinding.unwinding_size = bswap_64(jr->unwinding.unwinding_size);
315 jr->unwinding.eh_frame_hdr_size = bswap_64(jr->unwinding.eh_frame_hdr_size);
316 jr->unwinding.mapped_size = bswap_64(jr->unwinding.mapped_size);
317 }
318 break;
299 case JIT_CODE_CLOSE: 319 case JIT_CODE_CLOSE:
300 break; 320 break;
301 case JIT_CODE_LOAD: 321 case JIT_CODE_LOAD:
@@ -322,7 +342,8 @@ jit_get_next_entry(struct jit_buf_desc *jd)
322 break; 342 break;
323 case JIT_CODE_MAX: 343 case JIT_CODE_MAX:
324 default: 344 default:
325 return NULL; 345 /* skip unknown record (we have read them) */
346 break;
326 } 347 }
327 return jr; 348 return jr;
328} 349}
@@ -370,7 +391,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
370 u16 idr_size; 391 u16 idr_size;
371 const char *sym; 392 const char *sym;
372 uint32_t count; 393 uint32_t count;
373 int ret, csize; 394 int ret, csize, usize;
374 pid_t pid, tid; 395 pid_t pid, tid;
375 struct { 396 struct {
376 u32 pid, tid; 397 u32 pid, tid;
@@ -380,6 +401,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
380 pid = jr->load.pid; 401 pid = jr->load.pid;
381 tid = jr->load.tid; 402 tid = jr->load.tid;
382 csize = jr->load.code_size; 403 csize = jr->load.code_size;
404 usize = jd->unwinding_mapped_size;
383 addr = jr->load.code_addr; 405 addr = jr->load.code_addr;
384 sym = (void *)((unsigned long)jr + sizeof(jr->load)); 406 sym = (void *)((unsigned long)jr + sizeof(jr->load));
385 code = (unsigned long)jr + jr->load.p.total_size - csize; 407 code = (unsigned long)jr + jr->load.p.total_size - csize;
@@ -400,7 +422,8 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
400 422
401 size = PERF_ALIGN(size, sizeof(u64)); 423 size = PERF_ALIGN(size, sizeof(u64));
402 uaddr = (uintptr_t)code; 424 uaddr = (uintptr_t)code;
403 ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries); 425 ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries,
426 jd->unwinding_data, jd->eh_frame_hdr_size, jd->unwinding_size);
404 427
405 if (jd->debug_data && jd->nr_debug_entries) { 428 if (jd->debug_data && jd->nr_debug_entries) {
406 free(jd->debug_data); 429 free(jd->debug_data);
@@ -408,6 +431,14 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
408 jd->nr_debug_entries = 0; 431 jd->nr_debug_entries = 0;
409 } 432 }
410 433
434 if (jd->unwinding_data && jd->eh_frame_hdr_size) {
435 free(jd->unwinding_data);
436 jd->unwinding_data = NULL;
437 jd->eh_frame_hdr_size = 0;
438 jd->unwinding_mapped_size = 0;
439 jd->unwinding_size = 0;
440 }
441
411 if (ret) { 442 if (ret) {
412 free(event); 443 free(event);
413 return -1; 444 return -1;
@@ -422,7 +453,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
422 453
423 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET; 454 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
424 event->mmap2.start = addr; 455 event->mmap2.start = addr;
425 event->mmap2.len = csize; 456 event->mmap2.len = usize ? ALIGN_8(csize) + usize : csize;
426 event->mmap2.pid = pid; 457 event->mmap2.pid = pid;
427 event->mmap2.tid = tid; 458 event->mmap2.tid = tid;
428 event->mmap2.ino = st.st_ino; 459 event->mmap2.ino = st.st_ino;
@@ -473,6 +504,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
473 char *filename; 504 char *filename;
474 size_t size; 505 size_t size;
475 struct stat st; 506 struct stat st;
507 int usize;
476 u16 idr_size; 508 u16 idr_size;
477 int ret; 509 int ret;
478 pid_t pid, tid; 510 pid_t pid, tid;
@@ -483,6 +515,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
483 515
484 pid = jr->move.pid; 516 pid = jr->move.pid;
485 tid = jr->move.tid; 517 tid = jr->move.tid;
518 usize = jd->unwinding_mapped_size;
486 idr_size = jd->machine->id_hdr_size; 519 idr_size = jd->machine->id_hdr_size;
487 520
488 /* 521 /*
@@ -511,7 +544,8 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
511 (sizeof(event->mmap2.filename) - size) + idr_size); 544 (sizeof(event->mmap2.filename) - size) + idr_size);
512 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET; 545 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
513 event->mmap2.start = jr->move.new_code_addr; 546 event->mmap2.start = jr->move.new_code_addr;
514 event->mmap2.len = jr->move.code_size; 547 event->mmap2.len = usize ? ALIGN_8(jr->move.code_size) + usize
548 : jr->move.code_size;
515 event->mmap2.pid = pid; 549 event->mmap2.pid = pid;
516 event->mmap2.tid = tid; 550 event->mmap2.tid = tid;
517 event->mmap2.ino = st.st_ino; 551 event->mmap2.ino = st.st_ino;
@@ -578,10 +612,35 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
578} 612}
579 613
580static int 614static int
615jit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr)
616{
617 void *unwinding_data;
618 uint32_t unwinding_data_size;
619
620 if (!(jd && jr))
621 return -1;
622
623 unwinding_data_size = jr->prefix.total_size - sizeof(jr->unwinding);
624 unwinding_data = malloc(unwinding_data_size);
625 if (!unwinding_data)
626 return -1;
627
628 memcpy(unwinding_data, &jr->unwinding.unwinding_data,
629 unwinding_data_size);
630
631 jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size;
632 jd->unwinding_size = jr->unwinding.unwinding_size;
633 jd->unwinding_mapped_size = jr->unwinding.mapped_size;
634 jd->unwinding_data = unwinding_data;
635
636 return 0;
637}
638
639static int
581jit_process_dump(struct jit_buf_desc *jd) 640jit_process_dump(struct jit_buf_desc *jd)
582{ 641{
583 union jr_entry *jr; 642 union jr_entry *jr;
584 int ret; 643 int ret = 0;
585 644
586 while ((jr = jit_get_next_entry(jd))) { 645 while ((jr = jit_get_next_entry(jd))) {
587 switch(jr->prefix.id) { 646 switch(jr->prefix.id) {
@@ -594,6 +653,9 @@ jit_process_dump(struct jit_buf_desc *jd)
594 case JIT_CODE_DEBUG_INFO: 653 case JIT_CODE_DEBUG_INFO:
595 ret = jit_repipe_debug_info(jd, jr); 654 ret = jit_repipe_debug_info(jd, jr);
596 break; 655 break;
656 case JIT_CODE_UNWINDING_INFO:
657 ret = jit_repipe_unwinding_info(jd, jr);
658 break;
597 default: 659 default:
598 ret = 0; 660 ret = 0;
599 continue; 661 continue;
diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h
index bcacd20d0c1c..c6b9b67f43bf 100644
--- a/tools/perf/util/jitdump.h
+++ b/tools/perf/util/jitdump.h
@@ -19,6 +19,7 @@
19#define JITHEADER_MAGIC_SW 0x4454694A 19#define JITHEADER_MAGIC_SW 0x4454694A
20 20
21#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7) 21#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7)
22#define ALIGN_8(x) (((x) + 7) & (~7))
22 23
23#define JITHEADER_VERSION 1 24#define JITHEADER_VERSION 1
24 25
@@ -48,6 +49,7 @@ enum jit_record_type {
48 JIT_CODE_MOVE = 1, 49 JIT_CODE_MOVE = 1,
49 JIT_CODE_DEBUG_INFO = 2, 50 JIT_CODE_DEBUG_INFO = 2,
50 JIT_CODE_CLOSE = 3, 51 JIT_CODE_CLOSE = 3,
52 JIT_CODE_UNWINDING_INFO = 4,
51 53
52 JIT_CODE_MAX, 54 JIT_CODE_MAX,
53}; 55};
@@ -101,12 +103,22 @@ struct jr_code_debug_info {
101 struct debug_entry entries[0]; 103 struct debug_entry entries[0];
102}; 104};
103 105
106struct jr_code_unwinding_info {
107 struct jr_prefix p;
108
109 uint64_t unwinding_size;
110 uint64_t eh_frame_hdr_size;
111 uint64_t mapped_size;
112 const char unwinding_data[0];
113};
114
104union jr_entry { 115union jr_entry {
105 struct jr_code_debug_info info; 116 struct jr_code_debug_info info;
106 struct jr_code_close close; 117 struct jr_code_close close;
107 struct jr_code_load load; 118 struct jr_code_load load;
108 struct jr_code_move move; 119 struct jr_code_move move;
109 struct jr_prefix prefix; 120 struct jr_prefix prefix;
121 struct jr_code_unwinding_info unwinding;
110}; 122};
111 123
112static inline struct debug_entry * 124static inline struct debug_entry *
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index bf7216b8731d..b23ff44cf214 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -7,6 +7,7 @@
7#include <limits.h> 7#include <limits.h>
8#include <stdio.h> 8#include <stdio.h>
9#include <stdlib.h> 9#include <stdlib.h>
10#include <linux/err.h>
10#include "debug.h" 11#include "debug.h"
11#include "llvm-utils.h" 12#include "llvm-utils.h"
12#include "config.h" 13#include "config.h"
@@ -282,9 +283,10 @@ static const char *kinc_fetch_script =
282"rm -rf $TMPDIR\n" 283"rm -rf $TMPDIR\n"
283"exit $RET\n"; 284"exit $RET\n";
284 285
285static inline void 286void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
286get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
287{ 287{
288 static char *saved_kbuild_dir;
289 static char *saved_kbuild_include_opts;
288 int err; 290 int err;
289 291
290 if (!kbuild_dir || !kbuild_include_opts) 292 if (!kbuild_dir || !kbuild_include_opts)
@@ -293,10 +295,28 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
293 *kbuild_dir = NULL; 295 *kbuild_dir = NULL;
294 *kbuild_include_opts = NULL; 296 *kbuild_include_opts = NULL;
295 297
298 if (saved_kbuild_dir && saved_kbuild_include_opts &&
299 !IS_ERR(saved_kbuild_dir) && !IS_ERR(saved_kbuild_include_opts)) {
300 *kbuild_dir = strdup(saved_kbuild_dir);
301 *kbuild_include_opts = strdup(saved_kbuild_include_opts);
302
303 if (*kbuild_dir && *kbuild_include_opts)
304 return;
305
306 zfree(kbuild_dir);
307 zfree(kbuild_include_opts);
308 /*
309 * Don't fall through: it may breaks saved_kbuild_dir and
310 * saved_kbuild_include_opts if detect them again when
311 * memory is low.
312 */
313 return;
314 }
315
296 if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) { 316 if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) {
297 pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n"); 317 pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n");
298 pr_debug("Skip kbuild options detection.\n"); 318 pr_debug("Skip kbuild options detection.\n");
299 return; 319 goto errout;
300 } 320 }
301 321
302 err = detect_kbuild_dir(kbuild_dir); 322 err = detect_kbuild_dir(kbuild_dir);
@@ -306,7 +326,7 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
306"Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n" 326"Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n"
307" \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n" 327" \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n"
308" \tdetection.\n\n"); 328" \tdetection.\n\n");
309 return; 329 goto errout;
310 } 330 }
311 331
312 pr_debug("Kernel build dir is set to %s\n", *kbuild_dir); 332 pr_debug("Kernel build dir is set to %s\n", *kbuild_dir);
@@ -325,21 +345,50 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
325 345
326 free(*kbuild_dir); 346 free(*kbuild_dir);
327 *kbuild_dir = NULL; 347 *kbuild_dir = NULL;
328 return; 348 goto errout;
329 } 349 }
330 350
331 pr_debug("include option is set to %s\n", *kbuild_include_opts); 351 pr_debug("include option is set to %s\n", *kbuild_include_opts);
352
353 saved_kbuild_dir = strdup(*kbuild_dir);
354 saved_kbuild_include_opts = strdup(*kbuild_include_opts);
355
356 if (!saved_kbuild_dir || !saved_kbuild_include_opts) {
357 zfree(&saved_kbuild_dir);
358 zfree(&saved_kbuild_include_opts);
359 }
360 return;
361errout:
362 saved_kbuild_dir = ERR_PTR(-EINVAL);
363 saved_kbuild_include_opts = ERR_PTR(-EINVAL);
332} 364}
333 365
334static void 366int llvm__get_nr_cpus(void)
335dump_obj(const char *path, void *obj_buf, size_t size) 367{
368 static int nr_cpus_avail = 0;
369 char serr[STRERR_BUFSIZE];
370
371 if (nr_cpus_avail > 0)
372 return nr_cpus_avail;
373
374 nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
375 if (nr_cpus_avail <= 0) {
376 pr_err(
377"WARNING:\tunable to get available CPUs in this system: %s\n"
378" \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr)));
379 nr_cpus_avail = 128;
380 }
381 return nr_cpus_avail;
382}
383
384void llvm__dump_obj(const char *path, void *obj_buf, size_t size)
336{ 385{
337 char *obj_path = strdup(path); 386 char *obj_path = strdup(path);
338 FILE *fp; 387 FILE *fp;
339 char *p; 388 char *p;
340 389
341 if (!obj_path) { 390 if (!obj_path) {
342 pr_warning("WARNING: No enough memory, skip object dumping\n"); 391 pr_warning("WARNING: Not enough memory, skip object dumping\n");
343 return; 392 return;
344 } 393 }
345 394
@@ -406,15 +455,9 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
406 * This is an optional work. Even it fail we can continue our 455 * This is an optional work. Even it fail we can continue our
407 * work. Needn't to check error return. 456 * work. Needn't to check error return.
408 */ 457 */
409 get_kbuild_opts(&kbuild_dir, &kbuild_include_opts); 458 llvm__get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
410 459
411 nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF); 460 nr_cpus_avail = llvm__get_nr_cpus();
412 if (nr_cpus_avail <= 0) {
413 pr_err(
414"WARNING:\tunable to get available CPUs in this system: %s\n"
415" \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr)));
416 nr_cpus_avail = 128;
417 }
418 snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d", 461 snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
419 nr_cpus_avail); 462 nr_cpus_avail);
420 463
@@ -453,9 +496,6 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
453 free(kbuild_dir); 496 free(kbuild_dir);
454 free(kbuild_include_opts); 497 free(kbuild_include_opts);
455 498
456 if (llvm_param.dump_obj)
457 dump_obj(path, obj_buf, obj_buf_sz);
458
459 if (!p_obj_buf) 499 if (!p_obj_buf)
460 free(obj_buf); 500 free(obj_buf);
461 else 501 else
diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h
index 9f501cef06a1..c87a2a92a88f 100644
--- a/tools/perf/util/llvm-utils.h
+++ b/tools/perf/util/llvm-utils.h
@@ -50,4 +50,10 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, size_t *p_obj_buf_sz);
50 50
51/* This function is for test__llvm() use only */ 51/* This function is for test__llvm() use only */
52int llvm__search_clang(void); 52int llvm__search_clang(void);
53
54/* Following functions are reused by builtin clang support */
55void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts);
56int llvm__get_nr_cpus(void);
57
58void llvm__dump_obj(const char *path, void *obj_buf, size_t size);
53#endif 59#endif
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index df85b9efd80f..9b33bef54581 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1616,7 +1616,11 @@ static int add_callchain_ip(struct thread *thread,
1616 struct symbol **parent, 1616 struct symbol **parent,
1617 struct addr_location *root_al, 1617 struct addr_location *root_al,
1618 u8 *cpumode, 1618 u8 *cpumode,
1619 u64 ip) 1619 u64 ip,
1620 bool branch,
1621 struct branch_flags *flags,
1622 int nr_loop_iter,
1623 int samples)
1620{ 1624{
1621 struct addr_location al; 1625 struct addr_location al;
1622 1626
@@ -1668,7 +1672,8 @@ static int add_callchain_ip(struct thread *thread,
1668 1672
1669 if (symbol_conf.hide_unresolved && al.sym == NULL) 1673 if (symbol_conf.hide_unresolved && al.sym == NULL)
1670 return 0; 1674 return 0;
1671 return callchain_cursor_append(cursor, al.addr, al.map, al.sym); 1675 return callchain_cursor_append(cursor, al.addr, al.map, al.sym,
1676 branch, flags, nr_loop_iter, samples);
1672} 1677}
1673 1678
1674struct branch_info *sample__resolve_bstack(struct perf_sample *sample, 1679struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
@@ -1757,7 +1762,9 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1757 /* LBR only affects the user callchain */ 1762 /* LBR only affects the user callchain */
1758 if (i != chain_nr) { 1763 if (i != chain_nr) {
1759 struct branch_stack *lbr_stack = sample->branch_stack; 1764 struct branch_stack *lbr_stack = sample->branch_stack;
1760 int lbr_nr = lbr_stack->nr, j; 1765 int lbr_nr = lbr_stack->nr, j, k;
1766 bool branch;
1767 struct branch_flags *flags;
1761 /* 1768 /*
1762 * LBR callstack can only get user call chain. 1769 * LBR callstack can only get user call chain.
1763 * The mix_chain_nr is kernel call chain 1770 * The mix_chain_nr is kernel call chain
@@ -1772,23 +1779,41 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1772 1779
1773 for (j = 0; j < mix_chain_nr; j++) { 1780 for (j = 0; j < mix_chain_nr; j++) {
1774 int err; 1781 int err;
1782 branch = false;
1783 flags = NULL;
1784
1775 if (callchain_param.order == ORDER_CALLEE) { 1785 if (callchain_param.order == ORDER_CALLEE) {
1776 if (j < i + 1) 1786 if (j < i + 1)
1777 ip = chain->ips[j]; 1787 ip = chain->ips[j];
1778 else if (j > i + 1) 1788 else if (j > i + 1) {
1779 ip = lbr_stack->entries[j - i - 2].from; 1789 k = j - i - 2;
1780 else 1790 ip = lbr_stack->entries[k].from;
1791 branch = true;
1792 flags = &lbr_stack->entries[k].flags;
1793 } else {
1781 ip = lbr_stack->entries[0].to; 1794 ip = lbr_stack->entries[0].to;
1795 branch = true;
1796 flags = &lbr_stack->entries[0].flags;
1797 }
1782 } else { 1798 } else {
1783 if (j < lbr_nr) 1799 if (j < lbr_nr) {
1784 ip = lbr_stack->entries[lbr_nr - j - 1].from; 1800 k = lbr_nr - j - 1;
1801 ip = lbr_stack->entries[k].from;
1802 branch = true;
1803 flags = &lbr_stack->entries[k].flags;
1804 }
1785 else if (j > lbr_nr) 1805 else if (j > lbr_nr)
1786 ip = chain->ips[i + 1 - (j - lbr_nr)]; 1806 ip = chain->ips[i + 1 - (j - lbr_nr)];
1787 else 1807 else {
1788 ip = lbr_stack->entries[0].to; 1808 ip = lbr_stack->entries[0].to;
1809 branch = true;
1810 flags = &lbr_stack->entries[0].flags;
1811 }
1789 } 1812 }
1790 1813
1791 err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); 1814 err = add_callchain_ip(thread, cursor, parent,
1815 root_al, &cpumode, ip,
1816 branch, flags, 0, 0);
1792 if (err) 1817 if (err)
1793 return (err < 0) ? err : 0; 1818 return (err < 0) ? err : 0;
1794 } 1819 }
@@ -1813,6 +1838,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1813 int i, j, err, nr_entries; 1838 int i, j, err, nr_entries;
1814 int skip_idx = -1; 1839 int skip_idx = -1;
1815 int first_call = 0; 1840 int first_call = 0;
1841 int nr_loop_iter;
1816 1842
1817 if (perf_evsel__has_branch_callstack(evsel)) { 1843 if (perf_evsel__has_branch_callstack(evsel)) {
1818 err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, 1844 err = resolve_lbr_callchain_sample(thread, cursor, sample, parent,
@@ -1868,14 +1894,37 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1868 be[i] = branch->entries[branch->nr - i - 1]; 1894 be[i] = branch->entries[branch->nr - i - 1];
1869 } 1895 }
1870 1896
1897 nr_loop_iter = nr;
1871 nr = remove_loops(be, nr); 1898 nr = remove_loops(be, nr);
1872 1899
1900 /*
1901 * Get the number of iterations.
1902 * It's only approximation, but good enough in practice.
1903 */
1904 if (nr_loop_iter > nr)
1905 nr_loop_iter = nr_loop_iter - nr + 1;
1906 else
1907 nr_loop_iter = 0;
1908
1873 for (i = 0; i < nr; i++) { 1909 for (i = 0; i < nr; i++) {
1874 err = add_callchain_ip(thread, cursor, parent, root_al, 1910 if (i == nr - 1)
1875 NULL, be[i].to); 1911 err = add_callchain_ip(thread, cursor, parent,
1912 root_al,
1913 NULL, be[i].to,
1914 true, &be[i].flags,
1915 nr_loop_iter, 1);
1916 else
1917 err = add_callchain_ip(thread, cursor, parent,
1918 root_al,
1919 NULL, be[i].to,
1920 true, &be[i].flags,
1921 0, 0);
1922
1876 if (!err) 1923 if (!err)
1877 err = add_callchain_ip(thread, cursor, parent, root_al, 1924 err = add_callchain_ip(thread, cursor, parent, root_al,
1878 NULL, be[i].from); 1925 NULL, be[i].from,
1926 true, &be[i].flags,
1927 0, 0);
1879 if (err == -EINVAL) 1928 if (err == -EINVAL)
1880 break; 1929 break;
1881 if (err) 1930 if (err)
@@ -1903,7 +1952,9 @@ check_calls:
1903 if (ip < PERF_CONTEXT_MAX) 1952 if (ip < PERF_CONTEXT_MAX)
1904 ++nr_entries; 1953 ++nr_entries;
1905 1954
1906 err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); 1955 err = add_callchain_ip(thread, cursor, parent,
1956 root_al, &cpumode, ip,
1957 false, NULL, 0, 0);
1907 1958
1908 if (err) 1959 if (err)
1909 return (err < 0) ? err : 0; 1960 return (err < 0) ? err : 0;
@@ -1919,7 +1970,8 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
1919 if (symbol_conf.hide_unresolved && entry->sym == NULL) 1970 if (symbol_conf.hide_unresolved && entry->sym == NULL)
1920 return 0; 1971 return 0;
1921 return callchain_cursor_append(cursor, entry->ip, 1972 return callchain_cursor_append(cursor, entry->ip,
1922 entry->map, entry->sym); 1973 entry->map, entry->sym,
1974 false, NULL, 0, 0);
1923} 1975}
1924 1976
1925static int thread__resolve_callchain_unwind(struct thread *thread, 1977static int thread__resolve_callchain_unwind(struct thread *thread,
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index c662fef95d14..4f9a71c63026 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -682,9 +682,16 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
682 continue; 682 continue;
683 683
684 if (verbose >= 2) { 684 if (verbose >= 2) {
685 fputs("overlapping maps:\n", fp); 685
686 map__fprintf(map, fp); 686 if (use_browser) {
687 map__fprintf(pos, fp); 687 pr_warning("overlapping maps in %s "
688 "(disable tui for more info)\n",
689 map->dso->name);
690 } else {
691 fputs("overlapping maps:\n", fp);
692 map__fprintf(map, fp);
693 map__fprintf(pos, fp);
694 }
688 } 695 }
689 696
690 rb_erase_init(&pos->rb_node, root); 697 rb_erase_init(&pos->rb_node, root);
@@ -702,7 +709,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
702 709
703 before->end = map->start; 710 before->end = map->start;
704 __map_groups__insert(pos->groups, before); 711 __map_groups__insert(pos->groups, before);
705 if (verbose >= 2) 712 if (verbose >= 2 && !use_browser)
706 map__fprintf(before, fp); 713 map__fprintf(before, fp);
707 map__put(before); 714 map__put(before);
708 } 715 }
@@ -717,7 +724,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
717 724
718 after->start = map->end; 725 after->start = map->end;
719 __map_groups__insert(pos->groups, after); 726 __map_groups__insert(pos->groups, after);
720 if (verbose >= 2) 727 if (verbose >= 2 && !use_browser)
721 map__fprintf(after, fp); 728 map__fprintf(after, fp);
722 map__put(after); 729 map__put(after);
723 } 730 }
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
index bbc368e7d1e4..1d4ab53c60ca 100644
--- a/tools/perf/util/mem-events.c
+++ b/tools/perf/util/mem-events.c
@@ -9,6 +9,7 @@
9#include "mem-events.h" 9#include "mem-events.h"
10#include "debug.h" 10#include "debug.h"
11#include "symbol.h" 11#include "symbol.h"
12#include "sort.h"
12 13
13unsigned int perf_mem_events__loads_ldlat = 30; 14unsigned int perf_mem_events__loads_ldlat = 30;
14 15
@@ -268,3 +269,138 @@ int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_in
268 269
269 return i; 270 return i;
270} 271}
272
273int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
274{
275 union perf_mem_data_src *data_src = &mi->data_src;
276 u64 daddr = mi->daddr.addr;
277 u64 op = data_src->mem_op;
278 u64 lvl = data_src->mem_lvl;
279 u64 snoop = data_src->mem_snoop;
280 u64 lock = data_src->mem_lock;
281 int err = 0;
282
283#define HITM_INC(__f) \
284do { \
285 stats->__f++; \
286 stats->tot_hitm++; \
287} while (0)
288
289#define P(a, b) PERF_MEM_##a##_##b
290
291 stats->nr_entries++;
292
293 if (lock & P(LOCK, LOCKED)) stats->locks++;
294
295 if (op & P(OP, LOAD)) {
296 /* load */
297 stats->load++;
298
299 if (!daddr) {
300 stats->ld_noadrs++;
301 return -1;
302 }
303
304 if (lvl & P(LVL, HIT)) {
305 if (lvl & P(LVL, UNC)) stats->ld_uncache++;
306 if (lvl & P(LVL, IO)) stats->ld_io++;
307 if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
308 if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
309 if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
310 if (lvl & P(LVL, L3 )) {
311 if (snoop & P(SNOOP, HITM))
312 HITM_INC(lcl_hitm);
313 else
314 stats->ld_llchit++;
315 }
316
317 if (lvl & P(LVL, LOC_RAM)) {
318 stats->lcl_dram++;
319 if (snoop & P(SNOOP, HIT))
320 stats->ld_shared++;
321 else
322 stats->ld_excl++;
323 }
324
325 if ((lvl & P(LVL, REM_RAM1)) ||
326 (lvl & P(LVL, REM_RAM2))) {
327 stats->rmt_dram++;
328 if (snoop & P(SNOOP, HIT))
329 stats->ld_shared++;
330 else
331 stats->ld_excl++;
332 }
333 }
334
335 if ((lvl & P(LVL, REM_CCE1)) ||
336 (lvl & P(LVL, REM_CCE2))) {
337 if (snoop & P(SNOOP, HIT))
338 stats->rmt_hit++;
339 else if (snoop & P(SNOOP, HITM))
340 HITM_INC(rmt_hitm);
341 }
342
343 if ((lvl & P(LVL, MISS)))
344 stats->ld_miss++;
345
346 } else if (op & P(OP, STORE)) {
347 /* store */
348 stats->store++;
349
350 if (!daddr) {
351 stats->st_noadrs++;
352 return -1;
353 }
354
355 if (lvl & P(LVL, HIT)) {
356 if (lvl & P(LVL, UNC)) stats->st_uncache++;
357 if (lvl & P(LVL, L1 )) stats->st_l1hit++;
358 }
359 if (lvl & P(LVL, MISS))
360 if (lvl & P(LVL, L1)) stats->st_l1miss++;
361 } else {
362 /* unparsable data_src? */
363 stats->noparse++;
364 return -1;
365 }
366
367 if (!mi->daddr.map || !mi->iaddr.map) {
368 stats->nomap++;
369 return -1;
370 }
371
372#undef P
373#undef HITM_INC
374 return err;
375}
376
377void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
378{
379 stats->nr_entries += add->nr_entries;
380
381 stats->locks += add->locks;
382 stats->store += add->store;
383 stats->st_uncache += add->st_uncache;
384 stats->st_noadrs += add->st_noadrs;
385 stats->st_l1hit += add->st_l1hit;
386 stats->st_l1miss += add->st_l1miss;
387 stats->load += add->load;
388 stats->ld_excl += add->ld_excl;
389 stats->ld_shared += add->ld_shared;
390 stats->ld_uncache += add->ld_uncache;
391 stats->ld_io += add->ld_io;
392 stats->ld_miss += add->ld_miss;
393 stats->ld_noadrs += add->ld_noadrs;
394 stats->ld_fbhit += add->ld_fbhit;
395 stats->ld_l1hit += add->ld_l1hit;
396 stats->ld_l2hit += add->ld_l2hit;
397 stats->ld_llchit += add->ld_llchit;
398 stats->lcl_hitm += add->lcl_hitm;
399 stats->rmt_hitm += add->rmt_hitm;
400 stats->tot_hitm += add->tot_hitm;
401 stats->rmt_hit += add->rmt_hit;
402 stats->lcl_dram += add->lcl_dram;
403 stats->rmt_dram += add->rmt_dram;
404 stats->nomap += add->nomap;
405 stats->noparse += add->noparse;
406}
diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h
index 7f69bf9d789d..40f72ee4f42a 100644
--- a/tools/perf/util/mem-events.h
+++ b/tools/perf/util/mem-events.h
@@ -2,6 +2,10 @@
2#define __PERF_MEM_EVENTS_H 2#define __PERF_MEM_EVENTS_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h>
6#include <stdio.h>
7#include <linux/types.h>
8#include "stat.h"
5 9
6struct perf_mem_event { 10struct perf_mem_event {
7 bool record; 11 bool record;
@@ -33,4 +37,38 @@ int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
33 37
34int perf_script__meminfo_scnprintf(char *bf, size_t size, struct mem_info *mem_info); 38int perf_script__meminfo_scnprintf(char *bf, size_t size, struct mem_info *mem_info);
35 39
40struct c2c_stats {
41 u32 nr_entries;
42
43 u32 locks; /* count of 'lock' transactions */
44 u32 store; /* count of all stores in trace */
45 u32 st_uncache; /* stores to uncacheable address */
46 u32 st_noadrs; /* cacheable store with no address */
47 u32 st_l1hit; /* count of stores that hit L1D */
48 u32 st_l1miss; /* count of stores that miss L1D */
49 u32 load; /* count of all loads in trace */
50 u32 ld_excl; /* exclusive loads, rmt/lcl DRAM - snp none/miss */
51 u32 ld_shared; /* shared loads, rmt/lcl DRAM - snp hit */
52 u32 ld_uncache; /* loads to uncacheable address */
53 u32 ld_io; /* loads to io address */
54 u32 ld_miss; /* loads miss */
55 u32 ld_noadrs; /* cacheable load with no address */
56 u32 ld_fbhit; /* count of loads hitting Fill Buffer */
57 u32 ld_l1hit; /* count of loads that hit L1D */
58 u32 ld_l2hit; /* count of loads that hit L2D */
59 u32 ld_llchit; /* count of loads that hit LLC */
60 u32 lcl_hitm; /* count of loads with local HITM */
61 u32 rmt_hitm; /* count of loads with remote HITM */
62 u32 tot_hitm; /* count of loads with local and remote HITM */
63 u32 rmt_hit; /* count of loads with remote hit clean; */
64 u32 lcl_dram; /* count of loads miss to local DRAM */
65 u32 rmt_dram; /* count of loads miss to remote DRAM */
66 u32 nomap; /* count of load/stores with no phys adrs */
67 u32 noparse; /* count of unparsable data sources */
68};
69
70struct hist_entry;
71int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi);
72void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add);
73
36#endif /* __PERF_MEM_EVENTS_H */ 74#endif /* __PERF_MEM_EVENTS_H */
diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c
index afc088dd7d20..38fd11504015 100644
--- a/tools/perf/util/parse-branch-options.c
+++ b/tools/perf/util/parse-branch-options.c
@@ -31,59 +31,51 @@ static const struct branch_mode branch_modes[] = {
31 BRANCH_END 31 BRANCH_END
32}; 32};
33 33
34int 34int parse_branch_str(const char *str, __u64 *mode)
35parse_branch_stack(const struct option *opt, const char *str, int unset)
36{ 35{
37#define ONLY_PLM \ 36#define ONLY_PLM \
38 (PERF_SAMPLE_BRANCH_USER |\ 37 (PERF_SAMPLE_BRANCH_USER |\
39 PERF_SAMPLE_BRANCH_KERNEL |\ 38 PERF_SAMPLE_BRANCH_KERNEL |\
40 PERF_SAMPLE_BRANCH_HV) 39 PERF_SAMPLE_BRANCH_HV)
41 40
42 uint64_t *mode = (uint64_t *)opt->value; 41 int ret = 0;
42 char *p, *s;
43 char *os = NULL;
43 const struct branch_mode *br; 44 const struct branch_mode *br;
44 char *s, *os = NULL, *p;
45 int ret = -1;
46 45
47 if (unset) 46 if (str == NULL) {
47 *mode = PERF_SAMPLE_BRANCH_ANY;
48 return 0; 48 return 0;
49 }
49 50
50 /* 51 /* because str is read-only */
51 * cannot set it twice, -b + --branch-filter for instance 52 s = os = strdup(str);
52 */ 53 if (!s)
53 if (*mode)
54 return -1; 54 return -1;
55 55
56 /* str may be NULL in case no arg is passed to -b */ 56 for (;;) {
57 if (str) { 57 p = strchr(s, ',');
58 /* because str is read-only */ 58 if (p)
59 s = os = strdup(str); 59 *p = '\0';
60 if (!s)
61 return -1;
62
63 for (;;) {
64 p = strchr(s, ',');
65 if (p)
66 *p = '\0';
67
68 for (br = branch_modes; br->name; br++) {
69 if (!strcasecmp(s, br->name))
70 break;
71 }
72 if (!br->name) {
73 ui__warning("unknown branch filter %s,"
74 " check man page\n", s);
75 goto error;
76 }
77
78 *mode |= br->mode;
79
80 if (!p)
81 break;
82 60
83 s = p + 1; 61 for (br = branch_modes; br->name; br++) {
62 if (!strcasecmp(s, br->name))
63 break;
64 }
65 if (!br->name) {
66 ret = -1;
67 pr_warning("unknown branch filter %s,"
68 " check man page\n", s);
69 goto error;
84 } 70 }
71
72 *mode |= br->mode;
73
74 if (!p)
75 break;
76
77 s = p + 1;
85 } 78 }
86 ret = 0;
87 79
88 /* default to any branch */ 80 /* default to any branch */
89 if ((*mode & ~ONLY_PLM) == 0) { 81 if ((*mode & ~ONLY_PLM) == 0) {
@@ -93,3 +85,20 @@ error:
93 free(os); 85 free(os);
94 return ret; 86 return ret;
95} 87}
88
89int
90parse_branch_stack(const struct option *opt, const char *str, int unset)
91{
92 __u64 *mode = (__u64 *)opt->value;
93
94 if (unset)
95 return 0;
96
97 /*
98 * cannot set it twice, -b + --branch-filter for instance
99 */
100 if (*mode)
101 return -1;
102
103 return parse_branch_str(str, mode);
104}
diff --git a/tools/perf/util/parse-branch-options.h b/tools/perf/util/parse-branch-options.h
index b9d9470c2e82..6086fd90eb23 100644
--- a/tools/perf/util/parse-branch-options.h
+++ b/tools/perf/util/parse-branch-options.h
@@ -1,5 +1,6 @@
1#ifndef _PERF_PARSE_BRANCH_OPTIONS_H 1#ifndef _PERF_PARSE_BRANCH_OPTIONS_H
2#define _PERF_PARSE_BRANCH_OPTIONS_H 1 2#define _PERF_PARSE_BRANCH_OPTIONS_H 1
3struct option; 3#include <stdint.h>
4int parse_branch_stack(const struct option *opt, const char *str, int unset); 4int parse_branch_stack(const struct option *opt, const char *str, int unset);
5int parse_branch_str(const char *str, __u64 *mode);
5#endif /* _PERF_PARSE_BRANCH_OPTIONS_H */ 6#endif /* _PERF_PARSE_BRANCH_OPTIONS_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4e778eae1510..3c876b8ba4de 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -22,6 +22,7 @@
22#include "cpumap.h" 22#include "cpumap.h"
23#include "probe-file.h" 23#include "probe-file.h"
24#include "asm/bug.h" 24#include "asm/bug.h"
25#include "util/parse-branch-options.h"
25 26
26#define MAX_NAME_LEN 100 27#define MAX_NAME_LEN 100
27 28
@@ -973,10 +974,13 @@ do { \
973 CHECK_TYPE_VAL(NUM); 974 CHECK_TYPE_VAL(NUM);
974 break; 975 break;
975 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 976 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
976 /* 977 CHECK_TYPE_VAL(STR);
977 * TODO uncomment when the field is available 978 if (strcmp(term->val.str, "no") &&
978 * attr->branch_sample_type = term->val.num; 979 parse_branch_str(term->val.str, &attr->branch_sample_type)) {
979 */ 980 err->str = strdup("invalid branch sample type");
981 err->idx = term->err_val;
982 return -EINVAL;
983 }
980 break; 984 break;
981 case PARSE_EVENTS__TERM_TYPE_TIME: 985 case PARSE_EVENTS__TERM_TYPE_TIME:
982 CHECK_TYPE_VAL(NUM); 986 CHECK_TYPE_VAL(NUM);
@@ -1119,6 +1123,9 @@ do { \
1119 case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: 1123 case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
1120 ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str); 1124 ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str);
1121 break; 1125 break;
1126 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
1127 ADD_CONFIG_TERM(BRANCH, branch, term->val.str);
1128 break;
1122 case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 1129 case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
1123 ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num); 1130 ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num);
1124 break; 1131 break;
diff --git a/tools/perf/util/perf-hooks-list.h b/tools/perf/util/perf-hooks-list.h
new file mode 100644
index 000000000000..2867c07ee84e
--- /dev/null
+++ b/tools/perf/util/perf-hooks-list.h
@@ -0,0 +1,3 @@
1PERF_HOOK(record_start)
2PERF_HOOK(record_end)
3PERF_HOOK(test)
diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c
new file mode 100644
index 000000000000..cb368306b12b
--- /dev/null
+++ b/tools/perf/util/perf-hooks.c
@@ -0,0 +1,88 @@
1/*
2 * perf_hooks.c
3 *
4 * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com>
5 * Copyright (C) 2016 Huawei Inc.
6 */
7
8#include <errno.h>
9#include <stdlib.h>
10#include <setjmp.h>
11#include <linux/err.h>
12#include "util/util.h"
13#include "util/debug.h"
14#include "util/perf-hooks.h"
15
16static sigjmp_buf jmpbuf;
17static const struct perf_hook_desc *current_perf_hook;
18
19void perf_hooks__invoke(const struct perf_hook_desc *desc)
20{
21 if (!(desc && desc->p_hook_func && *desc->p_hook_func))
22 return;
23
24 if (sigsetjmp(jmpbuf, 1)) {
25 pr_warning("Fatal error (SEGFAULT) in perf hook '%s'\n",
26 desc->hook_name);
27 *(current_perf_hook->p_hook_func) = NULL;
28 } else {
29 current_perf_hook = desc;
30 (**desc->p_hook_func)(desc->hook_ctx);
31 }
32 current_perf_hook = NULL;
33}
34
35void perf_hooks__recover(void)
36{
37 if (current_perf_hook)
38 siglongjmp(jmpbuf, 1);
39}
40
41#define PERF_HOOK(name) \
42perf_hook_func_t __perf_hook_func_##name = NULL; \
43struct perf_hook_desc __perf_hook_desc_##name = \
44 {.hook_name = #name, \
45 .p_hook_func = &__perf_hook_func_##name, \
46 .hook_ctx = NULL};
47#include "perf-hooks-list.h"
48#undef PERF_HOOK
49
50#define PERF_HOOK(name) \
51 &__perf_hook_desc_##name,
52
53static struct perf_hook_desc *perf_hooks[] = {
54#include "perf-hooks-list.h"
55};
56#undef PERF_HOOK
57
58int perf_hooks__set_hook(const char *hook_name,
59 perf_hook_func_t hook_func,
60 void *hook_ctx)
61{
62 unsigned int i;
63
64 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) {
65 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0)
66 continue;
67
68 if (*(perf_hooks[i]->p_hook_func))
69 pr_warning("Overwrite existing hook: %s\n", hook_name);
70 *(perf_hooks[i]->p_hook_func) = hook_func;
71 perf_hooks[i]->hook_ctx = hook_ctx;
72 return 0;
73 }
74 return -ENOENT;
75}
76
77perf_hook_func_t perf_hooks__get_hook(const char *hook_name)
78{
79 unsigned int i;
80
81 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) {
82 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0)
83 continue;
84
85 return *(perf_hooks[i]->p_hook_func);
86 }
87 return ERR_PTR(-ENOENT);
88}
diff --git a/tools/perf/util/perf-hooks.h b/tools/perf/util/perf-hooks.h
new file mode 100644
index 000000000000..838d5797bc1e
--- /dev/null
+++ b/tools/perf/util/perf-hooks.h
@@ -0,0 +1,39 @@
1#ifndef PERF_UTIL_PERF_HOOKS_H
2#define PERF_UTIL_PERF_HOOKS_H
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8typedef void (*perf_hook_func_t)(void *ctx);
9struct perf_hook_desc {
10 const char * const hook_name;
11 perf_hook_func_t * const p_hook_func;
12 void *hook_ctx;
13};
14
15extern void perf_hooks__invoke(const struct perf_hook_desc *);
16extern void perf_hooks__recover(void);
17
18#define PERF_HOOK(name) \
19extern struct perf_hook_desc __perf_hook_desc_##name; \
20static inline void perf_hooks__invoke_##name(void) \
21{ \
22 perf_hooks__invoke(&__perf_hook_desc_##name); \
23}
24
25#include "perf-hooks-list.h"
26#undef PERF_HOOK
27
28extern int
29perf_hooks__set_hook(const char *hook_name,
30 perf_hook_func_t hook_func,
31 void *hook_ctx);
32
33extern perf_hook_func_t
34perf_hooks__get_hook(const char *hook_name);
35
36#ifdef __cplusplus
37}
38#endif
39#endif
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b1474dcadfa2..dc6ccaa4e927 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -504,6 +504,7 @@ static void pmu_add_cpu_aliases(struct list_head *head)
504 struct pmu_events_map *map; 504 struct pmu_events_map *map;
505 struct pmu_event *pe; 505 struct pmu_event *pe;
506 char *cpuid; 506 char *cpuid;
507 static bool printed;
507 508
508 cpuid = getenv("PERF_CPUID"); 509 cpuid = getenv("PERF_CPUID");
509 if (cpuid) 510 if (cpuid)
@@ -513,7 +514,10 @@ static void pmu_add_cpu_aliases(struct list_head *head)
513 if (!cpuid) 514 if (!cpuid)
514 return; 515 return;
515 516
516 pr_debug("Using CPUID %s\n", cpuid); 517 if (!printed) {
518 pr_debug("Using CPUID %s\n", cpuid);
519 printed = true;
520 }
517 521
518 i = 0; 522 i = 0;
519 while (1) { 523 while (1) {
@@ -1135,9 +1139,11 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
1135 bool is_cpu = !strcmp(pmu->name, "cpu"); 1139 bool is_cpu = !strcmp(pmu->name, "cpu");
1136 1140
1137 if (event_glob != NULL && 1141 if (event_glob != NULL &&
1138 !(strglobmatch(name, event_glob) || 1142 !(strglobmatch_nocase(name, event_glob) ||
1139 (!is_cpu && strglobmatch(alias->name, 1143 (!is_cpu && strglobmatch_nocase(alias->name,
1140 event_glob)))) 1144 event_glob)) ||
1145 (alias->topic &&
1146 strglobmatch_nocase(alias->topic, event_glob))))
1141 continue; 1147 continue;
1142 1148
1143 if (is_cpu && !name_only && !alias->desc) 1149 if (is_cpu && !name_only && !alias->desc)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 8091d15113f7..5d4e94061402 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -18,6 +18,8 @@ struct probe_conf {
18extern struct probe_conf probe_conf; 18extern struct probe_conf probe_conf;
19extern bool probe_event_dry_run; 19extern bool probe_event_dry_run;
20 20
21struct symbol;
22
21/* kprobe-tracer and uprobe-tracer tracing point */ 23/* kprobe-tracer and uprobe-tracer tracing point */
22struct probe_trace_point { 24struct probe_trace_point {
23 char *realname; /* function real name (if needed) */ 25 char *realname; /* function real name (if needed) */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index b7d4f4aeee61..0546a4304347 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -18,6 +18,7 @@ util/thread_map.c
18util/util.c 18util/util.c
19util/xyarray.c 19util/xyarray.c
20util/cgroup.c 20util/cgroup.c
21util/parse-branch-options.c
21util/rblist.c 22util/rblist.c
22util/counts.c 23util/counts.c
23util/strlist.c 24util/strlist.c
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index 639d1da2f978..293534c1a474 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -54,7 +54,7 @@ int sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
54 break; 54 break;
55 ret = sq_quote_buf(dst, argv[i]); 55 ret = sq_quote_buf(dst, argv[i]);
56 if (maxlen && dst->len > maxlen) 56 if (maxlen && dst->len > maxlen)
57 die("Too many or long arguments"); 57 return -ENOSPC;
58 } 58 }
59 return ret; 59 return ret;
60} 60}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5d61242a6e64..f268201048a0 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -2025,20 +2025,10 @@ out_delete_map:
2025void perf_session__fprintf_info(struct perf_session *session, FILE *fp, 2025void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
2026 bool full) 2026 bool full)
2027{ 2027{
2028 struct stat st;
2029 int fd, ret;
2030
2031 if (session == NULL || fp == NULL) 2028 if (session == NULL || fp == NULL)
2032 return; 2029 return;
2033 2030
2034 fd = perf_data_file__fd(session->file);
2035
2036 ret = fstat(fd, &st);
2037 if (ret == -1)
2038 return;
2039
2040 fprintf(fp, "# ========\n"); 2031 fprintf(fp, "# ========\n");
2041 fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
2042 perf_header__fprintf_info(session, fp, full); 2032 perf_header__fprintf_info(session, fp, full);
2043 fprintf(fp, "# ========\n#\n"); 2033 fprintf(fp, "# ========\n#\n");
2044} 2034}
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 452e15a10dd2..df622f4e301e 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -315,7 +315,7 @@ struct sort_entry sort_sym = {
315 315
316/* --sort srcline */ 316/* --sort srcline */
317 317
318static char *hist_entry__get_srcline(struct hist_entry *he) 318char *hist_entry__get_srcline(struct hist_entry *he)
319{ 319{
320 struct map *map = he->ms.map; 320 struct map *map = he->ms.map;
321 321
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 099c97557d33..7aff317fc7c4 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -280,4 +280,5 @@ int64_t
280sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right); 280sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right);
281int64_t 281int64_t
282sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right); 282sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right);
283char *hist_entry__get_srcline(struct hist_entry *he);
283#endif /* __PERF_SORT_H */ 284#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 7f7e072be746..d8dfaf64b32e 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -193,7 +193,8 @@ error:
193} 193}
194 194
195/* Glob/lazy pattern matching */ 195/* Glob/lazy pattern matching */
196static bool __match_glob(const char *str, const char *pat, bool ignore_space) 196static bool __match_glob(const char *str, const char *pat, bool ignore_space,
197 bool case_ins)
197{ 198{
198 while (*str && *pat && *pat != '*') { 199 while (*str && *pat && *pat != '*') {
199 if (ignore_space) { 200 if (ignore_space) {
@@ -219,8 +220,13 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
219 return false; 220 return false;
220 else if (*pat == '\\') /* Escaped char match as normal char */ 221 else if (*pat == '\\') /* Escaped char match as normal char */
221 pat++; 222 pat++;
222 if (*str++ != *pat++) 223 if (case_ins) {
224 if (tolower(*str) != tolower(*pat))
225 return false;
226 } else if (*str != *pat)
223 return false; 227 return false;
228 str++;
229 pat++;
224 } 230 }
225 /* Check wild card */ 231 /* Check wild card */
226 if (*pat == '*') { 232 if (*pat == '*') {
@@ -229,7 +235,7 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
229 if (!*pat) /* Tail wild card matches all */ 235 if (!*pat) /* Tail wild card matches all */
230 return true; 236 return true;
231 while (*str) 237 while (*str)
232 if (__match_glob(str++, pat, ignore_space)) 238 if (__match_glob(str++, pat, ignore_space, case_ins))
233 return true; 239 return true;
234 } 240 }
235 return !*str && !*pat; 241 return !*str && !*pat;
@@ -249,7 +255,12 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
249 */ 255 */
250bool strglobmatch(const char *str, const char *pat) 256bool strglobmatch(const char *str, const char *pat)
251{ 257{
252 return __match_glob(str, pat, false); 258 return __match_glob(str, pat, false, false);
259}
260
261bool strglobmatch_nocase(const char *str, const char *pat)
262{
263 return __match_glob(str, pat, false, true);
253} 264}
254 265
255/** 266/**
@@ -262,7 +273,7 @@ bool strglobmatch(const char *str, const char *pat)
262 */ 273 */
263bool strlazymatch(const char *str, const char *pat) 274bool strlazymatch(const char *str, const char *pat)
264{ 275{
265 return __match_glob(str, pat, true); 276 return __match_glob(str, pat, true, false);
266} 277}
267 278
268/** 279/**
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index aecff69a510d..dc93940de351 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1459,7 +1459,8 @@ int dso__load(struct dso *dso, struct map *map)
1459 * Read the build id if possible. This is required for 1459 * Read the build id if possible. This is required for
1460 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 1460 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
1461 */ 1461 */
1462 if (is_regular_file(dso->long_name) && 1462 if (!dso->has_build_id &&
1463 is_regular_file(dso->long_name) &&
1463 filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) 1464 filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
1464 dso__set_build_id(dso, build_id); 1465 dso__set_build_id(dso, build_id);
1465 1466
@@ -1962,7 +1963,7 @@ static bool symbol__read_kptr_restrict(void)
1962 char line[8]; 1963 char line[8];
1963 1964
1964 if (fgets(line, sizeof(line), fp) != NULL) 1965 if (fgets(line, sizeof(line), fp) != NULL)
1965 value = (geteuid() != 0) ? 1966 value = ((geteuid() != 0) || (getuid() != 0)) ?
1966 (atoi(line) != 0) : 1967 (atoi(line) != 0) :
1967 (atoi(line) == 2); 1968 (atoi(line) == 2);
1968 1969
@@ -2032,6 +2033,10 @@ int symbol__init(struct perf_env *env)
2032 symbol_conf.sym_list_str, "symbol") < 0) 2033 symbol_conf.sym_list_str, "symbol") < 0)
2033 goto out_free_tid_list; 2034 goto out_free_tid_list;
2034 2035
2036 if (setup_list(&symbol_conf.bt_stop_list,
2037 symbol_conf.bt_stop_list_str, "symbol") < 0)
2038 goto out_free_sym_list;
2039
2035 /* 2040 /*
2036 * A path to symbols of "/" is identical to "" 2041 * A path to symbols of "/" is identical to ""
2037 * reset here for simplicity. 2042 * reset here for simplicity.
@@ -2049,6 +2054,8 @@ int symbol__init(struct perf_env *env)
2049 symbol_conf.initialized = true; 2054 symbol_conf.initialized = true;
2050 return 0; 2055 return 0;
2051 2056
2057out_free_sym_list:
2058 strlist__delete(symbol_conf.sym_list);
2052out_free_tid_list: 2059out_free_tid_list:
2053 intlist__delete(symbol_conf.tid_list); 2060 intlist__delete(symbol_conf.tid_list);
2054out_free_pid_list: 2061out_free_pid_list:
@@ -2064,6 +2071,7 @@ void symbol__exit(void)
2064{ 2071{
2065 if (!symbol_conf.initialized) 2072 if (!symbol_conf.initialized)
2066 return; 2073 return;
2074 strlist__delete(symbol_conf.bt_stop_list);
2067 strlist__delete(symbol_conf.sym_list); 2075 strlist__delete(symbol_conf.sym_list);
2068 strlist__delete(symbol_conf.dso_list); 2076 strlist__delete(symbol_conf.dso_list);
2069 strlist__delete(symbol_conf.comm_list); 2077 strlist__delete(symbol_conf.comm_list);
@@ -2071,6 +2079,7 @@ void symbol__exit(void)
2071 intlist__delete(symbol_conf.pid_list); 2079 intlist__delete(symbol_conf.pid_list);
2072 vmlinux_path__exit(); 2080 vmlinux_path__exit();
2073 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 2081 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2082 symbol_conf.bt_stop_list = NULL;
2074 symbol_conf.initialized = false; 2083 symbol_conf.initialized = false;
2075} 2084}
2076 2085
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index d964844eb314..6c358b7ed336 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -58,6 +58,7 @@ struct symbol {
58 u16 namelen; 58 u16 namelen;
59 u8 binding; 59 u8 binding;
60 u8 idle:1; 60 u8 idle:1;
61 u8 ignore:1;
61 u8 arch_sym; 62 u8 arch_sym;
62 char name[0]; 63 char name[0];
63}; 64};
@@ -100,6 +101,7 @@ struct symbol_conf {
100 show_total_period, 101 show_total_period,
101 use_callchain, 102 use_callchain,
102 cumulate_callchain, 103 cumulate_callchain,
104 show_branchflag_count,
103 exclude_other, 105 exclude_other,
104 show_cpu_utilization, 106 show_cpu_utilization,
105 initialized, 107 initialized,
@@ -130,14 +132,16 @@ struct symbol_conf {
130 *pid_list_str, 132 *pid_list_str,
131 *tid_list_str, 133 *tid_list_str,
132 *sym_list_str, 134 *sym_list_str,
133 *col_width_list_str; 135 *col_width_list_str,
136 *bt_stop_list_str;
134 struct strlist *dso_list, 137 struct strlist *dso_list,
135 *comm_list, 138 *comm_list,
136 *sym_list, 139 *sym_list,
137 *dso_from_list, 140 *dso_from_list,
138 *dso_to_list, 141 *dso_to_list,
139 *sym_from_list, 142 *sym_from_list,
140 *sym_to_list; 143 *sym_to_list,
144 *bt_stop_list;
141 struct intlist *pid_list, 145 struct intlist *pid_list,
142 *tid_list; 146 *tid_list;
143 const char *symfs; 147 const char *symfs;
@@ -281,7 +285,8 @@ int symbol__annotation_init(void);
281struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); 285struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
282size_t __symbol__fprintf_symname_offs(const struct symbol *sym, 286size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
283 const struct addr_location *al, 287 const struct addr_location *al,
284 bool unknown_as_addr, FILE *fp); 288 bool unknown_as_addr,
289 bool print_offsets, FILE *fp);
285size_t symbol__fprintf_symname_offs(const struct symbol *sym, 290size_t symbol__fprintf_symname_offs(const struct symbol *sym,
286 const struct addr_location *al, FILE *fp); 291 const struct addr_location *al, FILE *fp);
287size_t __symbol__fprintf_symname(const struct symbol *sym, 292size_t __symbol__fprintf_symname(const struct symbol *sym,
diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c
index a680bdaa65dc..7c6b33e8e2d2 100644
--- a/tools/perf/util/symbol_fprintf.c
+++ b/tools/perf/util/symbol_fprintf.c
@@ -15,14 +15,15 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp)
15 15
16size_t __symbol__fprintf_symname_offs(const struct symbol *sym, 16size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
17 const struct addr_location *al, 17 const struct addr_location *al,
18 bool unknown_as_addr, FILE *fp) 18 bool unknown_as_addr,
19 bool print_offsets, FILE *fp)
19{ 20{
20 unsigned long offset; 21 unsigned long offset;
21 size_t length; 22 size_t length;
22 23
23 if (sym && sym->name) { 24 if (sym && sym->name) {
24 length = fprintf(fp, "%s", sym->name); 25 length = fprintf(fp, "%s", sym->name);
25 if (al) { 26 if (al && print_offsets) {
26 if (al->addr < sym->end) 27 if (al->addr < sym->end)
27 offset = al->addr - sym->start; 28 offset = al->addr - sym->start;
28 else 29 else
@@ -40,19 +41,19 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
40 const struct addr_location *al, 41 const struct addr_location *al,
41 FILE *fp) 42 FILE *fp)
42{ 43{
43 return __symbol__fprintf_symname_offs(sym, al, false, fp); 44 return __symbol__fprintf_symname_offs(sym, al, false, true, fp);
44} 45}
45 46
46size_t __symbol__fprintf_symname(const struct symbol *sym, 47size_t __symbol__fprintf_symname(const struct symbol *sym,
47 const struct addr_location *al, 48 const struct addr_location *al,
48 bool unknown_as_addr, FILE *fp) 49 bool unknown_as_addr, FILE *fp)
49{ 50{
50 return __symbol__fprintf_symname_offs(sym, al, unknown_as_addr, fp); 51 return __symbol__fprintf_symname_offs(sym, al, unknown_as_addr, false, fp);
51} 52}
52 53
53size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 54size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
54{ 55{
55 return __symbol__fprintf_symname_offs(sym, NULL, false, fp); 56 return __symbol__fprintf_symname_offs(sym, NULL, false, false, fp);
56} 57}
57 58
58size_t dso__fprintf_symbols_by_name(struct dso *dso, 59size_t dso__fprintf_symbols_by_name(struct dso *dso,
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 40585f5b7027..f9eab200fd75 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -448,3 +448,25 @@ bool thread_map__has(struct thread_map *threads, pid_t pid)
448 448
449 return false; 449 return false;
450} 450}
451
452int thread_map__remove(struct thread_map *threads, int idx)
453{
454 int i;
455
456 if (threads->nr < 1)
457 return -EINVAL;
458
459 if (idx >= threads->nr)
460 return -EINVAL;
461
462 /*
463 * Free the 'idx' item and shift the rest up.
464 */
465 free(threads->map[idx].comm);
466
467 for (i = idx; i < threads->nr - 1; i++)
468 threads->map[i] = threads->map[i + 1];
469
470 threads->nr--;
471 return 0;
472}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index bd3b971588da..ea0ef08c6303 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -58,4 +58,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread)
58 58
59void thread_map__read_comms(struct thread_map *threads); 59void thread_map__read_comms(struct thread_map *threads);
60bool thread_map__has(struct thread_map *threads, pid_t pid); 60bool thread_map__has(struct thread_map *threads, pid_t pid);
61int thread_map__remove(struct thread_map *threads, int idx);
61#endif /* __PERF_THREAD_MAP_H */ 62#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c
new file mode 100644
index 000000000000..d1b21c72206d
--- /dev/null
+++ b/tools/perf/util/time-utils.c
@@ -0,0 +1,119 @@
1#include <stdlib.h>
2#include <string.h>
3#include <sys/time.h>
4#include <linux/time64.h>
5#include <time.h>
6#include <errno.h>
7#include <inttypes.h>
8
9#include "perf.h"
10#include "debug.h"
11#include "time-utils.h"
12
13int parse_nsec_time(const char *str, u64 *ptime)
14{
15 u64 time_sec, time_nsec;
16 char *end;
17
18 time_sec = strtoul(str, &end, 10);
19 if (*end != '.' && *end != '\0')
20 return -1;
21
22 if (*end == '.') {
23 int i;
24 char nsec_buf[10];
25
26 if (strlen(++end) > 9)
27 return -1;
28
29 strncpy(nsec_buf, end, 9);
30 nsec_buf[9] = '\0';
31
32 /* make it nsec precision */
33 for (i = strlen(nsec_buf); i < 9; i++)
34 nsec_buf[i] = '0';
35
36 time_nsec = strtoul(nsec_buf, &end, 10);
37 if (*end != '\0')
38 return -1;
39 } else
40 time_nsec = 0;
41
42 *ptime = time_sec * NSEC_PER_SEC + time_nsec;
43 return 0;
44}
45
46static int parse_timestr_sec_nsec(struct perf_time_interval *ptime,
47 char *start_str, char *end_str)
48{
49 if (start_str && (*start_str != '\0') &&
50 (parse_nsec_time(start_str, &ptime->start) != 0)) {
51 return -1;
52 }
53
54 if (end_str && (*end_str != '\0') &&
55 (parse_nsec_time(end_str, &ptime->end) != 0)) {
56 return -1;
57 }
58
59 return 0;
60}
61
62int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr)
63{
64 char *start_str, *end_str;
65 char *d, *str;
66 int rc = 0;
67
68 if (ostr == NULL || *ostr == '\0')
69 return 0;
70
71 /* copy original string because we need to modify it */
72 str = strdup(ostr);
73 if (str == NULL)
74 return -ENOMEM;
75
76 ptime->start = 0;
77 ptime->end = 0;
78
79 /* str has the format: <start>,<stop>
80 * variations: <start>,
81 * ,<stop>
82 * ,
83 */
84 start_str = str;
85 d = strchr(start_str, ',');
86 if (d) {
87 *d = '\0';
88 ++d;
89 }
90 end_str = d;
91
92 rc = parse_timestr_sec_nsec(ptime, start_str, end_str);
93
94 free(str);
95
96 /* make sure end time is after start time if it was given */
97 if (rc == 0 && ptime->end && ptime->end < ptime->start)
98 return -EINVAL;
99
100 pr_debug("start time %" PRIu64 ", ", ptime->start);
101 pr_debug("end time %" PRIu64 "\n", ptime->end);
102
103 return rc;
104}
105
106bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp)
107{
108 /* if time is not set don't drop sample */
109 if (timestamp == 0)
110 return false;
111
112 /* otherwise compare sample time to time window */
113 if ((ptime->start && timestamp < ptime->start) ||
114 (ptime->end && timestamp > ptime->end)) {
115 return true;
116 }
117
118 return false;
119}
diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h
new file mode 100644
index 000000000000..c1f197c4af6c
--- /dev/null
+++ b/tools/perf/util/time-utils.h
@@ -0,0 +1,14 @@
1#ifndef _TIME_UTILS_H_
2#define _TIME_UTILS_H_
3
4struct perf_time_interval {
5 u64 start, end;
6};
7
8int parse_nsec_time(const char *str, u64 *ptime);
9
10int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr);
11
12bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp);
13
14#endif
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 9df61059a85d..0ac9077f62a2 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -25,6 +25,7 @@
25#include <errno.h> 25#include <errno.h>
26 26
27#include "../perf.h" 27#include "../perf.h"
28#include "debug.h"
28#include "util.h" 29#include "util.h"
29#include "trace-event.h" 30#include "trace-event.h"
30 31
@@ -86,16 +87,15 @@ struct scripting_ops python_scripting_unsupported_ops = {
86 87
87static void register_python_scripting(struct scripting_ops *scripting_ops) 88static void register_python_scripting(struct scripting_ops *scripting_ops)
88{ 89{
89 int err; 90 if (scripting_context == NULL)
90 err = script_spec_register("Python", scripting_ops); 91 scripting_context = malloc(sizeof(*scripting_context));
91 if (err) 92
92 die("error registering Python script extension"); 93 if (scripting_context == NULL ||
93 94 script_spec_register("Python", scripting_ops) ||
94 err = script_spec_register("py", scripting_ops); 95 script_spec_register("py", scripting_ops)) {
95 if (err) 96 pr_err("Error registering Python script extension: disabling it\n");
96 die("error registering py script extension"); 97 zfree(&scripting_context);
97 98 }
98 scripting_context = malloc(sizeof(struct scripting_context));
99} 99}
100 100
101#ifdef NO_LIBPYTHON 101#ifdef NO_LIBPYTHON
@@ -150,16 +150,15 @@ struct scripting_ops perl_scripting_unsupported_ops = {
150 150
151static void register_perl_scripting(struct scripting_ops *scripting_ops) 151static void register_perl_scripting(struct scripting_ops *scripting_ops)
152{ 152{
153 int err; 153 if (scripting_context == NULL)
154 err = script_spec_register("Perl", scripting_ops); 154 scripting_context = malloc(sizeof(*scripting_context));
155 if (err) 155
156 die("error registering Perl script extension"); 156 if (scripting_context == NULL ||
157 157 script_spec_register("Perl", scripting_ops) ||
158 err = script_spec_register("pl", scripting_ops); 158 script_spec_register("pl", scripting_ops)) {
159 if (err) 159 pr_err("Error registering Perl script extension: disabling it\n");
160 die("error registering pl script extension"); 160 zfree(&scripting_context);
161 161 }
162 scripting_context = malloc(sizeof(struct scripting_context));
163} 162}
164 163
165#ifdef NO_LIBPERL 164#ifdef NO_LIBPERL
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 20c2e5743903..6fec84dff3f7 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -357,8 +357,8 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
357 di.format = UNW_INFO_FORMAT_REMOTE_TABLE; 357 di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
358 di.start_ip = map->start; 358 di.start_ip = map->start;
359 di.end_ip = map->end; 359 di.end_ip = map->end;
360 di.u.rti.segbase = map->start + segbase; 360 di.u.rti.segbase = map->start + segbase - map->pgoff;
361 di.u.rti.table_data = map->start + table_data; 361 di.u.rti.table_data = map->start + table_data - map->pgoff;
362 di.u.rti.table_len = fde_count * sizeof(struct table_entry) 362 di.u.rti.table_len = fde_count * sizeof(struct table_entry)
363 / sizeof(unw_word_t); 363 / sizeof(unw_word_t);
364 ret = dwarf_search_unwind_table(as, ip, &di, pi, 364 ret = dwarf_search_unwind_table(as, ip, &di, pi,
diff --git a/tools/perf/util/util-cxx.h b/tools/perf/util/util-cxx.h
new file mode 100644
index 000000000000..0e0e019c9f34
--- /dev/null
+++ b/tools/perf/util/util-cxx.h
@@ -0,0 +1,26 @@
1/*
2 * Support C++ source use utilities defined in util.h
3 */
4
5#ifndef PERF_UTIL_UTIL_CXX_H
6#define PERF_UTIL_UTIL_CXX_H
7
8#ifdef __cplusplus
9extern "C" {
10#endif
11
12/*
13 * Now 'new' is the only C++ keyword found in util.h:
14 * in tools/include/linux/rbtree.h
15 *
16 * Other keywords, like class and delete, should be
17 * redefined if necessary.
18 */
19#define new _new
20#include "util.h"
21#undef new
22
23#ifdef __cplusplus
24}
25#endif
26#endif
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 85c56800f17a..9ddd98827d12 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -400,37 +400,12 @@ void sighandler_dump_stack(int sig)
400 raise(sig); 400 raise(sig);
401} 401}
402 402
403int parse_nsec_time(const char *str, u64 *ptime) 403int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
404{ 404{
405 u64 time_sec, time_nsec; 405 u64 sec = timestamp / NSEC_PER_SEC;
406 char *end; 406 u64 usec = (timestamp % NSEC_PER_SEC) / NSEC_PER_USEC;
407 407
408 time_sec = strtoul(str, &end, 10); 408 return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
409 if (*end != '.' && *end != '\0')
410 return -1;
411
412 if (*end == '.') {
413 int i;
414 char nsec_buf[10];
415
416 if (strlen(++end) > 9)
417 return -1;
418
419 strncpy(nsec_buf, end, 9);
420 nsec_buf[9] = '\0';
421
422 /* make it nsec precision */
423 for (i = strlen(nsec_buf); i < 9; i++)
424 nsec_buf[i] = '0';
425
426 time_nsec = strtoul(nsec_buf, &end, 10);
427 if (*end != '\0')
428 return -1;
429 } else
430 time_nsec = 0;
431
432 *ptime = time_sec * NSEC_PER_SEC + time_nsec;
433 return 0;
434} 409}
435 410
436unsigned long parse_tag_value(const char *str, struct parse_tag *tags) 411unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
@@ -629,12 +604,63 @@ bool find_process(const char *name)
629 return ret ? false : true; 604 return ret ? false : true;
630} 605}
631 606
607static int
608fetch_ubuntu_kernel_version(unsigned int *puint)
609{
610 ssize_t len;
611 size_t line_len = 0;
612 char *ptr, *line = NULL;
613 int version, patchlevel, sublevel, err;
614 FILE *vsig = fopen("/proc/version_signature", "r");
615
616 if (!vsig) {
617 pr_debug("Open /proc/version_signature failed: %s\n",
618 strerror(errno));
619 return -1;
620 }
621
622 len = getline(&line, &line_len, vsig);
623 fclose(vsig);
624 err = -1;
625 if (len <= 0) {
626 pr_debug("Reading from /proc/version_signature failed: %s\n",
627 strerror(errno));
628 goto errout;
629 }
630
631 ptr = strrchr(line, ' ');
632 if (!ptr) {
633 pr_debug("Parsing /proc/version_signature failed: %s\n", line);
634 goto errout;
635 }
636
637 err = sscanf(ptr + 1, "%d.%d.%d",
638 &version, &patchlevel, &sublevel);
639 if (err != 3) {
640 pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
641 line);
642 goto errout;
643 }
644
645 if (puint)
646 *puint = (version << 16) + (patchlevel << 8) + sublevel;
647 err = 0;
648errout:
649 free(line);
650 return err;
651}
652
632int 653int
633fetch_kernel_version(unsigned int *puint, char *str, 654fetch_kernel_version(unsigned int *puint, char *str,
634 size_t str_size) 655 size_t str_size)
635{ 656{
636 struct utsname utsname; 657 struct utsname utsname;
637 int version, patchlevel, sublevel, err; 658 int version, patchlevel, sublevel, err;
659 bool int_ver_ready = false;
660
661 if (access("/proc/version_signature", R_OK) == 0)
662 if (!fetch_ubuntu_kernel_version(puint))
663 int_ver_ready = true;
638 664
639 if (uname(&utsname)) 665 if (uname(&utsname))
640 return -1; 666 return -1;
@@ -648,12 +674,12 @@ fetch_kernel_version(unsigned int *puint, char *str,
648 &version, &patchlevel, &sublevel); 674 &version, &patchlevel, &sublevel);
649 675
650 if (err != 3) { 676 if (err != 3) {
651 pr_debug("Unablt to get kernel version from uname '%s'\n", 677 pr_debug("Unable to get kernel version from uname '%s'\n",
652 utsname.release); 678 utsname.release);
653 return -1; 679 return -1;
654 } 680 }
655 681
656 if (puint) 682 if (puint && !int_ver_ready)
657 *puint = (version << 16) + (patchlevel << 8) + sublevel; 683 *puint = (version << 16) + (patchlevel << 8) + sublevel;
658 return 0; 684 return 0;
659} 685}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 43899e0d6fa1..1d639e38aa82 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -179,8 +179,6 @@ static inline void *zalloc(size_t size)
179#undef tolower 179#undef tolower
180#undef toupper 180#undef toupper
181 181
182int parse_nsec_time(const char *str, u64 *ptime);
183
184extern unsigned char sane_ctype[256]; 182extern unsigned char sane_ctype[256];
185#define GIT_SPACE 0x01 183#define GIT_SPACE 0x01
186#define GIT_DIGIT 0x02 184#define GIT_DIGIT 0x02
@@ -222,6 +220,7 @@ s64 perf_atoll(const char *str);
222char **argv_split(const char *str, int *argcp); 220char **argv_split(const char *str, int *argcp);
223void argv_free(char **argv); 221void argv_free(char **argv);
224bool strglobmatch(const char *str, const char *pat); 222bool strglobmatch(const char *str, const char *pat);
223bool strglobmatch_nocase(const char *str, const char *pat);
225bool strlazymatch(const char *str, const char *pat); 224bool strlazymatch(const char *str, const char *pat);
226static inline bool strisglob(const char *str) 225static inline bool strisglob(const char *str)
227{ 226{
@@ -361,4 +360,7 @@ extern int sched_getcpu(void);
361#endif 360#endif
362 361
363int is_printable_array(char *p, unsigned int len); 362int is_printable_array(char *p, unsigned int len);
363
364int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
365
364#endif /* GIT_COMPAT_UTIL_H */ 366#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 0fb3c1fcd3e6..5074be4ed467 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -2,15 +2,18 @@
2 2
3#include "util.h" 3#include "util.h"
4#include "values.h" 4#include "values.h"
5#include "debug.h"
5 6
6void perf_read_values_init(struct perf_read_values *values) 7int perf_read_values_init(struct perf_read_values *values)
7{ 8{
8 values->threads_max = 16; 9 values->threads_max = 16;
9 values->pid = malloc(values->threads_max * sizeof(*values->pid)); 10 values->pid = malloc(values->threads_max * sizeof(*values->pid));
10 values->tid = malloc(values->threads_max * sizeof(*values->tid)); 11 values->tid = malloc(values->threads_max * sizeof(*values->tid));
11 values->value = malloc(values->threads_max * sizeof(*values->value)); 12 values->value = malloc(values->threads_max * sizeof(*values->value));
12 if (!values->pid || !values->tid || !values->value) 13 if (!values->pid || !values->tid || !values->value) {
13 die("failed to allocate read_values threads arrays"); 14 pr_debug("failed to allocate read_values threads arrays");
15 goto out_free_pid;
16 }
14 values->threads = 0; 17 values->threads = 0;
15 18
16 values->counters_max = 16; 19 values->counters_max = 16;
@@ -18,9 +21,22 @@ void perf_read_values_init(struct perf_read_values *values)
18 * sizeof(*values->counterrawid)); 21 * sizeof(*values->counterrawid));
19 values->countername = malloc(values->counters_max 22 values->countername = malloc(values->counters_max
20 * sizeof(*values->countername)); 23 * sizeof(*values->countername));
21 if (!values->counterrawid || !values->countername) 24 if (!values->counterrawid || !values->countername) {
22 die("failed to allocate read_values counters arrays"); 25 pr_debug("failed to allocate read_values counters arrays");
26 goto out_free_counter;
27 }
23 values->counters = 0; 28 values->counters = 0;
29
30 return 0;
31
32out_free_counter:
33 zfree(&values->counterrawid);
34 zfree(&values->countername);
35out_free_pid:
36 zfree(&values->pid);
37 zfree(&values->tid);
38 zfree(&values->value);
39 return -ENOMEM;
24} 40}
25 41
26void perf_read_values_destroy(struct perf_read_values *values) 42void perf_read_values_destroy(struct perf_read_values *values)
@@ -41,17 +57,27 @@ void perf_read_values_destroy(struct perf_read_values *values)
41 zfree(&values->countername); 57 zfree(&values->countername);
42} 58}
43 59
44static void perf_read_values__enlarge_threads(struct perf_read_values *values) 60static int perf_read_values__enlarge_threads(struct perf_read_values *values)
45{ 61{
46 values->threads_max *= 2; 62 int nthreads_max = values->threads_max * 2;
47 values->pid = realloc(values->pid, 63 void *npid = realloc(values->pid, nthreads_max * sizeof(*values->pid)),
48 values->threads_max * sizeof(*values->pid)); 64 *ntid = realloc(values->tid, nthreads_max * sizeof(*values->tid)),
49 values->tid = realloc(values->tid, 65 *nvalue = realloc(values->value, nthreads_max * sizeof(*values->value));
50 values->threads_max * sizeof(*values->tid)); 66
51 values->value = realloc(values->value, 67 if (!npid || !ntid || !nvalue)
52 values->threads_max * sizeof(*values->value)); 68 goto out_err;
53 if (!values->pid || !values->tid || !values->value) 69
54 die("failed to enlarge read_values threads arrays"); 70 values->threads_max = nthreads_max;
71 values->pid = npid;
72 values->tid = ntid;
73 values->value = nvalue;
74 return 0;
75out_err:
76 free(npid);
77 free(ntid);
78 free(nvalue);
79 pr_debug("failed to enlarge read_values threads arrays");
80 return -ENOMEM;
55} 81}
56 82
57static int perf_read_values__findnew_thread(struct perf_read_values *values, 83static int perf_read_values__findnew_thread(struct perf_read_values *values,
@@ -63,15 +89,21 @@ static int perf_read_values__findnew_thread(struct perf_read_values *values,
63 if (values->pid[i] == pid && values->tid[i] == tid) 89 if (values->pid[i] == pid && values->tid[i] == tid)
64 return i; 90 return i;
65 91
66 if (values->threads == values->threads_max) 92 if (values->threads == values->threads_max) {
67 perf_read_values__enlarge_threads(values); 93 i = perf_read_values__enlarge_threads(values);
94 if (i < 0)
95 return i;
96 }
68 97
69 i = values->threads++; 98 i = values->threads + 1;
99 values->value[i] = malloc(values->counters_max * sizeof(**values->value));
100 if (!values->value[i]) {
101 pr_debug("failed to allocate read_values counters array");
102 return -ENOMEM;
103 }
70 values->pid[i] = pid; 104 values->pid[i] = pid;
71 values->tid[i] = tid; 105 values->tid[i] = tid;
72 values->value[i] = malloc(values->counters_max * sizeof(**values->value)); 106 values->threads = i;
73 if (!values->value[i])
74 die("failed to allocate read_values counters array");
75 107
76 return i; 108 return i;
77} 109}
@@ -115,16 +147,21 @@ static int perf_read_values__findnew_counter(struct perf_read_values *values,
115 return i; 147 return i;
116} 148}
117 149
118void perf_read_values_add_value(struct perf_read_values *values, 150int perf_read_values_add_value(struct perf_read_values *values,
119 u32 pid, u32 tid, 151 u32 pid, u32 tid,
120 u64 rawid, const char *name, u64 value) 152 u64 rawid, const char *name, u64 value)
121{ 153{
122 int tindex, cindex; 154 int tindex, cindex;
123 155
124 tindex = perf_read_values__findnew_thread(values, pid, tid); 156 tindex = perf_read_values__findnew_thread(values, pid, tid);
157 if (tindex < 0)
158 return tindex;
125 cindex = perf_read_values__findnew_counter(values, rawid, name); 159 cindex = perf_read_values__findnew_counter(values, rawid, name);
160 if (cindex < 0)
161 return cindex;
126 162
127 values->value[tindex][cindex] = value; 163 values->value[tindex][cindex] = value;
164 return 0;
128} 165}
129 166
130static void perf_read_values__display_pretty(FILE *fp, 167static void perf_read_values__display_pretty(FILE *fp,
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index b21a80c6cf8d..808ff9c73bf5 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -14,10 +14,10 @@ struct perf_read_values {
14 u64 **value; 14 u64 **value;
15}; 15};
16 16
17void perf_read_values_init(struct perf_read_values *values); 17int perf_read_values_init(struct perf_read_values *values);
18void perf_read_values_destroy(struct perf_read_values *values); 18void perf_read_values_destroy(struct perf_read_values *values);
19 19
20void perf_read_values_add_value(struct perf_read_values *values, 20int perf_read_values_add_value(struct perf_read_values *values,
21 u32 pid, u32 tid, 21 u32 pid, u32 tid,
22 u64 rawid, const char *name, u64 value); 22 u64 rawid, const char *name, u64 value);
23 23