| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * probe-file.c : operate ftrace k/uprobe events files |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.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 | 6 | */ |
|---|
| 17 | 7 | #include <errno.h> |
|---|
| 18 | 8 | #include <fcntl.h> |
|---|
| .. | .. |
|---|
| 20 | 10 | #include <sys/types.h> |
|---|
| 21 | 11 | #include <sys/uio.h> |
|---|
| 22 | 12 | #include <unistd.h> |
|---|
| 23 | | -#include "util.h" |
|---|
| 13 | +#include <linux/zalloc.h> |
|---|
| 14 | +#include "namespaces.h" |
|---|
| 24 | 15 | #include "event.h" |
|---|
| 25 | 16 | #include "strlist.h" |
|---|
| 26 | 17 | #include "strfilter.h" |
|---|
| 27 | 18 | #include "debug.h" |
|---|
| 28 | | -#include "cache.h" |
|---|
| 19 | +#include "build-id.h" |
|---|
| 20 | +#include "dso.h" |
|---|
| 29 | 21 | #include "color.h" |
|---|
| 30 | 22 | #include "symbol.h" |
|---|
| 31 | | -#include "thread.h" |
|---|
| 23 | +#include "strbuf.h" |
|---|
| 32 | 24 | #include <api/fs/tracing_path.h> |
|---|
| 33 | 25 | #include "probe-event.h" |
|---|
| 34 | 26 | #include "probe-file.h" |
|---|
| .. | .. |
|---|
| 214 | 206 | } else |
|---|
| 215 | 207 | ret = strlist__add(sl, tev.event); |
|---|
| 216 | 208 | clear_probe_trace_event(&tev); |
|---|
| 209 | + /* Skip if there is same name multi-probe event in the list */ |
|---|
| 210 | + if (ret == -EEXIST) |
|---|
| 211 | + ret = 0; |
|---|
| 217 | 212 | if (ret < 0) |
|---|
| 218 | 213 | break; |
|---|
| 219 | 214 | } |
|---|
| .. | .. |
|---|
| 309 | 304 | p = strchr(ent->s, ':'); |
|---|
| 310 | 305 | if ((p && strfilter__compare(filter, p + 1)) || |
|---|
| 311 | 306 | strfilter__compare(filter, ent->s)) { |
|---|
| 312 | | - strlist__add(plist, ent->s); |
|---|
| 307 | + ret = strlist__add(plist, ent->s); |
|---|
| 308 | + if (ret == -ENOMEM) { |
|---|
| 309 | + pr_err("strlist__add failed with -ENOMEM\n"); |
|---|
| 310 | + goto out; |
|---|
| 311 | + } |
|---|
| 313 | 312 | ret = 0; |
|---|
| 314 | 313 | } |
|---|
| 315 | 314 | } |
|---|
| 315 | +out: |
|---|
| 316 | 316 | strlist__delete(namelist); |
|---|
| 317 | 317 | |
|---|
| 318 | 318 | return ret; |
|---|
| .. | .. |
|---|
| 519 | 519 | ret = -EINVAL; |
|---|
| 520 | 520 | goto out; |
|---|
| 521 | 521 | } |
|---|
| 522 | | - strlist__add(entry->tevlist, buf); |
|---|
| 522 | + ret = strlist__add(entry->tevlist, buf); |
|---|
| 523 | + if (ret == -ENOMEM) { |
|---|
| 524 | + pr_err("strlist__add failed with -ENOMEM\n"); |
|---|
| 525 | + goto out; |
|---|
| 526 | + } |
|---|
| 523 | 527 | } |
|---|
| 524 | 528 | } |
|---|
| 525 | 529 | out: |
|---|
| .. | .. |
|---|
| 680 | 684 | command = synthesize_probe_trace_command(&tevs[i]); |
|---|
| 681 | 685 | if (!command) |
|---|
| 682 | 686 | goto out_err; |
|---|
| 683 | | - strlist__add(entry->tevlist, command); |
|---|
| 687 | + ret = strlist__add(entry->tevlist, command); |
|---|
| 688 | + if (ret == -ENOMEM) { |
|---|
| 689 | + pr_err("strlist__add failed with -ENOMEM\n"); |
|---|
| 690 | + goto out_err; |
|---|
| 691 | + } |
|---|
| 692 | + |
|---|
| 684 | 693 | free(command); |
|---|
| 685 | 694 | } |
|---|
| 686 | 695 | list_add_tail(&entry->node, &pcache->entries); |
|---|
| .. | .. |
|---|
| 696 | 705 | #ifdef HAVE_GELF_GETNOTE_SUPPORT |
|---|
| 697 | 706 | static unsigned long long sdt_note__get_addr(struct sdt_note *note) |
|---|
| 698 | 707 | { |
|---|
| 699 | | - return note->bit32 ? (unsigned long long)note->addr.a32[0] |
|---|
| 700 | | - : (unsigned long long)note->addr.a64[0]; |
|---|
| 708 | + return note->bit32 ? |
|---|
| 709 | + (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] : |
|---|
| 710 | + (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC]; |
|---|
| 711 | +} |
|---|
| 712 | + |
|---|
| 713 | +static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note) |
|---|
| 714 | +{ |
|---|
| 715 | + return note->bit32 ? |
|---|
| 716 | + (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] : |
|---|
| 717 | + (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR]; |
|---|
| 701 | 718 | } |
|---|
| 702 | 719 | |
|---|
| 703 | 720 | static const char * const type_to_suffix[] = { |
|---|
| .. | .. |
|---|
| 774 | 791 | const char *sdtgrp) |
|---|
| 775 | 792 | { |
|---|
| 776 | 793 | struct strbuf buf; |
|---|
| 777 | | - char *ret = NULL, **args; |
|---|
| 778 | | - int i, args_count; |
|---|
| 794 | + char *ret = NULL; |
|---|
| 795 | + int i, args_count, err; |
|---|
| 796 | + unsigned long long ref_ctr_offset; |
|---|
| 779 | 797 | |
|---|
| 780 | 798 | if (strbuf_init(&buf, 32) < 0) |
|---|
| 781 | 799 | return NULL; |
|---|
| 782 | 800 | |
|---|
| 783 | | - if (strbuf_addf(&buf, "p:%s/%s %s:0x%llx", |
|---|
| 784 | | - sdtgrp, note->name, pathname, |
|---|
| 785 | | - sdt_note__get_addr(note)) < 0) |
|---|
| 801 | + err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx", |
|---|
| 802 | + sdtgrp, note->name, pathname, |
|---|
| 803 | + sdt_note__get_addr(note)); |
|---|
| 804 | + |
|---|
| 805 | + ref_ctr_offset = sdt_note__get_ref_ctr_offset(note); |
|---|
| 806 | + if (ref_ctr_offset && err >= 0) |
|---|
| 807 | + err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset); |
|---|
| 808 | + |
|---|
| 809 | + if (err < 0) |
|---|
| 786 | 810 | goto error; |
|---|
| 787 | 811 | |
|---|
| 788 | 812 | if (!note->args) |
|---|
| 789 | 813 | goto out; |
|---|
| 790 | 814 | |
|---|
| 791 | 815 | if (note->args) { |
|---|
| 792 | | - args = argv_split(note->args, &args_count); |
|---|
| 816 | + char **args = argv_split(note->args, &args_count); |
|---|
| 817 | + |
|---|
| 818 | + if (args == NULL) |
|---|
| 819 | + goto error; |
|---|
| 793 | 820 | |
|---|
| 794 | 821 | for (i = 0; i < args_count; ++i) { |
|---|
| 795 | | - if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0) |
|---|
| 822 | + if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0) { |
|---|
| 823 | + argv_free(args); |
|---|
| 796 | 824 | goto error; |
|---|
| 825 | + } |
|---|
| 797 | 826 | } |
|---|
| 827 | + |
|---|
| 828 | + argv_free(args); |
|---|
| 798 | 829 | } |
|---|
| 799 | 830 | |
|---|
| 800 | 831 | out: |
|---|
| .. | .. |
|---|
| 846 | 877 | break; |
|---|
| 847 | 878 | } |
|---|
| 848 | 879 | |
|---|
| 849 | | - strlist__add(entry->tevlist, buf); |
|---|
| 880 | + ret = strlist__add(entry->tevlist, buf); |
|---|
| 881 | + |
|---|
| 850 | 882 | free(buf); |
|---|
| 851 | 883 | entry = NULL; |
|---|
| 884 | + |
|---|
| 885 | + if (ret == -ENOMEM) { |
|---|
| 886 | + pr_err("strlist__add failed with -ENOMEM\n"); |
|---|
| 887 | + break; |
|---|
| 888 | + } |
|---|
| 852 | 889 | } |
|---|
| 853 | 890 | if (entry) { |
|---|
| 854 | 891 | list_del_init(&entry->node); |
|---|
| .. | .. |
|---|
| 998 | 1035 | enum ftrace_readme { |
|---|
| 999 | 1036 | FTRACE_README_PROBE_TYPE_X = 0, |
|---|
| 1000 | 1037 | FTRACE_README_KRETPROBE_OFFSET, |
|---|
| 1038 | + FTRACE_README_UPROBE_REF_CTR, |
|---|
| 1039 | + FTRACE_README_USER_ACCESS, |
|---|
| 1040 | + FTRACE_README_MULTIPROBE_EVENT, |
|---|
| 1041 | + FTRACE_README_IMMEDIATE_VALUE, |
|---|
| 1001 | 1042 | FTRACE_README_END, |
|---|
| 1002 | 1043 | }; |
|---|
| 1003 | 1044 | |
|---|
| .. | .. |
|---|
| 1009 | 1050 | [idx] = {.pattern = pat, .avail = false} |
|---|
| 1010 | 1051 | DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"), |
|---|
| 1011 | 1052 | DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"), |
|---|
| 1053 | + DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"), |
|---|
| 1054 | + DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*u]<offset>*"), |
|---|
| 1055 | + DEFINE_TYPE(FTRACE_README_MULTIPROBE_EVENT, "*Create/append/*"), |
|---|
| 1056 | + DEFINE_TYPE(FTRACE_README_IMMEDIATE_VALUE, "*\\imm-value,*"), |
|---|
| 1012 | 1057 | }; |
|---|
| 1013 | 1058 | |
|---|
| 1014 | 1059 | static bool scan_ftrace_readme(enum ftrace_readme type) |
|---|
| .. | .. |
|---|
| 1064 | 1109 | { |
|---|
| 1065 | 1110 | return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET); |
|---|
| 1066 | 1111 | } |
|---|
| 1112 | + |
|---|
| 1113 | +bool uprobe_ref_ctr_is_supported(void) |
|---|
| 1114 | +{ |
|---|
| 1115 | + return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR); |
|---|
| 1116 | +} |
|---|
| 1117 | + |
|---|
| 1118 | +bool user_access_is_supported(void) |
|---|
| 1119 | +{ |
|---|
| 1120 | + return scan_ftrace_readme(FTRACE_README_USER_ACCESS); |
|---|
| 1121 | +} |
|---|
| 1122 | + |
|---|
| 1123 | +bool multiprobe_event_is_supported(void) |
|---|
| 1124 | +{ |
|---|
| 1125 | + return scan_ftrace_readme(FTRACE_README_MULTIPROBE_EVENT); |
|---|
| 1126 | +} |
|---|
| 1127 | + |
|---|
| 1128 | +bool immediate_value_is_supported(void) |
|---|
| 1129 | +{ |
|---|
| 1130 | + return scan_ftrace_readme(FTRACE_README_IMMEDIATE_VALUE); |
|---|
| 1131 | +} |
|---|