.. | .. |
---|
| 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)) |
---|