aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-04-16 05:09:57 -0400
committerIngo Molnar <mingo@kernel.org>2016-04-16 05:09:57 -0400
commit9243ae5b28d02dc7d71a4f00c981ef6feaede3f1 (patch)
treec6cc841dcb256d0ea77b0ab56b05fe0b344e4aab /tools
parent0b22cd276cec21107d9d69453fa58abba73e71df (diff)
parentf3e459d16a8493b617ccf2a940330279679e0291 (diff)
Merge tag 'perf-core-for-mingo-20160415' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements from Arnaldo Carvalho de Melo: User visible changes: - Wire the callchain unwinding "max-stack" now to 'perf script --max-stack', allowing to limit the depth of callchains, possibly reducing processing time (Arnaldo Carvalho de Melo) - Ditto for 'perf trace --max-stack' (Arnaldo Carvalho de Melo) - Introduce a --min-stack filter for 'perf trace', to show syscalls that had a userspace callchain leading to it at least min-stack deep (Arnaldo Carvalho de Melo) - Make 'perf trace' work with multiple threads and the --duration filter, i.e. do not print the start of an interrupted syscall followed by ... to print interrupts from other threads, as we need to wait the sys_exit syscall tracepoint to calculate the duration, duh. (Arnaldo Carvalho de Melo) System wide --duration now works as expected: [root@jouet ~]# trace --duration 100 152.393 (145.147 ms): Timer/24358 futex(uaddr: 0x7f5ed98e56cc, op: WAIT_BITSET|PRIV|CLKRT, val: 7055125, utime: 0x7f5ecdbfec30, val3: 4294967295) = -1 ETIMEDOUT Connection timed out 152.438 (145.040 ms): firefox/24321 poll(ufds: 0x7f5ec388b460, nfds: 6, timeout_msecs: 4294967295) = 1 358.580 (158.279 ms): Xorg/2025 select(n: 512, inp: 0x83a8e0, tvp: 0x7ffdcbb63610) = 0 Timeout 358.687 (148.285 ms): gnome-terminal/2711 poll(ufds: 0x55b7e6811ad0, nfds: 15, timeout_msecs: 249) = 1 370.150 (169.569 ms): gnome-shell/2287 poll(ufds: 0x55e623d65490, nfds: 86, timeout_msecs: 4294967295) = 1 - Now 'perf trace's --max-stack and --min-stack will automatically set "--call-graph dwarf", if --call-graph is not present on the command line: [root@jouet ~]# perf trace -e nanosleep --max-stack 3 usleep 1 0.299 ( 0.057 ms): usleep/29658 nanosleep(rqtp: 0x7fff80f3b230) = 0 __nanosleep+0x10 (/usr/lib64/libc-2.22.so) usleep+0x34 (/usr/lib64/libc-2.22.so) main+0x1eb (/usr/bin/usleep) [root@jouet ~]# - Bump 'perf trace --mmap-pages' for root when using callchains and not specifying --mmap-pages explicitely (Arnaldo Carvalho de Melo) Build fixes: - The python binding object had missing symbols, to some refactoring to fix that (Arnaldo Carvalho de Melo) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-script.txt10
-rw-r--r--tools/perf/Documentation/perf-trace.txt23
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/perf/builtin-record.c35
-rw-r--r--tools/perf/builtin-script.c39
-rw-r--r--tools/perf/builtin-trace.c144
-rw-r--r--tools/perf/trace/beauty/socket_type.c60
-rw-r--r--tools/perf/util/Build2
-rw-r--r--tools/perf/util/callchain.c5
-rw-r--r--tools/perf/util/callchain.h9
-rw-r--r--tools/perf/util/evlist.c42
-rw-r--r--tools/perf/util/evlist.h2
-rw-r--r--tools/perf/util/evsel.c220
-rw-r--r--tools/perf/util/evsel.h19
-rw-r--r--tools/perf/util/evsel_fprintf.c212
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/machine.c26
-rw-r--r--tools/perf/util/machine.h4
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/symbol.c71
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/symbol_fprintf.c71
24 files changed, 565 insertions, 443 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 22ef3933342a..4fc44c75263f 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -259,6 +259,16 @@ include::itrace.txt[]
259--full-source-path:: 259--full-source-path::
260 Show the full path for source files for srcline output. 260 Show the full path for source files for srcline output.
261 261
262--max-stack::
263 Set the stack depth limit when parsing the callchain, anything
264 beyond the specified depth will be ignored. This is a trade-off
265 between information loss and faster processing especially for
266 workloads that can have a very long callchain stack.
267 Note that when using the --itrace option the synthesized callchain size
268 will override this value if the synthesized callchain size is bigger.
269
270 Default: 127
271
262--ns:: 272--ns::
263 Use 9 decimal places when displaying time (i.e. show the nanoseconds) 273 Use 9 decimal places when displaying time (i.e. show the nanoseconds)
264 274
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 1bbcf305d233..c075c002eaa4 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -123,12 +123,35 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
123 man pages for details. The ones that are most useful in 'perf trace' 123 man pages for details. The ones that are most useful in 'perf trace'
124 are 'dwarf' and 'lbr', where available, try: 'perf trace --call-graph dwarf'. 124 are 'dwarf' and 'lbr', where available, try: 'perf trace --call-graph dwarf'.
125 125
126 Using this will, for the root user, bump the value of --mmap-pages to 4
127 times the maximum for non-root users, based on the kernel.perf_event_mlock_kb
128 sysctl. This is done only if the user doesn't specify a --mmap-pages value.
129
126--kernel-syscall-graph:: 130--kernel-syscall-graph::
127 Show the kernel callchains on the syscall exit path. 131 Show the kernel callchains on the syscall exit path.
128 132
129--event:: 133--event::
130 Trace other events, see 'perf list' for a complete list. 134 Trace other events, see 'perf list' for a complete list.
131 135
136--max-stack::
137 Set the stack depth limit when parsing the callchain, anything
138 beyond the specified depth will be ignored. Note that at this point
139 this is just about the presentation part, i.e. the kernel is still
140 not limiting, the overhead of callchains needs to be set via the
141 knobs in --call-graph dwarf.
142
143 Implies '--call-graph dwarf' when --call-graph not present on the
144 command line, on systems where DWARF unwinding was built in.
145
146 Default: 127
147
148--min-stack::
149 Set the stack depth limit when parsing the callchain, anything
150 below the specified depth will be ignored. Disabled by default.
151
152 Implies '--call-graph dwarf' when --call-graph not present on the
153 command line, on systems where DWARF unwinding was built in.
154
132--proc-map-timeout:: 155--proc-map-timeout::
133 When processing pre-existing threads /proc/XXX/mmap, it may take a long time, 156 When processing pre-existing threads /proc/XXX/mmap, it may take a long time,
134 because the file may be huge. A time out is needed in such cases. 157 because the file may be huge. A time out is needed in such cases.
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index c9cb3be47cff..58adfee230de 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -375,7 +375,7 @@ static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample)
375 } 375 }
376 376
377 al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); 377 al.thread = machine__findnew_thread(machine, sample->pid, sample->tid);
378 sample__resolve_callchain(sample, NULL, evsel, &al, 16); 378 sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16);
379 379
380 callchain_cursor_commit(&callchain_cursor); 380 callchain_cursor_commit(&callchain_cursor);
381 while (true) { 381 while (true) {
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 3239a6ec9d23..5b4758a08a49 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -930,45 +930,50 @@ out_delete_session:
930 return status; 930 return status;
931} 931}
932 932
933static void callchain_debug(void) 933static void callchain_debug(struct callchain_param *callchain)
934{ 934{
935 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" }; 935 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
936 936
937 pr_debug("callchain: type %s\n", str[callchain_param.record_mode]); 937 pr_debug("callchain: type %s\n", str[callchain->record_mode]);
938 938
939 if (callchain_param.record_mode == CALLCHAIN_DWARF) 939 if (callchain->record_mode == CALLCHAIN_DWARF)
940 pr_debug("callchain: stack dump size %d\n", 940 pr_debug("callchain: stack dump size %d\n",
941 callchain_param.dump_size); 941 callchain->dump_size);
942} 942}
943 943
944int record_parse_callchain_opt(const struct option *opt, 944int record_opts__parse_callchain(struct record_opts *record,
945 const char *arg, 945 struct callchain_param *callchain,
946 int unset) 946 const char *arg, bool unset)
947{ 947{
948 int ret; 948 int ret;
949 struct record_opts *record = (struct record_opts *)opt->value;
950
951 record->callgraph_set = true; 949 record->callgraph_set = true;
952 callchain_param.enabled = !unset; 950 callchain->enabled = !unset;
953 951
954 /* --no-call-graph */ 952 /* --no-call-graph */
955 if (unset) { 953 if (unset) {
956 callchain_param.record_mode = CALLCHAIN_NONE; 954 callchain->record_mode = CALLCHAIN_NONE;
957 pr_debug("callchain: disabled\n"); 955 pr_debug("callchain: disabled\n");
958 return 0; 956 return 0;
959 } 957 }
960 958
961 ret = parse_callchain_record_opt(arg, &callchain_param); 959 ret = parse_callchain_record_opt(arg, callchain);
962 if (!ret) { 960 if (!ret) {
963 /* Enable data address sampling for DWARF unwind. */ 961 /* Enable data address sampling for DWARF unwind. */
964 if (callchain_param.record_mode == CALLCHAIN_DWARF) 962 if (callchain->record_mode == CALLCHAIN_DWARF)
965 record->sample_address = true; 963 record->sample_address = true;
966 callchain_debug(); 964 callchain_debug(callchain);
967 } 965 }
968 966
969 return ret; 967 return ret;
970} 968}
971 969
970int record_parse_callchain_opt(const struct option *opt,
971 const char *arg,
972 int unset)
973{
974 return record_opts__parse_callchain(opt->value, &callchain_param, arg, unset);
975}
976
972int record_callchain_opt(const struct option *opt, 977int record_callchain_opt(const struct option *opt,
973 const char *arg __maybe_unused, 978 const char *arg __maybe_unused,
974 int unset __maybe_unused) 979 int unset __maybe_unused)
@@ -981,7 +986,7 @@ int record_callchain_opt(const struct option *opt,
981 if (callchain_param.record_mode == CALLCHAIN_NONE) 986 if (callchain_param.record_mode == CALLCHAIN_NONE)
982 callchain_param.record_mode = CALLCHAIN_FP; 987 callchain_param.record_mode = CALLCHAIN_FP;
983 988
984 callchain_debug(); 989 callchain_debug(&callchain_param);
985 return 0; 990 return 0;
986} 991}
987 992
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 838c0bc38105..0e93282b405e 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -22,6 +22,7 @@
22#include "util/thread_map.h" 22#include "util/thread_map.h"
23#include "util/stat.h" 23#include "util/stat.h"
24#include <linux/bitmap.h> 24#include <linux/bitmap.h>
25#include <linux/stringify.h>
25#include "asm/bug.h" 26#include "asm/bug.h"
26#include "util/mem-events.h" 27#include "util/mem-events.h"
27 28
@@ -569,18 +570,23 @@ static void print_sample_bts(struct perf_sample *sample,
569 /* print branch_from information */ 570 /* print branch_from information */
570 if (PRINT_FIELD(IP)) { 571 if (PRINT_FIELD(IP)) {
571 unsigned int print_opts = output[attr->type].print_ip_opts; 572 unsigned int print_opts = output[attr->type].print_ip_opts;
573 struct callchain_cursor *cursor = NULL, cursor_callchain;
572 574
573 if (symbol_conf.use_callchain && sample->callchain) { 575 if (symbol_conf.use_callchain && sample->callchain &&
574 printf("\n"); 576 thread__resolve_callchain(al->thread, &cursor_callchain, evsel,
575 } else { 577 sample, NULL, NULL, scripting_max_stack) == 0)
576 printf(" "); 578 cursor = &cursor_callchain;
579
580 if (cursor == NULL) {
581 putchar(' ');
577 if (print_opts & EVSEL__PRINT_SRCLINE) { 582 if (print_opts & EVSEL__PRINT_SRCLINE) {
578 print_srcline_last = true; 583 print_srcline_last = true;
579 print_opts &= ~EVSEL__PRINT_SRCLINE; 584 print_opts &= ~EVSEL__PRINT_SRCLINE;
580 } 585 }
581 } 586 } else
582 perf_evsel__fprintf_sym(evsel, sample, al, 0, print_opts, 587 putchar('\n');
583 scripting_max_stack, stdout); 588
589 sample__fprintf_sym(sample, al, 0, print_opts, cursor, stdout);
584 } 590 }
585 591
586 /* print branch_to information */ 592 /* print branch_to information */
@@ -783,14 +789,15 @@ static void process_event(struct perf_script *script,
783 printf("%16" PRIu64, sample->weight); 789 printf("%16" PRIu64, sample->weight);
784 790
785 if (PRINT_FIELD(IP)) { 791 if (PRINT_FIELD(IP)) {
786 if (!symbol_conf.use_callchain) 792 struct callchain_cursor *cursor = NULL, cursor_callchain;
787 printf(" "); 793
788 else 794 if (symbol_conf.use_callchain &&
789 printf("\n"); 795 thread__resolve_callchain(al->thread, &cursor_callchain, evsel,
796 sample, NULL, NULL, scripting_max_stack) == 0)
797 cursor = &cursor_callchain;
790 798
791 perf_evsel__fprintf_sym(evsel, sample, al, 0, 799 putchar(cursor ? '\n' : ' ');
792 output[attr->type].print_ip_opts, 800 sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout);
793 scripting_max_stack, stdout);
794 } 801 }
795 802
796 if (PRINT_FIELD(IREGS)) 803 if (PRINT_FIELD(IREGS))
@@ -2021,6 +2028,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2021 "only consider symbols in these pids"), 2028 "only consider symbols in these pids"),
2022 OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]", 2029 OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
2023 "only consider symbols in these tids"), 2030 "only consider symbols in these tids"),
2031 OPT_UINTEGER(0, "max-stack", &scripting_max_stack,
2032 "Set the maximum stack depth when parsing the callchain, "
2033 "anything beyond the specified depth will be ignored. "
2034 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
2024 OPT_BOOLEAN('I', "show-info", &show_full_info, 2035 OPT_BOOLEAN('I', "show-info", &show_full_info,
2025 "display extended information from perf.data file"), 2036 "display extended information from perf.data file"),
2026 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, 2037 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 8e090a785c5e..026ec0c749b0 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -46,23 +46,12 @@
46#include <linux/audit.h> 46#include <linux/audit.h>
47#include <sys/ptrace.h> 47#include <sys/ptrace.h>
48#include <linux/random.h> 48#include <linux/random.h>
49#include <linux/stringify.h>
49 50
50#ifndef O_CLOEXEC 51#ifndef O_CLOEXEC
51# define O_CLOEXEC 02000000 52# define O_CLOEXEC 02000000
52#endif 53#endif
53 54
54#ifndef SOCK_DCCP
55# define SOCK_DCCP 6
56#endif
57
58#ifndef SOCK_CLOEXEC
59# define SOCK_CLOEXEC 02000000
60#endif
61
62#ifndef SOCK_NONBLOCK
63# define SOCK_NONBLOCK 00004000
64#endif
65
66#ifndef MSG_CMSG_CLOEXEC 55#ifndef MSG_CMSG_CLOEXEC
67# define MSG_CMSG_CLOEXEC 0x40000000 56# define MSG_CMSG_CLOEXEC 0x40000000
68#endif 57#endif
@@ -118,6 +107,8 @@ struct trace {
118 u64 vfs_getname, 107 u64 vfs_getname,
119 proc_getname; 108 proc_getname;
120 } stats; 109 } stats;
110 unsigned int max_stack;
111 unsigned int min_stack;
121 bool not_ev_qualifier; 112 bool not_ev_qualifier;
122 bool live; 113 bool live;
123 bool full_time; 114 bool full_time;
@@ -538,53 +529,6 @@ static const char *socket_families[] = {
538}; 529};
539static DEFINE_STRARRAY(socket_families); 530static DEFINE_STRARRAY(socket_families);
540 531
541#ifndef SOCK_TYPE_MASK
542#define SOCK_TYPE_MASK 0xf
543#endif
544
545static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
546 struct syscall_arg *arg)
547{
548 size_t printed;
549 int type = arg->val,
550 flags = type & ~SOCK_TYPE_MASK;
551
552 type &= SOCK_TYPE_MASK;
553 /*
554 * Can't use a strarray, MIPS may override for ABI reasons.
555 */
556 switch (type) {
557#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
558 P_SK_TYPE(STREAM);
559 P_SK_TYPE(DGRAM);
560 P_SK_TYPE(RAW);
561 P_SK_TYPE(RDM);
562 P_SK_TYPE(SEQPACKET);
563 P_SK_TYPE(DCCP);
564 P_SK_TYPE(PACKET);
565#undef P_SK_TYPE
566 default:
567 printed = scnprintf(bf, size, "%#x", type);
568 }
569
570#define P_SK_FLAG(n) \
571 if (flags & SOCK_##n) { \
572 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
573 flags &= ~SOCK_##n; \
574 }
575
576 P_SK_FLAG(CLOEXEC);
577 P_SK_FLAG(NONBLOCK);
578#undef P_SK_FLAG
579
580 if (flags)
581 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
582
583 return printed;
584}
585
586#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
587
588#ifndef MSG_PROBE 532#ifndef MSG_PROBE
589#define MSG_PROBE 0x10 533#define MSG_PROBE 0x10
590#endif 534#endif
@@ -951,6 +895,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
951#include "trace/beauty/mmap.c" 895#include "trace/beauty/mmap.c"
952#include "trace/beauty/mode_t.c" 896#include "trace/beauty/mode_t.c"
953#include "trace/beauty/sched_policy.c" 897#include "trace/beauty/sched_policy.c"
898#include "trace/beauty/socket_type.c"
954#include "trace/beauty/waitid_options.c" 899#include "trace/beauty/waitid_options.c"
955 900
956static struct syscall_fmt { 901static struct syscall_fmt {
@@ -1905,7 +1850,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1905 goto out_put; 1850 goto out_put;
1906 } 1851 }
1907 1852
1908 if (!trace->summary_only) 1853 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
1909 trace__printf_interrupted_entry(trace, sample); 1854 trace__printf_interrupted_entry(trace, sample);
1910 1855
1911 ttrace->entry_time = sample->time; 1856 ttrace->entry_time = sample->time;
@@ -1916,7 +1861,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1916 args, trace, thread); 1861 args, trace, thread);
1917 1862
1918 if (sc->is_exit) { 1863 if (sc->is_exit) {
1919 if (!trace->duration_filter && !trace->summary_only) { 1864 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
1920 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 1865 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1921 fprintf(trace->output, "%-70s\n", ttrace->entry_str); 1866 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
1922 } 1867 }
@@ -1936,26 +1881,27 @@ out_put:
1936 return err; 1881 return err;
1937} 1882}
1938 1883
1939static int trace__fprintf_callchain(struct trace *trace, struct perf_evsel *evsel, 1884static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1940 struct perf_sample *sample) 1885 struct perf_sample *sample,
1886 struct callchain_cursor *cursor)
1941{ 1887{
1942 struct addr_location al; 1888 struct addr_location al;
1889
1890 if (machine__resolve(trace->host, &al, sample) < 0 ||
1891 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1892 return -1;
1893
1894 return 0;
1895}
1896
1897static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1898{
1943 /* TODO: user-configurable print_opts */ 1899 /* TODO: user-configurable print_opts */
1944 const unsigned int print_opts = EVSEL__PRINT_SYM | 1900 const unsigned int print_opts = EVSEL__PRINT_SYM |
1945 EVSEL__PRINT_DSO | 1901 EVSEL__PRINT_DSO |
1946 EVSEL__PRINT_UNKNOWN_AS_ADDR; 1902 EVSEL__PRINT_UNKNOWN_AS_ADDR;
1947 1903
1948 if (sample->callchain == NULL) 1904 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
1949 return 0;
1950
1951 if (machine__resolve(trace->host, &al, sample) < 0) {
1952 pr_err("Problem processing %s callchain, skipping...\n",
1953 perf_evsel__name(evsel));
1954 return 0;
1955 }
1956
1957 return perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
1958 scripting_max_stack, trace->output);
1959} 1905}
1960 1906
1961static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, 1907static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
@@ -1965,7 +1911,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1965 long ret; 1911 long ret;
1966 u64 duration = 0; 1912 u64 duration = 0;
1967 struct thread *thread; 1913 struct thread *thread;
1968 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; 1914 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
1969 struct syscall *sc = trace__syscall_info(trace, evsel, id); 1915 struct syscall *sc = trace__syscall_info(trace, evsel, id);
1970 struct thread_trace *ttrace; 1916 struct thread_trace *ttrace;
1971 1917
@@ -1997,6 +1943,15 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1997 } else if (trace->duration_filter) 1943 } else if (trace->duration_filter)
1998 goto out; 1944 goto out;
1999 1945
1946 if (sample->callchain) {
1947 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1948 if (callchain_ret == 0) {
1949 if (callchain_cursor.nr < trace->min_stack)
1950 goto out;
1951 callchain_ret = 1;
1952 }
1953 }
1954
2000 if (trace->summary_only) 1955 if (trace->summary_only)
2001 goto out; 1956 goto out;
2002 1957
@@ -2037,7 +1992,10 @@ signed_print:
2037 1992
2038 fputc('\n', trace->output); 1993 fputc('\n', trace->output);
2039 1994
2040 trace__fprintf_callchain(trace, evsel, sample); 1995 if (callchain_ret > 0)
1996 trace__fprintf_callchain(trace, sample);
1997 else if (callchain_ret < 0)
1998 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2041out: 1999out:
2042 ttrace->entry_pending = false; 2000 ttrace->entry_pending = false;
2043 err = 0; 2001 err = 0;
@@ -2186,7 +2144,10 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2186 2144
2187 fprintf(trace->output, ")\n"); 2145 fprintf(trace->output, ")\n");
2188 2146
2189 trace__fprintf_callchain(trace, evsel, sample); 2147 if (sample->callchain) {
2148 if (trace__resolve_callchain(trace, evsel, sample, &callchain_cursor) == 0)
2149 trace__fprintf_callchain(trace, sample);
2150 }
2190 2151
2191 return 0; 2152 return 0;
2192} 2153}
@@ -3086,6 +3047,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3086 .show_comm = true, 3047 .show_comm = true,
3087 .trace_syscalls = true, 3048 .trace_syscalls = true,
3088 .kernel_syscallchains = false, 3049 .kernel_syscallchains = false,
3050 .max_stack = UINT_MAX,
3089 }; 3051 };
3090 const char *output_name = NULL; 3052 const char *output_name = NULL;
3091 const char *ev_qualifier_str = NULL; 3053 const char *ev_qualifier_str = NULL;
@@ -3136,10 +3098,19 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3136 &record_parse_callchain_opt), 3098 &record_parse_callchain_opt),
3137 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, 3099 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3138 "Show the kernel callchains on the syscall exit path"), 3100 "Show the kernel callchains on the syscall exit path"),
3101 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3102 "Set the minimum stack depth when parsing the callchain, "
3103 "anything below the specified depth will be ignored."),
3104 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3105 "Set the maximum stack depth when parsing the callchain, "
3106 "anything beyond the specified depth will be ignored. "
3107 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
3139 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, 3108 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3140 "per thread proc mmap processing timeout in ms"), 3109 "per thread proc mmap processing timeout in ms"),
3141 OPT_END() 3110 OPT_END()
3142 }; 3111 };
3112 bool max_stack_user_set = true;
3113 bool mmap_pages_user_set = true;
3143 const char * const trace_subcommands[] = { "record", NULL }; 3114 const char * const trace_subcommands[] = { "record", NULL };
3144 int err; 3115 int err;
3145 char bf[BUFSIZ]; 3116 char bf[BUFSIZ];
@@ -3173,8 +3144,25 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3173 trace.opts.sample_time = true; 3144 trace.opts.sample_time = true;
3174 } 3145 }
3175 3146
3176 if (trace.opts.callgraph_set) 3147 if (trace.opts.mmap_pages == UINT_MAX)
3148 mmap_pages_user_set = false;
3149
3150 if (trace.max_stack == UINT_MAX) {
3151 trace.max_stack = PERF_MAX_STACK_DEPTH;
3152 max_stack_user_set = false;
3153 }
3154
3155#ifdef HAVE_DWARF_UNWIND_SUPPORT
3156 if ((trace.min_stack || max_stack_user_set) && !trace.opts.callgraph_set)
3157 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3158#endif
3159
3160 if (trace.opts.callgraph_set) {
3161 if (!mmap_pages_user_set && geteuid() == 0)
3162 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3163
3177 symbol_conf.use_callchain = true; 3164 symbol_conf.use_callchain = true;
3165 }
3178 3166
3179 if (trace.evlist->nr_entries > 0) 3167 if (trace.evlist->nr_entries > 0)
3180 evlist__set_evsel_handler(trace.evlist, trace__event_handler); 3168 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
diff --git a/tools/perf/trace/beauty/socket_type.c b/tools/perf/trace/beauty/socket_type.c
new file mode 100644
index 000000000000..0a5ce818131c
--- /dev/null
+++ b/tools/perf/trace/beauty/socket_type.c
@@ -0,0 +1,60 @@
1#include <sys/types.h>
2#include <sys/socket.h>
3
4#ifndef SOCK_DCCP
5# define SOCK_DCCP 6
6#endif
7
8#ifndef SOCK_CLOEXEC
9# define SOCK_CLOEXEC 02000000
10#endif
11
12#ifndef SOCK_NONBLOCK
13# define SOCK_NONBLOCK 00004000
14#endif
15
16#ifndef SOCK_TYPE_MASK
17#define SOCK_TYPE_MASK 0xf
18#endif
19
20static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size, struct syscall_arg *arg)
21{
22 size_t printed;
23 int type = arg->val,
24 flags = type & ~SOCK_TYPE_MASK;
25
26 type &= SOCK_TYPE_MASK;
27 /*
28 * Can't use a strarray, MIPS may override for ABI reasons.
29 */
30 switch (type) {
31#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
32 P_SK_TYPE(STREAM);
33 P_SK_TYPE(DGRAM);
34 P_SK_TYPE(RAW);
35 P_SK_TYPE(RDM);
36 P_SK_TYPE(SEQPACKET);
37 P_SK_TYPE(DCCP);
38 P_SK_TYPE(PACKET);
39#undef P_SK_TYPE
40 default:
41 printed = scnprintf(bf, size, "%#x", type);
42 }
43
44#define P_SK_FLAG(n) \
45 if (flags & SOCK_##n) { \
46 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
47 flags &= ~SOCK_##n; \
48 }
49
50 P_SK_FLAG(CLOEXEC);
51 P_SK_FLAG(NONBLOCK);
52#undef P_SK_FLAG
53
54 if (flags)
55 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
56
57 return printed;
58}
59
60#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index ea4ac03c1ec8..85a9ab62e23f 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -8,6 +8,7 @@ libperf-y += env.o
8libperf-y += event.o 8libperf-y += event.o
9libperf-y += evlist.o 9libperf-y += evlist.o
10libperf-y += evsel.o 10libperf-y += evsel.o
11libperf-y += evsel_fprintf.o
11libperf-y += find_bit.o 12libperf-y += find_bit.o
12libperf-y += kallsyms.o 13libperf-y += kallsyms.o
13libperf-y += levenshtein.o 14libperf-y += levenshtein.o
@@ -29,6 +30,7 @@ libperf-y += usage.o
29libperf-y += wrapper.o 30libperf-y += wrapper.o
30libperf-y += dso.o 31libperf-y += dso.o
31libperf-y += symbol.o 32libperf-y += symbol.o
33libperf-y += symbol_fprintf.o
32libperf-y += color.o 34libperf-y += color.o
33libperf-y += header.o 35libperf-y += header.o
34libperf-y += callchain.o 36libperf-y += callchain.o
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 24b4bd0d7754..2b4ceaf058bb 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -788,7 +788,8 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
788 return 0; 788 return 0;
789} 789}
790 790
791int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, 791int sample__resolve_callchain(struct perf_sample *sample,
792 struct callchain_cursor *cursor, struct symbol **parent,
792 struct perf_evsel *evsel, struct addr_location *al, 793 struct perf_evsel *evsel, struct addr_location *al,
793 int max_stack) 794 int max_stack)
794{ 795{
@@ -797,7 +798,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
797 798
798 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || 799 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
799 sort__has_parent) { 800 sort__has_parent) {
800 return thread__resolve_callchain(al->thread, evsel, sample, 801 return thread__resolve_callchain(al->thread, cursor, evsel, sample,
801 parent, al, max_stack); 802 parent, al, max_stack);
802 } 803 }
803 return 0; 804 return 0;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index d2a9e694810c..65e2a4f7cb4e 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -212,7 +212,14 @@ struct hist_entry;
212int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); 212int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
213int record_callchain_opt(const struct option *opt, const char *arg, int unset); 213int record_callchain_opt(const struct option *opt, const char *arg, int unset);
214 214
215int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, 215struct record_opts;
216
217int record_opts__parse_callchain(struct record_opts *record,
218 struct callchain_param *callchain,
219 const char *arg, bool unset);
220
221int sample__resolve_callchain(struct perf_sample *sample,
222 struct callchain_cursor *cursor, struct symbol **parent,
216 struct perf_evsel *evsel, struct addr_location *al, 223 struct perf_evsel *evsel, struct addr_location *al,
217 int max_stack); 224 int max_stack);
218int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 225int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 4c9f510ae18d..6fb5725821de 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -986,26 +986,34 @@ out_unmap:
986 return -1; 986 return -1;
987} 987}
988 988
989static size_t perf_evlist__mmap_size(unsigned long pages) 989unsigned long perf_event_mlock_kb_in_pages(void)
990{ 990{
991 if (pages == UINT_MAX) { 991 unsigned long pages;
992 int max; 992 int max;
993 993
994 if (sysctl__read_int("kernel/perf_event_mlock_kb", &max) < 0) { 994 if (sysctl__read_int("kernel/perf_event_mlock_kb", &max) < 0) {
995 /* 995 /*
996 * Pick a once upon a time good value, i.e. things look 996 * Pick a once upon a time good value, i.e. things look
997 * strange since we can't read a sysctl value, but lets not 997 * strange since we can't read a sysctl value, but lets not
998 * die yet... 998 * die yet...
999 */ 999 */
1000 max = 512; 1000 max = 512;
1001 } else { 1001 } else {
1002 max -= (page_size / 1024); 1002 max -= (page_size / 1024);
1003 } 1003 }
1004
1005 pages = (max * 1024) / page_size;
1006 if (!is_power_of_2(pages))
1007 pages = rounddown_pow_of_two(pages);
1004 1008
1005 pages = (max * 1024) / page_size; 1009 return pages;
1006 if (!is_power_of_2(pages)) 1010}
1007 pages = rounddown_pow_of_two(pages); 1011
1008 } else if (!is_power_of_2(pages)) 1012static size_t perf_evlist__mmap_size(unsigned long pages)
1013{
1014 if (pages == UINT_MAX)
1015 pages = perf_event_mlock_kb_in_pages();
1016 else if (!is_power_of_2(pages))
1009 return 0; 1017 return 0;
1010 1018
1011 return (pages + 1) * page_size; 1019 return (pages + 1) * page_size;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index da46423998e8..208897a646ca 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -158,6 +158,8 @@ int perf_evlist__parse_mmap_pages(const struct option *opt,
158 const char *str, 158 const char *str,
159 int unset); 159 int unset);
160 160
161unsigned long perf_event_mlock_kb_in_pages(void);
162
161int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, 163int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,
162 bool overwrite, unsigned int auxtrace_pages, 164 bool overwrite, unsigned int auxtrace_pages,
163 bool auxtrace_overwrite); 165 bool auxtrace_overwrite);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 6e86598682be..545bb3f0b2b0 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -2254,226 +2254,6 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
2254 return 0; 2254 return 0;
2255} 2255}
2256 2256
2257static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
2258{
2259 va_list args;
2260 int ret = 0;
2261
2262 if (!*first) {
2263 ret += fprintf(fp, ",");
2264 } else {
2265 ret += fprintf(fp, ":");
2266 *first = false;
2267 }
2268
2269 va_start(args, fmt);
2270 ret += vfprintf(fp, fmt, args);
2271 va_end(args);
2272 return ret;
2273}
2274
2275static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv)
2276{
2277 return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val);
2278}
2279
2280int perf_evsel__fprintf(struct perf_evsel *evsel,
2281 struct perf_attr_details *details, FILE *fp)
2282{
2283 bool first = true;
2284 int printed = 0;
2285
2286 if (details->event_group) {
2287 struct perf_evsel *pos;
2288
2289 if (!perf_evsel__is_group_leader(evsel))
2290 return 0;
2291
2292 if (evsel->nr_members > 1)
2293 printed += fprintf(fp, "%s{", evsel->group_name ?: "");
2294
2295 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
2296 for_each_group_member(pos, evsel)
2297 printed += fprintf(fp, ",%s", perf_evsel__name(pos));
2298
2299 if (evsel->nr_members > 1)
2300 printed += fprintf(fp, "}");
2301 goto out;
2302 }
2303
2304 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
2305
2306 if (details->verbose) {
2307 printed += perf_event_attr__fprintf(fp, &evsel->attr,
2308 __print_attr__fprintf, &first);
2309 } else if (details->freq) {
2310 const char *term = "sample_freq";
2311
2312 if (!evsel->attr.freq)
2313 term = "sample_period";
2314
2315 printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
2316 term, (u64)evsel->attr.sample_freq);
2317 }
2318
2319 if (details->trace_fields) {
2320 struct format_field *field;
2321
2322 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2323 printed += comma_fprintf(fp, &first, " (not a tracepoint)");
2324 goto out;
2325 }
2326
2327 field = evsel->tp_format->format.fields;
2328 if (field == NULL) {
2329 printed += comma_fprintf(fp, &first, " (no trace field)");
2330 goto out;
2331 }
2332
2333 printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
2334
2335 field = field->next;
2336 while (field) {
2337 printed += comma_fprintf(fp, &first, "%s", field->name);
2338 field = field->next;
2339 }
2340 }
2341out:
2342 fputc('\n', fp);
2343 return ++printed;
2344}
2345
2346int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, struct perf_sample *sample,
2347 struct addr_location *al, int left_alignment,
2348 unsigned int print_opts, unsigned int stack_depth,
2349 FILE *fp)
2350{
2351 int printed = 0;
2352 struct callchain_cursor_node *node;
2353 int print_ip = print_opts & EVSEL__PRINT_IP;
2354 int print_sym = print_opts & EVSEL__PRINT_SYM;
2355 int print_dso = print_opts & EVSEL__PRINT_DSO;
2356 int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
2357 int print_oneline = print_opts & EVSEL__PRINT_ONELINE;
2358 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
2359 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
2360 char s = print_oneline ? ' ' : '\t';
2361
2362 if (sample->callchain) {
2363 struct addr_location node_al;
2364
2365 if (thread__resolve_callchain(al->thread, evsel,
2366 sample, NULL, NULL,
2367 stack_depth) != 0) {
2368 if (verbose)
2369 error("Failed to resolve callchain. Skipping\n");
2370 return printed;
2371 }
2372 callchain_cursor_commit(&callchain_cursor);
2373
2374 if (print_symoffset)
2375 node_al = *al;
2376
2377 while (stack_depth) {
2378 u64 addr = 0;
2379
2380 node = callchain_cursor_current(&callchain_cursor);
2381 if (!node)
2382 break;
2383
2384 if (node->sym && node->sym->ignore)
2385 goto next;
2386
2387 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
2388
2389 if (print_ip)
2390 printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
2391
2392 if (node->map)
2393 addr = node->map->map_ip(node->map, node->ip);
2394
2395 if (print_sym) {
2396 printed += fprintf(fp, " ");
2397 node_al.addr = addr;
2398 node_al.map = node->map;
2399
2400 if (print_symoffset) {
2401 printed += __symbol__fprintf_symname_offs(node->sym, &node_al,
2402 print_unknown_as_addr, fp);
2403 } else {
2404 printed += __symbol__fprintf_symname(node->sym, &node_al,
2405 print_unknown_as_addr, fp);
2406 }
2407 }
2408
2409 if (print_dso) {
2410 printed += fprintf(fp, " (");
2411 printed += map__fprintf_dsoname(node->map, fp);
2412 printed += fprintf(fp, ")");
2413 }
2414
2415 if (print_srcline)
2416 printed += map__fprintf_srcline(node->map, addr, "\n ", fp);
2417
2418 if (!print_oneline)
2419 printed += fprintf(fp, "\n");
2420
2421 stack_depth--;
2422next:
2423 callchain_cursor_advance(&callchain_cursor);
2424 }
2425 }
2426
2427 return printed;
2428}
2429
2430int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample,
2431 struct addr_location *al, int left_alignment,
2432 unsigned int print_opts, unsigned int stack_depth,
2433 FILE *fp)
2434{
2435 int printed = 0;
2436 int print_ip = print_opts & EVSEL__PRINT_IP;
2437 int print_sym = print_opts & EVSEL__PRINT_SYM;
2438 int print_dso = print_opts & EVSEL__PRINT_DSO;
2439 int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
2440 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
2441 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
2442
2443 if (symbol_conf.use_callchain && sample->callchain) {
2444 printed += perf_evsel__fprintf_callchain(evsel, sample, al, left_alignment,
2445 print_opts, stack_depth, fp);
2446 } else if (!(al->sym && al->sym->ignore)) {
2447 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
2448
2449 if (print_ip)
2450 printed += fprintf(fp, "%16" PRIx64, sample->ip);
2451
2452 if (print_sym) {
2453 printed += fprintf(fp, " ");
2454 if (print_symoffset) {
2455 printed += __symbol__fprintf_symname_offs(al->sym, al,
2456 print_unknown_as_addr, fp);
2457 } else {
2458 printed += __symbol__fprintf_symname(al->sym, al,
2459 print_unknown_as_addr, fp);
2460 }
2461 }
2462
2463 if (print_dso) {
2464 printed += fprintf(fp, " (");
2465 printed += map__fprintf_dsoname(al->map, fp);
2466 printed += fprintf(fp, ")");
2467 }
2468
2469 if (print_srcline)
2470 printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);
2471 }
2472
2473 return printed;
2474}
2475
2476
2477bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 2257bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
2478 char *msg, size_t msgsize) 2258 char *msg, size_t msgsize)
2479{ 2259{
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 36edd3c91d5c..b993218744d4 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -395,16 +395,15 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
395#define EVSEL__PRINT_SRCLINE (1<<5) 395#define EVSEL__PRINT_SRCLINE (1<<5)
396#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) 396#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6)
397 397
398int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, 398struct callchain_cursor;
399 struct perf_sample *sample, 399
400 struct addr_location *al, int left_alignment, 400int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
401 unsigned int print_opts, 401 unsigned int print_opts,
402 unsigned int stack_depth, FILE *fp); 402 struct callchain_cursor *cursor, FILE *fp);
403 403
404int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample, 404int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
405 struct addr_location *al, int left_alignment, 405 int left_alignment, unsigned int print_opts,
406 unsigned int print_opts, unsigned int stack_depth, 406 struct callchain_cursor *cursor, FILE *fp);
407 FILE *fp);
408 407
409bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 408bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
410 char *msg, size_t msgsize); 409 char *msg, size_t msgsize);
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
new file mode 100644
index 000000000000..3674e77ad640
--- /dev/null
+++ b/tools/perf/util/evsel_fprintf.c
@@ -0,0 +1,212 @@
1#include <stdio.h>
2#include <stdbool.h>
3#include <traceevent/event-parse.h>
4#include "evsel.h"
5#include "callchain.h"
6#include "map.h"
7#include "symbol.h"
8
9static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
10{
11 va_list args;
12 int ret = 0;
13
14 if (!*first) {
15 ret += fprintf(fp, ",");
16 } else {
17 ret += fprintf(fp, ":");
18 *first = false;
19 }
20
21 va_start(args, fmt);
22 ret += vfprintf(fp, fmt, args);
23 va_end(args);
24 return ret;
25}
26
27static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv)
28{
29 return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val);
30}
31
32int perf_evsel__fprintf(struct perf_evsel *evsel,
33 struct perf_attr_details *details, FILE *fp)
34{
35 bool first = true;
36 int printed = 0;
37
38 if (details->event_group) {
39 struct perf_evsel *pos;
40
41 if (!perf_evsel__is_group_leader(evsel))
42 return 0;
43
44 if (evsel->nr_members > 1)
45 printed += fprintf(fp, "%s{", evsel->group_name ?: "");
46
47 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
48 for_each_group_member(pos, evsel)
49 printed += fprintf(fp, ",%s", perf_evsel__name(pos));
50
51 if (evsel->nr_members > 1)
52 printed += fprintf(fp, "}");
53 goto out;
54 }
55
56 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
57
58 if (details->verbose) {
59 printed += perf_event_attr__fprintf(fp, &evsel->attr,
60 __print_attr__fprintf, &first);
61 } else if (details->freq) {
62 const char *term = "sample_freq";
63
64 if (!evsel->attr.freq)
65 term = "sample_period";
66
67 printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
68 term, (u64)evsel->attr.sample_freq);
69 }
70
71 if (details->trace_fields) {
72 struct format_field *field;
73
74 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
75 printed += comma_fprintf(fp, &first, " (not a tracepoint)");
76 goto out;
77 }
78
79 field = evsel->tp_format->format.fields;
80 if (field == NULL) {
81 printed += comma_fprintf(fp, &first, " (no trace field)");
82 goto out;
83 }
84
85 printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
86
87 field = field->next;
88 while (field) {
89 printed += comma_fprintf(fp, &first, "%s", field->name);
90 field = field->next;
91 }
92 }
93out:
94 fputc('\n', fp);
95 return ++printed;
96}
97
98int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
99 unsigned int print_opts, struct callchain_cursor *cursor,
100 FILE *fp)
101{
102 int printed = 0;
103 struct callchain_cursor_node *node;
104 int print_ip = print_opts & EVSEL__PRINT_IP;
105 int print_sym = print_opts & EVSEL__PRINT_SYM;
106 int print_dso = print_opts & EVSEL__PRINT_DSO;
107 int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
108 int print_oneline = print_opts & EVSEL__PRINT_ONELINE;
109 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
110 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
111 char s = print_oneline ? ' ' : '\t';
112
113 if (sample->callchain) {
114 struct addr_location node_al;
115
116 callchain_cursor_commit(cursor);
117
118 while (1) {
119 u64 addr = 0;
120
121 node = callchain_cursor_current(cursor);
122 if (!node)
123 break;
124
125 if (node->sym && node->sym->ignore)
126 goto next;
127
128 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
129
130 if (print_ip)
131 printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
132
133 if (node->map)
134 addr = node->map->map_ip(node->map, node->ip);
135
136 if (print_sym) {
137 printed += fprintf(fp, " ");
138 node_al.addr = addr;
139 node_al.map = node->map;
140
141 if (print_symoffset) {
142 printed += __symbol__fprintf_symname_offs(node->sym, &node_al,
143 print_unknown_as_addr, fp);
144 } else {
145 printed += __symbol__fprintf_symname(node->sym, &node_al,
146 print_unknown_as_addr, fp);
147 }
148 }
149
150 if (print_dso) {
151 printed += fprintf(fp, " (");
152 printed += map__fprintf_dsoname(node->map, fp);
153 printed += fprintf(fp, ")");
154 }
155
156 if (print_srcline)
157 printed += map__fprintf_srcline(node->map, addr, "\n ", fp);
158
159 if (!print_oneline)
160 printed += fprintf(fp, "\n");
161next:
162 callchain_cursor_advance(cursor);
163 }
164 }
165
166 return printed;
167}
168
169int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
170 int left_alignment, unsigned int print_opts,
171 struct callchain_cursor *cursor, FILE *fp)
172{
173 int printed = 0;
174 int print_ip = print_opts & EVSEL__PRINT_IP;
175 int print_sym = print_opts & EVSEL__PRINT_SYM;
176 int print_dso = print_opts & EVSEL__PRINT_DSO;
177 int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
178 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
179 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
180
181 if (cursor != NULL) {
182 printed += sample__fprintf_callchain(sample, left_alignment,
183 print_opts, cursor, fp);
184 } else if (!(al->sym && al->sym->ignore)) {
185 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
186
187 if (print_ip)
188 printed += fprintf(fp, "%16" PRIx64, sample->ip);
189
190 if (print_sym) {
191 printed += fprintf(fp, " ");
192 if (print_symoffset) {
193 printed += __symbol__fprintf_symname_offs(al->sym, al,
194 print_unknown_as_addr, fp);
195 } else {
196 printed += __symbol__fprintf_symname(al->sym, al,
197 print_unknown_as_addr, fp);
198 }
199 }
200
201 if (print_dso) {
202 printed += fprintf(fp, " (");
203 printed += map__fprintf_dsoname(al->map, fp);
204 printed += fprintf(fp, ")");
205 }
206
207 if (print_srcline)
208 printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);
209 }
210
211 return printed;
212}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 3d34c57dfbe2..991a351a8a41 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -953,7 +953,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
953{ 953{
954 int err, err2; 954 int err, err2;
955 955
956 err = sample__resolve_callchain(iter->sample, &iter->parent, 956 err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent,
957 iter->evsel, al, max_stack_depth); 957 iter->evsel, al, max_stack_depth);
958 if (err) 958 if (err)
959 return err; 959 return err;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 80b9b6a87990..0c4dabc69932 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1599,6 +1599,7 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample,
1599} 1599}
1600 1600
1601static int add_callchain_ip(struct thread *thread, 1601static int add_callchain_ip(struct thread *thread,
1602 struct callchain_cursor *cursor,
1602 struct symbol **parent, 1603 struct symbol **parent,
1603 struct addr_location *root_al, 1604 struct addr_location *root_al,
1604 u8 *cpumode, 1605 u8 *cpumode,
@@ -1630,7 +1631,7 @@ static int add_callchain_ip(struct thread *thread,
1630 * It seems the callchain is corrupted. 1631 * It seems the callchain is corrupted.
1631 * Discard all. 1632 * Discard all.
1632 */ 1633 */
1633 callchain_cursor_reset(&callchain_cursor); 1634 callchain_cursor_reset(cursor);
1634 return 1; 1635 return 1;
1635 } 1636 }
1636 return 0; 1637 return 0;
@@ -1648,13 +1649,13 @@ static int add_callchain_ip(struct thread *thread,
1648 /* Treat this symbol as the root, 1649 /* Treat this symbol as the root,
1649 forgetting its callees. */ 1650 forgetting its callees. */
1650 *root_al = al; 1651 *root_al = al;
1651 callchain_cursor_reset(&callchain_cursor); 1652 callchain_cursor_reset(cursor);
1652 } 1653 }
1653 } 1654 }
1654 1655
1655 if (symbol_conf.hide_unresolved && al.sym == NULL) 1656 if (symbol_conf.hide_unresolved && al.sym == NULL)
1656 return 0; 1657 return 0;
1657 return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); 1658 return callchain_cursor_append(cursor, al.addr, al.map, al.sym);
1658} 1659}
1659 1660
1660struct branch_info *sample__resolve_bstack(struct perf_sample *sample, 1661struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
@@ -1724,6 +1725,7 @@ static int remove_loops(struct branch_entry *l, int nr)
1724 * negative error code on other errors. 1725 * negative error code on other errors.
1725 */ 1726 */
1726static int resolve_lbr_callchain_sample(struct thread *thread, 1727static int resolve_lbr_callchain_sample(struct thread *thread,
1728 struct callchain_cursor *cursor,
1727 struct perf_sample *sample, 1729 struct perf_sample *sample,
1728 struct symbol **parent, 1730 struct symbol **parent,
1729 struct addr_location *root_al, 1731 struct addr_location *root_al,
@@ -1778,7 +1780,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1778 ip = lbr_stack->entries[0].to; 1780 ip = lbr_stack->entries[0].to;
1779 } 1781 }
1780 1782
1781 err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); 1783 err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip);
1782 if (err) 1784 if (err)
1783 return (err < 0) ? err : 0; 1785 return (err < 0) ? err : 0;
1784 } 1786 }
@@ -1789,6 +1791,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1789} 1791}
1790 1792
1791static int thread__resolve_callchain_sample(struct thread *thread, 1793static int thread__resolve_callchain_sample(struct thread *thread,
1794 struct callchain_cursor *cursor,
1792 struct perf_evsel *evsel, 1795 struct perf_evsel *evsel,
1793 struct perf_sample *sample, 1796 struct perf_sample *sample,
1794 struct symbol **parent, 1797 struct symbol **parent,
@@ -1803,10 +1806,10 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1803 int skip_idx = -1; 1806 int skip_idx = -1;
1804 int first_call = 0; 1807 int first_call = 0;
1805 1808
1806 callchain_cursor_reset(&callchain_cursor); 1809 callchain_cursor_reset(cursor);
1807 1810
1808 if (has_branch_callstack(evsel)) { 1811 if (has_branch_callstack(evsel)) {
1809 err = resolve_lbr_callchain_sample(thread, sample, parent, 1812 err = resolve_lbr_callchain_sample(thread, cursor, sample, parent,
1810 root_al, max_stack); 1813 root_al, max_stack);
1811 if (err) 1814 if (err)
1812 return (err < 0) ? err : 0; 1815 return (err < 0) ? err : 0;
@@ -1863,10 +1866,10 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1863 nr = remove_loops(be, nr); 1866 nr = remove_loops(be, nr);
1864 1867
1865 for (i = 0; i < nr; i++) { 1868 for (i = 0; i < nr; i++) {
1866 err = add_callchain_ip(thread, parent, root_al, 1869 err = add_callchain_ip(thread, cursor, parent, root_al,
1867 NULL, be[i].to); 1870 NULL, be[i].to);
1868 if (!err) 1871 if (!err)
1869 err = add_callchain_ip(thread, parent, root_al, 1872 err = add_callchain_ip(thread, cursor, parent, root_al,
1870 NULL, be[i].from); 1873 NULL, be[i].from);
1871 if (err == -EINVAL) 1874 if (err == -EINVAL)
1872 break; 1875 break;
@@ -1896,7 +1899,7 @@ check_calls:
1896#endif 1899#endif
1897 ip = chain->ips[j]; 1900 ip = chain->ips[j];
1898 1901
1899 err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); 1902 err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip);
1900 1903
1901 if (err) 1904 if (err)
1902 return (err < 0) ? err : 0; 1905 return (err < 0) ? err : 0;
@@ -1916,13 +1919,14 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
1916} 1919}
1917 1920
1918int thread__resolve_callchain(struct thread *thread, 1921int thread__resolve_callchain(struct thread *thread,
1922 struct callchain_cursor *cursor,
1919 struct perf_evsel *evsel, 1923 struct perf_evsel *evsel,
1920 struct perf_sample *sample, 1924 struct perf_sample *sample,
1921 struct symbol **parent, 1925 struct symbol **parent,
1922 struct addr_location *root_al, 1926 struct addr_location *root_al,
1923 int max_stack) 1927 int max_stack)
1924{ 1928{
1925 int ret = thread__resolve_callchain_sample(thread, evsel, 1929 int ret = thread__resolve_callchain_sample(thread, cursor, evsel,
1926 sample, parent, 1930 sample, parent,
1927 root_al, max_stack); 1931 root_al, max_stack);
1928 if (ret) 1932 if (ret)
@@ -1938,7 +1942,7 @@ int thread__resolve_callchain(struct thread *thread,
1938 (!sample->user_stack.size)) 1942 (!sample->user_stack.size))
1939 return 0; 1943 return 0;
1940 1944
1941 return unwind__get_entries(unwind_entry, &callchain_cursor, 1945 return unwind__get_entries(unwind_entry, cursor,
1942 thread, sample, max_stack); 1946 thread, sample, max_stack);
1943 1947
1944} 1948}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 8499db281158..382873bdc563 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -141,7 +141,11 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
141 struct addr_location *al); 141 struct addr_location *al);
142struct mem_info *sample__resolve_mem(struct perf_sample *sample, 142struct mem_info *sample__resolve_mem(struct perf_sample *sample,
143 struct addr_location *al); 143 struct addr_location *al);
144
145struct callchain_cursor;
146
144int thread__resolve_callchain(struct thread *thread, 147int thread__resolve_callchain(struct thread *thread,
148 struct callchain_cursor *cursor,
145 struct perf_evsel *evsel, 149 struct perf_evsel *evsel,
146 struct perf_sample *sample, 150 struct perf_sample *sample,
147 struct symbol **parent, 151 struct symbol **parent,
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 8162ba0e2e57..36c6862119e3 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -23,3 +23,4 @@ util/strlist.c
23util/trace-event.c 23util/trace-event.c
24../lib/rbtree.c 24../lib/rbtree.c
25util/string.c 25util/string.c
26util/symbol_fprintf.c
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 35ed00a600fb..ae1cebc307c5 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -263,7 +263,7 @@ static SV *perl_process_callchain(struct perf_sample *sample,
263 if (!symbol_conf.use_callchain || !sample->callchain) 263 if (!symbol_conf.use_callchain || !sample->callchain)
264 goto exit; 264 goto exit;
265 265
266 if (thread__resolve_callchain(al->thread, evsel, 266 if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
267 sample, NULL, NULL, 267 sample, NULL, NULL,
268 PERF_MAX_STACK_DEPTH) != 0) { 268 PERF_MAX_STACK_DEPTH) != 0) {
269 pr_err("Failed to resolve callchain. Skipping\n"); 269 pr_err("Failed to resolve callchain. Skipping\n");
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index fbd05242b4e5..525eb49e7ba6 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -323,7 +323,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
323 if (!symbol_conf.use_callchain || !sample->callchain) 323 if (!symbol_conf.use_callchain || !sample->callchain)
324 goto exit; 324 goto exit;
325 325
326 if (thread__resolve_callchain(al->thread, evsel, 326 if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
327 sample, NULL, NULL, 327 sample, NULL, NULL,
328 scripting_max_stack) != 0) { 328 scripting_max_stack) != 0) {
329 pr_err("Failed to resolve callchain. Skipping\n"); 329 pr_err("Failed to resolve callchain. Skipping\n");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index bb162ee433c6..a36823c3b7c0 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -255,57 +255,6 @@ void symbol__delete(struct symbol *sym)
255 free(((void *)sym) - symbol_conf.priv_size); 255 free(((void *)sym) - symbol_conf.priv_size);
256} 256}
257 257
258size_t symbol__fprintf(struct symbol *sym, FILE *fp)
259{
260 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
261 sym->start, sym->end,
262 sym->binding == STB_GLOBAL ? 'g' :
263 sym->binding == STB_LOCAL ? 'l' : 'w',
264 sym->name);
265}
266
267size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
268 const struct addr_location *al,
269 bool unknown_as_addr, FILE *fp)
270{
271 unsigned long offset;
272 size_t length;
273
274 if (sym && sym->name) {
275 length = fprintf(fp, "%s", sym->name);
276 if (al) {
277 if (al->addr < sym->end)
278 offset = al->addr - sym->start;
279 else
280 offset = al->addr - al->map->start - sym->start;
281 length += fprintf(fp, "+0x%lx", offset);
282 }
283 return length;
284 } else if (al && unknown_as_addr)
285 return fprintf(fp, "[%#" PRIx64 "]", al->addr);
286 else
287 return fprintf(fp, "[unknown]");
288}
289
290size_t symbol__fprintf_symname_offs(const struct symbol *sym,
291 const struct addr_location *al,
292 FILE *fp)
293{
294 return __symbol__fprintf_symname_offs(sym, al, false, fp);
295}
296
297size_t __symbol__fprintf_symname(const struct symbol *sym,
298 const struct addr_location *al,
299 bool unknown_as_addr, FILE *fp)
300{
301 return __symbol__fprintf_symname_offs(sym, al, unknown_as_addr, fp);
302}
303
304size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
305{
306 return __symbol__fprintf_symname_offs(sym, NULL, false, fp);
307}
308
309void symbols__delete(struct rb_root *symbols) 258void symbols__delete(struct rb_root *symbols)
310{ 259{
311 struct symbol *pos; 260 struct symbol *pos;
@@ -381,11 +330,6 @@ static struct symbol *symbols__next(struct symbol *sym)
381 return NULL; 330 return NULL;
382} 331}
383 332
384struct symbol_name_rb_node {
385 struct rb_node rb_node;
386 struct symbol sym;
387};
388
389static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 333static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
390{ 334{
391 struct rb_node **p = &symbols->rb_node; 335 struct rb_node **p = &symbols->rb_node;
@@ -514,21 +458,6 @@ void dso__sort_by_name(struct dso *dso, enum map_type type)
514 &dso->symbols[type]); 458 &dso->symbols[type]);
515} 459}
516 460
517size_t dso__fprintf_symbols_by_name(struct dso *dso,
518 enum map_type type, FILE *fp)
519{
520 size_t ret = 0;
521 struct rb_node *nd;
522 struct symbol_name_rb_node *pos;
523
524 for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
525 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
526 fprintf(fp, "%s\n", pos->sym.name);
527 }
528
529 return ret;
530}
531
532int modules__parse(const char *filename, void *arg, 461int modules__parse(const char *filename, void *arg,
533 int (*process_module)(void *arg, const char *name, 462 int (*process_module)(void *arg, const char *name,
534 u64 start)) 463 u64 start))
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index e2562568418d..1da7b101bc7f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -140,6 +140,11 @@ struct symbol_conf {
140 140
141extern struct symbol_conf symbol_conf; 141extern struct symbol_conf symbol_conf;
142 142
143struct symbol_name_rb_node {
144 struct rb_node rb_node;
145 struct symbol sym;
146};
147
143static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) 148static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
144{ 149{
145 return path__join(bf, size, symbol_conf.symfs, path); 150 return path__join(bf, size, symbol_conf.symfs, path);
diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c
new file mode 100644
index 000000000000..a680bdaa65dc
--- /dev/null
+++ b/tools/perf/util/symbol_fprintf.c
@@ -0,0 +1,71 @@
1#include <elf.h>
2#include <inttypes.h>
3#include <stdio.h>
4
5#include "symbol.h"
6
7size_t symbol__fprintf(struct symbol *sym, FILE *fp)
8{
9 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
10 sym->start, sym->end,
11 sym->binding == STB_GLOBAL ? 'g' :
12 sym->binding == STB_LOCAL ? 'l' : 'w',
13 sym->name);
14}
15
16size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
17 const struct addr_location *al,
18 bool unknown_as_addr, FILE *fp)
19{
20 unsigned long offset;
21 size_t length;
22
23 if (sym && sym->name) {
24 length = fprintf(fp, "%s", sym->name);
25 if (al) {
26 if (al->addr < sym->end)
27 offset = al->addr - sym->start;
28 else
29 offset = al->addr - al->map->start - sym->start;
30 length += fprintf(fp, "+0x%lx", offset);
31 }
32 return length;
33 } else if (al && unknown_as_addr)
34 return fprintf(fp, "[%#" PRIx64 "]", al->addr);
35 else
36 return fprintf(fp, "[unknown]");
37}
38
39size_t symbol__fprintf_symname_offs(const struct symbol *sym,
40 const struct addr_location *al,
41 FILE *fp)
42{
43 return __symbol__fprintf_symname_offs(sym, al, false, fp);
44}
45
46size_t __symbol__fprintf_symname(const struct symbol *sym,
47 const struct addr_location *al,
48 bool unknown_as_addr, FILE *fp)
49{
50 return __symbol__fprintf_symname_offs(sym, al, unknown_as_addr, fp);
51}
52
53size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
54{
55 return __symbol__fprintf_symname_offs(sym, NULL, false, fp);
56}
57
58size_t dso__fprintf_symbols_by_name(struct dso *dso,
59 enum map_type type, FILE *fp)
60{
61 size_t ret = 0;
62 struct rb_node *nd;
63 struct symbol_name_rb_node *pos;
64
65 for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
66 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
67 fprintf(fp, "%s\n", pos->sym.name);
68 }
69
70 return ret;
71}