0001
0002
0003
0004
0005
0006 #include <dlfcn.h>
0007 #include <stdlib.h>
0008 #include <string.h>
0009 #include <dirent.h>
0010 #include <subcmd/exec-cmd.h>
0011 #include <linux/zalloc.h>
0012 #include <linux/build_bug.h>
0013
0014 #include "debug.h"
0015 #include "event.h"
0016 #include "evsel.h"
0017 #include "dso.h"
0018 #include "map.h"
0019 #include "thread.h"
0020 #include "trace-event.h"
0021 #include "symbol.h"
0022 #include "srcline.h"
0023 #include "dlfilter.h"
0024 #include "../include/perf/perf_dlfilter.h"
0025
0026 static void al_to_d_al(struct addr_location *al, struct perf_dlfilter_al *d_al)
0027 {
0028 struct symbol *sym = al->sym;
0029
0030 d_al->size = sizeof(*d_al);
0031 if (al->map) {
0032 struct dso *dso = al->map->dso;
0033
0034 if (symbol_conf.show_kernel_path && dso->long_name)
0035 d_al->dso = dso->long_name;
0036 else
0037 d_al->dso = dso->name;
0038 d_al->is_64_bit = dso->is_64_bit;
0039 d_al->buildid_size = dso->bid.size;
0040 d_al->buildid = dso->bid.data;
0041 } else {
0042 d_al->dso = NULL;
0043 d_al->is_64_bit = 0;
0044 d_al->buildid_size = 0;
0045 d_al->buildid = NULL;
0046 }
0047 if (sym) {
0048 d_al->sym = sym->name;
0049 d_al->sym_start = sym->start;
0050 d_al->sym_end = sym->end;
0051 if (al->addr < sym->end)
0052 d_al->symoff = al->addr - sym->start;
0053 else
0054 d_al->symoff = al->addr - al->map->start - sym->start;
0055 d_al->sym_binding = sym->binding;
0056 } else {
0057 d_al->sym = NULL;
0058 d_al->sym_start = 0;
0059 d_al->sym_end = 0;
0060 d_al->symoff = 0;
0061 d_al->sym_binding = 0;
0062 }
0063 d_al->addr = al->addr;
0064 d_al->comm = NULL;
0065 d_al->filtered = 0;
0066 }
0067
0068 static struct addr_location *get_al(struct dlfilter *d)
0069 {
0070 struct addr_location *al = d->al;
0071
0072 if (!al->thread && machine__resolve(d->machine, al, d->sample) < 0)
0073 return NULL;
0074 return al;
0075 }
0076
0077 static struct thread *get_thread(struct dlfilter *d)
0078 {
0079 struct addr_location *al = get_al(d);
0080
0081 return al ? al->thread : NULL;
0082 }
0083
0084 static const struct perf_dlfilter_al *dlfilter__resolve_ip(void *ctx)
0085 {
0086 struct dlfilter *d = (struct dlfilter *)ctx;
0087 struct perf_dlfilter_al *d_al = d->d_ip_al;
0088 struct addr_location *al;
0089
0090 if (!d->ctx_valid)
0091 return NULL;
0092
0093
0094 if (d_al->size)
0095 return d_al;
0096
0097 al = get_al(d);
0098 if (!al)
0099 return NULL;
0100
0101 al_to_d_al(al, d_al);
0102
0103 d_al->is_kernel_ip = machine__kernel_ip(d->machine, d->sample->ip);
0104 d_al->comm = al->thread ? thread__comm_str(al->thread) : ":-1";
0105 d_al->filtered = al->filtered;
0106
0107 return d_al;
0108 }
0109
0110 static const struct perf_dlfilter_al *dlfilter__resolve_addr(void *ctx)
0111 {
0112 struct dlfilter *d = (struct dlfilter *)ctx;
0113 struct perf_dlfilter_al *d_addr_al = d->d_addr_al;
0114 struct addr_location *addr_al = d->addr_al;
0115
0116 if (!d->ctx_valid || !d->d_sample->addr_correlates_sym)
0117 return NULL;
0118
0119
0120 if (d_addr_al->size)
0121 return d_addr_al;
0122
0123 if (!addr_al->thread) {
0124 struct thread *thread = get_thread(d);
0125
0126 if (!thread)
0127 return NULL;
0128 thread__resolve(thread, addr_al, d->sample);
0129 }
0130
0131 al_to_d_al(addr_al, d_addr_al);
0132
0133 d_addr_al->is_kernel_ip = machine__kernel_ip(d->machine, d->sample->addr);
0134
0135 return d_addr_al;
0136 }
0137
0138 static char **dlfilter__args(void *ctx, int *dlargc)
0139 {
0140 struct dlfilter *d = (struct dlfilter *)ctx;
0141
0142 if (dlargc)
0143 *dlargc = 0;
0144 else
0145 return NULL;
0146
0147 if (!d->ctx_valid && !d->in_start && !d->in_stop)
0148 return NULL;
0149
0150 *dlargc = d->dlargc;
0151 return d->dlargv;
0152 }
0153
0154 static __s32 dlfilter__resolve_address(void *ctx, __u64 address, struct perf_dlfilter_al *d_al_p)
0155 {
0156 struct dlfilter *d = (struct dlfilter *)ctx;
0157 struct perf_dlfilter_al d_al;
0158 struct addr_location al;
0159 struct thread *thread;
0160 __u32 sz;
0161
0162 if (!d->ctx_valid || !d_al_p)
0163 return -1;
0164
0165 thread = get_thread(d);
0166 if (!thread)
0167 return -1;
0168
0169 thread__find_symbol_fb(thread, d->sample->cpumode, address, &al);
0170
0171 al_to_d_al(&al, &d_al);
0172
0173 d_al.is_kernel_ip = machine__kernel_ip(d->machine, address);
0174
0175 sz = d_al_p->size;
0176 memcpy(d_al_p, &d_al, min((size_t)sz, sizeof(d_al)));
0177 d_al_p->size = sz;
0178
0179 return 0;
0180 }
0181
0182 static const __u8 *dlfilter__insn(void *ctx, __u32 *len)
0183 {
0184 struct dlfilter *d = (struct dlfilter *)ctx;
0185
0186 if (!len)
0187 return NULL;
0188
0189 *len = 0;
0190
0191 if (!d->ctx_valid)
0192 return NULL;
0193
0194 if (d->sample->ip && !d->sample->insn_len) {
0195 struct addr_location *al = d->al;
0196
0197 if (!al->thread && machine__resolve(d->machine, al, d->sample) < 0)
0198 return NULL;
0199
0200 if (al->thread->maps && al->thread->maps->machine)
0201 script_fetch_insn(d->sample, al->thread, al->thread->maps->machine);
0202 }
0203
0204 if (!d->sample->insn_len)
0205 return NULL;
0206
0207 *len = d->sample->insn_len;
0208
0209 return (__u8 *)d->sample->insn;
0210 }
0211
0212 static const char *dlfilter__srcline(void *ctx, __u32 *line_no)
0213 {
0214 struct dlfilter *d = (struct dlfilter *)ctx;
0215 struct addr_location *al;
0216 unsigned int line = 0;
0217 char *srcfile = NULL;
0218 struct map *map;
0219 u64 addr;
0220
0221 if (!d->ctx_valid || !line_no)
0222 return NULL;
0223
0224 al = get_al(d);
0225 if (!al)
0226 return NULL;
0227
0228 map = al->map;
0229 addr = al->addr;
0230
0231 if (map && map->dso)
0232 srcfile = get_srcline_split(map->dso, map__rip_2objdump(map, addr), &line);
0233
0234 *line_no = line;
0235 return srcfile;
0236 }
0237
0238 static struct perf_event_attr *dlfilter__attr(void *ctx)
0239 {
0240 struct dlfilter *d = (struct dlfilter *)ctx;
0241
0242 if (!d->ctx_valid)
0243 return NULL;
0244
0245 return &d->evsel->core.attr;
0246 }
0247
0248 static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len)
0249 {
0250 struct dlfilter *d = (struct dlfilter *)ctx;
0251 struct addr_location *al;
0252 struct addr_location a;
0253 struct map *map;
0254 u64 offset;
0255
0256 if (!d->ctx_valid)
0257 return -1;
0258
0259 al = get_al(d);
0260 if (!al)
0261 return -1;
0262
0263 map = al->map;
0264
0265 if (map && ip >= map->start && ip < map->end &&
0266 machine__kernel_ip(d->machine, ip) == machine__kernel_ip(d->machine, d->sample->ip))
0267 goto have_map;
0268
0269 thread__find_map_fb(al->thread, d->sample->cpumode, ip, &a);
0270 if (!a.map)
0271 return -1;
0272
0273 map = a.map;
0274 have_map:
0275 offset = map->map_ip(map, ip);
0276 if (ip + len >= map->end)
0277 len = map->end - ip;
0278 return dso__data_read_offset(map->dso, d->machine, offset, buf, len);
0279 }
0280
0281 static const struct perf_dlfilter_fns perf_dlfilter_fns = {
0282 .resolve_ip = dlfilter__resolve_ip,
0283 .resolve_addr = dlfilter__resolve_addr,
0284 .args = dlfilter__args,
0285 .resolve_address = dlfilter__resolve_address,
0286 .insn = dlfilter__insn,
0287 .srcline = dlfilter__srcline,
0288 .attr = dlfilter__attr,
0289 .object_code = dlfilter__object_code,
0290 };
0291
0292 static char *find_dlfilter(const char *file)
0293 {
0294 char path[PATH_MAX];
0295 char *exec_path;
0296
0297 if (strchr(file, '/'))
0298 goto out;
0299
0300 if (!access(file, R_OK)) {
0301
0302
0303
0304
0305 snprintf(path, sizeof(path), "./%s", file);
0306 file = path;
0307 goto out;
0308 }
0309
0310 exec_path = get_argv_exec_path();
0311 if (!exec_path)
0312 goto out;
0313 snprintf(path, sizeof(path), "%s/dlfilters/%s", exec_path, file);
0314 free(exec_path);
0315 if (!access(path, R_OK))
0316 file = path;
0317 out:
0318 return strdup(file);
0319 }
0320
0321 #define CHECK_FLAG(x) BUILD_BUG_ON((u64)PERF_DLFILTER_FLAG_ ## x != (u64)PERF_IP_FLAG_ ## x)
0322
0323 static int dlfilter__init(struct dlfilter *d, const char *file, int dlargc, char **dlargv)
0324 {
0325 CHECK_FLAG(BRANCH);
0326 CHECK_FLAG(CALL);
0327 CHECK_FLAG(RETURN);
0328 CHECK_FLAG(CONDITIONAL);
0329 CHECK_FLAG(SYSCALLRET);
0330 CHECK_FLAG(ASYNC);
0331 CHECK_FLAG(INTERRUPT);
0332 CHECK_FLAG(TX_ABORT);
0333 CHECK_FLAG(TRACE_BEGIN);
0334 CHECK_FLAG(TRACE_END);
0335 CHECK_FLAG(IN_TX);
0336 CHECK_FLAG(VMENTRY);
0337 CHECK_FLAG(VMEXIT);
0338
0339 memset(d, 0, sizeof(*d));
0340 d->file = find_dlfilter(file);
0341 if (!d->file)
0342 return -1;
0343 d->dlargc = dlargc;
0344 d->dlargv = dlargv;
0345 return 0;
0346 }
0347
0348 static void dlfilter__exit(struct dlfilter *d)
0349 {
0350 zfree(&d->file);
0351 }
0352
0353 static int dlfilter__open(struct dlfilter *d)
0354 {
0355 d->handle = dlopen(d->file, RTLD_NOW);
0356 if (!d->handle) {
0357 pr_err("dlopen failed for: '%s'\n", d->file);
0358 return -1;
0359 }
0360 d->start = dlsym(d->handle, "start");
0361 d->filter_event = dlsym(d->handle, "filter_event");
0362 d->filter_event_early = dlsym(d->handle, "filter_event_early");
0363 d->stop = dlsym(d->handle, "stop");
0364 d->fns = dlsym(d->handle, "perf_dlfilter_fns");
0365 if (d->fns)
0366 memcpy(d->fns, &perf_dlfilter_fns, sizeof(struct perf_dlfilter_fns));
0367 return 0;
0368 }
0369
0370 static int dlfilter__close(struct dlfilter *d)
0371 {
0372 return dlclose(d->handle);
0373 }
0374
0375 struct dlfilter *dlfilter__new(const char *file, int dlargc, char **dlargv)
0376 {
0377 struct dlfilter *d = malloc(sizeof(*d));
0378
0379 if (!d)
0380 return NULL;
0381
0382 if (dlfilter__init(d, file, dlargc, dlargv))
0383 goto err_free;
0384
0385 if (dlfilter__open(d))
0386 goto err_exit;
0387
0388 return d;
0389
0390 err_exit:
0391 dlfilter__exit(d);
0392 err_free:
0393 free(d);
0394 return NULL;
0395 }
0396
0397 static void dlfilter__free(struct dlfilter *d)
0398 {
0399 if (d) {
0400 dlfilter__exit(d);
0401 free(d);
0402 }
0403 }
0404
0405 int dlfilter__start(struct dlfilter *d, struct perf_session *session)
0406 {
0407 if (d) {
0408 d->session = session;
0409 if (d->start) {
0410 int ret;
0411
0412 d->in_start = true;
0413 ret = d->start(&d->data, d);
0414 d->in_start = false;
0415 return ret;
0416 }
0417 }
0418 return 0;
0419 }
0420
0421 static int dlfilter__stop(struct dlfilter *d)
0422 {
0423 if (d && d->stop) {
0424 int ret;
0425
0426 d->in_stop = true;
0427 ret = d->stop(d->data, d);
0428 d->in_stop = false;
0429 return ret;
0430 }
0431 return 0;
0432 }
0433
0434 void dlfilter__cleanup(struct dlfilter *d)
0435 {
0436 if (d) {
0437 dlfilter__stop(d);
0438 dlfilter__close(d);
0439 dlfilter__free(d);
0440 }
0441 }
0442
0443 #define ASSIGN(x) d_sample.x = sample->x
0444
0445 int dlfilter__do_filter_event(struct dlfilter *d,
0446 union perf_event *event,
0447 struct perf_sample *sample,
0448 struct evsel *evsel,
0449 struct machine *machine,
0450 struct addr_location *al,
0451 struct addr_location *addr_al,
0452 bool early)
0453 {
0454 struct perf_dlfilter_sample d_sample;
0455 struct perf_dlfilter_al d_ip_al;
0456 struct perf_dlfilter_al d_addr_al;
0457 int ret;
0458
0459 d->event = event;
0460 d->sample = sample;
0461 d->evsel = evsel;
0462 d->machine = machine;
0463 d->al = al;
0464 d->addr_al = addr_al;
0465 d->d_sample = &d_sample;
0466 d->d_ip_al = &d_ip_al;
0467 d->d_addr_al = &d_addr_al;
0468
0469 d_sample.size = sizeof(d_sample);
0470 d_ip_al.size = 0;
0471 d_addr_al.size = 0;
0472
0473 ASSIGN(ip);
0474 ASSIGN(pid);
0475 ASSIGN(tid);
0476 ASSIGN(time);
0477 ASSIGN(addr);
0478 ASSIGN(id);
0479 ASSIGN(stream_id);
0480 ASSIGN(period);
0481 ASSIGN(weight);
0482 ASSIGN(ins_lat);
0483 ASSIGN(p_stage_cyc);
0484 ASSIGN(transaction);
0485 ASSIGN(insn_cnt);
0486 ASSIGN(cyc_cnt);
0487 ASSIGN(cpu);
0488 ASSIGN(flags);
0489 ASSIGN(data_src);
0490 ASSIGN(phys_addr);
0491 ASSIGN(data_page_size);
0492 ASSIGN(code_page_size);
0493 ASSIGN(cgroup);
0494 ASSIGN(cpumode);
0495 ASSIGN(misc);
0496 ASSIGN(raw_size);
0497 ASSIGN(raw_data);
0498 ASSIGN(machine_pid);
0499 ASSIGN(vcpu);
0500
0501 if (sample->branch_stack) {
0502 d_sample.brstack_nr = sample->branch_stack->nr;
0503 d_sample.brstack = (struct perf_branch_entry *)perf_sample__branch_entries(sample);
0504 } else {
0505 d_sample.brstack_nr = 0;
0506 d_sample.brstack = NULL;
0507 }
0508
0509 if (sample->callchain) {
0510 d_sample.raw_callchain_nr = sample->callchain->nr;
0511 d_sample.raw_callchain = (__u64 *)sample->callchain->ips;
0512 } else {
0513 d_sample.raw_callchain_nr = 0;
0514 d_sample.raw_callchain = NULL;
0515 }
0516
0517 d_sample.addr_correlates_sym =
0518 (evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) &&
0519 sample_addr_correlates_sym(&evsel->core.attr);
0520
0521 d_sample.event = evsel__name(evsel);
0522
0523 d->ctx_valid = true;
0524
0525 if (early)
0526 ret = d->filter_event_early(d->data, &d_sample, d);
0527 else
0528 ret = d->filter_event(d->data, &d_sample, d);
0529
0530 d->ctx_valid = false;
0531
0532 return ret;
0533 }
0534
0535 bool get_filter_desc(const char *dirname, const char *name, char **desc,
0536 char **long_desc)
0537 {
0538 char path[PATH_MAX];
0539 void *handle;
0540 const char *(*desc_fn)(const char **long_description);
0541
0542 snprintf(path, sizeof(path), "%s/%s", dirname, name);
0543 handle = dlopen(path, RTLD_NOW);
0544 if (!handle || !(dlsym(handle, "filter_event") || dlsym(handle, "filter_event_early")))
0545 return false;
0546 desc_fn = dlsym(handle, "filter_description");
0547 if (desc_fn) {
0548 const char *dsc;
0549 const char *long_dsc;
0550
0551 dsc = desc_fn(&long_dsc);
0552 if (dsc)
0553 *desc = strdup(dsc);
0554 if (long_dsc)
0555 *long_desc = strdup(long_dsc);
0556 }
0557 dlclose(handle);
0558 return true;
0559 }
0560
0561 static void list_filters(const char *dirname)
0562 {
0563 struct dirent *entry;
0564 DIR *dir;
0565
0566 dir = opendir(dirname);
0567 if (!dir)
0568 return;
0569
0570 while ((entry = readdir(dir)) != NULL)
0571 {
0572 size_t n = strlen(entry->d_name);
0573 char *long_desc = NULL;
0574 char *desc = NULL;
0575
0576 if (entry->d_type == DT_DIR || n < 4 ||
0577 strcmp(".so", entry->d_name + n - 3))
0578 continue;
0579 if (!get_filter_desc(dirname, entry->d_name, &desc, &long_desc))
0580 continue;
0581 printf(" %-36s %s\n", entry->d_name, desc ? desc : "");
0582 if (verbose) {
0583 char *p = long_desc;
0584 char *line;
0585
0586 while ((line = strsep(&p, "\n")) != NULL)
0587 printf("%39s%s\n", "", line);
0588 }
0589 free(long_desc);
0590 free(desc);
0591 }
0592
0593 closedir(dir);
0594 }
0595
0596 int list_available_dlfilters(const struct option *opt __maybe_unused,
0597 const char *s __maybe_unused,
0598 int unset __maybe_unused)
0599 {
0600 char path[PATH_MAX];
0601 char *exec_path;
0602
0603 printf("List of available dlfilters:\n");
0604
0605 list_filters(".");
0606
0607 exec_path = get_argv_exec_path();
0608 if (!exec_path)
0609 goto out;
0610 snprintf(path, sizeof(path), "%s/dlfilters", exec_path);
0611
0612 list_filters(path);
0613
0614 free(exec_path);
0615 out:
0616 exit(0);
0617 }