Commit 469b9b88488e89114bb3e9ac5ee7906b7b96123f
Committed by
Arnaldo Carvalho de Melo
1 parent
fb8c5a56c7
Exists in
master
and in
7 other branches
perf probe: Add basic module support
Add basic module probe support on perf probe. This introduces "--module <MODNAME>" option to perf probe for putting probes and showing lines and variables in the given module. Currently, this supports only probing on running modules. Supporting off-line module probing is the next step. e.g.) [show lines] # ./perf probe --module drm -L drm_vblank_info <drm_vblank_info:0> 0 int drm_vblank_info(struct seq_file *m, void *data) 1 { struct drm_info_node *node = (struct drm_info_node *) m->private 3 struct drm_device *dev = node->minor->dev; ... [show vars] # ./perf probe --module drm -V drm_vblank_info:3 Available variables at drm_vblank_info:3 @<drm_vblank_info+20> (unknown_type) data struct drm_info_node* node struct seq_file* m [put a probe] # ./perf probe --module drm drm_vblank_info:3 node m Add new event: probe:drm_vblank_info (on drm_vblank_info:3 with node m) You can now use it on all perf tools, such as: perf record -e probe:drm_vblank_info -aR sleep 1 [list probes] # ./perf probe -l probe:drm_vblank_info (on drm_vblank_info:3@drivers/gpu/drm/drm_info.c with ... Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20101021101341.3542.71638.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Showing 7 changed files with 239 additions and 69 deletions Inline Diff
tools/perf/Documentation/perf-probe.txt
1 | perf-probe(1) | 1 | perf-probe(1) |
2 | ============= | 2 | ============= |
3 | 3 | ||
4 | NAME | 4 | NAME |
5 | ---- | 5 | ---- |
6 | perf-probe - Define new dynamic tracepoints | 6 | perf-probe - Define new dynamic tracepoints |
7 | 7 | ||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf probe' [options] --add='PROBE' [...] | 11 | 'perf probe' [options] --add='PROBE' [...] |
12 | or | 12 | or |
13 | 'perf probe' [options] PROBE | 13 | 'perf probe' [options] PROBE |
14 | or | 14 | or |
15 | 'perf probe' [options] --del='[GROUP:]EVENT' [...] | 15 | 'perf probe' [options] --del='[GROUP:]EVENT' [...] |
16 | or | 16 | or |
17 | 'perf probe' --list | 17 | 'perf probe' --list |
18 | or | 18 | or |
19 | 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' | 19 | 'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' |
20 | or | 20 | or |
21 | 'perf probe' [--externs] --vars='PROBEPOINT' | 21 | 'perf probe' [options] --vars='PROBEPOINT' |
22 | 22 | ||
23 | DESCRIPTION | 23 | DESCRIPTION |
24 | ----------- | 24 | ----------- |
25 | This command defines dynamic tracepoint events, by symbol and registers | 25 | This command defines dynamic tracepoint events, by symbol and registers |
26 | without debuginfo, or by C expressions (C line numbers, C function names, | 26 | without debuginfo, or by C expressions (C line numbers, C function names, |
27 | and C local variables) with debuginfo. | 27 | and C local variables) with debuginfo. |
28 | 28 | ||
29 | 29 | ||
30 | OPTIONS | 30 | OPTIONS |
31 | ------- | 31 | ------- |
32 | -k:: | 32 | -k:: |
33 | --vmlinux=PATH:: | 33 | --vmlinux=PATH:: |
34 | Specify vmlinux path which has debuginfo (Dwarf binary). | 34 | Specify vmlinux path which has debuginfo (Dwarf binary). |
35 | |||
36 | -m:: | ||
37 | --module=MODNAME:: | ||
38 | Specify module name in which perf-probe searches probe points | ||
39 | or lines. | ||
35 | 40 | ||
36 | -s:: | 41 | -s:: |
37 | --source=PATH:: | 42 | --source=PATH:: |
38 | Specify path to kernel source. | 43 | Specify path to kernel source. |
39 | 44 | ||
40 | -v:: | 45 | -v:: |
41 | --verbose:: | 46 | --verbose:: |
42 | Be more verbose (show parsed arguments, etc). | 47 | Be more verbose (show parsed arguments, etc). |
43 | 48 | ||
44 | -a:: | 49 | -a:: |
45 | --add=:: | 50 | --add=:: |
46 | Define a probe event (see PROBE SYNTAX for detail). | 51 | Define a probe event (see PROBE SYNTAX for detail). |
47 | 52 | ||
48 | -d:: | 53 | -d:: |
49 | --del=:: | 54 | --del=:: |
50 | Delete probe events. This accepts glob wildcards('*', '?') and character | 55 | Delete probe events. This accepts glob wildcards('*', '?') and character |
51 | classes(e.g. [a-z], [!A-Z]). | 56 | classes(e.g. [a-z], [!A-Z]). |
52 | 57 | ||
53 | -l:: | 58 | -l:: |
54 | --list:: | 59 | --list:: |
55 | List up current probe events. | 60 | List up current probe events. |
56 | 61 | ||
57 | -L:: | 62 | -L:: |
58 | --line=:: | 63 | --line=:: |
59 | Show source code lines which can be probed. This needs an argument | 64 | Show source code lines which can be probed. This needs an argument |
60 | which specifies a range of the source code. (see LINE SYNTAX for detail) | 65 | which specifies a range of the source code. (see LINE SYNTAX for detail) |
61 | 66 | ||
62 | -V:: | 67 | -V:: |
63 | --vars=:: | 68 | --vars=:: |
64 | Show available local variables at given probe point. The argument | 69 | Show available local variables at given probe point. The argument |
65 | syntax is same as PROBE SYNTAX, but NO ARGs. | 70 | syntax is same as PROBE SYNTAX, but NO ARGs. |
66 | 71 | ||
67 | --externs:: | 72 | --externs:: |
68 | (Only for --vars) Show external defined variables in addition to local | 73 | (Only for --vars) Show external defined variables in addition to local |
69 | variables. | 74 | variables. |
70 | 75 | ||
71 | -f:: | 76 | -f:: |
72 | --force:: | 77 | --force:: |
73 | Forcibly add events with existing name. | 78 | Forcibly add events with existing name. |
74 | 79 | ||
75 | -n:: | 80 | -n:: |
76 | --dry-run:: | 81 | --dry-run:: |
77 | Dry run. With this option, --add and --del doesn't execute actual | 82 | Dry run. With this option, --add and --del doesn't execute actual |
78 | adding and removal operations. | 83 | adding and removal operations. |
79 | 84 | ||
80 | --max-probes:: | 85 | --max-probes:: |
81 | Set the maximum number of probe points for an event. Default is 128. | 86 | Set the maximum number of probe points for an event. Default is 128. |
82 | 87 | ||
83 | PROBE SYNTAX | 88 | PROBE SYNTAX |
84 | ------------ | 89 | ------------ |
85 | Probe points are defined by following syntax. | 90 | Probe points are defined by following syntax. |
86 | 91 | ||
87 | 1) Define event based on function name | 92 | 1) Define event based on function name |
88 | [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...] | 93 | [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...] |
89 | 94 | ||
90 | 2) Define event based on source file with line number | 95 | 2) Define event based on source file with line number |
91 | [EVENT=]SRC:ALN [ARG ...] | 96 | [EVENT=]SRC:ALN [ARG ...] |
92 | 97 | ||
93 | 3) Define event based on source file with lazy pattern | 98 | 3) Define event based on source file with lazy pattern |
94 | [EVENT=]SRC;PTN [ARG ...] | 99 | [EVENT=]SRC;PTN [ARG ...] |
95 | 100 | ||
96 | 101 | ||
97 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. | 102 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. |
98 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. | 103 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. |
99 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. | 104 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. |
100 | 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). | 105 | 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). |
101 | 106 | ||
102 | PROBE ARGUMENT | 107 | PROBE ARGUMENT |
103 | -------------- | 108 | -------------- |
104 | Each probe argument follows below syntax. | 109 | Each probe argument follows below syntax. |
105 | 110 | ||
106 | [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] | 111 | [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] |
107 | 112 | ||
108 | 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) | 113 | 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) |
109 | 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type. | 114 | 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type. |
110 | 115 | ||
111 | LINE SYNTAX | 116 | LINE SYNTAX |
112 | ----------- | 117 | ----------- |
113 | Line range is descripted by following syntax. | 118 | Line range is descripted by following syntax. |
114 | 119 | ||
115 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]" | 120 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]" |
116 | 121 | ||
117 | FUNC specifies the function name of showing lines. 'RLN' is the start line | 122 | FUNC specifies the function name of showing lines. 'RLN' is the start line |
118 | number from function entry line, and 'RLN2' is the end line number. As same as | 123 | number from function entry line, and 'RLN2' is the end line number. As same as |
119 | probe syntax, 'SRC' means the source file path, 'ALN' is start line number, | 124 | probe syntax, 'SRC' means the source file path, 'ALN' is start line number, |
120 | and 'ALN2' is end line number in the file. It is also possible to specify how | 125 | and 'ALN2' is end line number in the file. It is also possible to specify how |
121 | many lines to show by using 'NUM'. | 126 | many lines to show by using 'NUM'. |
122 | So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. | 127 | So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. |
123 | 128 | ||
124 | LAZY MATCHING | 129 | LAZY MATCHING |
125 | ------------- | 130 | ------------- |
126 | The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]). | 131 | The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]). |
127 | 132 | ||
128 | e.g. | 133 | e.g. |
129 | 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on. | 134 | 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on. |
130 | 135 | ||
131 | This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.) | 136 | This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.) |
132 | 137 | ||
133 | 138 | ||
134 | EXAMPLES | 139 | EXAMPLES |
135 | -------- | 140 | -------- |
136 | Display which lines in schedule() can be probed: | 141 | Display which lines in schedule() can be probed: |
137 | 142 | ||
138 | ./perf probe --line schedule | 143 | ./perf probe --line schedule |
139 | 144 | ||
140 | Add a probe on schedule() function 12th line with recording cpu local variable: | 145 | Add a probe on schedule() function 12th line with recording cpu local variable: |
141 | 146 | ||
142 | ./perf probe schedule:12 cpu | 147 | ./perf probe schedule:12 cpu |
143 | or | 148 | or |
144 | ./perf probe --add='schedule:12 cpu' | 149 | ./perf probe --add='schedule:12 cpu' |
145 | 150 | ||
146 | this will add one or more probes which has the name start with "schedule". | 151 | this will add one or more probes which has the name start with "schedule". |
147 | 152 | ||
148 | Add probes on lines in schedule() function which calls update_rq_clock(). | 153 | Add probes on lines in schedule() function which calls update_rq_clock(). |
149 | 154 | ||
150 | ./perf probe 'schedule;update_rq_clock*' | 155 | ./perf probe 'schedule;update_rq_clock*' |
151 | or | 156 | or |
152 | ./perf probe --add='schedule;update_rq_clock*' | 157 | ./perf probe --add='schedule;update_rq_clock*' |
153 | 158 | ||
154 | Delete all probes on schedule(). | 159 | Delete all probes on schedule(). |
155 | 160 | ||
156 | ./perf probe --del='schedule*' | 161 | ./perf probe --del='schedule*' |
157 | 162 | ||
158 | 163 | ||
159 | SEE ALSO | 164 | SEE ALSO |
160 | -------- | 165 | -------- |
161 | linkperf:perf-trace[1], linkperf:perf-record[1] | 166 | linkperf:perf-trace[1], linkperf:perf-record[1] |
162 | 167 |
tools/perf/builtin-probe.c
1 | /* | 1 | /* |
2 | * builtin-probe.c | 2 | * builtin-probe.c |
3 | * | 3 | * |
4 | * Builtin probe command: Set up probe events by C expression | 4 | * Builtin probe command: Set up probe events by C expression |
5 | * | 5 | * |
6 | * Written by Masami Hiramatsu <mhiramat@redhat.com> | 6 | * Written by Masami Hiramatsu <mhiramat@redhat.com> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | #define _GNU_SOURCE | 23 | #define _GNU_SOURCE |
24 | #include <sys/utsname.h> | 24 | #include <sys/utsname.h> |
25 | #include <sys/types.h> | 25 | #include <sys/types.h> |
26 | #include <sys/stat.h> | 26 | #include <sys/stat.h> |
27 | #include <fcntl.h> | 27 | #include <fcntl.h> |
28 | #include <errno.h> | 28 | #include <errno.h> |
29 | #include <stdio.h> | 29 | #include <stdio.h> |
30 | #include <unistd.h> | 30 | #include <unistd.h> |
31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
32 | #include <string.h> | 32 | #include <string.h> |
33 | 33 | ||
34 | #undef _GNU_SOURCE | 34 | #undef _GNU_SOURCE |
35 | #include "perf.h" | 35 | #include "perf.h" |
36 | #include "builtin.h" | 36 | #include "builtin.h" |
37 | #include "util/util.h" | 37 | #include "util/util.h" |
38 | #include "util/strlist.h" | 38 | #include "util/strlist.h" |
39 | #include "util/symbol.h" | 39 | #include "util/symbol.h" |
40 | #include "util/debug.h" | 40 | #include "util/debug.h" |
41 | #include "util/debugfs.h" | 41 | #include "util/debugfs.h" |
42 | #include "util/parse-options.h" | 42 | #include "util/parse-options.h" |
43 | #include "util/probe-finder.h" | 43 | #include "util/probe-finder.h" |
44 | #include "util/probe-event.h" | 44 | #include "util/probe-event.h" |
45 | 45 | ||
46 | #define MAX_PATH_LEN 256 | 46 | #define MAX_PATH_LEN 256 |
47 | 47 | ||
48 | /* Session management structure */ | 48 | /* Session management structure */ |
49 | static struct { | 49 | static struct { |
50 | bool list_events; | 50 | bool list_events; |
51 | bool force_add; | 51 | bool force_add; |
52 | bool show_lines; | 52 | bool show_lines; |
53 | bool show_vars; | 53 | bool show_vars; |
54 | bool show_ext_vars; | 54 | bool show_ext_vars; |
55 | bool mod_events; | 55 | bool mod_events; |
56 | int nevents; | 56 | int nevents; |
57 | struct perf_probe_event events[MAX_PROBES]; | 57 | struct perf_probe_event events[MAX_PROBES]; |
58 | struct strlist *dellist; | 58 | struct strlist *dellist; |
59 | struct line_range line_range; | 59 | struct line_range line_range; |
60 | const char *target_module; | ||
60 | int max_probe_points; | 61 | int max_probe_points; |
61 | } params; | 62 | } params; |
62 | 63 | ||
63 | /* Parse an event definition. Note that any error must die. */ | 64 | /* Parse an event definition. Note that any error must die. */ |
64 | static int parse_probe_event(const char *str) | 65 | static int parse_probe_event(const char *str) |
65 | { | 66 | { |
66 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; | 67 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; |
67 | int ret; | 68 | int ret; |
68 | 69 | ||
69 | pr_debug("probe-definition(%d): %s\n", params.nevents, str); | 70 | pr_debug("probe-definition(%d): %s\n", params.nevents, str); |
70 | if (++params.nevents == MAX_PROBES) { | 71 | if (++params.nevents == MAX_PROBES) { |
71 | pr_err("Too many probes (> %d) were specified.", MAX_PROBES); | 72 | pr_err("Too many probes (> %d) were specified.", MAX_PROBES); |
72 | return -1; | 73 | return -1; |
73 | } | 74 | } |
74 | 75 | ||
75 | /* Parse a perf-probe command into event */ | 76 | /* Parse a perf-probe command into event */ |
76 | ret = parse_perf_probe_command(str, pev); | 77 | ret = parse_perf_probe_command(str, pev); |
77 | pr_debug("%d arguments\n", pev->nargs); | 78 | pr_debug("%d arguments\n", pev->nargs); |
78 | 79 | ||
79 | return ret; | 80 | return ret; |
80 | } | 81 | } |
81 | 82 | ||
82 | static int parse_probe_event_argv(int argc, const char **argv) | 83 | static int parse_probe_event_argv(int argc, const char **argv) |
83 | { | 84 | { |
84 | int i, len, ret; | 85 | int i, len, ret; |
85 | char *buf; | 86 | char *buf; |
86 | 87 | ||
87 | /* Bind up rest arguments */ | 88 | /* Bind up rest arguments */ |
88 | len = 0; | 89 | len = 0; |
89 | for (i = 0; i < argc; i++) | 90 | for (i = 0; i < argc; i++) |
90 | len += strlen(argv[i]) + 1; | 91 | len += strlen(argv[i]) + 1; |
91 | buf = zalloc(len + 1); | 92 | buf = zalloc(len + 1); |
92 | if (buf == NULL) | 93 | if (buf == NULL) |
93 | return -ENOMEM; | 94 | return -ENOMEM; |
94 | len = 0; | 95 | len = 0; |
95 | for (i = 0; i < argc; i++) | 96 | for (i = 0; i < argc; i++) |
96 | len += sprintf(&buf[len], "%s ", argv[i]); | 97 | len += sprintf(&buf[len], "%s ", argv[i]); |
97 | params.mod_events = true; | 98 | params.mod_events = true; |
98 | ret = parse_probe_event(buf); | 99 | ret = parse_probe_event(buf); |
99 | free(buf); | 100 | free(buf); |
100 | return ret; | 101 | return ret; |
101 | } | 102 | } |
102 | 103 | ||
103 | static int opt_add_probe_event(const struct option *opt __used, | 104 | static int opt_add_probe_event(const struct option *opt __used, |
104 | const char *str, int unset __used) | 105 | const char *str, int unset __used) |
105 | { | 106 | { |
106 | if (str) { | 107 | if (str) { |
107 | params.mod_events = true; | 108 | params.mod_events = true; |
108 | return parse_probe_event(str); | 109 | return parse_probe_event(str); |
109 | } else | 110 | } else |
110 | return 0; | 111 | return 0; |
111 | } | 112 | } |
112 | 113 | ||
113 | static int opt_del_probe_event(const struct option *opt __used, | 114 | static int opt_del_probe_event(const struct option *opt __used, |
114 | const char *str, int unset __used) | 115 | const char *str, int unset __used) |
115 | { | 116 | { |
116 | if (str) { | 117 | if (str) { |
117 | params.mod_events = true; | 118 | params.mod_events = true; |
118 | if (!params.dellist) | 119 | if (!params.dellist) |
119 | params.dellist = strlist__new(true, NULL); | 120 | params.dellist = strlist__new(true, NULL); |
120 | strlist__add(params.dellist, str); | 121 | strlist__add(params.dellist, str); |
121 | } | 122 | } |
122 | return 0; | 123 | return 0; |
123 | } | 124 | } |
124 | 125 | ||
125 | #ifdef DWARF_SUPPORT | 126 | #ifdef DWARF_SUPPORT |
126 | static int opt_show_lines(const struct option *opt __used, | 127 | static int opt_show_lines(const struct option *opt __used, |
127 | const char *str, int unset __used) | 128 | const char *str, int unset __used) |
128 | { | 129 | { |
129 | int ret = 0; | 130 | int ret = 0; |
130 | 131 | ||
131 | if (str) | 132 | if (str) |
132 | ret = parse_line_range_desc(str, ¶ms.line_range); | 133 | ret = parse_line_range_desc(str, ¶ms.line_range); |
133 | INIT_LIST_HEAD(¶ms.line_range.line_list); | 134 | INIT_LIST_HEAD(¶ms.line_range.line_list); |
134 | params.show_lines = true; | 135 | params.show_lines = true; |
135 | 136 | ||
136 | return ret; | 137 | return ret; |
137 | } | 138 | } |
138 | 139 | ||
139 | static int opt_show_vars(const struct option *opt __used, | 140 | static int opt_show_vars(const struct option *opt __used, |
140 | const char *str, int unset __used) | 141 | const char *str, int unset __used) |
141 | { | 142 | { |
142 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; | 143 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; |
143 | int ret; | 144 | int ret; |
144 | 145 | ||
145 | if (!str) | 146 | if (!str) |
146 | return 0; | 147 | return 0; |
147 | 148 | ||
148 | ret = parse_probe_event(str); | 149 | ret = parse_probe_event(str); |
149 | if (!ret && pev->nargs != 0) { | 150 | if (!ret && pev->nargs != 0) { |
150 | pr_err(" Error: '--vars' doesn't accept arguments.\n"); | 151 | pr_err(" Error: '--vars' doesn't accept arguments.\n"); |
151 | return -EINVAL; | 152 | return -EINVAL; |
152 | } | 153 | } |
153 | params.show_vars = true; | 154 | params.show_vars = true; |
154 | 155 | ||
155 | return ret; | 156 | return ret; |
156 | } | 157 | } |
157 | #endif | 158 | #endif |
158 | 159 | ||
159 | static const char * const probe_usage[] = { | 160 | static const char * const probe_usage[] = { |
160 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", | 161 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", |
161 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", | 162 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", |
162 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | 163 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", |
163 | "perf probe --list", | 164 | "perf probe --list", |
164 | #ifdef DWARF_SUPPORT | 165 | #ifdef DWARF_SUPPORT |
165 | "perf probe --line 'LINEDESC'", | 166 | "perf probe [<options>] --line 'LINEDESC'", |
166 | "perf probe [--externs] --vars 'PROBEPOINT'", | 167 | "perf probe [<options>] --vars 'PROBEPOINT'", |
167 | #endif | 168 | #endif |
168 | NULL | 169 | NULL |
169 | }; | 170 | }; |
170 | 171 | ||
171 | static const struct option options[] = { | 172 | static const struct option options[] = { |
172 | OPT_INCR('v', "verbose", &verbose, | 173 | OPT_INCR('v', "verbose", &verbose, |
173 | "be more verbose (show parsed arguments, etc)"), | 174 | "be more verbose (show parsed arguments, etc)"), |
174 | OPT_BOOLEAN('l', "list", ¶ms.list_events, | 175 | OPT_BOOLEAN('l', "list", ¶ms.list_events, |
175 | "list up current probe events"), | 176 | "list up current probe events"), |
176 | OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", | 177 | OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", |
177 | opt_del_probe_event), | 178 | opt_del_probe_event), |
178 | OPT_CALLBACK('a', "add", NULL, | 179 | OPT_CALLBACK('a', "add", NULL, |
179 | #ifdef DWARF_SUPPORT | 180 | #ifdef DWARF_SUPPORT |
180 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" | 181 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" |
181 | " [[NAME=]ARG ...]", | 182 | " [[NAME=]ARG ...]", |
182 | #else | 183 | #else |
183 | "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]", | 184 | "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]", |
184 | #endif | 185 | #endif |
185 | "probe point definition, where\n" | 186 | "probe point definition, where\n" |
186 | "\t\tGROUP:\tGroup name (optional)\n" | 187 | "\t\tGROUP:\tGroup name (optional)\n" |
187 | "\t\tEVENT:\tEvent name\n" | 188 | "\t\tEVENT:\tEvent name\n" |
188 | "\t\tFUNC:\tFunction name\n" | 189 | "\t\tFUNC:\tFunction name\n" |
189 | "\t\tOFF:\tOffset from function entry (in byte)\n" | 190 | "\t\tOFF:\tOffset from function entry (in byte)\n" |
190 | "\t\t%return:\tPut the probe at function return\n" | 191 | "\t\t%return:\tPut the probe at function return\n" |
191 | #ifdef DWARF_SUPPORT | 192 | #ifdef DWARF_SUPPORT |
192 | "\t\tSRC:\tSource code path\n" | 193 | "\t\tSRC:\tSource code path\n" |
193 | "\t\tRL:\tRelative line number from function entry.\n" | 194 | "\t\tRL:\tRelative line number from function entry.\n" |
194 | "\t\tAL:\tAbsolute line number in file.\n" | 195 | "\t\tAL:\tAbsolute line number in file.\n" |
195 | "\t\tPT:\tLazy expression of line code.\n" | 196 | "\t\tPT:\tLazy expression of line code.\n" |
196 | "\t\tARG:\tProbe argument (local variable name or\n" | 197 | "\t\tARG:\tProbe argument (local variable name or\n" |
197 | "\t\t\tkprobe-tracer argument format.)\n", | 198 | "\t\t\tkprobe-tracer argument format.)\n", |
198 | #else | 199 | #else |
199 | "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n", | 200 | "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n", |
200 | #endif | 201 | #endif |
201 | opt_add_probe_event), | 202 | opt_add_probe_event), |
202 | OPT_BOOLEAN('f', "force", ¶ms.force_add, "forcibly add events" | 203 | OPT_BOOLEAN('f', "force", ¶ms.force_add, "forcibly add events" |
203 | " with existing name"), | 204 | " with existing name"), |
204 | #ifdef DWARF_SUPPORT | 205 | #ifdef DWARF_SUPPORT |
205 | OPT_CALLBACK('L', "line", NULL, | 206 | OPT_CALLBACK('L', "line", NULL, |
206 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", | 207 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", |
207 | "Show source code lines.", opt_show_lines), | 208 | "Show source code lines.", opt_show_lines), |
208 | OPT_CALLBACK('V', "vars", NULL, | 209 | OPT_CALLBACK('V', "vars", NULL, |
209 | "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT", | 210 | "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT", |
210 | "Show accessible variables on PROBEDEF", opt_show_vars), | 211 | "Show accessible variables on PROBEDEF", opt_show_vars), |
211 | OPT_BOOLEAN('\0', "externs", ¶ms.show_ext_vars, | 212 | OPT_BOOLEAN('\0', "externs", ¶ms.show_ext_vars, |
212 | "Show external variables too (with --vars only)"), | 213 | "Show external variables too (with --vars only)"), |
213 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 214 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
214 | "file", "vmlinux pathname"), | 215 | "file", "vmlinux pathname"), |
215 | OPT_STRING('s', "source", &symbol_conf.source_prefix, | 216 | OPT_STRING('s', "source", &symbol_conf.source_prefix, |
216 | "directory", "path to kernel source"), | 217 | "directory", "path to kernel source"), |
218 | OPT_STRING('m', "module", ¶ms.target_module, | ||
219 | "modname", "target module name"), | ||
217 | #endif | 220 | #endif |
218 | OPT__DRY_RUN(&probe_event_dry_run), | 221 | OPT__DRY_RUN(&probe_event_dry_run), |
219 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, | 222 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, |
220 | "Set how many probe points can be found for a probe."), | 223 | "Set how many probe points can be found for a probe."), |
221 | OPT_END() | 224 | OPT_END() |
222 | }; | 225 | }; |
223 | 226 | ||
224 | int cmd_probe(int argc, const char **argv, const char *prefix __used) | 227 | int cmd_probe(int argc, const char **argv, const char *prefix __used) |
225 | { | 228 | { |
226 | int ret; | 229 | int ret; |
227 | 230 | ||
228 | argc = parse_options(argc, argv, options, probe_usage, | 231 | argc = parse_options(argc, argv, options, probe_usage, |
229 | PARSE_OPT_STOP_AT_NON_OPTION); | 232 | PARSE_OPT_STOP_AT_NON_OPTION); |
230 | if (argc > 0) { | 233 | if (argc > 0) { |
231 | if (strcmp(argv[0], "-") == 0) { | 234 | if (strcmp(argv[0], "-") == 0) { |
232 | pr_warning(" Error: '-' is not supported.\n"); | 235 | pr_warning(" Error: '-' is not supported.\n"); |
233 | usage_with_options(probe_usage, options); | 236 | usage_with_options(probe_usage, options); |
234 | } | 237 | } |
235 | ret = parse_probe_event_argv(argc, argv); | 238 | ret = parse_probe_event_argv(argc, argv); |
236 | if (ret < 0) { | 239 | if (ret < 0) { |
237 | pr_err(" Error: Parse Error. (%d)\n", ret); | 240 | pr_err(" Error: Parse Error. (%d)\n", ret); |
238 | return ret; | 241 | return ret; |
239 | } | 242 | } |
240 | } | 243 | } |
241 | 244 | ||
242 | if (params.max_probe_points == 0) | 245 | if (params.max_probe_points == 0) |
243 | params.max_probe_points = MAX_PROBES; | 246 | params.max_probe_points = MAX_PROBES; |
244 | 247 | ||
245 | if ((!params.nevents && !params.dellist && !params.list_events && | 248 | if ((!params.nevents && !params.dellist && !params.list_events && |
246 | !params.show_lines)) | 249 | !params.show_lines)) |
247 | usage_with_options(probe_usage, options); | 250 | usage_with_options(probe_usage, options); |
248 | 251 | ||
249 | if (params.list_events) { | 252 | if (params.list_events) { |
250 | if (params.mod_events) { | 253 | if (params.mod_events) { |
251 | pr_err(" Error: Don't use --list with --add/--del.\n"); | 254 | pr_err(" Error: Don't use --list with --add/--del.\n"); |
252 | usage_with_options(probe_usage, options); | 255 | usage_with_options(probe_usage, options); |
253 | } | 256 | } |
254 | if (params.show_lines) { | 257 | if (params.show_lines) { |
255 | pr_err(" Error: Don't use --list with --line.\n"); | 258 | pr_err(" Error: Don't use --list with --line.\n"); |
256 | usage_with_options(probe_usage, options); | 259 | usage_with_options(probe_usage, options); |
257 | } | 260 | } |
258 | if (params.show_vars) { | 261 | if (params.show_vars) { |
259 | pr_err(" Error: Don't use --list with --vars.\n"); | 262 | pr_err(" Error: Don't use --list with --vars.\n"); |
260 | usage_with_options(probe_usage, options); | 263 | usage_with_options(probe_usage, options); |
261 | } | 264 | } |
262 | ret = show_perf_probe_events(); | 265 | ret = show_perf_probe_events(); |
263 | if (ret < 0) | 266 | if (ret < 0) |
264 | pr_err(" Error: Failed to show event list. (%d)\n", | 267 | pr_err(" Error: Failed to show event list. (%d)\n", |
265 | ret); | 268 | ret); |
266 | return ret; | 269 | return ret; |
267 | } | 270 | } |
268 | 271 | ||
269 | #ifdef DWARF_SUPPORT | 272 | #ifdef DWARF_SUPPORT |
270 | if (params.show_lines) { | 273 | if (params.show_lines) { |
271 | if (params.mod_events) { | 274 | if (params.mod_events) { |
272 | pr_err(" Error: Don't use --line with" | 275 | pr_err(" Error: Don't use --line with" |
273 | " --add/--del.\n"); | 276 | " --add/--del.\n"); |
274 | usage_with_options(probe_usage, options); | 277 | usage_with_options(probe_usage, options); |
275 | } | 278 | } |
276 | if (params.show_vars) { | 279 | if (params.show_vars) { |
277 | pr_err(" Error: Don't use --line with --vars.\n"); | 280 | pr_err(" Error: Don't use --line with --vars.\n"); |
278 | usage_with_options(probe_usage, options); | 281 | usage_with_options(probe_usage, options); |
279 | } | 282 | } |
280 | 283 | ||
281 | ret = show_line_range(¶ms.line_range); | 284 | ret = show_line_range(¶ms.line_range, params.target_module); |
282 | if (ret < 0) | 285 | if (ret < 0) |
283 | pr_err(" Error: Failed to show lines. (%d)\n", ret); | 286 | pr_err(" Error: Failed to show lines. (%d)\n", ret); |
284 | return ret; | 287 | return ret; |
285 | } | 288 | } |
286 | if (params.show_vars) { | 289 | if (params.show_vars) { |
287 | if (params.mod_events) { | 290 | if (params.mod_events) { |
288 | pr_err(" Error: Don't use --vars with" | 291 | pr_err(" Error: Don't use --vars with" |
289 | " --add/--del.\n"); | 292 | " --add/--del.\n"); |
290 | usage_with_options(probe_usage, options); | 293 | usage_with_options(probe_usage, options); |
291 | } | 294 | } |
292 | ret = show_available_vars(params.events, params.nevents, | 295 | ret = show_available_vars(params.events, params.nevents, |
293 | params.max_probe_points, | 296 | params.max_probe_points, |
297 | params.target_module, | ||
294 | params.show_ext_vars); | 298 | params.show_ext_vars); |
295 | if (ret < 0) | 299 | if (ret < 0) |
296 | pr_err(" Error: Failed to show vars. (%d)\n", ret); | 300 | pr_err(" Error: Failed to show vars. (%d)\n", ret); |
297 | return ret; | 301 | return ret; |
298 | } | 302 | } |
299 | #endif | 303 | #endif |
300 | 304 | ||
301 | if (params.dellist) { | 305 | if (params.dellist) { |
302 | ret = del_perf_probe_events(params.dellist); | 306 | ret = del_perf_probe_events(params.dellist); |
303 | strlist__delete(params.dellist); | 307 | strlist__delete(params.dellist); |
304 | if (ret < 0) { | 308 | if (ret < 0) { |
305 | pr_err(" Error: Failed to delete events. (%d)\n", ret); | 309 | pr_err(" Error: Failed to delete events. (%d)\n", ret); |
306 | return ret; | 310 | return ret; |
307 | } | 311 | } |
308 | } | 312 | } |
309 | 313 | ||
310 | if (params.nevents) { | 314 | if (params.nevents) { |
311 | ret = add_perf_probe_events(params.events, params.nevents, | 315 | ret = add_perf_probe_events(params.events, params.nevents, |
312 | params.max_probe_points, | 316 | params.max_probe_points, |
317 | params.target_module, | ||
313 | params.force_add); | 318 | params.force_add); |
314 | if (ret < 0) { | 319 | if (ret < 0) { |
315 | pr_err(" Error: Failed to add events. (%d)\n", ret); | 320 | pr_err(" Error: Failed to add events. (%d)\n", ret); |
316 | return ret; | 321 | return ret; |
317 | } | 322 | } |
318 | } | 323 | } |
319 | return 0; | 324 | return 0; |
320 | } | 325 | } |
321 | 326 |
tools/perf/util/map.h
1 | #ifndef __PERF_MAP_H | 1 | #ifndef __PERF_MAP_H |
2 | #define __PERF_MAP_H | 2 | #define __PERF_MAP_H |
3 | 3 | ||
4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
5 | #include <linux/list.h> | 5 | #include <linux/list.h> |
6 | #include <linux/rbtree.h> | 6 | #include <linux/rbtree.h> |
7 | #include <stdio.h> | 7 | #include <stdio.h> |
8 | #include <stdbool.h> | 8 | #include <stdbool.h> |
9 | #include "types.h" | 9 | #include "types.h" |
10 | 10 | ||
11 | enum map_type { | 11 | enum map_type { |
12 | MAP__FUNCTION = 0, | 12 | MAP__FUNCTION = 0, |
13 | MAP__VARIABLE, | 13 | MAP__VARIABLE, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | #define MAP__NR_TYPES (MAP__VARIABLE + 1) | 16 | #define MAP__NR_TYPES (MAP__VARIABLE + 1) |
17 | 17 | ||
18 | extern const char *map_type__name[MAP__NR_TYPES]; | 18 | extern const char *map_type__name[MAP__NR_TYPES]; |
19 | 19 | ||
20 | struct dso; | 20 | struct dso; |
21 | struct ref_reloc_sym; | 21 | struct ref_reloc_sym; |
22 | struct map_groups; | 22 | struct map_groups; |
23 | struct machine; | 23 | struct machine; |
24 | 24 | ||
25 | struct map { | 25 | struct map { |
26 | union { | 26 | union { |
27 | struct rb_node rb_node; | 27 | struct rb_node rb_node; |
28 | struct list_head node; | 28 | struct list_head node; |
29 | }; | 29 | }; |
30 | u64 start; | 30 | u64 start; |
31 | u64 end; | 31 | u64 end; |
32 | u8 /* enum map_type */ type; | 32 | u8 /* enum map_type */ type; |
33 | bool referenced; | 33 | bool referenced; |
34 | u32 priv; | 34 | u32 priv; |
35 | u64 pgoff; | 35 | u64 pgoff; |
36 | 36 | ||
37 | /* ip -> dso rip */ | 37 | /* ip -> dso rip */ |
38 | u64 (*map_ip)(struct map *, u64); | 38 | u64 (*map_ip)(struct map *, u64); |
39 | /* dso rip -> ip */ | 39 | /* dso rip -> ip */ |
40 | u64 (*unmap_ip)(struct map *, u64); | 40 | u64 (*unmap_ip)(struct map *, u64); |
41 | 41 | ||
42 | struct dso *dso; | 42 | struct dso *dso; |
43 | struct map_groups *groups; | 43 | struct map_groups *groups; |
44 | }; | 44 | }; |
45 | 45 | ||
46 | struct kmap { | 46 | struct kmap { |
47 | struct ref_reloc_sym *ref_reloc_sym; | 47 | struct ref_reloc_sym *ref_reloc_sym; |
48 | struct map_groups *kmaps; | 48 | struct map_groups *kmaps; |
49 | }; | 49 | }; |
50 | 50 | ||
51 | struct map_groups { | 51 | struct map_groups { |
52 | struct rb_root maps[MAP__NR_TYPES]; | 52 | struct rb_root maps[MAP__NR_TYPES]; |
53 | struct list_head removed_maps[MAP__NR_TYPES]; | 53 | struct list_head removed_maps[MAP__NR_TYPES]; |
54 | struct machine *machine; | 54 | struct machine *machine; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /* Native host kernel uses -1 as pid index in machine */ | 57 | /* Native host kernel uses -1 as pid index in machine */ |
58 | #define HOST_KERNEL_ID (-1) | 58 | #define HOST_KERNEL_ID (-1) |
59 | #define DEFAULT_GUEST_KERNEL_ID (0) | 59 | #define DEFAULT_GUEST_KERNEL_ID (0) |
60 | 60 | ||
61 | struct machine { | 61 | struct machine { |
62 | struct rb_node rb_node; | 62 | struct rb_node rb_node; |
63 | pid_t pid; | 63 | pid_t pid; |
64 | char *root_dir; | 64 | char *root_dir; |
65 | struct list_head user_dsos; | 65 | struct list_head user_dsos; |
66 | struct list_head kernel_dsos; | 66 | struct list_head kernel_dsos; |
67 | struct map_groups kmaps; | 67 | struct map_groups kmaps; |
68 | struct map *vmlinux_maps[MAP__NR_TYPES]; | 68 | struct map *vmlinux_maps[MAP__NR_TYPES]; |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static inline | 71 | static inline |
72 | struct map *machine__kernel_map(struct machine *self, enum map_type type) | 72 | struct map *machine__kernel_map(struct machine *self, enum map_type type) |
73 | { | 73 | { |
74 | return self->vmlinux_maps[type]; | 74 | return self->vmlinux_maps[type]; |
75 | } | 75 | } |
76 | 76 | ||
77 | static inline struct kmap *map__kmap(struct map *self) | 77 | static inline struct kmap *map__kmap(struct map *self) |
78 | { | 78 | { |
79 | return (struct kmap *)(self + 1); | 79 | return (struct kmap *)(self + 1); |
80 | } | 80 | } |
81 | 81 | ||
82 | static inline u64 map__map_ip(struct map *map, u64 ip) | 82 | static inline u64 map__map_ip(struct map *map, u64 ip) |
83 | { | 83 | { |
84 | return ip - map->start + map->pgoff; | 84 | return ip - map->start + map->pgoff; |
85 | } | 85 | } |
86 | 86 | ||
87 | static inline u64 map__unmap_ip(struct map *map, u64 ip) | 87 | static inline u64 map__unmap_ip(struct map *map, u64 ip) |
88 | { | 88 | { |
89 | return ip + map->start - map->pgoff; | 89 | return ip + map->start - map->pgoff; |
90 | } | 90 | } |
91 | 91 | ||
92 | static inline u64 identity__map_ip(struct map *map __used, u64 ip) | 92 | static inline u64 identity__map_ip(struct map *map __used, u64 ip) |
93 | { | 93 | { |
94 | return ip; | 94 | return ip; |
95 | } | 95 | } |
96 | 96 | ||
97 | 97 | ||
98 | /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ | 98 | /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ |
99 | u64 map__rip_2objdump(struct map *map, u64 rip); | 99 | u64 map__rip_2objdump(struct map *map, u64 rip); |
100 | u64 map__objdump_2ip(struct map *map, u64 addr); | 100 | u64 map__objdump_2ip(struct map *map, u64 addr); |
101 | 101 | ||
102 | struct symbol; | 102 | struct symbol; |
103 | 103 | ||
104 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | 104 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); |
105 | 105 | ||
106 | void map__init(struct map *self, enum map_type type, | 106 | void map__init(struct map *self, enum map_type type, |
107 | u64 start, u64 end, u64 pgoff, struct dso *dso); | 107 | u64 start, u64 end, u64 pgoff, struct dso *dso); |
108 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 108 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
109 | u64 pgoff, u32 pid, char *filename, | 109 | u64 pgoff, u32 pid, char *filename, |
110 | enum map_type type); | 110 | enum map_type type); |
111 | void map__delete(struct map *self); | 111 | void map__delete(struct map *self); |
112 | struct map *map__clone(struct map *self); | 112 | struct map *map__clone(struct map *self); |
113 | int map__overlap(struct map *l, struct map *r); | 113 | int map__overlap(struct map *l, struct map *r); |
114 | size_t map__fprintf(struct map *self, FILE *fp); | 114 | size_t map__fprintf(struct map *self, FILE *fp); |
115 | 115 | ||
116 | int map__load(struct map *self, symbol_filter_t filter); | 116 | int map__load(struct map *self, symbol_filter_t filter); |
117 | struct symbol *map__find_symbol(struct map *self, | 117 | struct symbol *map__find_symbol(struct map *self, |
118 | u64 addr, symbol_filter_t filter); | 118 | u64 addr, symbol_filter_t filter); |
119 | struct symbol *map__find_symbol_by_name(struct map *self, const char *name, | 119 | struct symbol *map__find_symbol_by_name(struct map *self, const char *name, |
120 | symbol_filter_t filter); | 120 | symbol_filter_t filter); |
121 | void map__fixup_start(struct map *self); | 121 | void map__fixup_start(struct map *self); |
122 | void map__fixup_end(struct map *self); | 122 | void map__fixup_end(struct map *self); |
123 | 123 | ||
124 | void map__reloc_vmlinux(struct map *self); | 124 | void map__reloc_vmlinux(struct map *self); |
125 | 125 | ||
126 | size_t __map_groups__fprintf_maps(struct map_groups *self, | 126 | size_t __map_groups__fprintf_maps(struct map_groups *self, |
127 | enum map_type type, int verbose, FILE *fp); | 127 | enum map_type type, int verbose, FILE *fp); |
128 | void maps__insert(struct rb_root *maps, struct map *map); | 128 | void maps__insert(struct rb_root *maps, struct map *map); |
129 | void maps__remove(struct rb_root *self, struct map *map); | 129 | void maps__remove(struct rb_root *self, struct map *map); |
130 | struct map *maps__find(struct rb_root *maps, u64 addr); | 130 | struct map *maps__find(struct rb_root *maps, u64 addr); |
131 | void map_groups__init(struct map_groups *self); | 131 | void map_groups__init(struct map_groups *self); |
132 | void map_groups__exit(struct map_groups *self); | 132 | void map_groups__exit(struct map_groups *self); |
133 | int map_groups__clone(struct map_groups *self, | 133 | int map_groups__clone(struct map_groups *self, |
134 | struct map_groups *parent, enum map_type type); | 134 | struct map_groups *parent, enum map_type type); |
135 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); | 135 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); |
136 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); | 136 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); |
137 | 137 | ||
138 | typedef void (*machine__process_t)(struct machine *self, void *data); | 138 | typedef void (*machine__process_t)(struct machine *self, void *data); |
139 | 139 | ||
140 | void machines__process(struct rb_root *self, machine__process_t process, void *data); | 140 | void machines__process(struct rb_root *self, machine__process_t process, void *data); |
141 | struct machine *machines__add(struct rb_root *self, pid_t pid, | 141 | struct machine *machines__add(struct rb_root *self, pid_t pid, |
142 | const char *root_dir); | 142 | const char *root_dir); |
143 | struct machine *machines__find_host(struct rb_root *self); | 143 | struct machine *machines__find_host(struct rb_root *self); |
144 | struct machine *machines__find(struct rb_root *self, pid_t pid); | 144 | struct machine *machines__find(struct rb_root *self, pid_t pid); |
145 | struct machine *machines__findnew(struct rb_root *self, pid_t pid); | 145 | struct machine *machines__findnew(struct rb_root *self, pid_t pid); |
146 | char *machine__mmap_name(struct machine *self, char *bf, size_t size); | 146 | char *machine__mmap_name(struct machine *self, char *bf, size_t size); |
147 | int machine__init(struct machine *self, const char *root_dir, pid_t pid); | 147 | int machine__init(struct machine *self, const char *root_dir, pid_t pid); |
148 | void machine__exit(struct machine *self); | 148 | void machine__exit(struct machine *self); |
149 | void machine__delete(struct machine *self); | 149 | void machine__delete(struct machine *self); |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * Default guest kernel is defined by parameter --guestkallsyms | 152 | * Default guest kernel is defined by parameter --guestkallsyms |
153 | * and --guestmodules | 153 | * and --guestmodules |
154 | */ | 154 | */ |
155 | static inline bool machine__is_default_guest(struct machine *self) | 155 | static inline bool machine__is_default_guest(struct machine *self) |
156 | { | 156 | { |
157 | return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false; | 157 | return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false; |
158 | } | 158 | } |
159 | 159 | ||
160 | static inline bool machine__is_host(struct machine *self) | 160 | static inline bool machine__is_host(struct machine *self) |
161 | { | 161 | { |
162 | return self ? self->pid == HOST_KERNEL_ID : false; | 162 | return self ? self->pid == HOST_KERNEL_ID : false; |
163 | } | 163 | } |
164 | 164 | ||
165 | static inline void map_groups__insert(struct map_groups *self, struct map *map) | 165 | static inline void map_groups__insert(struct map_groups *self, struct map *map) |
166 | { | 166 | { |
167 | maps__insert(&self->maps[map->type], map); | 167 | maps__insert(&self->maps[map->type], map); |
168 | map->groups = self; | 168 | map->groups = self; |
169 | } | 169 | } |
170 | 170 | ||
171 | static inline void map_groups__remove(struct map_groups *self, struct map *map) | 171 | static inline void map_groups__remove(struct map_groups *self, struct map *map) |
172 | { | 172 | { |
173 | maps__remove(&self->maps[map->type], map); | 173 | maps__remove(&self->maps[map->type], map); |
174 | } | 174 | } |
175 | 175 | ||
176 | static inline struct map *map_groups__find(struct map_groups *self, | 176 | static inline struct map *map_groups__find(struct map_groups *self, |
177 | enum map_type type, u64 addr) | 177 | enum map_type type, u64 addr) |
178 | { | 178 | { |
179 | return maps__find(&self->maps[type], addr); | 179 | return maps__find(&self->maps[type], addr); |
180 | } | 180 | } |
181 | 181 | ||
182 | struct symbol *map_groups__find_symbol(struct map_groups *self, | 182 | struct symbol *map_groups__find_symbol(struct map_groups *self, |
183 | enum map_type type, u64 addr, | 183 | enum map_type type, u64 addr, |
184 | struct map **mapp, | 184 | struct map **mapp, |
185 | symbol_filter_t filter); | 185 | symbol_filter_t filter); |
186 | 186 | ||
187 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, | 187 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, |
188 | enum map_type type, | 188 | enum map_type type, |
189 | const char *name, | 189 | const char *name, |
190 | struct map **mapp, | 190 | struct map **mapp, |
191 | symbol_filter_t filter); | 191 | symbol_filter_t filter); |
192 | 192 | ||
193 | static inline | 193 | static inline |
194 | struct symbol *machine__find_kernel_symbol(struct machine *self, | 194 | struct symbol *machine__find_kernel_symbol(struct machine *self, |
195 | enum map_type type, u64 addr, | 195 | enum map_type type, u64 addr, |
196 | struct map **mapp, | 196 | struct map **mapp, |
197 | symbol_filter_t filter) | 197 | symbol_filter_t filter) |
198 | { | 198 | { |
199 | return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter); | 199 | return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter); |
200 | } | 200 | } |
201 | 201 | ||
202 | static inline | 202 | static inline |
203 | struct symbol *machine__find_kernel_function(struct machine *self, u64 addr, | 203 | struct symbol *machine__find_kernel_function(struct machine *self, u64 addr, |
204 | struct map **mapp, | 204 | struct map **mapp, |
205 | symbol_filter_t filter) | 205 | symbol_filter_t filter) |
206 | { | 206 | { |
207 | return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter); | 207 | return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter); |
208 | } | 208 | } |
209 | 209 | ||
210 | static inline | 210 | static inline |
211 | struct symbol *map_groups__find_function_by_name(struct map_groups *self, | 211 | struct symbol *map_groups__find_function_by_name(struct map_groups *self, |
212 | const char *name, struct map **mapp, | 212 | const char *name, struct map **mapp, |
213 | symbol_filter_t filter) | 213 | symbol_filter_t filter) |
214 | { | 214 | { |
215 | return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); | 215 | return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); |
216 | } | 216 | } |
217 | 217 | ||
218 | static inline | ||
219 | struct symbol *machine__find_kernel_function_by_name(struct machine *self, | ||
220 | const char *name, | ||
221 | struct map **mapp, | ||
222 | symbol_filter_t filter) | ||
223 | { | ||
224 | return map_groups__find_function_by_name(&self->kmaps, name, mapp, | ||
225 | filter); | ||
226 | } | ||
227 | |||
218 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | 228 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, |
219 | int verbose, FILE *fp); | 229 | int verbose, FILE *fp); |
220 | 230 | ||
221 | struct map *map_groups__find_by_name(struct map_groups *self, | 231 | struct map *map_groups__find_by_name(struct map_groups *self, |
222 | enum map_type type, const char *name); | 232 | enum map_type type, const char *name); |
223 | struct map *machine__new_module(struct machine *self, u64 start, const char *filename); | 233 | struct map *machine__new_module(struct machine *self, u64 start, const char *filename); |
224 | 234 | ||
225 | void map_groups__flush(struct map_groups *self); | 235 | void map_groups__flush(struct map_groups *self); |
226 | 236 | ||
227 | #endif /* __PERF_MAP_H */ | 237 | #endif /* __PERF_MAP_H */ |
228 | 238 |
tools/perf/util/probe-event.c
1 | /* | 1 | /* |
2 | * probe-event.c : perf-probe definition to probe_events format converter | 2 | * probe-event.c : perf-probe definition to probe_events format converter |
3 | * | 3 | * |
4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> | 4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 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 | 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. | 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #define _GNU_SOURCE | 22 | #define _GNU_SOURCE |
23 | #include <sys/utsname.h> | 23 | #include <sys/utsname.h> |
24 | #include <sys/types.h> | 24 | #include <sys/types.h> |
25 | #include <sys/stat.h> | 25 | #include <sys/stat.h> |
26 | #include <fcntl.h> | 26 | #include <fcntl.h> |
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | #include <stdio.h> | 28 | #include <stdio.h> |
29 | #include <unistd.h> | 29 | #include <unistd.h> |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> |
31 | #include <string.h> | 31 | #include <string.h> |
32 | #include <stdarg.h> | 32 | #include <stdarg.h> |
33 | #include <limits.h> | 33 | #include <limits.h> |
34 | 34 | ||
35 | #undef _GNU_SOURCE | 35 | #undef _GNU_SOURCE |
36 | #include "util.h" | 36 | #include "util.h" |
37 | #include "event.h" | 37 | #include "event.h" |
38 | #include "string.h" | 38 | #include "string.h" |
39 | #include "strlist.h" | 39 | #include "strlist.h" |
40 | #include "debug.h" | 40 | #include "debug.h" |
41 | #include "cache.h" | 41 | #include "cache.h" |
42 | #include "color.h" | 42 | #include "color.h" |
43 | #include "symbol.h" | 43 | #include "symbol.h" |
44 | #include "thread.h" | 44 | #include "thread.h" |
45 | #include "debugfs.h" | 45 | #include "debugfs.h" |
46 | #include "trace-event.h" /* For __unused */ | 46 | #include "trace-event.h" /* For __unused */ |
47 | #include "probe-event.h" | 47 | #include "probe-event.h" |
48 | #include "probe-finder.h" | 48 | #include "probe-finder.h" |
49 | 49 | ||
50 | #define MAX_CMDLEN 256 | 50 | #define MAX_CMDLEN 256 |
51 | #define MAX_PROBE_ARGS 128 | 51 | #define MAX_PROBE_ARGS 128 |
52 | #define PERFPROBE_GROUP "probe" | 52 | #define PERFPROBE_GROUP "probe" |
53 | 53 | ||
54 | bool probe_event_dry_run; /* Dry run flag */ | 54 | bool probe_event_dry_run; /* Dry run flag */ |
55 | 55 | ||
56 | #define semantic_error(msg ...) pr_err("Semantic error :" msg) | 56 | #define semantic_error(msg ...) pr_err("Semantic error :" msg) |
57 | 57 | ||
58 | /* If there is no space to write, returns -E2BIG. */ | 58 | /* If there is no space to write, returns -E2BIG. */ |
59 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 59 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
60 | __attribute__((format(printf, 3, 4))); | 60 | __attribute__((format(printf, 3, 4))); |
61 | 61 | ||
62 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 62 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
63 | { | 63 | { |
64 | int ret; | 64 | int ret; |
65 | va_list ap; | 65 | va_list ap; |
66 | va_start(ap, format); | 66 | va_start(ap, format); |
67 | ret = vsnprintf(str, size, format, ap); | 67 | ret = vsnprintf(str, size, format, ap); |
68 | va_end(ap); | 68 | va_end(ap); |
69 | if (ret >= (int)size) | 69 | if (ret >= (int)size) |
70 | ret = -E2BIG; | 70 | ret = -E2BIG; |
71 | return ret; | 71 | return ret; |
72 | } | 72 | } |
73 | 73 | ||
74 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 74 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
75 | static struct machine machine; | 75 | static struct machine machine; |
76 | 76 | ||
77 | /* Initialize symbol maps and path of vmlinux */ | 77 | /* Initialize symbol maps and path of vmlinux/modules */ |
78 | static int init_vmlinux(void) | 78 | static int init_vmlinux(void) |
79 | { | 79 | { |
80 | struct dso *kernel; | ||
81 | int ret; | 80 | int ret; |
82 | 81 | ||
83 | symbol_conf.sort_by_name = true; | 82 | symbol_conf.sort_by_name = true; |
84 | if (symbol_conf.vmlinux_name == NULL) | 83 | if (symbol_conf.vmlinux_name == NULL) |
85 | symbol_conf.try_vmlinux_path = true; | 84 | symbol_conf.try_vmlinux_path = true; |
86 | else | 85 | else |
87 | pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); | 86 | pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); |
88 | ret = symbol__init(); | 87 | ret = symbol__init(); |
89 | if (ret < 0) { | 88 | if (ret < 0) { |
90 | pr_debug("Failed to init symbol map.\n"); | 89 | pr_debug("Failed to init symbol map.\n"); |
91 | goto out; | 90 | goto out; |
92 | } | 91 | } |
93 | 92 | ||
94 | ret = machine__init(&machine, "/", 0); | 93 | ret = machine__init(&machine, "", HOST_KERNEL_ID); |
95 | if (ret < 0) | 94 | if (ret < 0) |
96 | goto out; | 95 | goto out; |
97 | 96 | ||
98 | kernel = dso__new_kernel(symbol_conf.vmlinux_name); | 97 | if (machine__create_kernel_maps(&machine) < 0) { |
99 | if (kernel == NULL) | 98 | pr_debug("machine__create_kernel_maps "); |
100 | die("Failed to create kernel dso."); | 99 | goto out; |
101 | 100 | } | |
102 | ret = __machine__create_kernel_maps(&machine, kernel); | ||
103 | if (ret < 0) | ||
104 | pr_debug("Failed to create kernel maps.\n"); | ||
105 | |||
106 | out: | 101 | out: |
107 | if (ret < 0) | 102 | if (ret < 0) |
108 | pr_warning("Failed to init vmlinux path.\n"); | 103 | pr_warning("Failed to init vmlinux path.\n"); |
109 | return ret; | 104 | return ret; |
110 | } | 105 | } |
111 | 106 | ||
107 | static struct symbol *__find_kernel_function_by_name(const char *name, | ||
108 | struct map **mapp) | ||
109 | { | ||
110 | return machine__find_kernel_function_by_name(&machine, name, mapp, | ||
111 | NULL); | ||
112 | } | ||
113 | |||
114 | const char *kernel_get_module_path(const char *module) | ||
115 | { | ||
116 | struct dso *dso; | ||
117 | |||
118 | if (module) { | ||
119 | list_for_each_entry(dso, &machine.kernel_dsos, node) { | ||
120 | if (strncmp(dso->short_name + 1, module, | ||
121 | dso->short_name_len - 2) == 0) | ||
122 | goto found; | ||
123 | } | ||
124 | pr_debug("Failed to find module %s.\n", module); | ||
125 | return NULL; | ||
126 | } else { | ||
127 | dso = machine.vmlinux_maps[MAP__FUNCTION]->dso; | ||
128 | if (dso__load_vmlinux_path(dso, | ||
129 | machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { | ||
130 | pr_debug("Failed to load kernel map.\n"); | ||
131 | return NULL; | ||
132 | } | ||
133 | } | ||
134 | found: | ||
135 | return dso->long_name; | ||
136 | } | ||
137 | |||
112 | #ifdef DWARF_SUPPORT | 138 | #ifdef DWARF_SUPPORT |
113 | static int open_vmlinux(void) | 139 | static int open_vmlinux(const char *module) |
114 | { | 140 | { |
115 | if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { | 141 | const char *path = kernel_get_module_path(module); |
116 | pr_debug("Failed to load kernel map.\n"); | 142 | if (!path) { |
117 | return -EINVAL; | 143 | pr_err("Failed to find path of %s module", module ?: "kernel"); |
144 | return -ENOENT; | ||
118 | } | 145 | } |
119 | pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name); | 146 | pr_debug("Try to open %s\n", path); |
120 | return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); | 147 | return open(path, O_RDONLY); |
121 | } | 148 | } |
122 | 149 | ||
123 | /* | 150 | /* |
124 | * Convert trace point to probe point with debuginfo | 151 | * Convert trace point to probe point with debuginfo |
125 | * Currently only handles kprobes. | 152 | * Currently only handles kprobes. |
126 | */ | 153 | */ |
127 | static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | 154 | static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, |
128 | struct perf_probe_point *pp) | 155 | struct perf_probe_point *pp) |
129 | { | 156 | { |
130 | struct symbol *sym; | 157 | struct symbol *sym; |
131 | int fd, ret = -ENOENT; | 158 | struct map *map; |
159 | u64 addr; | ||
160 | int ret = -ENOENT; | ||
132 | 161 | ||
133 | sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], | 162 | sym = __find_kernel_function_by_name(tp->symbol, &map); |
134 | tp->symbol, NULL); | ||
135 | if (sym) { | 163 | if (sym) { |
136 | fd = open_vmlinux(); | 164 | addr = map->unmap_ip(map, sym->start + tp->offset); |
137 | if (fd >= 0) { | 165 | pr_debug("try to find %s+%ld@%llx\n", tp->symbol, |
138 | ret = find_perf_probe_point(fd, | 166 | tp->offset, addr); |
139 | sym->start + tp->offset, pp); | 167 | ret = find_perf_probe_point((unsigned long)addr, pp); |
140 | close(fd); | ||
141 | } | ||
142 | } | 168 | } |
143 | if (ret <= 0) { | 169 | if (ret <= 0) { |
144 | pr_debug("Failed to find corresponding probes from " | 170 | pr_debug("Failed to find corresponding probes from " |
145 | "debuginfo. Use kprobe event information.\n"); | 171 | "debuginfo. Use kprobe event information.\n"); |
146 | pp->function = strdup(tp->symbol); | 172 | pp->function = strdup(tp->symbol); |
147 | if (pp->function == NULL) | 173 | if (pp->function == NULL) |
148 | return -ENOMEM; | 174 | return -ENOMEM; |
149 | pp->offset = tp->offset; | 175 | pp->offset = tp->offset; |
150 | } | 176 | } |
151 | pp->retprobe = tp->retprobe; | 177 | pp->retprobe = tp->retprobe; |
152 | 178 | ||
153 | return 0; | 179 | return 0; |
154 | } | 180 | } |
155 | 181 | ||
156 | /* Try to find perf_probe_event with debuginfo */ | 182 | /* Try to find perf_probe_event with debuginfo */ |
157 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 183 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
158 | struct probe_trace_event **tevs, | 184 | struct probe_trace_event **tevs, |
159 | int max_tevs) | 185 | int max_tevs, const char *module) |
160 | { | 186 | { |
161 | bool need_dwarf = perf_probe_event_need_dwarf(pev); | 187 | bool need_dwarf = perf_probe_event_need_dwarf(pev); |
162 | int fd, ntevs; | 188 | int fd, ntevs; |
163 | 189 | ||
164 | fd = open_vmlinux(); | 190 | fd = open_vmlinux(module); |
165 | if (fd < 0) { | 191 | if (fd < 0) { |
166 | if (need_dwarf) { | 192 | if (need_dwarf) { |
167 | pr_warning("Failed to open debuginfo file.\n"); | 193 | pr_warning("Failed to open debuginfo file.\n"); |
168 | return fd; | 194 | return fd; |
169 | } | 195 | } |
170 | pr_debug("Could not open vmlinux. Try to use symbols.\n"); | 196 | pr_debug("Could not open vmlinux. Try to use symbols.\n"); |
171 | return 0; | 197 | return 0; |
172 | } | 198 | } |
173 | 199 | ||
174 | /* Searching trace events corresponding to probe event */ | 200 | /* Searching trace events corresponding to probe event */ |
175 | ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); | 201 | ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); |
176 | close(fd); | 202 | close(fd); |
177 | 203 | ||
178 | if (ntevs > 0) { /* Succeeded to find trace events */ | 204 | if (ntevs > 0) { /* Succeeded to find trace events */ |
179 | pr_debug("find %d probe_trace_events.\n", ntevs); | 205 | pr_debug("find %d probe_trace_events.\n", ntevs); |
180 | return ntevs; | 206 | return ntevs; |
181 | } | 207 | } |
182 | 208 | ||
183 | if (ntevs == 0) { /* No error but failed to find probe point. */ | 209 | if (ntevs == 0) { /* No error but failed to find probe point. */ |
184 | pr_warning("Probe point '%s' not found.\n", | 210 | pr_warning("Probe point '%s' not found.\n", |
185 | synthesize_perf_probe_point(&pev->point)); | 211 | synthesize_perf_probe_point(&pev->point)); |
186 | return -ENOENT; | 212 | return -ENOENT; |
187 | } | 213 | } |
188 | /* Error path : ntevs < 0 */ | 214 | /* Error path : ntevs < 0 */ |
189 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); | 215 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); |
190 | if (ntevs == -EBADF) { | 216 | if (ntevs == -EBADF) { |
191 | pr_warning("Warning: No dwarf info found in the vmlinux - " | 217 | pr_warning("Warning: No dwarf info found in the vmlinux - " |
192 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); | 218 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); |
193 | if (!need_dwarf) { | 219 | if (!need_dwarf) { |
194 | pr_debug("Trying to use symbols.\nn"); | 220 | pr_debug("Trying to use symbols.\nn"); |
195 | return 0; | 221 | return 0; |
196 | } | 222 | } |
197 | } | 223 | } |
198 | return ntevs; | 224 | return ntevs; |
199 | } | 225 | } |
200 | 226 | ||
201 | /* | 227 | /* |
202 | * Find a src file from a DWARF tag path. Prepend optional source path prefix | 228 | * Find a src file from a DWARF tag path. Prepend optional source path prefix |
203 | * and chop off leading directories that do not exist. Result is passed back as | 229 | * and chop off leading directories that do not exist. Result is passed back as |
204 | * a newly allocated path on success. | 230 | * a newly allocated path on success. |
205 | * Return 0 if file was found and readable, -errno otherwise. | 231 | * Return 0 if file was found and readable, -errno otherwise. |
206 | */ | 232 | */ |
207 | static int get_real_path(const char *raw_path, const char *comp_dir, | 233 | static int get_real_path(const char *raw_path, const char *comp_dir, |
208 | char **new_path) | 234 | char **new_path) |
209 | { | 235 | { |
210 | const char *prefix = symbol_conf.source_prefix; | 236 | const char *prefix = symbol_conf.source_prefix; |
211 | 237 | ||
212 | if (!prefix) { | 238 | if (!prefix) { |
213 | if (raw_path[0] != '/' && comp_dir) | 239 | if (raw_path[0] != '/' && comp_dir) |
214 | /* If not an absolute path, try to use comp_dir */ | 240 | /* If not an absolute path, try to use comp_dir */ |
215 | prefix = comp_dir; | 241 | prefix = comp_dir; |
216 | else { | 242 | else { |
217 | if (access(raw_path, R_OK) == 0) { | 243 | if (access(raw_path, R_OK) == 0) { |
218 | *new_path = strdup(raw_path); | 244 | *new_path = strdup(raw_path); |
219 | return 0; | 245 | return 0; |
220 | } else | 246 | } else |
221 | return -errno; | 247 | return -errno; |
222 | } | 248 | } |
223 | } | 249 | } |
224 | 250 | ||
225 | *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); | 251 | *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); |
226 | if (!*new_path) | 252 | if (!*new_path) |
227 | return -ENOMEM; | 253 | return -ENOMEM; |
228 | 254 | ||
229 | for (;;) { | 255 | for (;;) { |
230 | sprintf(*new_path, "%s/%s", prefix, raw_path); | 256 | sprintf(*new_path, "%s/%s", prefix, raw_path); |
231 | 257 | ||
232 | if (access(*new_path, R_OK) == 0) | 258 | if (access(*new_path, R_OK) == 0) |
233 | return 0; | 259 | return 0; |
234 | 260 | ||
235 | if (!symbol_conf.source_prefix) | 261 | if (!symbol_conf.source_prefix) |
236 | /* In case of searching comp_dir, don't retry */ | 262 | /* In case of searching comp_dir, don't retry */ |
237 | return -errno; | 263 | return -errno; |
238 | 264 | ||
239 | switch (errno) { | 265 | switch (errno) { |
240 | case ENAMETOOLONG: | 266 | case ENAMETOOLONG: |
241 | case ENOENT: | 267 | case ENOENT: |
242 | case EROFS: | 268 | case EROFS: |
243 | case EFAULT: | 269 | case EFAULT: |
244 | raw_path = strchr(++raw_path, '/'); | 270 | raw_path = strchr(++raw_path, '/'); |
245 | if (!raw_path) { | 271 | if (!raw_path) { |
246 | free(*new_path); | 272 | free(*new_path); |
247 | *new_path = NULL; | 273 | *new_path = NULL; |
248 | return -ENOENT; | 274 | return -ENOENT; |
249 | } | 275 | } |
250 | continue; | 276 | continue; |
251 | 277 | ||
252 | default: | 278 | default: |
253 | free(*new_path); | 279 | free(*new_path); |
254 | *new_path = NULL; | 280 | *new_path = NULL; |
255 | return -errno; | 281 | return -errno; |
256 | } | 282 | } |
257 | } | 283 | } |
258 | } | 284 | } |
259 | 285 | ||
260 | #define LINEBUF_SIZE 256 | 286 | #define LINEBUF_SIZE 256 |
261 | #define NR_ADDITIONAL_LINES 2 | 287 | #define NR_ADDITIONAL_LINES 2 |
262 | 288 | ||
263 | static int show_one_line(FILE *fp, int l, bool skip, bool show_num) | 289 | static int show_one_line(FILE *fp, int l, bool skip, bool show_num) |
264 | { | 290 | { |
265 | char buf[LINEBUF_SIZE]; | 291 | char buf[LINEBUF_SIZE]; |
266 | const char *color = PERF_COLOR_BLUE; | 292 | const char *color = PERF_COLOR_BLUE; |
267 | 293 | ||
268 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) | 294 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) |
269 | goto error; | 295 | goto error; |
270 | if (!skip) { | 296 | if (!skip) { |
271 | if (show_num) | 297 | if (show_num) |
272 | fprintf(stdout, "%7d %s", l, buf); | 298 | fprintf(stdout, "%7d %s", l, buf); |
273 | else | 299 | else |
274 | color_fprintf(stdout, color, " %s", buf); | 300 | color_fprintf(stdout, color, " %s", buf); |
275 | } | 301 | } |
276 | 302 | ||
277 | while (strlen(buf) == LINEBUF_SIZE - 1 && | 303 | while (strlen(buf) == LINEBUF_SIZE - 1 && |
278 | buf[LINEBUF_SIZE - 2] != '\n') { | 304 | buf[LINEBUF_SIZE - 2] != '\n') { |
279 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) | 305 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) |
280 | goto error; | 306 | goto error; |
281 | if (!skip) { | 307 | if (!skip) { |
282 | if (show_num) | 308 | if (show_num) |
283 | fprintf(stdout, "%s", buf); | 309 | fprintf(stdout, "%s", buf); |
284 | else | 310 | else |
285 | color_fprintf(stdout, color, "%s", buf); | 311 | color_fprintf(stdout, color, "%s", buf); |
286 | } | 312 | } |
287 | } | 313 | } |
288 | 314 | ||
289 | return 0; | 315 | return 0; |
290 | error: | 316 | error: |
291 | if (feof(fp)) | 317 | if (feof(fp)) |
292 | pr_warning("Source file is shorter than expected.\n"); | 318 | pr_warning("Source file is shorter than expected.\n"); |
293 | else | 319 | else |
294 | pr_warning("File read error: %s\n", strerror(errno)); | 320 | pr_warning("File read error: %s\n", strerror(errno)); |
295 | 321 | ||
296 | return -1; | 322 | return -1; |
297 | } | 323 | } |
298 | 324 | ||
299 | /* | 325 | /* |
300 | * Show line-range always requires debuginfo to find source file and | 326 | * Show line-range always requires debuginfo to find source file and |
301 | * line number. | 327 | * line number. |
302 | */ | 328 | */ |
303 | int show_line_range(struct line_range *lr) | 329 | int show_line_range(struct line_range *lr, const char *module) |
304 | { | 330 | { |
305 | int l = 1; | 331 | int l = 1; |
306 | struct line_node *ln; | 332 | struct line_node *ln; |
307 | FILE *fp; | 333 | FILE *fp; |
308 | int fd, ret; | 334 | int fd, ret; |
309 | char *tmp; | 335 | char *tmp; |
310 | 336 | ||
311 | /* Search a line range */ | 337 | /* Search a line range */ |
312 | ret = init_vmlinux(); | 338 | ret = init_vmlinux(); |
313 | if (ret < 0) | 339 | if (ret < 0) |
314 | return ret; | 340 | return ret; |
315 | 341 | ||
316 | fd = open_vmlinux(); | 342 | fd = open_vmlinux(module); |
317 | if (fd < 0) { | 343 | if (fd < 0) { |
318 | pr_warning("Failed to open debuginfo file.\n"); | 344 | pr_warning("Failed to open debuginfo file.\n"); |
319 | return fd; | 345 | return fd; |
320 | } | 346 | } |
321 | 347 | ||
322 | ret = find_line_range(fd, lr); | 348 | ret = find_line_range(fd, lr); |
323 | close(fd); | 349 | close(fd); |
324 | if (ret == 0) { | 350 | if (ret == 0) { |
325 | pr_warning("Specified source line is not found.\n"); | 351 | pr_warning("Specified source line is not found.\n"); |
326 | return -ENOENT; | 352 | return -ENOENT; |
327 | } else if (ret < 0) { | 353 | } else if (ret < 0) { |
328 | pr_warning("Debuginfo analysis failed. (%d)\n", ret); | 354 | pr_warning("Debuginfo analysis failed. (%d)\n", ret); |
329 | return ret; | 355 | return ret; |
330 | } | 356 | } |
331 | 357 | ||
332 | /* Convert source file path */ | 358 | /* Convert source file path */ |
333 | tmp = lr->path; | 359 | tmp = lr->path; |
334 | ret = get_real_path(tmp, lr->comp_dir, &lr->path); | 360 | ret = get_real_path(tmp, lr->comp_dir, &lr->path); |
335 | free(tmp); /* Free old path */ | 361 | free(tmp); /* Free old path */ |
336 | if (ret < 0) { | 362 | if (ret < 0) { |
337 | pr_warning("Failed to find source file. (%d)\n", ret); | 363 | pr_warning("Failed to find source file. (%d)\n", ret); |
338 | return ret; | 364 | return ret; |
339 | } | 365 | } |
340 | 366 | ||
341 | setup_pager(); | 367 | setup_pager(); |
342 | 368 | ||
343 | if (lr->function) | 369 | if (lr->function) |
344 | fprintf(stdout, "<%s:%d>\n", lr->function, | 370 | fprintf(stdout, "<%s:%d>\n", lr->function, |
345 | lr->start - lr->offset); | 371 | lr->start - lr->offset); |
346 | else | 372 | else |
347 | fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); | 373 | fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); |
348 | 374 | ||
349 | fp = fopen(lr->path, "r"); | 375 | fp = fopen(lr->path, "r"); |
350 | if (fp == NULL) { | 376 | if (fp == NULL) { |
351 | pr_warning("Failed to open %s: %s\n", lr->path, | 377 | pr_warning("Failed to open %s: %s\n", lr->path, |
352 | strerror(errno)); | 378 | strerror(errno)); |
353 | return -errno; | 379 | return -errno; |
354 | } | 380 | } |
355 | /* Skip to starting line number */ | 381 | /* Skip to starting line number */ |
356 | while (l < lr->start && ret >= 0) | 382 | while (l < lr->start && ret >= 0) |
357 | ret = show_one_line(fp, l++, true, false); | 383 | ret = show_one_line(fp, l++, true, false); |
358 | if (ret < 0) | 384 | if (ret < 0) |
359 | goto end; | 385 | goto end; |
360 | 386 | ||
361 | list_for_each_entry(ln, &lr->line_list, list) { | 387 | list_for_each_entry(ln, &lr->line_list, list) { |
362 | while (ln->line > l && ret >= 0) | 388 | while (ln->line > l && ret >= 0) |
363 | ret = show_one_line(fp, (l++) - lr->offset, | 389 | ret = show_one_line(fp, (l++) - lr->offset, |
364 | false, false); | 390 | false, false); |
365 | if (ret >= 0) | 391 | if (ret >= 0) |
366 | ret = show_one_line(fp, (l++) - lr->offset, | 392 | ret = show_one_line(fp, (l++) - lr->offset, |
367 | false, true); | 393 | false, true); |
368 | if (ret < 0) | 394 | if (ret < 0) |
369 | goto end; | 395 | goto end; |
370 | } | 396 | } |
371 | 397 | ||
372 | if (lr->end == INT_MAX) | 398 | if (lr->end == INT_MAX) |
373 | lr->end = l + NR_ADDITIONAL_LINES; | 399 | lr->end = l + NR_ADDITIONAL_LINES; |
374 | while (l <= lr->end && !feof(fp) && ret >= 0) | 400 | while (l <= lr->end && !feof(fp) && ret >= 0) |
375 | ret = show_one_line(fp, (l++) - lr->offset, false, false); | 401 | ret = show_one_line(fp, (l++) - lr->offset, false, false); |
376 | end: | 402 | end: |
377 | fclose(fp); | 403 | fclose(fp); |
378 | return ret; | 404 | return ret; |
379 | } | 405 | } |
380 | 406 | ||
381 | static int show_available_vars_at(int fd, struct perf_probe_event *pev, | 407 | static int show_available_vars_at(int fd, struct perf_probe_event *pev, |
382 | int max_vls, bool externs) | 408 | int max_vls, bool externs) |
383 | { | 409 | { |
384 | char *buf; | 410 | char *buf; |
385 | int ret, i; | 411 | int ret, i; |
386 | struct str_node *node; | 412 | struct str_node *node; |
387 | struct variable_list *vls = NULL, *vl; | 413 | struct variable_list *vls = NULL, *vl; |
388 | 414 | ||
389 | buf = synthesize_perf_probe_point(&pev->point); | 415 | buf = synthesize_perf_probe_point(&pev->point); |
390 | if (!buf) | 416 | if (!buf) |
391 | return -EINVAL; | 417 | return -EINVAL; |
392 | pr_debug("Searching variables at %s\n", buf); | 418 | pr_debug("Searching variables at %s\n", buf); |
393 | 419 | ||
394 | ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); | 420 | ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); |
395 | if (ret > 0) { | 421 | if (ret > 0) { |
396 | /* Some variables were found */ | 422 | /* Some variables were found */ |
397 | fprintf(stdout, "Available variables at %s\n", buf); | 423 | fprintf(stdout, "Available variables at %s\n", buf); |
398 | for (i = 0; i < ret; i++) { | 424 | for (i = 0; i < ret; i++) { |
399 | vl = &vls[i]; | 425 | vl = &vls[i]; |
400 | /* | 426 | /* |
401 | * A probe point might be converted to | 427 | * A probe point might be converted to |
402 | * several trace points. | 428 | * several trace points. |
403 | */ | 429 | */ |
404 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, | 430 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, |
405 | vl->point.offset); | 431 | vl->point.offset); |
406 | free(vl->point.symbol); | 432 | free(vl->point.symbol); |
407 | if (vl->vars) { | 433 | if (vl->vars) { |
408 | strlist__for_each(node, vl->vars) | 434 | strlist__for_each(node, vl->vars) |
409 | fprintf(stdout, "\t\t%s\n", node->s); | 435 | fprintf(stdout, "\t\t%s\n", node->s); |
410 | strlist__delete(vl->vars); | 436 | strlist__delete(vl->vars); |
411 | } else | 437 | } else |
412 | fprintf(stdout, "(No variables)\n"); | 438 | fprintf(stdout, "(No variables)\n"); |
413 | } | 439 | } |
414 | free(vls); | 440 | free(vls); |
415 | } else | 441 | } else |
416 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); | 442 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); |
417 | 443 | ||
418 | free(buf); | 444 | free(buf); |
419 | return ret; | 445 | return ret; |
420 | } | 446 | } |
421 | 447 | ||
422 | /* Show available variables on given probe point */ | 448 | /* Show available variables on given probe point */ |
423 | int show_available_vars(struct perf_probe_event *pevs, int npevs, | 449 | int show_available_vars(struct perf_probe_event *pevs, int npevs, |
424 | int max_vls, bool externs) | 450 | int max_vls, const char *module, bool externs) |
425 | { | 451 | { |
426 | int i, fd, ret = 0; | 452 | int i, fd, ret = 0; |
427 | 453 | ||
428 | ret = init_vmlinux(); | 454 | ret = init_vmlinux(); |
429 | if (ret < 0) | 455 | if (ret < 0) |
430 | return ret; | 456 | return ret; |
431 | 457 | ||
432 | fd = open_vmlinux(); | 458 | fd = open_vmlinux(module); |
433 | if (fd < 0) { | 459 | if (fd < 0) { |
434 | pr_warning("Failed to open debuginfo file.\n"); | 460 | pr_warning("Failed to open debuginfo file.\n"); |
435 | return fd; | 461 | return fd; |
436 | } | 462 | } |
437 | 463 | ||
438 | setup_pager(); | 464 | setup_pager(); |
439 | 465 | ||
440 | for (i = 0; i < npevs && ret >= 0; i++) | 466 | for (i = 0; i < npevs && ret >= 0; i++) |
441 | ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); | 467 | ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); |
442 | 468 | ||
443 | close(fd); | 469 | close(fd); |
444 | return ret; | 470 | return ret; |
445 | } | 471 | } |
446 | 472 | ||
447 | #else /* !DWARF_SUPPORT */ | 473 | #else /* !DWARF_SUPPORT */ |
448 | 474 | ||
449 | static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | 475 | static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, |
450 | struct perf_probe_point *pp) | 476 | struct perf_probe_point *pp) |
451 | { | 477 | { |
478 | struct symbol *sym; | ||
479 | |||
480 | sym = __find_kernel_function_by_name(tp->symbol, NULL); | ||
481 | if (!sym) { | ||
482 | pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); | ||
483 | return -ENOENT; | ||
484 | } | ||
452 | pp->function = strdup(tp->symbol); | 485 | pp->function = strdup(tp->symbol); |
453 | if (pp->function == NULL) | 486 | if (pp->function == NULL) |
454 | return -ENOMEM; | 487 | return -ENOMEM; |
455 | pp->offset = tp->offset; | 488 | pp->offset = tp->offset; |
456 | pp->retprobe = tp->retprobe; | 489 | pp->retprobe = tp->retprobe; |
457 | 490 | ||
458 | return 0; | 491 | return 0; |
459 | } | 492 | } |
460 | 493 | ||
461 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 494 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
462 | struct probe_trace_event **tevs __unused, | 495 | struct probe_trace_event **tevs __unused, |
463 | int max_tevs __unused) | 496 | int max_tevs __unused, const char *mod __unused) |
464 | { | 497 | { |
465 | if (perf_probe_event_need_dwarf(pev)) { | 498 | if (perf_probe_event_need_dwarf(pev)) { |
466 | pr_warning("Debuginfo-analysis is not supported.\n"); | 499 | pr_warning("Debuginfo-analysis is not supported.\n"); |
467 | return -ENOSYS; | 500 | return -ENOSYS; |
468 | } | 501 | } |
469 | return 0; | 502 | return 0; |
470 | } | 503 | } |
471 | 504 | ||
472 | int show_line_range(struct line_range *lr __unused) | 505 | int show_line_range(struct line_range *lr __unused, const char *module __unused) |
473 | { | 506 | { |
474 | pr_warning("Debuginfo-analysis is not supported.\n"); | 507 | pr_warning("Debuginfo-analysis is not supported.\n"); |
475 | return -ENOSYS; | 508 | return -ENOSYS; |
476 | } | 509 | } |
477 | 510 | ||
478 | int show_available_vars(struct perf_probe_event *pevs __unused, | 511 | int show_available_vars(struct perf_probe_event *pevs __unused, |
479 | int npevs __unused, int max_probe_points __unused) | 512 | int npevs __unused, int max_vls __unused, |
513 | const char *module __unused, bool externs __unused) | ||
480 | { | 514 | { |
481 | pr_warning("Debuginfo-analysis is not supported.\n"); | 515 | pr_warning("Debuginfo-analysis is not supported.\n"); |
482 | return -ENOSYS; | 516 | return -ENOSYS; |
483 | } | 517 | } |
484 | #endif | 518 | #endif |
485 | 519 | ||
486 | int parse_line_range_desc(const char *arg, struct line_range *lr) | 520 | int parse_line_range_desc(const char *arg, struct line_range *lr) |
487 | { | 521 | { |
488 | const char *ptr; | 522 | const char *ptr; |
489 | char *tmp; | 523 | char *tmp; |
490 | /* | 524 | /* |
491 | * <Syntax> | 525 | * <Syntax> |
492 | * SRC:SLN[+NUM|-ELN] | 526 | * SRC:SLN[+NUM|-ELN] |
493 | * FUNC[:SLN[+NUM|-ELN]] | 527 | * FUNC[:SLN[+NUM|-ELN]] |
494 | */ | 528 | */ |
495 | ptr = strchr(arg, ':'); | 529 | ptr = strchr(arg, ':'); |
496 | if (ptr) { | 530 | if (ptr) { |
497 | lr->start = (int)strtoul(ptr + 1, &tmp, 0); | 531 | lr->start = (int)strtoul(ptr + 1, &tmp, 0); |
498 | if (*tmp == '+') { | 532 | if (*tmp == '+') { |
499 | lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0); | 533 | lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0); |
500 | lr->end--; /* | 534 | lr->end--; /* |
501 | * Adjust the number of lines here. | 535 | * Adjust the number of lines here. |
502 | * If the number of lines == 1, the | 536 | * If the number of lines == 1, the |
503 | * the end of line should be equal to | 537 | * the end of line should be equal to |
504 | * the start of line. | 538 | * the start of line. |
505 | */ | 539 | */ |
506 | } else if (*tmp == '-') | 540 | } else if (*tmp == '-') |
507 | lr->end = (int)strtoul(tmp + 1, &tmp, 0); | 541 | lr->end = (int)strtoul(tmp + 1, &tmp, 0); |
508 | else | 542 | else |
509 | lr->end = INT_MAX; | 543 | lr->end = INT_MAX; |
510 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); | 544 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); |
511 | if (lr->start > lr->end) { | 545 | if (lr->start > lr->end) { |
512 | semantic_error("Start line must be smaller" | 546 | semantic_error("Start line must be smaller" |
513 | " than end line.\n"); | 547 | " than end line.\n"); |
514 | return -EINVAL; | 548 | return -EINVAL; |
515 | } | 549 | } |
516 | if (*tmp != '\0') { | 550 | if (*tmp != '\0') { |
517 | semantic_error("Tailing with invalid character '%d'.\n", | 551 | semantic_error("Tailing with invalid character '%d'.\n", |
518 | *tmp); | 552 | *tmp); |
519 | return -EINVAL; | 553 | return -EINVAL; |
520 | } | 554 | } |
521 | tmp = strndup(arg, (ptr - arg)); | 555 | tmp = strndup(arg, (ptr - arg)); |
522 | } else { | 556 | } else { |
523 | tmp = strdup(arg); | 557 | tmp = strdup(arg); |
524 | lr->end = INT_MAX; | 558 | lr->end = INT_MAX; |
525 | } | 559 | } |
526 | 560 | ||
527 | if (tmp == NULL) | 561 | if (tmp == NULL) |
528 | return -ENOMEM; | 562 | return -ENOMEM; |
529 | 563 | ||
530 | if (strchr(tmp, '.')) | 564 | if (strchr(tmp, '.')) |
531 | lr->file = tmp; | 565 | lr->file = tmp; |
532 | else | 566 | else |
533 | lr->function = tmp; | 567 | lr->function = tmp; |
534 | 568 | ||
535 | return 0; | 569 | return 0; |
536 | } | 570 | } |
537 | 571 | ||
538 | /* Check the name is good for event/group */ | 572 | /* Check the name is good for event/group */ |
539 | static bool check_event_name(const char *name) | 573 | static bool check_event_name(const char *name) |
540 | { | 574 | { |
541 | if (!isalpha(*name) && *name != '_') | 575 | if (!isalpha(*name) && *name != '_') |
542 | return false; | 576 | return false; |
543 | while (*++name != '\0') { | 577 | while (*++name != '\0') { |
544 | if (!isalpha(*name) && !isdigit(*name) && *name != '_') | 578 | if (!isalpha(*name) && !isdigit(*name) && *name != '_') |
545 | return false; | 579 | return false; |
546 | } | 580 | } |
547 | return true; | 581 | return true; |
548 | } | 582 | } |
549 | 583 | ||
550 | /* Parse probepoint definition. */ | 584 | /* Parse probepoint definition. */ |
551 | static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | 585 | static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) |
552 | { | 586 | { |
553 | struct perf_probe_point *pp = &pev->point; | 587 | struct perf_probe_point *pp = &pev->point; |
554 | char *ptr, *tmp; | 588 | char *ptr, *tmp; |
555 | char c, nc = 0; | 589 | char c, nc = 0; |
556 | /* | 590 | /* |
557 | * <Syntax> | 591 | * <Syntax> |
558 | * perf probe [EVENT=]SRC[:LN|;PTN] | 592 | * perf probe [EVENT=]SRC[:LN|;PTN] |
559 | * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] | 593 | * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] |
560 | * | 594 | * |
561 | * TODO:Group name support | 595 | * TODO:Group name support |
562 | */ | 596 | */ |
563 | 597 | ||
564 | ptr = strpbrk(arg, ";=@+%"); | 598 | ptr = strpbrk(arg, ";=@+%"); |
565 | if (ptr && *ptr == '=') { /* Event name */ | 599 | if (ptr && *ptr == '=') { /* Event name */ |
566 | *ptr = '\0'; | 600 | *ptr = '\0'; |
567 | tmp = ptr + 1; | 601 | tmp = ptr + 1; |
568 | if (strchr(arg, ':')) { | 602 | if (strchr(arg, ':')) { |
569 | semantic_error("Group name is not supported yet.\n"); | 603 | semantic_error("Group name is not supported yet.\n"); |
570 | return -ENOTSUP; | 604 | return -ENOTSUP; |
571 | } | 605 | } |
572 | if (!check_event_name(arg)) { | 606 | if (!check_event_name(arg)) { |
573 | semantic_error("%s is bad for event name -it must " | 607 | semantic_error("%s is bad for event name -it must " |
574 | "follow C symbol-naming rule.\n", arg); | 608 | "follow C symbol-naming rule.\n", arg); |
575 | return -EINVAL; | 609 | return -EINVAL; |
576 | } | 610 | } |
577 | pev->event = strdup(arg); | 611 | pev->event = strdup(arg); |
578 | if (pev->event == NULL) | 612 | if (pev->event == NULL) |
579 | return -ENOMEM; | 613 | return -ENOMEM; |
580 | pev->group = NULL; | 614 | pev->group = NULL; |
581 | arg = tmp; | 615 | arg = tmp; |
582 | } | 616 | } |
583 | 617 | ||
584 | ptr = strpbrk(arg, ";:+@%"); | 618 | ptr = strpbrk(arg, ";:+@%"); |
585 | if (ptr) { | 619 | if (ptr) { |
586 | nc = *ptr; | 620 | nc = *ptr; |
587 | *ptr++ = '\0'; | 621 | *ptr++ = '\0'; |
588 | } | 622 | } |
589 | 623 | ||
590 | tmp = strdup(arg); | 624 | tmp = strdup(arg); |
591 | if (tmp == NULL) | 625 | if (tmp == NULL) |
592 | return -ENOMEM; | 626 | return -ENOMEM; |
593 | 627 | ||
594 | /* Check arg is function or file and copy it */ | 628 | /* Check arg is function or file and copy it */ |
595 | if (strchr(tmp, '.')) /* File */ | 629 | if (strchr(tmp, '.')) /* File */ |
596 | pp->file = tmp; | 630 | pp->file = tmp; |
597 | else /* Function */ | 631 | else /* Function */ |
598 | pp->function = tmp; | 632 | pp->function = tmp; |
599 | 633 | ||
600 | /* Parse other options */ | 634 | /* Parse other options */ |
601 | while (ptr) { | 635 | while (ptr) { |
602 | arg = ptr; | 636 | arg = ptr; |
603 | c = nc; | 637 | c = nc; |
604 | if (c == ';') { /* Lazy pattern must be the last part */ | 638 | if (c == ';') { /* Lazy pattern must be the last part */ |
605 | pp->lazy_line = strdup(arg); | 639 | pp->lazy_line = strdup(arg); |
606 | if (pp->lazy_line == NULL) | 640 | if (pp->lazy_line == NULL) |
607 | return -ENOMEM; | 641 | return -ENOMEM; |
608 | break; | 642 | break; |
609 | } | 643 | } |
610 | ptr = strpbrk(arg, ";:+@%"); | 644 | ptr = strpbrk(arg, ";:+@%"); |
611 | if (ptr) { | 645 | if (ptr) { |
612 | nc = *ptr; | 646 | nc = *ptr; |
613 | *ptr++ = '\0'; | 647 | *ptr++ = '\0'; |
614 | } | 648 | } |
615 | switch (c) { | 649 | switch (c) { |
616 | case ':': /* Line number */ | 650 | case ':': /* Line number */ |
617 | pp->line = strtoul(arg, &tmp, 0); | 651 | pp->line = strtoul(arg, &tmp, 0); |
618 | if (*tmp != '\0') { | 652 | if (*tmp != '\0') { |
619 | semantic_error("There is non-digit char" | 653 | semantic_error("There is non-digit char" |
620 | " in line number.\n"); | 654 | " in line number.\n"); |
621 | return -EINVAL; | 655 | return -EINVAL; |
622 | } | 656 | } |
623 | break; | 657 | break; |
624 | case '+': /* Byte offset from a symbol */ | 658 | case '+': /* Byte offset from a symbol */ |
625 | pp->offset = strtoul(arg, &tmp, 0); | 659 | pp->offset = strtoul(arg, &tmp, 0); |
626 | if (*tmp != '\0') { | 660 | if (*tmp != '\0') { |
627 | semantic_error("There is non-digit character" | 661 | semantic_error("There is non-digit character" |
628 | " in offset.\n"); | 662 | " in offset.\n"); |
629 | return -EINVAL; | 663 | return -EINVAL; |
630 | } | 664 | } |
631 | break; | 665 | break; |
632 | case '@': /* File name */ | 666 | case '@': /* File name */ |
633 | if (pp->file) { | 667 | if (pp->file) { |
634 | semantic_error("SRC@SRC is not allowed.\n"); | 668 | semantic_error("SRC@SRC is not allowed.\n"); |
635 | return -EINVAL; | 669 | return -EINVAL; |
636 | } | 670 | } |
637 | pp->file = strdup(arg); | 671 | pp->file = strdup(arg); |
638 | if (pp->file == NULL) | 672 | if (pp->file == NULL) |
639 | return -ENOMEM; | 673 | return -ENOMEM; |
640 | break; | 674 | break; |
641 | case '%': /* Probe places */ | 675 | case '%': /* Probe places */ |
642 | if (strcmp(arg, "return") == 0) { | 676 | if (strcmp(arg, "return") == 0) { |
643 | pp->retprobe = 1; | 677 | pp->retprobe = 1; |
644 | } else { /* Others not supported yet */ | 678 | } else { /* Others not supported yet */ |
645 | semantic_error("%%%s is not supported.\n", arg); | 679 | semantic_error("%%%s is not supported.\n", arg); |
646 | return -ENOTSUP; | 680 | return -ENOTSUP; |
647 | } | 681 | } |
648 | break; | 682 | break; |
649 | default: /* Buggy case */ | 683 | default: /* Buggy case */ |
650 | pr_err("This program has a bug at %s:%d.\n", | 684 | pr_err("This program has a bug at %s:%d.\n", |
651 | __FILE__, __LINE__); | 685 | __FILE__, __LINE__); |
652 | return -ENOTSUP; | 686 | return -ENOTSUP; |
653 | break; | 687 | break; |
654 | } | 688 | } |
655 | } | 689 | } |
656 | 690 | ||
657 | /* Exclusion check */ | 691 | /* Exclusion check */ |
658 | if (pp->lazy_line && pp->line) { | 692 | if (pp->lazy_line && pp->line) { |
659 | semantic_error("Lazy pattern can't be used with line number."); | 693 | semantic_error("Lazy pattern can't be used with line number."); |
660 | return -EINVAL; | 694 | return -EINVAL; |
661 | } | 695 | } |
662 | 696 | ||
663 | if (pp->lazy_line && pp->offset) { | 697 | if (pp->lazy_line && pp->offset) { |
664 | semantic_error("Lazy pattern can't be used with offset."); | 698 | semantic_error("Lazy pattern can't be used with offset."); |
665 | return -EINVAL; | 699 | return -EINVAL; |
666 | } | 700 | } |
667 | 701 | ||
668 | if (pp->line && pp->offset) { | 702 | if (pp->line && pp->offset) { |
669 | semantic_error("Offset can't be used with line number."); | 703 | semantic_error("Offset can't be used with line number."); |
670 | return -EINVAL; | 704 | return -EINVAL; |
671 | } | 705 | } |
672 | 706 | ||
673 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { | 707 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { |
674 | semantic_error("File always requires line number or " | 708 | semantic_error("File always requires line number or " |
675 | "lazy pattern."); | 709 | "lazy pattern."); |
676 | return -EINVAL; | 710 | return -EINVAL; |
677 | } | 711 | } |
678 | 712 | ||
679 | if (pp->offset && !pp->function) { | 713 | if (pp->offset && !pp->function) { |
680 | semantic_error("Offset requires an entry function."); | 714 | semantic_error("Offset requires an entry function."); |
681 | return -EINVAL; | 715 | return -EINVAL; |
682 | } | 716 | } |
683 | 717 | ||
684 | if (pp->retprobe && !pp->function) { | 718 | if (pp->retprobe && !pp->function) { |
685 | semantic_error("Return probe requires an entry function."); | 719 | semantic_error("Return probe requires an entry function."); |
686 | return -EINVAL; | 720 | return -EINVAL; |
687 | } | 721 | } |
688 | 722 | ||
689 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { | 723 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { |
690 | semantic_error("Offset/Line/Lazy pattern can't be used with " | 724 | semantic_error("Offset/Line/Lazy pattern can't be used with " |
691 | "return probe."); | 725 | "return probe."); |
692 | return -EINVAL; | 726 | return -EINVAL; |
693 | } | 727 | } |
694 | 728 | ||
695 | pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", | 729 | pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", |
696 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, | 730 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, |
697 | pp->lazy_line); | 731 | pp->lazy_line); |
698 | return 0; | 732 | return 0; |
699 | } | 733 | } |
700 | 734 | ||
701 | /* Parse perf-probe event argument */ | 735 | /* Parse perf-probe event argument */ |
702 | static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) | 736 | static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) |
703 | { | 737 | { |
704 | char *tmp, *goodname; | 738 | char *tmp, *goodname; |
705 | struct perf_probe_arg_field **fieldp; | 739 | struct perf_probe_arg_field **fieldp; |
706 | 740 | ||
707 | pr_debug("parsing arg: %s into ", str); | 741 | pr_debug("parsing arg: %s into ", str); |
708 | 742 | ||
709 | tmp = strchr(str, '='); | 743 | tmp = strchr(str, '='); |
710 | if (tmp) { | 744 | if (tmp) { |
711 | arg->name = strndup(str, tmp - str); | 745 | arg->name = strndup(str, tmp - str); |
712 | if (arg->name == NULL) | 746 | if (arg->name == NULL) |
713 | return -ENOMEM; | 747 | return -ENOMEM; |
714 | pr_debug("name:%s ", arg->name); | 748 | pr_debug("name:%s ", arg->name); |
715 | str = tmp + 1; | 749 | str = tmp + 1; |
716 | } | 750 | } |
717 | 751 | ||
718 | tmp = strchr(str, ':'); | 752 | tmp = strchr(str, ':'); |
719 | if (tmp) { /* Type setting */ | 753 | if (tmp) { /* Type setting */ |
720 | *tmp = '\0'; | 754 | *tmp = '\0'; |
721 | arg->type = strdup(tmp + 1); | 755 | arg->type = strdup(tmp + 1); |
722 | if (arg->type == NULL) | 756 | if (arg->type == NULL) |
723 | return -ENOMEM; | 757 | return -ENOMEM; |
724 | pr_debug("type:%s ", arg->type); | 758 | pr_debug("type:%s ", arg->type); |
725 | } | 759 | } |
726 | 760 | ||
727 | tmp = strpbrk(str, "-.["); | 761 | tmp = strpbrk(str, "-.["); |
728 | if (!is_c_varname(str) || !tmp) { | 762 | if (!is_c_varname(str) || !tmp) { |
729 | /* A variable, register, symbol or special value */ | 763 | /* A variable, register, symbol or special value */ |
730 | arg->var = strdup(str); | 764 | arg->var = strdup(str); |
731 | if (arg->var == NULL) | 765 | if (arg->var == NULL) |
732 | return -ENOMEM; | 766 | return -ENOMEM; |
733 | pr_debug("%s\n", arg->var); | 767 | pr_debug("%s\n", arg->var); |
734 | return 0; | 768 | return 0; |
735 | } | 769 | } |
736 | 770 | ||
737 | /* Structure fields or array element */ | 771 | /* Structure fields or array element */ |
738 | arg->var = strndup(str, tmp - str); | 772 | arg->var = strndup(str, tmp - str); |
739 | if (arg->var == NULL) | 773 | if (arg->var == NULL) |
740 | return -ENOMEM; | 774 | return -ENOMEM; |
741 | goodname = arg->var; | 775 | goodname = arg->var; |
742 | pr_debug("%s, ", arg->var); | 776 | pr_debug("%s, ", arg->var); |
743 | fieldp = &arg->field; | 777 | fieldp = &arg->field; |
744 | 778 | ||
745 | do { | 779 | do { |
746 | *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); | 780 | *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); |
747 | if (*fieldp == NULL) | 781 | if (*fieldp == NULL) |
748 | return -ENOMEM; | 782 | return -ENOMEM; |
749 | if (*tmp == '[') { /* Array */ | 783 | if (*tmp == '[') { /* Array */ |
750 | str = tmp; | 784 | str = tmp; |
751 | (*fieldp)->index = strtol(str + 1, &tmp, 0); | 785 | (*fieldp)->index = strtol(str + 1, &tmp, 0); |
752 | (*fieldp)->ref = true; | 786 | (*fieldp)->ref = true; |
753 | if (*tmp != ']' || tmp == str + 1) { | 787 | if (*tmp != ']' || tmp == str + 1) { |
754 | semantic_error("Array index must be a" | 788 | semantic_error("Array index must be a" |
755 | " number.\n"); | 789 | " number.\n"); |
756 | return -EINVAL; | 790 | return -EINVAL; |
757 | } | 791 | } |
758 | tmp++; | 792 | tmp++; |
759 | if (*tmp == '\0') | 793 | if (*tmp == '\0') |
760 | tmp = NULL; | 794 | tmp = NULL; |
761 | } else { /* Structure */ | 795 | } else { /* Structure */ |
762 | if (*tmp == '.') { | 796 | if (*tmp == '.') { |
763 | str = tmp + 1; | 797 | str = tmp + 1; |
764 | (*fieldp)->ref = false; | 798 | (*fieldp)->ref = false; |
765 | } else if (tmp[1] == '>') { | 799 | } else if (tmp[1] == '>') { |
766 | str = tmp + 2; | 800 | str = tmp + 2; |
767 | (*fieldp)->ref = true; | 801 | (*fieldp)->ref = true; |
768 | } else { | 802 | } else { |
769 | semantic_error("Argument parse error: %s\n", | 803 | semantic_error("Argument parse error: %s\n", |
770 | str); | 804 | str); |
771 | return -EINVAL; | 805 | return -EINVAL; |
772 | } | 806 | } |
773 | tmp = strpbrk(str, "-.["); | 807 | tmp = strpbrk(str, "-.["); |
774 | } | 808 | } |
775 | if (tmp) { | 809 | if (tmp) { |
776 | (*fieldp)->name = strndup(str, tmp - str); | 810 | (*fieldp)->name = strndup(str, tmp - str); |
777 | if ((*fieldp)->name == NULL) | 811 | if ((*fieldp)->name == NULL) |
778 | return -ENOMEM; | 812 | return -ENOMEM; |
779 | if (*str != '[') | 813 | if (*str != '[') |
780 | goodname = (*fieldp)->name; | 814 | goodname = (*fieldp)->name; |
781 | pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); | 815 | pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); |
782 | fieldp = &(*fieldp)->next; | 816 | fieldp = &(*fieldp)->next; |
783 | } | 817 | } |
784 | } while (tmp); | 818 | } while (tmp); |
785 | (*fieldp)->name = strdup(str); | 819 | (*fieldp)->name = strdup(str); |
786 | if ((*fieldp)->name == NULL) | 820 | if ((*fieldp)->name == NULL) |
787 | return -ENOMEM; | 821 | return -ENOMEM; |
788 | if (*str != '[') | 822 | if (*str != '[') |
789 | goodname = (*fieldp)->name; | 823 | goodname = (*fieldp)->name; |
790 | pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); | 824 | pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); |
791 | 825 | ||
792 | /* If no name is specified, set the last field name (not array index)*/ | 826 | /* If no name is specified, set the last field name (not array index)*/ |
793 | if (!arg->name) { | 827 | if (!arg->name) { |
794 | arg->name = strdup(goodname); | 828 | arg->name = strdup(goodname); |
795 | if (arg->name == NULL) | 829 | if (arg->name == NULL) |
796 | return -ENOMEM; | 830 | return -ENOMEM; |
797 | } | 831 | } |
798 | return 0; | 832 | return 0; |
799 | } | 833 | } |
800 | 834 | ||
801 | /* Parse perf-probe event command */ | 835 | /* Parse perf-probe event command */ |
802 | int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) | 836 | int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) |
803 | { | 837 | { |
804 | char **argv; | 838 | char **argv; |
805 | int argc, i, ret = 0; | 839 | int argc, i, ret = 0; |
806 | 840 | ||
807 | argv = argv_split(cmd, &argc); | 841 | argv = argv_split(cmd, &argc); |
808 | if (!argv) { | 842 | if (!argv) { |
809 | pr_debug("Failed to split arguments.\n"); | 843 | pr_debug("Failed to split arguments.\n"); |
810 | return -ENOMEM; | 844 | return -ENOMEM; |
811 | } | 845 | } |
812 | if (argc - 1 > MAX_PROBE_ARGS) { | 846 | if (argc - 1 > MAX_PROBE_ARGS) { |
813 | semantic_error("Too many probe arguments (%d).\n", argc - 1); | 847 | semantic_error("Too many probe arguments (%d).\n", argc - 1); |
814 | ret = -ERANGE; | 848 | ret = -ERANGE; |
815 | goto out; | 849 | goto out; |
816 | } | 850 | } |
817 | /* Parse probe point */ | 851 | /* Parse probe point */ |
818 | ret = parse_perf_probe_point(argv[0], pev); | 852 | ret = parse_perf_probe_point(argv[0], pev); |
819 | if (ret < 0) | 853 | if (ret < 0) |
820 | goto out; | 854 | goto out; |
821 | 855 | ||
822 | /* Copy arguments and ensure return probe has no C argument */ | 856 | /* Copy arguments and ensure return probe has no C argument */ |
823 | pev->nargs = argc - 1; | 857 | pev->nargs = argc - 1; |
824 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 858 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
825 | if (pev->args == NULL) { | 859 | if (pev->args == NULL) { |
826 | ret = -ENOMEM; | 860 | ret = -ENOMEM; |
827 | goto out; | 861 | goto out; |
828 | } | 862 | } |
829 | for (i = 0; i < pev->nargs && ret >= 0; i++) { | 863 | for (i = 0; i < pev->nargs && ret >= 0; i++) { |
830 | ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); | 864 | ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); |
831 | if (ret >= 0 && | 865 | if (ret >= 0 && |
832 | is_c_varname(pev->args[i].var) && pev->point.retprobe) { | 866 | is_c_varname(pev->args[i].var) && pev->point.retprobe) { |
833 | semantic_error("You can't specify local variable for" | 867 | semantic_error("You can't specify local variable for" |
834 | " kretprobe.\n"); | 868 | " kretprobe.\n"); |
835 | ret = -EINVAL; | 869 | ret = -EINVAL; |
836 | } | 870 | } |
837 | } | 871 | } |
838 | out: | 872 | out: |
839 | argv_free(argv); | 873 | argv_free(argv); |
840 | 874 | ||
841 | return ret; | 875 | return ret; |
842 | } | 876 | } |
843 | 877 | ||
844 | /* Return true if this perf_probe_event requires debuginfo */ | 878 | /* Return true if this perf_probe_event requires debuginfo */ |
845 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | 879 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) |
846 | { | 880 | { |
847 | int i; | 881 | int i; |
848 | 882 | ||
849 | if (pev->point.file || pev->point.line || pev->point.lazy_line) | 883 | if (pev->point.file || pev->point.line || pev->point.lazy_line) |
850 | return true; | 884 | return true; |
851 | 885 | ||
852 | for (i = 0; i < pev->nargs; i++) | 886 | for (i = 0; i < pev->nargs; i++) |
853 | if (is_c_varname(pev->args[i].var)) | 887 | if (is_c_varname(pev->args[i].var)) |
854 | return true; | 888 | return true; |
855 | 889 | ||
856 | return false; | 890 | return false; |
857 | } | 891 | } |
858 | 892 | ||
859 | /* Parse probe_events event into struct probe_point */ | 893 | /* Parse probe_events event into struct probe_point */ |
860 | static int parse_probe_trace_command(const char *cmd, | 894 | static int parse_probe_trace_command(const char *cmd, |
861 | struct probe_trace_event *tev) | 895 | struct probe_trace_event *tev) |
862 | { | 896 | { |
863 | struct probe_trace_point *tp = &tev->point; | 897 | struct probe_trace_point *tp = &tev->point; |
864 | char pr; | 898 | char pr; |
865 | char *p; | 899 | char *p; |
866 | int ret, i, argc; | 900 | int ret, i, argc; |
867 | char **argv; | 901 | char **argv; |
868 | 902 | ||
869 | pr_debug("Parsing probe_events: %s\n", cmd); | 903 | pr_debug("Parsing probe_events: %s\n", cmd); |
870 | argv = argv_split(cmd, &argc); | 904 | argv = argv_split(cmd, &argc); |
871 | if (!argv) { | 905 | if (!argv) { |
872 | pr_debug("Failed to split arguments.\n"); | 906 | pr_debug("Failed to split arguments.\n"); |
873 | return -ENOMEM; | 907 | return -ENOMEM; |
874 | } | 908 | } |
875 | if (argc < 2) { | 909 | if (argc < 2) { |
876 | semantic_error("Too few probe arguments.\n"); | 910 | semantic_error("Too few probe arguments.\n"); |
877 | ret = -ERANGE; | 911 | ret = -ERANGE; |
878 | goto out; | 912 | goto out; |
879 | } | 913 | } |
880 | 914 | ||
881 | /* Scan event and group name. */ | 915 | /* Scan event and group name. */ |
882 | ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", | 916 | ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", |
883 | &pr, (float *)(void *)&tev->group, | 917 | &pr, (float *)(void *)&tev->group, |
884 | (float *)(void *)&tev->event); | 918 | (float *)(void *)&tev->event); |
885 | if (ret != 3) { | 919 | if (ret != 3) { |
886 | semantic_error("Failed to parse event name: %s\n", argv[0]); | 920 | semantic_error("Failed to parse event name: %s\n", argv[0]); |
887 | ret = -EINVAL; | 921 | ret = -EINVAL; |
888 | goto out; | 922 | goto out; |
889 | } | 923 | } |
890 | pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); | 924 | pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); |
891 | 925 | ||
892 | tp->retprobe = (pr == 'r'); | 926 | tp->retprobe = (pr == 'r'); |
893 | 927 | ||
894 | /* Scan function name and offset */ | 928 | /* Scan function name and offset */ |
895 | ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol, | 929 | ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol, |
896 | &tp->offset); | 930 | &tp->offset); |
897 | if (ret == 1) | 931 | if (ret == 1) |
898 | tp->offset = 0; | 932 | tp->offset = 0; |
899 | 933 | ||
900 | tev->nargs = argc - 2; | 934 | tev->nargs = argc - 2; |
901 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | 935 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); |
902 | if (tev->args == NULL) { | 936 | if (tev->args == NULL) { |
903 | ret = -ENOMEM; | 937 | ret = -ENOMEM; |
904 | goto out; | 938 | goto out; |
905 | } | 939 | } |
906 | for (i = 0; i < tev->nargs; i++) { | 940 | for (i = 0; i < tev->nargs; i++) { |
907 | p = strchr(argv[i + 2], '='); | 941 | p = strchr(argv[i + 2], '='); |
908 | if (p) /* We don't need which register is assigned. */ | 942 | if (p) /* We don't need which register is assigned. */ |
909 | *p++ = '\0'; | 943 | *p++ = '\0'; |
910 | else | 944 | else |
911 | p = argv[i + 2]; | 945 | p = argv[i + 2]; |
912 | tev->args[i].name = strdup(argv[i + 2]); | 946 | tev->args[i].name = strdup(argv[i + 2]); |
913 | /* TODO: parse regs and offset */ | 947 | /* TODO: parse regs and offset */ |
914 | tev->args[i].value = strdup(p); | 948 | tev->args[i].value = strdup(p); |
915 | if (tev->args[i].name == NULL || tev->args[i].value == NULL) { | 949 | if (tev->args[i].name == NULL || tev->args[i].value == NULL) { |
916 | ret = -ENOMEM; | 950 | ret = -ENOMEM; |
917 | goto out; | 951 | goto out; |
918 | } | 952 | } |
919 | } | 953 | } |
920 | ret = 0; | 954 | ret = 0; |
921 | out: | 955 | out: |
922 | argv_free(argv); | 956 | argv_free(argv); |
923 | return ret; | 957 | return ret; |
924 | } | 958 | } |
925 | 959 | ||
926 | /* Compose only probe arg */ | 960 | /* Compose only probe arg */ |
927 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | 961 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) |
928 | { | 962 | { |
929 | struct perf_probe_arg_field *field = pa->field; | 963 | struct perf_probe_arg_field *field = pa->field; |
930 | int ret; | 964 | int ret; |
931 | char *tmp = buf; | 965 | char *tmp = buf; |
932 | 966 | ||
933 | if (pa->name && pa->var) | 967 | if (pa->name && pa->var) |
934 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); | 968 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); |
935 | else | 969 | else |
936 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); | 970 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); |
937 | if (ret <= 0) | 971 | if (ret <= 0) |
938 | goto error; | 972 | goto error; |
939 | tmp += ret; | 973 | tmp += ret; |
940 | len -= ret; | 974 | len -= ret; |
941 | 975 | ||
942 | while (field) { | 976 | while (field) { |
943 | if (field->name[0] == '[') | 977 | if (field->name[0] == '[') |
944 | ret = e_snprintf(tmp, len, "%s", field->name); | 978 | ret = e_snprintf(tmp, len, "%s", field->name); |
945 | else | 979 | else |
946 | ret = e_snprintf(tmp, len, "%s%s", | 980 | ret = e_snprintf(tmp, len, "%s%s", |
947 | field->ref ? "->" : ".", field->name); | 981 | field->ref ? "->" : ".", field->name); |
948 | if (ret <= 0) | 982 | if (ret <= 0) |
949 | goto error; | 983 | goto error; |
950 | tmp += ret; | 984 | tmp += ret; |
951 | len -= ret; | 985 | len -= ret; |
952 | field = field->next; | 986 | field = field->next; |
953 | } | 987 | } |
954 | 988 | ||
955 | if (pa->type) { | 989 | if (pa->type) { |
956 | ret = e_snprintf(tmp, len, ":%s", pa->type); | 990 | ret = e_snprintf(tmp, len, ":%s", pa->type); |
957 | if (ret <= 0) | 991 | if (ret <= 0) |
958 | goto error; | 992 | goto error; |
959 | tmp += ret; | 993 | tmp += ret; |
960 | len -= ret; | 994 | len -= ret; |
961 | } | 995 | } |
962 | 996 | ||
963 | return tmp - buf; | 997 | return tmp - buf; |
964 | error: | 998 | error: |
965 | pr_debug("Failed to synthesize perf probe argument: %s", | 999 | pr_debug("Failed to synthesize perf probe argument: %s", |
966 | strerror(-ret)); | 1000 | strerror(-ret)); |
967 | return ret; | 1001 | return ret; |
968 | } | 1002 | } |
969 | 1003 | ||
970 | /* Compose only probe point (not argument) */ | 1004 | /* Compose only probe point (not argument) */ |
971 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | 1005 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
972 | { | 1006 | { |
973 | char *buf, *tmp; | 1007 | char *buf, *tmp; |
974 | char offs[32] = "", line[32] = "", file[32] = ""; | 1008 | char offs[32] = "", line[32] = "", file[32] = ""; |
975 | int ret, len; | 1009 | int ret, len; |
976 | 1010 | ||
977 | buf = zalloc(MAX_CMDLEN); | 1011 | buf = zalloc(MAX_CMDLEN); |
978 | if (buf == NULL) { | 1012 | if (buf == NULL) { |
979 | ret = -ENOMEM; | 1013 | ret = -ENOMEM; |
980 | goto error; | 1014 | goto error; |
981 | } | 1015 | } |
982 | if (pp->offset) { | 1016 | if (pp->offset) { |
983 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); | 1017 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); |
984 | if (ret <= 0) | 1018 | if (ret <= 0) |
985 | goto error; | 1019 | goto error; |
986 | } | 1020 | } |
987 | if (pp->line) { | 1021 | if (pp->line) { |
988 | ret = e_snprintf(line, 32, ":%d", pp->line); | 1022 | ret = e_snprintf(line, 32, ":%d", pp->line); |
989 | if (ret <= 0) | 1023 | if (ret <= 0) |
990 | goto error; | 1024 | goto error; |
991 | } | 1025 | } |
992 | if (pp->file) { | 1026 | if (pp->file) { |
993 | len = strlen(pp->file) - 31; | 1027 | len = strlen(pp->file) - 31; |
994 | if (len < 0) | 1028 | if (len < 0) |
995 | len = 0; | 1029 | len = 0; |
996 | tmp = strchr(pp->file + len, '/'); | 1030 | tmp = strchr(pp->file + len, '/'); |
997 | if (!tmp) | 1031 | if (!tmp) |
998 | tmp = pp->file + len; | 1032 | tmp = pp->file + len; |
999 | ret = e_snprintf(file, 32, "@%s", tmp + 1); | 1033 | ret = e_snprintf(file, 32, "@%s", tmp + 1); |
1000 | if (ret <= 0) | 1034 | if (ret <= 0) |
1001 | goto error; | 1035 | goto error; |
1002 | } | 1036 | } |
1003 | 1037 | ||
1004 | if (pp->function) | 1038 | if (pp->function) |
1005 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, | 1039 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, |
1006 | offs, pp->retprobe ? "%return" : "", line, | 1040 | offs, pp->retprobe ? "%return" : "", line, |
1007 | file); | 1041 | file); |
1008 | else | 1042 | else |
1009 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); | 1043 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); |
1010 | if (ret <= 0) | 1044 | if (ret <= 0) |
1011 | goto error; | 1045 | goto error; |
1012 | 1046 | ||
1013 | return buf; | 1047 | return buf; |
1014 | error: | 1048 | error: |
1015 | pr_debug("Failed to synthesize perf probe point: %s", | 1049 | pr_debug("Failed to synthesize perf probe point: %s", |
1016 | strerror(-ret)); | 1050 | strerror(-ret)); |
1017 | if (buf) | 1051 | if (buf) |
1018 | free(buf); | 1052 | free(buf); |
1019 | return NULL; | 1053 | return NULL; |
1020 | } | 1054 | } |
1021 | 1055 | ||
1022 | #if 0 | 1056 | #if 0 |
1023 | char *synthesize_perf_probe_command(struct perf_probe_event *pev) | 1057 | char *synthesize_perf_probe_command(struct perf_probe_event *pev) |
1024 | { | 1058 | { |
1025 | char *buf; | 1059 | char *buf; |
1026 | int i, len, ret; | 1060 | int i, len, ret; |
1027 | 1061 | ||
1028 | buf = synthesize_perf_probe_point(&pev->point); | 1062 | buf = synthesize_perf_probe_point(&pev->point); |
1029 | if (!buf) | 1063 | if (!buf) |
1030 | return NULL; | 1064 | return NULL; |
1031 | 1065 | ||
1032 | len = strlen(buf); | 1066 | len = strlen(buf); |
1033 | for (i = 0; i < pev->nargs; i++) { | 1067 | for (i = 0; i < pev->nargs; i++) { |
1034 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", | 1068 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", |
1035 | pev->args[i].name); | 1069 | pev->args[i].name); |
1036 | if (ret <= 0) { | 1070 | if (ret <= 0) { |
1037 | free(buf); | 1071 | free(buf); |
1038 | return NULL; | 1072 | return NULL; |
1039 | } | 1073 | } |
1040 | len += ret; | 1074 | len += ret; |
1041 | } | 1075 | } |
1042 | 1076 | ||
1043 | return buf; | 1077 | return buf; |
1044 | } | 1078 | } |
1045 | #endif | 1079 | #endif |
1046 | 1080 | ||
1047 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, | 1081 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, |
1048 | char **buf, size_t *buflen, | 1082 | char **buf, size_t *buflen, |
1049 | int depth) | 1083 | int depth) |
1050 | { | 1084 | { |
1051 | int ret; | 1085 | int ret; |
1052 | if (ref->next) { | 1086 | if (ref->next) { |
1053 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, | 1087 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, |
1054 | buflen, depth + 1); | 1088 | buflen, depth + 1); |
1055 | if (depth < 0) | 1089 | if (depth < 0) |
1056 | goto out; | 1090 | goto out; |
1057 | } | 1091 | } |
1058 | 1092 | ||
1059 | ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); | 1093 | ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); |
1060 | if (ret < 0) | 1094 | if (ret < 0) |
1061 | depth = ret; | 1095 | depth = ret; |
1062 | else { | 1096 | else { |
1063 | *buf += ret; | 1097 | *buf += ret; |
1064 | *buflen -= ret; | 1098 | *buflen -= ret; |
1065 | } | 1099 | } |
1066 | out: | 1100 | out: |
1067 | return depth; | 1101 | return depth; |
1068 | 1102 | ||
1069 | } | 1103 | } |
1070 | 1104 | ||
1071 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, | 1105 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, |
1072 | char *buf, size_t buflen) | 1106 | char *buf, size_t buflen) |
1073 | { | 1107 | { |
1074 | struct probe_trace_arg_ref *ref = arg->ref; | 1108 | struct probe_trace_arg_ref *ref = arg->ref; |
1075 | int ret, depth = 0; | 1109 | int ret, depth = 0; |
1076 | char *tmp = buf; | 1110 | char *tmp = buf; |
1077 | 1111 | ||
1078 | /* Argument name or separator */ | 1112 | /* Argument name or separator */ |
1079 | if (arg->name) | 1113 | if (arg->name) |
1080 | ret = e_snprintf(buf, buflen, " %s=", arg->name); | 1114 | ret = e_snprintf(buf, buflen, " %s=", arg->name); |
1081 | else | 1115 | else |
1082 | ret = e_snprintf(buf, buflen, " "); | 1116 | ret = e_snprintf(buf, buflen, " "); |
1083 | if (ret < 0) | 1117 | if (ret < 0) |
1084 | return ret; | 1118 | return ret; |
1085 | buf += ret; | 1119 | buf += ret; |
1086 | buflen -= ret; | 1120 | buflen -= ret; |
1087 | 1121 | ||
1088 | /* Special case: @XXX */ | 1122 | /* Special case: @XXX */ |
1089 | if (arg->value[0] == '@' && arg->ref) | 1123 | if (arg->value[0] == '@' && arg->ref) |
1090 | ref = ref->next; | 1124 | ref = ref->next; |
1091 | 1125 | ||
1092 | /* Dereferencing arguments */ | 1126 | /* Dereferencing arguments */ |
1093 | if (ref) { | 1127 | if (ref) { |
1094 | depth = __synthesize_probe_trace_arg_ref(ref, &buf, | 1128 | depth = __synthesize_probe_trace_arg_ref(ref, &buf, |
1095 | &buflen, 1); | 1129 | &buflen, 1); |
1096 | if (depth < 0) | 1130 | if (depth < 0) |
1097 | return depth; | 1131 | return depth; |
1098 | } | 1132 | } |
1099 | 1133 | ||
1100 | /* Print argument value */ | 1134 | /* Print argument value */ |
1101 | if (arg->value[0] == '@' && arg->ref) | 1135 | if (arg->value[0] == '@' && arg->ref) |
1102 | ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, | 1136 | ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, |
1103 | arg->ref->offset); | 1137 | arg->ref->offset); |
1104 | else | 1138 | else |
1105 | ret = e_snprintf(buf, buflen, "%s", arg->value); | 1139 | ret = e_snprintf(buf, buflen, "%s", arg->value); |
1106 | if (ret < 0) | 1140 | if (ret < 0) |
1107 | return ret; | 1141 | return ret; |
1108 | buf += ret; | 1142 | buf += ret; |
1109 | buflen -= ret; | 1143 | buflen -= ret; |
1110 | 1144 | ||
1111 | /* Closing */ | 1145 | /* Closing */ |
1112 | while (depth--) { | 1146 | while (depth--) { |
1113 | ret = e_snprintf(buf, buflen, ")"); | 1147 | ret = e_snprintf(buf, buflen, ")"); |
1114 | if (ret < 0) | 1148 | if (ret < 0) |
1115 | return ret; | 1149 | return ret; |
1116 | buf += ret; | 1150 | buf += ret; |
1117 | buflen -= ret; | 1151 | buflen -= ret; |
1118 | } | 1152 | } |
1119 | /* Print argument type */ | 1153 | /* Print argument type */ |
1120 | if (arg->type) { | 1154 | if (arg->type) { |
1121 | ret = e_snprintf(buf, buflen, ":%s", arg->type); | 1155 | ret = e_snprintf(buf, buflen, ":%s", arg->type); |
1122 | if (ret <= 0) | 1156 | if (ret <= 0) |
1123 | return ret; | 1157 | return ret; |
1124 | buf += ret; | 1158 | buf += ret; |
1125 | } | 1159 | } |
1126 | 1160 | ||
1127 | return buf - tmp; | 1161 | return buf - tmp; |
1128 | } | 1162 | } |
1129 | 1163 | ||
1130 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) | 1164 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) |
1131 | { | 1165 | { |
1132 | struct probe_trace_point *tp = &tev->point; | 1166 | struct probe_trace_point *tp = &tev->point; |
1133 | char *buf; | 1167 | char *buf; |
1134 | int i, len, ret; | 1168 | int i, len, ret; |
1135 | 1169 | ||
1136 | buf = zalloc(MAX_CMDLEN); | 1170 | buf = zalloc(MAX_CMDLEN); |
1137 | if (buf == NULL) | 1171 | if (buf == NULL) |
1138 | return NULL; | 1172 | return NULL; |
1139 | 1173 | ||
1140 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", | 1174 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", |
1141 | tp->retprobe ? 'r' : 'p', | 1175 | tp->retprobe ? 'r' : 'p', |
1142 | tev->group, tev->event, | 1176 | tev->group, tev->event, |
1143 | tp->symbol, tp->offset); | 1177 | tp->symbol, tp->offset); |
1144 | if (len <= 0) | 1178 | if (len <= 0) |
1145 | goto error; | 1179 | goto error; |
1146 | 1180 | ||
1147 | for (i = 0; i < tev->nargs; i++) { | 1181 | for (i = 0; i < tev->nargs; i++) { |
1148 | ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, | 1182 | ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, |
1149 | MAX_CMDLEN - len); | 1183 | MAX_CMDLEN - len); |
1150 | if (ret <= 0) | 1184 | if (ret <= 0) |
1151 | goto error; | 1185 | goto error; |
1152 | len += ret; | 1186 | len += ret; |
1153 | } | 1187 | } |
1154 | 1188 | ||
1155 | return buf; | 1189 | return buf; |
1156 | error: | 1190 | error: |
1157 | free(buf); | 1191 | free(buf); |
1158 | return NULL; | 1192 | return NULL; |
1159 | } | 1193 | } |
1160 | 1194 | ||
1161 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, | 1195 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, |
1162 | struct perf_probe_event *pev) | 1196 | struct perf_probe_event *pev) |
1163 | { | 1197 | { |
1164 | char buf[64] = ""; | 1198 | char buf[64] = ""; |
1165 | int i, ret; | 1199 | int i, ret; |
1166 | 1200 | ||
1167 | /* Convert event/group name */ | 1201 | /* Convert event/group name */ |
1168 | pev->event = strdup(tev->event); | 1202 | pev->event = strdup(tev->event); |
1169 | pev->group = strdup(tev->group); | 1203 | pev->group = strdup(tev->group); |
1170 | if (pev->event == NULL || pev->group == NULL) | 1204 | if (pev->event == NULL || pev->group == NULL) |
1171 | return -ENOMEM; | 1205 | return -ENOMEM; |
1172 | 1206 | ||
1173 | /* Convert trace_point to probe_point */ | 1207 | /* Convert trace_point to probe_point */ |
1174 | ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); | 1208 | ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); |
1175 | if (ret < 0) | 1209 | if (ret < 0) |
1176 | return ret; | 1210 | return ret; |
1177 | 1211 | ||
1178 | /* Convert trace_arg to probe_arg */ | 1212 | /* Convert trace_arg to probe_arg */ |
1179 | pev->nargs = tev->nargs; | 1213 | pev->nargs = tev->nargs; |
1180 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 1214 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
1181 | if (pev->args == NULL) | 1215 | if (pev->args == NULL) |
1182 | return -ENOMEM; | 1216 | return -ENOMEM; |
1183 | for (i = 0; i < tev->nargs && ret >= 0; i++) { | 1217 | for (i = 0; i < tev->nargs && ret >= 0; i++) { |
1184 | if (tev->args[i].name) | 1218 | if (tev->args[i].name) |
1185 | pev->args[i].name = strdup(tev->args[i].name); | 1219 | pev->args[i].name = strdup(tev->args[i].name); |
1186 | else { | 1220 | else { |
1187 | ret = synthesize_probe_trace_arg(&tev->args[i], | 1221 | ret = synthesize_probe_trace_arg(&tev->args[i], |
1188 | buf, 64); | 1222 | buf, 64); |
1189 | pev->args[i].name = strdup(buf); | 1223 | pev->args[i].name = strdup(buf); |
1190 | } | 1224 | } |
1191 | if (pev->args[i].name == NULL && ret >= 0) | 1225 | if (pev->args[i].name == NULL && ret >= 0) |
1192 | ret = -ENOMEM; | 1226 | ret = -ENOMEM; |
1193 | } | 1227 | } |
1194 | 1228 | ||
1195 | if (ret < 0) | 1229 | if (ret < 0) |
1196 | clear_perf_probe_event(pev); | 1230 | clear_perf_probe_event(pev); |
1197 | 1231 | ||
1198 | return ret; | 1232 | return ret; |
1199 | } | 1233 | } |
1200 | 1234 | ||
1201 | void clear_perf_probe_event(struct perf_probe_event *pev) | 1235 | void clear_perf_probe_event(struct perf_probe_event *pev) |
1202 | { | 1236 | { |
1203 | struct perf_probe_point *pp = &pev->point; | 1237 | struct perf_probe_point *pp = &pev->point; |
1204 | struct perf_probe_arg_field *field, *next; | 1238 | struct perf_probe_arg_field *field, *next; |
1205 | int i; | 1239 | int i; |
1206 | 1240 | ||
1207 | if (pev->event) | 1241 | if (pev->event) |
1208 | free(pev->event); | 1242 | free(pev->event); |
1209 | if (pev->group) | 1243 | if (pev->group) |
1210 | free(pev->group); | 1244 | free(pev->group); |
1211 | if (pp->file) | 1245 | if (pp->file) |
1212 | free(pp->file); | 1246 | free(pp->file); |
1213 | if (pp->function) | 1247 | if (pp->function) |
1214 | free(pp->function); | 1248 | free(pp->function); |
1215 | if (pp->lazy_line) | 1249 | if (pp->lazy_line) |
1216 | free(pp->lazy_line); | 1250 | free(pp->lazy_line); |
1217 | for (i = 0; i < pev->nargs; i++) { | 1251 | for (i = 0; i < pev->nargs; i++) { |
1218 | if (pev->args[i].name) | 1252 | if (pev->args[i].name) |
1219 | free(pev->args[i].name); | 1253 | free(pev->args[i].name); |
1220 | if (pev->args[i].var) | 1254 | if (pev->args[i].var) |
1221 | free(pev->args[i].var); | 1255 | free(pev->args[i].var); |
1222 | if (pev->args[i].type) | 1256 | if (pev->args[i].type) |
1223 | free(pev->args[i].type); | 1257 | free(pev->args[i].type); |
1224 | field = pev->args[i].field; | 1258 | field = pev->args[i].field; |
1225 | while (field) { | 1259 | while (field) { |
1226 | next = field->next; | 1260 | next = field->next; |
1227 | if (field->name) | 1261 | if (field->name) |
1228 | free(field->name); | 1262 | free(field->name); |
1229 | free(field); | 1263 | free(field); |
1230 | field = next; | 1264 | field = next; |
1231 | } | 1265 | } |
1232 | } | 1266 | } |
1233 | if (pev->args) | 1267 | if (pev->args) |
1234 | free(pev->args); | 1268 | free(pev->args); |
1235 | memset(pev, 0, sizeof(*pev)); | 1269 | memset(pev, 0, sizeof(*pev)); |
1236 | } | 1270 | } |
1237 | 1271 | ||
1238 | static void clear_probe_trace_event(struct probe_trace_event *tev) | 1272 | static void clear_probe_trace_event(struct probe_trace_event *tev) |
1239 | { | 1273 | { |
1240 | struct probe_trace_arg_ref *ref, *next; | 1274 | struct probe_trace_arg_ref *ref, *next; |
1241 | int i; | 1275 | int i; |
1242 | 1276 | ||
1243 | if (tev->event) | 1277 | if (tev->event) |
1244 | free(tev->event); | 1278 | free(tev->event); |
1245 | if (tev->group) | 1279 | if (tev->group) |
1246 | free(tev->group); | 1280 | free(tev->group); |
1247 | if (tev->point.symbol) | 1281 | if (tev->point.symbol) |
1248 | free(tev->point.symbol); | 1282 | free(tev->point.symbol); |
1249 | for (i = 0; i < tev->nargs; i++) { | 1283 | for (i = 0; i < tev->nargs; i++) { |
1250 | if (tev->args[i].name) | 1284 | if (tev->args[i].name) |
1251 | free(tev->args[i].name); | 1285 | free(tev->args[i].name); |
1252 | if (tev->args[i].value) | 1286 | if (tev->args[i].value) |
1253 | free(tev->args[i].value); | 1287 | free(tev->args[i].value); |
1254 | if (tev->args[i].type) | 1288 | if (tev->args[i].type) |
1255 | free(tev->args[i].type); | 1289 | free(tev->args[i].type); |
1256 | ref = tev->args[i].ref; | 1290 | ref = tev->args[i].ref; |
1257 | while (ref) { | 1291 | while (ref) { |
1258 | next = ref->next; | 1292 | next = ref->next; |
1259 | free(ref); | 1293 | free(ref); |
1260 | ref = next; | 1294 | ref = next; |
1261 | } | 1295 | } |
1262 | } | 1296 | } |
1263 | if (tev->args) | 1297 | if (tev->args) |
1264 | free(tev->args); | 1298 | free(tev->args); |
1265 | memset(tev, 0, sizeof(*tev)); | 1299 | memset(tev, 0, sizeof(*tev)); |
1266 | } | 1300 | } |
1267 | 1301 | ||
1268 | static int open_kprobe_events(bool readwrite) | 1302 | static int open_kprobe_events(bool readwrite) |
1269 | { | 1303 | { |
1270 | char buf[PATH_MAX]; | 1304 | char buf[PATH_MAX]; |
1271 | const char *__debugfs; | 1305 | const char *__debugfs; |
1272 | int ret; | 1306 | int ret; |
1273 | 1307 | ||
1274 | __debugfs = debugfs_find_mountpoint(); | 1308 | __debugfs = debugfs_find_mountpoint(); |
1275 | if (__debugfs == NULL) { | 1309 | if (__debugfs == NULL) { |
1276 | pr_warning("Debugfs is not mounted.\n"); | 1310 | pr_warning("Debugfs is not mounted.\n"); |
1277 | return -ENOENT; | 1311 | return -ENOENT; |
1278 | } | 1312 | } |
1279 | 1313 | ||
1280 | ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); | 1314 | ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); |
1281 | if (ret >= 0) { | 1315 | if (ret >= 0) { |
1282 | pr_debug("Opening %s write=%d\n", buf, readwrite); | 1316 | pr_debug("Opening %s write=%d\n", buf, readwrite); |
1283 | if (readwrite && !probe_event_dry_run) | 1317 | if (readwrite && !probe_event_dry_run) |
1284 | ret = open(buf, O_RDWR, O_APPEND); | 1318 | ret = open(buf, O_RDWR, O_APPEND); |
1285 | else | 1319 | else |
1286 | ret = open(buf, O_RDONLY, 0); | 1320 | ret = open(buf, O_RDONLY, 0); |
1287 | } | 1321 | } |
1288 | 1322 | ||
1289 | if (ret < 0) { | 1323 | if (ret < 0) { |
1290 | if (errno == ENOENT) | 1324 | if (errno == ENOENT) |
1291 | pr_warning("kprobe_events file does not exist - please" | 1325 | pr_warning("kprobe_events file does not exist - please" |
1292 | " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); | 1326 | " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); |
1293 | else | 1327 | else |
1294 | pr_warning("Failed to open kprobe_events file: %s\n", | 1328 | pr_warning("Failed to open kprobe_events file: %s\n", |
1295 | strerror(errno)); | 1329 | strerror(errno)); |
1296 | } | 1330 | } |
1297 | return ret; | 1331 | return ret; |
1298 | } | 1332 | } |
1299 | 1333 | ||
1300 | /* Get raw string list of current kprobe_events */ | 1334 | /* Get raw string list of current kprobe_events */ |
1301 | static struct strlist *get_probe_trace_command_rawlist(int fd) | 1335 | static struct strlist *get_probe_trace_command_rawlist(int fd) |
1302 | { | 1336 | { |
1303 | int ret, idx; | 1337 | int ret, idx; |
1304 | FILE *fp; | 1338 | FILE *fp; |
1305 | char buf[MAX_CMDLEN]; | 1339 | char buf[MAX_CMDLEN]; |
1306 | char *p; | 1340 | char *p; |
1307 | struct strlist *sl; | 1341 | struct strlist *sl; |
1308 | 1342 | ||
1309 | sl = strlist__new(true, NULL); | 1343 | sl = strlist__new(true, NULL); |
1310 | 1344 | ||
1311 | fp = fdopen(dup(fd), "r"); | 1345 | fp = fdopen(dup(fd), "r"); |
1312 | while (!feof(fp)) { | 1346 | while (!feof(fp)) { |
1313 | p = fgets(buf, MAX_CMDLEN, fp); | 1347 | p = fgets(buf, MAX_CMDLEN, fp); |
1314 | if (!p) | 1348 | if (!p) |
1315 | break; | 1349 | break; |
1316 | 1350 | ||
1317 | idx = strlen(p) - 1; | 1351 | idx = strlen(p) - 1; |
1318 | if (p[idx] == '\n') | 1352 | if (p[idx] == '\n') |
1319 | p[idx] = '\0'; | 1353 | p[idx] = '\0'; |
1320 | ret = strlist__add(sl, buf); | 1354 | ret = strlist__add(sl, buf); |
1321 | if (ret < 0) { | 1355 | if (ret < 0) { |
1322 | pr_debug("strlist__add failed: %s\n", strerror(-ret)); | 1356 | pr_debug("strlist__add failed: %s\n", strerror(-ret)); |
1323 | strlist__delete(sl); | 1357 | strlist__delete(sl); |
1324 | return NULL; | 1358 | return NULL; |
1325 | } | 1359 | } |
1326 | } | 1360 | } |
1327 | fclose(fp); | 1361 | fclose(fp); |
1328 | 1362 | ||
1329 | return sl; | 1363 | return sl; |
1330 | } | 1364 | } |
1331 | 1365 | ||
1332 | /* Show an event */ | 1366 | /* Show an event */ |
1333 | static int show_perf_probe_event(struct perf_probe_event *pev) | 1367 | static int show_perf_probe_event(struct perf_probe_event *pev) |
1334 | { | 1368 | { |
1335 | int i, ret; | 1369 | int i, ret; |
1336 | char buf[128]; | 1370 | char buf[128]; |
1337 | char *place; | 1371 | char *place; |
1338 | 1372 | ||
1339 | /* Synthesize only event probe point */ | 1373 | /* Synthesize only event probe point */ |
1340 | place = synthesize_perf_probe_point(&pev->point); | 1374 | place = synthesize_perf_probe_point(&pev->point); |
1341 | if (!place) | 1375 | if (!place) |
1342 | return -EINVAL; | 1376 | return -EINVAL; |
1343 | 1377 | ||
1344 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); | 1378 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); |
1345 | if (ret < 0) | 1379 | if (ret < 0) |
1346 | return ret; | 1380 | return ret; |
1347 | 1381 | ||
1348 | printf(" %-20s (on %s", buf, place); | 1382 | printf(" %-20s (on %s", buf, place); |
1349 | 1383 | ||
1350 | if (pev->nargs > 0) { | 1384 | if (pev->nargs > 0) { |
1351 | printf(" with"); | 1385 | printf(" with"); |
1352 | for (i = 0; i < pev->nargs; i++) { | 1386 | for (i = 0; i < pev->nargs; i++) { |
1353 | ret = synthesize_perf_probe_arg(&pev->args[i], | 1387 | ret = synthesize_perf_probe_arg(&pev->args[i], |
1354 | buf, 128); | 1388 | buf, 128); |
1355 | if (ret < 0) | 1389 | if (ret < 0) |
1356 | break; | 1390 | break; |
1357 | printf(" %s", buf); | 1391 | printf(" %s", buf); |
1358 | } | 1392 | } |
1359 | } | 1393 | } |
1360 | printf(")\n"); | 1394 | printf(")\n"); |
1361 | free(place); | 1395 | free(place); |
1362 | return ret; | 1396 | return ret; |
1363 | } | 1397 | } |
1364 | 1398 | ||
1365 | /* List up current perf-probe events */ | 1399 | /* List up current perf-probe events */ |
1366 | int show_perf_probe_events(void) | 1400 | int show_perf_probe_events(void) |
1367 | { | 1401 | { |
1368 | int fd, ret; | 1402 | int fd, ret; |
1369 | struct probe_trace_event tev; | 1403 | struct probe_trace_event tev; |
1370 | struct perf_probe_event pev; | 1404 | struct perf_probe_event pev; |
1371 | struct strlist *rawlist; | 1405 | struct strlist *rawlist; |
1372 | struct str_node *ent; | 1406 | struct str_node *ent; |
1373 | 1407 | ||
1374 | setup_pager(); | 1408 | setup_pager(); |
1375 | ret = init_vmlinux(); | 1409 | ret = init_vmlinux(); |
1376 | if (ret < 0) | 1410 | if (ret < 0) |
1377 | return ret; | 1411 | return ret; |
1378 | 1412 | ||
1379 | memset(&tev, 0, sizeof(tev)); | 1413 | memset(&tev, 0, sizeof(tev)); |
1380 | memset(&pev, 0, sizeof(pev)); | 1414 | memset(&pev, 0, sizeof(pev)); |
1381 | 1415 | ||
1382 | fd = open_kprobe_events(false); | 1416 | fd = open_kprobe_events(false); |
1383 | if (fd < 0) | 1417 | if (fd < 0) |
1384 | return fd; | 1418 | return fd; |
1385 | 1419 | ||
1386 | rawlist = get_probe_trace_command_rawlist(fd); | 1420 | rawlist = get_probe_trace_command_rawlist(fd); |
1387 | close(fd); | 1421 | close(fd); |
1388 | if (!rawlist) | 1422 | if (!rawlist) |
1389 | return -ENOENT; | 1423 | return -ENOENT; |
1390 | 1424 | ||
1391 | strlist__for_each(ent, rawlist) { | 1425 | strlist__for_each(ent, rawlist) { |
1392 | ret = parse_probe_trace_command(ent->s, &tev); | 1426 | ret = parse_probe_trace_command(ent->s, &tev); |
1393 | if (ret >= 0) { | 1427 | if (ret >= 0) { |
1394 | ret = convert_to_perf_probe_event(&tev, &pev); | 1428 | ret = convert_to_perf_probe_event(&tev, &pev); |
1395 | if (ret >= 0) | 1429 | if (ret >= 0) |
1396 | ret = show_perf_probe_event(&pev); | 1430 | ret = show_perf_probe_event(&pev); |
1397 | } | 1431 | } |
1398 | clear_perf_probe_event(&pev); | 1432 | clear_perf_probe_event(&pev); |
1399 | clear_probe_trace_event(&tev); | 1433 | clear_probe_trace_event(&tev); |
1400 | if (ret < 0) | 1434 | if (ret < 0) |
1401 | break; | 1435 | break; |
1402 | } | 1436 | } |
1403 | strlist__delete(rawlist); | 1437 | strlist__delete(rawlist); |
1404 | 1438 | ||
1405 | return ret; | 1439 | return ret; |
1406 | } | 1440 | } |
1407 | 1441 | ||
1408 | /* Get current perf-probe event names */ | 1442 | /* Get current perf-probe event names */ |
1409 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) | 1443 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) |
1410 | { | 1444 | { |
1411 | char buf[128]; | 1445 | char buf[128]; |
1412 | struct strlist *sl, *rawlist; | 1446 | struct strlist *sl, *rawlist; |
1413 | struct str_node *ent; | 1447 | struct str_node *ent; |
1414 | struct probe_trace_event tev; | 1448 | struct probe_trace_event tev; |
1415 | int ret = 0; | 1449 | int ret = 0; |
1416 | 1450 | ||
1417 | memset(&tev, 0, sizeof(tev)); | 1451 | memset(&tev, 0, sizeof(tev)); |
1418 | rawlist = get_probe_trace_command_rawlist(fd); | 1452 | rawlist = get_probe_trace_command_rawlist(fd); |
1419 | sl = strlist__new(true, NULL); | 1453 | sl = strlist__new(true, NULL); |
1420 | strlist__for_each(ent, rawlist) { | 1454 | strlist__for_each(ent, rawlist) { |
1421 | ret = parse_probe_trace_command(ent->s, &tev); | 1455 | ret = parse_probe_trace_command(ent->s, &tev); |
1422 | if (ret < 0) | 1456 | if (ret < 0) |
1423 | break; | 1457 | break; |
1424 | if (include_group) { | 1458 | if (include_group) { |
1425 | ret = e_snprintf(buf, 128, "%s:%s", tev.group, | 1459 | ret = e_snprintf(buf, 128, "%s:%s", tev.group, |
1426 | tev.event); | 1460 | tev.event); |
1427 | if (ret >= 0) | 1461 | if (ret >= 0) |
1428 | ret = strlist__add(sl, buf); | 1462 | ret = strlist__add(sl, buf); |
1429 | } else | 1463 | } else |
1430 | ret = strlist__add(sl, tev.event); | 1464 | ret = strlist__add(sl, tev.event); |
1431 | clear_probe_trace_event(&tev); | 1465 | clear_probe_trace_event(&tev); |
1432 | if (ret < 0) | 1466 | if (ret < 0) |
1433 | break; | 1467 | break; |
1434 | } | 1468 | } |
1435 | strlist__delete(rawlist); | 1469 | strlist__delete(rawlist); |
1436 | 1470 | ||
1437 | if (ret < 0) { | 1471 | if (ret < 0) { |
1438 | strlist__delete(sl); | 1472 | strlist__delete(sl); |
1439 | return NULL; | 1473 | return NULL; |
1440 | } | 1474 | } |
1441 | return sl; | 1475 | return sl; |
1442 | } | 1476 | } |
1443 | 1477 | ||
1444 | static int write_probe_trace_event(int fd, struct probe_trace_event *tev) | 1478 | static int write_probe_trace_event(int fd, struct probe_trace_event *tev) |
1445 | { | 1479 | { |
1446 | int ret = 0; | 1480 | int ret = 0; |
1447 | char *buf = synthesize_probe_trace_command(tev); | 1481 | char *buf = synthesize_probe_trace_command(tev); |
1448 | 1482 | ||
1449 | if (!buf) { | 1483 | if (!buf) { |
1450 | pr_debug("Failed to synthesize probe trace event.\n"); | 1484 | pr_debug("Failed to synthesize probe trace event.\n"); |
1451 | return -EINVAL; | 1485 | return -EINVAL; |
1452 | } | 1486 | } |
1453 | 1487 | ||
1454 | pr_debug("Writing event: %s\n", buf); | 1488 | pr_debug("Writing event: %s\n", buf); |
1455 | if (!probe_event_dry_run) { | 1489 | if (!probe_event_dry_run) { |
1456 | ret = write(fd, buf, strlen(buf)); | 1490 | ret = write(fd, buf, strlen(buf)); |
1457 | if (ret <= 0) | 1491 | if (ret <= 0) |
1458 | pr_warning("Failed to write event: %s\n", | 1492 | pr_warning("Failed to write event: %s\n", |
1459 | strerror(errno)); | 1493 | strerror(errno)); |
1460 | } | 1494 | } |
1461 | free(buf); | 1495 | free(buf); |
1462 | return ret; | 1496 | return ret; |
1463 | } | 1497 | } |
1464 | 1498 | ||
1465 | static int get_new_event_name(char *buf, size_t len, const char *base, | 1499 | static int get_new_event_name(char *buf, size_t len, const char *base, |
1466 | struct strlist *namelist, bool allow_suffix) | 1500 | struct strlist *namelist, bool allow_suffix) |
1467 | { | 1501 | { |
1468 | int i, ret; | 1502 | int i, ret; |
1469 | 1503 | ||
1470 | /* Try no suffix */ | 1504 | /* Try no suffix */ |
1471 | ret = e_snprintf(buf, len, "%s", base); | 1505 | ret = e_snprintf(buf, len, "%s", base); |
1472 | if (ret < 0) { | 1506 | if (ret < 0) { |
1473 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); | 1507 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); |
1474 | return ret; | 1508 | return ret; |
1475 | } | 1509 | } |
1476 | if (!strlist__has_entry(namelist, buf)) | 1510 | if (!strlist__has_entry(namelist, buf)) |
1477 | return 0; | 1511 | return 0; |
1478 | 1512 | ||
1479 | if (!allow_suffix) { | 1513 | if (!allow_suffix) { |
1480 | pr_warning("Error: event \"%s\" already exists. " | 1514 | pr_warning("Error: event \"%s\" already exists. " |
1481 | "(Use -f to force duplicates.)\n", base); | 1515 | "(Use -f to force duplicates.)\n", base); |
1482 | return -EEXIST; | 1516 | return -EEXIST; |
1483 | } | 1517 | } |
1484 | 1518 | ||
1485 | /* Try to add suffix */ | 1519 | /* Try to add suffix */ |
1486 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | 1520 | for (i = 1; i < MAX_EVENT_INDEX; i++) { |
1487 | ret = e_snprintf(buf, len, "%s_%d", base, i); | 1521 | ret = e_snprintf(buf, len, "%s_%d", base, i); |
1488 | if (ret < 0) { | 1522 | if (ret < 0) { |
1489 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); | 1523 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); |
1490 | return ret; | 1524 | return ret; |
1491 | } | 1525 | } |
1492 | if (!strlist__has_entry(namelist, buf)) | 1526 | if (!strlist__has_entry(namelist, buf)) |
1493 | break; | 1527 | break; |
1494 | } | 1528 | } |
1495 | if (i == MAX_EVENT_INDEX) { | 1529 | if (i == MAX_EVENT_INDEX) { |
1496 | pr_warning("Too many events are on the same function.\n"); | 1530 | pr_warning("Too many events are on the same function.\n"); |
1497 | ret = -ERANGE; | 1531 | ret = -ERANGE; |
1498 | } | 1532 | } |
1499 | 1533 | ||
1500 | return ret; | 1534 | return ret; |
1501 | } | 1535 | } |
1502 | 1536 | ||
1503 | static int __add_probe_trace_events(struct perf_probe_event *pev, | 1537 | static int __add_probe_trace_events(struct perf_probe_event *pev, |
1504 | struct probe_trace_event *tevs, | 1538 | struct probe_trace_event *tevs, |
1505 | int ntevs, bool allow_suffix) | 1539 | int ntevs, bool allow_suffix) |
1506 | { | 1540 | { |
1507 | int i, fd, ret; | 1541 | int i, fd, ret; |
1508 | struct probe_trace_event *tev = NULL; | 1542 | struct probe_trace_event *tev = NULL; |
1509 | char buf[64]; | 1543 | char buf[64]; |
1510 | const char *event, *group; | 1544 | const char *event, *group; |
1511 | struct strlist *namelist; | 1545 | struct strlist *namelist; |
1512 | 1546 | ||
1513 | fd = open_kprobe_events(true); | 1547 | fd = open_kprobe_events(true); |
1514 | if (fd < 0) | 1548 | if (fd < 0) |
1515 | return fd; | 1549 | return fd; |
1516 | /* Get current event names */ | 1550 | /* Get current event names */ |
1517 | namelist = get_probe_trace_event_names(fd, false); | 1551 | namelist = get_probe_trace_event_names(fd, false); |
1518 | if (!namelist) { | 1552 | if (!namelist) { |
1519 | pr_debug("Failed to get current event list.\n"); | 1553 | pr_debug("Failed to get current event list.\n"); |
1520 | return -EIO; | 1554 | return -EIO; |
1521 | } | 1555 | } |
1522 | 1556 | ||
1523 | ret = 0; | 1557 | ret = 0; |
1524 | printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); | 1558 | printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); |
1525 | for (i = 0; i < ntevs; i++) { | 1559 | for (i = 0; i < ntevs; i++) { |
1526 | tev = &tevs[i]; | 1560 | tev = &tevs[i]; |
1527 | if (pev->event) | 1561 | if (pev->event) |
1528 | event = pev->event; | 1562 | event = pev->event; |
1529 | else | 1563 | else |
1530 | if (pev->point.function) | 1564 | if (pev->point.function) |
1531 | event = pev->point.function; | 1565 | event = pev->point.function; |
1532 | else | 1566 | else |
1533 | event = tev->point.symbol; | 1567 | event = tev->point.symbol; |
1534 | if (pev->group) | 1568 | if (pev->group) |
1535 | group = pev->group; | 1569 | group = pev->group; |
1536 | else | 1570 | else |
1537 | group = PERFPROBE_GROUP; | 1571 | group = PERFPROBE_GROUP; |
1538 | 1572 | ||
1539 | /* Get an unused new event name */ | 1573 | /* Get an unused new event name */ |
1540 | ret = get_new_event_name(buf, 64, event, | 1574 | ret = get_new_event_name(buf, 64, event, |
1541 | namelist, allow_suffix); | 1575 | namelist, allow_suffix); |
1542 | if (ret < 0) | 1576 | if (ret < 0) |
1543 | break; | 1577 | break; |
1544 | event = buf; | 1578 | event = buf; |
1545 | 1579 | ||
1546 | tev->event = strdup(event); | 1580 | tev->event = strdup(event); |
1547 | tev->group = strdup(group); | 1581 | tev->group = strdup(group); |
1548 | if (tev->event == NULL || tev->group == NULL) { | 1582 | if (tev->event == NULL || tev->group == NULL) { |
1549 | ret = -ENOMEM; | 1583 | ret = -ENOMEM; |
1550 | break; | 1584 | break; |
1551 | } | 1585 | } |
1552 | ret = write_probe_trace_event(fd, tev); | 1586 | ret = write_probe_trace_event(fd, tev); |
1553 | if (ret < 0) | 1587 | if (ret < 0) |
1554 | break; | 1588 | break; |
1555 | /* Add added event name to namelist */ | 1589 | /* Add added event name to namelist */ |
1556 | strlist__add(namelist, event); | 1590 | strlist__add(namelist, event); |
1557 | 1591 | ||
1558 | /* Trick here - save current event/group */ | 1592 | /* Trick here - save current event/group */ |
1559 | event = pev->event; | 1593 | event = pev->event; |
1560 | group = pev->group; | 1594 | group = pev->group; |
1561 | pev->event = tev->event; | 1595 | pev->event = tev->event; |
1562 | pev->group = tev->group; | 1596 | pev->group = tev->group; |
1563 | show_perf_probe_event(pev); | 1597 | show_perf_probe_event(pev); |
1564 | /* Trick here - restore current event/group */ | 1598 | /* Trick here - restore current event/group */ |
1565 | pev->event = (char *)event; | 1599 | pev->event = (char *)event; |
1566 | pev->group = (char *)group; | 1600 | pev->group = (char *)group; |
1567 | 1601 | ||
1568 | /* | 1602 | /* |
1569 | * Probes after the first probe which comes from same | 1603 | * Probes after the first probe which comes from same |
1570 | * user input are always allowed to add suffix, because | 1604 | * user input are always allowed to add suffix, because |
1571 | * there might be several addresses corresponding to | 1605 | * there might be several addresses corresponding to |
1572 | * one code line. | 1606 | * one code line. |
1573 | */ | 1607 | */ |
1574 | allow_suffix = true; | 1608 | allow_suffix = true; |
1575 | } | 1609 | } |
1576 | 1610 | ||
1577 | if (ret >= 0) { | 1611 | if (ret >= 0) { |
1578 | /* Show how to use the event. */ | 1612 | /* Show how to use the event. */ |
1579 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | 1613 | printf("\nYou can now use it on all perf tools, such as:\n\n"); |
1580 | printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, | 1614 | printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, |
1581 | tev->event); | 1615 | tev->event); |
1582 | } | 1616 | } |
1583 | 1617 | ||
1584 | strlist__delete(namelist); | 1618 | strlist__delete(namelist); |
1585 | close(fd); | 1619 | close(fd); |
1586 | return ret; | 1620 | return ret; |
1587 | } | 1621 | } |
1588 | 1622 | ||
1589 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, | 1623 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, |
1590 | struct probe_trace_event **tevs, | 1624 | struct probe_trace_event **tevs, |
1591 | int max_tevs) | 1625 | int max_tevs, const char *module) |
1592 | { | 1626 | { |
1593 | struct symbol *sym; | 1627 | struct symbol *sym; |
1594 | int ret = 0, i; | 1628 | int ret = 0, i; |
1595 | struct probe_trace_event *tev; | 1629 | struct probe_trace_event *tev; |
1596 | 1630 | ||
1597 | /* Convert perf_probe_event with debuginfo */ | 1631 | /* Convert perf_probe_event with debuginfo */ |
1598 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); | 1632 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); |
1599 | if (ret != 0) | 1633 | if (ret != 0) |
1600 | return ret; | 1634 | return ret; |
1601 | 1635 | ||
1602 | /* Allocate trace event buffer */ | 1636 | /* Allocate trace event buffer */ |
1603 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); | 1637 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); |
1604 | if (tev == NULL) | 1638 | if (tev == NULL) |
1605 | return -ENOMEM; | 1639 | return -ENOMEM; |
1606 | 1640 | ||
1607 | /* Copy parameters */ | 1641 | /* Copy parameters */ |
1608 | tev->point.symbol = strdup(pev->point.function); | 1642 | tev->point.symbol = strdup(pev->point.function); |
1609 | if (tev->point.symbol == NULL) { | 1643 | if (tev->point.symbol == NULL) { |
1610 | ret = -ENOMEM; | 1644 | ret = -ENOMEM; |
1611 | goto error; | 1645 | goto error; |
1612 | } | 1646 | } |
1613 | tev->point.offset = pev->point.offset; | 1647 | tev->point.offset = pev->point.offset; |
1614 | tev->point.retprobe = pev->point.retprobe; | 1648 | tev->point.retprobe = pev->point.retprobe; |
1615 | tev->nargs = pev->nargs; | 1649 | tev->nargs = pev->nargs; |
1616 | if (tev->nargs) { | 1650 | if (tev->nargs) { |
1617 | tev->args = zalloc(sizeof(struct probe_trace_arg) | 1651 | tev->args = zalloc(sizeof(struct probe_trace_arg) |
1618 | * tev->nargs); | 1652 | * tev->nargs); |
1619 | if (tev->args == NULL) { | 1653 | if (tev->args == NULL) { |
1620 | ret = -ENOMEM; | 1654 | ret = -ENOMEM; |
1621 | goto error; | 1655 | goto error; |
1622 | } | 1656 | } |
1623 | for (i = 0; i < tev->nargs; i++) { | 1657 | for (i = 0; i < tev->nargs; i++) { |
1624 | if (pev->args[i].name) { | 1658 | if (pev->args[i].name) { |
1625 | tev->args[i].name = strdup(pev->args[i].name); | 1659 | tev->args[i].name = strdup(pev->args[i].name); |
1626 | if (tev->args[i].name == NULL) { | 1660 | if (tev->args[i].name == NULL) { |
1627 | ret = -ENOMEM; | 1661 | ret = -ENOMEM; |
1628 | goto error; | 1662 | goto error; |
1629 | } | 1663 | } |
1630 | } | 1664 | } |
1631 | tev->args[i].value = strdup(pev->args[i].var); | 1665 | tev->args[i].value = strdup(pev->args[i].var); |
1632 | if (tev->args[i].value == NULL) { | 1666 | if (tev->args[i].value == NULL) { |
1633 | ret = -ENOMEM; | 1667 | ret = -ENOMEM; |
1634 | goto error; | 1668 | goto error; |
1635 | } | 1669 | } |
1636 | if (pev->args[i].type) { | 1670 | if (pev->args[i].type) { |
1637 | tev->args[i].type = strdup(pev->args[i].type); | 1671 | tev->args[i].type = strdup(pev->args[i].type); |
1638 | if (tev->args[i].type == NULL) { | 1672 | if (tev->args[i].type == NULL) { |
1639 | ret = -ENOMEM; | 1673 | ret = -ENOMEM; |
1640 | goto error; | 1674 | goto error; |
1641 | } | 1675 | } |
1642 | } | 1676 | } |
1643 | } | 1677 | } |
1644 | } | 1678 | } |
1645 | 1679 | ||
1646 | /* Currently just checking function name from symbol map */ | 1680 | /* Currently just checking function name from symbol map */ |
1647 | sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], | 1681 | sym = __find_kernel_function_by_name(tev->point.symbol, NULL); |
1648 | tev->point.symbol, NULL); | ||
1649 | if (!sym) { | 1682 | if (!sym) { |
1650 | pr_warning("Kernel symbol \'%s\' not found.\n", | 1683 | pr_warning("Kernel symbol \'%s\' not found.\n", |
1651 | tev->point.symbol); | 1684 | tev->point.symbol); |
1652 | ret = -ENOENT; | 1685 | ret = -ENOENT; |
1653 | goto error; | 1686 | goto error; |
1654 | } | 1687 | } |
1655 | 1688 | ||
1656 | return 1; | 1689 | return 1; |
1657 | error: | 1690 | error: |
1658 | clear_probe_trace_event(tev); | 1691 | clear_probe_trace_event(tev); |
1659 | free(tev); | 1692 | free(tev); |
1660 | *tevs = NULL; | 1693 | *tevs = NULL; |
1661 | return ret; | 1694 | return ret; |
1662 | } | 1695 | } |
1663 | 1696 | ||
1664 | struct __event_package { | 1697 | struct __event_package { |
1665 | struct perf_probe_event *pev; | 1698 | struct perf_probe_event *pev; |
1666 | struct probe_trace_event *tevs; | 1699 | struct probe_trace_event *tevs; |
1667 | int ntevs; | 1700 | int ntevs; |
1668 | }; | 1701 | }; |
1669 | 1702 | ||
1670 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | 1703 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, |
1671 | int max_tevs, bool force_add) | 1704 | int max_tevs, const char *module, bool force_add) |
1672 | { | 1705 | { |
1673 | int i, j, ret; | 1706 | int i, j, ret; |
1674 | struct __event_package *pkgs; | 1707 | struct __event_package *pkgs; |
1675 | 1708 | ||
1676 | pkgs = zalloc(sizeof(struct __event_package) * npevs); | 1709 | pkgs = zalloc(sizeof(struct __event_package) * npevs); |
1677 | if (pkgs == NULL) | 1710 | if (pkgs == NULL) |
1678 | return -ENOMEM; | 1711 | return -ENOMEM; |
1679 | 1712 | ||
1680 | /* Init vmlinux path */ | 1713 | /* Init vmlinux path */ |
1681 | ret = init_vmlinux(); | 1714 | ret = init_vmlinux(); |
1682 | if (ret < 0) { | 1715 | if (ret < 0) { |
1683 | free(pkgs); | 1716 | free(pkgs); |
1684 | return ret; | 1717 | return ret; |
1685 | } | 1718 | } |
1686 | 1719 | ||
1687 | /* Loop 1: convert all events */ | 1720 | /* Loop 1: convert all events */ |
1688 | for (i = 0; i < npevs; i++) { | 1721 | for (i = 0; i < npevs; i++) { |
1689 | pkgs[i].pev = &pevs[i]; | 1722 | pkgs[i].pev = &pevs[i]; |
1690 | /* Convert with or without debuginfo */ | 1723 | /* Convert with or without debuginfo */ |
1691 | ret = convert_to_probe_trace_events(pkgs[i].pev, | 1724 | ret = convert_to_probe_trace_events(pkgs[i].pev, |
1692 | &pkgs[i].tevs, max_tevs); | 1725 | &pkgs[i].tevs, |
1726 | max_tevs, | ||
1727 | module); | ||
1693 | if (ret < 0) | 1728 | if (ret < 0) |
1694 | goto end; | 1729 | goto end; |
1695 | pkgs[i].ntevs = ret; | 1730 | pkgs[i].ntevs = ret; |
1696 | } | 1731 | } |
1697 | 1732 | ||
1698 | /* Loop 2: add all events */ | 1733 | /* Loop 2: add all events */ |
1699 | for (i = 0; i < npevs && ret >= 0; i++) | 1734 | for (i = 0; i < npevs && ret >= 0; i++) |
1700 | ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, | 1735 | ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, |
1701 | pkgs[i].ntevs, force_add); | 1736 | pkgs[i].ntevs, force_add); |
1702 | end: | 1737 | end: |
1703 | /* Loop 3: cleanup and free trace events */ | 1738 | /* Loop 3: cleanup and free trace events */ |
1704 | for (i = 0; i < npevs; i++) { | 1739 | for (i = 0; i < npevs; i++) { |
1705 | for (j = 0; j < pkgs[i].ntevs; j++) | 1740 | for (j = 0; j < pkgs[i].ntevs; j++) |
1706 | clear_probe_trace_event(&pkgs[i].tevs[j]); | 1741 | clear_probe_trace_event(&pkgs[i].tevs[j]); |
1707 | free(pkgs[i].tevs); | 1742 | free(pkgs[i].tevs); |
1708 | } | 1743 | } |
1709 | free(pkgs); | 1744 | free(pkgs); |
1710 | 1745 | ||
1711 | return ret; | 1746 | return ret; |
1712 | } | 1747 | } |
1713 | 1748 | ||
1714 | static int __del_trace_probe_event(int fd, struct str_node *ent) | 1749 | static int __del_trace_probe_event(int fd, struct str_node *ent) |
1715 | { | 1750 | { |
1716 | char *p; | 1751 | char *p; |
1717 | char buf[128]; | 1752 | char buf[128]; |
1718 | int ret; | 1753 | int ret; |
1719 | 1754 | ||
1720 | /* Convert from perf-probe event to trace-probe event */ | 1755 | /* Convert from perf-probe event to trace-probe event */ |
1721 | ret = e_snprintf(buf, 128, "-:%s", ent->s); | 1756 | ret = e_snprintf(buf, 128, "-:%s", ent->s); |
1722 | if (ret < 0) | 1757 | if (ret < 0) |
1723 | goto error; | 1758 | goto error; |
1724 | 1759 | ||
1725 | p = strchr(buf + 2, ':'); | 1760 | p = strchr(buf + 2, ':'); |
1726 | if (!p) { | 1761 | if (!p) { |
1727 | pr_debug("Internal error: %s should have ':' but not.\n", | 1762 | pr_debug("Internal error: %s should have ':' but not.\n", |
1728 | ent->s); | 1763 | ent->s); |
1729 | ret = -ENOTSUP; | 1764 | ret = -ENOTSUP; |
1730 | goto error; | 1765 | goto error; |
1731 | } | 1766 | } |
1732 | *p = '/'; | 1767 | *p = '/'; |
1733 | 1768 | ||
1734 | pr_debug("Writing event: %s\n", buf); | 1769 | pr_debug("Writing event: %s\n", buf); |
1735 | ret = write(fd, buf, strlen(buf)); | 1770 | ret = write(fd, buf, strlen(buf)); |
1736 | if (ret < 0) | 1771 | if (ret < 0) |
1737 | goto error; | 1772 | goto error; |
1738 | 1773 | ||
1739 | printf("Remove event: %s\n", ent->s); | 1774 | printf("Remove event: %s\n", ent->s); |
1740 | return 0; | 1775 | return 0; |
1741 | error: | 1776 | error: |
1742 | pr_warning("Failed to delete event: %s\n", strerror(-ret)); | 1777 | pr_warning("Failed to delete event: %s\n", strerror(-ret)); |
1743 | return ret; | 1778 | return ret; |
1744 | } | 1779 | } |
1745 | 1780 | ||
1746 | static int del_trace_probe_event(int fd, const char *group, | 1781 | static int del_trace_probe_event(int fd, const char *group, |
1747 | const char *event, struct strlist *namelist) | 1782 | const char *event, struct strlist *namelist) |
1748 | { | 1783 | { |
1749 | char buf[128]; | 1784 | char buf[128]; |
1750 | struct str_node *ent, *n; | 1785 | struct str_node *ent, *n; |
1751 | int found = 0, ret = 0; | 1786 | int found = 0, ret = 0; |
1752 | 1787 | ||
1753 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | 1788 | ret = e_snprintf(buf, 128, "%s:%s", group, event); |
1754 | if (ret < 0) { | 1789 | if (ret < 0) { |
1755 | pr_err("Failed to copy event."); | 1790 | pr_err("Failed to copy event."); |
1756 | return ret; | 1791 | return ret; |
1757 | } | 1792 | } |
1758 | 1793 | ||
1759 | if (strpbrk(buf, "*?")) { /* Glob-exp */ | 1794 | if (strpbrk(buf, "*?")) { /* Glob-exp */ |
1760 | strlist__for_each_safe(ent, n, namelist) | 1795 | strlist__for_each_safe(ent, n, namelist) |
1761 | if (strglobmatch(ent->s, buf)) { | 1796 | if (strglobmatch(ent->s, buf)) { |
1762 | found++; | 1797 | found++; |
1763 | ret = __del_trace_probe_event(fd, ent); | 1798 | ret = __del_trace_probe_event(fd, ent); |
1764 | if (ret < 0) | 1799 | if (ret < 0) |
1765 | break; | 1800 | break; |
1766 | strlist__remove(namelist, ent); | 1801 | strlist__remove(namelist, ent); |
1767 | } | 1802 | } |
1768 | } else { | 1803 | } else { |
1769 | ent = strlist__find(namelist, buf); | 1804 | ent = strlist__find(namelist, buf); |
1770 | if (ent) { | 1805 | if (ent) { |
1771 | found++; | 1806 | found++; |
1772 | ret = __del_trace_probe_event(fd, ent); | 1807 | ret = __del_trace_probe_event(fd, ent); |
1773 | if (ret >= 0) | 1808 | if (ret >= 0) |
1774 | strlist__remove(namelist, ent); | 1809 | strlist__remove(namelist, ent); |
1775 | } | 1810 | } |
1776 | } | 1811 | } |
1777 | if (found == 0 && ret >= 0) | 1812 | if (found == 0 && ret >= 0) |
1778 | pr_info("Info: Event \"%s\" does not exist.\n", buf); | 1813 | pr_info("Info: Event \"%s\" does not exist.\n", buf); |
1779 | 1814 | ||
1780 | return ret; | 1815 | return ret; |
1781 | } | 1816 | } |
1782 | 1817 | ||
1783 | int del_perf_probe_events(struct strlist *dellist) | 1818 | int del_perf_probe_events(struct strlist *dellist) |
1784 | { | 1819 | { |
1785 | int fd, ret = 0; | 1820 | int fd, ret = 0; |
1786 | const char *group, *event; | 1821 | const char *group, *event; |
1787 | char *p, *str; | 1822 | char *p, *str; |
1788 | struct str_node *ent; | 1823 | struct str_node *ent; |
1789 | struct strlist *namelist; | 1824 | struct strlist *namelist; |
1790 | 1825 | ||
1791 | fd = open_kprobe_events(true); | 1826 | fd = open_kprobe_events(true); |
1792 | if (fd < 0) | 1827 | if (fd < 0) |
1793 | return fd; | 1828 | return fd; |
1794 | 1829 | ||
1795 | /* Get current event names */ | 1830 | /* Get current event names */ |
1796 | namelist = get_probe_trace_event_names(fd, true); | 1831 | namelist = get_probe_trace_event_names(fd, true); |
1797 | if (namelist == NULL) | 1832 | if (namelist == NULL) |
1798 | return -EINVAL; | 1833 | return -EINVAL; |
1799 | 1834 | ||
1800 | strlist__for_each(ent, dellist) { | 1835 | strlist__for_each(ent, dellist) { |
1801 | str = strdup(ent->s); | 1836 | str = strdup(ent->s); |
1802 | if (str == NULL) { | 1837 | if (str == NULL) { |
1803 | ret = -ENOMEM; | 1838 | ret = -ENOMEM; |
1804 | break; | 1839 | break; |
1805 | } | 1840 | } |
1806 | pr_debug("Parsing: %s\n", str); | 1841 | pr_debug("Parsing: %s\n", str); |
1807 | p = strchr(str, ':'); | 1842 | p = strchr(str, ':'); |
1808 | if (p) { | 1843 | if (p) { |
1809 | group = str; | 1844 | group = str; |
1810 | *p = '\0'; | 1845 | *p = '\0'; |
1811 | event = p + 1; | 1846 | event = p + 1; |
1812 | } else { | 1847 | } else { |
1813 | group = "*"; | 1848 | group = "*"; |
1814 | event = str; | 1849 | event = str; |
1815 | } | 1850 | } |
1816 | pr_debug("Group: %s, Event: %s\n", group, event); | 1851 | pr_debug("Group: %s, Event: %s\n", group, event); |
1817 | ret = del_trace_probe_event(fd, group, event, namelist); | 1852 | ret = del_trace_probe_event(fd, group, event, namelist); |
1818 | free(str); | 1853 | free(str); |
1819 | if (ret < 0) | 1854 | if (ret < 0) |
tools/perf/util/probe-event.h
1 | #ifndef _PROBE_EVENT_H | 1 | #ifndef _PROBE_EVENT_H |
2 | #define _PROBE_EVENT_H | 2 | #define _PROBE_EVENT_H |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include "strlist.h" | 5 | #include "strlist.h" |
6 | 6 | ||
7 | extern bool probe_event_dry_run; | 7 | extern bool probe_event_dry_run; |
8 | 8 | ||
9 | /* kprobe-tracer tracing point */ | 9 | /* kprobe-tracer tracing point */ |
10 | struct probe_trace_point { | 10 | struct probe_trace_point { |
11 | char *symbol; /* Base symbol */ | 11 | char *symbol; /* Base symbol */ |
12 | unsigned long offset; /* Offset from symbol */ | 12 | unsigned long offset; /* Offset from symbol */ |
13 | bool retprobe; /* Return probe flag */ | 13 | bool retprobe; /* Return probe flag */ |
14 | }; | 14 | }; |
15 | 15 | ||
16 | /* probe-tracer tracing argument referencing offset */ | 16 | /* probe-tracer tracing argument referencing offset */ |
17 | struct probe_trace_arg_ref { | 17 | struct probe_trace_arg_ref { |
18 | struct probe_trace_arg_ref *next; /* Next reference */ | 18 | struct probe_trace_arg_ref *next; /* Next reference */ |
19 | long offset; /* Offset value */ | 19 | long offset; /* Offset value */ |
20 | }; | 20 | }; |
21 | 21 | ||
22 | /* kprobe-tracer tracing argument */ | 22 | /* kprobe-tracer tracing argument */ |
23 | struct probe_trace_arg { | 23 | struct probe_trace_arg { |
24 | char *name; /* Argument name */ | 24 | char *name; /* Argument name */ |
25 | char *value; /* Base value */ | 25 | char *value; /* Base value */ |
26 | char *type; /* Type name */ | 26 | char *type; /* Type name */ |
27 | struct probe_trace_arg_ref *ref; /* Referencing offset */ | 27 | struct probe_trace_arg_ref *ref; /* Referencing offset */ |
28 | }; | 28 | }; |
29 | 29 | ||
30 | /* kprobe-tracer tracing event (point + arg) */ | 30 | /* kprobe-tracer tracing event (point + arg) */ |
31 | struct probe_trace_event { | 31 | struct probe_trace_event { |
32 | char *event; /* Event name */ | 32 | char *event; /* Event name */ |
33 | char *group; /* Group name */ | 33 | char *group; /* Group name */ |
34 | struct probe_trace_point point; /* Trace point */ | 34 | struct probe_trace_point point; /* Trace point */ |
35 | int nargs; /* Number of args */ | 35 | int nargs; /* Number of args */ |
36 | struct probe_trace_arg *args; /* Arguments */ | 36 | struct probe_trace_arg *args; /* Arguments */ |
37 | }; | 37 | }; |
38 | 38 | ||
39 | /* Perf probe probing point */ | 39 | /* Perf probe probing point */ |
40 | struct perf_probe_point { | 40 | struct perf_probe_point { |
41 | char *file; /* File path */ | 41 | char *file; /* File path */ |
42 | char *function; /* Function name */ | 42 | char *function; /* Function name */ |
43 | int line; /* Line number */ | 43 | int line; /* Line number */ |
44 | bool retprobe; /* Return probe flag */ | 44 | bool retprobe; /* Return probe flag */ |
45 | char *lazy_line; /* Lazy matching pattern */ | 45 | char *lazy_line; /* Lazy matching pattern */ |
46 | unsigned long offset; /* Offset from function entry */ | 46 | unsigned long offset; /* Offset from function entry */ |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* Perf probe probing argument field chain */ | 49 | /* Perf probe probing argument field chain */ |
50 | struct perf_probe_arg_field { | 50 | struct perf_probe_arg_field { |
51 | struct perf_probe_arg_field *next; /* Next field */ | 51 | struct perf_probe_arg_field *next; /* Next field */ |
52 | char *name; /* Name of the field */ | 52 | char *name; /* Name of the field */ |
53 | long index; /* Array index number */ | 53 | long index; /* Array index number */ |
54 | bool ref; /* Referencing flag */ | 54 | bool ref; /* Referencing flag */ |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /* Perf probe probing argument */ | 57 | /* Perf probe probing argument */ |
58 | struct perf_probe_arg { | 58 | struct perf_probe_arg { |
59 | char *name; /* Argument name */ | 59 | char *name; /* Argument name */ |
60 | char *var; /* Variable name */ | 60 | char *var; /* Variable name */ |
61 | char *type; /* Type name */ | 61 | char *type; /* Type name */ |
62 | struct perf_probe_arg_field *field; /* Structure fields */ | 62 | struct perf_probe_arg_field *field; /* Structure fields */ |
63 | }; | 63 | }; |
64 | 64 | ||
65 | /* Perf probe probing event (point + arg) */ | 65 | /* Perf probe probing event (point + arg) */ |
66 | struct perf_probe_event { | 66 | struct perf_probe_event { |
67 | char *event; /* Event name */ | 67 | char *event; /* Event name */ |
68 | char *group; /* Group name */ | 68 | char *group; /* Group name */ |
69 | struct perf_probe_point point; /* Probe point */ | 69 | struct perf_probe_point point; /* Probe point */ |
70 | int nargs; /* Number of arguments */ | 70 | int nargs; /* Number of arguments */ |
71 | struct perf_probe_arg *args; /* Arguments */ | 71 | struct perf_probe_arg *args; /* Arguments */ |
72 | }; | 72 | }; |
73 | 73 | ||
74 | 74 | ||
75 | /* Line number container */ | 75 | /* Line number container */ |
76 | struct line_node { | 76 | struct line_node { |
77 | struct list_head list; | 77 | struct list_head list; |
78 | int line; | 78 | int line; |
79 | }; | 79 | }; |
80 | 80 | ||
81 | /* Line range */ | 81 | /* Line range */ |
82 | struct line_range { | 82 | struct line_range { |
83 | char *file; /* File name */ | 83 | char *file; /* File name */ |
84 | char *function; /* Function name */ | 84 | char *function; /* Function name */ |
85 | int start; /* Start line number */ | 85 | int start; /* Start line number */ |
86 | int end; /* End line number */ | 86 | int end; /* End line number */ |
87 | int offset; /* Start line offset */ | 87 | int offset; /* Start line offset */ |
88 | char *path; /* Real path name */ | 88 | char *path; /* Real path name */ |
89 | char *comp_dir; /* Compile directory */ | 89 | char *comp_dir; /* Compile directory */ |
90 | struct list_head line_list; /* Visible lines */ | 90 | struct list_head line_list; /* Visible lines */ |
91 | }; | 91 | }; |
92 | 92 | ||
93 | /* List of variables */ | 93 | /* List of variables */ |
94 | struct variable_list { | 94 | struct variable_list { |
95 | struct probe_trace_point point; /* Actual probepoint */ | 95 | struct probe_trace_point point; /* Actual probepoint */ |
96 | struct strlist *vars; /* Available variables */ | 96 | struct strlist *vars; /* Available variables */ |
97 | }; | 97 | }; |
98 | 98 | ||
99 | /* Command string to events */ | 99 | /* Command string to events */ |
100 | extern int parse_perf_probe_command(const char *cmd, | 100 | extern int parse_perf_probe_command(const char *cmd, |
101 | struct perf_probe_event *pev); | 101 | struct perf_probe_event *pev); |
102 | 102 | ||
103 | /* Events to command string */ | 103 | /* Events to command string */ |
104 | extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); | 104 | extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); |
105 | extern char *synthesize_probe_trace_command(struct probe_trace_event *tev); | 105 | extern char *synthesize_probe_trace_command(struct probe_trace_event *tev); |
106 | extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, | 106 | extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, |
107 | size_t len); | 107 | size_t len); |
108 | 108 | ||
109 | /* Check the perf_probe_event needs debuginfo */ | 109 | /* Check the perf_probe_event needs debuginfo */ |
110 | extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); | 110 | extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); |
111 | 111 | ||
112 | /* Release event contents */ | 112 | /* Release event contents */ |
113 | extern void clear_perf_probe_event(struct perf_probe_event *pev); | 113 | extern void clear_perf_probe_event(struct perf_probe_event *pev); |
114 | 114 | ||
115 | /* Command string to line-range */ | 115 | /* Command string to line-range */ |
116 | extern int parse_line_range_desc(const char *cmd, struct line_range *lr); | 116 | extern int parse_line_range_desc(const char *cmd, struct line_range *lr); |
117 | 117 | ||
118 | /* Internal use: Return kernel/module path */ | ||
119 | extern const char *kernel_get_module_path(const char *module); | ||
118 | 120 | ||
119 | extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | 121 | extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, |
120 | int max_probe_points, bool force_add); | 122 | int max_probe_points, const char *module, |
123 | bool force_add); | ||
121 | extern int del_perf_probe_events(struct strlist *dellist); | 124 | extern int del_perf_probe_events(struct strlist *dellist); |
122 | extern int show_perf_probe_events(void); | 125 | extern int show_perf_probe_events(void); |
123 | extern int show_line_range(struct line_range *lr); | 126 | extern int show_line_range(struct line_range *lr, const char *module); |
124 | extern int show_available_vars(struct perf_probe_event *pevs, int npevs, | 127 | extern int show_available_vars(struct perf_probe_event *pevs, int npevs, |
125 | int max_probe_points, bool externs); | 128 | int max_probe_points, const char *module, |
129 | bool externs); | ||
126 | 130 | ||
127 | 131 | ||
128 | /* Maximum index number of event-name postfix */ | 132 | /* Maximum index number of event-name postfix */ |
129 | #define MAX_EVENT_INDEX 1024 | 133 | #define MAX_EVENT_INDEX 1024 |
130 | 134 | ||
131 | #endif /*_PROBE_EVENT_H */ | 135 | #endif /*_PROBE_EVENT_H */ |
132 | 136 |
tools/perf/util/probe-finder.c
1 | /* | 1 | /* |
2 | * probe-finder.c : C expression to kprobe event converter | 2 | * probe-finder.c : C expression to kprobe event converter |
3 | * | 3 | * |
4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> | 4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 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 | 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. | 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sys/utsname.h> | 22 | #include <sys/utsname.h> |
23 | #include <sys/types.h> | 23 | #include <sys/types.h> |
24 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
26 | #include <errno.h> | 26 | #include <errno.h> |
27 | #include <stdio.h> | 27 | #include <stdio.h> |
28 | #include <unistd.h> | 28 | #include <unistd.h> |
29 | #include <getopt.h> | 29 | #include <getopt.h> |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> |
31 | #include <string.h> | 31 | #include <string.h> |
32 | #include <stdarg.h> | 32 | #include <stdarg.h> |
33 | #include <ctype.h> | 33 | #include <ctype.h> |
34 | #include <dwarf-regs.h> | 34 | #include <dwarf-regs.h> |
35 | 35 | ||
36 | #include "event.h" | 36 | #include "event.h" |
37 | #include "debug.h" | 37 | #include "debug.h" |
38 | #include "util.h" | 38 | #include "util.h" |
39 | #include "symbol.h" | 39 | #include "symbol.h" |
40 | #include "probe-finder.h" | 40 | #include "probe-finder.h" |
41 | 41 | ||
42 | /* Kprobe tracer basic type is up to u64 */ | 42 | /* Kprobe tracer basic type is up to u64 */ |
43 | #define MAX_BASIC_TYPE_BITS 64 | 43 | #define MAX_BASIC_TYPE_BITS 64 |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * Compare the tail of two strings. | 46 | * Compare the tail of two strings. |
47 | * Return 0 if whole of either string is same as another's tail part. | 47 | * Return 0 if whole of either string is same as another's tail part. |
48 | */ | 48 | */ |
49 | static int strtailcmp(const char *s1, const char *s2) | 49 | static int strtailcmp(const char *s1, const char *s2) |
50 | { | 50 | { |
51 | int i1 = strlen(s1); | 51 | int i1 = strlen(s1); |
52 | int i2 = strlen(s2); | 52 | int i2 = strlen(s2); |
53 | while (--i1 >= 0 && --i2 >= 0) { | 53 | while (--i1 >= 0 && --i2 >= 0) { |
54 | if (s1[i1] != s2[i2]) | 54 | if (s1[i1] != s2[i2]) |
55 | return s1[i1] - s2[i2]; | 55 | return s1[i1] - s2[i2]; |
56 | } | 56 | } |
57 | return 0; | 57 | return 0; |
58 | } | 58 | } |
59 | 59 | ||
60 | /* Line number list operations */ | 60 | /* Line number list operations */ |
61 | 61 | ||
62 | /* Add a line to line number list */ | 62 | /* Add a line to line number list */ |
63 | static int line_list__add_line(struct list_head *head, int line) | 63 | static int line_list__add_line(struct list_head *head, int line) |
64 | { | 64 | { |
65 | struct line_node *ln; | 65 | struct line_node *ln; |
66 | struct list_head *p; | 66 | struct list_head *p; |
67 | 67 | ||
68 | /* Reverse search, because new line will be the last one */ | 68 | /* Reverse search, because new line will be the last one */ |
69 | list_for_each_entry_reverse(ln, head, list) { | 69 | list_for_each_entry_reverse(ln, head, list) { |
70 | if (ln->line < line) { | 70 | if (ln->line < line) { |
71 | p = &ln->list; | 71 | p = &ln->list; |
72 | goto found; | 72 | goto found; |
73 | } else if (ln->line == line) /* Already exist */ | 73 | } else if (ln->line == line) /* Already exist */ |
74 | return 1; | 74 | return 1; |
75 | } | 75 | } |
76 | /* List is empty, or the smallest entry */ | 76 | /* List is empty, or the smallest entry */ |
77 | p = head; | 77 | p = head; |
78 | found: | 78 | found: |
79 | pr_debug("line list: add a line %u\n", line); | 79 | pr_debug("line list: add a line %u\n", line); |
80 | ln = zalloc(sizeof(struct line_node)); | 80 | ln = zalloc(sizeof(struct line_node)); |
81 | if (ln == NULL) | 81 | if (ln == NULL) |
82 | return -ENOMEM; | 82 | return -ENOMEM; |
83 | ln->line = line; | 83 | ln->line = line; |
84 | INIT_LIST_HEAD(&ln->list); | 84 | INIT_LIST_HEAD(&ln->list); |
85 | list_add(&ln->list, p); | 85 | list_add(&ln->list, p); |
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |
88 | 88 | ||
89 | /* Check if the line in line number list */ | 89 | /* Check if the line in line number list */ |
90 | static int line_list__has_line(struct list_head *head, int line) | 90 | static int line_list__has_line(struct list_head *head, int line) |
91 | { | 91 | { |
92 | struct line_node *ln; | 92 | struct line_node *ln; |
93 | 93 | ||
94 | /* Reverse search, because new line will be the last one */ | 94 | /* Reverse search, because new line will be the last one */ |
95 | list_for_each_entry(ln, head, list) | 95 | list_for_each_entry(ln, head, list) |
96 | if (ln->line == line) | 96 | if (ln->line == line) |
97 | return 1; | 97 | return 1; |
98 | 98 | ||
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | 101 | ||
102 | /* Init line number list */ | 102 | /* Init line number list */ |
103 | static void line_list__init(struct list_head *head) | 103 | static void line_list__init(struct list_head *head) |
104 | { | 104 | { |
105 | INIT_LIST_HEAD(head); | 105 | INIT_LIST_HEAD(head); |
106 | } | 106 | } |
107 | 107 | ||
108 | /* Free line number list */ | 108 | /* Free line number list */ |
109 | static void line_list__free(struct list_head *head) | 109 | static void line_list__free(struct list_head *head) |
110 | { | 110 | { |
111 | struct line_node *ln; | 111 | struct line_node *ln; |
112 | while (!list_empty(head)) { | 112 | while (!list_empty(head)) { |
113 | ln = list_first_entry(head, struct line_node, list); | 113 | ln = list_first_entry(head, struct line_node, list); |
114 | list_del(&ln->list); | 114 | list_del(&ln->list); |
115 | free(ln); | 115 | free(ln); |
116 | } | 116 | } |
117 | } | 117 | } |
118 | 118 | ||
119 | /* Dwarf FL wrappers */ | ||
120 | |||
121 | static int __linux_kernel_find_elf(Dwfl_Module *mod, | ||
122 | void **userdata, | ||
123 | const char *module_name, | ||
124 | Dwarf_Addr base, | ||
125 | char **file_name, Elf **elfp) | ||
126 | { | ||
127 | int fd; | ||
128 | const char *path = kernel_get_module_path(module_name); | ||
129 | |||
130 | if (path) { | ||
131 | fd = open(path, O_RDONLY); | ||
132 | if (fd >= 0) { | ||
133 | *file_name = strdup(path); | ||
134 | return fd; | ||
135 | } | ||
136 | } | ||
137 | /* If failed, try to call standard method */ | ||
138 | return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, | ||
139 | file_name, elfp); | ||
140 | } | ||
141 | |||
142 | static char *debuginfo_path; /* Currently dummy */ | ||
143 | |||
144 | static const Dwfl_Callbacks offline_callbacks = { | ||
145 | .find_debuginfo = dwfl_standard_find_debuginfo, | ||
146 | .debuginfo_path = &debuginfo_path, | ||
147 | |||
148 | .section_address = dwfl_offline_section_address, | ||
149 | |||
150 | /* We use this table for core files too. */ | ||
151 | .find_elf = dwfl_build_id_find_elf, | ||
152 | }; | ||
153 | |||
154 | static const Dwfl_Callbacks kernel_callbacks = { | ||
155 | .find_debuginfo = dwfl_standard_find_debuginfo, | ||
156 | .debuginfo_path = &debuginfo_path, | ||
157 | |||
158 | .find_elf = __linux_kernel_find_elf, | ||
159 | .section_address = dwfl_linux_kernel_module_section_address, | ||
160 | }; | ||
161 | |||
162 | /* Get a Dwarf from offline image */ | ||
163 | static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) | ||
164 | { | ||
165 | Dwfl_Module *mod; | ||
166 | Dwarf *dbg = NULL; | ||
167 | |||
168 | if (!dwflp) | ||
169 | return NULL; | ||
170 | |||
171 | *dwflp = dwfl_begin(&offline_callbacks); | ||
172 | if (!*dwflp) | ||
173 | return NULL; | ||
174 | |||
175 | mod = dwfl_report_offline(*dwflp, "", "", fd); | ||
176 | if (!mod) | ||
177 | goto error; | ||
178 | |||
179 | dbg = dwfl_module_getdwarf(mod, bias); | ||
180 | if (!dbg) { | ||
181 | error: | ||
182 | dwfl_end(*dwflp); | ||
183 | *dwflp = NULL; | ||
184 | } | ||
185 | return dbg; | ||
186 | } | ||
187 | |||
188 | /* Get a Dwarf from live kernel image */ | ||
189 | static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, | ||
190 | Dwarf_Addr *bias) | ||
191 | { | ||
192 | Dwarf *dbg; | ||
193 | |||
194 | if (!dwflp) | ||
195 | return NULL; | ||
196 | |||
197 | *dwflp = dwfl_begin(&kernel_callbacks); | ||
198 | if (!*dwflp) | ||
199 | return NULL; | ||
200 | |||
201 | /* Load the kernel dwarves: Don't care the result here */ | ||
202 | dwfl_linux_kernel_report_kernel(*dwflp); | ||
203 | dwfl_linux_kernel_report_modules(*dwflp); | ||
204 | |||
205 | dbg = dwfl_addrdwarf(*dwflp, addr, bias); | ||
206 | /* Here, check whether we could get a real dwarf */ | ||
207 | if (!dbg) { | ||
208 | dwfl_end(*dwflp); | ||
209 | *dwflp = NULL; | ||
210 | } | ||
211 | return dbg; | ||
212 | } | ||
213 | |||
119 | /* Dwarf wrappers */ | 214 | /* Dwarf wrappers */ |
120 | 215 | ||
121 | /* Find the realpath of the target file. */ | 216 | /* Find the realpath of the target file. */ |
122 | static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | 217 | static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) |
123 | { | 218 | { |
124 | Dwarf_Files *files; | 219 | Dwarf_Files *files; |
125 | size_t nfiles, i; | 220 | size_t nfiles, i; |
126 | const char *src = NULL; | 221 | const char *src = NULL; |
127 | int ret; | 222 | int ret; |
128 | 223 | ||
129 | if (!fname) | 224 | if (!fname) |
130 | return NULL; | 225 | return NULL; |
131 | 226 | ||
132 | ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); | 227 | ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); |
133 | if (ret != 0) | 228 | if (ret != 0) |
134 | return NULL; | 229 | return NULL; |
135 | 230 | ||
136 | for (i = 0; i < nfiles; i++) { | 231 | for (i = 0; i < nfiles; i++) { |
137 | src = dwarf_filesrc(files, i, NULL, NULL); | 232 | src = dwarf_filesrc(files, i, NULL, NULL); |
138 | if (strtailcmp(src, fname) == 0) | 233 | if (strtailcmp(src, fname) == 0) |
139 | break; | 234 | break; |
140 | } | 235 | } |
141 | if (i == nfiles) | 236 | if (i == nfiles) |
142 | return NULL; | 237 | return NULL; |
143 | return src; | 238 | return src; |
144 | } | 239 | } |
145 | 240 | ||
146 | /* Get DW_AT_comp_dir (should be NULL with older gcc) */ | 241 | /* Get DW_AT_comp_dir (should be NULL with older gcc) */ |
147 | static const char *cu_get_comp_dir(Dwarf_Die *cu_die) | 242 | static const char *cu_get_comp_dir(Dwarf_Die *cu_die) |
148 | { | 243 | { |
149 | Dwarf_Attribute attr; | 244 | Dwarf_Attribute attr; |
150 | if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) | 245 | if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) |
151 | return NULL; | 246 | return NULL; |
152 | return dwarf_formstring(&attr); | 247 | return dwarf_formstring(&attr); |
153 | } | 248 | } |
154 | 249 | ||
155 | /* Compare diename and tname */ | 250 | /* Compare diename and tname */ |
156 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 251 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) |
157 | { | 252 | { |
158 | const char *name; | 253 | const char *name; |
159 | name = dwarf_diename(dw_die); | 254 | name = dwarf_diename(dw_die); |
160 | return name ? (strcmp(tname, name) == 0) : false; | 255 | return name ? (strcmp(tname, name) == 0) : false; |
161 | } | 256 | } |
162 | 257 | ||
163 | /* Get type die */ | 258 | /* Get type die */ |
164 | static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 259 | static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) |
165 | { | 260 | { |
166 | Dwarf_Attribute attr; | 261 | Dwarf_Attribute attr; |
167 | 262 | ||
168 | if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && | 263 | if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && |
169 | dwarf_formref_die(&attr, die_mem)) | 264 | dwarf_formref_die(&attr, die_mem)) |
170 | return die_mem; | 265 | return die_mem; |
171 | else | 266 | else |
172 | return NULL; | 267 | return NULL; |
173 | } | 268 | } |
174 | 269 | ||
175 | /* Get a type die, but skip qualifiers */ | 270 | /* Get a type die, but skip qualifiers */ |
176 | static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 271 | static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) |
177 | { | 272 | { |
178 | int tag; | 273 | int tag; |
179 | 274 | ||
180 | do { | 275 | do { |
181 | vr_die = die_get_type(vr_die, die_mem); | 276 | vr_die = die_get_type(vr_die, die_mem); |
182 | if (!vr_die) | 277 | if (!vr_die) |
183 | break; | 278 | break; |
184 | tag = dwarf_tag(vr_die); | 279 | tag = dwarf_tag(vr_die); |
185 | } while (tag == DW_TAG_const_type || | 280 | } while (tag == DW_TAG_const_type || |
186 | tag == DW_TAG_restrict_type || | 281 | tag == DW_TAG_restrict_type || |
187 | tag == DW_TAG_volatile_type || | 282 | tag == DW_TAG_volatile_type || |
188 | tag == DW_TAG_shared_type); | 283 | tag == DW_TAG_shared_type); |
189 | 284 | ||
190 | return vr_die; | 285 | return vr_die; |
191 | } | 286 | } |
192 | 287 | ||
193 | /* Get a type die, but skip qualifiers and typedef */ | 288 | /* Get a type die, but skip qualifiers and typedef */ |
194 | static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 289 | static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) |
195 | { | 290 | { |
196 | do { | 291 | do { |
197 | vr_die = __die_get_real_type(vr_die, die_mem); | 292 | vr_die = __die_get_real_type(vr_die, die_mem); |
198 | } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); | 293 | } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); |
199 | 294 | ||
200 | return vr_die; | 295 | return vr_die; |
201 | } | 296 | } |
202 | 297 | ||
203 | static bool die_is_signed_type(Dwarf_Die *tp_die) | 298 | static bool die_is_signed_type(Dwarf_Die *tp_die) |
204 | { | 299 | { |
205 | Dwarf_Attribute attr; | 300 | Dwarf_Attribute attr; |
206 | Dwarf_Word ret; | 301 | Dwarf_Word ret; |
207 | 302 | ||
208 | if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || | 303 | if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || |
209 | dwarf_formudata(&attr, &ret) != 0) | 304 | dwarf_formudata(&attr, &ret) != 0) |
210 | return false; | 305 | return false; |
211 | 306 | ||
212 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || | 307 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || |
213 | ret == DW_ATE_signed_fixed); | 308 | ret == DW_ATE_signed_fixed); |
214 | } | 309 | } |
215 | 310 | ||
216 | static int die_get_byte_size(Dwarf_Die *tp_die) | 311 | static int die_get_byte_size(Dwarf_Die *tp_die) |
217 | { | 312 | { |
218 | Dwarf_Attribute attr; | 313 | Dwarf_Attribute attr; |
219 | Dwarf_Word ret; | 314 | Dwarf_Word ret; |
220 | 315 | ||
221 | if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || | 316 | if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || |
222 | dwarf_formudata(&attr, &ret) != 0) | 317 | dwarf_formudata(&attr, &ret) != 0) |
223 | return 0; | 318 | return 0; |
224 | 319 | ||
225 | return (int)ret; | 320 | return (int)ret; |
226 | } | 321 | } |
227 | 322 | ||
228 | /* Get data_member_location offset */ | 323 | /* Get data_member_location offset */ |
229 | static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | 324 | static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) |
230 | { | 325 | { |
231 | Dwarf_Attribute attr; | 326 | Dwarf_Attribute attr; |
232 | Dwarf_Op *expr; | 327 | Dwarf_Op *expr; |
233 | size_t nexpr; | 328 | size_t nexpr; |
234 | int ret; | 329 | int ret; |
235 | 330 | ||
236 | if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) | 331 | if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) |
237 | return -ENOENT; | 332 | return -ENOENT; |
238 | 333 | ||
239 | if (dwarf_formudata(&attr, offs) != 0) { | 334 | if (dwarf_formudata(&attr, offs) != 0) { |
240 | /* DW_AT_data_member_location should be DW_OP_plus_uconst */ | 335 | /* DW_AT_data_member_location should be DW_OP_plus_uconst */ |
241 | ret = dwarf_getlocation(&attr, &expr, &nexpr); | 336 | ret = dwarf_getlocation(&attr, &expr, &nexpr); |
242 | if (ret < 0 || nexpr == 0) | 337 | if (ret < 0 || nexpr == 0) |
243 | return -ENOENT; | 338 | return -ENOENT; |
244 | 339 | ||
245 | if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { | 340 | if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { |
246 | pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", | 341 | pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", |
247 | expr[0].atom, nexpr); | 342 | expr[0].atom, nexpr); |
248 | return -ENOTSUP; | 343 | return -ENOTSUP; |
249 | } | 344 | } |
250 | *offs = (Dwarf_Word)expr[0].number; | 345 | *offs = (Dwarf_Word)expr[0].number; |
251 | } | 346 | } |
252 | return 0; | 347 | return 0; |
253 | } | 348 | } |
254 | 349 | ||
255 | /* Return values for die_find callbacks */ | 350 | /* Return values for die_find callbacks */ |
256 | enum { | 351 | enum { |
257 | DIE_FIND_CB_FOUND = 0, /* End of Search */ | 352 | DIE_FIND_CB_FOUND = 0, /* End of Search */ |
258 | DIE_FIND_CB_CHILD = 1, /* Search only children */ | 353 | DIE_FIND_CB_CHILD = 1, /* Search only children */ |
259 | DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ | 354 | DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ |
260 | DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ | 355 | DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ |
261 | }; | 356 | }; |
262 | 357 | ||
263 | /* Search a child die */ | 358 | /* Search a child die */ |
264 | static Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | 359 | static Dwarf_Die *die_find_child(Dwarf_Die *rt_die, |
265 | int (*callback)(Dwarf_Die *, void *), | 360 | int (*callback)(Dwarf_Die *, void *), |
266 | void *data, Dwarf_Die *die_mem) | 361 | void *data, Dwarf_Die *die_mem) |
267 | { | 362 | { |
268 | Dwarf_Die child_die; | 363 | Dwarf_Die child_die; |
269 | int ret; | 364 | int ret; |
270 | 365 | ||
271 | ret = dwarf_child(rt_die, die_mem); | 366 | ret = dwarf_child(rt_die, die_mem); |
272 | if (ret != 0) | 367 | if (ret != 0) |
273 | return NULL; | 368 | return NULL; |
274 | 369 | ||
275 | do { | 370 | do { |
276 | ret = callback(die_mem, data); | 371 | ret = callback(die_mem, data); |
277 | if (ret == DIE_FIND_CB_FOUND) | 372 | if (ret == DIE_FIND_CB_FOUND) |
278 | return die_mem; | 373 | return die_mem; |
279 | 374 | ||
280 | if ((ret & DIE_FIND_CB_CHILD) && | 375 | if ((ret & DIE_FIND_CB_CHILD) && |
281 | die_find_child(die_mem, callback, data, &child_die)) { | 376 | die_find_child(die_mem, callback, data, &child_die)) { |
282 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | 377 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); |
283 | return die_mem; | 378 | return die_mem; |
284 | } | 379 | } |
285 | } while ((ret & DIE_FIND_CB_SIBLING) && | 380 | } while ((ret & DIE_FIND_CB_SIBLING) && |
286 | dwarf_siblingof(die_mem, die_mem) == 0); | 381 | dwarf_siblingof(die_mem, die_mem) == 0); |
287 | 382 | ||
288 | return NULL; | 383 | return NULL; |
289 | } | 384 | } |
290 | 385 | ||
291 | struct __addr_die_search_param { | 386 | struct __addr_die_search_param { |
292 | Dwarf_Addr addr; | 387 | Dwarf_Addr addr; |
293 | Dwarf_Die *die_mem; | 388 | Dwarf_Die *die_mem; |
294 | }; | 389 | }; |
295 | 390 | ||
296 | static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | 391 | static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) |
297 | { | 392 | { |
298 | struct __addr_die_search_param *ad = data; | 393 | struct __addr_die_search_param *ad = data; |
299 | 394 | ||
300 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && | 395 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && |
301 | dwarf_haspc(fn_die, ad->addr)) { | 396 | dwarf_haspc(fn_die, ad->addr)) { |
302 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); | 397 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); |
303 | return DWARF_CB_ABORT; | 398 | return DWARF_CB_ABORT; |
304 | } | 399 | } |
305 | return DWARF_CB_OK; | 400 | return DWARF_CB_OK; |
306 | } | 401 | } |
307 | 402 | ||
308 | /* Search a real subprogram including this line, */ | 403 | /* Search a real subprogram including this line, */ |
309 | static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, | 404 | static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, |
310 | Dwarf_Die *die_mem) | 405 | Dwarf_Die *die_mem) |
311 | { | 406 | { |
312 | struct __addr_die_search_param ad; | 407 | struct __addr_die_search_param ad; |
313 | ad.addr = addr; | 408 | ad.addr = addr; |
314 | ad.die_mem = die_mem; | 409 | ad.die_mem = die_mem; |
315 | /* dwarf_getscopes can't find subprogram. */ | 410 | /* dwarf_getscopes can't find subprogram. */ |
316 | if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) | 411 | if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) |
317 | return NULL; | 412 | return NULL; |
318 | else | 413 | else |
319 | return die_mem; | 414 | return die_mem; |
320 | } | 415 | } |
321 | 416 | ||
322 | /* die_find callback for inline function search */ | 417 | /* die_find callback for inline function search */ |
323 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) | 418 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) |
324 | { | 419 | { |
325 | Dwarf_Addr *addr = data; | 420 | Dwarf_Addr *addr = data; |
326 | 421 | ||
327 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && | 422 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && |
328 | dwarf_haspc(die_mem, *addr)) | 423 | dwarf_haspc(die_mem, *addr)) |
329 | return DIE_FIND_CB_FOUND; | 424 | return DIE_FIND_CB_FOUND; |
330 | 425 | ||
331 | return DIE_FIND_CB_CONTINUE; | 426 | return DIE_FIND_CB_CONTINUE; |
332 | } | 427 | } |
333 | 428 | ||
334 | /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ | 429 | /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ |
335 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 430 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
336 | Dwarf_Die *die_mem) | 431 | Dwarf_Die *die_mem) |
337 | { | 432 | { |
338 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); | 433 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); |
339 | } | 434 | } |
340 | 435 | ||
341 | struct __find_variable_param { | 436 | struct __find_variable_param { |
342 | const char *name; | 437 | const char *name; |
343 | Dwarf_Addr addr; | 438 | Dwarf_Addr addr; |
344 | }; | 439 | }; |
345 | 440 | ||
346 | static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) | 441 | static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) |
347 | { | 442 | { |
348 | struct __find_variable_param *fvp = data; | 443 | struct __find_variable_param *fvp = data; |
349 | int tag; | 444 | int tag; |
350 | 445 | ||
351 | tag = dwarf_tag(die_mem); | 446 | tag = dwarf_tag(die_mem); |
352 | if ((tag == DW_TAG_formal_parameter || | 447 | if ((tag == DW_TAG_formal_parameter || |
353 | tag == DW_TAG_variable) && | 448 | tag == DW_TAG_variable) && |
354 | die_compare_name(die_mem, fvp->name)) | 449 | die_compare_name(die_mem, fvp->name)) |
355 | return DIE_FIND_CB_FOUND; | 450 | return DIE_FIND_CB_FOUND; |
356 | 451 | ||
357 | if (dwarf_haspc(die_mem, fvp->addr)) | 452 | if (dwarf_haspc(die_mem, fvp->addr)) |
358 | return DIE_FIND_CB_CONTINUE; | 453 | return DIE_FIND_CB_CONTINUE; |
359 | else | 454 | else |
360 | return DIE_FIND_CB_SIBLING; | 455 | return DIE_FIND_CB_SIBLING; |
361 | } | 456 | } |
362 | 457 | ||
363 | /* Find a variable called 'name' at given address */ | 458 | /* Find a variable called 'name' at given address */ |
364 | static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, | 459 | static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, |
365 | Dwarf_Addr addr, Dwarf_Die *die_mem) | 460 | Dwarf_Addr addr, Dwarf_Die *die_mem) |
366 | { | 461 | { |
367 | struct __find_variable_param fvp = { .name = name, .addr = addr}; | 462 | struct __find_variable_param fvp = { .name = name, .addr = addr}; |
368 | 463 | ||
369 | return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, | 464 | return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, |
370 | die_mem); | 465 | die_mem); |
371 | } | 466 | } |
372 | 467 | ||
373 | static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) | 468 | static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) |
374 | { | 469 | { |
375 | const char *name = data; | 470 | const char *name = data; |
376 | 471 | ||
377 | if ((dwarf_tag(die_mem) == DW_TAG_member) && | 472 | if ((dwarf_tag(die_mem) == DW_TAG_member) && |
378 | die_compare_name(die_mem, name)) | 473 | die_compare_name(die_mem, name)) |
379 | return DIE_FIND_CB_FOUND; | 474 | return DIE_FIND_CB_FOUND; |
380 | 475 | ||
381 | return DIE_FIND_CB_SIBLING; | 476 | return DIE_FIND_CB_SIBLING; |
382 | } | 477 | } |
383 | 478 | ||
384 | /* Find a member called 'name' */ | 479 | /* Find a member called 'name' */ |
385 | static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | 480 | static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, |
386 | Dwarf_Die *die_mem) | 481 | Dwarf_Die *die_mem) |
387 | { | 482 | { |
388 | return die_find_child(st_die, __die_find_member_cb, (void *)name, | 483 | return die_find_child(st_die, __die_find_member_cb, (void *)name, |
389 | die_mem); | 484 | die_mem); |
390 | } | 485 | } |
391 | 486 | ||
392 | /* Get the name of given variable DIE */ | 487 | /* Get the name of given variable DIE */ |
393 | static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) | 488 | static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) |
394 | { | 489 | { |
395 | Dwarf_Die type; | 490 | Dwarf_Die type; |
396 | int tag, ret, ret2; | 491 | int tag, ret, ret2; |
397 | const char *tmp = ""; | 492 | const char *tmp = ""; |
398 | 493 | ||
399 | if (__die_get_real_type(vr_die, &type) == NULL) | 494 | if (__die_get_real_type(vr_die, &type) == NULL) |
400 | return -ENOENT; | 495 | return -ENOENT; |
401 | 496 | ||
402 | tag = dwarf_tag(&type); | 497 | tag = dwarf_tag(&type); |
403 | if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) | 498 | if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) |
404 | tmp = "*"; | 499 | tmp = "*"; |
405 | else if (tag == DW_TAG_subroutine_type) { | 500 | else if (tag == DW_TAG_subroutine_type) { |
406 | /* Function pointer */ | 501 | /* Function pointer */ |
407 | ret = snprintf(buf, len, "(function_type)"); | 502 | ret = snprintf(buf, len, "(function_type)"); |
408 | return (ret >= len) ? -E2BIG : ret; | 503 | return (ret >= len) ? -E2BIG : ret; |
409 | } else { | 504 | } else { |
410 | if (!dwarf_diename(&type)) | 505 | if (!dwarf_diename(&type)) |
411 | return -ENOENT; | 506 | return -ENOENT; |
412 | if (tag == DW_TAG_union_type) | 507 | if (tag == DW_TAG_union_type) |
413 | tmp = "union "; | 508 | tmp = "union "; |
414 | else if (tag == DW_TAG_structure_type) | 509 | else if (tag == DW_TAG_structure_type) |
415 | tmp = "struct "; | 510 | tmp = "struct "; |
416 | /* Write a base name */ | 511 | /* Write a base name */ |
417 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); | 512 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); |
418 | return (ret >= len) ? -E2BIG : ret; | 513 | return (ret >= len) ? -E2BIG : ret; |
419 | } | 514 | } |
420 | ret = die_get_typename(&type, buf, len); | 515 | ret = die_get_typename(&type, buf, len); |
421 | if (ret > 0) { | 516 | if (ret > 0) { |
422 | ret2 = snprintf(buf + ret, len - ret, "%s", tmp); | 517 | ret2 = snprintf(buf + ret, len - ret, "%s", tmp); |
423 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; | 518 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; |
424 | } | 519 | } |
425 | return ret; | 520 | return ret; |
426 | } | 521 | } |
427 | 522 | ||
428 | /* Get the name and type of given variable DIE, stored as "type\tname" */ | 523 | /* Get the name and type of given variable DIE, stored as "type\tname" */ |
429 | static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len) | 524 | static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len) |
430 | { | 525 | { |
431 | int ret, ret2; | 526 | int ret, ret2; |
432 | 527 | ||
433 | ret = die_get_typename(vr_die, buf, len); | 528 | ret = die_get_typename(vr_die, buf, len); |
434 | if (ret < 0) { | 529 | if (ret < 0) { |
435 | pr_debug("Failed to get type, make it unknown.\n"); | 530 | pr_debug("Failed to get type, make it unknown.\n"); |
436 | ret = snprintf(buf, len, "(unknown_type)"); | 531 | ret = snprintf(buf, len, "(unknown_type)"); |
437 | } | 532 | } |
438 | if (ret > 0) { | 533 | if (ret > 0) { |
439 | ret2 = snprintf(buf + ret, len - ret, "\t%s", | 534 | ret2 = snprintf(buf + ret, len - ret, "\t%s", |
440 | dwarf_diename(vr_die)); | 535 | dwarf_diename(vr_die)); |
441 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; | 536 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; |
442 | } | 537 | } |
443 | return ret; | 538 | return ret; |
444 | } | 539 | } |
445 | 540 | ||
446 | /* | 541 | /* |
447 | * Probe finder related functions | 542 | * Probe finder related functions |
448 | */ | 543 | */ |
449 | 544 | ||
450 | static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) | 545 | static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) |
451 | { | 546 | { |
452 | struct probe_trace_arg_ref *ref; | 547 | struct probe_trace_arg_ref *ref; |
453 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); | 548 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
454 | if (ref != NULL) | 549 | if (ref != NULL) |
455 | ref->offset = offs; | 550 | ref->offset = offs; |
456 | return ref; | 551 | return ref; |
457 | } | 552 | } |
458 | 553 | ||
459 | /* | 554 | /* |
460 | * Convert a location into trace_arg. | 555 | * Convert a location into trace_arg. |
461 | * If tvar == NULL, this just checks variable can be converted. | 556 | * If tvar == NULL, this just checks variable can be converted. |
462 | */ | 557 | */ |
463 | static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, | 558 | static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, |
464 | Dwarf_Op *fb_ops, | 559 | Dwarf_Op *fb_ops, |
465 | struct probe_trace_arg *tvar) | 560 | struct probe_trace_arg *tvar) |
466 | { | 561 | { |
467 | Dwarf_Attribute attr; | 562 | Dwarf_Attribute attr; |
468 | Dwarf_Op *op; | 563 | Dwarf_Op *op; |
469 | size_t nops; | 564 | size_t nops; |
470 | unsigned int regn; | 565 | unsigned int regn; |
471 | Dwarf_Word offs = 0; | 566 | Dwarf_Word offs = 0; |
472 | bool ref = false; | 567 | bool ref = false; |
473 | const char *regs; | 568 | const char *regs; |
474 | int ret; | 569 | int ret; |
475 | 570 | ||
476 | if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) | 571 | if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) |
477 | goto static_var; | 572 | goto static_var; |
478 | 573 | ||
479 | /* TODO: handle more than 1 exprs */ | 574 | /* TODO: handle more than 1 exprs */ |
480 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || | 575 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || |
481 | dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || | 576 | dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || |
482 | nops == 0) { | 577 | nops == 0) { |
483 | /* TODO: Support const_value */ | 578 | /* TODO: Support const_value */ |
484 | return -ENOENT; | 579 | return -ENOENT; |
485 | } | 580 | } |
486 | 581 | ||
487 | if (op->atom == DW_OP_addr) { | 582 | if (op->atom == DW_OP_addr) { |
488 | static_var: | 583 | static_var: |
489 | if (!tvar) | 584 | if (!tvar) |
490 | return 0; | 585 | return 0; |
491 | /* Static variables on memory (not stack), make @varname */ | 586 | /* Static variables on memory (not stack), make @varname */ |
492 | ret = strlen(dwarf_diename(vr_die)); | 587 | ret = strlen(dwarf_diename(vr_die)); |
493 | tvar->value = zalloc(ret + 2); | 588 | tvar->value = zalloc(ret + 2); |
494 | if (tvar->value == NULL) | 589 | if (tvar->value == NULL) |
495 | return -ENOMEM; | 590 | return -ENOMEM; |
496 | snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); | 591 | snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); |
497 | tvar->ref = alloc_trace_arg_ref((long)offs); | 592 | tvar->ref = alloc_trace_arg_ref((long)offs); |
498 | if (tvar->ref == NULL) | 593 | if (tvar->ref == NULL) |
499 | return -ENOMEM; | 594 | return -ENOMEM; |
500 | return 0; | 595 | return 0; |
501 | } | 596 | } |
502 | 597 | ||
503 | /* If this is based on frame buffer, set the offset */ | 598 | /* If this is based on frame buffer, set the offset */ |
504 | if (op->atom == DW_OP_fbreg) { | 599 | if (op->atom == DW_OP_fbreg) { |
505 | if (fb_ops == NULL) | 600 | if (fb_ops == NULL) |
506 | return -ENOTSUP; | 601 | return -ENOTSUP; |
507 | ref = true; | 602 | ref = true; |
508 | offs = op->number; | 603 | offs = op->number; |
509 | op = &fb_ops[0]; | 604 | op = &fb_ops[0]; |
510 | } | 605 | } |
511 | 606 | ||
512 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { | 607 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { |
513 | regn = op->atom - DW_OP_breg0; | 608 | regn = op->atom - DW_OP_breg0; |
514 | offs += op->number; | 609 | offs += op->number; |
515 | ref = true; | 610 | ref = true; |
516 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { | 611 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { |
517 | regn = op->atom - DW_OP_reg0; | 612 | regn = op->atom - DW_OP_reg0; |
518 | } else if (op->atom == DW_OP_bregx) { | 613 | } else if (op->atom == DW_OP_bregx) { |
519 | regn = op->number; | 614 | regn = op->number; |
520 | offs += op->number2; | 615 | offs += op->number2; |
521 | ref = true; | 616 | ref = true; |
522 | } else if (op->atom == DW_OP_regx) { | 617 | } else if (op->atom == DW_OP_regx) { |
523 | regn = op->number; | 618 | regn = op->number; |
524 | } else { | 619 | } else { |
525 | pr_debug("DW_OP %x is not supported.\n", op->atom); | 620 | pr_debug("DW_OP %x is not supported.\n", op->atom); |
526 | return -ENOTSUP; | 621 | return -ENOTSUP; |
527 | } | 622 | } |
528 | 623 | ||
529 | if (!tvar) | 624 | if (!tvar) |
530 | return 0; | 625 | return 0; |
531 | 626 | ||
532 | regs = get_arch_regstr(regn); | 627 | regs = get_arch_regstr(regn); |
533 | if (!regs) { | 628 | if (!regs) { |
534 | /* This should be a bug in DWARF or this tool */ | 629 | /* This should be a bug in DWARF or this tool */ |
535 | pr_warning("Mapping for DWARF register number %u " | 630 | pr_warning("Mapping for DWARF register number %u " |
536 | "missing on this architecture.", regn); | 631 | "missing on this architecture.", regn); |
537 | return -ERANGE; | 632 | return -ERANGE; |
538 | } | 633 | } |
539 | 634 | ||
540 | tvar->value = strdup(regs); | 635 | tvar->value = strdup(regs); |
541 | if (tvar->value == NULL) | 636 | if (tvar->value == NULL) |
542 | return -ENOMEM; | 637 | return -ENOMEM; |
543 | 638 | ||
544 | if (ref) { | 639 | if (ref) { |
545 | tvar->ref = alloc_trace_arg_ref((long)offs); | 640 | tvar->ref = alloc_trace_arg_ref((long)offs); |
546 | if (tvar->ref == NULL) | 641 | if (tvar->ref == NULL) |
547 | return -ENOMEM; | 642 | return -ENOMEM; |
548 | } | 643 | } |
549 | return 0; | 644 | return 0; |
550 | } | 645 | } |
551 | 646 | ||
552 | static int convert_variable_type(Dwarf_Die *vr_die, | 647 | static int convert_variable_type(Dwarf_Die *vr_die, |
553 | struct probe_trace_arg *tvar, | 648 | struct probe_trace_arg *tvar, |
554 | const char *cast) | 649 | const char *cast) |
555 | { | 650 | { |
556 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; | 651 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; |
557 | Dwarf_Die type; | 652 | Dwarf_Die type; |
558 | char buf[16]; | 653 | char buf[16]; |
559 | int ret; | 654 | int ret; |
560 | 655 | ||
561 | /* TODO: check all types */ | 656 | /* TODO: check all types */ |
562 | if (cast && strcmp(cast, "string") != 0) { | 657 | if (cast && strcmp(cast, "string") != 0) { |
563 | /* Non string type is OK */ | 658 | /* Non string type is OK */ |
564 | tvar->type = strdup(cast); | 659 | tvar->type = strdup(cast); |
565 | return (tvar->type == NULL) ? -ENOMEM : 0; | 660 | return (tvar->type == NULL) ? -ENOMEM : 0; |
566 | } | 661 | } |
567 | 662 | ||
568 | if (die_get_real_type(vr_die, &type) == NULL) { | 663 | if (die_get_real_type(vr_die, &type) == NULL) { |
569 | pr_warning("Failed to get a type information of %s.\n", | 664 | pr_warning("Failed to get a type information of %s.\n", |
570 | dwarf_diename(vr_die)); | 665 | dwarf_diename(vr_die)); |
571 | return -ENOENT; | 666 | return -ENOENT; |
572 | } | 667 | } |
573 | 668 | ||
574 | pr_debug("%s type is %s.\n", | 669 | pr_debug("%s type is %s.\n", |
575 | dwarf_diename(vr_die), dwarf_diename(&type)); | 670 | dwarf_diename(vr_die), dwarf_diename(&type)); |
576 | 671 | ||
577 | if (cast && strcmp(cast, "string") == 0) { /* String type */ | 672 | if (cast && strcmp(cast, "string") == 0) { /* String type */ |
578 | ret = dwarf_tag(&type); | 673 | ret = dwarf_tag(&type); |
579 | if (ret != DW_TAG_pointer_type && | 674 | if (ret != DW_TAG_pointer_type && |
580 | ret != DW_TAG_array_type) { | 675 | ret != DW_TAG_array_type) { |
581 | pr_warning("Failed to cast into string: " | 676 | pr_warning("Failed to cast into string: " |
582 | "%s(%s) is not a pointer nor array.", | 677 | "%s(%s) is not a pointer nor array.", |
583 | dwarf_diename(vr_die), dwarf_diename(&type)); | 678 | dwarf_diename(vr_die), dwarf_diename(&type)); |
584 | return -EINVAL; | 679 | return -EINVAL; |
585 | } | 680 | } |
586 | if (ret == DW_TAG_pointer_type) { | 681 | if (ret == DW_TAG_pointer_type) { |
587 | if (die_get_real_type(&type, &type) == NULL) { | 682 | if (die_get_real_type(&type, &type) == NULL) { |
588 | pr_warning("Failed to get a type information."); | 683 | pr_warning("Failed to get a type information."); |
589 | return -ENOENT; | 684 | return -ENOENT; |
590 | } | 685 | } |
591 | while (*ref_ptr) | 686 | while (*ref_ptr) |
592 | ref_ptr = &(*ref_ptr)->next; | 687 | ref_ptr = &(*ref_ptr)->next; |
593 | /* Add new reference with offset +0 */ | 688 | /* Add new reference with offset +0 */ |
594 | *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); | 689 | *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); |
595 | if (*ref_ptr == NULL) { | 690 | if (*ref_ptr == NULL) { |
596 | pr_warning("Out of memory error\n"); | 691 | pr_warning("Out of memory error\n"); |
597 | return -ENOMEM; | 692 | return -ENOMEM; |
598 | } | 693 | } |
599 | } | 694 | } |
600 | if (!die_compare_name(&type, "char") && | 695 | if (!die_compare_name(&type, "char") && |
601 | !die_compare_name(&type, "unsigned char")) { | 696 | !die_compare_name(&type, "unsigned char")) { |
602 | pr_warning("Failed to cast into string: " | 697 | pr_warning("Failed to cast into string: " |
603 | "%s is not (unsigned) char *.", | 698 | "%s is not (unsigned) char *.", |
604 | dwarf_diename(vr_die)); | 699 | dwarf_diename(vr_die)); |
605 | return -EINVAL; | 700 | return -EINVAL; |
606 | } | 701 | } |
607 | tvar->type = strdup(cast); | 702 | tvar->type = strdup(cast); |
608 | return (tvar->type == NULL) ? -ENOMEM : 0; | 703 | return (tvar->type == NULL) ? -ENOMEM : 0; |
609 | } | 704 | } |
610 | 705 | ||
611 | ret = die_get_byte_size(&type) * 8; | 706 | ret = die_get_byte_size(&type) * 8; |
612 | if (ret) { | 707 | if (ret) { |
613 | /* Check the bitwidth */ | 708 | /* Check the bitwidth */ |
614 | if (ret > MAX_BASIC_TYPE_BITS) { | 709 | if (ret > MAX_BASIC_TYPE_BITS) { |
615 | pr_info("%s exceeds max-bitwidth." | 710 | pr_info("%s exceeds max-bitwidth." |
616 | " Cut down to %d bits.\n", | 711 | " Cut down to %d bits.\n", |
617 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); | 712 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); |
618 | ret = MAX_BASIC_TYPE_BITS; | 713 | ret = MAX_BASIC_TYPE_BITS; |
619 | } | 714 | } |
620 | 715 | ||
621 | ret = snprintf(buf, 16, "%c%d", | 716 | ret = snprintf(buf, 16, "%c%d", |
622 | die_is_signed_type(&type) ? 's' : 'u', ret); | 717 | die_is_signed_type(&type) ? 's' : 'u', ret); |
623 | if (ret < 0 || ret >= 16) { | 718 | if (ret < 0 || ret >= 16) { |
624 | if (ret >= 16) | 719 | if (ret >= 16) |
625 | ret = -E2BIG; | 720 | ret = -E2BIG; |
626 | pr_warning("Failed to convert variable type: %s\n", | 721 | pr_warning("Failed to convert variable type: %s\n", |
627 | strerror(-ret)); | 722 | strerror(-ret)); |
628 | return ret; | 723 | return ret; |
629 | } | 724 | } |
630 | tvar->type = strdup(buf); | 725 | tvar->type = strdup(buf); |
631 | if (tvar->type == NULL) | 726 | if (tvar->type == NULL) |
632 | return -ENOMEM; | 727 | return -ENOMEM; |
633 | } | 728 | } |
634 | return 0; | 729 | return 0; |
635 | } | 730 | } |
636 | 731 | ||
637 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | 732 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, |
638 | struct perf_probe_arg_field *field, | 733 | struct perf_probe_arg_field *field, |
639 | struct probe_trace_arg_ref **ref_ptr, | 734 | struct probe_trace_arg_ref **ref_ptr, |
640 | Dwarf_Die *die_mem) | 735 | Dwarf_Die *die_mem) |
641 | { | 736 | { |
642 | struct probe_trace_arg_ref *ref = *ref_ptr; | 737 | struct probe_trace_arg_ref *ref = *ref_ptr; |
643 | Dwarf_Die type; | 738 | Dwarf_Die type; |
644 | Dwarf_Word offs; | 739 | Dwarf_Word offs; |
645 | int ret, tag; | 740 | int ret, tag; |
646 | 741 | ||
647 | pr_debug("converting %s in %s\n", field->name, varname); | 742 | pr_debug("converting %s in %s\n", field->name, varname); |
648 | if (die_get_real_type(vr_die, &type) == NULL) { | 743 | if (die_get_real_type(vr_die, &type) == NULL) { |
649 | pr_warning("Failed to get the type of %s.\n", varname); | 744 | pr_warning("Failed to get the type of %s.\n", varname); |
650 | return -ENOENT; | 745 | return -ENOENT; |
651 | } | 746 | } |
652 | pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); | 747 | pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); |
653 | tag = dwarf_tag(&type); | 748 | tag = dwarf_tag(&type); |
654 | 749 | ||
655 | if (field->name[0] == '[' && | 750 | if (field->name[0] == '[' && |
656 | (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { | 751 | (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { |
657 | if (field->next) | 752 | if (field->next) |
658 | /* Save original type for next field */ | 753 | /* Save original type for next field */ |
659 | memcpy(die_mem, &type, sizeof(*die_mem)); | 754 | memcpy(die_mem, &type, sizeof(*die_mem)); |
660 | /* Get the type of this array */ | 755 | /* Get the type of this array */ |
661 | if (die_get_real_type(&type, &type) == NULL) { | 756 | if (die_get_real_type(&type, &type) == NULL) { |
662 | pr_warning("Failed to get the type of %s.\n", varname); | 757 | pr_warning("Failed to get the type of %s.\n", varname); |
663 | return -ENOENT; | 758 | return -ENOENT; |
664 | } | 759 | } |
665 | pr_debug2("Array real type: (%x)\n", | 760 | pr_debug2("Array real type: (%x)\n", |
666 | (unsigned)dwarf_dieoffset(&type)); | 761 | (unsigned)dwarf_dieoffset(&type)); |
667 | if (tag == DW_TAG_pointer_type) { | 762 | if (tag == DW_TAG_pointer_type) { |
668 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); | 763 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
669 | if (ref == NULL) | 764 | if (ref == NULL) |
670 | return -ENOMEM; | 765 | return -ENOMEM; |
671 | if (*ref_ptr) | 766 | if (*ref_ptr) |
672 | (*ref_ptr)->next = ref; | 767 | (*ref_ptr)->next = ref; |
673 | else | 768 | else |
674 | *ref_ptr = ref; | 769 | *ref_ptr = ref; |
675 | } | 770 | } |
676 | ref->offset += die_get_byte_size(&type) * field->index; | 771 | ref->offset += die_get_byte_size(&type) * field->index; |
677 | if (!field->next) | 772 | if (!field->next) |
678 | /* Save vr_die for converting types */ | 773 | /* Save vr_die for converting types */ |
679 | memcpy(die_mem, vr_die, sizeof(*die_mem)); | 774 | memcpy(die_mem, vr_die, sizeof(*die_mem)); |
680 | goto next; | 775 | goto next; |
681 | } else if (tag == DW_TAG_pointer_type) { | 776 | } else if (tag == DW_TAG_pointer_type) { |
682 | /* Check the pointer and dereference */ | 777 | /* Check the pointer and dereference */ |
683 | if (!field->ref) { | 778 | if (!field->ref) { |
684 | pr_err("Semantic error: %s must be referred by '->'\n", | 779 | pr_err("Semantic error: %s must be referred by '->'\n", |
685 | field->name); | 780 | field->name); |
686 | return -EINVAL; | 781 | return -EINVAL; |
687 | } | 782 | } |
688 | /* Get the type pointed by this pointer */ | 783 | /* Get the type pointed by this pointer */ |
689 | if (die_get_real_type(&type, &type) == NULL) { | 784 | if (die_get_real_type(&type, &type) == NULL) { |
690 | pr_warning("Failed to get the type of %s.\n", varname); | 785 | pr_warning("Failed to get the type of %s.\n", varname); |
691 | return -ENOENT; | 786 | return -ENOENT; |
692 | } | 787 | } |
693 | /* Verify it is a data structure */ | 788 | /* Verify it is a data structure */ |
694 | if (dwarf_tag(&type) != DW_TAG_structure_type) { | 789 | if (dwarf_tag(&type) != DW_TAG_structure_type) { |
695 | pr_warning("%s is not a data structure.\n", varname); | 790 | pr_warning("%s is not a data structure.\n", varname); |
696 | return -EINVAL; | 791 | return -EINVAL; |
697 | } | 792 | } |
698 | 793 | ||
699 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); | 794 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
700 | if (ref == NULL) | 795 | if (ref == NULL) |
701 | return -ENOMEM; | 796 | return -ENOMEM; |
702 | if (*ref_ptr) | 797 | if (*ref_ptr) |
703 | (*ref_ptr)->next = ref; | 798 | (*ref_ptr)->next = ref; |
704 | else | 799 | else |
705 | *ref_ptr = ref; | 800 | *ref_ptr = ref; |
706 | } else { | 801 | } else { |
707 | /* Verify it is a data structure */ | 802 | /* Verify it is a data structure */ |
708 | if (tag != DW_TAG_structure_type) { | 803 | if (tag != DW_TAG_structure_type) { |
709 | pr_warning("%s is not a data structure.\n", varname); | 804 | pr_warning("%s is not a data structure.\n", varname); |
710 | return -EINVAL; | 805 | return -EINVAL; |
711 | } | 806 | } |
712 | if (field->name[0] == '[') { | 807 | if (field->name[0] == '[') { |
713 | pr_err("Semantic error: %s is not a pointor nor array.", | 808 | pr_err("Semantic error: %s is not a pointor nor array.", |
714 | varname); | 809 | varname); |
715 | return -EINVAL; | 810 | return -EINVAL; |
716 | } | 811 | } |
717 | if (field->ref) { | 812 | if (field->ref) { |
718 | pr_err("Semantic error: %s must be referred by '.'\n", | 813 | pr_err("Semantic error: %s must be referred by '.'\n", |
719 | field->name); | 814 | field->name); |
720 | return -EINVAL; | 815 | return -EINVAL; |
721 | } | 816 | } |
722 | if (!ref) { | 817 | if (!ref) { |
723 | pr_warning("Structure on a register is not " | 818 | pr_warning("Structure on a register is not " |
724 | "supported yet.\n"); | 819 | "supported yet.\n"); |
725 | return -ENOTSUP; | 820 | return -ENOTSUP; |
726 | } | 821 | } |
727 | } | 822 | } |
728 | 823 | ||
729 | if (die_find_member(&type, field->name, die_mem) == NULL) { | 824 | if (die_find_member(&type, field->name, die_mem) == NULL) { |
730 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, | 825 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, |
731 | dwarf_diename(&type), field->name); | 826 | dwarf_diename(&type), field->name); |
732 | return -EINVAL; | 827 | return -EINVAL; |
733 | } | 828 | } |
734 | 829 | ||
735 | /* Get the offset of the field */ | 830 | /* Get the offset of the field */ |
736 | ret = die_get_data_member_location(die_mem, &offs); | 831 | ret = die_get_data_member_location(die_mem, &offs); |
737 | if (ret < 0) { | 832 | if (ret < 0) { |
738 | pr_warning("Failed to get the offset of %s.\n", field->name); | 833 | pr_warning("Failed to get the offset of %s.\n", field->name); |
739 | return ret; | 834 | return ret; |
740 | } | 835 | } |
741 | ref->offset += (long)offs; | 836 | ref->offset += (long)offs; |
742 | 837 | ||
743 | next: | 838 | next: |
744 | /* Converting next field */ | 839 | /* Converting next field */ |
745 | if (field->next) | 840 | if (field->next) |
746 | return convert_variable_fields(die_mem, field->name, | 841 | return convert_variable_fields(die_mem, field->name, |
747 | field->next, &ref, die_mem); | 842 | field->next, &ref, die_mem); |
748 | else | 843 | else |
749 | return 0; | 844 | return 0; |
750 | } | 845 | } |
751 | 846 | ||
752 | /* Show a variables in kprobe event format */ | 847 | /* Show a variables in kprobe event format */ |
753 | static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 848 | static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
754 | { | 849 | { |
755 | Dwarf_Die die_mem; | 850 | Dwarf_Die die_mem; |
756 | int ret; | 851 | int ret; |
757 | 852 | ||
758 | pr_debug("Converting variable %s into trace event.\n", | 853 | pr_debug("Converting variable %s into trace event.\n", |
759 | dwarf_diename(vr_die)); | 854 | dwarf_diename(vr_die)); |
760 | 855 | ||
761 | ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, | 856 | ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, |
762 | pf->tvar); | 857 | pf->tvar); |
763 | if (ret == -ENOENT) | 858 | if (ret == -ENOENT) |
764 | pr_err("Failed to find the location of %s at this address.\n" | 859 | pr_err("Failed to find the location of %s at this address.\n" |
765 | " Perhaps, it has been optimized out.\n", pf->pvar->var); | 860 | " Perhaps, it has been optimized out.\n", pf->pvar->var); |
766 | else if (ret == -ENOTSUP) | 861 | else if (ret == -ENOTSUP) |
767 | pr_err("Sorry, we don't support this variable location yet.\n"); | 862 | pr_err("Sorry, we don't support this variable location yet.\n"); |
768 | else if (pf->pvar->field) { | 863 | else if (pf->pvar->field) { |
769 | ret = convert_variable_fields(vr_die, pf->pvar->var, | 864 | ret = convert_variable_fields(vr_die, pf->pvar->var, |
770 | pf->pvar->field, &pf->tvar->ref, | 865 | pf->pvar->field, &pf->tvar->ref, |
771 | &die_mem); | 866 | &die_mem); |
772 | vr_die = &die_mem; | 867 | vr_die = &die_mem; |
773 | } | 868 | } |
774 | if (ret == 0) | 869 | if (ret == 0) |
775 | ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); | 870 | ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); |
776 | /* *expr will be cached in libdw. Don't free it. */ | 871 | /* *expr will be cached in libdw. Don't free it. */ |
777 | return ret; | 872 | return ret; |
778 | } | 873 | } |
779 | 874 | ||
780 | /* Find a variable in a subprogram die */ | 875 | /* Find a variable in a subprogram die */ |
781 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 876 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
782 | { | 877 | { |
783 | Dwarf_Die vr_die, *scopes; | 878 | Dwarf_Die vr_die, *scopes; |
784 | char buf[32], *ptr; | 879 | char buf[32], *ptr; |
785 | int ret, nscopes; | 880 | int ret, nscopes; |
786 | 881 | ||
787 | if (!is_c_varname(pf->pvar->var)) { | 882 | if (!is_c_varname(pf->pvar->var)) { |
788 | /* Copy raw parameters */ | 883 | /* Copy raw parameters */ |
789 | pf->tvar->value = strdup(pf->pvar->var); | 884 | pf->tvar->value = strdup(pf->pvar->var); |
790 | if (pf->tvar->value == NULL) | 885 | if (pf->tvar->value == NULL) |
791 | return -ENOMEM; | 886 | return -ENOMEM; |
792 | if (pf->pvar->type) { | 887 | if (pf->pvar->type) { |
793 | pf->tvar->type = strdup(pf->pvar->type); | 888 | pf->tvar->type = strdup(pf->pvar->type); |
794 | if (pf->tvar->type == NULL) | 889 | if (pf->tvar->type == NULL) |
795 | return -ENOMEM; | 890 | return -ENOMEM; |
796 | } | 891 | } |
797 | if (pf->pvar->name) { | 892 | if (pf->pvar->name) { |
798 | pf->tvar->name = strdup(pf->pvar->name); | 893 | pf->tvar->name = strdup(pf->pvar->name); |
799 | if (pf->tvar->name == NULL) | 894 | if (pf->tvar->name == NULL) |
800 | return -ENOMEM; | 895 | return -ENOMEM; |
801 | } else | 896 | } else |
802 | pf->tvar->name = NULL; | 897 | pf->tvar->name = NULL; |
803 | return 0; | 898 | return 0; |
804 | } | 899 | } |
805 | 900 | ||
806 | if (pf->pvar->name) | 901 | if (pf->pvar->name) |
807 | pf->tvar->name = strdup(pf->pvar->name); | 902 | pf->tvar->name = strdup(pf->pvar->name); |
808 | else { | 903 | else { |
809 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); | 904 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); |
810 | if (ret < 0) | 905 | if (ret < 0) |
811 | return ret; | 906 | return ret; |
812 | ptr = strchr(buf, ':'); /* Change type separator to _ */ | 907 | ptr = strchr(buf, ':'); /* Change type separator to _ */ |
813 | if (ptr) | 908 | if (ptr) |
814 | *ptr = '_'; | 909 | *ptr = '_'; |
815 | pf->tvar->name = strdup(buf); | 910 | pf->tvar->name = strdup(buf); |
816 | } | 911 | } |
817 | if (pf->tvar->name == NULL) | 912 | if (pf->tvar->name == NULL) |
818 | return -ENOMEM; | 913 | return -ENOMEM; |
819 | 914 | ||
820 | pr_debug("Searching '%s' variable in context.\n", | 915 | pr_debug("Searching '%s' variable in context.\n", |
821 | pf->pvar->var); | 916 | pf->pvar->var); |
822 | /* Search child die for local variables and parameters. */ | 917 | /* Search child die for local variables and parameters. */ |
823 | if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) | 918 | if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) |
824 | ret = convert_variable(&vr_die, pf); | 919 | ret = convert_variable(&vr_die, pf); |
825 | else { | 920 | else { |
826 | /* Search upper class */ | 921 | /* Search upper class */ |
827 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | 922 | nscopes = dwarf_getscopes_die(sp_die, &scopes); |
828 | while (nscopes-- > 1) { | 923 | while (nscopes-- > 1) { |
829 | pr_debug("Searching variables in %s\n", | 924 | pr_debug("Searching variables in %s\n", |
830 | dwarf_diename(&scopes[nscopes])); | 925 | dwarf_diename(&scopes[nscopes])); |
831 | /* We should check this scope, so give dummy address */ | 926 | /* We should check this scope, so give dummy address */ |
832 | if (die_find_variable_at(&scopes[nscopes], | 927 | if (die_find_variable_at(&scopes[nscopes], |
833 | pf->pvar->var, 0, | 928 | pf->pvar->var, 0, |
834 | &vr_die)) { | 929 | &vr_die)) { |
835 | ret = convert_variable(&vr_die, pf); | 930 | ret = convert_variable(&vr_die, pf); |
836 | goto found; | 931 | goto found; |
837 | } | 932 | } |
838 | } | 933 | } |
839 | if (scopes) | 934 | if (scopes) |
840 | free(scopes); | 935 | free(scopes); |
841 | ret = -ENOENT; | 936 | ret = -ENOENT; |
842 | } | 937 | } |
843 | found: | 938 | found: |
844 | if (ret < 0) | 939 | if (ret < 0) |
845 | pr_warning("Failed to find '%s' in this function.\n", | 940 | pr_warning("Failed to find '%s' in this function.\n", |
846 | pf->pvar->var); | 941 | pf->pvar->var); |
847 | return ret; | 942 | return ret; |
848 | } | 943 | } |
849 | 944 | ||
850 | /* Convert subprogram DIE to trace point */ | 945 | /* Convert subprogram DIE to trace point */ |
851 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | 946 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, |
852 | bool retprobe, struct probe_trace_point *tp) | 947 | bool retprobe, struct probe_trace_point *tp) |
853 | { | 948 | { |
854 | Dwarf_Addr eaddr; | 949 | Dwarf_Addr eaddr; |
855 | const char *name; | 950 | const char *name; |
856 | 951 | ||
857 | /* Copy the name of probe point */ | 952 | /* Copy the name of probe point */ |
858 | name = dwarf_diename(sp_die); | 953 | name = dwarf_diename(sp_die); |
859 | if (name) { | 954 | if (name) { |
860 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { | 955 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
861 | pr_warning("Failed to get entry pc of %s\n", | 956 | pr_warning("Failed to get entry pc of %s\n", |
862 | dwarf_diename(sp_die)); | 957 | dwarf_diename(sp_die)); |
863 | return -ENOENT; | 958 | return -ENOENT; |
864 | } | 959 | } |
865 | tp->symbol = strdup(name); | 960 | tp->symbol = strdup(name); |
866 | if (tp->symbol == NULL) | 961 | if (tp->symbol == NULL) |
867 | return -ENOMEM; | 962 | return -ENOMEM; |
868 | tp->offset = (unsigned long)(paddr - eaddr); | 963 | tp->offset = (unsigned long)(paddr - eaddr); |
869 | } else | 964 | } else |
870 | /* This function has no name. */ | 965 | /* This function has no name. */ |
871 | tp->offset = (unsigned long)paddr; | 966 | tp->offset = (unsigned long)paddr; |
872 | 967 | ||
873 | /* Return probe must be on the head of a subprogram */ | 968 | /* Return probe must be on the head of a subprogram */ |
874 | if (retprobe) { | 969 | if (retprobe) { |
875 | if (eaddr != paddr) { | 970 | if (eaddr != paddr) { |
876 | pr_warning("Return probe must be on the head of" | 971 | pr_warning("Return probe must be on the head of" |
877 | " a real function\n"); | 972 | " a real function\n"); |
878 | return -EINVAL; | 973 | return -EINVAL; |
879 | } | 974 | } |
880 | tp->retprobe = true; | 975 | tp->retprobe = true; |
881 | } | 976 | } |
882 | 977 | ||
883 | return 0; | 978 | return 0; |
884 | } | 979 | } |
885 | 980 | ||
886 | /* Call probe_finder callback with real subprogram DIE */ | 981 | /* Call probe_finder callback with real subprogram DIE */ |
887 | static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | 982 | static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) |
888 | { | 983 | { |
889 | Dwarf_Die die_mem; | 984 | Dwarf_Die die_mem; |
890 | Dwarf_Attribute fb_attr; | 985 | Dwarf_Attribute fb_attr; |
891 | size_t nops; | 986 | size_t nops; |
892 | int ret; | 987 | int ret; |
893 | 988 | ||
894 | /* If no real subprogram, find a real one */ | 989 | /* If no real subprogram, find a real one */ |
895 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 990 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { |
896 | sp_die = die_find_real_subprogram(&pf->cu_die, | 991 | sp_die = die_find_real_subprogram(&pf->cu_die, |
897 | pf->addr, &die_mem); | 992 | pf->addr, &die_mem); |
898 | if (!sp_die) { | 993 | if (!sp_die) { |
899 | pr_warning("Failed to find probe point in any " | 994 | pr_warning("Failed to find probe point in any " |
900 | "functions.\n"); | 995 | "functions.\n"); |
901 | return -ENOENT; | 996 | return -ENOENT; |
902 | } | 997 | } |
903 | } | 998 | } |
904 | 999 | ||
905 | /* Get the frame base attribute/ops */ | 1000 | /* Get the frame base attribute/ops */ |
906 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 1001 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); |
907 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 1002 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
908 | if (ret <= 0 || nops == 0) { | 1003 | if (ret <= 0 || nops == 0) { |
909 | pf->fb_ops = NULL; | 1004 | pf->fb_ops = NULL; |
910 | #if _ELFUTILS_PREREQ(0, 142) | 1005 | #if _ELFUTILS_PREREQ(0, 142) |
911 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && | 1006 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && |
912 | pf->cfi != NULL) { | 1007 | pf->cfi != NULL) { |
913 | Dwarf_Frame *frame; | 1008 | Dwarf_Frame *frame; |
914 | if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || | 1009 | if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || |
915 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { | 1010 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { |
916 | pr_warning("Failed to get CFA on 0x%jx\n", | 1011 | pr_warning("Failed to get CFA on 0x%jx\n", |
917 | (uintmax_t)pf->addr); | 1012 | (uintmax_t)pf->addr); |
918 | return -ENOENT; | 1013 | return -ENOENT; |
919 | } | 1014 | } |
920 | #endif | 1015 | #endif |
921 | } | 1016 | } |
922 | 1017 | ||
923 | /* Call finder's callback handler */ | 1018 | /* Call finder's callback handler */ |
924 | ret = pf->callback(sp_die, pf); | 1019 | ret = pf->callback(sp_die, pf); |
925 | 1020 | ||
926 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 1021 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
927 | pf->fb_ops = NULL; | 1022 | pf->fb_ops = NULL; |
928 | 1023 | ||
929 | return ret; | 1024 | return ret; |
930 | } | 1025 | } |
931 | 1026 | ||
932 | /* Find probe point from its line number */ | 1027 | /* Find probe point from its line number */ |
933 | static int find_probe_point_by_line(struct probe_finder *pf) | 1028 | static int find_probe_point_by_line(struct probe_finder *pf) |
934 | { | 1029 | { |
935 | Dwarf_Lines *lines; | 1030 | Dwarf_Lines *lines; |
936 | Dwarf_Line *line; | 1031 | Dwarf_Line *line; |
937 | size_t nlines, i; | 1032 | size_t nlines, i; |
938 | Dwarf_Addr addr; | 1033 | Dwarf_Addr addr; |
939 | int lineno; | 1034 | int lineno; |
940 | int ret = 0; | 1035 | int ret = 0; |
941 | 1036 | ||
942 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { | 1037 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
943 | pr_warning("No source lines found in this CU.\n"); | 1038 | pr_warning("No source lines found in this CU.\n"); |
944 | return -ENOENT; | 1039 | return -ENOENT; |
945 | } | 1040 | } |
946 | 1041 | ||
947 | for (i = 0; i < nlines && ret == 0; i++) { | 1042 | for (i = 0; i < nlines && ret == 0; i++) { |
948 | line = dwarf_onesrcline(lines, i); | 1043 | line = dwarf_onesrcline(lines, i); |
949 | if (dwarf_lineno(line, &lineno) != 0 || | 1044 | if (dwarf_lineno(line, &lineno) != 0 || |
950 | lineno != pf->lno) | 1045 | lineno != pf->lno) |
951 | continue; | 1046 | continue; |
952 | 1047 | ||
953 | /* TODO: Get fileno from line, but how? */ | 1048 | /* TODO: Get fileno from line, but how? */ |
954 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 1049 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
955 | continue; | 1050 | continue; |
956 | 1051 | ||
957 | if (dwarf_lineaddr(line, &addr) != 0) { | 1052 | if (dwarf_lineaddr(line, &addr) != 0) { |
958 | pr_warning("Failed to get the address of the line.\n"); | 1053 | pr_warning("Failed to get the address of the line.\n"); |
959 | return -ENOENT; | 1054 | return -ENOENT; |
960 | } | 1055 | } |
961 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", | 1056 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", |
962 | (int)i, lineno, (uintmax_t)addr); | 1057 | (int)i, lineno, (uintmax_t)addr); |
963 | pf->addr = addr; | 1058 | pf->addr = addr; |
964 | 1059 | ||
965 | ret = call_probe_finder(NULL, pf); | 1060 | ret = call_probe_finder(NULL, pf); |
966 | /* Continuing, because target line might be inlined. */ | 1061 | /* Continuing, because target line might be inlined. */ |
967 | } | 1062 | } |
968 | return ret; | 1063 | return ret; |
969 | } | 1064 | } |
970 | 1065 | ||
971 | /* Find lines which match lazy pattern */ | 1066 | /* Find lines which match lazy pattern */ |
972 | static int find_lazy_match_lines(struct list_head *head, | 1067 | static int find_lazy_match_lines(struct list_head *head, |
973 | const char *fname, const char *pat) | 1068 | const char *fname, const char *pat) |
974 | { | 1069 | { |
975 | char *fbuf, *p1, *p2; | 1070 | char *fbuf, *p1, *p2; |
976 | int fd, line, nlines = -1; | 1071 | int fd, line, nlines = -1; |
977 | struct stat st; | 1072 | struct stat st; |
978 | 1073 | ||
979 | fd = open(fname, O_RDONLY); | 1074 | fd = open(fname, O_RDONLY); |
980 | if (fd < 0) { | 1075 | if (fd < 0) { |
981 | pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); | 1076 | pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); |
982 | return -errno; | 1077 | return -errno; |
983 | } | 1078 | } |
984 | 1079 | ||
985 | if (fstat(fd, &st) < 0) { | 1080 | if (fstat(fd, &st) < 0) { |
986 | pr_warning("Failed to get the size of %s: %s\n", | 1081 | pr_warning("Failed to get the size of %s: %s\n", |
987 | fname, strerror(errno)); | 1082 | fname, strerror(errno)); |
988 | nlines = -errno; | 1083 | nlines = -errno; |
989 | goto out_close; | 1084 | goto out_close; |
990 | } | 1085 | } |
991 | 1086 | ||
992 | nlines = -ENOMEM; | 1087 | nlines = -ENOMEM; |
993 | fbuf = malloc(st.st_size + 2); | 1088 | fbuf = malloc(st.st_size + 2); |
994 | if (fbuf == NULL) | 1089 | if (fbuf == NULL) |
995 | goto out_close; | 1090 | goto out_close; |
996 | if (read(fd, fbuf, st.st_size) < 0) { | 1091 | if (read(fd, fbuf, st.st_size) < 0) { |
997 | pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); | 1092 | pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); |
998 | nlines = -errno; | 1093 | nlines = -errno; |
999 | goto out_free_fbuf; | 1094 | goto out_free_fbuf; |
1000 | } | 1095 | } |
1001 | fbuf[st.st_size] = '\n'; /* Dummy line */ | 1096 | fbuf[st.st_size] = '\n'; /* Dummy line */ |
1002 | fbuf[st.st_size + 1] = '\0'; | 1097 | fbuf[st.st_size + 1] = '\0'; |
1003 | p1 = fbuf; | 1098 | p1 = fbuf; |
1004 | line = 1; | 1099 | line = 1; |
1005 | nlines = 0; | 1100 | nlines = 0; |
1006 | while ((p2 = strchr(p1, '\n')) != NULL) { | 1101 | while ((p2 = strchr(p1, '\n')) != NULL) { |
1007 | *p2 = '\0'; | 1102 | *p2 = '\0'; |
1008 | if (strlazymatch(p1, pat)) { | 1103 | if (strlazymatch(p1, pat)) { |
1009 | line_list__add_line(head, line); | 1104 | line_list__add_line(head, line); |
1010 | nlines++; | 1105 | nlines++; |
1011 | } | 1106 | } |
1012 | line++; | 1107 | line++; |
1013 | p1 = p2 + 1; | 1108 | p1 = p2 + 1; |
1014 | } | 1109 | } |
1015 | out_free_fbuf: | 1110 | out_free_fbuf: |
1016 | free(fbuf); | 1111 | free(fbuf); |
1017 | out_close: | 1112 | out_close: |
1018 | close(fd); | 1113 | close(fd); |
1019 | return nlines; | 1114 | return nlines; |
1020 | } | 1115 | } |
1021 | 1116 | ||
1022 | /* Find probe points from lazy pattern */ | 1117 | /* Find probe points from lazy pattern */ |
1023 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 1118 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
1024 | { | 1119 | { |
1025 | Dwarf_Lines *lines; | 1120 | Dwarf_Lines *lines; |
1026 | Dwarf_Line *line; | 1121 | Dwarf_Line *line; |
1027 | size_t nlines, i; | 1122 | size_t nlines, i; |
1028 | Dwarf_Addr addr; | 1123 | Dwarf_Addr addr; |
1029 | Dwarf_Die die_mem; | 1124 | Dwarf_Die die_mem; |
1030 | int lineno; | 1125 | int lineno; |
1031 | int ret = 0; | 1126 | int ret = 0; |
1032 | 1127 | ||
1033 | if (list_empty(&pf->lcache)) { | 1128 | if (list_empty(&pf->lcache)) { |
1034 | /* Matching lazy line pattern */ | 1129 | /* Matching lazy line pattern */ |
1035 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 1130 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
1036 | pf->pev->point.lazy_line); | 1131 | pf->pev->point.lazy_line); |
1037 | if (ret == 0) { | 1132 | if (ret == 0) { |
1038 | pr_debug("No matched lines found in %s.\n", pf->fname); | 1133 | pr_debug("No matched lines found in %s.\n", pf->fname); |
1039 | return 0; | 1134 | return 0; |
1040 | } else if (ret < 0) | 1135 | } else if (ret < 0) |
1041 | return ret; | 1136 | return ret; |
1042 | } | 1137 | } |
1043 | 1138 | ||
1044 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { | 1139 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
1045 | pr_warning("No source lines found in this CU.\n"); | 1140 | pr_warning("No source lines found in this CU.\n"); |
1046 | return -ENOENT; | 1141 | return -ENOENT; |
1047 | } | 1142 | } |
1048 | 1143 | ||
1049 | for (i = 0; i < nlines && ret >= 0; i++) { | 1144 | for (i = 0; i < nlines && ret >= 0; i++) { |
1050 | line = dwarf_onesrcline(lines, i); | 1145 | line = dwarf_onesrcline(lines, i); |
1051 | 1146 | ||
1052 | if (dwarf_lineno(line, &lineno) != 0 || | 1147 | if (dwarf_lineno(line, &lineno) != 0 || |
1053 | !line_list__has_line(&pf->lcache, lineno)) | 1148 | !line_list__has_line(&pf->lcache, lineno)) |
1054 | continue; | 1149 | continue; |
1055 | 1150 | ||
1056 | /* TODO: Get fileno from line, but how? */ | 1151 | /* TODO: Get fileno from line, but how? */ |
1057 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 1152 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
1058 | continue; | 1153 | continue; |
1059 | 1154 | ||
1060 | if (dwarf_lineaddr(line, &addr) != 0) { | 1155 | if (dwarf_lineaddr(line, &addr) != 0) { |
1061 | pr_debug("Failed to get the address of line %d.\n", | 1156 | pr_debug("Failed to get the address of line %d.\n", |
1062 | lineno); | 1157 | lineno); |
1063 | continue; | 1158 | continue; |
1064 | } | 1159 | } |
1065 | if (sp_die) { | 1160 | if (sp_die) { |
1066 | /* Address filtering 1: does sp_die include addr? */ | 1161 | /* Address filtering 1: does sp_die include addr? */ |
1067 | if (!dwarf_haspc(sp_die, addr)) | 1162 | if (!dwarf_haspc(sp_die, addr)) |
1068 | continue; | 1163 | continue; |
1069 | /* Address filtering 2: No child include addr? */ | 1164 | /* Address filtering 2: No child include addr? */ |
1070 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) | 1165 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) |
1071 | continue; | 1166 | continue; |
1072 | } | 1167 | } |
1073 | 1168 | ||
1074 | pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", | 1169 | pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", |
1075 | (int)i, lineno, (unsigned long long)addr); | 1170 | (int)i, lineno, (unsigned long long)addr); |
1076 | pf->addr = addr; | 1171 | pf->addr = addr; |
1077 | 1172 | ||
1078 | ret = call_probe_finder(sp_die, pf); | 1173 | ret = call_probe_finder(sp_die, pf); |
1079 | /* Continuing, because target line might be inlined. */ | 1174 | /* Continuing, because target line might be inlined. */ |
1080 | } | 1175 | } |
1081 | /* TODO: deallocate lines, but how? */ | 1176 | /* TODO: deallocate lines, but how? */ |
1082 | return ret; | 1177 | return ret; |
1083 | } | 1178 | } |
1084 | 1179 | ||
1085 | /* Callback parameter with return value */ | 1180 | /* Callback parameter with return value */ |
1086 | struct dwarf_callback_param { | 1181 | struct dwarf_callback_param { |
1087 | void *data; | 1182 | void *data; |
1088 | int retval; | 1183 | int retval; |
1089 | }; | 1184 | }; |
1090 | 1185 | ||
1091 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 1186 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
1092 | { | 1187 | { |
1093 | struct dwarf_callback_param *param = data; | 1188 | struct dwarf_callback_param *param = data; |
1094 | struct probe_finder *pf = param->data; | 1189 | struct probe_finder *pf = param->data; |
1095 | struct perf_probe_point *pp = &pf->pev->point; | 1190 | struct perf_probe_point *pp = &pf->pev->point; |
1096 | Dwarf_Addr addr; | 1191 | Dwarf_Addr addr; |
1097 | 1192 | ||
1098 | if (pp->lazy_line) | 1193 | if (pp->lazy_line) |
1099 | param->retval = find_probe_point_lazy(in_die, pf); | 1194 | param->retval = find_probe_point_lazy(in_die, pf); |
1100 | else { | 1195 | else { |
1101 | /* Get probe address */ | 1196 | /* Get probe address */ |
1102 | if (dwarf_entrypc(in_die, &addr) != 0) { | 1197 | if (dwarf_entrypc(in_die, &addr) != 0) { |
1103 | pr_warning("Failed to get entry pc of %s.\n", | 1198 | pr_warning("Failed to get entry pc of %s.\n", |
1104 | dwarf_diename(in_die)); | 1199 | dwarf_diename(in_die)); |
1105 | param->retval = -ENOENT; | 1200 | param->retval = -ENOENT; |
1106 | return DWARF_CB_ABORT; | 1201 | return DWARF_CB_ABORT; |
1107 | } | 1202 | } |
1108 | pf->addr = addr; | 1203 | pf->addr = addr; |
1109 | pf->addr += pp->offset; | 1204 | pf->addr += pp->offset; |
1110 | pr_debug("found inline addr: 0x%jx\n", | 1205 | pr_debug("found inline addr: 0x%jx\n", |
1111 | (uintmax_t)pf->addr); | 1206 | (uintmax_t)pf->addr); |
1112 | 1207 | ||
1113 | param->retval = call_probe_finder(in_die, pf); | 1208 | param->retval = call_probe_finder(in_die, pf); |
1114 | if (param->retval < 0) | 1209 | if (param->retval < 0) |
1115 | return DWARF_CB_ABORT; | 1210 | return DWARF_CB_ABORT; |
1116 | } | 1211 | } |
1117 | 1212 | ||
1118 | return DWARF_CB_OK; | 1213 | return DWARF_CB_OK; |
1119 | } | 1214 | } |
1120 | 1215 | ||
1121 | /* Search function from function name */ | 1216 | /* Search function from function name */ |
1122 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 1217 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
1123 | { | 1218 | { |
1124 | struct dwarf_callback_param *param = data; | 1219 | struct dwarf_callback_param *param = data; |
1125 | struct probe_finder *pf = param->data; | 1220 | struct probe_finder *pf = param->data; |
1126 | struct perf_probe_point *pp = &pf->pev->point; | 1221 | struct perf_probe_point *pp = &pf->pev->point; |
1127 | 1222 | ||
1128 | /* Check tag and diename */ | 1223 | /* Check tag and diename */ |
1129 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 1224 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || |
1130 | !die_compare_name(sp_die, pp->function)) | 1225 | !die_compare_name(sp_die, pp->function)) |
1131 | return DWARF_CB_OK; | 1226 | return DWARF_CB_OK; |
1132 | 1227 | ||
1133 | pf->fname = dwarf_decl_file(sp_die); | 1228 | pf->fname = dwarf_decl_file(sp_die); |
1134 | if (pp->line) { /* Function relative line */ | 1229 | if (pp->line) { /* Function relative line */ |
1135 | dwarf_decl_line(sp_die, &pf->lno); | 1230 | dwarf_decl_line(sp_die, &pf->lno); |
1136 | pf->lno += pp->line; | 1231 | pf->lno += pp->line; |
1137 | param->retval = find_probe_point_by_line(pf); | 1232 | param->retval = find_probe_point_by_line(pf); |
1138 | } else if (!dwarf_func_inline(sp_die)) { | 1233 | } else if (!dwarf_func_inline(sp_die)) { |
1139 | /* Real function */ | 1234 | /* Real function */ |
1140 | if (pp->lazy_line) | 1235 | if (pp->lazy_line) |
1141 | param->retval = find_probe_point_lazy(sp_die, pf); | 1236 | param->retval = find_probe_point_lazy(sp_die, pf); |
1142 | else { | 1237 | else { |
1143 | if (dwarf_entrypc(sp_die, &pf->addr) != 0) { | 1238 | if (dwarf_entrypc(sp_die, &pf->addr) != 0) { |
1144 | pr_warning("Failed to get entry pc of %s.\n", | 1239 | pr_warning("Failed to get entry pc of %s.\n", |
1145 | dwarf_diename(sp_die)); | 1240 | dwarf_diename(sp_die)); |
1146 | param->retval = -ENOENT; | 1241 | param->retval = -ENOENT; |
1147 | return DWARF_CB_ABORT; | 1242 | return DWARF_CB_ABORT; |
1148 | } | 1243 | } |
1149 | pf->addr += pp->offset; | 1244 | pf->addr += pp->offset; |
1150 | /* TODO: Check the address in this function */ | 1245 | /* TODO: Check the address in this function */ |
1151 | param->retval = call_probe_finder(sp_die, pf); | 1246 | param->retval = call_probe_finder(sp_die, pf); |
1152 | } | 1247 | } |
1153 | } else { | 1248 | } else { |
1154 | struct dwarf_callback_param _param = {.data = (void *)pf, | 1249 | struct dwarf_callback_param _param = {.data = (void *)pf, |
1155 | .retval = 0}; | 1250 | .retval = 0}; |
1156 | /* Inlined function: search instances */ | 1251 | /* Inlined function: search instances */ |
1157 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 1252 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, |
1158 | &_param); | 1253 | &_param); |
1159 | param->retval = _param.retval; | 1254 | param->retval = _param.retval; |
1160 | } | 1255 | } |
1161 | 1256 | ||
1162 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1257 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
1163 | } | 1258 | } |
1164 | 1259 | ||
1165 | static int find_probe_point_by_func(struct probe_finder *pf) | 1260 | static int find_probe_point_by_func(struct probe_finder *pf) |
1166 | { | 1261 | { |
1167 | struct dwarf_callback_param _param = {.data = (void *)pf, | 1262 | struct dwarf_callback_param _param = {.data = (void *)pf, |
1168 | .retval = 0}; | 1263 | .retval = 0}; |
1169 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); | 1264 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); |
1170 | return _param.retval; | 1265 | return _param.retval; |
1171 | } | 1266 | } |
1172 | 1267 | ||
1173 | /* Find probe points from debuginfo */ | 1268 | /* Find probe points from debuginfo */ |
1174 | static int find_probes(int fd, struct probe_finder *pf) | 1269 | static int find_probes(int fd, struct probe_finder *pf) |
1175 | { | 1270 | { |
1176 | struct perf_probe_point *pp = &pf->pev->point; | 1271 | struct perf_probe_point *pp = &pf->pev->point; |
1177 | Dwarf_Off off, noff; | 1272 | Dwarf_Off off, noff; |
1178 | size_t cuhl; | 1273 | size_t cuhl; |
1179 | Dwarf_Die *diep; | 1274 | Dwarf_Die *diep; |
1180 | Dwarf *dbg; | 1275 | Dwarf *dbg = NULL; |
1276 | Dwfl *dwfl; | ||
1277 | Dwarf_Addr bias; /* Currently ignored */ | ||
1181 | int ret = 0; | 1278 | int ret = 0; |
1182 | 1279 | ||
1183 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1280 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); |
1184 | if (!dbg) { | 1281 | if (!dbg) { |
1185 | pr_warning("No dwarf info found in the vmlinux - " | 1282 | pr_warning("No dwarf info found in the vmlinux - " |
1186 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1283 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
1187 | return -EBADF; | 1284 | return -EBADF; |
1188 | } | 1285 | } |
1189 | 1286 | ||
1190 | #if _ELFUTILS_PREREQ(0, 142) | 1287 | #if _ELFUTILS_PREREQ(0, 142) |
1191 | /* Get the call frame information from this dwarf */ | 1288 | /* Get the call frame information from this dwarf */ |
1192 | pf->cfi = dwarf_getcfi(dbg); | 1289 | pf->cfi = dwarf_getcfi(dbg); |
1193 | #endif | 1290 | #endif |
1194 | 1291 | ||
1195 | off = 0; | 1292 | off = 0; |
1196 | line_list__init(&pf->lcache); | 1293 | line_list__init(&pf->lcache); |
1197 | /* Loop on CUs (Compilation Unit) */ | 1294 | /* Loop on CUs (Compilation Unit) */ |
1198 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && | 1295 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && |
1199 | ret >= 0) { | 1296 | ret >= 0) { |
1200 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1297 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1201 | diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); | 1298 | diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); |
1202 | if (!diep) | 1299 | if (!diep) |
1203 | continue; | 1300 | continue; |
1204 | 1301 | ||
1205 | /* Check if target file is included. */ | 1302 | /* Check if target file is included. */ |
1206 | if (pp->file) | 1303 | if (pp->file) |
1207 | pf->fname = cu_find_realpath(&pf->cu_die, pp->file); | 1304 | pf->fname = cu_find_realpath(&pf->cu_die, pp->file); |
1208 | else | 1305 | else |
1209 | pf->fname = NULL; | 1306 | pf->fname = NULL; |
1210 | 1307 | ||
1211 | if (!pp->file || pf->fname) { | 1308 | if (!pp->file || pf->fname) { |
1212 | if (pp->function) | 1309 | if (pp->function) |
1213 | ret = find_probe_point_by_func(pf); | 1310 | ret = find_probe_point_by_func(pf); |
1214 | else if (pp->lazy_line) | 1311 | else if (pp->lazy_line) |
1215 | ret = find_probe_point_lazy(NULL, pf); | 1312 | ret = find_probe_point_lazy(NULL, pf); |
1216 | else { | 1313 | else { |
1217 | pf->lno = pp->line; | 1314 | pf->lno = pp->line; |
1218 | ret = find_probe_point_by_line(pf); | 1315 | ret = find_probe_point_by_line(pf); |
1219 | } | 1316 | } |
1220 | } | 1317 | } |
1221 | off = noff; | 1318 | off = noff; |
1222 | } | 1319 | } |
1223 | line_list__free(&pf->lcache); | 1320 | line_list__free(&pf->lcache); |
1224 | dwarf_end(dbg); | 1321 | if (dwfl) |
1322 | dwfl_end(dwfl); | ||
1225 | 1323 | ||
1226 | return ret; | 1324 | return ret; |
1227 | } | 1325 | } |
1228 | 1326 | ||
1229 | /* Add a found probe point into trace event list */ | 1327 | /* Add a found probe point into trace event list */ |
1230 | static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | 1328 | static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) |
1231 | { | 1329 | { |
1232 | struct trace_event_finder *tf = | 1330 | struct trace_event_finder *tf = |
1233 | container_of(pf, struct trace_event_finder, pf); | 1331 | container_of(pf, struct trace_event_finder, pf); |
1234 | struct probe_trace_event *tev; | 1332 | struct probe_trace_event *tev; |
1235 | int ret, i; | 1333 | int ret, i; |
1236 | 1334 | ||
1237 | /* Check number of tevs */ | 1335 | /* Check number of tevs */ |
1238 | if (tf->ntevs == tf->max_tevs) { | 1336 | if (tf->ntevs == tf->max_tevs) { |
1239 | pr_warning("Too many( > %d) probe point found.\n", | 1337 | pr_warning("Too many( > %d) probe point found.\n", |
1240 | tf->max_tevs); | 1338 | tf->max_tevs); |
1241 | return -ERANGE; | 1339 | return -ERANGE; |
1242 | } | 1340 | } |
1243 | tev = &tf->tevs[tf->ntevs++]; | 1341 | tev = &tf->tevs[tf->ntevs++]; |
1244 | 1342 | ||
1245 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1343 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, |
1246 | &tev->point); | 1344 | &tev->point); |
1247 | if (ret < 0) | 1345 | if (ret < 0) |
1248 | return ret; | 1346 | return ret; |
1249 | 1347 | ||
1250 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, | 1348 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, |
1251 | tev->point.offset); | 1349 | tev->point.offset); |
1252 | 1350 | ||
1253 | /* Find each argument */ | 1351 | /* Find each argument */ |
1254 | tev->nargs = pf->pev->nargs; | 1352 | tev->nargs = pf->pev->nargs; |
1255 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | 1353 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); |
1256 | if (tev->args == NULL) | 1354 | if (tev->args == NULL) |
1257 | return -ENOMEM; | 1355 | return -ENOMEM; |
1258 | for (i = 0; i < pf->pev->nargs; i++) { | 1356 | for (i = 0; i < pf->pev->nargs; i++) { |
1259 | pf->pvar = &pf->pev->args[i]; | 1357 | pf->pvar = &pf->pev->args[i]; |
1260 | pf->tvar = &tev->args[i]; | 1358 | pf->tvar = &tev->args[i]; |
1261 | ret = find_variable(sp_die, pf); | 1359 | ret = find_variable(sp_die, pf); |
1262 | if (ret != 0) | 1360 | if (ret != 0) |
1263 | return ret; | 1361 | return ret; |
1264 | } | 1362 | } |
1265 | 1363 | ||
1266 | return 0; | 1364 | return 0; |
1267 | } | 1365 | } |
1268 | 1366 | ||
1269 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | 1367 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
1270 | int find_probe_trace_events(int fd, struct perf_probe_event *pev, | 1368 | int find_probe_trace_events(int fd, struct perf_probe_event *pev, |
1271 | struct probe_trace_event **tevs, int max_tevs) | 1369 | struct probe_trace_event **tevs, int max_tevs) |
1272 | { | 1370 | { |
1273 | struct trace_event_finder tf = { | 1371 | struct trace_event_finder tf = { |
1274 | .pf = {.pev = pev, .callback = add_probe_trace_event}, | 1372 | .pf = {.pev = pev, .callback = add_probe_trace_event}, |
1275 | .max_tevs = max_tevs}; | 1373 | .max_tevs = max_tevs}; |
1276 | int ret; | 1374 | int ret; |
1277 | 1375 | ||
1278 | /* Allocate result tevs array */ | 1376 | /* Allocate result tevs array */ |
1279 | *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); | 1377 | *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); |
1280 | if (*tevs == NULL) | 1378 | if (*tevs == NULL) |
1281 | return -ENOMEM; | 1379 | return -ENOMEM; |
1282 | 1380 | ||
1283 | tf.tevs = *tevs; | 1381 | tf.tevs = *tevs; |
1284 | tf.ntevs = 0; | 1382 | tf.ntevs = 0; |
1285 | 1383 | ||
1286 | ret = find_probes(fd, &tf.pf); | 1384 | ret = find_probes(fd, &tf.pf); |
1287 | if (ret < 0) { | 1385 | if (ret < 0) { |
1288 | free(*tevs); | 1386 | free(*tevs); |
1289 | *tevs = NULL; | 1387 | *tevs = NULL; |
1290 | return ret; | 1388 | return ret; |
1291 | } | 1389 | } |
1292 | 1390 | ||
1293 | return (ret < 0) ? ret : tf.ntevs; | 1391 | return (ret < 0) ? ret : tf.ntevs; |
1294 | } | 1392 | } |
1295 | 1393 | ||
1296 | #define MAX_VAR_LEN 64 | 1394 | #define MAX_VAR_LEN 64 |
1297 | 1395 | ||
1298 | /* Collect available variables in this scope */ | 1396 | /* Collect available variables in this scope */ |
1299 | static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | 1397 | static int collect_variables_cb(Dwarf_Die *die_mem, void *data) |
1300 | { | 1398 | { |
1301 | struct available_var_finder *af = data; | 1399 | struct available_var_finder *af = data; |
1302 | struct variable_list *vl; | 1400 | struct variable_list *vl; |
1303 | char buf[MAX_VAR_LEN]; | 1401 | char buf[MAX_VAR_LEN]; |
1304 | int tag, ret; | 1402 | int tag, ret; |
1305 | 1403 | ||
1306 | vl = &af->vls[af->nvls - 1]; | 1404 | vl = &af->vls[af->nvls - 1]; |
1307 | 1405 | ||
1308 | tag = dwarf_tag(die_mem); | 1406 | tag = dwarf_tag(die_mem); |
1309 | if (tag == DW_TAG_formal_parameter || | 1407 | if (tag == DW_TAG_formal_parameter || |
1310 | tag == DW_TAG_variable) { | 1408 | tag == DW_TAG_variable) { |
1311 | ret = convert_variable_location(die_mem, af->pf.addr, | 1409 | ret = convert_variable_location(die_mem, af->pf.addr, |
1312 | af->pf.fb_ops, NULL); | 1410 | af->pf.fb_ops, NULL); |
1313 | if (ret == 0) { | 1411 | if (ret == 0) { |
1314 | ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); | 1412 | ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); |
1315 | pr_debug2("Add new var: %s\n", buf); | 1413 | pr_debug2("Add new var: %s\n", buf); |
1316 | if (ret > 0) | 1414 | if (ret > 0) |
1317 | strlist__add(vl->vars, buf); | 1415 | strlist__add(vl->vars, buf); |
1318 | } | 1416 | } |
1319 | } | 1417 | } |
1320 | 1418 | ||
1321 | if (af->child && dwarf_haspc(die_mem, af->pf.addr)) | 1419 | if (af->child && dwarf_haspc(die_mem, af->pf.addr)) |
1322 | return DIE_FIND_CB_CONTINUE; | 1420 | return DIE_FIND_CB_CONTINUE; |
1323 | else | 1421 | else |
1324 | return DIE_FIND_CB_SIBLING; | 1422 | return DIE_FIND_CB_SIBLING; |
1325 | } | 1423 | } |
1326 | 1424 | ||
1327 | /* Add a found vars into available variables list */ | 1425 | /* Add a found vars into available variables list */ |
1328 | static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | 1426 | static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) |
1329 | { | 1427 | { |
1330 | struct available_var_finder *af = | 1428 | struct available_var_finder *af = |
1331 | container_of(pf, struct available_var_finder, pf); | 1429 | container_of(pf, struct available_var_finder, pf); |
1332 | struct variable_list *vl; | 1430 | struct variable_list *vl; |
1333 | Dwarf_Die die_mem, *scopes = NULL; | 1431 | Dwarf_Die die_mem, *scopes = NULL; |
1334 | int ret, nscopes; | 1432 | int ret, nscopes; |
1335 | 1433 | ||
1336 | /* Check number of tevs */ | 1434 | /* Check number of tevs */ |
1337 | if (af->nvls == af->max_vls) { | 1435 | if (af->nvls == af->max_vls) { |
1338 | pr_warning("Too many( > %d) probe point found.\n", af->max_vls); | 1436 | pr_warning("Too many( > %d) probe point found.\n", af->max_vls); |
1339 | return -ERANGE; | 1437 | return -ERANGE; |
1340 | } | 1438 | } |
1341 | vl = &af->vls[af->nvls++]; | 1439 | vl = &af->vls[af->nvls++]; |
1342 | 1440 | ||
1343 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1441 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, |
1344 | &vl->point); | 1442 | &vl->point); |
1345 | if (ret < 0) | 1443 | if (ret < 0) |
1346 | return ret; | 1444 | return ret; |
1347 | 1445 | ||
1348 | pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, | 1446 | pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, |
1349 | vl->point.offset); | 1447 | vl->point.offset); |
1350 | 1448 | ||
1351 | /* Find local variables */ | 1449 | /* Find local variables */ |
1352 | vl->vars = strlist__new(true, NULL); | 1450 | vl->vars = strlist__new(true, NULL); |
1353 | if (vl->vars == NULL) | 1451 | if (vl->vars == NULL) |
1354 | return -ENOMEM; | 1452 | return -ENOMEM; |
1355 | af->child = true; | 1453 | af->child = true; |
1356 | die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); | 1454 | die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); |
1357 | 1455 | ||
1358 | /* Find external variables */ | 1456 | /* Find external variables */ |
1359 | if (!af->externs) | 1457 | if (!af->externs) |
1360 | goto out; | 1458 | goto out; |
1361 | /* Don't need to search child DIE for externs. */ | 1459 | /* Don't need to search child DIE for externs. */ |
1362 | af->child = false; | 1460 | af->child = false; |
1363 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | 1461 | nscopes = dwarf_getscopes_die(sp_die, &scopes); |
1364 | while (nscopes-- > 1) | 1462 | while (nscopes-- > 1) |
1365 | die_find_child(&scopes[nscopes], collect_variables_cb, | 1463 | die_find_child(&scopes[nscopes], collect_variables_cb, |
1366 | (void *)af, &die_mem); | 1464 | (void *)af, &die_mem); |
1367 | if (scopes) | 1465 | if (scopes) |
1368 | free(scopes); | 1466 | free(scopes); |
1369 | 1467 | ||
1370 | out: | 1468 | out: |
1371 | if (strlist__empty(vl->vars)) { | 1469 | if (strlist__empty(vl->vars)) { |
1372 | strlist__delete(vl->vars); | 1470 | strlist__delete(vl->vars); |
1373 | vl->vars = NULL; | 1471 | vl->vars = NULL; |
1374 | } | 1472 | } |
1375 | 1473 | ||
1376 | return ret; | 1474 | return ret; |
1377 | } | 1475 | } |
1378 | 1476 | ||
1379 | /* Find available variables at given probe point */ | 1477 | /* Find available variables at given probe point */ |
1380 | int find_available_vars_at(int fd, struct perf_probe_event *pev, | 1478 | int find_available_vars_at(int fd, struct perf_probe_event *pev, |
1381 | struct variable_list **vls, int max_vls, | 1479 | struct variable_list **vls, int max_vls, |
1382 | bool externs) | 1480 | bool externs) |
1383 | { | 1481 | { |
1384 | struct available_var_finder af = { | 1482 | struct available_var_finder af = { |
1385 | .pf = {.pev = pev, .callback = add_available_vars}, | 1483 | .pf = {.pev = pev, .callback = add_available_vars}, |
1386 | .max_vls = max_vls, .externs = externs}; | 1484 | .max_vls = max_vls, .externs = externs}; |
1387 | int ret; | 1485 | int ret; |
1388 | 1486 | ||
1389 | /* Allocate result vls array */ | 1487 | /* Allocate result vls array */ |
1390 | *vls = zalloc(sizeof(struct variable_list) * max_vls); | 1488 | *vls = zalloc(sizeof(struct variable_list) * max_vls); |
1391 | if (*vls == NULL) | 1489 | if (*vls == NULL) |
1392 | return -ENOMEM; | 1490 | return -ENOMEM; |
1393 | 1491 | ||
1394 | af.vls = *vls; | 1492 | af.vls = *vls; |
1395 | af.nvls = 0; | 1493 | af.nvls = 0; |
1396 | 1494 | ||
1397 | ret = find_probes(fd, &af.pf); | 1495 | ret = find_probes(fd, &af.pf); |
1398 | if (ret < 0) { | 1496 | if (ret < 0) { |
1399 | /* Free vlist for error */ | 1497 | /* Free vlist for error */ |
1400 | while (af.nvls--) { | 1498 | while (af.nvls--) { |
1401 | if (af.vls[af.nvls].point.symbol) | 1499 | if (af.vls[af.nvls].point.symbol) |
1402 | free(af.vls[af.nvls].point.symbol); | 1500 | free(af.vls[af.nvls].point.symbol); |
1403 | if (af.vls[af.nvls].vars) | 1501 | if (af.vls[af.nvls].vars) |
1404 | strlist__delete(af.vls[af.nvls].vars); | 1502 | strlist__delete(af.vls[af.nvls].vars); |
1405 | } | 1503 | } |
1406 | free(af.vls); | 1504 | free(af.vls); |
1407 | *vls = NULL; | 1505 | *vls = NULL; |
1408 | return ret; | 1506 | return ret; |
1409 | } | 1507 | } |
1410 | 1508 | ||
1411 | return (ret < 0) ? ret : af.nvls; | 1509 | return (ret < 0) ? ret : af.nvls; |
1412 | } | 1510 | } |
1413 | 1511 | ||
1414 | /* Reverse search */ | 1512 | /* Reverse search */ |
1415 | int find_perf_probe_point(int fd, unsigned long addr, | 1513 | int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) |
1416 | struct perf_probe_point *ppt) | ||
1417 | { | 1514 | { |
1418 | Dwarf_Die cudie, spdie, indie; | 1515 | Dwarf_Die cudie, spdie, indie; |
1419 | Dwarf *dbg; | 1516 | Dwarf *dbg = NULL; |
1517 | Dwfl *dwfl = NULL; | ||
1420 | Dwarf_Line *line; | 1518 | Dwarf_Line *line; |
1421 | Dwarf_Addr laddr, eaddr; | 1519 | Dwarf_Addr laddr, eaddr, bias = 0; |
1422 | const char *tmp; | 1520 | const char *tmp; |
1423 | int lineno, ret = 0; | 1521 | int lineno, ret = 0; |
1424 | bool found = false; | 1522 | bool found = false; |
1425 | 1523 | ||
1426 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1524 | /* Open the live linux kernel */ |
1427 | if (!dbg) | 1525 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); |
1428 | return -EBADF; | 1526 | if (!dbg) { |
1527 | pr_warning("No dwarf info found in the vmlinux - " | ||
1528 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1529 | ret = -EINVAL; | ||
1530 | goto end; | ||
1531 | } | ||
1429 | 1532 | ||
1533 | /* Adjust address with bias */ | ||
1534 | addr += bias; | ||
1430 | /* Find cu die */ | 1535 | /* Find cu die */ |
1431 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { | 1536 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { |
1537 | pr_warning("No CU DIE is found at %lx\n", addr); | ||
1432 | ret = -EINVAL; | 1538 | ret = -EINVAL; |
1433 | goto end; | 1539 | goto end; |
1434 | } | 1540 | } |
1435 | 1541 | ||
1436 | /* Find a corresponding line */ | 1542 | /* Find a corresponding line */ |
1437 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | 1543 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); |
1438 | if (line) { | 1544 | if (line) { |
1439 | if (dwarf_lineaddr(line, &laddr) == 0 && | 1545 | if (dwarf_lineaddr(line, &laddr) == 0 && |
1440 | (Dwarf_Addr)addr == laddr && | 1546 | (Dwarf_Addr)addr == laddr && |
1441 | dwarf_lineno(line, &lineno) == 0) { | 1547 | dwarf_lineno(line, &lineno) == 0) { |
1442 | tmp = dwarf_linesrc(line, NULL, NULL); | 1548 | tmp = dwarf_linesrc(line, NULL, NULL); |
1443 | if (tmp) { | 1549 | if (tmp) { |
1444 | ppt->line = lineno; | 1550 | ppt->line = lineno; |
1445 | ppt->file = strdup(tmp); | 1551 | ppt->file = strdup(tmp); |
1446 | if (ppt->file == NULL) { | 1552 | if (ppt->file == NULL) { |
1447 | ret = -ENOMEM; | 1553 | ret = -ENOMEM; |
1448 | goto end; | 1554 | goto end; |
1449 | } | 1555 | } |
1450 | found = true; | 1556 | found = true; |
1451 | } | 1557 | } |
1452 | } | 1558 | } |
1453 | } | 1559 | } |
1454 | 1560 | ||
1455 | /* Find a corresponding function */ | 1561 | /* Find a corresponding function */ |
1456 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1562 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1457 | tmp = dwarf_diename(&spdie); | 1563 | tmp = dwarf_diename(&spdie); |
1458 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) | 1564 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) |
1459 | goto end; | 1565 | goto end; |
1460 | 1566 | ||
1461 | if (ppt->line) { | 1567 | if (ppt->line) { |
1462 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1568 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, |
1463 | &indie)) { | 1569 | &indie)) { |
1464 | /* addr in an inline function */ | 1570 | /* addr in an inline function */ |
1465 | tmp = dwarf_diename(&indie); | 1571 | tmp = dwarf_diename(&indie); |
1466 | if (!tmp) | 1572 | if (!tmp) |
1467 | goto end; | 1573 | goto end; |
1468 | ret = dwarf_decl_line(&indie, &lineno); | 1574 | ret = dwarf_decl_line(&indie, &lineno); |
1469 | } else { | 1575 | } else { |
1470 | if (eaddr == addr) { /* Function entry */ | 1576 | if (eaddr == addr) { /* Function entry */ |
1471 | lineno = ppt->line; | 1577 | lineno = ppt->line; |
1472 | ret = 0; | 1578 | ret = 0; |
1473 | } else | 1579 | } else |
1474 | ret = dwarf_decl_line(&spdie, &lineno); | 1580 | ret = dwarf_decl_line(&spdie, &lineno); |
1475 | } | 1581 | } |
1476 | if (ret == 0) { | 1582 | if (ret == 0) { |
1477 | /* Make a relative line number */ | 1583 | /* Make a relative line number */ |
1478 | ppt->line -= lineno; | 1584 | ppt->line -= lineno; |
1479 | goto found; | 1585 | goto found; |
1480 | } | 1586 | } |
1481 | } | 1587 | } |
1482 | /* We don't have a line number, let's use offset */ | 1588 | /* We don't have a line number, let's use offset */ |
1483 | ppt->offset = addr - (unsigned long)eaddr; | 1589 | ppt->offset = addr - (unsigned long)eaddr; |
1484 | found: | 1590 | found: |
1485 | ppt->function = strdup(tmp); | 1591 | ppt->function = strdup(tmp); |
1486 | if (ppt->function == NULL) { | 1592 | if (ppt->function == NULL) { |
1487 | ret = -ENOMEM; | 1593 | ret = -ENOMEM; |
1488 | goto end; | 1594 | goto end; |
1489 | } | 1595 | } |
1490 | found = true; | 1596 | found = true; |
1491 | } | 1597 | } |
1492 | 1598 | ||
1493 | end: | 1599 | end: |
1494 | dwarf_end(dbg); | 1600 | if (dwfl) |
1601 | dwfl_end(dwfl); | ||
1495 | if (ret >= 0) | 1602 | if (ret >= 0) |
1496 | ret = found ? 1 : 0; | 1603 | ret = found ? 1 : 0; |
1497 | return ret; | 1604 | return ret; |
1498 | } | 1605 | } |
1499 | 1606 | ||
1500 | /* Add a line and store the src path */ | 1607 | /* Add a line and store the src path */ |
1501 | static int line_range_add_line(const char *src, unsigned int lineno, | 1608 | static int line_range_add_line(const char *src, unsigned int lineno, |
1502 | struct line_range *lr) | 1609 | struct line_range *lr) |
1503 | { | 1610 | { |
1504 | /* Copy source path */ | 1611 | /* Copy source path */ |
1505 | if (!lr->path) { | 1612 | if (!lr->path) { |
1506 | lr->path = strdup(src); | 1613 | lr->path = strdup(src); |
1507 | if (lr->path == NULL) | 1614 | if (lr->path == NULL) |
1508 | return -ENOMEM; | 1615 | return -ENOMEM; |
1509 | } | 1616 | } |
1510 | return line_list__add_line(&lr->line_list, lineno); | 1617 | return line_list__add_line(&lr->line_list, lineno); |
1511 | } | 1618 | } |
1512 | 1619 | ||
1513 | /* Search function declaration lines */ | 1620 | /* Search function declaration lines */ |
1514 | static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) | 1621 | static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) |
1515 | { | 1622 | { |
1516 | struct dwarf_callback_param *param = data; | 1623 | struct dwarf_callback_param *param = data; |
1517 | struct line_finder *lf = param->data; | 1624 | struct line_finder *lf = param->data; |
1518 | const char *src; | 1625 | const char *src; |
1519 | int lineno; | 1626 | int lineno; |
1520 | 1627 | ||
1521 | src = dwarf_decl_file(sp_die); | 1628 | src = dwarf_decl_file(sp_die); |
1522 | if (src && strtailcmp(src, lf->fname) != 0) | 1629 | if (src && strtailcmp(src, lf->fname) != 0) |
1523 | return DWARF_CB_OK; | 1630 | return DWARF_CB_OK; |
1524 | 1631 | ||
1525 | if (dwarf_decl_line(sp_die, &lineno) != 0 || | 1632 | if (dwarf_decl_line(sp_die, &lineno) != 0 || |
1526 | (lf->lno_s > lineno || lf->lno_e < lineno)) | 1633 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
1527 | return DWARF_CB_OK; | 1634 | return DWARF_CB_OK; |
1528 | 1635 | ||
1529 | param->retval = line_range_add_line(src, lineno, lf->lr); | 1636 | param->retval = line_range_add_line(src, lineno, lf->lr); |
1530 | if (param->retval < 0) | 1637 | if (param->retval < 0) |
1531 | return DWARF_CB_ABORT; | 1638 | return DWARF_CB_ABORT; |
1532 | return DWARF_CB_OK; | 1639 | return DWARF_CB_OK; |
1533 | } | 1640 | } |
1534 | 1641 | ||
1535 | static int find_line_range_func_decl_lines(struct line_finder *lf) | 1642 | static int find_line_range_func_decl_lines(struct line_finder *lf) |
1536 | { | 1643 | { |
1537 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; | 1644 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; |
1538 | dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0); | 1645 | dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0); |
1539 | return param.retval; | 1646 | return param.retval; |
1540 | } | 1647 | } |
1541 | 1648 | ||
1542 | /* Find line range from its line number */ | 1649 | /* Find line range from its line number */ |
1543 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1650 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
1544 | { | 1651 | { |
1545 | Dwarf_Lines *lines; | 1652 | Dwarf_Lines *lines; |
1546 | Dwarf_Line *line; | 1653 | Dwarf_Line *line; |
1547 | size_t nlines, i; | 1654 | size_t nlines, i; |
1548 | Dwarf_Addr addr; | 1655 | Dwarf_Addr addr; |
1549 | int lineno, ret = 0; | 1656 | int lineno, ret = 0; |
1550 | const char *src; | 1657 | const char *src; |
1551 | Dwarf_Die die_mem; | 1658 | Dwarf_Die die_mem; |
1552 | 1659 | ||
1553 | line_list__init(&lf->lr->line_list); | 1660 | line_list__init(&lf->lr->line_list); |
1554 | if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { | 1661 | if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { |
1555 | pr_warning("No source lines found in this CU.\n"); | 1662 | pr_warning("No source lines found in this CU.\n"); |
1556 | return -ENOENT; | 1663 | return -ENOENT; |
1557 | } | 1664 | } |
1558 | 1665 | ||
1559 | /* Search probable lines on lines list */ | 1666 | /* Search probable lines on lines list */ |
1560 | for (i = 0; i < nlines; i++) { | 1667 | for (i = 0; i < nlines; i++) { |
1561 | line = dwarf_onesrcline(lines, i); | 1668 | line = dwarf_onesrcline(lines, i); |
1562 | if (dwarf_lineno(line, &lineno) != 0 || | 1669 | if (dwarf_lineno(line, &lineno) != 0 || |
1563 | (lf->lno_s > lineno || lf->lno_e < lineno)) | 1670 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
1564 | continue; | 1671 | continue; |
1565 | 1672 | ||
1566 | if (sp_die) { | 1673 | if (sp_die) { |
1567 | /* Address filtering 1: does sp_die include addr? */ | 1674 | /* Address filtering 1: does sp_die include addr? */ |
1568 | if (dwarf_lineaddr(line, &addr) != 0 || | 1675 | if (dwarf_lineaddr(line, &addr) != 0 || |
1569 | !dwarf_haspc(sp_die, addr)) | 1676 | !dwarf_haspc(sp_die, addr)) |
1570 | continue; | 1677 | continue; |
1571 | 1678 | ||
1572 | /* Address filtering 2: No child include addr? */ | 1679 | /* Address filtering 2: No child include addr? */ |
1573 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) | 1680 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) |
1574 | continue; | 1681 | continue; |
1575 | } | 1682 | } |
1576 | 1683 | ||
1577 | /* TODO: Get fileno from line, but how? */ | 1684 | /* TODO: Get fileno from line, but how? */ |
1578 | src = dwarf_linesrc(line, NULL, NULL); | 1685 | src = dwarf_linesrc(line, NULL, NULL); |
1579 | if (strtailcmp(src, lf->fname) != 0) | 1686 | if (strtailcmp(src, lf->fname) != 0) |
1580 | continue; | 1687 | continue; |
1581 | 1688 | ||
1582 | ret = line_range_add_line(src, lineno, lf->lr); | 1689 | ret = line_range_add_line(src, lineno, lf->lr); |
1583 | if (ret < 0) | 1690 | if (ret < 0) |
1584 | return ret; | 1691 | return ret; |
1585 | } | 1692 | } |
1586 | 1693 | ||
1587 | /* | 1694 | /* |
1588 | * Dwarf lines doesn't include function declarations. We have to | 1695 | * Dwarf lines doesn't include function declarations. We have to |
1589 | * check functions list or given function. | 1696 | * check functions list or given function. |
1590 | */ | 1697 | */ |
1591 | if (sp_die) { | 1698 | if (sp_die) { |
1592 | src = dwarf_decl_file(sp_die); | 1699 | src = dwarf_decl_file(sp_die); |
1593 | if (src && dwarf_decl_line(sp_die, &lineno) == 0 && | 1700 | if (src && dwarf_decl_line(sp_die, &lineno) == 0 && |
1594 | (lf->lno_s <= lineno && lf->lno_e >= lineno)) | 1701 | (lf->lno_s <= lineno && lf->lno_e >= lineno)) |
1595 | ret = line_range_add_line(src, lineno, lf->lr); | 1702 | ret = line_range_add_line(src, lineno, lf->lr); |
1596 | } else | 1703 | } else |
1597 | ret = find_line_range_func_decl_lines(lf); | 1704 | ret = find_line_range_func_decl_lines(lf); |
1598 | 1705 | ||
1599 | /* Update status */ | 1706 | /* Update status */ |
1600 | if (ret >= 0) | 1707 | if (ret >= 0) |
1601 | if (!list_empty(&lf->lr->line_list)) | 1708 | if (!list_empty(&lf->lr->line_list)) |
1602 | ret = lf->found = 1; | 1709 | ret = lf->found = 1; |
1603 | else | 1710 | else |
1604 | ret = 0; /* Lines are not found */ | 1711 | ret = 0; /* Lines are not found */ |
1605 | else { | 1712 | else { |
1606 | free(lf->lr->path); | 1713 | free(lf->lr->path); |
1607 | lf->lr->path = NULL; | 1714 | lf->lr->path = NULL; |
1608 | } | 1715 | } |
1609 | return ret; | 1716 | return ret; |
1610 | } | 1717 | } |
1611 | 1718 | ||
1612 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1719 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
1613 | { | 1720 | { |
1614 | struct dwarf_callback_param *param = data; | 1721 | struct dwarf_callback_param *param = data; |
1615 | 1722 | ||
1616 | param->retval = find_line_range_by_line(in_die, param->data); | 1723 | param->retval = find_line_range_by_line(in_die, param->data); |
1617 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1724 | return DWARF_CB_ABORT; /* No need to find other instances */ |
1618 | } | 1725 | } |
1619 | 1726 | ||
1620 | /* Search function from function name */ | 1727 | /* Search function from function name */ |
1621 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | 1728 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
1622 | { | 1729 | { |
1623 | struct dwarf_callback_param *param = data; | 1730 | struct dwarf_callback_param *param = data; |
1624 | struct line_finder *lf = param->data; | 1731 | struct line_finder *lf = param->data; |
1625 | struct line_range *lr = lf->lr; | 1732 | struct line_range *lr = lf->lr; |
1626 | 1733 | ||
1734 | pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die), | ||
1735 | dwarf_diename(sp_die)); | ||
1627 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1736 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1628 | die_compare_name(sp_die, lr->function)) { | 1737 | die_compare_name(sp_die, lr->function)) { |
1629 | lf->fname = dwarf_decl_file(sp_die); | 1738 | lf->fname = dwarf_decl_file(sp_die); |
1630 | dwarf_decl_line(sp_die, &lr->offset); | 1739 | dwarf_decl_line(sp_die, &lr->offset); |
1631 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); | 1740 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); |
1632 | lf->lno_s = lr->offset + lr->start; | 1741 | lf->lno_s = lr->offset + lr->start; |
1633 | if (lf->lno_s < 0) /* Overflow */ | 1742 | if (lf->lno_s < 0) /* Overflow */ |
1634 | lf->lno_s = INT_MAX; | 1743 | lf->lno_s = INT_MAX; |
1635 | lf->lno_e = lr->offset + lr->end; | 1744 | lf->lno_e = lr->offset + lr->end; |
1636 | if (lf->lno_e < 0) /* Overflow */ | 1745 | if (lf->lno_e < 0) /* Overflow */ |
1637 | lf->lno_e = INT_MAX; | 1746 | lf->lno_e = INT_MAX; |
1638 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1747 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
1639 | lr->start = lf->lno_s; | 1748 | lr->start = lf->lno_s; |
1640 | lr->end = lf->lno_e; | 1749 | lr->end = lf->lno_e; |
1641 | if (dwarf_func_inline(sp_die)) { | 1750 | if (dwarf_func_inline(sp_die)) { |
1642 | struct dwarf_callback_param _param; | 1751 | struct dwarf_callback_param _param; |
1643 | _param.data = (void *)lf; | 1752 | _param.data = (void *)lf; |
1644 | _param.retval = 0; | 1753 | _param.retval = 0; |
1645 | dwarf_func_inline_instances(sp_die, | 1754 | dwarf_func_inline_instances(sp_die, |
1646 | line_range_inline_cb, | 1755 | line_range_inline_cb, |
1647 | &_param); | 1756 | &_param); |
1648 | param->retval = _param.retval; | 1757 | param->retval = _param.retval; |
1649 | } else | 1758 | } else |
1650 | param->retval = find_line_range_by_line(sp_die, lf); | 1759 | param->retval = find_line_range_by_line(sp_die, lf); |
1651 | return DWARF_CB_ABORT; | 1760 | return DWARF_CB_ABORT; |
1652 | } | 1761 | } |
1653 | return DWARF_CB_OK; | 1762 | return DWARF_CB_OK; |
1654 | } | 1763 | } |
1655 | 1764 | ||
1656 | static int find_line_range_by_func(struct line_finder *lf) | 1765 | static int find_line_range_by_func(struct line_finder *lf) |
1657 | { | 1766 | { |
1658 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; | 1767 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; |
1659 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); | 1768 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); |
1660 | return param.retval; | 1769 | return param.retval; |
1661 | } | 1770 | } |
1662 | 1771 | ||
1663 | int find_line_range(int fd, struct line_range *lr) | 1772 | int find_line_range(int fd, struct line_range *lr) |
1664 | { | 1773 | { |
1665 | struct line_finder lf = {.lr = lr, .found = 0}; | 1774 | struct line_finder lf = {.lr = lr, .found = 0}; |
1666 | int ret = 0; | 1775 | int ret = 0; |
1667 | Dwarf_Off off = 0, noff; | 1776 | Dwarf_Off off = 0, noff; |
1668 | size_t cuhl; | 1777 | size_t cuhl; |
1669 | Dwarf_Die *diep; | 1778 | Dwarf_Die *diep; |
1670 | Dwarf *dbg; | 1779 | Dwarf *dbg = NULL; |
1780 | Dwfl *dwfl; | ||
1781 | Dwarf_Addr bias; /* Currently ignored */ | ||
1671 | const char *comp_dir; | 1782 | const char *comp_dir; |
1672 | 1783 | ||
1673 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1784 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); |
1674 | if (!dbg) { | 1785 | if (!dbg) { |
1675 | pr_warning("No dwarf info found in the vmlinux - " | 1786 | pr_warning("No dwarf info found in the vmlinux - " |
1676 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1787 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
1677 | return -EBADF; | 1788 | return -EBADF; |
1678 | } | 1789 | } |
1679 | 1790 | ||
1680 | /* Loop on CUs (Compilation Unit) */ | 1791 | /* Loop on CUs (Compilation Unit) */ |
1681 | while (!lf.found && ret >= 0) { | 1792 | while (!lf.found && ret >= 0) { |
1682 | if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) | 1793 | if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) |
1683 | break; | 1794 | break; |
1684 | 1795 | ||
1685 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1796 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1686 | diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); | 1797 | diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); |
1687 | if (!diep) | 1798 | if (!diep) |
1688 | continue; | 1799 | continue; |
1689 | 1800 | ||
1690 | /* Check if target file is included. */ | 1801 | /* Check if target file is included. */ |
1691 | if (lr->file) | 1802 | if (lr->file) |
1692 | lf.fname = cu_find_realpath(&lf.cu_die, lr->file); | 1803 | lf.fname = cu_find_realpath(&lf.cu_die, lr->file); |
1693 | else | 1804 | else |
1694 | lf.fname = 0; | 1805 | lf.fname = 0; |
1695 | 1806 | ||
1696 | if (!lr->file || lf.fname) { | 1807 | if (!lr->file || lf.fname) { |
1697 | if (lr->function) | 1808 | if (lr->function) |
1698 | ret = find_line_range_by_func(&lf); | 1809 | ret = find_line_range_by_func(&lf); |
1699 | else { | 1810 | else { |
1700 | lf.lno_s = lr->start; | 1811 | lf.lno_s = lr->start; |
1701 | lf.lno_e = lr->end; | 1812 | lf.lno_e = lr->end; |
1702 | ret = find_line_range_by_line(NULL, &lf); | 1813 | ret = find_line_range_by_line(NULL, &lf); |
1703 | } | 1814 | } |
1704 | } | 1815 | } |
1705 | off = noff; | 1816 | off = noff; |
1706 | } | 1817 | } |
1707 | 1818 | ||
1708 | /* Store comp_dir */ | 1819 | /* Store comp_dir */ |
1709 | if (lf.found) { | 1820 | if (lf.found) { |
1710 | comp_dir = cu_get_comp_dir(&lf.cu_die); | 1821 | comp_dir = cu_get_comp_dir(&lf.cu_die); |
1711 | if (comp_dir) { | 1822 | if (comp_dir) { |
1712 | lr->comp_dir = strdup(comp_dir); | 1823 | lr->comp_dir = strdup(comp_dir); |
1713 | if (!lr->comp_dir) | 1824 | if (!lr->comp_dir) |
1714 | ret = -ENOMEM; | 1825 | ret = -ENOMEM; |
1715 | } | 1826 | } |
1716 | } | 1827 | } |
1717 | 1828 | ||
1718 | pr_debug("path: %s\n", lr->path); | 1829 | pr_debug("path: %s\n", lr->path); |
1719 | dwarf_end(dbg); | 1830 | dwfl_end(dwfl); |
1720 | |||
1721 | return (ret < 0) ? ret : lf.found; | 1831 | return (ret < 0) ? ret : lf.found; |
1722 | } | 1832 | } |
tools/perf/util/probe-finder.h
1 | #ifndef _PROBE_FINDER_H | 1 | #ifndef _PROBE_FINDER_H |
2 | #define _PROBE_FINDER_H | 2 | #define _PROBE_FINDER_H |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include "util.h" | 5 | #include "util.h" |
6 | #include "probe-event.h" | 6 | #include "probe-event.h" |
7 | 7 | ||
8 | #define MAX_PATH_LEN 256 | 8 | #define MAX_PATH_LEN 256 |
9 | #define MAX_PROBE_BUFFER 1024 | 9 | #define MAX_PROBE_BUFFER 1024 |
10 | #define MAX_PROBES 128 | 10 | #define MAX_PROBES 128 |
11 | 11 | ||
12 | static inline int is_c_varname(const char *name) | 12 | static inline int is_c_varname(const char *name) |
13 | { | 13 | { |
14 | /* TODO */ | 14 | /* TODO */ |
15 | return isalpha(name[0]) || name[0] == '_'; | 15 | return isalpha(name[0]) || name[0] == '_'; |
16 | } | 16 | } |
17 | 17 | ||
18 | #ifdef DWARF_SUPPORT | 18 | #ifdef DWARF_SUPPORT |
19 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | 19 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
20 | extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, | 20 | extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, |
21 | struct probe_trace_event **tevs, | 21 | struct probe_trace_event **tevs, |
22 | int max_tevs); | 22 | int max_tevs); |
23 | 23 | ||
24 | /* Find a perf_probe_point from debuginfo */ | 24 | /* Find a perf_probe_point from debuginfo */ |
25 | extern int find_perf_probe_point(int fd, unsigned long addr, | 25 | extern int find_perf_probe_point(unsigned long addr, |
26 | struct perf_probe_point *ppt); | 26 | struct perf_probe_point *ppt); |
27 | 27 | ||
28 | /* Find a line range */ | 28 | /* Find a line range */ |
29 | extern int find_line_range(int fd, struct line_range *lr); | 29 | extern int find_line_range(int fd, struct line_range *lr); |
30 | 30 | ||
31 | /* Find available variables */ | 31 | /* Find available variables */ |
32 | extern int find_available_vars_at(int fd, struct perf_probe_event *pev, | 32 | extern int find_available_vars_at(int fd, struct perf_probe_event *pev, |
33 | struct variable_list **vls, int max_points, | 33 | struct variable_list **vls, int max_points, |
34 | bool externs); | 34 | bool externs); |
35 | 35 | ||
36 | #include <dwarf.h> | 36 | #include <dwarf.h> |
37 | #include <libdw.h> | 37 | #include <libdw.h> |
38 | #include <libdwfl.h> | ||
38 | #include <version.h> | 39 | #include <version.h> |
39 | 40 | ||
40 | struct probe_finder { | 41 | struct probe_finder { |
41 | struct perf_probe_event *pev; /* Target probe event */ | 42 | struct perf_probe_event *pev; /* Target probe event */ |
42 | 43 | ||
43 | /* Callback when a probe point is found */ | 44 | /* Callback when a probe point is found */ |
44 | int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); | 45 | int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); |
45 | 46 | ||
46 | /* For function searching */ | 47 | /* For function searching */ |
47 | int lno; /* Line number */ | 48 | int lno; /* Line number */ |
48 | Dwarf_Addr addr; /* Address */ | 49 | Dwarf_Addr addr; /* Address */ |
49 | const char *fname; /* Real file name */ | 50 | const char *fname; /* Real file name */ |
50 | Dwarf_Die cu_die; /* Current CU */ | 51 | Dwarf_Die cu_die; /* Current CU */ |
51 | struct list_head lcache; /* Line cache for lazy match */ | 52 | struct list_head lcache; /* Line cache for lazy match */ |
52 | 53 | ||
53 | /* For variable searching */ | 54 | /* For variable searching */ |
54 | #if _ELFUTILS_PREREQ(0, 142) | 55 | #if _ELFUTILS_PREREQ(0, 142) |
55 | Dwarf_CFI *cfi; /* Call Frame Information */ | 56 | Dwarf_CFI *cfi; /* Call Frame Information */ |
56 | #endif | 57 | #endif |
57 | Dwarf_Op *fb_ops; /* Frame base attribute */ | 58 | Dwarf_Op *fb_ops; /* Frame base attribute */ |
58 | struct perf_probe_arg *pvar; /* Current target variable */ | 59 | struct perf_probe_arg *pvar; /* Current target variable */ |
59 | struct probe_trace_arg *tvar; /* Current result variable */ | 60 | struct probe_trace_arg *tvar; /* Current result variable */ |
60 | }; | 61 | }; |
61 | 62 | ||
62 | struct trace_event_finder { | 63 | struct trace_event_finder { |
63 | struct probe_finder pf; | 64 | struct probe_finder pf; |
64 | struct probe_trace_event *tevs; /* Found trace events */ | 65 | struct probe_trace_event *tevs; /* Found trace events */ |
65 | int ntevs; /* Number of trace events */ | 66 | int ntevs; /* Number of trace events */ |
66 | int max_tevs; /* Max number of trace events */ | 67 | int max_tevs; /* Max number of trace events */ |
67 | }; | 68 | }; |
68 | 69 | ||
69 | struct available_var_finder { | 70 | struct available_var_finder { |
70 | struct probe_finder pf; | 71 | struct probe_finder pf; |
71 | struct variable_list *vls; /* Found variable lists */ | 72 | struct variable_list *vls; /* Found variable lists */ |
72 | int nvls; /* Number of variable lists */ | 73 | int nvls; /* Number of variable lists */ |
73 | int max_vls; /* Max no. of variable lists */ | 74 | int max_vls; /* Max no. of variable lists */ |
74 | bool externs; /* Find external vars too */ | 75 | bool externs; /* Find external vars too */ |
75 | bool child; /* Search child scopes */ | 76 | bool child; /* Search child scopes */ |
76 | }; | 77 | }; |
77 | 78 | ||
78 | struct line_finder { | 79 | struct line_finder { |
79 | struct line_range *lr; /* Target line range */ | 80 | struct line_range *lr; /* Target line range */ |
80 | 81 | ||
81 | const char *fname; /* File name */ | 82 | const char *fname; /* File name */ |
82 | int lno_s; /* Start line number */ | 83 | int lno_s; /* Start line number */ |
83 | int lno_e; /* End line number */ | 84 | int lno_e; /* End line number */ |
84 | Dwarf_Die cu_die; /* Current CU */ | 85 | Dwarf_Die cu_die; /* Current CU */ |
85 | int found; | 86 | int found; |
86 | }; | 87 | }; |
87 | 88 | ||
88 | #endif /* DWARF_SUPPORT */ | 89 | #endif /* DWARF_SUPPORT */ |
89 | 90 | ||
90 | #endif /*_PROBE_FINDER_H */ | 91 | #endif /*_PROBE_FINDER_H */ |
91 | 92 |