aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-04-13 03:02:07 -0400
committerIngo Molnar <mingo@kernel.org>2016-04-13 03:02:07 -0400
commitbed9441ba787da1026f95ce6160b38994c510fe3 (patch)
tree204a4a8d1179eb4dd709ae060627304a91c47193 /tools
parentaeaae7d612ff2ad647ba422099da56eb3aa89237 (diff)
parent00768a2bd3245eace0690fcf2c02776a256b66d7 (diff)
Merge tag 'perf-core-for-mingo-20160411' 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: - Automagically create a 'bpf-output' event, easing the setup of BPF C "scripts" that produce output via the perf ring buffer. Now it is just a matter of calling any perf tool, such as 'trace', with a C source file that references the __bpf_stdout__ output channel and that channel will be created and connected to the script: # trace -e nanosleep --event test_bpf_stdout.c usleep 1 0.013 ( 0.013 ms): usleep/2818 nanosleep(rqtp: 0x7ffcead45f40 ) ... 0.013 ( ): __bpf_stdout__:Raise a BPF event!..) 0.015 ( ): perf_bpf_probe:func_begin:(ffffffff81112460)) 0.261 ( ): __bpf_stdout__:Raise a BPF event!..) 0.262 ( ): perf_bpf_probe:func_end:(ffffffff81112460 <- ffffffff81003d92)) 0.264 ( 0.264 ms): usleep/2818 ... [continued]: nanosleep()) = 0 # Further work is needed to reduce the number of lines in a perf bpf C source file, this being the part where we greatly reduce the command line setup (Wang Nan) - 'perf trace' now supports callchains, with 'trace --call-graph dwarf' using libunwind, just like 'perf top', to ask the kernel for stack dumps for CFI processing. This reduces the overhead by asking just for userspace callchains and also only for the syscall exit tracepoint (raw_syscalls:sys_exit) (Milian Wolff, Arnaldo Carvalho de Melo) Try it with, for instance: # perf trace --call dwarf ping 127.0.0.1 An excerpt of a system wide 'perf trace --call dwarf" session is at: https://fedorapeople.org/~acme/perf/perf-trace--call-graph-dwarf--all-cpus.txt You may need to bump the number of mmap pages, using -m/--mmap-pages, but on a Broadwell machine the defaults allowed system wide tracing to work without losing that many records, experiment with just some syscalls, like: # perf trace --call dwarf -e nanosleep,futex All the targets available for 'perf record', 'perf top' (--pid, --tid, --cpu, etc) should work. Also --duration may be interesting to try. To get filenames from in various syscalls pointer args (open, ettc), add this to the mix: # perf probe 'vfs_getname=getname_flags:72 pathname=filename:string' Making this work is next in line: # trace --call dwarf --ev sched:sched_switch/call-graph=fp/ usleep 1 I.e. honouring per-tracepoint callchains in 'perf trace' in addition to in raw_syscalls:sys_exit. 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-trace.txt9
-rw-r--r--tools/perf/arch/x86/tests/perf-time-to-tsc.c2
-rw-r--r--tools/perf/arch/x86/util/dwarf-regs.c8
-rw-r--r--tools/perf/builtin-kvm.c2
-rw-r--r--tools/perf/builtin-record.c10
-rw-r--r--tools/perf/builtin-script.c78
-rw-r--r--tools/perf/builtin-top.c2
-rw-r--r--tools/perf/builtin-trace.c65
-rw-r--r--tools/perf/tests/bpf.c2
-rw-r--r--tools/perf/tests/code-reading.c2
-rw-r--r--tools/perf/tests/keep-tracking.c2
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c2
-rw-r--r--tools/perf/tests/perf-record.c2
-rw-r--r--tools/perf/tests/switch-tracking.c2
-rw-r--r--tools/perf/util/bpf-loader.c143
-rw-r--r--tools/perf/util/bpf-loader.h19
-rw-r--r--tools/perf/util/event.c12
-rw-r--r--tools/perf/util/evlist.c18
-rw-r--r--tools/perf/util/evlist.h16
-rw-r--r--tools/perf/util/evsel.c16
-rw-r--r--tools/perf/util/evsel.h14
-rw-r--r--tools/perf/util/parse-events.c60
-rw-r--r--tools/perf/util/record.c5
-rw-r--r--tools/perf/util/session.c95
-rw-r--r--tools/perf/util/session.h8
-rw-r--r--tools/perf/util/symbol.c25
-rw-r--r--tools/perf/util/symbol.h6
-rw-r--r--tools/perf/util/thread_map.c8
28 files changed, 487 insertions, 146 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 13293de8869f..1bbcf305d233 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -117,6 +117,15 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
117--syscalls:: 117--syscalls::
118 Trace system calls. This options is enabled by default. 118 Trace system calls. This options is enabled by default.
119 119
120--call-graph [mode,type,min[,limit],order[,key][,branch]]::
121 Setup and enable call-graph (stack chain/backtrace) recording.
122 See `--call-graph` section in perf-record and perf-report
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'.
125
126--kernel-syscall-graph::
127 Show the kernel callchains on the syscall exit path.
128
120--event:: 129--event::
121 Trace other events, see 'perf list' for a complete list. 130 Trace other events, see 'perf list' for a complete list.
122 131
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
index 9d29ee283ac5..d4aa567a29c4 100644
--- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c
+++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
@@ -71,7 +71,7 @@ int test__perf_time_to_tsc(int subtest __maybe_unused)
71 71
72 CHECK__(parse_events(evlist, "cycles:u", NULL)); 72 CHECK__(parse_events(evlist, "cycles:u", NULL));
73 73
74 perf_evlist__config(evlist, &opts); 74 perf_evlist__config(evlist, &opts, NULL);
75 75
76 evsel = perf_evlist__first(evlist); 76 evsel = perf_evlist__first(evlist);
77 77
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c
index 9223c164e545..1f86ee8fb831 100644
--- a/tools/perf/arch/x86/util/dwarf-regs.c
+++ b/tools/perf/arch/x86/util/dwarf-regs.c
@@ -63,6 +63,8 @@ struct pt_regs_offset {
63# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} 63# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)}
64#endif 64#endif
65 65
66/* TODO: switching by dwarf address size */
67#ifndef __x86_64__
66static const struct pt_regs_offset x86_32_regoffset_table[] = { 68static const struct pt_regs_offset x86_32_regoffset_table[] = {
67 REG_OFFSET_NAME_32("%ax", eax), 69 REG_OFFSET_NAME_32("%ax", eax),
68 REG_OFFSET_NAME_32("%cx", ecx), 70 REG_OFFSET_NAME_32("%cx", ecx),
@@ -75,6 +77,8 @@ static const struct pt_regs_offset x86_32_regoffset_table[] = {
75 REG_OFFSET_END, 77 REG_OFFSET_END,
76}; 78};
77 79
80#define regoffset_table x86_32_regoffset_table
81#else
78static const struct pt_regs_offset x86_64_regoffset_table[] = { 82static const struct pt_regs_offset x86_64_regoffset_table[] = {
79 REG_OFFSET_NAME_64("%ax", rax), 83 REG_OFFSET_NAME_64("%ax", rax),
80 REG_OFFSET_NAME_64("%dx", rdx), 84 REG_OFFSET_NAME_64("%dx", rdx),
@@ -95,11 +99,7 @@ static const struct pt_regs_offset x86_64_regoffset_table[] = {
95 REG_OFFSET_END, 99 REG_OFFSET_END,
96}; 100};
97 101
98/* TODO: switching by dwarf address size */
99#ifdef __x86_64__
100#define regoffset_table x86_64_regoffset_table 102#define regoffset_table x86_64_regoffset_table
101#else
102#define regoffset_table x86_32_regoffset_table
103#endif 103#endif
104 104
105/* Minus 1 for the ending REG_OFFSET_END */ 105/* Minus 1 for the ending REG_OFFSET_END */
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index bff666458b28..6487c06d2708 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -982,7 +982,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
982 struct perf_evlist *evlist = kvm->evlist; 982 struct perf_evlist *evlist = kvm->evlist;
983 char sbuf[STRERR_BUFSIZE]; 983 char sbuf[STRERR_BUFSIZE];
984 984
985 perf_evlist__config(evlist, &kvm->opts); 985 perf_evlist__config(evlist, &kvm->opts, NULL);
986 986
987 /* 987 /*
988 * Note: exclude_{guest,host} do not apply here. 988 * Note: exclude_{guest,host} do not apply here.
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 410035c6e300..eb6a199a833c 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -284,7 +284,7 @@ static int record__open(struct record *rec)
284 struct record_opts *opts = &rec->opts; 284 struct record_opts *opts = &rec->opts;
285 int rc = 0; 285 int rc = 0;
286 286
287 perf_evlist__config(evlist, opts); 287 perf_evlist__config(evlist, opts, &callchain_param);
288 288
289 evlist__for_each(evlist, pos) { 289 evlist__for_each(evlist, pos) {
290try_again: 290try_again:
@@ -1276,6 +1276,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1276 if (err) 1276 if (err)
1277 return err; 1277 return err;
1278 1278
1279 err = bpf__setup_stdout(rec->evlist);
1280 if (err) {
1281 bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf));
1282 pr_err("ERROR: Setup BPF stdout failed: %s\n",
1283 errbuf);
1284 return err;
1285 }
1286
1279 err = -ENOMEM; 1287 err = -ENOMEM;
1280 1288
1281 symbol__init(NULL); 1289 symbol__init(NULL);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 59009aa7e2ca..ddd5b79e94c2 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -579,8 +579,8 @@ static void print_sample_bts(struct perf_sample *sample,
579 print_opts &= ~PRINT_IP_OPT_SRCLINE; 579 print_opts &= ~PRINT_IP_OPT_SRCLINE;
580 } 580 }
581 } 581 }
582 perf_evsel__print_ip(evsel, sample, al, print_opts, 582 perf_evsel__fprintf_sym(evsel, sample, al, 0, print_opts,
583 scripting_max_stack); 583 scripting_max_stack, stdout);
584 } 584 }
585 585
586 /* print branch_to information */ 586 /* print branch_to information */
@@ -788,9 +788,9 @@ static void process_event(struct perf_script *script,
788 else 788 else
789 printf("\n"); 789 printf("\n");
790 790
791 perf_evsel__print_ip(evsel, sample, al, 791 perf_evsel__fprintf_sym(evsel, sample, al, 0,
792 output[attr->type].print_ip_opts, 792 output[attr->type].print_ip_opts,
793 scripting_max_stack); 793 scripting_max_stack, stdout);
794 } 794 }
795 795
796 if (PRINT_FIELD(IREGS)) 796 if (PRINT_FIELD(IREGS))
@@ -1415,21 +1415,19 @@ static int is_directory(const char *base_path, const struct dirent *dent)
1415 return S_ISDIR(st.st_mode); 1415 return S_ISDIR(st.st_mode);
1416} 1416}
1417 1417
1418#define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\ 1418#define for_each_lang(scripts_path, scripts_dir, lang_dirent) \
1419 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ 1419 while ((lang_dirent = readdir(scripts_dir)) != NULL) \
1420 lang_next) \ 1420 if ((lang_dirent->d_type == DT_DIR || \
1421 if ((lang_dirent.d_type == DT_DIR || \ 1421 (lang_dirent->d_type == DT_UNKNOWN && \
1422 (lang_dirent.d_type == DT_UNKNOWN && \ 1422 is_directory(scripts_path, lang_dirent))) && \
1423 is_directory(scripts_path, &lang_dirent))) && \ 1423 (strcmp(lang_dirent->d_name, ".")) && \
1424 (strcmp(lang_dirent.d_name, ".")) && \ 1424 (strcmp(lang_dirent->d_name, "..")))
1425 (strcmp(lang_dirent.d_name, "..")))
1426 1425
1427#define for_each_script(lang_path, lang_dir, script_dirent, script_next)\ 1426#define for_each_script(lang_path, lang_dir, script_dirent) \
1428 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ 1427 while ((script_dirent = readdir(lang_dir)) != NULL) \
1429 script_next) \ 1428 if (script_dirent->d_type != DT_DIR && \
1430 if (script_dirent.d_type != DT_DIR && \ 1429 (script_dirent->d_type != DT_UNKNOWN || \
1431 (script_dirent.d_type != DT_UNKNOWN || \ 1430 !is_directory(lang_path, script_dirent)))
1432 !is_directory(lang_path, &script_dirent)))
1433 1431
1434 1432
1435#define RECORD_SUFFIX "-record" 1433#define RECORD_SUFFIX "-record"
@@ -1575,7 +1573,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1575 const char *s __maybe_unused, 1573 const char *s __maybe_unused,
1576 int unset __maybe_unused) 1574 int unset __maybe_unused)
1577{ 1575{
1578 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 1576 struct dirent *script_dirent, *lang_dirent;
1579 char scripts_path[MAXPATHLEN]; 1577 char scripts_path[MAXPATHLEN];
1580 DIR *scripts_dir, *lang_dir; 1578 DIR *scripts_dir, *lang_dir;
1581 char script_path[MAXPATHLEN]; 1579 char script_path[MAXPATHLEN];
@@ -1590,19 +1588,19 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1590 if (!scripts_dir) 1588 if (!scripts_dir)
1591 return -1; 1589 return -1;
1592 1590
1593 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { 1591 for_each_lang(scripts_path, scripts_dir, lang_dirent) {
1594 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 1592 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
1595 lang_dirent.d_name); 1593 lang_dirent->d_name);
1596 lang_dir = opendir(lang_path); 1594 lang_dir = opendir(lang_path);
1597 if (!lang_dir) 1595 if (!lang_dir)
1598 continue; 1596 continue;
1599 1597
1600 for_each_script(lang_path, lang_dir, script_dirent, script_next) { 1598 for_each_script(lang_path, lang_dir, script_dirent) {
1601 script_root = get_script_root(&script_dirent, REPORT_SUFFIX); 1599 script_root = get_script_root(script_dirent, REPORT_SUFFIX);
1602 if (script_root) { 1600 if (script_root) {
1603 desc = script_desc__findnew(script_root); 1601 desc = script_desc__findnew(script_root);
1604 snprintf(script_path, MAXPATHLEN, "%s/%s", 1602 snprintf(script_path, MAXPATHLEN, "%s/%s",
1605 lang_path, script_dirent.d_name); 1603 lang_path, script_dirent->d_name);
1606 read_script_info(desc, script_path); 1604 read_script_info(desc, script_path);
1607 free(script_root); 1605 free(script_root);
1608 } 1606 }
@@ -1690,7 +1688,7 @@ static int check_ev_match(char *dir_name, char *scriptname,
1690 */ 1688 */
1691int find_scripts(char **scripts_array, char **scripts_path_array) 1689int find_scripts(char **scripts_array, char **scripts_path_array)
1692{ 1690{
1693 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 1691 struct dirent *script_dirent, *lang_dirent;
1694 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; 1692 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
1695 DIR *scripts_dir, *lang_dir; 1693 DIR *scripts_dir, *lang_dir;
1696 struct perf_session *session; 1694 struct perf_session *session;
@@ -1713,9 +1711,9 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1713 return -1; 1711 return -1;
1714 } 1712 }
1715 1713
1716 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { 1714 for_each_lang(scripts_path, scripts_dir, lang_dirent) {
1717 snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, 1715 snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path,
1718 lang_dirent.d_name); 1716 lang_dirent->d_name);
1719#ifdef NO_LIBPERL 1717#ifdef NO_LIBPERL
1720 if (strstr(lang_path, "perl")) 1718 if (strstr(lang_path, "perl"))
1721 continue; 1719 continue;
@@ -1729,16 +1727,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1729 if (!lang_dir) 1727 if (!lang_dir)
1730 continue; 1728 continue;
1731 1729
1732 for_each_script(lang_path, lang_dir, script_dirent, script_next) { 1730 for_each_script(lang_path, lang_dir, script_dirent) {
1733 /* Skip those real time scripts: xxxtop.p[yl] */ 1731 /* Skip those real time scripts: xxxtop.p[yl] */
1734 if (strstr(script_dirent.d_name, "top.")) 1732 if (strstr(script_dirent->d_name, "top."))
1735 continue; 1733 continue;
1736 sprintf(scripts_path_array[i], "%s/%s", lang_path, 1734 sprintf(scripts_path_array[i], "%s/%s", lang_path,
1737 script_dirent.d_name); 1735 script_dirent->d_name);
1738 temp = strchr(script_dirent.d_name, '.'); 1736 temp = strchr(script_dirent->d_name, '.');
1739 snprintf(scripts_array[i], 1737 snprintf(scripts_array[i],
1740 (temp - script_dirent.d_name) + 1, 1738 (temp - script_dirent->d_name) + 1,
1741 "%s", script_dirent.d_name); 1739 "%s", script_dirent->d_name);
1742 1740
1743 if (check_ev_match(lang_path, 1741 if (check_ev_match(lang_path,
1744 scripts_array[i], session)) 1742 scripts_array[i], session))
@@ -1756,7 +1754,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1756 1754
1757static char *get_script_path(const char *script_root, const char *suffix) 1755static char *get_script_path(const char *script_root, const char *suffix)
1758{ 1756{
1759 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 1757 struct dirent *script_dirent, *lang_dirent;
1760 char scripts_path[MAXPATHLEN]; 1758 char scripts_path[MAXPATHLEN];
1761 char script_path[MAXPATHLEN]; 1759 char script_path[MAXPATHLEN];
1762 DIR *scripts_dir, *lang_dir; 1760 DIR *scripts_dir, *lang_dir;
@@ -1769,21 +1767,21 @@ static char *get_script_path(const char *script_root, const char *suffix)
1769 if (!scripts_dir) 1767 if (!scripts_dir)
1770 return NULL; 1768 return NULL;
1771 1769
1772 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { 1770 for_each_lang(scripts_path, scripts_dir, lang_dirent) {
1773 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 1771 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
1774 lang_dirent.d_name); 1772 lang_dirent->d_name);
1775 lang_dir = opendir(lang_path); 1773 lang_dir = opendir(lang_path);
1776 if (!lang_dir) 1774 if (!lang_dir)
1777 continue; 1775 continue;
1778 1776
1779 for_each_script(lang_path, lang_dir, script_dirent, script_next) { 1777 for_each_script(lang_path, lang_dir, script_dirent) {
1780 __script_root = get_script_root(&script_dirent, suffix); 1778 __script_root = get_script_root(script_dirent, suffix);
1781 if (__script_root && !strcmp(script_root, __script_root)) { 1779 if (__script_root && !strcmp(script_root, __script_root)) {
1782 free(__script_root); 1780 free(__script_root);
1783 closedir(lang_dir); 1781 closedir(lang_dir);
1784 closedir(scripts_dir); 1782 closedir(scripts_dir);
1785 snprintf(script_path, MAXPATHLEN, "%s/%s", 1783 snprintf(script_path, MAXPATHLEN, "%s/%s",
1786 lang_path, script_dirent.d_name); 1784 lang_path, script_dirent->d_name);
1787 return strdup(script_path); 1785 return strdup(script_path);
1788 } 1786 }
1789 free(__script_root); 1787 free(__script_root);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 833214979c4f..8846df0ec0c3 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -886,7 +886,7 @@ static int perf_top__start_counters(struct perf_top *top)
886 struct perf_evlist *evlist = top->evlist; 886 struct perf_evlist *evlist = top->evlist;
887 struct record_opts *opts = &top->record_opts; 887 struct record_opts *opts = &top->record_opts;
888 888
889 perf_evlist__config(evlist, opts); 889 perf_evlist__config(evlist, opts, &callchain_param);
890 890
891 evlist__for_each(evlist, counter) { 891 evlist__for_each(evlist, counter) {
892try_again: 892try_again:
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 11290b57ce04..2ec53edcf649 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -34,6 +34,7 @@
34#include "trace-event.h" 34#include "trace-event.h"
35#include "util/parse-events.h" 35#include "util/parse-events.h"
36#include "util/bpf-loader.h" 36#include "util/bpf-loader.h"
37#include "callchain.h"
37#include "syscalltbl.h" 38#include "syscalltbl.h"
38 39
39#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ 40#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
@@ -158,6 +159,7 @@ struct trace {
158 bool show_comm; 159 bool show_comm;
159 bool show_tool_stats; 160 bool show_tool_stats;
160 bool trace_syscalls; 161 bool trace_syscalls;
162 bool kernel_syscallchains;
161 bool force; 163 bool force;
162 bool vfs_getname; 164 bool vfs_getname;
163 int trace_pgfaults; 165 int trace_pgfaults;
@@ -2190,6 +2192,22 @@ signed_print:
2190 goto signed_print; 2192 goto signed_print;
2191 2193
2192 fputc('\n', trace->output); 2194 fputc('\n', trace->output);
2195
2196 if (sample->callchain) {
2197 struct addr_location al;
2198 /* TODO: user-configurable print_opts */
2199 const unsigned int print_opts = PRINT_IP_OPT_SYM |
2200 PRINT_IP_OPT_DSO |
2201 PRINT_IP_OPT_UNKNOWN_AS_ADDR;
2202
2203 if (machine__resolve(trace->host, &al, sample) < 0) {
2204 pr_err("problem processing %d event, skipping it.\n",
2205 event->header.type);
2206 goto out_put;
2207 }
2208 perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
2209 scripting_max_stack, trace->output);
2210 }
2193out: 2211out:
2194 ttrace->entry_pending = false; 2212 ttrace->entry_pending = false;
2195 err = 0; 2213 err = 0;
@@ -2645,6 +2663,15 @@ static int trace__add_syscall_newtp(struct trace *trace)
2645 perf_evlist__add(evlist, sys_enter); 2663 perf_evlist__add(evlist, sys_enter);
2646 perf_evlist__add(evlist, sys_exit); 2664 perf_evlist__add(evlist, sys_exit);
2647 2665
2666 if (trace->opts.callgraph_set && !trace->kernel_syscallchains) {
2667 /*
2668 * We're interested only in the user space callchain
2669 * leading to the syscall, allow overriding that for
2670 * debugging reasons using --kernel_syscall_callchains
2671 */
2672 sys_exit->attr.exclude_callchain_kernel = 1;
2673 }
2674
2648 trace->syscalls.events.sys_enter = sys_enter; 2675 trace->syscalls.events.sys_enter = sys_enter;
2649 trace->syscalls.events.sys_exit = sys_exit; 2676 trace->syscalls.events.sys_exit = sys_exit;
2650 2677
@@ -2723,7 +2750,27 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2723 goto out_delete_evlist; 2750 goto out_delete_evlist;
2724 } 2751 }
2725 2752
2726 perf_evlist__config(evlist, &trace->opts); 2753 perf_evlist__config(evlist, &trace->opts, NULL);
2754
2755 if (trace->opts.callgraph_set && trace->syscalls.events.sys_exit) {
2756 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2757 &trace->opts, &callchain_param);
2758 /*
2759 * Now we have evsels with different sample_ids, use
2760 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2761 * from a fixed position in each ring buffer record.
2762 *
2763 * As of this the changeset introducing this comment, this
2764 * isn't strictly needed, as the fields that can come before
2765 * PERF_SAMPLE_ID are all used, but we'll probably disable
2766 * some of those for things like copying the payload of
2767 * pointer syscall arguments, and for vfs_getname we don't
2768 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2769 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2770 */
2771 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2772 perf_evlist__reset_sample_bit(evlist, ID);
2773 }
2727 2774
2728 signal(SIGCHLD, sig_handler); 2775 signal(SIGCHLD, sig_handler);
2729 signal(SIGINT, sig_handler); 2776 signal(SIGINT, sig_handler);
@@ -3205,6 +3252,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3205 .output = stderr, 3252 .output = stderr,
3206 .show_comm = true, 3253 .show_comm = true,
3207 .trace_syscalls = true, 3254 .trace_syscalls = true,
3255 .kernel_syscallchains = false,
3208 }; 3256 };
3209 const char *output_name = NULL; 3257 const char *output_name = NULL;
3210 const char *ev_qualifier_str = NULL; 3258 const char *ev_qualifier_str = NULL;
@@ -3250,6 +3298,11 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3250 "Trace pagefaults", parse_pagefaults, "maj"), 3298 "Trace pagefaults", parse_pagefaults, "maj"),
3251 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), 3299 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
3252 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), 3300 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
3301 OPT_CALLBACK(0, "call-graph", &trace.opts,
3302 "record_mode[,record_size]", record_callchain_help,
3303 &record_parse_callchain_opt),
3304 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3305 "Show the kernel callchains on the syscall exit path"),
3253 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, 3306 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3254 "per thread proc mmap processing timeout in ms"), 3307 "per thread proc mmap processing timeout in ms"),
3255 OPT_END() 3308 OPT_END()
@@ -3273,11 +3326,21 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3273 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands, 3326 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3274 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION); 3327 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
3275 3328
3329 err = bpf__setup_stdout(trace.evlist);
3330 if (err) {
3331 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3332 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3333 goto out;
3334 }
3335
3276 if (trace.trace_pgfaults) { 3336 if (trace.trace_pgfaults) {
3277 trace.opts.sample_address = true; 3337 trace.opts.sample_address = true;
3278 trace.opts.sample_time = true; 3338 trace.opts.sample_time = true;
3279 } 3339 }
3280 3340
3341 if (trace.opts.callgraph_set)
3342 symbol_conf.use_callchain = true;
3343
3281 if (trace.evlist->nr_entries > 0) 3344 if (trace.evlist->nr_entries > 0)
3282 evlist__set_evsel_handler(trace.evlist, trace__event_handler); 3345 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3283 3346
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index 199501c71e27..f31eed31c1a9 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -138,7 +138,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
138 perf_evlist__splice_list_tail(evlist, &parse_evlist.list); 138 perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
139 evlist->nr_groups = parse_evlist.nr_groups; 139 evlist->nr_groups = parse_evlist.nr_groups;
140 140
141 perf_evlist__config(evlist, &opts); 141 perf_evlist__config(evlist, &opts, NULL);
142 142
143 err = perf_evlist__open(evlist); 143 err = perf_evlist__open(evlist);
144 if (err < 0) { 144 if (err < 0) {
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index abd3f0ec0c0b..68a69a195545 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -532,7 +532,7 @@ static int do_test_code_reading(bool try_kcore)
532 goto out_put; 532 goto out_put;
533 } 533 }
534 534
535 perf_evlist__config(evlist, &opts); 535 perf_evlist__config(evlist, &opts, NULL);
536 536
537 evsel = perf_evlist__first(evlist); 537 evsel = perf_evlist__first(evlist);
538 538
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index ddb78fae064a..614e45a3c603 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -80,7 +80,7 @@ int test__keep_tracking(int subtest __maybe_unused)
80 CHECK__(parse_events(evlist, "dummy:u", NULL)); 80 CHECK__(parse_events(evlist, "dummy:u", NULL));
81 CHECK__(parse_events(evlist, "cycles:u", NULL)); 81 CHECK__(parse_events(evlist, "cycles:u", NULL));
82 82
83 perf_evlist__config(evlist, &opts); 83 perf_evlist__config(evlist, &opts, NULL);
84 84
85 evsel = perf_evlist__first(evlist); 85 evsel = perf_evlist__first(evlist);
86 86
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index eb99a105f31c..4344fe482c1d 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -44,7 +44,7 @@ int test__syscall_openat_tp_fields(int subtest __maybe_unused)
44 goto out_delete_evlist; 44 goto out_delete_evlist;
45 } 45 }
46 46
47 perf_evsel__config(evsel, &opts); 47 perf_evsel__config(evsel, &opts, NULL);
48 48
49 thread_map__set_pid(evlist->threads, 0, getpid()); 49 thread_map__set_pid(evlist->threads, 0, getpid());
50 50
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 1cc78cefe399..b836ee6a8d9b 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -99,7 +99,7 @@ int test__PERF_RECORD(int subtest __maybe_unused)
99 perf_evsel__set_sample_bit(evsel, CPU); 99 perf_evsel__set_sample_bit(evsel, CPU);
100 perf_evsel__set_sample_bit(evsel, TID); 100 perf_evsel__set_sample_bit(evsel, TID);
101 perf_evsel__set_sample_bit(evsel, TIME); 101 perf_evsel__set_sample_bit(evsel, TIME);
102 perf_evlist__config(evlist, &opts); 102 perf_evlist__config(evlist, &opts, NULL);
103 103
104 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); 104 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
105 if (err < 0) { 105 if (err < 0) {
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index ebd80168d51e..39a689bf7574 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -417,7 +417,7 @@ int test__switch_tracking(int subtest __maybe_unused)
417 perf_evsel__set_sample_bit(tracking_evsel, TIME); 417 perf_evsel__set_sample_bit(tracking_evsel, TIME);
418 418
419 /* Config events */ 419 /* Config events */
420 perf_evlist__config(evlist, &opts); 420 perf_evlist__config(evlist, &opts, NULL);
421 421
422 /* Check moved event is still at the front */ 422 /* Check moved event is still at the front */
423 if (cycles_evsel != perf_evlist__first(evlist)) { 423 if (cycles_evsel != perf_evlist__first(evlist)) {
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 0967ce601931..493307d1414c 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -842,6 +842,58 @@ bpf_map_op__new(struct parse_events_term *term)
842 return op; 842 return op;
843} 843}
844 844
845static struct bpf_map_op *
846bpf_map_op__clone(struct bpf_map_op *op)
847{
848 struct bpf_map_op *newop;
849
850 newop = memdup(op, sizeof(*op));
851 if (!newop) {
852 pr_debug("Failed to alloc bpf_map_op\n");
853 return NULL;
854 }
855
856 INIT_LIST_HEAD(&newop->list);
857 if (op->key_type == BPF_MAP_KEY_RANGES) {
858 size_t memsz = op->k.array.nr_ranges *
859 sizeof(op->k.array.ranges[0]);
860
861 newop->k.array.ranges = memdup(op->k.array.ranges, memsz);
862 if (!newop->k.array.ranges) {
863 pr_debug("Failed to alloc indices for map\n");
864 free(newop);
865 return NULL;
866 }
867 }
868
869 return newop;
870}
871
872static struct bpf_map_priv *
873bpf_map_priv__clone(struct bpf_map_priv *priv)
874{
875 struct bpf_map_priv *newpriv;
876 struct bpf_map_op *pos, *newop;
877
878 newpriv = zalloc(sizeof(*newpriv));
879 if (!newpriv) {
880 pr_debug("No enough memory to alloc map private\n");
881 return NULL;
882 }
883 INIT_LIST_HEAD(&newpriv->ops_list);
884
885 list_for_each_entry(pos, &priv->ops_list, list) {
886 newop = bpf_map_op__clone(pos);
887 if (!newop) {
888 bpf_map_priv__purge(newpriv);
889 return NULL;
890 }
891 list_add_tail(&newop->list, &newpriv->ops_list);
892 }
893
894 return newpriv;
895}
896
845static int 897static int
846bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) 898bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op)
847{ 899{
@@ -1417,6 +1469,89 @@ int bpf__apply_obj_config(void)
1417 return 0; 1469 return 0;
1418} 1470}
1419 1471
1472#define bpf__for_each_map(pos, obj, objtmp) \
1473 bpf_object__for_each_safe(obj, objtmp) \
1474 bpf_map__for_each(pos, obj)
1475
1476#define bpf__for_each_stdout_map(pos, obj, objtmp) \
1477 bpf__for_each_map(pos, obj, objtmp) \
1478 if (bpf_map__get_name(pos) && \
1479 (strcmp("__bpf_stdout__", \
1480 bpf_map__get_name(pos)) == 0))
1481
1482int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused)
1483{
1484 struct bpf_map_priv *tmpl_priv = NULL;
1485 struct bpf_object *obj, *tmp;
1486 struct perf_evsel *evsel = NULL;
1487 struct bpf_map *map;
1488 int err;
1489 bool need_init = false;
1490
1491 bpf__for_each_stdout_map(map, obj, tmp) {
1492 struct bpf_map_priv *priv;
1493
1494 err = bpf_map__get_private(map, (void **)&priv);
1495 if (err)
1496 return -BPF_LOADER_ERRNO__INTERNAL;
1497
1498 /*
1499 * No need to check map type: type should have been
1500 * verified by kernel.
1501 */
1502 if (!need_init && !priv)
1503 need_init = !priv;
1504 if (!tmpl_priv && priv)
1505 tmpl_priv = priv;
1506 }
1507
1508 if (!need_init)
1509 return 0;
1510
1511 if (!tmpl_priv) {
1512 err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/",
1513 NULL);
1514 if (err) {
1515 pr_debug("ERROR: failed to create bpf-output event\n");
1516 return -err;
1517 }
1518
1519 evsel = perf_evlist__last(evlist);
1520 }
1521
1522 bpf__for_each_stdout_map(map, obj, tmp) {
1523 struct bpf_map_priv *priv;
1524
1525 err = bpf_map__get_private(map, (void **)&priv);
1526 if (err)
1527 return -BPF_LOADER_ERRNO__INTERNAL;
1528 if (priv)
1529 continue;
1530
1531 if (tmpl_priv) {
1532 priv = bpf_map_priv__clone(tmpl_priv);
1533 if (!priv)
1534 return -ENOMEM;
1535
1536 err = bpf_map__set_private(map, priv, bpf_map_priv__clear);
1537 if (err) {
1538 bpf_map_priv__clear(map, priv);
1539 return err;
1540 }
1541 } else if (evsel) {
1542 struct bpf_map_op *op;
1543
1544 op = bpf_map__add_newop(map, NULL);
1545 if (IS_ERR(op))
1546 return PTR_ERR(op);
1547 op->op_type = BPF_MAP_OP_SET_EVSEL;
1548 op->v.evsel = evsel;
1549 }
1550 }
1551
1552 return 0;
1553}
1554
1420#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) 1555#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
1421#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) 1556#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
1422#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) 1557#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
@@ -1590,3 +1725,11 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size)
1590 bpf__strerror_end(buf, size); 1725 bpf__strerror_end(buf, size);
1591 return 0; 1726 return 0;
1592} 1727}
1728
1729int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused,
1730 int err, char *buf, size_t size)
1731{
1732 bpf__strerror_head(err, buf, size);
1733 bpf__strerror_end(buf, size);
1734 return 0;
1735}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index be4311944e3d..941e17275aa7 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -79,6 +79,11 @@ int bpf__strerror_config_obj(struct bpf_object *obj,
79 size_t size); 79 size_t size);
80int bpf__apply_obj_config(void); 80int bpf__apply_obj_config(void);
81int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); 81int bpf__strerror_apply_obj_config(int err, char *buf, size_t size);
82
83int bpf__setup_stdout(struct perf_evlist *evlist);
84int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err,
85 char *buf, size_t size);
86
82#else 87#else
83static inline struct bpf_object * 88static inline struct bpf_object *
84bpf__prepare_load(const char *filename __maybe_unused, 89bpf__prepare_load(const char *filename __maybe_unused,
@@ -125,6 +130,12 @@ bpf__apply_obj_config(void)
125} 130}
126 131
127static inline int 132static inline int
133bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused)
134{
135 return 0;
136}
137
138static inline int
128__bpf_strerror(char *buf, size_t size) 139__bpf_strerror(char *buf, size_t size)
129{ 140{
130 if (!size) 141 if (!size)
@@ -177,5 +188,13 @@ bpf__strerror_apply_obj_config(int err __maybe_unused,
177{ 188{
178 return __bpf_strerror(buf, size); 189 return __bpf_strerror(buf, size);
179} 190}
191
192static inline int
193bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused,
194 int err __maybe_unused, char *buf,
195 size_t size)
196{
197 return __bpf_strerror(buf, size);
198}
180#endif 199#endif
181#endif 200#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index b68959037688..f6fcc6832949 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -434,7 +434,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
434{ 434{
435 char filename[PATH_MAX]; 435 char filename[PATH_MAX];
436 DIR *tasks; 436 DIR *tasks;
437 struct dirent dirent, *next; 437 struct dirent *dirent;
438 pid_t tgid, ppid; 438 pid_t tgid, ppid;
439 int rc = 0; 439 int rc = 0;
440 440
@@ -463,11 +463,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
463 return 0; 463 return 0;
464 } 464 }
465 465
466 while (!readdir_r(tasks, &dirent, &next) && next) { 466 while ((dirent = readdir(tasks)) != NULL) {
467 char *end; 467 char *end;
468 pid_t _pid; 468 pid_t _pid;
469 469
470 _pid = strtol(dirent.d_name, &end, 10); 470 _pid = strtol(dirent->d_name, &end, 10);
471 if (*end) 471 if (*end)
472 continue; 472 continue;
473 473
@@ -576,7 +576,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
576{ 576{
577 DIR *proc; 577 DIR *proc;
578 char proc_path[PATH_MAX]; 578 char proc_path[PATH_MAX];
579 struct dirent dirent, *next; 579 struct dirent *dirent;
580 union perf_event *comm_event, *mmap_event, *fork_event; 580 union perf_event *comm_event, *mmap_event, *fork_event;
581 int err = -1; 581 int err = -1;
582 582
@@ -601,9 +601,9 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
601 if (proc == NULL) 601 if (proc == NULL)
602 goto out_free_fork; 602 goto out_free_fork;
603 603
604 while (!readdir_r(proc, &dirent, &next) && next) { 604 while ((dirent = readdir(proc)) != NULL) {
605 char *end; 605 char *end;
606 pid_t pid = strtol(dirent.d_name, &end, 10); 606 pid_t pid = strtol(dirent->d_name, &end, 10);
607 607
608 if (*end) /* only interested in proper numerical dirents */ 608 if (*end) /* only interested in proper numerical dirents */
609 continue; 609 continue;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 86a03836a83f..4c9f510ae18d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1192,6 +1192,24 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus,
1192 perf_evlist__propagate_maps(evlist); 1192 perf_evlist__propagate_maps(evlist);
1193} 1193}
1194 1194
1195void __perf_evlist__set_sample_bit(struct perf_evlist *evlist,
1196 enum perf_event_sample_format bit)
1197{
1198 struct perf_evsel *evsel;
1199
1200 evlist__for_each(evlist, evsel)
1201 __perf_evsel__set_sample_bit(evsel, bit);
1202}
1203
1204void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist,
1205 enum perf_event_sample_format bit)
1206{
1207 struct perf_evsel *evsel;
1208
1209 evlist__for_each(evlist, evsel)
1210 __perf_evsel__reset_sample_bit(evsel, bit);
1211}
1212
1195int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) 1213int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel)
1196{ 1214{
1197 struct perf_evsel *evsel; 1215 struct perf_evsel *evsel;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index a0d15221db6e..da46423998e8 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -87,6 +87,17 @@ int perf_evlist__add_dummy(struct perf_evlist *evlist);
87int perf_evlist__add_newtp(struct perf_evlist *evlist, 87int perf_evlist__add_newtp(struct perf_evlist *evlist,
88 const char *sys, const char *name, void *handler); 88 const char *sys, const char *name, void *handler);
89 89
90void __perf_evlist__set_sample_bit(struct perf_evlist *evlist,
91 enum perf_event_sample_format bit);
92void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist,
93 enum perf_event_sample_format bit);
94
95#define perf_evlist__set_sample_bit(evlist, bit) \
96 __perf_evlist__set_sample_bit(evlist, PERF_SAMPLE_##bit)
97
98#define perf_evlist__reset_sample_bit(evlist, bit) \
99 __perf_evlist__reset_sample_bit(evlist, PERF_SAMPLE_##bit)
100
90int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); 101int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
91int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); 102int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid);
92int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); 103int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids);
@@ -123,11 +134,14 @@ void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
123int perf_evlist__open(struct perf_evlist *evlist); 134int perf_evlist__open(struct perf_evlist *evlist);
124void perf_evlist__close(struct perf_evlist *evlist); 135void perf_evlist__close(struct perf_evlist *evlist);
125 136
137struct callchain_param;
138
126void perf_evlist__set_id_pos(struct perf_evlist *evlist); 139void perf_evlist__set_id_pos(struct perf_evlist *evlist);
127bool perf_can_sample_identifier(void); 140bool perf_can_sample_identifier(void);
128bool perf_can_record_switch_events(void); 141bool perf_can_record_switch_events(void);
129bool perf_can_record_cpu_wide(void); 142bool perf_can_record_cpu_wide(void);
130void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts); 143void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts,
144 struct callchain_param *callchain);
131int record_opts__config(struct record_opts *opts); 145int record_opts__config(struct record_opts *opts);
132 146
133int perf_evlist__prepare_workload(struct perf_evlist *evlist, 147int perf_evlist__prepare_workload(struct perf_evlist *evlist,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3fd7c2c72f4a..d475a4ec8b57 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -562,10 +562,9 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
562 return ret; 562 return ret;
563} 563}
564 564
565static void 565void perf_evsel__config_callchain(struct perf_evsel *evsel,
566perf_evsel__config_callgraph(struct perf_evsel *evsel, 566 struct record_opts *opts,
567 struct record_opts *opts, 567 struct callchain_param *param)
568 struct callchain_param *param)
569{ 568{
570 bool function = perf_evsel__is_function_event(evsel); 569 bool function = perf_evsel__is_function_event(evsel);
571 struct perf_event_attr *attr = &evsel->attr; 570 struct perf_event_attr *attr = &evsel->attr;
@@ -705,7 +704,7 @@ static void apply_config_terms(struct perf_evsel *evsel,
705 704
706 /* set perf-event callgraph */ 705 /* set perf-event callgraph */
707 if (param.enabled) 706 if (param.enabled)
708 perf_evsel__config_callgraph(evsel, opts, &param); 707 perf_evsel__config_callchain(evsel, opts, &param);
709 } 708 }
710} 709}
711 710
@@ -737,7 +736,8 @@ static void apply_config_terms(struct perf_evsel *evsel,
737 * enable/disable events specifically, as there's no 736 * enable/disable events specifically, as there's no
738 * initial traced exec call. 737 * initial traced exec call.
739 */ 738 */
740void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) 739void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
740 struct callchain_param *callchain)
741{ 741{
742 struct perf_evsel *leader = evsel->leader; 742 struct perf_evsel *leader = evsel->leader;
743 struct perf_event_attr *attr = &evsel->attr; 743 struct perf_event_attr *attr = &evsel->attr;
@@ -812,8 +812,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
812 if (perf_evsel__is_function_event(evsel)) 812 if (perf_evsel__is_function_event(evsel))
813 evsel->attr.exclude_callchain_user = 1; 813 evsel->attr.exclude_callchain_user = 1;
814 814
815 if (callchain_param.enabled && !evsel->no_aux_samples) 815 if (callchain && callchain->enabled && !evsel->no_aux_samples)
816 perf_evsel__config_callgraph(evsel, opts, &callchain_param); 816 perf_evsel__config_callchain(evsel, opts, callchain);
817 817
818 if (opts->sample_intr_regs) { 818 if (opts->sample_intr_regs) {
819 attr->sample_regs_intr = opts->sample_intr_regs; 819 attr->sample_regs_intr = opts->sample_intr_regs;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 501ea6e565f1..1bd6c2e02dfa 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -178,8 +178,14 @@ void perf_evsel__init(struct perf_evsel *evsel,
178void perf_evsel__exit(struct perf_evsel *evsel); 178void perf_evsel__exit(struct perf_evsel *evsel);
179void perf_evsel__delete(struct perf_evsel *evsel); 179void perf_evsel__delete(struct perf_evsel *evsel);
180 180
181struct callchain_param;
182
181void perf_evsel__config(struct perf_evsel *evsel, 183void perf_evsel__config(struct perf_evsel *evsel,
182 struct record_opts *opts); 184 struct record_opts *opts,
185 struct callchain_param *callchain);
186void perf_evsel__config_callchain(struct perf_evsel *evsel,
187 struct record_opts *opts,
188 struct callchain_param *callchain);
183 189
184int __perf_evsel__sample_size(u64 sample_type); 190int __perf_evsel__sample_size(u64 sample_type);
185void perf_evsel__calc_id_pos(struct perf_evsel *evsel); 191void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
@@ -381,6 +387,12 @@ struct perf_attr_details {
381int perf_evsel__fprintf(struct perf_evsel *evsel, 387int perf_evsel__fprintf(struct perf_evsel *evsel,
382 struct perf_attr_details *details, FILE *fp); 388 struct perf_attr_details *details, FILE *fp);
383 389
390int perf_evsel__fprintf_callchain(struct perf_evsel *evsel,
391 struct perf_sample *sample,
392 struct addr_location *al, int left_alignment,
393 unsigned int print_opts,
394 unsigned int stack_depth, FILE *fp);
395
384bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 396bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
385 char *msg, size_t msgsize); 397 char *msg, size_t msgsize);
386int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, 398int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4c19d5e79d8c..bcbc983d4b12 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -138,11 +138,11 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
138#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 138#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
139#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 139#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
140 140
141#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ 141#define for_each_subsystem(sys_dir, sys_dirent) \
142 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 142 while ((sys_dirent = readdir(sys_dir)) != NULL) \
143 if (sys_dirent.d_type == DT_DIR && \ 143 if (sys_dirent->d_type == DT_DIR && \
144 (strcmp(sys_dirent.d_name, ".")) && \ 144 (strcmp(sys_dirent->d_name, ".")) && \
145 (strcmp(sys_dirent.d_name, ".."))) 145 (strcmp(sys_dirent->d_name, "..")))
146 146
147static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) 147static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
148{ 148{
@@ -159,12 +159,12 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
159 return 0; 159 return 0;
160} 160}
161 161
162#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ 162#define for_each_event(sys_dirent, evt_dir, evt_dirent) \
163 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ 163 while ((evt_dirent = readdir(evt_dir)) != NULL) \
164 if (evt_dirent.d_type == DT_DIR && \ 164 if (evt_dirent->d_type == DT_DIR && \
165 (strcmp(evt_dirent.d_name, ".")) && \ 165 (strcmp(evt_dirent->d_name, ".")) && \
166 (strcmp(evt_dirent.d_name, "..")) && \ 166 (strcmp(evt_dirent->d_name, "..")) && \
167 (!tp_event_has_id(&sys_dirent, &evt_dirent))) 167 (!tp_event_has_id(sys_dirent, evt_dirent)))
168 168
169#define MAX_EVENT_LENGTH 512 169#define MAX_EVENT_LENGTH 512
170 170
@@ -173,7 +173,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
173{ 173{
174 struct tracepoint_path *path = NULL; 174 struct tracepoint_path *path = NULL;
175 DIR *sys_dir, *evt_dir; 175 DIR *sys_dir, *evt_dir;
176 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 176 struct dirent *sys_dirent, *evt_dirent;
177 char id_buf[24]; 177 char id_buf[24];
178 int fd; 178 int fd;
179 u64 id; 179 u64 id;
@@ -184,18 +184,18 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
184 if (!sys_dir) 184 if (!sys_dir)
185 return NULL; 185 return NULL;
186 186
187 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 187 for_each_subsystem(sys_dir, sys_dirent) {
188 188
189 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, 189 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
190 sys_dirent.d_name); 190 sys_dirent->d_name);
191 evt_dir = opendir(dir_path); 191 evt_dir = opendir(dir_path);
192 if (!evt_dir) 192 if (!evt_dir)
193 continue; 193 continue;
194 194
195 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 195 for_each_event(sys_dirent, evt_dir, evt_dirent) {
196 196
197 snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, 197 snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path,
198 evt_dirent.d_name); 198 evt_dirent->d_name);
199 fd = open(evt_path, O_RDONLY); 199 fd = open(evt_path, O_RDONLY);
200 if (fd < 0) 200 if (fd < 0)
201 continue; 201 continue;
@@ -220,9 +220,9 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
220 free(path); 220 free(path);
221 return NULL; 221 return NULL;
222 } 222 }
223 strncpy(path->system, sys_dirent.d_name, 223 strncpy(path->system, sys_dirent->d_name,
224 MAX_EVENT_LENGTH); 224 MAX_EVENT_LENGTH);
225 strncpy(path->name, evt_dirent.d_name, 225 strncpy(path->name, evt_dirent->d_name,
226 MAX_EVENT_LENGTH); 226 MAX_EVENT_LENGTH);
227 return path; 227 return path;
228 } 228 }
@@ -1812,7 +1812,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
1812 bool name_only) 1812 bool name_only)
1813{ 1813{
1814 DIR *sys_dir, *evt_dir; 1814 DIR *sys_dir, *evt_dir;
1815 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 1815 struct dirent *sys_dirent, *evt_dirent;
1816 char evt_path[MAXPATHLEN]; 1816 char evt_path[MAXPATHLEN];
1817 char dir_path[MAXPATHLEN]; 1817 char dir_path[MAXPATHLEN];
1818 char **evt_list = NULL; 1818 char **evt_list = NULL;
@@ -1830,20 +1830,20 @@ restart:
1830 goto out_close_sys_dir; 1830 goto out_close_sys_dir;
1831 } 1831 }
1832 1832
1833 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 1833 for_each_subsystem(sys_dir, sys_dirent) {
1834 if (subsys_glob != NULL && 1834 if (subsys_glob != NULL &&
1835 !strglobmatch(sys_dirent.d_name, subsys_glob)) 1835 !strglobmatch(sys_dirent->d_name, subsys_glob))
1836 continue; 1836 continue;
1837 1837
1838 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, 1838 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
1839 sys_dirent.d_name); 1839 sys_dirent->d_name);
1840 evt_dir = opendir(dir_path); 1840 evt_dir = opendir(dir_path);
1841 if (!evt_dir) 1841 if (!evt_dir)
1842 continue; 1842 continue;
1843 1843
1844 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 1844 for_each_event(sys_dirent, evt_dir, evt_dirent) {
1845 if (event_glob != NULL && 1845 if (event_glob != NULL &&
1846 !strglobmatch(evt_dirent.d_name, event_glob)) 1846 !strglobmatch(evt_dirent->d_name, event_glob))
1847 continue; 1847 continue;
1848 1848
1849 if (!evt_num_known) { 1849 if (!evt_num_known) {
@@ -1852,7 +1852,7 @@ restart:
1852 } 1852 }
1853 1853
1854 snprintf(evt_path, MAXPATHLEN, "%s:%s", 1854 snprintf(evt_path, MAXPATHLEN, "%s:%s",
1855 sys_dirent.d_name, evt_dirent.d_name); 1855 sys_dirent->d_name, evt_dirent->d_name);
1856 1856
1857 evt_list[evt_i] = strdup(evt_path); 1857 evt_list[evt_i] = strdup(evt_path);
1858 if (evt_list[evt_i] == NULL) 1858 if (evt_list[evt_i] == NULL)
@@ -1905,7 +1905,7 @@ out_close_sys_dir:
1905int is_valid_tracepoint(const char *event_string) 1905int is_valid_tracepoint(const char *event_string)
1906{ 1906{
1907 DIR *sys_dir, *evt_dir; 1907 DIR *sys_dir, *evt_dir;
1908 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 1908 struct dirent *sys_dirent, *evt_dirent;
1909 char evt_path[MAXPATHLEN]; 1909 char evt_path[MAXPATHLEN];
1910 char dir_path[MAXPATHLEN]; 1910 char dir_path[MAXPATHLEN];
1911 1911
@@ -1913,17 +1913,17 @@ int is_valid_tracepoint(const char *event_string)
1913 if (!sys_dir) 1913 if (!sys_dir)
1914 return 0; 1914 return 0;
1915 1915
1916 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 1916 for_each_subsystem(sys_dir, sys_dirent) {
1917 1917
1918 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, 1918 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
1919 sys_dirent.d_name); 1919 sys_dirent->d_name);
1920 evt_dir = opendir(dir_path); 1920 evt_dir = opendir(dir_path);
1921 if (!evt_dir) 1921 if (!evt_dir)
1922 continue; 1922 continue;
1923 1923
1924 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 1924 for_each_event(sys_dirent, evt_dir, evt_dirent) {
1925 snprintf(evt_path, MAXPATHLEN, "%s:%s", 1925 snprintf(evt_path, MAXPATHLEN, "%s:%s",
1926 sys_dirent.d_name, evt_dirent.d_name); 1926 sys_dirent->d_name, evt_dirent->d_name);
1927 if (!strcmp(evt_path, event_string)) { 1927 if (!strcmp(evt_path, event_string)) {
1928 closedir(evt_dir); 1928 closedir(evt_dir);
1929 closedir(sys_dir); 1929 closedir(sys_dir);
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 0467367dc315..481792c7484b 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -129,7 +129,8 @@ bool perf_can_record_cpu_wide(void)
129 return true; 129 return true;
130} 130}
131 131
132void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) 132void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts,
133 struct callchain_param *callchain)
133{ 134{
134 struct perf_evsel *evsel; 135 struct perf_evsel *evsel;
135 bool use_sample_identifier = false; 136 bool use_sample_identifier = false;
@@ -148,7 +149,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
148 use_comm_exec = perf_can_comm_exec(); 149 use_comm_exec = perf_can_comm_exec();
149 150
150 evlist__for_each(evlist, evsel) { 151 evlist__for_each(evlist, evsel) {
151 perf_evsel__config(evsel, opts); 152 perf_evsel__config(evsel, opts, callchain);
152 if (evsel->tracking && use_comm_exec) 153 if (evsel->tracking && use_comm_exec)
153 evsel->attr.comm_exec = 1; 154 evsel->attr.comm_exec = 1;
154 } 155 }
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ef370557fb9a..0516d06a2741 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1953,10 +1953,12 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1953 return NULL; 1953 return NULL;
1954} 1954}
1955 1955
1956void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, 1956int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, struct perf_sample *sample,
1957 struct addr_location *al, 1957 struct addr_location *al, int left_alignment,
1958 unsigned int print_opts, unsigned int stack_depth) 1958 unsigned int print_opts, unsigned int stack_depth,
1959 FILE *fp)
1959{ 1960{
1961 int printed = 0;
1960 struct callchain_cursor_node *node; 1962 struct callchain_cursor_node *node;
1961 int print_ip = print_opts & PRINT_IP_OPT_IP; 1963 int print_ip = print_opts & PRINT_IP_OPT_IP;
1962 int print_sym = print_opts & PRINT_IP_OPT_SYM; 1964 int print_sym = print_opts & PRINT_IP_OPT_SYM;
@@ -1964,9 +1966,10 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
1964 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; 1966 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
1965 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; 1967 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
1966 int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; 1968 int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE;
1969 int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR;
1967 char s = print_oneline ? ' ' : '\t'; 1970 char s = print_oneline ? ' ' : '\t';
1968 1971
1969 if (symbol_conf.use_callchain && sample->callchain) { 1972 if (sample->callchain) {
1970 struct addr_location node_al; 1973 struct addr_location node_al;
1971 1974
1972 if (thread__resolve_callchain(al->thread, evsel, 1975 if (thread__resolve_callchain(al->thread, evsel,
@@ -1974,7 +1977,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
1974 stack_depth) != 0) { 1977 stack_depth) != 0) {
1975 if (verbose) 1978 if (verbose)
1976 error("Failed to resolve callchain. Skipping\n"); 1979 error("Failed to resolve callchain. Skipping\n");
1977 return; 1980 return printed;
1978 } 1981 }
1979 callchain_cursor_commit(&callchain_cursor); 1982 callchain_cursor_commit(&callchain_cursor);
1980 1983
@@ -1991,65 +1994,93 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
1991 if (node->sym && node->sym->ignore) 1994 if (node->sym && node->sym->ignore)
1992 goto next; 1995 goto next;
1993 1996
1997 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
1998
1994 if (print_ip) 1999 if (print_ip)
1995 printf("%c%16" PRIx64, s, node->ip); 2000 printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
1996 2001
1997 if (node->map) 2002 if (node->map)
1998 addr = node->map->map_ip(node->map, node->ip); 2003 addr = node->map->map_ip(node->map, node->ip);
1999 2004
2000 if (print_sym) { 2005 if (print_sym) {
2001 printf(" "); 2006 printed += fprintf(fp, " ");
2007 node_al.addr = addr;
2008 node_al.map = node->map;
2009
2002 if (print_symoffset) { 2010 if (print_symoffset) {
2003 node_al.addr = addr; 2011 printed += __symbol__fprintf_symname_offs(node->sym, &node_al,
2004 node_al.map = node->map; 2012 print_unknown_as_addr, fp);
2005 symbol__fprintf_symname_offs(node->sym, &node_al, stdout); 2013 } else {
2006 } else 2014 printed += __symbol__fprintf_symname(node->sym, &node_al,
2007 symbol__fprintf_symname(node->sym, stdout); 2015 print_unknown_as_addr, fp);
2016 }
2008 } 2017 }
2009 2018
2010 if (print_dso) { 2019 if (print_dso) {
2011 printf(" ("); 2020 printed += fprintf(fp, " (");
2012 map__fprintf_dsoname(node->map, stdout); 2021 printed += map__fprintf_dsoname(node->map, fp);
2013 printf(")"); 2022 printed += fprintf(fp, ")");
2014 } 2023 }
2015 2024
2016 if (print_srcline) 2025 if (print_srcline)
2017 map__fprintf_srcline(node->map, addr, "\n ", 2026 printed += map__fprintf_srcline(node->map, addr, "\n ", fp);
2018 stdout);
2019 2027
2020 if (!print_oneline) 2028 if (!print_oneline)
2021 printf("\n"); 2029 printed += fprintf(fp, "\n");
2022 2030
2023 stack_depth--; 2031 stack_depth--;
2024next: 2032next:
2025 callchain_cursor_advance(&callchain_cursor); 2033 callchain_cursor_advance(&callchain_cursor);
2026 } 2034 }
2035 }
2036
2037 return printed;
2038}
2039
2040int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample,
2041 struct addr_location *al, int left_alignment,
2042 unsigned int print_opts, unsigned int stack_depth,
2043 FILE *fp)
2044{
2045 int printed = 0;
2046 int print_ip = print_opts & PRINT_IP_OPT_IP;
2047 int print_sym = print_opts & PRINT_IP_OPT_SYM;
2048 int print_dso = print_opts & PRINT_IP_OPT_DSO;
2049 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
2050 int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE;
2051 int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR;
2027 2052
2028 } else { 2053 if (symbol_conf.use_callchain && sample->callchain) {
2029 if (al->sym && al->sym->ignore) 2054 printed += perf_evsel__fprintf_callchain(evsel, sample, al, left_alignment,
2030 return; 2055 print_opts, stack_depth, fp);
2056 } else if (!(al->sym && al->sym->ignore)) {
2057 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
2031 2058
2032 if (print_ip) 2059 if (print_ip)
2033 printf("%16" PRIx64, sample->ip); 2060 printed += fprintf(fp, "%16" PRIx64, sample->ip);
2034 2061
2035 if (print_sym) { 2062 if (print_sym) {
2036 printf(" "); 2063 printed += fprintf(fp, " ");
2037 if (print_symoffset) 2064 if (print_symoffset) {
2038 symbol__fprintf_symname_offs(al->sym, al, 2065 printed += __symbol__fprintf_symname_offs(al->sym, al,
2039 stdout); 2066 print_unknown_as_addr, fp);
2040 else 2067 } else {
2041 symbol__fprintf_symname(al->sym, stdout); 2068 printed += __symbol__fprintf_symname(al->sym, al,
2069 print_unknown_as_addr, fp);
2070 }
2042 } 2071 }
2043 2072
2044 if (print_dso) { 2073 if (print_dso) {
2045 printf(" ("); 2074 printed += fprintf(fp, " (");
2046 map__fprintf_dsoname(al->map, stdout); 2075 printed += map__fprintf_dsoname(al->map, fp);
2047 printf(")"); 2076 printed += fprintf(fp, ")");
2048 } 2077 }
2049 2078
2050 if (print_srcline) 2079 if (print_srcline)
2051 map__fprintf_srcline(al->map, al->addr, "\n ", stdout); 2080 printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);
2052 } 2081 }
2082
2083 return printed;
2053} 2084}
2054 2085
2055int perf_session__cpu_bitmap(struct perf_session *session, 2086int perf_session__cpu_bitmap(struct perf_session *session,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index f96fc9e8c52e..4257fac56618 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -42,6 +42,7 @@ struct perf_session {
42#define PRINT_IP_OPT_SYMOFFSET (1<<3) 42#define PRINT_IP_OPT_SYMOFFSET (1<<3)
43#define PRINT_IP_OPT_ONELINE (1<<4) 43#define PRINT_IP_OPT_ONELINE (1<<4)
44#define PRINT_IP_OPT_SRCLINE (1<<5) 44#define PRINT_IP_OPT_SRCLINE (1<<5)
45#define PRINT_IP_OPT_UNKNOWN_AS_ADDR (1<<6)
45 46
46struct perf_tool; 47struct perf_tool;
47 48
@@ -104,9 +105,10 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
104struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 105struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
105 unsigned int type); 106 unsigned int type);
106 107
107void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, 108int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample,
108 struct addr_location *al, 109 struct addr_location *al, int left_alignment,
109 unsigned int print_opts, unsigned int stack_depth); 110 unsigned int print_opts, unsigned int stack_depth,
111 FILE *fp);
110 112
111int perf_session__cpu_bitmap(struct perf_session *session, 113int perf_session__cpu_bitmap(struct perf_session *session,
112 const char *cpu_list, unsigned long *cpu_bitmap); 114 const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e7588dc91518..bb162ee433c6 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -264,8 +264,9 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp)
264 sym->name); 264 sym->name);
265} 265}
266 266
267size_t symbol__fprintf_symname_offs(const struct symbol *sym, 267size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
268 const struct addr_location *al, FILE *fp) 268 const struct addr_location *al,
269 bool unknown_as_addr, FILE *fp)
269{ 270{
270 unsigned long offset; 271 unsigned long offset;
271 size_t length; 272 size_t length;
@@ -280,13 +281,29 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
280 length += fprintf(fp, "+0x%lx", offset); 281 length += fprintf(fp, "+0x%lx", offset);
281 } 282 }
282 return length; 283 return length;
283 } else 284 } else if (al && unknown_as_addr)
285 return fprintf(fp, "[%#" PRIx64 "]", al->addr);
286 else
284 return fprintf(fp, "[unknown]"); 287 return fprintf(fp, "[unknown]");
285} 288}
286 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
287size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 304size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
288{ 305{
289 return symbol__fprintf_symname_offs(sym, NULL, fp); 306 return __symbol__fprintf_symname_offs(sym, NULL, false, fp);
290} 307}
291 308
292void symbols__delete(struct rb_root *symbols) 309void symbols__delete(struct rb_root *symbols)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index c8b7544d9267..e2562568418d 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -262,8 +262,14 @@ int symbol__init(struct perf_env *env);
262void symbol__exit(void); 262void symbol__exit(void);
263void symbol__elf_init(void); 263void symbol__elf_init(void);
264struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); 264struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
265size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
266 const struct addr_location *al,
267 bool unknown_as_addr, FILE *fp);
265size_t symbol__fprintf_symname_offs(const struct symbol *sym, 268size_t symbol__fprintf_symname_offs(const struct symbol *sym,
266 const struct addr_location *al, FILE *fp); 269 const struct addr_location *al, FILE *fp);
270size_t __symbol__fprintf_symname(const struct symbol *sym,
271 const struct addr_location *al,
272 bool unknown_as_addr, FILE *fp);
267size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); 273size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
268size_t symbol__fprintf(struct symbol *sym, FILE *fp); 274size_t symbol__fprintf(struct symbol *sym, FILE *fp);
269bool symbol_type__is_a(char symbol_type, enum map_type map_type); 275bool symbol_type__is_a(char symbol_type, enum map_type map_type);
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 08afc6909953..267112b4e3db 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -94,7 +94,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
94 DIR *proc; 94 DIR *proc;
95 int max_threads = 32, items, i; 95 int max_threads = 32, items, i;
96 char path[256]; 96 char path[256];
97 struct dirent dirent, *next, **namelist = NULL; 97 struct dirent *dirent, **namelist = NULL;
98 struct thread_map *threads = thread_map__alloc(max_threads); 98 struct thread_map *threads = thread_map__alloc(max_threads);
99 99
100 if (threads == NULL) 100 if (threads == NULL)
@@ -107,16 +107,16 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
107 threads->nr = 0; 107 threads->nr = 0;
108 atomic_set(&threads->refcnt, 1); 108 atomic_set(&threads->refcnt, 1);
109 109
110 while (!readdir_r(proc, &dirent, &next) && next) { 110 while ((dirent = readdir(proc)) != NULL) {
111 char *end; 111 char *end;
112 bool grow = false; 112 bool grow = false;
113 struct stat st; 113 struct stat st;
114 pid_t pid = strtol(dirent.d_name, &end, 10); 114 pid_t pid = strtol(dirent->d_name, &end, 10);
115 115
116 if (*end) /* only interested in proper numerical dirents */ 116 if (*end) /* only interested in proper numerical dirents */
117 continue; 117 continue;
118 118
119 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name); 119 snprintf(path, sizeof(path), "/proc/%s", dirent->d_name);
120 120
121 if (stat(path, &st) != 0) 121 if (stat(path, &st) != 0)
122 continue; 122 continue;