aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c142
1 files changed, 97 insertions, 45 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index ebde59e61133..adbf28183560 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -60,6 +60,7 @@
60#include <linux/stringify.h> 60#include <linux/stringify.h>
61#include <linux/time64.h> 61#include <linux/time64.h>
62#include <fcntl.h> 62#include <fcntl.h>
63#include <sys/sysmacros.h>
63 64
64#include "sane_ctype.h" 65#include "sane_ctype.h"
65 66
@@ -112,8 +113,9 @@ struct trace {
112 } stats; 113 } stats;
113 unsigned int max_stack; 114 unsigned int max_stack;
114 unsigned int min_stack; 115 unsigned int min_stack;
115 bool sort_events; 116 int raw_augmented_syscalls_args_size;
116 bool raw_augmented_syscalls; 117 bool raw_augmented_syscalls;
118 bool sort_events;
117 bool not_ev_qualifier; 119 bool not_ev_qualifier;
118 bool live; 120 bool live;
119 bool full_time; 121 bool full_time;
@@ -283,12 +285,17 @@ out_delete:
283 return -ENOENT; 285 return -ENOENT;
284} 286}
285 287
286static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel) 288static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel, struct perf_evsel *tp)
287{ 289{
288 struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); 290 struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
289 291
290 if (evsel->priv != NULL) { /* field, sizeof_field, offsetof_field */ 292 if (evsel->priv != NULL) {
291 if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap)) 293 struct tep_format_field *syscall_id = perf_evsel__field(tp, "id");
294 if (syscall_id == NULL)
295 syscall_id = perf_evsel__field(tp, "__syscall_nr");
296 if (syscall_id == NULL)
297 goto out_delete;
298 if (__tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
292 goto out_delete; 299 goto out_delete;
293 300
294 return 0; 301 return 0;
@@ -974,9 +981,9 @@ struct thread_trace {
974 char *name; 981 char *name;
975 } filename; 982 } filename;
976 struct { 983 struct {
977 int max; 984 int max;
978 char **table; 985 struct file *table;
979 } paths; 986 } files;
980 987
981 struct intlist *syscall_stats; 988 struct intlist *syscall_stats;
982}; 989};
@@ -986,7 +993,7 @@ static struct thread_trace *thread_trace__new(void)
986 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace)); 993 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
987 994
988 if (ttrace) 995 if (ttrace)
989 ttrace->paths.max = -1; 996 ttrace->files.max = -1;
990 997
991 ttrace->syscall_stats = intlist__new(NULL); 998 ttrace->syscall_stats = intlist__new(NULL);
992 999
@@ -1030,30 +1037,48 @@ void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
1030 1037
1031static const size_t trace__entry_str_size = 2048; 1038static const size_t trace__entry_str_size = 2048;
1032 1039
1033static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 1040static struct file *thread_trace__files_entry(struct thread_trace *ttrace, int fd)
1034{ 1041{
1035 struct thread_trace *ttrace = thread__priv(thread); 1042 if (fd > ttrace->files.max) {
1036 1043 struct file *nfiles = realloc(ttrace->files.table, (fd + 1) * sizeof(struct file));
1037 if (fd > ttrace->paths.max) {
1038 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1039 1044
1040 if (npath == NULL) 1045 if (nfiles == NULL)
1041 return -1; 1046 return NULL;
1042 1047
1043 if (ttrace->paths.max != -1) { 1048 if (ttrace->files.max != -1) {
1044 memset(npath + ttrace->paths.max + 1, 0, 1049 memset(nfiles + ttrace->files.max + 1, 0,
1045 (fd - ttrace->paths.max) * sizeof(char *)); 1050 (fd - ttrace->files.max) * sizeof(struct file));
1046 } else { 1051 } else {
1047 memset(npath, 0, (fd + 1) * sizeof(char *)); 1052 memset(nfiles, 0, (fd + 1) * sizeof(struct file));
1048 } 1053 }
1049 1054
1050 ttrace->paths.table = npath; 1055 ttrace->files.table = nfiles;
1051 ttrace->paths.max = fd; 1056 ttrace->files.max = fd;
1052 } 1057 }
1053 1058
1054 ttrace->paths.table[fd] = strdup(pathname); 1059 return ttrace->files.table + fd;
1060}
1055 1061
1056 return ttrace->paths.table[fd] != NULL ? 0 : -1; 1062struct file *thread__files_entry(struct thread *thread, int fd)
1063{
1064 return thread_trace__files_entry(thread__priv(thread), fd);
1065}
1066
1067static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
1068{
1069 struct thread_trace *ttrace = thread__priv(thread);
1070 struct file *file = thread_trace__files_entry(ttrace, fd);
1071
1072 if (file != NULL) {
1073 struct stat st;
1074 if (stat(pathname, &st) == 0)
1075 file->dev_maj = major(st.st_rdev);
1076 file->pathname = strdup(pathname);
1077 if (file->pathname)
1078 return 0;
1079 }
1080
1081 return -1;
1057} 1082}
1058 1083
1059static int thread__read_fd_path(struct thread *thread, int fd) 1084static int thread__read_fd_path(struct thread *thread, int fd)
@@ -1093,7 +1118,7 @@ static const char *thread__fd_path(struct thread *thread, int fd,
1093 if (fd < 0) 1118 if (fd < 0)
1094 return NULL; 1119 return NULL;
1095 1120
1096 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) { 1121 if ((fd > ttrace->files.max || ttrace->files.table[fd].pathname == NULL)) {
1097 if (!trace->live) 1122 if (!trace->live)
1098 return NULL; 1123 return NULL;
1099 ++trace->stats.proc_getname; 1124 ++trace->stats.proc_getname;
@@ -1101,7 +1126,7 @@ static const char *thread__fd_path(struct thread *thread, int fd,
1101 return NULL; 1126 return NULL;
1102 } 1127 }
1103 1128
1104 return ttrace->paths.table[fd]; 1129 return ttrace->files.table[fd].pathname;
1105} 1130}
1106 1131
1107size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg) 1132size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
@@ -1140,8 +1165,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1140 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); 1165 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1141 struct thread_trace *ttrace = thread__priv(arg->thread); 1166 struct thread_trace *ttrace = thread__priv(arg->thread);
1142 1167
1143 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) 1168 if (ttrace && fd >= 0 && fd <= ttrace->files.max)
1144 zfree(&ttrace->paths.table[fd]); 1169 zfree(&ttrace->files.table[fd].pathname);
1145 1170
1146 return printed; 1171 return printed;
1147} 1172}
@@ -1768,16 +1793,16 @@ static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1768 return printed; 1793 return printed;
1769} 1794}
1770 1795
1771static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, bool raw_augmented) 1796static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, int raw_augmented_args_size)
1772{ 1797{
1773 void *augmented_args = NULL; 1798 void *augmented_args = NULL;
1774 /* 1799 /*
1775 * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter 1800 * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter
1776 * and there we get all 6 syscall args plus the tracepoint common 1801 * and there we get all 6 syscall args plus the tracepoint common fields
1777 * fields (sizeof(long)) and the syscall_nr (another long). So we check 1802 * that gets calculated at the start and the syscall_nr (another long).
1778 * if that is the case and if so don't look after the sc->args_size, 1803 * So we check if that is the case and if so don't look after the
1779 * but always after the full raw_syscalls:sys_enter payload, which is 1804 * sc->args_size but always after the full raw_syscalls:sys_enter payload,
1780 * fixed. 1805 * which is fixed.
1781 * 1806 *
1782 * We'll revisit this later to pass s->args_size to the BPF augmenter 1807 * We'll revisit this later to pass s->args_size to the BPF augmenter
1783 * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it 1808 * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it
@@ -1785,7 +1810,7 @@ static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sam
1785 * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace 1810 * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace
1786 * traffic to just what is needed for each syscall. 1811 * traffic to just what is needed for each syscall.
1787 */ 1812 */
1788 int args_size = raw_augmented ? (8 * (int)sizeof(long)) : sc->args_size; 1813 int args_size = raw_augmented_args_size ?: sc->args_size;
1789 1814
1790 *augmented_args_size = sample->raw_size - args_size; 1815 *augmented_args_size = sample->raw_size - args_size;
1791 if (*augmented_args_size > 0) 1816 if (*augmented_args_size > 0)
@@ -1839,7 +1864,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1839 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one. 1864 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
1840 */ 1865 */
1841 if (evsel != trace->syscalls.events.sys_enter) 1866 if (evsel != trace->syscalls.events.sys_enter)
1842 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls); 1867 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
1843 ttrace->entry_time = sample->time; 1868 ttrace->entry_time = sample->time;
1844 msg = ttrace->entry_str; 1869 msg = ttrace->entry_str;
1845 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name); 1870 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
@@ -1897,7 +1922,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evse
1897 goto out_put; 1922 goto out_put;
1898 1923
1899 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1924 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
1900 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls); 1925 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
1901 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread); 1926 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
1902 fprintf(trace->output, "%s", msg); 1927 fprintf(trace->output, "%s", msg);
1903 err = 0; 1928 err = 0;
@@ -2686,7 +2711,9 @@ static int trace__set_ev_qualifier_filter(struct trace *trace)
2686{ 2711{
2687 if (trace->syscalls.map) 2712 if (trace->syscalls.map)
2688 return trace__set_ev_qualifier_bpf_filter(trace); 2713 return trace__set_ev_qualifier_bpf_filter(trace);
2689 return trace__set_ev_qualifier_tp_filter(trace); 2714 if (trace->syscalls.events.sys_enter)
2715 return trace__set_ev_qualifier_tp_filter(trace);
2716 return 0;
2690} 2717}
2691 2718
2692static int bpf_map__set_filter_pids(struct bpf_map *map __maybe_unused, 2719static int bpf_map__set_filter_pids(struct bpf_map *map __maybe_unused,
@@ -3812,13 +3839,6 @@ int cmd_trace(int argc, const char **argv)
3812 * syscall. 3839 * syscall.
3813 */ 3840 */
3814 if (trace.syscalls.events.augmented) { 3841 if (trace.syscalls.events.augmented) {
3815 evsel = trace.syscalls.events.augmented;
3816
3817 if (perf_evsel__init_augmented_syscall_tp(evsel) ||
3818 perf_evsel__init_augmented_syscall_tp_args(evsel))
3819 goto out;
3820 evsel->handler = trace__sys_enter;
3821
3822 evlist__for_each_entry(trace.evlist, evsel) { 3842 evlist__for_each_entry(trace.evlist, evsel) {
3823 bool raw_syscalls_sys_exit = strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_exit") == 0; 3843 bool raw_syscalls_sys_exit = strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_exit") == 0;
3824 3844
@@ -3827,9 +3847,41 @@ int cmd_trace(int argc, const char **argv)
3827 goto init_augmented_syscall_tp; 3847 goto init_augmented_syscall_tp;
3828 } 3848 }
3829 3849
3850 if (strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_enter") == 0) {
3851 struct perf_evsel *augmented = trace.syscalls.events.augmented;
3852 if (perf_evsel__init_augmented_syscall_tp(augmented, evsel) ||
3853 perf_evsel__init_augmented_syscall_tp_args(augmented))
3854 goto out;
3855 augmented->handler = trace__sys_enter;
3856 }
3857
3830 if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) { 3858 if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) {
3859 struct syscall_tp *sc;
3831init_augmented_syscall_tp: 3860init_augmented_syscall_tp:
3832 perf_evsel__init_augmented_syscall_tp(evsel); 3861 if (perf_evsel__init_augmented_syscall_tp(evsel, evsel))
3862 goto out;
3863 sc = evsel->priv;
3864 /*
3865 * For now with BPF raw_augmented we hook into
3866 * raw_syscalls:sys_enter and there we get all
3867 * 6 syscall args plus the tracepoint common
3868 * fields and the syscall_nr (another long).
3869 * So we check if that is the case and if so
3870 * don't look after the sc->args_size but
3871 * always after the full raw_syscalls:sys_enter
3872 * payload, which is fixed.
3873 *
3874 * We'll revisit this later to pass
3875 * s->args_size to the BPF augmenter (now
3876 * tools/perf/examples/bpf/augmented_raw_syscalls.c,
3877 * so that it copies only what we need for each
3878 * syscall, like what happens when we use
3879 * syscalls:sys_enter_NAME, so that we reduce
3880 * the kernel/userspace traffic to just what is
3881 * needed for each syscall.
3882 */
3883 if (trace.raw_augmented_syscalls)
3884 trace.raw_augmented_syscalls_args_size = (6 + 1) * sizeof(long) + sc->id.offset;
3833 perf_evsel__init_augmented_syscall_tp_ret(evsel); 3885 perf_evsel__init_augmented_syscall_tp_ret(evsel);
3834 evsel->handler = trace__sys_exit; 3886 evsel->handler = trace__sys_exit;
3835 } 3887 }