diff options
-rw-r--r-- | tools/perf/util/probe-event.c | 55 | ||||
-rw-r--r-- | tools/perf/util/string.c | 101 | ||||
-rw-r--r-- | tools/perf/util/string.h | 2 |
3 files changed, 118 insertions, 40 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 7335a3b5e494..e3a683ab976f 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -32,6 +32,7 @@ | |||
32 | 32 | ||
33 | #undef _GNU_SOURCE | 33 | #undef _GNU_SOURCE |
34 | #include "event.h" | 34 | #include "event.h" |
35 | #include "string.h" | ||
35 | #include "debug.h" | 36 | #include "debug.h" |
36 | #include "parse-events.h" /* For debugfs_path */ | 37 | #include "parse-events.h" /* For debugfs_path */ |
37 | #include "probe-event.h" | 38 | #include "probe-event.h" |
@@ -132,62 +133,36 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) | |||
132 | /* Parse perf-probe event definition */ | 133 | /* Parse perf-probe event definition */ |
133 | int parse_perf_probe_event(const char *str, struct probe_point *pp) | 134 | int parse_perf_probe_event(const char *str, struct probe_point *pp) |
134 | { | 135 | { |
135 | char *argv[MAX_PROBE_ARGS + 1]; /* probe + args */ | 136 | char **argv; |
136 | int argc, i, need_dwarf = 0; | 137 | int argc, i, need_dwarf = 0; |
137 | 138 | ||
138 | /* Separate arguments, similar to argv_split */ | 139 | argv = argv_split(str, &argc); |
139 | argc = 0; | 140 | if (!argv) |
140 | do { | 141 | die("argv_split failed."); |
141 | /* Skip separators */ | 142 | if (argc > MAX_PROBE_ARGS + 1) |
142 | while (isspace(*str)) | 143 | semantic_error("Too many arguments"); |
143 | str++; | ||
144 | |||
145 | /* Add an argument */ | ||
146 | if (*str != '\0') { | ||
147 | const char *s = str; | ||
148 | /* Check the limit number of arguments */ | ||
149 | if (argc == MAX_PROBE_ARGS + 1) | ||
150 | semantic_error("Too many arguments"); | ||
151 | |||
152 | /* Skip the argument */ | ||
153 | while (!isspace(*str) && *str != '\0') | ||
154 | str++; | ||
155 | |||
156 | /* Duplicate the argument */ | ||
157 | argv[argc] = strndup(s, str - s); | ||
158 | if (argv[argc] == NULL) | ||
159 | die("strndup"); | ||
160 | pr_debug("argv[%d]=%s\n", argc, argv[argc]); | ||
161 | argc++; | ||
162 | } | ||
163 | } while (*str != '\0'); | ||
164 | if (!argc) | ||
165 | semantic_error("An empty argument."); | ||
166 | 144 | ||
167 | /* Parse probe point */ | 145 | /* Parse probe point */ |
168 | parse_perf_probe_probepoint(argv[0], pp); | 146 | parse_perf_probe_probepoint(argv[0], pp); |
169 | free(argv[0]); | ||
170 | if (pp->file || pp->line) | 147 | if (pp->file || pp->line) |
171 | need_dwarf = 1; | 148 | need_dwarf = 1; |
172 | 149 | ||
173 | /* Copy arguments */ | 150 | /* Copy arguments and ensure return probe has no C argument */ |
174 | pp->nr_args = argc - 1; | 151 | pp->nr_args = argc - 1; |
175 | if (pp->nr_args > 0) { | 152 | pp->args = zalloc(sizeof(char *) * pp->nr_args); |
176 | pp->args = (char **)malloc(sizeof(char *) * pp->nr_args); | 153 | for (i = 0; i < pp->nr_args; i++) { |
177 | if (!pp->args) | 154 | pp->args[i] = strdup(argv[i + 1]); |
178 | die("malloc"); | 155 | if (!pp->args[i]) |
179 | memcpy(pp->args, &argv[1], sizeof(char *) * pp->nr_args); | 156 | die("Failed to copy argument."); |
180 | } | ||
181 | |||
182 | /* Ensure return probe has no C argument */ | ||
183 | for (i = 0; i < pp->nr_args; i++) | ||
184 | if (is_c_varname(pp->args[i])) { | 157 | if (is_c_varname(pp->args[i])) { |
185 | if (pp->retprobe) | 158 | if (pp->retprobe) |
186 | semantic_error("You can't specify local" | 159 | semantic_error("You can't specify local" |
187 | " variable for kretprobe"); | 160 | " variable for kretprobe"); |
188 | need_dwarf = 1; | 161 | need_dwarf = 1; |
189 | } | 162 | } |
163 | } | ||
190 | 164 | ||
165 | argv_free(argv); | ||
191 | return need_dwarf; | 166 | return need_dwarf; |
192 | } | 167 | } |
193 | 168 | ||
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 227043577e06..0977cf431789 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -127,3 +127,104 @@ out_err: | |||
127 | out: | 127 | out: |
128 | return length; | 128 | return length; |
129 | } | 129 | } |
130 | |||
131 | /* | ||
132 | * Helper function for splitting a string into an argv-like array. | ||
133 | * originaly copied from lib/argv_split.c | ||
134 | */ | ||
135 | static const char *skip_sep(const char *cp) | ||
136 | { | ||
137 | while (*cp && isspace(*cp)) | ||
138 | cp++; | ||
139 | |||
140 | return cp; | ||
141 | } | ||
142 | |||
143 | static const char *skip_arg(const char *cp) | ||
144 | { | ||
145 | while (*cp && !isspace(*cp)) | ||
146 | cp++; | ||
147 | |||
148 | return cp; | ||
149 | } | ||
150 | |||
151 | static int count_argc(const char *str) | ||
152 | { | ||
153 | int count = 0; | ||
154 | |||
155 | while (*str) { | ||
156 | str = skip_sep(str); | ||
157 | if (*str) { | ||
158 | count++; | ||
159 | str = skip_arg(str); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return count; | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * argv_free - free an argv | ||
168 | * @argv - the argument vector to be freed | ||
169 | * | ||
170 | * Frees an argv and the strings it points to. | ||
171 | */ | ||
172 | void argv_free(char **argv) | ||
173 | { | ||
174 | char **p; | ||
175 | for (p = argv; *p; p++) | ||
176 | free(*p); | ||
177 | |||
178 | free(argv); | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * argv_split - split a string at whitespace, returning an argv | ||
183 | * @str: the string to be split | ||
184 | * @argcp: returned argument count | ||
185 | * | ||
186 | * Returns an array of pointers to strings which are split out from | ||
187 | * @str. This is performed by strictly splitting on white-space; no | ||
188 | * quote processing is performed. Multiple whitespace characters are | ||
189 | * considered to be a single argument separator. The returned array | ||
190 | * is always NULL-terminated. Returns NULL on memory allocation | ||
191 | * failure. | ||
192 | */ | ||
193 | char **argv_split(const char *str, int *argcp) | ||
194 | { | ||
195 | int argc = count_argc(str); | ||
196 | char **argv = zalloc(sizeof(*argv) * (argc+1)); | ||
197 | char **argvp; | ||
198 | |||
199 | if (argv == NULL) | ||
200 | goto out; | ||
201 | |||
202 | if (argcp) | ||
203 | *argcp = argc; | ||
204 | |||
205 | argvp = argv; | ||
206 | |||
207 | while (*str) { | ||
208 | str = skip_sep(str); | ||
209 | |||
210 | if (*str) { | ||
211 | const char *p = str; | ||
212 | char *t; | ||
213 | |||
214 | str = skip_arg(str); | ||
215 | |||
216 | t = strndup(p, str-p); | ||
217 | if (t == NULL) | ||
218 | goto fail; | ||
219 | *argvp++ = t; | ||
220 | } | ||
221 | } | ||
222 | *argvp = NULL; | ||
223 | |||
224 | out: | ||
225 | return argv; | ||
226 | |||
227 | fail: | ||
228 | argv_free(argv); | ||
229 | return NULL; | ||
230 | } | ||
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h index e50b07f80827..bfecec265a1a 100644 --- a/tools/perf/util/string.h +++ b/tools/perf/util/string.h | |||
@@ -6,6 +6,8 @@ | |||
6 | int hex2u64(const char *ptr, u64 *val); | 6 | int hex2u64(const char *ptr, u64 *val); |
7 | char *strxfrchar(char *s, char from, char to); | 7 | char *strxfrchar(char *s, char from, char to); |
8 | s64 perf_atoll(const char *str); | 8 | s64 perf_atoll(const char *str); |
9 | char **argv_split(const char *str, int *argcp); | ||
10 | void argv_free(char **argv); | ||
9 | 11 | ||
10 | #define _STR(x) #x | 12 | #define _STR(x) #x |
11 | #define STR(x) _STR(x) | 13 | #define STR(x) _STR(x) |