1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 #include "tp_pmu.h" 3 #include "pmus.h" 4 #include <api/fs/fs.h> 5 #include <api/fs/tracing_path.h> 6 #include <api/io_dir.h> 7 #include <linux/kernel.h> 8 #include <errno.h> 9 #include <string.h> 10 11 int tp_pmu__id(const char *sys, const char *name) 12 { 13 char *tp_dir = get_events_file(sys); 14 char path[PATH_MAX]; 15 int id, err; 16 17 if (!tp_dir) 18 return -1; 19 20 scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name); 21 put_events_file(tp_dir); 22 err = filename__read_int(path, &id); 23 if (err) 24 return err; 25 26 return id; 27 } 28 29 30 int tp_pmu__for_each_tp_event(const char *sys, void *state, tp_event_callback cb) 31 { 32 char *evt_path; 33 struct io_dirent64 *evt_ent; 34 struct io_dir evt_dir; 35 int ret = 0; 36 37 evt_path = get_events_file(sys); 38 if (!evt_path) 39 return -errno; 40 41 io_dir__init(&evt_dir, open(evt_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY)); 42 if (evt_dir.dirfd < 0) { 43 ret = -errno; 44 put_events_file(evt_path); 45 return ret; 46 } 47 put_events_file(evt_path); 48 49 while (!ret && (evt_ent = io_dir__readdir(&evt_dir))) { 50 if (!strcmp(evt_ent->d_name, ".") 51 || !strcmp(evt_ent->d_name, "..") 52 || !strcmp(evt_ent->d_name, "enable") 53 || !strcmp(evt_ent->d_name, "filter")) 54 continue; 55 56 ret = cb(state, sys, evt_ent->d_name); 57 if (ret) 58 break; 59 } 60 close(evt_dir.dirfd); 61 return ret; 62 } 63 64 int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb) 65 { 66 struct io_dirent64 *events_ent; 67 struct io_dir events_dir; 68 int ret = 0; 69 char *events_dir_path = get_tracing_file("events"); 70 71 if (!events_dir_path) 72 return -errno; 73 74 io_dir__init(&events_dir, open(events_dir_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY)); 75 if (events_dir.dirfd < 0) { 76 ret = -errno; 77 put_events_file(events_dir_path); 78 return ret; 79 } 80 put_events_file(events_dir_path); 81 82 while (!ret && (events_ent = io_dir__readdir(&events_dir))) { 83 if (!strcmp(events_ent->d_name, ".") || 84 !strcmp(events_ent->d_name, "..") || 85 !strcmp(events_ent->d_name, "enable") || 86 !strcmp(events_ent->d_name, "header_event") || 87 !strcmp(events_ent->d_name, "header_page")) 88 continue; 89 90 ret = cb(state, events_ent->d_name); 91 if (ret) 92 break; 93 } 94 close(events_dir.dirfd); 95 return ret; 96 } 97 98 bool perf_pmu__is_tracepoint(const struct perf_pmu *pmu) 99 { 100 return pmu->type == PERF_TYPE_TRACEPOINT; 101 } 102 103 struct for_each_event_args { 104 void *state; 105 pmu_event_callback cb; 106 const struct perf_pmu *pmu; 107 }; 108 109 static int for_each_event_cb(void *state, const char *sys_name, const char *evt_name) 110 { 111 struct for_each_event_args *args = state; 112 char name[2 * FILENAME_MAX + 2]; 113 /* 16 possible hex digits and 22 other characters and \0. */ 114 char encoding[16 + 22]; 115 char *format = NULL; 116 size_t format_size; 117 struct pmu_event_info info = { 118 .pmu = args->pmu, 119 .pmu_name = args->pmu->name, 120 .event_type_desc = "Tracepoint event", 121 }; 122 char *tp_dir = get_events_file(sys_name); 123 char path[PATH_MAX]; 124 int id, err; 125 126 if (!tp_dir) 127 return -1; 128 129 scnprintf(path, sizeof(path), "%s/%s/id", tp_dir, evt_name); 130 err = filename__read_int(path, &id); 131 if (err == 0) { 132 snprintf(encoding, sizeof(encoding), "tracepoint/config=0x%x/", id); 133 info.encoding_desc = encoding; 134 } 135 136 scnprintf(path, sizeof(path), "%s/%s/format", tp_dir, evt_name); 137 put_events_file(tp_dir); 138 err = filename__read_str(path, &format, &format_size); 139 if (err == 0) { 140 info.long_desc = format; 141 for (size_t i = 0 ; i < format_size; i++) { 142 /* Swap tabs to spaces due to some rendering issues. */ 143 if (format[i] == '\t') 144 format[i] = ' '; 145 } 146 } 147 snprintf(name, sizeof(name), "%s:%s", sys_name, evt_name); 148 info.name = name; 149 err = args->cb(args->state, &info); 150 free(format); 151 return err; 152 } 153 154 static int for_each_event_sys_cb(void *state, const char *sys_name) 155 { 156 return tp_pmu__for_each_tp_event(sys_name, state, for_each_event_cb); 157 } 158 159 int tp_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb) 160 { 161 struct for_each_event_args args = { 162 .state = state, 163 .cb = cb, 164 .pmu = pmu, 165 }; 166 167 return tp_pmu__for_each_tp_sys(&args, for_each_event_sys_cb); 168 } 169 170 static int num_events_cb(void *state, const char *sys_name __maybe_unused, 171 const char *evt_name __maybe_unused) 172 { 173 size_t *count = state; 174 175 (*count)++; 176 return 0; 177 } 178 179 static int num_events_sys_cb(void *state, const char *sys_name) 180 { 181 return tp_pmu__for_each_tp_event(sys_name, state, num_events_cb); 182 } 183 184 size_t tp_pmu__num_events(struct perf_pmu *pmu __maybe_unused) 185 { 186 size_t count = 0; 187 188 tp_pmu__for_each_tp_sys(&count, num_events_sys_cb); 189 return count; 190 } 191 192 bool tp_pmu__have_event(struct perf_pmu *pmu __maybe_unused, const char *name) 193 { 194 char *dup_name, *colon; 195 int id; 196 197 colon = strchr(name, ':'); 198 if (colon == NULL) 199 return false; 200 201 dup_name = strdup(name); 202 if (!dup_name) 203 return false; 204 205 colon = dup_name + (colon - name); 206 *colon = '\0'; 207 id = tp_pmu__id(dup_name, colon + 1); 208 free(dup_name); 209 return id >= 0; 210 } 211