1201 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * probe-file.c : operate ftrace k/uprobe events files4 *5 * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>6 */7#include <errno.h>8#include <fcntl.h>9#include <sys/stat.h>10#include <sys/types.h>11#include <sys/uio.h>12#include <unistd.h>13#include <linux/zalloc.h>14#include "namespaces.h"15#include "event.h"16#include "strlist.h"17#include "strfilter.h"18#include "debug.h"19#include "build-id.h"20#include "dso.h"21#include "color.h"22#include "symbol.h"23#include "strbuf.h"24#include <api/fs/tracing_path.h>25#include <api/fs/fs.h>26#include "probe-event.h"27#include "probe-file.h"28#include "session.h"29#include "perf_regs.h"30#include "string2.h"31 32/* 4096 - 2 ('\n' + '\0') */33#define MAX_CMDLEN 409434 35static bool print_common_warning(int err, bool readwrite)36{37 if (err == -EACCES)38 pr_warning("No permission to %s tracefs.\nPlease %s\n",39 readwrite ? "write" : "read",40 readwrite ? "run this command again with sudo." :41 "try 'sudo mount -o remount,mode=755 /sys/kernel/tracing/'");42 else43 return false;44 45 return true;46}47 48static bool print_configure_probe_event(int kerr, int uerr)49{50 const char *config, *file;51 52 if (kerr == -ENOENT && uerr == -ENOENT) {53 file = "{k,u}probe_events";54 config = "CONFIG_KPROBE_EVENTS=y and CONFIG_UPROBE_EVENTS=y";55 } else if (kerr == -ENOENT) {56 file = "kprobe_events";57 config = "CONFIG_KPROBE_EVENTS=y";58 } else if (uerr == -ENOENT) {59 file = "uprobe_events";60 config = "CONFIG_UPROBE_EVENTS=y";61 } else62 return false;63 64 if (!debugfs__configured() && !tracefs__configured())65 pr_warning("Debugfs or tracefs is not mounted\n"66 "Please try 'sudo mount -t tracefs nodev /sys/kernel/tracing/'\n");67 else68 pr_warning("%s/%s does not exist.\nPlease rebuild kernel with %s.\n",69 tracing_path_mount(), file, config);70 71 return true;72}73 74static void print_open_warning(int err, bool uprobe, bool readwrite)75{76 char sbuf[STRERR_BUFSIZE];77 78 if (print_common_warning(err, readwrite))79 return;80 81 if (print_configure_probe_event(uprobe ? 0 : err, uprobe ? err : 0))82 return;83 84 pr_warning("Failed to open %s/%cprobe_events: %s\n",85 tracing_path_mount(), uprobe ? 'u' : 'k',86 str_error_r(-err, sbuf, sizeof(sbuf)));87}88 89static void print_both_open_warning(int kerr, int uerr, bool readwrite)90{91 char sbuf[STRERR_BUFSIZE];92 93 if (kerr == uerr && print_common_warning(kerr, readwrite))94 return;95 96 if (print_configure_probe_event(kerr, uerr))97 return;98 99 if (kerr < 0)100 pr_warning("Failed to open %s/kprobe_events: %s.\n",101 tracing_path_mount(),102 str_error_r(-kerr, sbuf, sizeof(sbuf)));103 if (uerr < 0)104 pr_warning("Failed to open %s/uprobe_events: %s.\n",105 tracing_path_mount(),106 str_error_r(-uerr, sbuf, sizeof(sbuf)));107}108 109int open_trace_file(const char *trace_file, bool readwrite)110{111 char buf[PATH_MAX];112 int ret;113 114 ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);115 if (ret >= 0) {116 pr_debug("Opening %s write=%d\n", buf, readwrite);117 if (readwrite && !probe_event_dry_run)118 ret = open(buf, O_RDWR | O_APPEND, 0);119 else120 ret = open(buf, O_RDONLY, 0);121 122 if (ret < 0)123 ret = -errno;124 }125 return ret;126}127 128static int open_kprobe_events(bool readwrite)129{130 return open_trace_file("kprobe_events", readwrite);131}132 133static int open_uprobe_events(bool readwrite)134{135 return open_trace_file("uprobe_events", readwrite);136}137 138int probe_file__open(int flag)139{140 int fd;141 142 if (flag & PF_FL_UPROBE)143 fd = open_uprobe_events(flag & PF_FL_RW);144 else145 fd = open_kprobe_events(flag & PF_FL_RW);146 if (fd < 0)147 print_open_warning(fd, flag & PF_FL_UPROBE, flag & PF_FL_RW);148 149 return fd;150}151 152int probe_file__open_both(int *kfd, int *ufd, int flag)153{154 if (!kfd || !ufd)155 return -EINVAL;156 157 *kfd = open_kprobe_events(flag & PF_FL_RW);158 *ufd = open_uprobe_events(flag & PF_FL_RW);159 if (*kfd < 0 && *ufd < 0) {160 print_both_open_warning(*kfd, *ufd, flag & PF_FL_RW);161 return *kfd;162 }163 164 return 0;165}166 167/* Get raw string list of current kprobe_events or uprobe_events */168struct strlist *probe_file__get_rawlist(int fd)169{170 int ret, idx, fddup;171 FILE *fp;172 char buf[MAX_CMDLEN];173 char *p;174 struct strlist *sl;175 176 if (fd < 0)177 return NULL;178 179 sl = strlist__new(NULL, NULL);180 if (sl == NULL)181 return NULL;182 183 fddup = dup(fd);184 if (fddup < 0)185 goto out_free_sl;186 187 fp = fdopen(fddup, "r");188 if (!fp)189 goto out_close_fddup;190 191 while (!feof(fp)) {192 p = fgets(buf, MAX_CMDLEN, fp);193 if (!p)194 break;195 196 idx = strlen(p) - 1;197 if (p[idx] == '\n')198 p[idx] = '\0';199 ret = strlist__add(sl, buf);200 if (ret < 0) {201 pr_debug("strlist__add failed (%d)\n", ret);202 goto out_close_fp;203 }204 }205 fclose(fp);206 207 return sl;208 209out_close_fp:210 fclose(fp);211 goto out_free_sl;212out_close_fddup:213 close(fddup);214out_free_sl:215 strlist__delete(sl);216 return NULL;217}218 219static struct strlist *__probe_file__get_namelist(int fd, bool include_group)220{221 char buf[128];222 struct strlist *sl, *rawlist;223 struct str_node *ent;224 struct probe_trace_event tev;225 int ret = 0;226 227 memset(&tev, 0, sizeof(tev));228 rawlist = probe_file__get_rawlist(fd);229 if (!rawlist)230 return NULL;231 sl = strlist__new(NULL, NULL);232 strlist__for_each_entry(ent, rawlist) {233 ret = parse_probe_trace_command(ent->s, &tev);234 if (ret < 0)235 break;236 if (include_group) {237 ret = e_snprintf(buf, 128, "%s:%s", tev.group,238 tev.event);239 if (ret >= 0)240 ret = strlist__add(sl, buf);241 } else242 ret = strlist__add(sl, tev.event);243 clear_probe_trace_event(&tev);244 /* Skip if there is same name multi-probe event in the list */245 if (ret == -EEXIST)246 ret = 0;247 if (ret < 0)248 break;249 }250 strlist__delete(rawlist);251 252 if (ret < 0) {253 strlist__delete(sl);254 return NULL;255 }256 return sl;257}258 259/* Get current perf-probe event names */260struct strlist *probe_file__get_namelist(int fd)261{262 return __probe_file__get_namelist(fd, false);263}264 265int probe_file__add_event(int fd, struct probe_trace_event *tev)266{267 int ret = 0;268 char *buf = synthesize_probe_trace_command(tev);269 char sbuf[STRERR_BUFSIZE];270 271 if (!buf) {272 pr_debug("Failed to synthesize probe trace event.\n");273 return -EINVAL;274 }275 276 pr_debug("Writing event: %s\n", buf);277 if (!probe_event_dry_run) {278 if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) {279 ret = -errno;280 pr_warning("Failed to write event: %s\n",281 str_error_r(errno, sbuf, sizeof(sbuf)));282 }283 }284 free(buf);285 286 return ret;287}288 289static int __del_trace_probe_event(int fd, struct str_node *ent)290{291 char *p;292 char buf[128];293 int ret;294 295 /* Convert from perf-probe event to trace-probe event */296 ret = e_snprintf(buf, 128, "-:%s", ent->s);297 if (ret < 0)298 goto error;299 300 p = strchr(buf + 2, ':');301 if (!p) {302 pr_debug("Internal error: %s should have ':' but not.\n",303 ent->s);304 ret = -ENOTSUP;305 goto error;306 }307 *p = '/';308 309 pr_debug("Writing event: %s\n", buf);310 ret = write(fd, buf, strlen(buf));311 if (ret < 0) {312 ret = -errno;313 goto error;314 }315 316 return 0;317error:318 pr_warning("Failed to delete event: %s\n",319 str_error_r(-ret, buf, sizeof(buf)));320 return ret;321}322 323int probe_file__get_events(int fd, struct strfilter *filter,324 struct strlist *plist)325{326 struct strlist *namelist;327 struct str_node *ent;328 const char *p;329 int ret = -ENOENT;330 331 if (!plist)332 return -EINVAL;333 334 namelist = __probe_file__get_namelist(fd, true);335 if (!namelist)336 return -ENOENT;337 338 strlist__for_each_entry(ent, namelist) {339 p = strchr(ent->s, ':');340 if ((p && strfilter__compare(filter, p + 1)) ||341 strfilter__compare(filter, ent->s)) {342 ret = strlist__add(plist, ent->s);343 if (ret == -ENOMEM) {344 pr_err("strlist__add failed with -ENOMEM\n");345 goto out;346 }347 ret = 0;348 }349 }350out:351 strlist__delete(namelist);352 353 return ret;354}355 356int probe_file__del_strlist(int fd, struct strlist *namelist)357{358 int ret = 0;359 struct str_node *ent;360 361 strlist__for_each_entry(ent, namelist) {362 ret = __del_trace_probe_event(fd, ent);363 if (ret < 0)364 break;365 }366 return ret;367}368 369int probe_file__del_events(int fd, struct strfilter *filter)370{371 struct strlist *namelist;372 int ret;373 374 namelist = strlist__new(NULL, NULL);375 if (!namelist)376 return -ENOMEM;377 378 ret = probe_file__get_events(fd, filter, namelist);379 if (ret < 0)380 goto out;381 382 ret = probe_file__del_strlist(fd, namelist);383out:384 strlist__delete(namelist);385 return ret;386}387 388/* Caller must ensure to remove this entry from list */389static void probe_cache_entry__delete(struct probe_cache_entry *entry)390{391 if (entry) {392 BUG_ON(!list_empty(&entry->node));393 394 strlist__delete(entry->tevlist);395 clear_perf_probe_event(&entry->pev);396 zfree(&entry->spev);397 free(entry);398 }399}400 401static struct probe_cache_entry *402probe_cache_entry__new(struct perf_probe_event *pev)403{404 struct probe_cache_entry *entry = zalloc(sizeof(*entry));405 406 if (entry) {407 INIT_LIST_HEAD(&entry->node);408 entry->tevlist = strlist__new(NULL, NULL);409 if (!entry->tevlist)410 zfree(&entry);411 else if (pev) {412 entry->spev = synthesize_perf_probe_command(pev);413 if (!entry->spev ||414 perf_probe_event__copy(&entry->pev, pev) < 0) {415 probe_cache_entry__delete(entry);416 return NULL;417 }418 }419 }420 421 return entry;422}423 424int probe_cache_entry__get_event(struct probe_cache_entry *entry,425 struct probe_trace_event **tevs)426{427 struct probe_trace_event *tev;428 struct str_node *node;429 int ret, i;430 431 ret = strlist__nr_entries(entry->tevlist);432 if (ret > probe_conf.max_probes)433 return -E2BIG;434 435 *tevs = zalloc(ret * sizeof(*tev));436 if (!*tevs)437 return -ENOMEM;438 439 i = 0;440 strlist__for_each_entry(node, entry->tevlist) {441 tev = &(*tevs)[i++];442 ret = parse_probe_trace_command(node->s, tev);443 if (ret < 0)444 break;445 }446 return i;447}448 449/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */450static int probe_cache__open(struct probe_cache *pcache, const char *target,451 struct nsinfo *nsi)452{453 char cpath[PATH_MAX];454 char sbuildid[SBUILD_ID_SIZE];455 char *dir_name = NULL;456 bool is_kallsyms = false;457 int ret, fd;458 struct nscookie nsc;459 460 if (target && build_id_cache__cached(target)) {461 /* This is a cached buildid */462 strlcpy(sbuildid, target, SBUILD_ID_SIZE);463 dir_name = build_id_cache__linkname(sbuildid, NULL, 0);464 goto found;465 }466 467 if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {468 target = DSO__NAME_KALLSYMS;469 is_kallsyms = true;470 ret = sysfs__sprintf_build_id("/", sbuildid);471 } else {472 nsinfo__mountns_enter(nsi, &nsc);473 ret = filename__sprintf_build_id(target, sbuildid);474 nsinfo__mountns_exit(&nsc);475 }476 477 if (ret < 0) {478 pr_debug("Failed to get build-id from %s.\n", target);479 return ret;480 }481 482 /* If we have no buildid cache, make it */483 if (!build_id_cache__cached(sbuildid)) {484 ret = build_id_cache__add_s(sbuildid, target, nsi,485 is_kallsyms, NULL);486 if (ret < 0) {487 pr_debug("Failed to add build-id cache: %s\n", target);488 return ret;489 }490 }491 492 dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms,493 false);494found:495 if (!dir_name) {496 pr_debug("Failed to get cache from %s\n", target);497 return -ENOMEM;498 }499 500 snprintf(cpath, PATH_MAX, "%s/probes", dir_name);501 fd = open(cpath, O_CREAT | O_RDWR, 0644);502 if (fd < 0)503 pr_debug("Failed to open cache(%d): %s\n", fd, cpath);504 free(dir_name);505 pcache->fd = fd;506 507 return fd;508}509 510static int probe_cache__load(struct probe_cache *pcache)511{512 struct probe_cache_entry *entry = NULL;513 char buf[MAX_CMDLEN], *p;514 int ret = 0, fddup;515 FILE *fp;516 517 fddup = dup(pcache->fd);518 if (fddup < 0)519 return -errno;520 fp = fdopen(fddup, "r");521 if (!fp) {522 close(fddup);523 return -EINVAL;524 }525 526 while (!feof(fp)) {527 if (!fgets(buf, MAX_CMDLEN, fp))528 break;529 p = strchr(buf, '\n');530 if (p)531 *p = '\0';532 /* #perf_probe_event or %sdt_event */533 if (buf[0] == '#' || buf[0] == '%') {534 entry = probe_cache_entry__new(NULL);535 if (!entry) {536 ret = -ENOMEM;537 goto out;538 }539 if (buf[0] == '%')540 entry->sdt = true;541 entry->spev = strdup(buf + 1);542 if (entry->spev)543 ret = parse_perf_probe_command(buf + 1,544 &entry->pev);545 else546 ret = -ENOMEM;547 if (ret < 0) {548 probe_cache_entry__delete(entry);549 goto out;550 }551 list_add_tail(&entry->node, &pcache->entries);552 } else { /* trace_probe_event */553 if (!entry) {554 ret = -EINVAL;555 goto out;556 }557 ret = strlist__add(entry->tevlist, buf);558 if (ret == -ENOMEM) {559 pr_err("strlist__add failed with -ENOMEM\n");560 goto out;561 }562 }563 }564out:565 fclose(fp);566 return ret;567}568 569static struct probe_cache *probe_cache__alloc(void)570{571 struct probe_cache *pcache = zalloc(sizeof(*pcache));572 573 if (pcache) {574 INIT_LIST_HEAD(&pcache->entries);575 pcache->fd = -EINVAL;576 }577 return pcache;578}579 580void probe_cache__purge(struct probe_cache *pcache)581{582 struct probe_cache_entry *entry, *n;583 584 list_for_each_entry_safe(entry, n, &pcache->entries, node) {585 list_del_init(&entry->node);586 probe_cache_entry__delete(entry);587 }588}589 590void probe_cache__delete(struct probe_cache *pcache)591{592 if (!pcache)593 return;594 595 probe_cache__purge(pcache);596 if (pcache->fd > 0)597 close(pcache->fd);598 free(pcache);599}600 601struct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi)602{603 struct probe_cache *pcache = probe_cache__alloc();604 int ret;605 606 if (!pcache)607 return NULL;608 609 ret = probe_cache__open(pcache, target, nsi);610 if (ret < 0) {611 pr_debug("Cache open error: %d\n", ret);612 goto out_err;613 }614 615 ret = probe_cache__load(pcache);616 if (ret < 0) {617 pr_debug("Cache read error: %d\n", ret);618 goto out_err;619 }620 621 return pcache;622 623out_err:624 probe_cache__delete(pcache);625 return NULL;626}627 628static bool streql(const char *a, const char *b)629{630 if (a == b)631 return true;632 633 if (!a || !b)634 return false;635 636 return !strcmp(a, b);637}638 639struct probe_cache_entry *640probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)641{642 struct probe_cache_entry *entry = NULL;643 char *cmd = synthesize_perf_probe_command(pev);644 645 if (!cmd)646 return NULL;647 648 for_each_probe_cache_entry(entry, pcache) {649 if (pev->sdt) {650 if (entry->pev.event &&651 streql(entry->pev.event, pev->event) &&652 (!pev->group ||653 streql(entry->pev.group, pev->group)))654 goto found;655 656 continue;657 }658 /* Hit if same event name or same command-string */659 if ((pev->event &&660 (streql(entry->pev.group, pev->group) &&661 streql(entry->pev.event, pev->event))) ||662 (!strcmp(entry->spev, cmd)))663 goto found;664 }665 entry = NULL;666 667found:668 free(cmd);669 return entry;670}671 672struct probe_cache_entry *673probe_cache__find_by_name(struct probe_cache *pcache,674 const char *group, const char *event)675{676 struct probe_cache_entry *entry = NULL;677 678 for_each_probe_cache_entry(entry, pcache) {679 /* Hit if same event name or same command-string */680 if (streql(entry->pev.group, group) &&681 streql(entry->pev.event, event))682 goto found;683 }684 entry = NULL;685 686found:687 return entry;688}689 690int probe_cache__add_entry(struct probe_cache *pcache,691 struct perf_probe_event *pev,692 struct probe_trace_event *tevs, int ntevs)693{694 struct probe_cache_entry *entry = NULL;695 char *command;696 int i, ret = 0;697 698 if (!pcache || !pev || !tevs || ntevs <= 0) {699 ret = -EINVAL;700 goto out_err;701 }702 703 /* Remove old cache entry */704 entry = probe_cache__find(pcache, pev);705 if (entry) {706 list_del_init(&entry->node);707 probe_cache_entry__delete(entry);708 }709 710 ret = -ENOMEM;711 entry = probe_cache_entry__new(pev);712 if (!entry)713 goto out_err;714 715 for (i = 0; i < ntevs; i++) {716 if (!tevs[i].point.symbol)717 continue;718 719 command = synthesize_probe_trace_command(&tevs[i]);720 if (!command)721 goto out_err;722 ret = strlist__add(entry->tevlist, command);723 if (ret == -ENOMEM) {724 pr_err("strlist__add failed with -ENOMEM\n");725 goto out_err;726 }727 728 free(command);729 }730 list_add_tail(&entry->node, &pcache->entries);731 pr_debug("Added probe cache: %d\n", ntevs);732 return 0;733 734out_err:735 pr_debug("Failed to add probe caches\n");736 probe_cache_entry__delete(entry);737 return ret;738}739 740#ifdef HAVE_GELF_GETNOTE_SUPPORT741static unsigned long long sdt_note__get_addr(struct sdt_note *note)742{743 return note->bit32 ?744 (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] :745 (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC];746}747 748static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note)749{750 return note->bit32 ?751 (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] :752 (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR];753}754 755static const char * const type_to_suffix[] = {756 ":s64", "", "", "", ":s32", "", ":s16", ":s8",757 "", ":u8", ":u16", "", ":u32", "", "", "", ":u64"758};759 760/*761 * Isolate the string number and convert it into a decimal value;762 * this will be an index to get suffix of the uprobe name (defining763 * the type)764 */765static int sdt_arg_parse_size(char *n_ptr, const char **suffix)766{767 long type_idx;768 769 type_idx = strtol(n_ptr, NULL, 10);770 if (type_idx < -8 || type_idx > 8) {771 pr_debug4("Failed to get a valid sdt type\n");772 return -1;773 }774 775 *suffix = type_to_suffix[type_idx + 8];776 return 0;777}778 779static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)780{781 char *op, *desc = strdup(arg), *new_op = NULL;782 const char *suffix = "";783 int ret = -1;784 785 if (desc == NULL) {786 pr_debug4("Allocation error\n");787 return ret;788 }789 790 /*791 * Argument is in N@OP format. N is size of the argument and OP is792 * the actual assembly operand. N can be omitted; in that case793 * argument is just OP(without @).794 */795 op = strchr(desc, '@');796 if (op) {797 op[0] = '\0';798 op++;799 800 if (sdt_arg_parse_size(desc, &suffix))801 goto error;802 } else {803 op = desc;804 }805 806 ret = arch_sdt_arg_parse_op(op, &new_op);807 808 if (ret < 0)809 goto error;810 811 if (ret == SDT_ARG_VALID) {812 ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);813 if (ret < 0)814 goto error;815 }816 817 ret = 0;818error:819 free(desc);820 free(new_op);821 return ret;822}823 824static char *synthesize_sdt_probe_command(struct sdt_note *note,825 const char *pathname,826 const char *sdtgrp)827{828 struct strbuf buf;829 char *ret = NULL;830 int i, args_count, err;831 unsigned long long ref_ctr_offset;832 char *arg;833 int arg_idx = 0;834 835 if (strbuf_init(&buf, 32) < 0)836 return NULL;837 838 err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx",839 sdtgrp, note->name, pathname,840 sdt_note__get_addr(note));841 842 ref_ctr_offset = sdt_note__get_ref_ctr_offset(note);843 if (ref_ctr_offset && err >= 0)844 err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset);845 846 if (err < 0)847 goto error;848 849 if (!note->args)850 goto out;851 852 if (note->args) {853 char **args = argv_split(note->args, &args_count);854 855 if (args == NULL)856 goto error;857 858 for (i = 0; i < args_count; ) {859 /*860 * FIXUP: Arm64 ELF section '.note.stapsdt' uses string861 * format "-4@[sp, NUM]" if a probe is to access data in862 * the stack, e.g. below is an example for the SDT863 * Arguments:864 *865 * Arguments: -4@[sp, 12] -4@[sp, 8] -4@[sp, 4]866 *867 * Since the string introduces an extra space character868 * in the middle of square brackets, the argument is869 * divided into two items. Fixup for this case, if an870 * item contains sub string "[sp,", need to concatenate871 * the two items.872 */873 if (strstr(args[i], "[sp,") && (i+1) < args_count) {874 err = asprintf(&arg, "%s %s", args[i], args[i+1]);875 i += 2;876 } else {877 err = asprintf(&arg, "%s", args[i]);878 i += 1;879 }880 881 /* Failed to allocate memory */882 if (err < 0) {883 argv_free(args);884 goto error;885 }886 887 if (synthesize_sdt_probe_arg(&buf, arg_idx, arg) < 0) {888 free(arg);889 argv_free(args);890 goto error;891 }892 893 free(arg);894 arg_idx++;895 }896 897 argv_free(args);898 }899 900out:901 ret = strbuf_detach(&buf, NULL);902error:903 strbuf_release(&buf);904 return ret;905}906 907int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)908{909 struct probe_cache_entry *entry = NULL;910 struct list_head sdtlist;911 struct sdt_note *note;912 char *buf;913 char sdtgrp[64];914 int ret;915 916 INIT_LIST_HEAD(&sdtlist);917 ret = get_sdt_note_list(&sdtlist, pathname);918 if (ret < 0) {919 pr_debug4("Failed to get sdt note: %d\n", ret);920 return ret;921 }922 list_for_each_entry(note, &sdtlist, note_list) {923 ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);924 if (ret < 0)925 break;926 /* Try to find same-name entry */927 entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);928 if (!entry) {929 entry = probe_cache_entry__new(NULL);930 if (!entry) {931 ret = -ENOMEM;932 break;933 }934 entry->sdt = true;935 ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,936 note->name, note->name);937 if (ret < 0)938 break;939 entry->pev.event = strdup(note->name);940 entry->pev.group = strdup(sdtgrp);941 list_add_tail(&entry->node, &pcache->entries);942 }943 buf = synthesize_sdt_probe_command(note, pathname, sdtgrp);944 if (!buf) {945 ret = -ENOMEM;946 break;947 }948 949 ret = strlist__add(entry->tevlist, buf);950 951 free(buf);952 entry = NULL;953 954 if (ret == -ENOMEM) {955 pr_err("strlist__add failed with -ENOMEM\n");956 break;957 }958 }959 if (entry) {960 list_del_init(&entry->node);961 probe_cache_entry__delete(entry);962 }963 cleanup_sdt_note_list(&sdtlist);964 return ret;965}966#endif967 968static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)969{970 struct str_node *snode;971 struct stat st;972 struct iovec iov[3];973 const char *prefix = entry->sdt ? "%" : "#";974 int ret;975 /* Save stat for rollback */976 ret = fstat(fd, &st);977 if (ret < 0)978 return ret;979 980 pr_debug("Writing cache: %s%s\n", prefix, entry->spev);981 iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;982 iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);983 iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;984 ret = writev(fd, iov, 3);985 if (ret < (int)iov[1].iov_len + 2)986 goto rollback;987 988 strlist__for_each_entry(snode, entry->tevlist) {989 iov[0].iov_base = (void *)snode->s;990 iov[0].iov_len = strlen(snode->s);991 iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;992 ret = writev(fd, iov, 2);993 if (ret < (int)iov[0].iov_len + 1)994 goto rollback;995 }996 return 0;997 998rollback:999 /* Rollback to avoid cache file corruption */1000 if (ret > 0)1001 ret = -1;1002 if (ftruncate(fd, st.st_size) < 0)1003 ret = -2;1004 1005 return ret;1006}1007 1008int probe_cache__commit(struct probe_cache *pcache)1009{1010 struct probe_cache_entry *entry;1011 int ret = 0;1012 1013 /* TBD: if we do not update existing entries, skip it */1014 ret = lseek(pcache->fd, 0, SEEK_SET);1015 if (ret < 0)1016 goto out;1017 1018 ret = ftruncate(pcache->fd, 0);1019 if (ret < 0)1020 goto out;1021 1022 for_each_probe_cache_entry(entry, pcache) {1023 ret = probe_cache_entry__write(entry, pcache->fd);1024 pr_debug("Cache committed: %d\n", ret);1025 if (ret < 0)1026 break;1027 }1028out:1029 return ret;1030}1031 1032static bool probe_cache_entry__compare(struct probe_cache_entry *entry,1033 struct strfilter *filter)1034{1035 char buf[128], *ptr = entry->spev;1036 1037 if (entry->pev.event) {1038 snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);1039 ptr = buf;1040 }1041 return strfilter__compare(filter, ptr);1042}1043 1044int probe_cache__filter_purge(struct probe_cache *pcache,1045 struct strfilter *filter)1046{1047 struct probe_cache_entry *entry, *tmp;1048 1049 list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {1050 if (probe_cache_entry__compare(entry, filter)) {1051 pr_info("Removed cached event: %s\n", entry->spev);1052 list_del_init(&entry->node);1053 probe_cache_entry__delete(entry);1054 }1055 }1056 return 0;1057}1058 1059static int probe_cache__show_entries(struct probe_cache *pcache,1060 struct strfilter *filter)1061{1062 struct probe_cache_entry *entry;1063 1064 for_each_probe_cache_entry(entry, pcache) {1065 if (probe_cache_entry__compare(entry, filter))1066 printf("%s\n", entry->spev);1067 }1068 return 0;1069}1070 1071/* Show all cached probes */1072int probe_cache__show_all_caches(struct strfilter *filter)1073{1074 struct probe_cache *pcache;1075 struct strlist *bidlist;1076 struct str_node *nd;1077 char *buf = strfilter__string(filter);1078 1079 pr_debug("list cache with filter: %s\n", buf);1080 free(buf);1081 1082 bidlist = build_id_cache__list_all(true);1083 if (!bidlist) {1084 pr_debug("Failed to get buildids: %d\n", errno);1085 return -EINVAL;1086 }1087 strlist__for_each_entry(nd, bidlist) {1088 pcache = probe_cache__new(nd->s, NULL);1089 if (!pcache)1090 continue;1091 if (!list_empty(&pcache->entries)) {1092 buf = build_id_cache__origname(nd->s);1093 printf("%s (%s):\n", buf, nd->s);1094 free(buf);1095 probe_cache__show_entries(pcache, filter);1096 }1097 probe_cache__delete(pcache);1098 }1099 strlist__delete(bidlist);1100 1101 return 0;1102}1103 1104enum ftrace_readme {1105 FTRACE_README_PROBE_TYPE_X = 0,1106 FTRACE_README_KRETPROBE_OFFSET,1107 FTRACE_README_UPROBE_REF_CTR,1108 FTRACE_README_USER_ACCESS,1109 FTRACE_README_MULTIPROBE_EVENT,1110 FTRACE_README_IMMEDIATE_VALUE,1111 FTRACE_README_END,1112};1113 1114static struct {1115 const char *pattern;1116 bool avail;1117} ftrace_readme_table[] = {1118#define DEFINE_TYPE(idx, pat) \1119 [idx] = {.pattern = pat, .avail = false}1120 DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),1121 DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),1122 DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),1123 DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*u]<offset>*"),1124 DEFINE_TYPE(FTRACE_README_MULTIPROBE_EVENT, "*Create/append/*"),1125 DEFINE_TYPE(FTRACE_README_IMMEDIATE_VALUE, "*\\imm-value,*"),1126};1127 1128static bool scan_ftrace_readme(enum ftrace_readme type)1129{1130 int fd;1131 FILE *fp;1132 char *buf = NULL;1133 size_t len = 0;1134 bool ret = false;1135 static bool scanned = false;1136 1137 if (scanned)1138 goto result;1139 1140 fd = open_trace_file("README", false);1141 if (fd < 0)1142 return ret;1143 1144 fp = fdopen(fd, "r");1145 if (!fp) {1146 close(fd);1147 return ret;1148 }1149 1150 while (getline(&buf, &len, fp) > 0)1151 for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)1152 if (!ftrace_readme_table[i].avail)1153 ftrace_readme_table[i].avail =1154 strglobmatch(buf, ftrace_readme_table[i].pattern);1155 scanned = true;1156 1157 fclose(fp);1158 free(buf);1159 1160result:1161 if (type >= FTRACE_README_END)1162 return false;1163 1164 return ftrace_readme_table[type].avail;1165}1166 1167bool probe_type_is_available(enum probe_type type)1168{1169 if (type >= PROBE_TYPE_END)1170 return false;1171 else if (type == PROBE_TYPE_X)1172 return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);1173 1174 return true;1175}1176 1177bool kretprobe_offset_is_supported(void)1178{1179 return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);1180}1181 1182bool uprobe_ref_ctr_is_supported(void)1183{1184 return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);1185}1186 1187bool user_access_is_supported(void)1188{1189 return scan_ftrace_readme(FTRACE_README_USER_ACCESS);1190}1191 1192bool multiprobe_event_is_supported(void)1193{1194 return scan_ftrace_readme(FTRACE_README_MULTIPROBE_EVENT);1195}1196 1197bool immediate_value_is_supported(void)1198{1199 return scan_ftrace_readme(FTRACE_README_IMMEDIATE_VALUE);1200}1201