| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * probe-event.c : perf-probe definition to probe_events format converter |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Written by Masami Hiramatsu <mhiramat@redhat.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; if not, write to the Free Software |
|---|
| 18 | | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 19 | | - * |
|---|
| 20 | 6 | */ |
|---|
| 21 | 7 | |
|---|
| 22 | 8 | #include <inttypes.h> |
|---|
| .. | .. |
|---|
| 33 | 19 | #include <limits.h> |
|---|
| 34 | 20 | #include <elf.h> |
|---|
| 35 | 21 | |
|---|
| 36 | | -#include "util.h" |
|---|
| 22 | +#include "build-id.h" |
|---|
| 37 | 23 | #include "event.h" |
|---|
| 24 | +#include "namespaces.h" |
|---|
| 38 | 25 | #include "strlist.h" |
|---|
| 39 | 26 | #include "strfilter.h" |
|---|
| 40 | 27 | #include "debug.h" |
|---|
| 41 | | -#include "cache.h" |
|---|
| 28 | +#include "dso.h" |
|---|
| 42 | 29 | #include "color.h" |
|---|
| 30 | +#include "map.h" |
|---|
| 31 | +#include "maps.h" |
|---|
| 43 | 32 | #include "symbol.h" |
|---|
| 44 | | -#include "thread.h" |
|---|
| 45 | 33 | #include <api/fs/fs.h> |
|---|
| 46 | 34 | #include "trace-event.h" /* For __maybe_unused */ |
|---|
| 47 | 35 | #include "probe-event.h" |
|---|
| .. | .. |
|---|
| 49 | 37 | #include "probe-file.h" |
|---|
| 50 | 38 | #include "session.h" |
|---|
| 51 | 39 | #include "string2.h" |
|---|
| 40 | +#include "strbuf.h" |
|---|
| 52 | 41 | |
|---|
| 53 | | -#include "sane_ctype.h" |
|---|
| 42 | +#include <subcmd/pager.h> |
|---|
| 43 | +#include <linux/ctype.h> |
|---|
| 44 | +#include <linux/zalloc.h> |
|---|
| 45 | + |
|---|
| 46 | +#ifdef HAVE_DEBUGINFOD_SUPPORT |
|---|
| 47 | +#include <elfutils/debuginfod.h> |
|---|
| 48 | +#endif |
|---|
| 54 | 49 | |
|---|
| 55 | 50 | #define PERFPROBE_GROUP "probe" |
|---|
| 56 | 51 | |
|---|
| 57 | 52 | bool probe_event_dry_run; /* Dry run flag */ |
|---|
| 58 | | -struct probe_conf probe_conf; |
|---|
| 53 | +struct probe_conf probe_conf = { .magic_num = DEFAULT_PROBE_MAGIC_NUM }; |
|---|
| 59 | 54 | |
|---|
| 60 | 55 | #define semantic_error(msg ...) pr_err("Semantic error :" msg) |
|---|
| 61 | 56 | |
|---|
| .. | .. |
|---|
| 138 | 133 | struct map *map; |
|---|
| 139 | 134 | |
|---|
| 140 | 135 | /* ref_reloc_sym is just a label. Need a special fix*/ |
|---|
| 141 | | - reloc_sym = kernel_get_ref_reloc_sym(NULL); |
|---|
| 136 | + reloc_sym = kernel_get_ref_reloc_sym(&map); |
|---|
| 142 | 137 | if (reloc_sym && strcmp(name, reloc_sym->name) == 0) |
|---|
| 143 | | - *addr = (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; |
|---|
| 138 | + *addr = (!map->reloc || reloc) ? reloc_sym->addr : |
|---|
| 139 | + reloc_sym->unrelocated_addr; |
|---|
| 144 | 140 | else { |
|---|
| 145 | 141 | sym = machine__find_kernel_symbol_by_name(host_machine, name, &map); |
|---|
| 146 | 142 | if (!sym) |
|---|
| .. | .. |
|---|
| 166 | 162 | return map__get(pos); |
|---|
| 167 | 163 | } |
|---|
| 168 | 164 | |
|---|
| 169 | | - for (pos = maps__first(maps); pos; pos = map__next(pos)) { |
|---|
| 165 | + maps__for_each_entry(maps, pos) { |
|---|
| 170 | 166 | /* short_name is "[module]" */ |
|---|
| 171 | 167 | if (strncmp(pos->dso->short_name + 1, module, |
|---|
| 172 | 168 | pos->dso->short_name_len - 2) == 0 && |
|---|
| .. | .. |
|---|
| 231 | 227 | |
|---|
| 232 | 228 | static void clear_perf_probe_point(struct perf_probe_point *pp) |
|---|
| 233 | 229 | { |
|---|
| 234 | | - free(pp->file); |
|---|
| 235 | | - free(pp->function); |
|---|
| 236 | | - free(pp->lazy_line); |
|---|
| 230 | + zfree(&pp->file); |
|---|
| 231 | + zfree(&pp->function); |
|---|
| 232 | + zfree(&pp->lazy_line); |
|---|
| 237 | 233 | } |
|---|
| 238 | 234 | |
|---|
| 239 | 235 | static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) |
|---|
| .. | .. |
|---|
| 337 | 333 | char module_name[128]; |
|---|
| 338 | 334 | |
|---|
| 339 | 335 | snprintf(module_name, sizeof(module_name), "[%s]", module); |
|---|
| 340 | | - map = map_groups__find_by_name(&host_machine->kmaps, module_name); |
|---|
| 336 | + map = maps__find_by_name(&host_machine->kmaps, module_name); |
|---|
| 341 | 337 | if (map) { |
|---|
| 342 | 338 | dso = map->dso; |
|---|
| 343 | 339 | goto found; |
|---|
| .. | .. |
|---|
| 348 | 344 | |
|---|
| 349 | 345 | map = machine__kernel_map(host_machine); |
|---|
| 350 | 346 | dso = map->dso; |
|---|
| 347 | + if (!dso->has_build_id) |
|---|
| 348 | + dso__read_running_kernel_build_id(dso, host_machine); |
|---|
| 351 | 349 | |
|---|
| 352 | 350 | vmlinux_name = symbol_conf.vmlinux_name; |
|---|
| 353 | 351 | dso->load_errno = 0; |
|---|
| .. | .. |
|---|
| 386 | 384 | |
|---|
| 387 | 385 | /* Find the address of given function */ |
|---|
| 388 | 386 | map__for_each_symbol_by_name(map, pp->function, sym) { |
|---|
| 389 | | - if (uprobes) |
|---|
| 387 | + if (uprobes) { |
|---|
| 390 | 388 | address = sym->start; |
|---|
| 391 | | - else |
|---|
| 389 | + if (sym->type == STT_GNU_IFUNC) |
|---|
| 390 | + pr_warning("Warning: The probe function (%s) is a GNU indirect function.\n" |
|---|
| 391 | + "Consider identifying the final function used at run time and set the probe directly on that.\n", |
|---|
| 392 | + pp->function); |
|---|
| 393 | + } else |
|---|
| 392 | 394 | address = map->unmap_ip(map, sym->start) - map->reloc; |
|---|
| 393 | 395 | break; |
|---|
| 394 | 396 | } |
|---|
| .. | .. |
|---|
| 459 | 461 | return ret; |
|---|
| 460 | 462 | } |
|---|
| 461 | 463 | |
|---|
| 464 | +#ifdef HAVE_DEBUGINFOD_SUPPORT |
|---|
| 465 | +static struct debuginfo *open_from_debuginfod(struct dso *dso, struct nsinfo *nsi, |
|---|
| 466 | + bool silent) |
|---|
| 467 | +{ |
|---|
| 468 | + debuginfod_client *c = debuginfod_begin(); |
|---|
| 469 | + char sbuild_id[SBUILD_ID_SIZE + 1]; |
|---|
| 470 | + struct debuginfo *ret = NULL; |
|---|
| 471 | + struct nscookie nsc; |
|---|
| 472 | + char *path; |
|---|
| 473 | + int fd; |
|---|
| 474 | + |
|---|
| 475 | + if (!c) |
|---|
| 476 | + return NULL; |
|---|
| 477 | + |
|---|
| 478 | + build_id__sprintf(&dso->bid, sbuild_id); |
|---|
| 479 | + fd = debuginfod_find_debuginfo(c, (const unsigned char *)sbuild_id, |
|---|
| 480 | + 0, &path); |
|---|
| 481 | + if (fd >= 0) |
|---|
| 482 | + close(fd); |
|---|
| 483 | + debuginfod_end(c); |
|---|
| 484 | + if (fd < 0) { |
|---|
| 485 | + if (!silent) |
|---|
| 486 | + pr_debug("Failed to find debuginfo in debuginfod.\n"); |
|---|
| 487 | + return NULL; |
|---|
| 488 | + } |
|---|
| 489 | + if (!silent) |
|---|
| 490 | + pr_debug("Load debuginfo from debuginfod (%s)\n", path); |
|---|
| 491 | + |
|---|
| 492 | + nsinfo__mountns_enter(nsi, &nsc); |
|---|
| 493 | + ret = debuginfo__new((const char *)path); |
|---|
| 494 | + nsinfo__mountns_exit(&nsc); |
|---|
| 495 | + return ret; |
|---|
| 496 | +} |
|---|
| 497 | +#else |
|---|
| 498 | +static inline |
|---|
| 499 | +struct debuginfo *open_from_debuginfod(struct dso *dso __maybe_unused, |
|---|
| 500 | + struct nsinfo *nsi __maybe_unused, |
|---|
| 501 | + bool silent __maybe_unused) |
|---|
| 502 | +{ |
|---|
| 503 | + return NULL; |
|---|
| 504 | +} |
|---|
| 505 | +#endif |
|---|
| 506 | + |
|---|
| 462 | 507 | /* Open new debuginfo of given module */ |
|---|
| 463 | 508 | static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi, |
|---|
| 464 | 509 | bool silent) |
|---|
| .. | .. |
|---|
| 478 | 523 | strcpy(reason, "(unknown)"); |
|---|
| 479 | 524 | } else |
|---|
| 480 | 525 | dso__strerror_load(dso, reason, STRERR_BUFSIZE); |
|---|
| 481 | | - if (!silent) |
|---|
| 482 | | - pr_err("Failed to find the path for %s: %s\n", |
|---|
| 483 | | - module ?: "kernel", reason); |
|---|
| 526 | + if (dso) |
|---|
| 527 | + ret = open_from_debuginfod(dso, nsi, silent); |
|---|
| 528 | + if (ret) |
|---|
| 529 | + return ret; |
|---|
| 530 | + if (!silent) { |
|---|
| 531 | + if (module) |
|---|
| 532 | + pr_err("Module %s is not loaded, please specify its full path name.\n", module); |
|---|
| 533 | + else |
|---|
| 534 | + pr_err("Failed to find the path for the kernel: %s\n", reason); |
|---|
| 535 | + } |
|---|
| 484 | 536 | return NULL; |
|---|
| 485 | 537 | } |
|---|
| 486 | 538 | path = dso->long_name; |
|---|
| .. | .. |
|---|
| 701 | 753 | return ret; |
|---|
| 702 | 754 | |
|---|
| 703 | 755 | for (i = 0; i < ntevs && ret >= 0; i++) { |
|---|
| 704 | | - /* point.address is the addres of point.symbol + point.offset */ |
|---|
| 756 | + /* point.address is the address of point.symbol + point.offset */ |
|---|
| 705 | 757 | tevs[i].point.address -= stext; |
|---|
| 706 | 758 | tevs[i].point.module = strdup(exec); |
|---|
| 707 | 759 | if (!tevs[i].point.module) { |
|---|
| .. | .. |
|---|
| 799 | 851 | free(tevs[i].point.symbol); |
|---|
| 800 | 852 | tevs[i].point.symbol = tmp; |
|---|
| 801 | 853 | tevs[i].point.offset = tevs[i].point.address - |
|---|
| 802 | | - reloc_sym->unrelocated_addr; |
|---|
| 854 | + (map->reloc ? reloc_sym->unrelocated_addr : |
|---|
| 855 | + reloc_sym->addr); |
|---|
| 803 | 856 | } |
|---|
| 804 | 857 | return skipped; |
|---|
| 805 | 858 | } |
|---|
| .. | .. |
|---|
| 954 | 1007 | static int __show_line_range(struct line_range *lr, const char *module, |
|---|
| 955 | 1008 | bool user) |
|---|
| 956 | 1009 | { |
|---|
| 1010 | + struct build_id bid; |
|---|
| 957 | 1011 | int l = 1; |
|---|
| 958 | 1012 | struct int_node *ln; |
|---|
| 959 | 1013 | struct debuginfo *dinfo; |
|---|
| .. | .. |
|---|
| 961 | 1015 | int ret; |
|---|
| 962 | 1016 | char *tmp; |
|---|
| 963 | 1017 | char sbuf[STRERR_BUFSIZE]; |
|---|
| 1018 | + char sbuild_id[SBUILD_ID_SIZE] = ""; |
|---|
| 964 | 1019 | |
|---|
| 965 | 1020 | /* Search a line range */ |
|---|
| 966 | 1021 | dinfo = open_debuginfo(module, NULL, false); |
|---|
| .. | .. |
|---|
| 973 | 1028 | if (!ret) |
|---|
| 974 | 1029 | ret = debuginfo__find_line_range(dinfo, lr); |
|---|
| 975 | 1030 | } |
|---|
| 1031 | + if (dinfo->build_id) { |
|---|
| 1032 | + build_id__init(&bid, dinfo->build_id, BUILD_ID_SIZE); |
|---|
| 1033 | + build_id__sprintf(&bid, sbuild_id); |
|---|
| 1034 | + } |
|---|
| 976 | 1035 | debuginfo__delete(dinfo); |
|---|
| 977 | 1036 | if (ret == 0 || ret == -ENOENT) { |
|---|
| 978 | 1037 | pr_warning("Specified source line is not found.\n"); |
|---|
| .. | .. |
|---|
| 984 | 1043 | |
|---|
| 985 | 1044 | /* Convert source file path */ |
|---|
| 986 | 1045 | tmp = lr->path; |
|---|
| 987 | | - ret = get_real_path(tmp, lr->comp_dir, &lr->path); |
|---|
| 1046 | + ret = find_source_path(tmp, sbuild_id, lr->comp_dir, &lr->path); |
|---|
| 988 | 1047 | |
|---|
| 989 | 1048 | /* Free old path when new path is assigned */ |
|---|
| 990 | 1049 | if (tmp != lr->path) |
|---|
| .. | .. |
|---|
| 1195 | 1254 | |
|---|
| 1196 | 1255 | void line_range__clear(struct line_range *lr) |
|---|
| 1197 | 1256 | { |
|---|
| 1198 | | - free(lr->function); |
|---|
| 1199 | | - free(lr->file); |
|---|
| 1200 | | - free(lr->path); |
|---|
| 1201 | | - free(lr->comp_dir); |
|---|
| 1257 | + zfree(&lr->function); |
|---|
| 1258 | + zfree(&lr->file); |
|---|
| 1259 | + zfree(&lr->path); |
|---|
| 1260 | + zfree(&lr->comp_dir); |
|---|
| 1202 | 1261 | intlist__delete(lr->line_list); |
|---|
| 1203 | | - memset(lr, 0, sizeof(*lr)); |
|---|
| 1204 | 1262 | } |
|---|
| 1205 | 1263 | |
|---|
| 1206 | 1264 | int line_range__init(struct line_range *lr) |
|---|
| .. | .. |
|---|
| 1583 | 1641 | str = tmp + 1; |
|---|
| 1584 | 1642 | } |
|---|
| 1585 | 1643 | |
|---|
| 1644 | + tmp = strchr(str, '@'); |
|---|
| 1645 | + if (tmp && tmp != str && !strcmp(tmp + 1, "user")) { /* user attr */ |
|---|
| 1646 | + if (!user_access_is_supported()) { |
|---|
| 1647 | + semantic_error("ftrace does not support user access\n"); |
|---|
| 1648 | + return -EINVAL; |
|---|
| 1649 | + } |
|---|
| 1650 | + *tmp = '\0'; |
|---|
| 1651 | + arg->user_access = true; |
|---|
| 1652 | + pr_debug("user_access "); |
|---|
| 1653 | + } |
|---|
| 1654 | + |
|---|
| 1586 | 1655 | tmp = strchr(str, ':'); |
|---|
| 1587 | 1656 | if (tmp) { /* Type setting */ |
|---|
| 1588 | 1657 | *tmp = '\0'; |
|---|
| .. | .. |
|---|
| 1686 | 1755 | ret = parse_perf_probe_point(argv[0], pev); |
|---|
| 1687 | 1756 | if (ret < 0) |
|---|
| 1688 | 1757 | goto out; |
|---|
| 1758 | + |
|---|
| 1759 | + /* Generate event name if needed */ |
|---|
| 1760 | + if (!pev->event && pev->point.function && pev->point.line |
|---|
| 1761 | + && !pev->point.lazy_line && !pev->point.offset) { |
|---|
| 1762 | + if (asprintf(&pev->event, "%s_L%d", pev->point.function, |
|---|
| 1763 | + pev->point.line) < 0) { |
|---|
| 1764 | + ret = -ENOMEM; |
|---|
| 1765 | + goto out; |
|---|
| 1766 | + } |
|---|
| 1767 | + } |
|---|
| 1689 | 1768 | |
|---|
| 1690 | 1769 | /* Copy arguments and ensure return probe has no C argument */ |
|---|
| 1691 | 1770 | pev->nargs = argc - 1; |
|---|
| .. | .. |
|---|
| 1830 | 1909 | tp->offset = 0; |
|---|
| 1831 | 1910 | else |
|---|
| 1832 | 1911 | tp->offset = strtoul(fmt2_str, NULL, 10); |
|---|
| 1912 | + } |
|---|
| 1913 | + |
|---|
| 1914 | + if (tev->uprobes) { |
|---|
| 1915 | + fmt2_str = strchr(p, '('); |
|---|
| 1916 | + if (fmt2_str) |
|---|
| 1917 | + tp->ref_ctr_offset = strtoul(fmt2_str + 1, NULL, 0); |
|---|
| 1833 | 1918 | } |
|---|
| 1834 | 1919 | |
|---|
| 1835 | 1920 | tev->nargs = argc - 2; |
|---|
| .. | .. |
|---|
| 1979 | 2064 | if (depth < 0) |
|---|
| 1980 | 2065 | return depth; |
|---|
| 1981 | 2066 | } |
|---|
| 1982 | | - err = strbuf_addf(buf, "%+ld(", ref->offset); |
|---|
| 2067 | + if (ref->user_access) |
|---|
| 2068 | + err = strbuf_addf(buf, "%s%ld(", "+u", ref->offset); |
|---|
| 2069 | + else |
|---|
| 2070 | + err = strbuf_addf(buf, "%+ld(", ref->offset); |
|---|
| 1983 | 2071 | return (err < 0) ? err : depth; |
|---|
| 1984 | 2072 | } |
|---|
| 1985 | 2073 | |
|---|
| .. | .. |
|---|
| 2025 | 2113 | return err; |
|---|
| 2026 | 2114 | } |
|---|
| 2027 | 2115 | |
|---|
| 2116 | +static int |
|---|
| 2117 | +synthesize_uprobe_trace_def(struct probe_trace_event *tev, struct strbuf *buf) |
|---|
| 2118 | +{ |
|---|
| 2119 | + struct probe_trace_point *tp = &tev->point; |
|---|
| 2120 | + int err; |
|---|
| 2121 | + |
|---|
| 2122 | + err = strbuf_addf(buf, "%s:0x%lx", tp->module, tp->address); |
|---|
| 2123 | + |
|---|
| 2124 | + if (err >= 0 && tp->ref_ctr_offset) { |
|---|
| 2125 | + if (!uprobe_ref_ctr_is_supported()) |
|---|
| 2126 | + return -1; |
|---|
| 2127 | + err = strbuf_addf(buf, "(0x%lx)", tp->ref_ctr_offset); |
|---|
| 2128 | + } |
|---|
| 2129 | + return err >= 0 ? 0 : -1; |
|---|
| 2130 | +} |
|---|
| 2131 | + |
|---|
| 2028 | 2132 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) |
|---|
| 2029 | 2133 | { |
|---|
| 2030 | 2134 | struct probe_trace_point *tp = &tev->point; |
|---|
| .. | .. |
|---|
| 2054 | 2158 | } |
|---|
| 2055 | 2159 | |
|---|
| 2056 | 2160 | /* Use the tp->address for uprobes */ |
|---|
| 2057 | | - if (tev->uprobes) |
|---|
| 2058 | | - err = strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address); |
|---|
| 2059 | | - else if (!strncmp(tp->symbol, "0x", 2)) |
|---|
| 2161 | + if (tev->uprobes) { |
|---|
| 2162 | + err = synthesize_uprobe_trace_def(tev, &buf); |
|---|
| 2163 | + } else if (!strncmp(tp->symbol, "0x", 2)) { |
|---|
| 2060 | 2164 | /* Absolute address. See try_to_find_absolute_address() */ |
|---|
| 2061 | 2165 | err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", |
|---|
| 2062 | 2166 | tp->module ? ":" : "", tp->address); |
|---|
| 2063 | | - else |
|---|
| 2167 | + } else { |
|---|
| 2064 | 2168 | err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", |
|---|
| 2065 | 2169 | tp->module ? ":" : "", tp->symbol, tp->offset); |
|---|
| 2170 | + } |
|---|
| 2171 | + |
|---|
| 2066 | 2172 | if (err) |
|---|
| 2067 | 2173 | goto error; |
|---|
| 2068 | 2174 | |
|---|
| .. | .. |
|---|
| 2198 | 2304 | struct perf_probe_arg_field *field, *next; |
|---|
| 2199 | 2305 | int i; |
|---|
| 2200 | 2306 | |
|---|
| 2201 | | - free(pev->event); |
|---|
| 2202 | | - free(pev->group); |
|---|
| 2203 | | - free(pev->target); |
|---|
| 2307 | + zfree(&pev->event); |
|---|
| 2308 | + zfree(&pev->group); |
|---|
| 2309 | + zfree(&pev->target); |
|---|
| 2204 | 2310 | clear_perf_probe_point(&pev->point); |
|---|
| 2205 | 2311 | |
|---|
| 2206 | 2312 | for (i = 0; i < pev->nargs; i++) { |
|---|
| 2207 | | - free(pev->args[i].name); |
|---|
| 2208 | | - free(pev->args[i].var); |
|---|
| 2209 | | - free(pev->args[i].type); |
|---|
| 2313 | + zfree(&pev->args[i].name); |
|---|
| 2314 | + zfree(&pev->args[i].var); |
|---|
| 2315 | + zfree(&pev->args[i].type); |
|---|
| 2210 | 2316 | field = pev->args[i].field; |
|---|
| 2211 | 2317 | while (field) { |
|---|
| 2212 | 2318 | next = field->next; |
|---|
| .. | .. |
|---|
| 2215 | 2321 | field = next; |
|---|
| 2216 | 2322 | } |
|---|
| 2217 | 2323 | } |
|---|
| 2218 | | - free(pev->args); |
|---|
| 2219 | | - memset(pev, 0, sizeof(*pev)); |
|---|
| 2324 | + pev->nargs = 0; |
|---|
| 2325 | + zfree(&pev->args); |
|---|
| 2220 | 2326 | } |
|---|
| 2221 | 2327 | |
|---|
| 2222 | 2328 | #define strdup_or_goto(str, label) \ |
|---|
| .. | .. |
|---|
| 2297 | 2403 | struct probe_trace_arg_ref *ref, *next; |
|---|
| 2298 | 2404 | int i; |
|---|
| 2299 | 2405 | |
|---|
| 2300 | | - free(tev->event); |
|---|
| 2301 | | - free(tev->group); |
|---|
| 2302 | | - free(tev->point.symbol); |
|---|
| 2303 | | - free(tev->point.realname); |
|---|
| 2304 | | - free(tev->point.module); |
|---|
| 2406 | + zfree(&tev->event); |
|---|
| 2407 | + zfree(&tev->group); |
|---|
| 2408 | + zfree(&tev->point.symbol); |
|---|
| 2409 | + zfree(&tev->point.realname); |
|---|
| 2410 | + zfree(&tev->point.module); |
|---|
| 2305 | 2411 | for (i = 0; i < tev->nargs; i++) { |
|---|
| 2306 | | - free(tev->args[i].name); |
|---|
| 2307 | | - free(tev->args[i].value); |
|---|
| 2308 | | - free(tev->args[i].type); |
|---|
| 2412 | + zfree(&tev->args[i].name); |
|---|
| 2413 | + zfree(&tev->args[i].value); |
|---|
| 2414 | + zfree(&tev->args[i].type); |
|---|
| 2309 | 2415 | ref = tev->args[i].ref; |
|---|
| 2310 | 2416 | while (ref) { |
|---|
| 2311 | 2417 | next = ref->next; |
|---|
| .. | .. |
|---|
| 2313 | 2419 | ref = next; |
|---|
| 2314 | 2420 | } |
|---|
| 2315 | 2421 | } |
|---|
| 2316 | | - free(tev->args); |
|---|
| 2317 | | - memset(tev, 0, sizeof(*tev)); |
|---|
| 2422 | + zfree(&tev->args); |
|---|
| 2423 | + tev->nargs = 0; |
|---|
| 2318 | 2424 | } |
|---|
| 2319 | 2425 | |
|---|
| 2320 | 2426 | struct kprobe_blacklist_node { |
|---|
| .. | .. |
|---|
| 2331 | 2437 | while (!list_empty(blacklist)) { |
|---|
| 2332 | 2438 | node = list_first_entry(blacklist, |
|---|
| 2333 | 2439 | struct kprobe_blacklist_node, list); |
|---|
| 2334 | | - list_del(&node->list); |
|---|
| 2335 | | - free(node->symbol); |
|---|
| 2440 | + list_del_init(&node->list); |
|---|
| 2441 | + zfree(&node->symbol); |
|---|
| 2336 | 2442 | free(node); |
|---|
| 2337 | 2443 | } |
|---|
| 2338 | 2444 | } |
|---|
| .. | .. |
|---|
| 2646 | 2752 | { |
|---|
| 2647 | 2753 | int i; |
|---|
| 2648 | 2754 | char *buf = synthesize_probe_trace_command(tev); |
|---|
| 2755 | + struct probe_trace_point *tp = &tev->point; |
|---|
| 2756 | + |
|---|
| 2757 | + if (tp->ref_ctr_offset && !uprobe_ref_ctr_is_supported()) { |
|---|
| 2758 | + pr_warning("A semaphore is associated with %s:%s and " |
|---|
| 2759 | + "seems your kernel doesn't support it.\n", |
|---|
| 2760 | + tev->group, tev->event); |
|---|
| 2761 | + } |
|---|
| 2649 | 2762 | |
|---|
| 2650 | 2763 | /* Old uprobe event doesn't support memory dereference */ |
|---|
| 2651 | 2764 | if (!tev->uprobes || tev->nargs == 0 || !buf) |
|---|
| .. | .. |
|---|
| 2706 | 2819 | if (tev->event == NULL || tev->group == NULL) |
|---|
| 2707 | 2820 | return -ENOMEM; |
|---|
| 2708 | 2821 | |
|---|
| 2709 | | - /* Add added event name to namelist */ |
|---|
| 2710 | | - strlist__add(namelist, event); |
|---|
| 2822 | + /* |
|---|
| 2823 | + * Add new event name to namelist if multiprobe event is NOT |
|---|
| 2824 | + * supported, since we have to use new event name for following |
|---|
| 2825 | + * probes in that case. |
|---|
| 2826 | + */ |
|---|
| 2827 | + if (!multiprobe_event_is_supported()) |
|---|
| 2828 | + strlist__add(namelist, event); |
|---|
| 2711 | 2829 | return 0; |
|---|
| 2712 | 2830 | } |
|---|
| 2713 | 2831 | |
|---|
| .. | .. |
|---|
| 2922 | 3040 | if (sym->type != STT_FUNC) |
|---|
| 2923 | 3041 | continue; |
|---|
| 2924 | 3042 | |
|---|
| 3043 | + /* There can be duplicated symbols in the map */ |
|---|
| 3044 | + for (i = 0; i < j; i++) |
|---|
| 3045 | + if (sym->start == syms[i]->start) { |
|---|
| 3046 | + pr_debug("Found duplicated symbol %s @ %" PRIx64 "\n", |
|---|
| 3047 | + sym->name, sym->start); |
|---|
| 3048 | + break; |
|---|
| 3049 | + } |
|---|
| 3050 | + if (i != j) |
|---|
| 3051 | + continue; |
|---|
| 3052 | + |
|---|
| 2925 | 3053 | tev = (*tevs) + ret; |
|---|
| 2926 | 3054 | tp = &tev->point; |
|---|
| 2927 | 3055 | if (ret == num_matched_functions) { |
|---|
| .. | .. |
|---|
| 3047 | 3175 | /* |
|---|
| 3048 | 3176 | * Give it a '0x' leading symbol name. |
|---|
| 3049 | 3177 | * In __add_probe_trace_events, a NULL symbol is interpreted as |
|---|
| 3050 | | - * invalud. |
|---|
| 3178 | + * invalid. |
|---|
| 3051 | 3179 | */ |
|---|
| 3052 | 3180 | if (asprintf(&tp->symbol, "0x%lx", tp->address) < 0) |
|---|
| 3053 | 3181 | goto errout; |
|---|
| .. | .. |
|---|
| 3513 | 3641 | /* Show all (filtered) symbols */ |
|---|
| 3514 | 3642 | setup_pager(); |
|---|
| 3515 | 3643 | |
|---|
| 3516 | | - for (nd = rb_first(&map->dso->symbol_names); nd; nd = rb_next(nd)) { |
|---|
| 3644 | + for (nd = rb_first_cached(&map->dso->symbol_names); nd; |
|---|
| 3645 | + nd = rb_next(nd)) { |
|---|
| 3517 | 3646 | struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); |
|---|
| 3518 | 3647 | |
|---|
| 3519 | 3648 | if (strfilter__compare(_filter, pos->sym.name)) |
|---|