diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
| -rw-r--r-- | tools/perf/builtin-trace.c | 142 |
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 | ||
| 286 | static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel) | 288 | static 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 | ||
| 1031 | static const size_t trace__entry_str_size = 2048; | 1038 | static const size_t trace__entry_str_size = 2048; |
| 1032 | 1039 | ||
| 1033 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) | 1040 | static 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; | 1062 | struct file *thread__files_entry(struct thread *thread, int fd) |
| 1063 | { | ||
| 1064 | return thread_trace__files_entry(thread__priv(thread), fd); | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | static 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 | ||
| 1059 | static int thread__read_fd_path(struct thread *thread, int fd) | 1084 | static 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 | ||
| 1107 | size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg) | 1132 | size_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 | ||
| 1771 | static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, bool raw_augmented) | 1796 | static 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 | ||
| 2692 | static int bpf_map__set_filter_pids(struct bpf_map *map __maybe_unused, | 2719 | static 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; | ||
| 3831 | init_augmented_syscall_tp: | 3860 | init_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 | } |
