aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
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;