aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile4
-rw-r--r--tools/perf/builtin-annotate.c143
-rw-r--r--tools/perf/builtin-probe.c241
-rw-r--r--tools/perf/builtin-timechart.c170
-rw-r--r--tools/perf/util/event.c3
-rw-r--r--tools/perf/util/probe-event.c484
-rw-r--r--tools/perf/util/probe-event.h18
-rw-r--r--tools/perf/util/string.c103
-rw-r--r--tools/perf/util/string.h2
9 files changed, 681 insertions, 487 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 20cd66362d2d..23ec66098bdc 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -369,6 +369,8 @@ LIB_H += util/sort.h
369LIB_H += util/hist.h 369LIB_H += util/hist.h
370LIB_H += util/thread.h 370LIB_H += util/thread.h
371LIB_H += util/data_map.h 371LIB_H += util/data_map.h
372LIB_H += util/probe-finder.h
373LIB_H += util/probe-event.h
372 374
373LIB_OBJS += util/abspath.o 375LIB_OBJS += util/abspath.o
374LIB_OBJS += util/alias.o 376LIB_OBJS += util/alias.o
@@ -412,6 +414,7 @@ LIB_OBJS += util/svghelper.o
412LIB_OBJS += util/sort.o 414LIB_OBJS += util/sort.o
413LIB_OBJS += util/hist.o 415LIB_OBJS += util/hist.o
414LIB_OBJS += util/data_map.o 416LIB_OBJS += util/data_map.o
417LIB_OBJS += util/probe-event.o
415 418
416BUILTIN_OBJS += builtin-annotate.o 419BUILTIN_OBJS += builtin-annotate.o
417 420
@@ -486,7 +489,6 @@ ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <lib
486 BASIC_CFLAGS += -DNO_LIBDWARF 489 BASIC_CFLAGS += -DNO_LIBDWARF
487else 490else
488 EXTLIBS += -lelf -ldwarf 491 EXTLIBS += -lelf -ldwarf
489 LIB_H += util/probe-finder.h
490 LIB_OBJS += util/probe-finder.o 492 LIB_OBJS += util/probe-finder.o
491endif 493endif
492 494
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7f85c6e159a4..0bf2e8f9af57 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -25,19 +25,16 @@
25#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h" 26#include "util/sort.h"
27#include "util/hist.h" 27#include "util/hist.h"
28#include "util/data_map.h"
28 29
29static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
30 31
31static int force; 32static int force;
32static int input;
33 33
34static int full_paths; 34static int full_paths;
35 35
36static int print_line; 36static int print_line;
37 37
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
40
41struct sym_hist { 38struct sym_hist {
42 u64 sum; 39 u64 sum;
43 u64 ip[0]; 40 u64 ip[0];
@@ -156,35 +153,6 @@ static int process_sample_event(event_t *event)
156 return 0; 153 return 0;
157} 154}
158 155
159static int event__process(event_t *self)
160{
161 switch (self->header.type) {
162 case PERF_RECORD_SAMPLE:
163 return process_sample_event(self);
164
165 case PERF_RECORD_MMAP:
166 return event__process_mmap(self);
167
168 case PERF_RECORD_COMM:
169 return event__process_comm(self);
170
171 case PERF_RECORD_FORK:
172 return event__process_task(self);
173 /*
174 * We dont process them right now but they are fine:
175 */
176
177 case PERF_RECORD_THROTTLE:
178 case PERF_RECORD_UNTHROTTLE:
179 return 0;
180
181 default:
182 return -1;
183 }
184
185 return 0;
186}
187
188static int parse_line(FILE *file, struct hist_entry *he, u64 len) 156static int parse_line(FILE *file, struct hist_entry *he, u64 len)
189{ 157{
190 struct symbol *sym = he->sym; 158 struct symbol *sym = he->sym;
@@ -485,99 +453,26 @@ static void find_annotations(void)
485 } 453 }
486} 454}
487 455
456static struct perf_file_handler file_handler = {
457 .process_sample_event = process_sample_event,
458 .process_mmap_event = event__process_mmap,
459 .process_comm_event = event__process_comm,
460 .process_fork_event = event__process_task,
461};
462
488static int __cmd_annotate(void) 463static int __cmd_annotate(void)
489{ 464{
490 int ret, rc = EXIT_FAILURE; 465 struct perf_header *header;
491 unsigned long offset = 0; 466 struct thread *idle;
492 unsigned long head = 0; 467 int ret;
493 struct stat input_stat;
494 event_t *event;
495 uint32_t size;
496 char *buf;
497
498 register_idle_thread();
499
500 input = open(input_name, O_RDONLY);
501 if (input < 0) {
502 perror("failed to open file");
503 exit(-1);
504 }
505
506 ret = fstat(input, &input_stat);
507 if (ret < 0) {
508 perror("failed to stat file");
509 exit(-1);
510 }
511
512 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
513 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
514 exit(-1);
515 }
516
517 if (!input_stat.st_size) {
518 fprintf(stderr, "zero-sized file, nothing to do!\n");
519 exit(0);
520 }
521
522remap:
523 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
524 MAP_SHARED, input, offset);
525 if (buf == MAP_FAILED) {
526 perror("failed to mmap file");
527 exit(-1);
528 }
529
530more:
531 event = (event_t *)(buf + head);
532
533 size = event->header.size;
534 if (!size)
535 size = 8;
536
537 if (head + event->header.size >= page_size * mmap_window) {
538 unsigned long shift = page_size * (head / page_size);
539 int munmap_ret;
540
541 munmap_ret = munmap(buf, page_size * mmap_window);
542 assert(munmap_ret == 0);
543
544 offset += shift;
545 head -= shift;
546 goto remap;
547 }
548
549 size = event->header.size;
550
551 dump_printf("%p [%p]: event: %d\n",
552 (void *)(offset + head),
553 (void *)(long)event->header.size,
554 event->header.type);
555
556 if (!size || event__process(event) < 0) {
557
558 dump_printf("%p [%p]: skipping unknown header type: %d\n",
559 (void *)(offset + head),
560 (void *)(long)(event->header.size),
561 event->header.type);
562 /*
563 * assume we lost track of the stream, check alignment, and
564 * increment a single u64 in the hope to catch on again 'soon'.
565 */
566
567 if (unlikely(head & 7))
568 head &= ~7ULL;
569
570 size = 8;
571 }
572
573 head += size;
574
575 if (offset + head < (unsigned long)input_stat.st_size)
576 goto more;
577 468
578 rc = EXIT_SUCCESS; 469 idle = register_idle_thread();
579 close(input); 470 register_perf_file_handler(&file_handler);
580 471
472 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
473 &event__cwdlen, &event__cwd);
474 if (ret)
475 return ret;
581 476
582 if (dump_trace) { 477 if (dump_trace) {
583 event__print_totals(); 478 event__print_totals();
@@ -595,7 +490,7 @@ more:
595 490
596 find_annotations(); 491 find_annotations();
597 492
598 return rc; 493 return ret;
599} 494}
600 495
601static const char * const annotate_usage[] = { 496static const char * const annotate_usage[] = {
@@ -644,8 +539,6 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
644 if (symbol__init(&symbol_conf) < 0) 539 if (symbol__init(&symbol_conf) < 0)
645 return -1; 540 return -1;
646 541
647 page_size = getpagesize();
648
649 argc = parse_options(argc, argv, options, annotate_usage, 0); 542 argc = parse_options(argc, argv, options, annotate_usage, 0);
650 543
651 setup_sorting(); 544 setup_sorting();
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index a2f6daf01ecb..a58e11b7ea80 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -40,6 +40,7 @@
40#include "util/parse-options.h" 40#include "util/parse-options.h"
41#include "util/parse-events.h" /* For debugfs_path */ 41#include "util/parse-events.h" /* For debugfs_path */
42#include "util/probe-finder.h" 42#include "util/probe-finder.h"
43#include "util/probe-event.h"
43 44
44/* Default vmlinux search paths */ 45/* Default vmlinux search paths */
45#define NR_SEARCH_PATH 3 46#define NR_SEARCH_PATH 3
@@ -51,8 +52,6 @@ const char *default_search_path[NR_SEARCH_PATH] = {
51 52
52#define MAX_PATH_LEN 256 53#define MAX_PATH_LEN 256
53#define MAX_PROBES 128 54#define MAX_PROBES 128
54#define MAX_PROBE_ARGS 128
55#define PERFPROBE_GROUP "probe"
56 55
57/* Session management structure */ 56/* Session management structure */
58static struct { 57static struct {
@@ -63,152 +62,19 @@ static struct {
63 struct probe_point probes[MAX_PROBES]; 62 struct probe_point probes[MAX_PROBES];
64} session; 63} session;
65 64
66#define semantic_error(msg ...) die("Semantic error :" msg) 65static bool listing;
67
68/* Parse probe point. Return 1 if return probe */
69static void parse_probe_point(char *arg, struct probe_point *pp)
70{
71 char *ptr, *tmp;
72 char c, nc = 0;
73 /*
74 * <Syntax>
75 * perf probe SRC:LN
76 * perf probe FUNC[+OFFS|%return][@SRC]
77 */
78
79 ptr = strpbrk(arg, ":+@%");
80 if (ptr) {
81 nc = *ptr;
82 *ptr++ = '\0';
83 }
84
85 /* Check arg is function or file and copy it */
86 if (strchr(arg, '.')) /* File */
87 pp->file = strdup(arg);
88 else /* Function */
89 pp->function = strdup(arg);
90 DIE_IF(pp->file == NULL && pp->function == NULL);
91
92 /* Parse other options */
93 while (ptr) {
94 arg = ptr;
95 c = nc;
96 ptr = strpbrk(arg, ":+@%");
97 if (ptr) {
98 nc = *ptr;
99 *ptr++ = '\0';
100 }
101 switch (c) {
102 case ':': /* Line number */
103 pp->line = strtoul(arg, &tmp, 0);
104 if (*tmp != '\0')
105 semantic_error("There is non-digit charactor"
106 " in line number.");
107 break;
108 case '+': /* Byte offset from a symbol */
109 pp->offset = strtoul(arg, &tmp, 0);
110 if (*tmp != '\0')
111 semantic_error("There is non-digit charactor"
112 " in offset.");
113 break;
114 case '@': /* File name */
115 if (pp->file)
116 semantic_error("SRC@SRC is not allowed.");
117 pp->file = strdup(arg);
118 DIE_IF(pp->file == NULL);
119 if (ptr)
120 semantic_error("@SRC must be the last "
121 "option.");
122 break;
123 case '%': /* Probe places */
124 if (strcmp(arg, "return") == 0) {
125 pp->retprobe = 1;
126 } else /* Others not supported yet */
127 semantic_error("%%%s is not supported.", arg);
128 break;
129 default:
130 DIE_IF("Program has a bug.");
131 break;
132 }
133 }
134
135 /* Exclusion check */
136 if (pp->line && pp->offset)
137 semantic_error("Offset can't be used with line number.");
138 if (!pp->line && pp->file && !pp->function)
139 semantic_error("File always requires line number.");
140 if (pp->offset && !pp->function)
141 semantic_error("Offset requires an entry function.");
142 if (pp->retprobe && !pp->function)
143 semantic_error("Return probe requires an entry function.");
144 if ((pp->offset || pp->line) && pp->retprobe)
145 semantic_error("Offset/Line can't be used with return probe.");
146
147 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
148 pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
149}
150 66
151/* Parse an event definition. Note that any error must die. */ 67/* Parse an event definition. Note that any error must die. */
152static void parse_probe_event(const char *str) 68static void parse_probe_event(const char *str)
153{ 69{
154 char *argv[MAX_PROBE_ARGS + 2]; /* Event + probe + args */
155 int argc, i;
156 struct probe_point *pp = &session.probes[session.nr_probe]; 70 struct probe_point *pp = &session.probes[session.nr_probe];
157 71
158 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str); 72 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
159 if (++session.nr_probe == MAX_PROBES) 73 if (++session.nr_probe == MAX_PROBES)
160 semantic_error("Too many probes"); 74 die("Too many probes (> %d) are specified.", MAX_PROBES);
161
162 /* Separate arguments, similar to argv_split */
163 argc = 0;
164 do {
165 /* Skip separators */
166 while (isspace(*str))
167 str++;
168
169 /* Add an argument */
170 if (*str != '\0') {
171 const char *s = str;
172
173 /* Skip the argument */
174 while (!isspace(*str) && *str != '\0')
175 str++;
176
177 /* Duplicate the argument */
178 argv[argc] = strndup(s, str - s);
179 if (argv[argc] == NULL)
180 die("strndup");
181 if (++argc == MAX_PROBE_ARGS)
182 semantic_error("Too many arguments");
183 pr_debug("argv[%d]=%s\n", argc, argv[argc - 1]);
184 }
185 } while (*str != '\0');
186 if (!argc)
187 semantic_error("An empty argument.");
188
189 /* Parse probe point */
190 parse_probe_point(argv[0], pp);
191 free(argv[0]);
192 if (pp->file || pp->line)
193 session.need_dwarf = 1;
194
195 /* Copy arguments */
196 pp->nr_args = argc - 1;
197 if (pp->nr_args > 0) {
198 pp->args = (char **)malloc(sizeof(char *) * pp->nr_args);
199 if (!pp->args)
200 die("malloc");
201 memcpy(pp->args, &argv[1], sizeof(char *) * pp->nr_args);
202 }
203 75
204 /* Ensure return probe has no C argument */ 76 /* Parse perf-probe event into probe_point */
205 for (i = 0; i < pp->nr_args; i++) 77 session.need_dwarf = parse_perf_probe_event(str, pp);
206 if (is_c_varname(pp->args[i])) {
207 if (pp->retprobe)
208 semantic_error("You can't specify local"
209 " variable for kretprobe");
210 session.need_dwarf = 1;
211 }
212 78
213 pr_debug("%d arguments\n", pp->nr_args); 79 pr_debug("%d arguments\n", pp->nr_args);
214} 80}
@@ -255,6 +121,7 @@ static int open_default_vmlinux(void)
255static const char * const probe_usage[] = { 121static const char * const probe_usage[] = {
256 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 122 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
257 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 123 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
124 "perf probe --list",
258 NULL 125 NULL
259}; 126};
260 127
@@ -265,6 +132,7 @@ static const struct option options[] = {
265 OPT_STRING('k', "vmlinux", &session.vmlinux, "file", 132 OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
266 "vmlinux/module pathname"), 133 "vmlinux/module pathname"),
267#endif 134#endif
135 OPT_BOOLEAN('l', "list", &listing, "list up current probes"),
268 OPT_CALLBACK('a', "add", NULL, 136 OPT_CALLBACK('a', "add", NULL,
269#ifdef NO_LIBDWARF 137#ifdef NO_LIBDWARF
270 "FUNC[+OFFS|%return] [ARG ...]", 138 "FUNC[+OFFS|%return] [ARG ...]",
@@ -285,73 +153,38 @@ static const struct option options[] = {
285 "\t\tALN:\tAbsolute line number in file.\n" 153 "\t\tALN:\tAbsolute line number in file.\n"
286 "\t\tARG:\tProbe argument (local variable name or\n" 154 "\t\tARG:\tProbe argument (local variable name or\n"
287#endif 155#endif
288 "\t\t\tkprobe-tracer argument format is supported.)\n", 156 "\t\t\tkprobe-tracer argument format.)\n",
289 opt_add_probe_event), 157 opt_add_probe_event),
290 OPT_END() 158 OPT_END()
291}; 159};
292 160
293static int write_new_event(int fd, const char *buf)
294{
295 int ret;
296
297 ret = write(fd, buf, strlen(buf));
298 if (ret <= 0)
299 die("Failed to create event.");
300 else
301 printf("Added new event: %s\n", buf);
302
303 return ret;
304}
305
306#define MAX_CMDLEN 256
307
308static int synthesize_probe_event(struct probe_point *pp)
309{
310 char *buf;
311 int i, len, ret;
312 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
313 if (!buf)
314 die("Failed to allocate memory by zalloc.");
315 ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
316 if (ret <= 0 || ret >= MAX_CMDLEN)
317 goto error;
318 len = ret;
319
320 for (i = 0; i < pp->nr_args; i++) {
321 ret = snprintf(&buf[len], MAX_CMDLEN - len, " %s",
322 pp->args[i]);
323 if (ret <= 0 || ret >= MAX_CMDLEN - len)
324 goto error;
325 len += ret;
326 }
327 pp->found = 1;
328 return pp->found;
329error:
330 free(pp->probes[0]);
331 if (ret > 0)
332 ret = -E2BIG;
333 return ret;
334}
335
336int cmd_probe(int argc, const char **argv, const char *prefix __used) 161int cmd_probe(int argc, const char **argv, const char *prefix __used)
337{ 162{
338 int i, j, fd, ret; 163 int i, j, ret;
164#ifndef NO_LIBDWARF
165 int fd;
166#endif
339 struct probe_point *pp; 167 struct probe_point *pp;
340 char buf[MAX_CMDLEN];
341 168
342 argc = parse_options(argc, argv, options, probe_usage, 169 argc = parse_options(argc, argv, options, probe_usage,
343 PARSE_OPT_STOP_AT_NON_OPTION); 170 PARSE_OPT_STOP_AT_NON_OPTION);
344 for (i = 0; i < argc; i++) 171 for (i = 0; i < argc; i++)
345 parse_probe_event(argv[i]); 172 parse_probe_event(argv[i]);
346 173
347 if (session.nr_probe == 0) 174 if ((session.nr_probe == 0 && !listing) ||
175 (session.nr_probe != 0 && listing))
348 usage_with_options(probe_usage, options); 176 usage_with_options(probe_usage, options);
349 177
178 if (listing) {
179 show_perf_probe_events();
180 return 0;
181 }
182
350 if (session.need_dwarf) 183 if (session.need_dwarf)
351#ifdef NO_LIBDWARF 184#ifdef NO_LIBDWARF
352 semantic_error("Debuginfo-analysis is not supported"); 185 die("Debuginfo-analysis is not supported");
353#else /* !NO_LIBDWARF */ 186#else /* !NO_LIBDWARF */
354 pr_info("Some probes require debuginfo.\n"); 187 pr_debug("Some probes require debuginfo.\n");
355 188
356 if (session.vmlinux) 189 if (session.vmlinux)
357 fd = open(session.vmlinux, O_RDONLY); 190 fd = open(session.vmlinux, O_RDONLY);
@@ -395,41 +228,15 @@ end_dwarf:
395 if (pp->found) /* This probe is already found. */ 228 if (pp->found) /* This probe is already found. */
396 continue; 229 continue;
397 230
398 ret = synthesize_probe_event(pp); 231 ret = synthesize_trace_kprobe_event(pp);
399 if (ret == -E2BIG) 232 if (ret == -E2BIG)
400 semantic_error("probe point is too long."); 233 die("probe point definition becomes too long.");
401 else if (ret < 0) 234 else if (ret < 0)
402 die("Failed to synthesize a probe point."); 235 die("Failed to synthesize a probe point.");
403 } 236 }
404 237
405 /* Settng up probe points */ 238 /* Settng up probe points */
406 snprintf(buf, MAX_CMDLEN, "%s/../kprobe_events", debugfs_path); 239 add_trace_kprobe_events(session.probes, session.nr_probe);
407 fd = open(buf, O_WRONLY, O_APPEND);
408 if (fd < 0) {
409 if (errno == ENOENT)
410 die("kprobe_events file does not exist - please rebuild with CONFIG_KPROBE_TRACER.");
411 else
412 die("Could not open kprobe_events file: %s",
413 strerror(errno));
414 }
415 for (j = 0; j < session.nr_probe; j++) {
416 pp = &session.probes[j];
417 if (pp->found == 1) {
418 snprintf(buf, MAX_CMDLEN, "%c:%s/%s_%x %s\n",
419 pp->retprobe ? 'r' : 'p', PERFPROBE_GROUP,
420 pp->function, pp->offset, pp->probes[0]);
421 write_new_event(fd, buf);
422 } else
423 for (i = 0; i < pp->found; i++) {
424 snprintf(buf, MAX_CMDLEN, "%c:%s/%s_%x_%d %s\n",
425 pp->retprobe ? 'r' : 'p',
426 PERFPROBE_GROUP,
427 pp->function, pp->offset, i,
428 pp->probes[0]);
429 write_new_event(fd, buf);
430 }
431 }
432 close(fd);
433 return 0; 240 return 0;
434} 241}
435 242
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index dd4d82ac7aa4..cb58b6605fcc 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -29,14 +29,14 @@
29#include "util/header.h" 29#include "util/header.h"
30#include "util/parse-options.h" 30#include "util/parse-options.h"
31#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/event.h"
33#include "util/data_map.h"
32#include "util/svghelper.h" 34#include "util/svghelper.h"
33 35
34static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
35static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
36 38
37 39
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
40static u64 sample_type; 40static u64 sample_type;
41 41
42static unsigned int numcpus; 42static unsigned int numcpus;
@@ -49,8 +49,6 @@ static u64 first_time, last_time;
49static int power_only; 49static int power_only;
50 50
51 51
52static struct perf_header *header;
53
54struct per_pid; 52struct per_pid;
55struct per_pidcomm; 53struct per_pidcomm;
56 54
@@ -156,9 +154,9 @@ struct sample_wrapper *all_samples;
156 154
157struct process_filter; 155struct process_filter;
158struct process_filter { 156struct process_filter {
159 char *name; 157 char *name;
160 int pid; 158 int pid;
161 struct process_filter *next; 159 struct process_filter *next;
162}; 160};
163 161
164static struct process_filter *process_filter; 162static struct process_filter *process_filter;
@@ -1045,36 +1043,6 @@ static void write_svg_file(const char *filename)
1045 svg_close(); 1043 svg_close();
1046} 1044}
1047 1045
1048static int
1049process_event(event_t *event)
1050{
1051
1052 switch (event->header.type) {
1053
1054 case PERF_RECORD_COMM:
1055 return process_comm_event(event);
1056 case PERF_RECORD_FORK:
1057 return process_fork_event(event);
1058 case PERF_RECORD_EXIT:
1059 return process_exit_event(event);
1060 case PERF_RECORD_SAMPLE:
1061 return queue_sample_event(event);
1062
1063 /*
1064 * We dont process them right now but they are fine:
1065 */
1066 case PERF_RECORD_MMAP:
1067 case PERF_RECORD_THROTTLE:
1068 case PERF_RECORD_UNTHROTTLE:
1069 return 0;
1070
1071 default:
1072 return -1;
1073 }
1074
1075 return 0;
1076}
1077
1078static void process_samples(void) 1046static void process_samples(void)
1079{ 1047{
1080 struct sample_wrapper *cursor; 1048 struct sample_wrapper *cursor;
@@ -1090,114 +1058,38 @@ static void process_samples(void)
1090 } 1058 }
1091} 1059}
1092 1060
1093 1061static int sample_type_check(u64 type)
1094static int __cmd_timechart(void)
1095{ 1062{
1096 int err, rc = EXIT_FAILURE; 1063 sample_type = type;
1097 unsigned long offset = 0;
1098 unsigned long head, shift;
1099 struct stat statbuf;
1100 event_t *event;
1101 uint32_t size;
1102 char *buf;
1103 int input;
1104
1105 input = open(input_name, O_RDONLY);
1106 if (input < 0) {
1107 fprintf(stderr, " failed to open file: %s", input_name);
1108 if (!strcmp(input_name, "perf.data"))
1109 fprintf(stderr, " (try 'perf record' first)");
1110 fprintf(stderr, "\n");
1111 exit(-1);
1112 }
1113
1114 err = fstat(input, &statbuf);
1115 if (err < 0) {
1116 perror("failed to stat file");
1117 exit(-1);
1118 }
1119
1120 if (!statbuf.st_size) {
1121 fprintf(stderr, "zero-sized file, nothing to do!\n");
1122 exit(0);
1123 }
1124 1064
1125 header = perf_header__new(); 1065 if (!(sample_type & PERF_SAMPLE_RAW)) {
1126 if (header == NULL) 1066 fprintf(stderr, "No trace samples found in the file.\n"
1127 return -ENOMEM; 1067 "Have you used 'perf timechart record' to record it?\n");
1128 1068 return -1;
1129 err = perf_header__read(header, input);
1130 if (err < 0) {
1131 perf_header__delete(header);
1132 return err;
1133 }
1134
1135 head = header->data_offset;
1136
1137 sample_type = perf_header__sample_type(header);
1138
1139 shift = page_size * (head / page_size);
1140 offset += shift;
1141 head -= shift;
1142
1143remap:
1144 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1145 MAP_SHARED, input, offset);
1146 if (buf == MAP_FAILED) {
1147 perror("failed to mmap file");
1148 exit(-1);
1149 }
1150
1151more:
1152 event = (event_t *)(buf + head);
1153
1154 size = event->header.size;
1155 if (!size)
1156 size = 8;
1157
1158 if (head + event->header.size >= page_size * mmap_window) {
1159 int ret2;
1160
1161 shift = page_size * (head / page_size);
1162
1163 ret2 = munmap(buf, page_size * mmap_window);
1164 assert(ret2 == 0);
1165
1166 offset += shift;
1167 head -= shift;
1168 goto remap;
1169 }
1170
1171 size = event->header.size;
1172
1173 if (!size || process_event(event) < 0) {
1174 pr_warning("%p [%p]: skipping unknown header type: %d\n",
1175 (void *)(offset + head),
1176 (void *)(long)(event->header.size),
1177 event->header.type);
1178 /*
1179 * assume we lost track of the stream, check alignment, and
1180 * increment a single u64 in the hope to catch on again 'soon'.
1181 */
1182
1183 if (unlikely(head & 7))
1184 head &= ~7ULL;
1185
1186 size = 8;
1187 } 1069 }
1188 1070
1189 head += size; 1071 return 0;
1072}
1190 1073
1191 if (offset + head >= header->data_offset + header->data_size) 1074static struct perf_file_handler file_handler = {
1192 goto done; 1075 .process_comm_event = process_comm_event,
1076 .process_fork_event = process_fork_event,
1077 .process_exit_event = process_exit_event,
1078 .process_sample_event = queue_sample_event,
1079 .sample_type_check = sample_type_check,
1080};
1193 1081
1194 if (offset + head < (unsigned long)statbuf.st_size) 1082static int __cmd_timechart(void)
1195 goto more; 1083{
1084 struct perf_header *header;
1085 int ret;
1196 1086
1197done: 1087 register_perf_file_handler(&file_handler);
1198 rc = EXIT_SUCCESS;
1199 close(input);
1200 1088
1089 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
1090 &event__cwdlen, &event__cwd);
1091 if (ret)
1092 return EXIT_FAILURE;
1201 1093
1202 process_samples(); 1094 process_samples();
1203 1095
@@ -1210,7 +1102,7 @@ done:
1210 pr_info("Written %2.1f seconds of trace to %s.\n", 1102 pr_info("Written %2.1f seconds of trace to %s.\n",
1211 (last_time - first_time) / 1000000000.0, output_name); 1103 (last_time - first_time) / 1000000000.0, output_name);
1212 1104
1213 return rc; 1105 return EXIT_SUCCESS;
1214} 1106}
1215 1107
1216static const char * const timechart_usage[] = { 1108static const char * const timechart_usage[] = {
@@ -1277,8 +1169,6 @@ int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1277{ 1169{
1278 symbol__init(0); 1170 symbol__init(0);
1279 1171
1280 page_size = getpagesize();
1281
1282 argc = parse_options(argc, argv, options, timechart_usage, 1172 argc = parse_options(argc, argv, options, timechart_usage,
1283 PARSE_OPT_STOP_AT_NON_OPTION); 1173 PARSE_OPT_STOP_AT_NON_OPTION);
1284 1174
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 233d7ad9bd7f..414b89d1bde9 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -186,8 +186,7 @@ int event__process_comm(event_t *self)
186{ 186{
187 struct thread *thread = threads__findnew(self->comm.pid); 187 struct thread *thread = threads__findnew(self->comm.pid);
188 188
189 dump_printf("PERF_RECORD_COMM: %s:%d\n", 189 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190 self->comm.comm, self->comm.pid);
191 190
192 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { 191 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
193 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 192 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
new file mode 100644
index 000000000000..cd7fbda5e2a5
--- /dev/null
+++ b/tools/perf/util/probe-event.c
@@ -0,0 +1,484 @@
1/*
2 * probe-event.c : perf-probe definition to kprobe_events format converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#define _GNU_SOURCE
23#include <sys/utsname.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <errno.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <limits.h>
34
35#undef _GNU_SOURCE
36#include "event.h"
37#include "string.h"
38#include "strlist.h"
39#include "debug.h"
40#include "parse-events.h" /* For debugfs_path */
41#include "probe-event.h"
42
43#define MAX_CMDLEN 256
44#define MAX_PROBE_ARGS 128
45#define PERFPROBE_GROUP "probe"
46
47#define semantic_error(msg ...) die("Semantic error :" msg)
48
49/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...)
51{
52 int ret;
53 va_list ap;
54 va_start(ap, format);
55 ret = vsnprintf(str, size, format, ap);
56 va_end(ap);
57 if (ret >= (int)size)
58 ret = -E2BIG;
59 return ret;
60}
61
62/* Parse probepoint definition. */
63static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
64{
65 char *ptr, *tmp;
66 char c, nc = 0;
67 /*
68 * <Syntax>
69 * perf probe SRC:LN
70 * perf probe FUNC[+OFFS|%return][@SRC]
71 */
72
73 ptr = strpbrk(arg, ":+@%");
74 if (ptr) {
75 nc = *ptr;
76 *ptr++ = '\0';
77 }
78
79 /* Check arg is function or file and copy it */
80 if (strchr(arg, '.')) /* File */
81 pp->file = strdup(arg);
82 else /* Function */
83 pp->function = strdup(arg);
84 DIE_IF(pp->file == NULL && pp->function == NULL);
85
86 /* Parse other options */
87 while (ptr) {
88 arg = ptr;
89 c = nc;
90 ptr = strpbrk(arg, ":+@%");
91 if (ptr) {
92 nc = *ptr;
93 *ptr++ = '\0';
94 }
95 switch (c) {
96 case ':': /* Line number */
97 pp->line = strtoul(arg, &tmp, 0);
98 if (*tmp != '\0')
99 semantic_error("There is non-digit charactor"
100 " in line number.");
101 break;
102 case '+': /* Byte offset from a symbol */
103 pp->offset = strtoul(arg, &tmp, 0);
104 if (*tmp != '\0')
105 semantic_error("There is non-digit charactor"
106 " in offset.");
107 break;
108 case '@': /* File name */
109 if (pp->file)
110 semantic_error("SRC@SRC is not allowed.");
111 pp->file = strdup(arg);
112 DIE_IF(pp->file == NULL);
113 if (ptr)
114 semantic_error("@SRC must be the last "
115 "option.");
116 break;
117 case '%': /* Probe places */
118 if (strcmp(arg, "return") == 0) {
119 pp->retprobe = 1;
120 } else /* Others not supported yet */
121 semantic_error("%%%s is not supported.", arg);
122 break;
123 default:
124 DIE_IF("Program has a bug.");
125 break;
126 }
127 }
128
129 /* Exclusion check */
130 if (pp->line && pp->offset)
131 semantic_error("Offset can't be used with line number.");
132
133 if (!pp->line && pp->file && !pp->function)
134 semantic_error("File always requires line number.");
135
136 if (pp->offset && !pp->function)
137 semantic_error("Offset requires an entry function.");
138
139 if (pp->retprobe && !pp->function)
140 semantic_error("Return probe requires an entry function.");
141
142 if ((pp->offset || pp->line) && pp->retprobe)
143 semantic_error("Offset/Line can't be used with return probe.");
144
145 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
146 pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
147}
148
149/* Parse perf-probe event definition */
150int parse_perf_probe_event(const char *str, struct probe_point *pp)
151{
152 char **argv;
153 int argc, i, need_dwarf = 0;
154
155 argv = argv_split(str, &argc);
156 if (!argv)
157 die("argv_split failed.");
158 if (argc > MAX_PROBE_ARGS + 1)
159 semantic_error("Too many arguments");
160
161 /* Parse probe point */
162 parse_perf_probe_probepoint(argv[0], pp);
163 if (pp->file || pp->line)
164 need_dwarf = 1;
165
166 /* Copy arguments and ensure return probe has no C argument */
167 pp->nr_args = argc - 1;
168 pp->args = zalloc(sizeof(char *) * pp->nr_args);
169 for (i = 0; i < pp->nr_args; i++) {
170 pp->args[i] = strdup(argv[i + 1]);
171 if (!pp->args[i])
172 die("Failed to copy argument.");
173 if (is_c_varname(pp->args[i])) {
174 if (pp->retprobe)
175 semantic_error("You can't specify local"
176 " variable for kretprobe");
177 need_dwarf = 1;
178 }
179 }
180
181 argv_free(argv);
182 return need_dwarf;
183}
184
185/* Parse kprobe_events event into struct probe_point */
186void parse_trace_kprobe_event(const char *str, char **group, char **event,
187 struct probe_point *pp)
188{
189 char pr;
190 char *p;
191 int ret, i, argc;
192 char **argv;
193
194 pr_debug("Parsing kprobe_events: %s\n", str);
195 argv = argv_split(str, &argc);
196 if (!argv)
197 die("argv_split failed.");
198 if (argc < 2)
199 semantic_error("Too less arguments.");
200
201 /* Scan event and group name. */
202 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
203 &pr, (float *)(void *)group, (float *)(void *)event);
204 if (ret != 3)
205 semantic_error("Failed to parse event name: %s", argv[0]);
206 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
207
208 if (!pp)
209 goto end;
210
211 pp->retprobe = (pr == 'r');
212
213 /* Scan function name and offset */
214 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset);
215 if (ret == 1)
216 pp->offset = 0;
217
218 /* kprobe_events doesn't have this information */
219 pp->line = 0;
220 pp->file = NULL;
221
222 pp->nr_args = argc - 2;
223 pp->args = zalloc(sizeof(char *) * pp->nr_args);
224 for (i = 0; i < pp->nr_args; i++) {
225 p = strchr(argv[i + 2], '=');
226 if (p) /* We don't need which register is assigned. */
227 *p = '\0';
228 pp->args[i] = strdup(argv[i + 2]);
229 if (!pp->args[i])
230 die("Failed to copy argument.");
231 }
232
233end:
234 argv_free(argv);
235}
236
237int synthesize_perf_probe_event(struct probe_point *pp)
238{
239 char *buf;
240 char offs[64] = "", line[64] = "";
241 int i, len, ret;
242
243 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
244 if (!buf)
245 die("Failed to allocate memory by zalloc.");
246 if (pp->offset) {
247 ret = e_snprintf(offs, 64, "+%d", pp->offset);
248 if (ret <= 0)
249 goto error;
250 }
251 if (pp->line) {
252 ret = e_snprintf(line, 64, ":%d", pp->line);
253 if (ret <= 0)
254 goto error;
255 }
256
257 if (pp->function)
258 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
259 offs, pp->retprobe ? "%return" : "", line);
260 else
261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line);
262 if (ret <= 0)
263 goto error;
264 len = ret;
265
266 for (i = 0; i < pp->nr_args; i++) {
267 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
268 pp->args[i]);
269 if (ret <= 0)
270 goto error;
271 len += ret;
272 }
273 pp->found = 1;
274
275 return pp->found;
276error:
277 free(pp->probes[0]);
278
279 return ret;
280}
281
282int synthesize_trace_kprobe_event(struct probe_point *pp)
283{
284 char *buf;
285 int i, len, ret;
286
287 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
288 if (!buf)
289 die("Failed to allocate memory by zalloc.");
290 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
291 if (ret <= 0)
292 goto error;
293 len = ret;
294
295 for (i = 0; i < pp->nr_args; i++) {
296 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
297 pp->args[i]);
298 if (ret <= 0)
299 goto error;
300 len += ret;
301 }
302 pp->found = 1;
303
304 return pp->found;
305error:
306 free(pp->probes[0]);
307
308 return ret;
309}
310
311static int open_kprobe_events(int flags, int mode)
312{
313 char buf[PATH_MAX];
314 int ret;
315
316 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
317 if (ret < 0)
318 die("Failed to make kprobe_events path.");
319
320 ret = open(buf, flags, mode);
321 if (ret < 0) {
322 if (errno == ENOENT)
323 die("kprobe_events file does not exist -"
324 " please rebuild with CONFIG_KPROBE_TRACER.");
325 else
326 die("Could not open kprobe_events file: %s",
327 strerror(errno));
328 }
329 return ret;
330}
331
332/* Get raw string list of current kprobe_events */
333static struct strlist *get_trace_kprobe_event_rawlist(int fd)
334{
335 int ret, idx;
336 FILE *fp;
337 char buf[MAX_CMDLEN];
338 char *p;
339 struct strlist *sl;
340
341 sl = strlist__new(true, NULL);
342
343 fp = fdopen(dup(fd), "r");
344 while (!feof(fp)) {
345 p = fgets(buf, MAX_CMDLEN, fp);
346 if (!p)
347 break;
348
349 idx = strlen(p) - 1;
350 if (p[idx] == '\n')
351 p[idx] = '\0';
352 ret = strlist__add(sl, buf);
353 if (ret < 0)
354 die("strlist__add failed: %s", strerror(-ret));
355 }
356 fclose(fp);
357
358 return sl;
359}
360
361/* Free and zero clear probe_point */
362static void clear_probe_point(struct probe_point *pp)
363{
364 int i;
365
366 if (pp->function)
367 free(pp->function);
368 if (pp->file)
369 free(pp->file);
370 for (i = 0; i < pp->nr_args; i++)
371 free(pp->args[i]);
372 if (pp->args)
373 free(pp->args);
374 for (i = 0; i < pp->found; i++)
375 free(pp->probes[i]);
376 memset(pp, 0, sizeof(pp));
377}
378
379/* List up current perf-probe events */
380void show_perf_probe_events(void)
381{
382 unsigned int i;
383 int fd;
384 char *group, *event;
385 struct probe_point pp;
386 struct strlist *rawlist;
387 struct str_node *ent;
388
389 fd = open_kprobe_events(O_RDONLY, 0);
390 rawlist = get_trace_kprobe_event_rawlist(fd);
391 close(fd);
392
393 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
394 ent = strlist__entry(rawlist, i);
395 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
396 synthesize_perf_probe_event(&pp);
397 printf("[%s:%s]\t%s\n", group, event, pp.probes[0]);
398 free(group);
399 free(event);
400 clear_probe_point(&pp);
401 }
402
403 strlist__delete(rawlist);
404}
405
406/* Get current perf-probe event names */
407static struct strlist *get_perf_event_names(int fd)
408{
409 unsigned int i;
410 char *group, *event;
411 struct strlist *sl, *rawlist;
412 struct str_node *ent;
413
414 rawlist = get_trace_kprobe_event_rawlist(fd);
415
416 sl = strlist__new(false, NULL);
417 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
418 ent = strlist__entry(rawlist, i);
419 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
420 strlist__add(sl, event);
421 free(group);
422 }
423
424 strlist__delete(rawlist);
425
426 return sl;
427}
428
429static int write_trace_kprobe_event(int fd, const char *buf)
430{
431 int ret;
432
433 ret = write(fd, buf, strlen(buf));
434 if (ret <= 0)
435 die("Failed to create event.");
436 else
437 printf("Added new event: %s\n", buf);
438
439 return ret;
440}
441
442static void get_new_event_name(char *buf, size_t len, const char *base,
443 struct strlist *namelist)
444{
445 int i, ret;
446 for (i = 0; i < MAX_EVENT_INDEX; i++) {
447 ret = e_snprintf(buf, len, "%s_%d", base, i);
448 if (ret < 0)
449 die("snprintf() failed: %s", strerror(-ret));
450 if (!strlist__has_entry(namelist, buf))
451 break;
452 }
453 if (i == MAX_EVENT_INDEX)
454 die("Too many events are on the same function.");
455}
456
457void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
458{
459 int i, j, fd;
460 struct probe_point *pp;
461 char buf[MAX_CMDLEN];
462 char event[64];
463 struct strlist *namelist;
464
465 fd = open_kprobe_events(O_RDWR, O_APPEND);
466 /* Get current event names */
467 namelist = get_perf_event_names(fd);
468
469 for (j = 0; j < nr_probes; j++) {
470 pp = probes + j;
471 for (i = 0; i < pp->found; i++) {
472 /* Get an unused new event name */
473 get_new_event_name(event, 64, pp->function, namelist);
474 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
475 pp->retprobe ? 'r' : 'p',
476 PERFPROBE_GROUP, event,
477 pp->probes[i]);
478 write_trace_kprobe_event(fd, buf);
479 /* Add added event name to namelist */
480 strlist__add(namelist, event);
481 }
482 }
483 close(fd);
484}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644
index 000000000000..0c6fe56fe38a
--- /dev/null
+++ b/tools/perf/util/probe-event.h
@@ -0,0 +1,18 @@
1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H
3
4#include "probe-finder.h"
5#include "strlist.h"
6
7extern int parse_perf_probe_event(const char *str, struct probe_point *pp);
8extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group,
10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes);
13extern void show_perf_probe_events(void);
14
15/* Maximum index number of event-name postfix */
16#define MAX_EVENT_INDEX 1024
17
18#endif /*_PROBE_EVENT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 227043577e06..f24a8cc933d5 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,5 +1,3 @@
1#include <string.h>
2#include <stdlib.h>
3#include "string.h" 1#include "string.h"
4#include "util.h" 2#include "util.h"
5 3
@@ -127,3 +125,104 @@ out_err:
127out: 125out:
128 return length; 126 return length;
129} 127}
128
129/*
130 * Helper function for splitting a string into an argv-like array.
131 * originaly copied from lib/argv_split.c
132 */
133static const char *skip_sep(const char *cp)
134{
135 while (*cp && isspace(*cp))
136 cp++;
137
138 return cp;
139}
140
141static const char *skip_arg(const char *cp)
142{
143 while (*cp && !isspace(*cp))
144 cp++;
145
146 return cp;
147}
148
149static int count_argc(const char *str)
150{
151 int count = 0;
152
153 while (*str) {
154 str = skip_sep(str);
155 if (*str) {
156 count++;
157 str = skip_arg(str);
158 }
159 }
160
161 return count;
162}
163
164/**
165 * argv_free - free an argv
166 * @argv - the argument vector to be freed
167 *
168 * Frees an argv and the strings it points to.
169 */
170void argv_free(char **argv)
171{
172 char **p;
173 for (p = argv; *p; p++)
174 free(*p);
175
176 free(argv);
177}
178
179/**
180 * argv_split - split a string at whitespace, returning an argv
181 * @str: the string to be split
182 * @argcp: returned argument count
183 *
184 * Returns an array of pointers to strings which are split out from
185 * @str. This is performed by strictly splitting on white-space; no
186 * quote processing is performed. Multiple whitespace characters are
187 * considered to be a single argument separator. The returned array
188 * is always NULL-terminated. Returns NULL on memory allocation
189 * failure.
190 */
191char **argv_split(const char *str, int *argcp)
192{
193 int argc = count_argc(str);
194 char **argv = zalloc(sizeof(*argv) * (argc+1));
195 char **argvp;
196
197 if (argv == NULL)
198 goto out;
199
200 if (argcp)
201 *argcp = argc;
202
203 argvp = argv;
204
205 while (*str) {
206 str = skip_sep(str);
207
208 if (*str) {
209 const char *p = str;
210 char *t;
211
212 str = skip_arg(str);
213
214 t = strndup(p, str-p);
215 if (t == NULL)
216 goto fail;
217 *argvp++ = t;
218 }
219 }
220 *argvp = NULL;
221
222out:
223 return argv;
224
225fail:
226 argv_free(argv);
227 return NULL;
228}
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 @@
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7char *strxfrchar(char *s, char from, char to); 7char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str); 8s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp);
10void 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)