aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/build-id.c39
-rw-r--r--tools/perf/util/build-id.h8
-rw-r--r--tools/perf/util/cache.h11
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/cpumap.c59
-rw-r--r--tools/perf/util/cpumap.h7
-rw-r--r--tools/perf/util/ctype.c8
-rw-r--r--tools/perf/util/debug.c5
-rw-r--r--tools/perf/util/debug.h9
-rw-r--r--tools/perf/util/debugfs.c240
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/event.c612
-rw-r--r--tools/perf/util/event.h91
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c640
-rw-r--r--tools/perf/util/header.h83
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/hist.c668
-rw-r--r--tools/perf/util/hist.h29
-rw-r--r--tools/perf/util/include/asm/asm-offsets.h1
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/bug.h22
-rw-r--r--tools/perf/util/include/asm/byteorder.h2
-rw-r--r--tools/perf/util/include/asm/swab.h1
-rw-r--r--tools/perf/util/include/asm/uaccess.h14
-rw-r--r--tools/perf/util/include/linux/bitmap.h3
-rw-r--r--tools/perf/util/include/linux/bitops.h29
-rw-r--r--tools/perf/util/include/linux/compiler.h10
-rw-r--r--tools/perf/util/include/linux/ctype.h1
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h77
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/include/linux/types.h9
-rw-r--r--tools/perf/util/levenshtein.h6
-rw-r--r--tools/perf/util/map.c162
-rw-r--r--tools/perf/util/map.h94
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.c214
-rw-r--r--tools/perf/util/parse-events.h8
-rw-r--r--tools/perf/util/parse-options.c3
-rw-r--r--tools/perf/util/parse-options.h6
-rw-r--r--tools/perf/util/probe-event.c802
-rw-r--r--tools/perf/util/probe-event.h24
-rw-r--r--tools/perf/util/probe-finder.c829
-rw-r--r--tools/perf/util/probe-finder.h92
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c568
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c580
-rw-r--r--tools/perf/util/session.c574
-rw-r--r--tools/perf/util/session.h89
-rw-r--r--tools/perf/util/sigchain.h6
-rw-r--r--tools/perf/util/sort.c316
-rw-r--r--tools/perf/util/sort.h107
-rw-r--r--tools/perf/util/strbuf.h6
-rw-r--r--tools/perf/util/string.c305
-rw-r--r--tools/perf/util/string.h13
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h47
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol.c1561
-rw-r--r--tools/perf/util/symbol.h146
-rw-r--r--tools/perf/util/thread.c315
-rw-r--r--tools/perf/util/thread.h81
-rw-r--r--tools/perf/util/trace-event-info.c90
-rw-r--r--tools/perf/util/trace-event-parse.c601
-rw-r--r--tools/perf/util/trace-event-read.c32
-rw-r--r--tools/perf/util/trace-event-scripting.c167
-rw-r--r--tools/perf/util/trace-event.h72
-rw-r--r--tools/perf/util/types.h6
-rw-r--r--tools/perf/util/util.c94
-rw-r--r--tools/perf/util/util.h34
-rw-r--r--tools/perf/util/values.c1
-rw-r--r--tools/perf/util/values.h6
-rw-r--r--tools/perf/util/wrapper.c61
78 files changed, 9900 insertions, 1589 deletions
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
new file mode 100644
index 000000000000..04904b35ba81
--- /dev/null
+++ b/tools/perf/util/build-id.c
@@ -0,0 +1,39 @@
1/*
2 * build-id.c
3 *
4 * build-id support
5 *
6 * Copyright (C) 2009, 2010 Red Hat Inc.
7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "build-id.h"
10#include "event.h"
11#include "symbol.h"
12#include <linux/kernel.h>
13
14static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
15{
16 struct addr_location al;
17 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
18 struct thread *thread = perf_session__findnew(session, event->ip.pid);
19
20 if (thread == NULL) {
21 pr_err("problem processing %d event, skipping it.\n",
22 event->header.type);
23 return -1;
24 }
25
26 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
27 event->ip.ip, &al);
28
29 if (al.map != NULL)
30 al.map->dso->hit = 1;
31
32 return 0;
33}
34
35struct perf_event_ops build_id__mark_dso_hit_ops = {
36 .sample = build_id__mark_dso_hit,
37 .mmap = event__process_mmap,
38 .fork = event__process_task,
39};
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
new file mode 100644
index 000000000000..1d981d63cf9a
--- /dev/null
+++ b/tools/perf/util/build-id.h
@@ -0,0 +1,8 @@
1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1
3
4#include "session.h"
5
6extern struct perf_event_ops build_id__mark_dso_hit_ops;
7
8#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 6f8ea9d210b6..918eb376abe3 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,10 +1,15 @@
1#ifndef CACHE_H 1#ifndef __PERF_CACHE_H
2#define CACHE_H 2#define __PERF_CACHE_H
3 3
4#include "util.h" 4#include "util.h"
5#include "strbuf.h" 5#include "strbuf.h"
6#include "../perf.h" 6#include "../perf.h"
7 7
8#define CMD_EXEC_PATH "--exec-path"
9#define CMD_PERF_DIR "--perf-dir="
10#define CMD_WORK_TREE "--work-tree="
11#define CMD_DEBUGFS_DIR "--debugfs-dir="
12
8#define PERF_DIR_ENVIRONMENT "PERF_DIR" 13#define PERF_DIR_ENVIRONMENT "PERF_DIR"
9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 14#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
10#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" 15#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
117 122
118extern size_t strlcpy(char *dest, const char *src, size_t size); 123extern size_t strlcpy(char *dest, const char *src, size_t size);
119 124
120#endif /* CACHE_H */ 125#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3b8380f1b478..b3b71258272a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
206 } 206 }
207 node->val_nr = chain->nr - start; 207 node->val_nr = chain->nr - start;
208 if (!node->val_nr) 208 if (!node->val_nr)
209 printf("Warning: empty node in callchain tree\n"); 209 pr_warning("Warning: empty node in callchain tree\n");
210} 210}
211 211
212static void 212static void
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 43cf3ea9e088..ad4626de4c2b 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
58int register_callchain_param(struct callchain_param *param); 58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 59void append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 60 struct symbol **syms);
61#endif 61#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 58d597564b99..24e8809210bb 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -1,5 +1,5 @@
1#ifndef COLOR_H 1#ifndef __PERF_COLOR_H
2#define COLOR_H 2#define __PERF_COLOR_H
3 3
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ 4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24 5#define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 40const char *get_percent_color(double percent);
41 41
42#endif /* COLOR_H */ 42#endif /* __PERF_COLOR_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
new file mode 100644
index 000000000000..4e01490e51e5
--- /dev/null
+++ b/tools/perf/util/cpumap.c
@@ -0,0 +1,59 @@
1#include "util.h"
2#include "../perf.h"
3#include "cpumap.h"
4#include <assert.h>
5#include <stdio.h>
6
7int cpumap[MAX_NR_CPUS];
8
9static int default_cpu_map(void)
10{
11 int nr_cpus, i;
12
13 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14 assert(nr_cpus <= MAX_NR_CPUS);
15 assert((int)nr_cpus >= 0);
16
17 for (i = 0; i < nr_cpus; ++i)
18 cpumap[i] = i;
19
20 return nr_cpus;
21}
22
23int read_cpu_map(void)
24{
25 FILE *onlnf;
26 int nr_cpus = 0;
27 int n, cpu, prev;
28 char sep;
29
30 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 if (!onlnf)
32 return default_cpu_map();
33
34 sep = 0;
35 prev = -1;
36 for (;;) {
37 n = fscanf(onlnf, "%u%c", &cpu, &sep);
38 if (n <= 0)
39 break;
40 if (prev >= 0) {
41 assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS);
42 while (++prev < cpu)
43 cpumap[nr_cpus++] = prev;
44 }
45 assert (nr_cpus < MAX_NR_CPUS);
46 cpumap[nr_cpus++] = cpu;
47 if (n == 2 && sep == '-')
48 prev = cpu;
49 else
50 prev = -1;
51 if (n == 1 || sep == '\n')
52 break;
53 }
54 fclose(onlnf);
55 if (nr_cpus > 0)
56 return nr_cpus;
57
58 return default_cpu_map();
59}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
new file mode 100644
index 000000000000..86c78bb33098
--- /dev/null
+++ b/tools/perf/util/cpumap.h
@@ -0,0 +1,7 @@
1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H
3
4extern int read_cpu_map(void);
5extern int cpumap[];
6
7#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index 0b791bd346bc..35073621e5de 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -29,3 +29,11 @@ unsigned char sane_ctype[256] = {
29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */ 29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
30 /* Nothing in the 128.. range */ 30 /* Nothing in the 128.. range */
31}; 31};
32
33const char *graph_line =
34 "_____________________________________________________________________"
35 "_____________________________________________________________________";
36const char *graph_dotted_line =
37 "---------------------------------------------------------------------"
38 "---------------------------------------------------------------------"
39 "---------------------------------------------------------------------";
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index e8ca98fe0bd4..0905600c3851 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -9,16 +9,17 @@
9#include "color.h" 9#include "color.h"
10#include "event.h" 10#include "event.h"
11#include "debug.h" 11#include "debug.h"
12#include "util.h"
12 13
13int verbose = 0; 14int verbose = 0;
14int dump_trace = 0; 15int dump_trace = 0;
15 16
16int eprintf(const char *fmt, ...) 17int eprintf(int level, const char *fmt, ...)
17{ 18{
18 va_list args; 19 va_list args;
19 int ret = 0; 20 int ret = 0;
20 21
21 if (verbose) { 22 if (verbose >= level) {
22 va_start(args, fmt); 23 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args); 24 ret = vfprintf(stderr, fmt, args);
24 va_end(args); 25 va_end(args);
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 437eea58ce40..c6c24c522dea 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -1,8 +1,15 @@
1/* For debugging general purposes */ 1/* For debugging general purposes */
2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H
4
5#include "event.h"
2 6
3extern int verbose; 7extern int verbose;
4extern int dump_trace; 8extern int dump_trace;
5 9
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event); 13void trace_event(event_t *event);
14
15#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
new file mode 100644
index 000000000000..a88fefc0cc0a
--- /dev/null
+++ b/tools/perf/util/debugfs.c
@@ -0,0 +1,240 @@
1#include "util.h"
2#include "debugfs.h"
3#include "cache.h"
4
5static int debugfs_premounted;
6static char debugfs_mountpoint[MAX_PATH+1];
7
8static const char *debugfs_known_mountpoints[] = {
9 "/sys/kernel/debug/",
10 "/debug/",
11 0,
12};
13
14/* use this to force a umount */
15void debugfs_force_cleanup(void)
16{
17 debugfs_find_mountpoint();
18 debugfs_premounted = 0;
19 debugfs_umount();
20}
21
22/* construct a full path to a debugfs element */
23int debugfs_make_path(const char *element, char *buffer, int size)
24{
25 int len;
26
27 if (strlen(debugfs_mountpoint) == 0) {
28 buffer[0] = '\0';
29 return -1;
30 }
31
32 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
33 if (len >= size)
34 return len+1;
35
36 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
37 return 0;
38}
39
40static int debugfs_found;
41
42/* find the path to the mounted debugfs */
43const char *debugfs_find_mountpoint(void)
44{
45 const char **ptr;
46 char type[100];
47 FILE *fp;
48
49 if (debugfs_found)
50 return (const char *) debugfs_mountpoint;
51
52 ptr = debugfs_known_mountpoints;
53 while (*ptr) {
54 if (debugfs_valid_mountpoint(*ptr) == 0) {
55 debugfs_found = 1;
56 strcpy(debugfs_mountpoint, *ptr);
57 return debugfs_mountpoint;
58 }
59 ptr++;
60 }
61
62 /* give up and parse /proc/mounts */
63 fp = fopen("/proc/mounts", "r");
64 if (fp == NULL)
65 die("Can't open /proc/mounts for read");
66
67 while (fscanf(fp, "%*s %"
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
70 debugfs_mountpoint, type) == 2) {
71 if (strcmp(type, "debugfs") == 0)
72 break;
73 }
74 fclose(fp);
75
76 if (strcmp(type, "debugfs") != 0)
77 return NULL;
78
79 debugfs_found = 1;
80
81 return debugfs_mountpoint;
82}
83
84/* verify that a mountpoint is actually a debugfs instance */
85
86int debugfs_valid_mountpoint(const char *debugfs)
87{
88 struct statfs st_fs;
89
90 if (statfs(debugfs, &st_fs) < 0)
91 return -ENOENT;
92 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
93 return -ENOENT;
94
95 return 0;
96}
97
98
99int debugfs_valid_entry(const char *path)
100{
101 struct stat st;
102
103 if (stat(path, &st))
104 return -errno;
105
106 return 0;
107}
108
109/* mount the debugfs somewhere if it's not mounted */
110
111char *debugfs_mount(const char *mountpoint)
112{
113 /* see if it's already mounted */
114 if (debugfs_find_mountpoint()) {
115 debugfs_premounted = 1;
116 return debugfs_mountpoint;
117 }
118
119 /* if not mounted and no argument */
120 if (mountpoint == NULL) {
121 /* see if environment variable set */
122 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
123 /* if no environment variable, use default */
124 if (mountpoint == NULL)
125 mountpoint = "/sys/kernel/debug";
126 }
127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
131 /* save the mountpoint */
132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
134
135 return debugfs_mountpoint;
136}
137
138/* umount the debugfs */
139
140int debugfs_umount(void)
141{
142 char umountcmd[128];
143 int ret;
144
145 /* if it was already mounted, leave it */
146 if (debugfs_premounted)
147 return 0;
148
149 /* make sure it's a valid mount point */
150 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
151 if (ret)
152 return ret;
153
154 snprintf(umountcmd, sizeof(umountcmd),
155 "/bin/umount %s", debugfs_mountpoint);
156 return system(umountcmd);
157}
158
159int debugfs_write(const char *entry, const char *value)
160{
161 char path[MAX_PATH+1];
162 int ret, count;
163 int fd;
164
165 /* construct the path */
166 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
167
168 /* verify that it exists */
169 ret = debugfs_valid_entry(path);
170 if (ret)
171 return ret;
172
173 /* get how many chars we're going to write */
174 count = strlen(value);
175
176 /* open the debugfs entry */
177 fd = open(path, O_RDWR);
178 if (fd < 0)
179 return -errno;
180
181 while (count > 0) {
182 /* write it */
183 ret = write(fd, value, count);
184 if (ret <= 0) {
185 if (ret == EAGAIN)
186 continue;
187 close(fd);
188 return -errno;
189 }
190 count -= ret;
191 }
192
193 /* close it */
194 close(fd);
195
196 /* return success */
197 return 0;
198}
199
200/*
201 * read a debugfs entry
202 * returns the number of chars read or a negative errno
203 */
204int debugfs_read(const char *entry, char *buffer, size_t size)
205{
206 char path[MAX_PATH+1];
207 int ret;
208 int fd;
209
210 /* construct the path */
211 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
212
213 /* verify that it exists */
214 ret = debugfs_valid_entry(path);
215 if (ret)
216 return ret;
217
218 /* open the debugfs entry */
219 fd = open(path, O_RDONLY);
220 if (fd < 0)
221 return -errno;
222
223 do {
224 /* read it */
225 ret = read(fd, buffer, size);
226 if (ret == 0) {
227 close(fd);
228 return EOF;
229 }
230 } while (ret < 0 && errno == EAGAIN);
231
232 /* close it */
233 close(fd);
234
235 /* make *sure* there's a null character at the end */
236 buffer[ret] = '\0';
237
238 /* return the number of chars read */
239 return ret;
240}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
new file mode 100644
index 000000000000..83a02879745f
--- /dev/null
+++ b/tools/perf/util/debugfs.h
@@ -0,0 +1,25 @@
1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__
3
4#include <sys/mount.h>
5
6#ifndef MAX_PATH
7# define MAX_PATH 256
8#endif
9
10#ifndef STR
11# define _STR(x) #x
12# define STR(x) _STR(x)
13#endif
14
15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path);
18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size);
22extern void debugfs_force_cleanup(void);
23extern int debugfs_make_path(const char *element, char *buffer, int size);
24
25#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644
index 000000000000..705ec63548b4
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,612 @@
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "session.h"
5#include "sort.h"
6#include "string.h"
7#include "strlist.h"
8#include "thread.h"
9
10static pid_t event__synthesize_comm(pid_t pid, int full,
11 event__handler_t process,
12 struct perf_session *session)
13{
14 event_t ev;
15 char filename[PATH_MAX];
16 char bf[BUFSIZ];
17 FILE *fp;
18 size_t size = 0;
19 DIR *tasks;
20 struct dirent dirent, *next;
21 pid_t tgid = 0;
22
23 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
24
25 fp = fopen(filename, "r");
26 if (fp == NULL) {
27out_race:
28 /*
29 * We raced with a task exiting - just return:
30 */
31 pr_debug("couldn't open %s\n", filename);
32 return 0;
33 }
34
35 memset(&ev.comm, 0, sizeof(ev.comm));
36 while (!ev.comm.comm[0] || !ev.comm.pid) {
37 if (fgets(bf, sizeof(bf), fp) == NULL)
38 goto out_failure;
39
40 if (memcmp(bf, "Name:", 5) == 0) {
41 char *name = bf + 5;
42 while (*name && isspace(*name))
43 ++name;
44 size = strlen(name) - 1;
45 memcpy(ev.comm.comm, name, size++);
46 } else if (memcmp(bf, "Tgid:", 5) == 0) {
47 char *tgids = bf + 5;
48 while (*tgids && isspace(*tgids))
49 ++tgids;
50 tgid = ev.comm.pid = atoi(tgids);
51 }
52 }
53
54 ev.comm.header.type = PERF_RECORD_COMM;
55 size = ALIGN(size, sizeof(u64));
56 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
57
58 if (!full) {
59 ev.comm.tid = pid;
60
61 process(&ev, session);
62 goto out_fclose;
63 }
64
65 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
66
67 tasks = opendir(filename);
68 if (tasks == NULL)
69 goto out_race;
70
71 while (!readdir_r(tasks, &dirent, &next) && next) {
72 char *end;
73 pid = strtol(dirent.d_name, &end, 10);
74 if (*end)
75 continue;
76
77 ev.comm.tid = pid;
78
79 process(&ev, session);
80 }
81 closedir(tasks);
82
83out_fclose:
84 fclose(fp);
85 return tgid;
86
87out_failure:
88 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
89 return -1;
90}
91
92static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
93 event__handler_t process,
94 struct perf_session *session)
95{
96 char filename[PATH_MAX];
97 FILE *fp;
98
99 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
100
101 fp = fopen(filename, "r");
102 if (fp == NULL) {
103 /*
104 * We raced with a task exiting - just return:
105 */
106 pr_debug("couldn't open %s\n", filename);
107 return -1;
108 }
109
110 while (1) {
111 char bf[BUFSIZ], *pbf = bf;
112 event_t ev = {
113 .header = {
114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */
116 },
117 };
118 int n;
119 size_t size;
120 if (fgets(bf, sizeof(bf), fp) == NULL)
121 break;
122
123 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
124 n = hex2u64(pbf, &ev.mmap.start);
125 if (n < 0)
126 continue;
127 pbf += n + 1;
128 n = hex2u64(pbf, &ev.mmap.len);
129 if (n < 0)
130 continue;
131 pbf += n + 3;
132 if (*pbf == 'x') { /* vm_exec */
133 char *execname = strchr(bf, '/');
134
135 /* Catch VDSO */
136 if (execname == NULL)
137 execname = strstr(bf, "[vdso]");
138
139 if (execname == NULL)
140 continue;
141
142 size = strlen(execname);
143 execname[size - 1] = '\0'; /* Remove \n */
144 memcpy(ev.mmap.filename, execname, size);
145 size = ALIGN(size, sizeof(u64));
146 ev.mmap.len -= ev.mmap.start;
147 ev.mmap.header.size = (sizeof(ev.mmap) -
148 (sizeof(ev.mmap.filename) - size));
149 ev.mmap.pid = tgid;
150 ev.mmap.tid = pid;
151
152 process(&ev, session);
153 }
154 }
155
156 fclose(fp);
157 return 0;
158}
159
160int event__synthesize_modules(event__handler_t process,
161 struct perf_session *session)
162{
163 struct rb_node *nd;
164
165 for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]);
166 nd; nd = rb_next(nd)) {
167 event_t ev;
168 size_t size;
169 struct map *pos = rb_entry(nd, struct map, rb_node);
170
171 if (pos->dso->kernel)
172 continue;
173
174 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
175 memset(&ev, 0, sizeof(ev));
176 ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
177 ev.mmap.header.type = PERF_RECORD_MMAP;
178 ev.mmap.header.size = (sizeof(ev.mmap) -
179 (sizeof(ev.mmap.filename) - size));
180 ev.mmap.start = pos->start;
181 ev.mmap.len = pos->end - pos->start;
182
183 memcpy(ev.mmap.filename, pos->dso->long_name,
184 pos->dso->long_name_len + 1);
185 process(&ev, session);
186 }
187
188 return 0;
189}
190
191int event__synthesize_thread(pid_t pid, event__handler_t process,
192 struct perf_session *session)
193{
194 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
195 if (tgid == -1)
196 return -1;
197 return event__synthesize_mmap_events(pid, tgid, process, session);
198}
199
200void event__synthesize_threads(event__handler_t process,
201 struct perf_session *session)
202{
203 DIR *proc;
204 struct dirent dirent, *next;
205
206 proc = opendir("/proc");
207
208 while (!readdir_r(proc, &dirent, &next) && next) {
209 char *end;
210 pid_t pid = strtol(dirent.d_name, &end, 10);
211
212 if (*end) /* only interested in proper numerical dirents */
213 continue;
214
215 event__synthesize_thread(pid, process, session);
216 }
217
218 closedir(proc);
219}
220
221struct process_symbol_args {
222 const char *name;
223 u64 start;
224};
225
226static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
227{
228 struct process_symbol_args *args = arg;
229
230 /*
231 * Must be a function or at least an alias, as in PARISC64, where "_text" is
232 * an 'A' to the same address as "_stext".
233 */
234 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
235 type == 'A') || strcmp(name, args->name))
236 return 0;
237
238 args->start = start;
239 return 1;
240}
241
242int event__synthesize_kernel_mmap(event__handler_t process,
243 struct perf_session *session,
244 const char *symbol_name)
245{
246 size_t size;
247 event_t ev = {
248 .header = {
249 .type = PERF_RECORD_MMAP,
250 .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
251 },
252 };
253 /*
254 * We should get this from /sys/kernel/sections/.text, but till that is
255 * available use this, and after it is use this as a fallback for older
256 * kernels.
257 */
258 struct process_symbol_args args = { .name = symbol_name, };
259
260 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
261 return -ENOENT;
262
263 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
264 "[kernel.kallsyms.%s]", symbol_name) + 1;
265 size = ALIGN(size, sizeof(u64));
266 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
267 ev.mmap.pgoff = args.start;
268 ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start;
269 ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ;
270
271 return process(&ev, session);
272}
273
274static void thread__comm_adjust(struct thread *self)
275{
276 char *comm = self->comm;
277
278 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
279 (!symbol_conf.comm_list ||
280 strlist__has_entry(symbol_conf.comm_list, comm))) {
281 unsigned int slen = strlen(comm);
282
283 if (slen > comms__col_width) {
284 comms__col_width = slen;
285 threads__col_width = slen + 6;
286 }
287 }
288}
289
290static int thread__set_comm_adjust(struct thread *self, const char *comm)
291{
292 int ret = thread__set_comm(self, comm);
293
294 if (ret)
295 return ret;
296
297 thread__comm_adjust(self);
298
299 return 0;
300}
301
302int event__process_comm(event_t *self, struct perf_session *session)
303{
304 struct thread *thread = perf_session__findnew(session, self->comm.pid);
305
306 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
307
308 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
309 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
310 return -1;
311 }
312
313 return 0;
314}
315
316int event__process_lost(event_t *self, struct perf_session *session)
317{
318 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
319 session->events_stats.lost += self->lost.lost;
320 return 0;
321}
322
323int event__process_mmap(event_t *self, struct perf_session *session)
324{
325 struct thread *thread;
326 struct map *map;
327
328 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
329 self->mmap.pid, self->mmap.tid, self->mmap.start,
330 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
331
332 if (self->mmap.pid == 0) {
333 static const char kmmap_prefix[] = "[kernel.kallsyms.";
334
335 if (self->mmap.filename[0] == '/') {
336 char short_module_name[1024];
337 char *name = strrchr(self->mmap.filename, '/'), *dot;
338
339 if (name == NULL)
340 goto out_problem;
341
342 ++name; /* skip / */
343 dot = strrchr(name, '.');
344 if (dot == NULL)
345 goto out_problem;
346
347 snprintf(short_module_name, sizeof(short_module_name),
348 "[%.*s]", (int)(dot - name), name);
349 strxfrchar(short_module_name, '-', '_');
350
351 map = perf_session__new_module_map(session,
352 self->mmap.start,
353 self->mmap.filename);
354 if (map == NULL)
355 goto out_problem;
356
357 name = strdup(short_module_name);
358 if (name == NULL)
359 goto out_problem;
360
361 map->dso->short_name = name;
362 map->end = map->start + self->mmap.len;
363 } else if (memcmp(self->mmap.filename, kmmap_prefix,
364 sizeof(kmmap_prefix) - 1) == 0) {
365 const char *symbol_name = (self->mmap.filename +
366 sizeof(kmmap_prefix) - 1);
367 /*
368 * Should be there already, from the build-id table in
369 * the header.
370 */
371 struct dso *kernel = __dsos__findnew(&dsos__kernel,
372 "[kernel.kallsyms]");
373 if (kernel == NULL)
374 goto out_problem;
375
376 kernel->kernel = 1;
377 if (__perf_session__create_kernel_maps(session, kernel) < 0)
378 goto out_problem;
379
380 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start;
381 session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
382 /*
383 * Be a bit paranoid here, some perf.data file came with
384 * a zero sized synthesized MMAP event for the kernel.
385 */
386 if (session->vmlinux_maps[MAP__FUNCTION]->end == 0)
387 session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL;
388
389 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
390 self->mmap.pgoff);
391 }
392 return 0;
393 }
394
395 thread = perf_session__findnew(session, self->mmap.pid);
396 map = map__new(&self->mmap, MAP__FUNCTION,
397 session->cwd, session->cwdlen);
398
399 if (thread == NULL || map == NULL)
400 goto out_problem;
401
402 thread__insert_map(thread, map);
403 return 0;
404
405out_problem:
406 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
407 return 0;
408}
409
410int event__process_task(event_t *self, struct perf_session *session)
411{
412 struct thread *thread = perf_session__findnew(session, self->fork.pid);
413 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
414
415 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
416 self->fork.ppid, self->fork.ptid);
417 /*
418 * A thread clone will have the same PID for both parent and child.
419 */
420 if (thread == parent)
421 return 0;
422
423 if (self->header.type == PERF_RECORD_EXIT)
424 return 0;
425
426 if (thread == NULL || parent == NULL ||
427 thread__fork(thread, parent) < 0) {
428 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
429 return -1;
430 }
431
432 return 0;
433}
434
435void thread__find_addr_map(struct thread *self,
436 struct perf_session *session, u8 cpumode,
437 enum map_type type, u64 addr,
438 struct addr_location *al)
439{
440 struct map_groups *mg = &self->mg;
441
442 al->thread = self;
443 al->addr = addr;
444
445 if (cpumode == PERF_RECORD_MISC_KERNEL) {
446 al->level = 'k';
447 mg = &session->kmaps;
448 } else if (cpumode == PERF_RECORD_MISC_USER)
449 al->level = '.';
450 else {
451 al->level = 'H';
452 al->map = NULL;
453 return;
454 }
455try_again:
456 al->map = map_groups__find(mg, type, al->addr);
457 if (al->map == NULL) {
458 /*
459 * If this is outside of all known maps, and is a negative
460 * address, try to look it up in the kernel dso, as it might be
461 * a vsyscall or vdso (which executes in user-mode).
462 *
463 * XXX This is nasty, we should have a symbol list in the
464 * "[vdso]" dso, but for now lets use the old trick of looking
465 * in the whole kernel symbol list.
466 */
467 if ((long long)al->addr < 0 && mg != &session->kmaps) {
468 mg = &session->kmaps;
469 goto try_again;
470 }
471 } else
472 al->addr = al->map->map_ip(al->map, al->addr);
473}
474
475void thread__find_addr_location(struct thread *self,
476 struct perf_session *session, u8 cpumode,
477 enum map_type type, u64 addr,
478 struct addr_location *al,
479 symbol_filter_t filter)
480{
481 thread__find_addr_map(self, session, cpumode, type, addr, al);
482 if (al->map != NULL)
483 al->sym = map__find_symbol(al->map, al->addr, filter);
484 else
485 al->sym = NULL;
486}
487
488static void dso__calc_col_width(struct dso *self)
489{
490 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
491 (!symbol_conf.dso_list ||
492 strlist__has_entry(symbol_conf.dso_list, self->name))) {
493 unsigned int slen = strlen(self->name);
494 if (slen > dsos__col_width)
495 dsos__col_width = slen;
496 }
497
498 self->slen_calculated = 1;
499}
500
501int event__preprocess_sample(const event_t *self, struct perf_session *session,
502 struct addr_location *al, symbol_filter_t filter)
503{
504 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
505 struct thread *thread = perf_session__findnew(session, self->ip.pid);
506
507 if (thread == NULL)
508 return -1;
509
510 if (symbol_conf.comm_list &&
511 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
512 goto out_filtered;
513
514 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
515
516 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
517 self->ip.ip, al, filter);
518 dump_printf(" ...... dso: %s\n",
519 al->map ? al->map->dso->long_name :
520 al->level == 'H' ? "[hypervisor]" : "<not found>");
521 /*
522 * We have to do this here as we may have a dso with no symbol hit that
523 * has a name longer than the ones with symbols sampled.
524 */
525 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
526 dso__calc_col_width(al->map->dso);
527
528 if (symbol_conf.dso_list &&
529 (!al->map || !al->map->dso ||
530 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
531 (al->map->dso->short_name != al->map->dso->long_name &&
532 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
533 goto out_filtered;
534
535 if (symbol_conf.sym_list && al->sym &&
536 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
537 goto out_filtered;
538
539 al->filtered = false;
540 return 0;
541
542out_filtered:
543 al->filtered = true;
544 return 0;
545}
546
547int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
548{
549 u64 *array = event->sample.array;
550
551 if (type & PERF_SAMPLE_IP) {
552 data->ip = event->ip.ip;
553 array++;
554 }
555
556 if (type & PERF_SAMPLE_TID) {
557 u32 *p = (u32 *)array;
558 data->pid = p[0];
559 data->tid = p[1];
560 array++;
561 }
562
563 if (type & PERF_SAMPLE_TIME) {
564 data->time = *array;
565 array++;
566 }
567
568 if (type & PERF_SAMPLE_ADDR) {
569 data->addr = *array;
570 array++;
571 }
572
573 if (type & PERF_SAMPLE_ID) {
574 data->id = *array;
575 array++;
576 }
577
578 if (type & PERF_SAMPLE_STREAM_ID) {
579 data->stream_id = *array;
580 array++;
581 }
582
583 if (type & PERF_SAMPLE_CPU) {
584 u32 *p = (u32 *)array;
585 data->cpu = *p;
586 array++;
587 }
588
589 if (type & PERF_SAMPLE_PERIOD) {
590 data->period = *array;
591 array++;
592 }
593
594 if (type & PERF_SAMPLE_READ) {
595 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
596 return -1;
597 }
598
599 if (type & PERF_SAMPLE_CALLCHAIN) {
600 data->callchain = (struct ip_callchain *)array;
601 array += 1 + data->callchain->nr;
602 }
603
604 if (type & PERF_SAMPLE_RAW) {
605 u32 *p = (u32 *)array;
606 data->raw_size = *p;
607 p++;
608 data->raw_data = p;
609 }
610
611 return 0;
612}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..a33b94952e34 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,14 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3#include "../perf.h"
4#include "util.h"
5#include <linux/list.h>
6 3
7enum { 4#include <limits.h>
8 SHOW_KERNEL = 1, 5
9 SHOW_USER = 2, 6#include "../perf.h"
10 SHOW_HV = 4, 7#include "map.h"
11};
12 8
13/* 9/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -60,11 +56,32 @@ struct read_event {
60 u64 id; 56 u64 id;
61}; 57};
62 58
63struct sample_event{ 59struct sample_event {
64 struct perf_event_header header; 60 struct perf_event_header header;
65 u64 array[]; 61 u64 array[];
66}; 62};
67 63
64struct sample_data {
65 u64 ip;
66 u32 pid, tid;
67 u64 time;
68 u64 addr;
69 u64 id;
70 u64 stream_id;
71 u32 cpu;
72 u64 period;
73 struct ip_callchain *callchain;
74 u32 raw_size;
75 void *raw_data;
76};
77
78#define BUILD_ID_SIZE 20
79
80struct build_id_event {
81 struct perf_event_header header;
82 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
83 char filename[];
84};
68 85
69typedef union event_union { 86typedef union event_union {
70 struct perf_event_header header; 87 struct perf_event_header header;
@@ -77,28 +94,44 @@ typedef union event_union {
77 struct sample_event sample; 94 struct sample_event sample;
78} event_t; 95} event_t;
79 96
80struct map { 97struct events_stats {
81 struct list_head node; 98 u64 total;
82 u64 start; 99 u64 lost;
83 u64 end;
84 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64);
86 struct dso *dso;
87}; 100};
88 101
89static inline u64 map__map_ip(struct map *map, u64 ip) 102struct event_stat_id {
90{ 103 struct rb_node rb_node;
91 return ip - map->start + map->pgoff; 104 struct rb_root hists;
92} 105 struct events_stats stats;
106 u64 config;
107 u64 event_stream;
108 u32 type;
109};
110
111void event__print_totals(void);
112
113struct perf_session;
114
115typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
116
117int event__synthesize_thread(pid_t pid, event__handler_t process,
118 struct perf_session *session);
119void event__synthesize_threads(event__handler_t process,
120 struct perf_session *session);
121int event__synthesize_kernel_mmap(event__handler_t process,
122 struct perf_session *session,
123 const char *symbol_name);
124int event__synthesize_modules(event__handler_t process,
125 struct perf_session *session);
93 126
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip) 127int event__process_comm(event_t *self, struct perf_session *session);
95{ 128int event__process_lost(event_t *self, struct perf_session *session);
96 return ip; 129int event__process_mmap(event_t *self, struct perf_session *session);
97} 130int event__process_task(event_t *self, struct perf_session *session);
98 131
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); 132struct addr_location;
100struct map *map__clone(struct map *self); 133int event__preprocess_sample(const event_t *self, struct perf_session *session,
101int map__overlap(struct map *l, struct map *r); 134 struct addr_location *al, symbol_filter_t filter);
102size_t map__fprintf(struct map *self, FILE *fp); 135int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
103 136
104#endif 137#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index effe25eb1545..31647ac92ed1 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -1,5 +1,5 @@
1#ifndef PERF_EXEC_CMD_H 1#ifndef __PERF_EXEC_CMD_H
2#define PERF_EXEC_CMD_H 2#define __PERF_EXEC_CMD_H
3 3
4extern void perf_set_argv_exec_path(const char *exec_path); 4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path); 5extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...); 10extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path); 11extern const char *system_path(const char *path);
12 12
13#endif /* PERF_EXEC_CMD_H */ 13#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e306857b2c2b..6c9aa16ee51f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,10 +1,20 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <sys/types.h> 3#include <sys/types.h>
4#include <byteswap.h>
2#include <unistd.h> 5#include <unistd.h>
3#include <stdio.h> 6#include <stdio.h>
4#include <stdlib.h> 7#include <stdlib.h>
8#include <linux/list.h>
9#include <linux/kernel.h>
5 10
6#include "util.h" 11#include "util.h"
7#include "header.h" 12#include "header.h"
13#include "../perf.h"
14#include "trace-event.h"
15#include "session.h"
16#include "symbol.h"
17#include "debug.h"
8 18
9/* 19/*
10 * Create new perf.data header attribute: 20 * Create new perf.data header attribute:
@@ -13,75 +23,80 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
13{ 23{
14 struct perf_header_attr *self = malloc(sizeof(*self)); 24 struct perf_header_attr *self = malloc(sizeof(*self));
15 25
16 if (!self) 26 if (self != NULL) {
17 die("nomem"); 27 self->attr = *attr;
18 28 self->ids = 0;
19 self->attr = *attr; 29 self->size = 1;
20 self->ids = 0; 30 self->id = malloc(sizeof(u64));
21 self->size = 1; 31 if (self->id == NULL) {
22 self->id = malloc(sizeof(u64)); 32 free(self);
23 33 self = NULL;
24 if (!self->id) 34 }
25 die("nomem"); 35 }
26 36
27 return self; 37 return self;
28} 38}
29 39
30void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 40void perf_header_attr__delete(struct perf_header_attr *self)
41{
42 free(self->id);
43 free(self);
44}
45
46int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
31{ 47{
32 int pos = self->ids; 48 int pos = self->ids;
33 49
34 self->ids++; 50 self->ids++;
35 if (self->ids > self->size) { 51 if (self->ids > self->size) {
36 self->size *= 2; 52 int nsize = self->size * 2;
37 self->id = realloc(self->id, self->size * sizeof(u64)); 53 u64 *nid = realloc(self->id, nsize * sizeof(u64));
38 if (!self->id) 54
39 die("nomem"); 55 if (nid == NULL)
56 return -1;
57
58 self->size = nsize;
59 self->id = nid;
40 } 60 }
41 self->id[pos] = id; 61 self->id[pos] = id;
62 return 0;
42} 63}
43 64
44/* 65int perf_header__init(struct perf_header *self)
45 * Create new perf.data header:
46 */
47struct perf_header *perf_header__new(void)
48{ 66{
49 struct perf_header *self = malloc(sizeof(*self));
50
51 if (!self)
52 die("nomem");
53
54 self->frozen = 0;
55
56 self->attrs = 0;
57 self->size = 1; 67 self->size = 1;
58 self->attr = malloc(sizeof(void *)); 68 self->attr = malloc(sizeof(void *));
59 69 return self->attr == NULL ? -ENOMEM : 0;
60 if (!self->attr)
61 die("nomem");
62
63 self->data_offset = 0;
64 self->data_size = 0;
65
66 return self;
67} 70}
68 71
69void perf_header__add_attr(struct perf_header *self, 72void perf_header__exit(struct perf_header *self)
70 struct perf_header_attr *attr)
71{ 73{
72 int pos = self->attrs; 74 int i;
75 for (i = 0; i < self->attrs; ++i)
76 perf_header_attr__delete(self->attr[i]);
77 free(self->attr);
78}
73 79
80int perf_header__add_attr(struct perf_header *self,
81 struct perf_header_attr *attr)
82{
74 if (self->frozen) 83 if (self->frozen)
75 die("frozen"); 84 return -1;
76 85
77 self->attrs++; 86 if (self->attrs == self->size) {
78 if (self->attrs > self->size) { 87 int nsize = self->size * 2;
79 self->size *= 2; 88 struct perf_header_attr **nattr;
80 self->attr = realloc(self->attr, self->size * sizeof(void *)); 89
81 if (!self->attr) 90 nattr = realloc(self->attr, nsize * sizeof(void *));
82 die("nomem"); 91 if (nattr == NULL)
92 return -1;
93
94 self->size = nsize;
95 self->attr = nattr;
83 } 96 }
84 self->attr[pos] = attr; 97
98 self->attr[self->attrs++] = attr;
99 return 0;
85} 100}
86 101
87#define MAX_EVENT_NAME 64 102#define MAX_EVENT_NAME 64
@@ -94,24 +109,28 @@ struct perf_trace_event_type {
94static int event_count; 109static int event_count;
95static struct perf_trace_event_type *events; 110static struct perf_trace_event_type *events;
96 111
97void perf_header__push_event(u64 id, const char *name) 112int perf_header__push_event(u64 id, const char *name)
98{ 113{
99 if (strlen(name) > MAX_EVENT_NAME) 114 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name); 115 pr_warning("Event %s will be truncated\n", name);
101 116
102 if (!events) { 117 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type)); 118 events = malloc(sizeof(struct perf_trace_event_type));
104 if (!events) 119 if (events == NULL)
105 die("nomem"); 120 return -ENOMEM;
106 } else { 121 } else {
107 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 122 struct perf_trace_event_type *nevents;
108 if (!events) 123
109 die("nomem"); 124 nevents = realloc(events, (event_count + 1) * sizeof(*events));
125 if (nevents == NULL)
126 return -ENOMEM;
127 events = nevents;
110 } 128 }
111 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 129 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
112 events[event_count].event_id = id; 130 events[event_count].event_id = id;
113 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 131 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
114 event_count++; 132 event_count++;
133 return 0;
115} 134}
116 135
117char *perf_header__find_event(u64 id) 136char *perf_header__find_event(u64 id)
@@ -128,44 +147,292 @@ static const char *__perf_magic = "PERFFILE";
128 147
129#define PERF_MAGIC (*(u64 *)__perf_magic) 148#define PERF_MAGIC (*(u64 *)__perf_magic)
130 149
131struct perf_file_section {
132 u64 offset;
133 u64 size;
134};
135
136struct perf_file_attr { 150struct perf_file_attr {
137 struct perf_event_attr attr; 151 struct perf_event_attr attr;
138 struct perf_file_section ids; 152 struct perf_file_section ids;
139}; 153};
140 154
141struct perf_file_header { 155void perf_header__set_feat(struct perf_header *self, int feat)
142 u64 magic; 156{
143 u64 size; 157 set_bit(feat, self->adds_features);
144 u64 attr_size; 158}
145 struct perf_file_section attrs;
146 struct perf_file_section data;
147 struct perf_file_section event_types;
148};
149 159
150static void do_write(int fd, void *buf, size_t size) 160bool perf_header__has_feat(const struct perf_header *self, int feat)
161{
162 return test_bit(feat, self->adds_features);
163}
164
165static int do_write(int fd, const void *buf, size_t size)
151{ 166{
152 while (size) { 167 while (size) {
153 int ret = write(fd, buf, size); 168 int ret = write(fd, buf, size);
154 169
155 if (ret < 0) 170 if (ret < 0)
156 die("failed to write"); 171 return -errno;
157 172
158 size -= ret; 173 size -= ret;
159 buf += ret; 174 buf += ret;
160 } 175 }
176
177 return 0;
178}
179
180#define NAME_ALIGN 64
181
182static int write_padded(int fd, const void *bf, size_t count,
183 size_t count_aligned)
184{
185 static const char zero_buf[NAME_ALIGN];
186 int err = do_write(fd, bf, count);
187
188 if (!err)
189 err = do_write(fd, zero_buf, count_aligned - count);
190
191 return err;
192}
193
194#define dsos__for_each_with_build_id(pos, head) \
195 list_for_each_entry(pos, head, node) \
196 if (!pos->has_build_id) \
197 continue; \
198 else
199
200static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
201{
202 struct dso *pos;
203
204 dsos__for_each_with_build_id(pos, head) {
205 int err;
206 struct build_id_event b;
207 size_t len;
208
209 if (!pos->hit)
210 continue;
211 len = pos->long_name_len + 1;
212 len = ALIGN(len, NAME_ALIGN);
213 memset(&b, 0, sizeof(b));
214 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
215 b.header.misc = misc;
216 b.header.size = sizeof(b) + len;
217 err = do_write(fd, &b, sizeof(b));
218 if (err < 0)
219 return err;
220 err = write_padded(fd, pos->long_name,
221 pos->long_name_len + 1, len);
222 if (err < 0)
223 return err;
224 }
225
226 return 0;
227}
228
229static int dsos__write_buildid_table(int fd)
230{
231 int err = __dsos__write_buildid_table(&dsos__kernel,
232 PERF_RECORD_MISC_KERNEL, fd);
233 if (err == 0)
234 err = __dsos__write_buildid_table(&dsos__user,
235 PERF_RECORD_MISC_USER, fd);
236 return err;
237}
238
239int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
240 const char *name, bool is_kallsyms)
241{
242 const size_t size = PATH_MAX;
243 char *filename = malloc(size),
244 *linkname = malloc(size), *targetname;
245 int len, err = -1;
246
247 if (filename == NULL || linkname == NULL)
248 goto out_free;
249
250 len = snprintf(filename, size, "%s%s%s",
251 debugdir, is_kallsyms ? "/" : "", name);
252 if (mkdir_p(filename, 0755))
253 goto out_free;
254
255 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
256
257 if (access(filename, F_OK)) {
258 if (is_kallsyms) {
259 if (copyfile("/proc/kallsyms", filename))
260 goto out_free;
261 } else if (link(name, filename) && copyfile(name, filename))
262 goto out_free;
263 }
264
265 len = snprintf(linkname, size, "%s/.build-id/%.2s",
266 debugdir, sbuild_id);
267
268 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
269 goto out_free;
270
271 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
272 targetname = filename + strlen(debugdir) - 5;
273 memcpy(targetname, "../..", 5);
274
275 if (symlink(targetname, linkname) == 0)
276 err = 0;
277out_free:
278 free(filename);
279 free(linkname);
280 return err;
281}
282
283static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
284 const char *name, const char *debugdir,
285 bool is_kallsyms)
286{
287 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
288
289 build_id__sprintf(build_id, build_id_size, sbuild_id);
290
291 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
292}
293
294int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
295{
296 const size_t size = PATH_MAX;
297 char *filename = malloc(size),
298 *linkname = malloc(size);
299 int err = -1;
300
301 if (filename == NULL || linkname == NULL)
302 goto out_free;
303
304 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
305 debugdir, sbuild_id, sbuild_id + 2);
306
307 if (access(linkname, F_OK))
308 goto out_free;
309
310 if (readlink(linkname, filename, size) < 0)
311 goto out_free;
312
313 if (unlink(linkname))
314 goto out_free;
315
316 /*
317 * Since the link is relative, we must make it absolute:
318 */
319 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
320 debugdir, sbuild_id, filename);
321
322 if (unlink(linkname))
323 goto out_free;
324
325 err = 0;
326out_free:
327 free(filename);
328 free(linkname);
329 return err;
330}
331
332static int dso__cache_build_id(struct dso *self, const char *debugdir)
333{
334 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
335
336 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
337 self->long_name, debugdir, is_kallsyms);
338}
339
340static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
341{
342 struct dso *pos;
343 int err = 0;
344
345 dsos__for_each_with_build_id(pos, head)
346 if (dso__cache_build_id(pos, debugdir))
347 err = -1;
348
349 return err;
350}
351
352static int dsos__cache_build_ids(void)
353{
354 int err_kernel, err_user;
355 char debugdir[PATH_MAX];
356
357 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
358 DEBUG_CACHE_DIR);
359
360 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
361 return -1;
362
363 err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
364 err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
365 return err_kernel || err_user ? -1 : 0;
366}
367
368static int perf_header__adds_write(struct perf_header *self, int fd)
369{
370 int nr_sections;
371 struct perf_file_section *feat_sec;
372 int sec_size;
373 u64 sec_start;
374 int idx = 0, err;
375
376 if (dsos__read_build_ids(true))
377 perf_header__set_feat(self, HEADER_BUILD_ID);
378
379 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
380 if (!nr_sections)
381 return 0;
382
383 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
384 if (feat_sec == NULL)
385 return -ENOMEM;
386
387 sec_size = sizeof(*feat_sec) * nr_sections;
388
389 sec_start = self->data_offset + self->data_size;
390 lseek(fd, sec_start + sec_size, SEEK_SET);
391
392 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
393 struct perf_file_section *trace_sec;
394
395 trace_sec = &feat_sec[idx++];
396
397 /* Write trace info */
398 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
399 read_tracing_data(fd, attrs, nr_counters);
400 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
401 }
402
403
404 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
405 struct perf_file_section *buildid_sec;
406
407 buildid_sec = &feat_sec[idx++];
408
409 /* Write build-ids */
410 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
411 err = dsos__write_buildid_table(fd);
412 if (err < 0) {
413 pr_debug("failed to write buildid table\n");
414 goto out_free;
415 }
416 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
417 buildid_sec->offset;
418 dsos__cache_build_ids();
419 }
420
421 lseek(fd, sec_start, SEEK_SET);
422 err = do_write(fd, feat_sec, sec_size);
423 if (err < 0)
424 pr_debug("failed to write feature section\n");
425out_free:
426 free(feat_sec);
427 return err;
161} 428}
162 429
163void perf_header__write(struct perf_header *self, int fd) 430int perf_header__write(struct perf_header *self, int fd, bool at_exit)
164{ 431{
165 struct perf_file_header f_header; 432 struct perf_file_header f_header;
166 struct perf_file_attr f_attr; 433 struct perf_file_attr f_attr;
167 struct perf_header_attr *attr; 434 struct perf_header_attr *attr;
168 int i; 435 int i, err;
169 436
170 lseek(fd, sizeof(f_header), SEEK_SET); 437 lseek(fd, sizeof(f_header), SEEK_SET);
171 438
@@ -174,7 +441,11 @@ void perf_header__write(struct perf_header *self, int fd)
174 attr = self->attr[i]; 441 attr = self->attr[i];
175 442
176 attr->id_offset = lseek(fd, 0, SEEK_CUR); 443 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177 do_write(fd, attr->id, attr->ids * sizeof(u64)); 444 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
445 if (err < 0) {
446 pr_debug("failed to write perf header\n");
447 return err;
448 }
178 } 449 }
179 450
180 451
@@ -190,17 +461,31 @@ void perf_header__write(struct perf_header *self, int fd)
190 .size = attr->ids * sizeof(u64), 461 .size = attr->ids * sizeof(u64),
191 } 462 }
192 }; 463 };
193 do_write(fd, &f_attr, sizeof(f_attr)); 464 err = do_write(fd, &f_attr, sizeof(f_attr));
465 if (err < 0) {
466 pr_debug("failed to write perf header attribute\n");
467 return err;
468 }
194 } 469 }
195 470
196 self->event_offset = lseek(fd, 0, SEEK_CUR); 471 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type); 472 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events) 473 if (events) {
199 do_write(fd, events, self->event_size); 474 err = do_write(fd, events, self->event_size);
200 475 if (err < 0) {
476 pr_debug("failed to write perf header events\n");
477 return err;
478 }
479 }
201 480
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 481 self->data_offset = lseek(fd, 0, SEEK_CUR);
203 482
483 if (at_exit) {
484 err = perf_header__adds_write(self, fd);
485 if (err < 0)
486 return err;
487 }
488
204 f_header = (struct perf_file_header){ 489 f_header = (struct perf_file_header){
205 .magic = PERF_MAGIC, 490 .magic = PERF_MAGIC,
206 .size = sizeof(f_header), 491 .size = sizeof(f_header),
@@ -219,44 +504,175 @@ void perf_header__write(struct perf_header *self, int fd)
219 }, 504 },
220 }; 505 };
221 506
507 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
508
222 lseek(fd, 0, SEEK_SET); 509 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header)); 510 err = do_write(fd, &f_header, sizeof(f_header));
511 if (err < 0) {
512 pr_debug("failed to write perf header\n");
513 return err;
514 }
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 515 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225 516
226 self->frozen = 1; 517 self->frozen = 1;
518 return 0;
227} 519}
228 520
229static void do_read(int fd, void *buf, size_t size) 521static int do_read(int fd, void *buf, size_t size)
230{ 522{
231 while (size) { 523 while (size) {
232 int ret = read(fd, buf, size); 524 int ret = read(fd, buf, size);
233 525
234 if (ret < 0) 526 if (ret <= 0)
235 die("failed to read"); 527 return -1;
236 if (ret == 0)
237 die("failed to read: missing data");
238 528
239 size -= ret; 529 size -= ret;
240 buf += ret; 530 buf += ret;
241 } 531 }
532
533 return 0;
242} 534}
243 535
244struct perf_header *perf_header__read(int fd) 536static int perf_header__getbuffer64(struct perf_header *self,
537 int fd, void *buf, size_t size)
245{ 538{
246 struct perf_header *self = perf_header__new(); 539 if (do_read(fd, buf, size))
247 struct perf_file_header f_header; 540 return -1;
248 struct perf_file_attr f_attr;
249 u64 f_id;
250 541
251 int nr_attrs, nr_ids, i, j; 542 if (self->needs_swap)
543 mem_bswap_64(buf, size);
544
545 return 0;
546}
547
548int perf_header__process_sections(struct perf_header *self, int fd,
549 int (*process)(struct perf_file_section *self,
550 struct perf_header *ph,
551 int feat, int fd))
552{
553 struct perf_file_section *feat_sec;
554 int nr_sections;
555 int sec_size;
556 int idx = 0;
557 int err = -1, feat = 1;
558
559 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
560 if (!nr_sections)
561 return 0;
562
563 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
564 if (!feat_sec)
565 return -1;
566
567 sec_size = sizeof(*feat_sec) * nr_sections;
568
569 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
570
571 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
572 goto out_free;
573
574 err = 0;
575 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
576 if (perf_header__has_feat(self, feat)) {
577 struct perf_file_section *sec = &feat_sec[idx++];
578
579 err = process(sec, self, feat, fd);
580 if (err < 0)
581 break;
582 }
583 ++feat;
584 }
585out_free:
586 free(feat_sec);
587 return err;
588}
252 589
590int perf_file_header__read(struct perf_file_header *self,
591 struct perf_header *ph, int fd)
592{
253 lseek(fd, 0, SEEK_SET); 593 lseek(fd, 0, SEEK_SET);
254 do_read(fd, &f_header, sizeof(f_header));
255 594
256 if (f_header.magic != PERF_MAGIC || 595 if (do_read(fd, self, sizeof(*self)) ||
257 f_header.size != sizeof(f_header) || 596 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
258 f_header.attr_size != sizeof(f_attr)) 597 return -1;
259 die("incompatible file format"); 598
599 if (self->attr_size != sizeof(struct perf_file_attr)) {
600 u64 attr_size = bswap_64(self->attr_size);
601
602 if (attr_size != sizeof(struct perf_file_attr))
603 return -1;
604
605 mem_bswap_64(self, offsetof(struct perf_file_header,
606 adds_features));
607 ph->needs_swap = true;
608 }
609
610 if (self->size != sizeof(*self)) {
611 /* Support the previous format */
612 if (self->size == offsetof(typeof(*self), adds_features))
613 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
614 else
615 return -1;
616 }
617
618 memcpy(&ph->adds_features, &self->adds_features,
619 sizeof(ph->adds_features));
620 /*
621 * FIXME: hack that assumes that if we need swap the perf.data file
622 * may be coming from an arch with a different word-size, ergo different
623 * DEFINE_BITMAP format, investigate more later, but for now its mostly
624 * safe to assume that we have a build-id section. Trace files probably
625 * have several other issues in this realm anyway...
626 */
627 if (ph->needs_swap) {
628 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
629 perf_header__set_feat(ph, HEADER_BUILD_ID);
630 }
631
632 ph->event_offset = self->event_types.offset;
633 ph->event_size = self->event_types.size;
634 ph->data_offset = self->data.offset;
635 ph->data_size = self->data.size;
636 return 0;
637}
638
639static int perf_file_section__process(struct perf_file_section *self,
640 struct perf_header *ph,
641 int feat, int fd)
642{
643 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
644 pr_debug("Failed to lseek to %Ld offset for feature %d, "
645 "continuing...\n", self->offset, feat);
646 return 0;
647 }
648
649 switch (feat) {
650 case HEADER_TRACE_INFO:
651 trace_report(fd);
652 break;
653
654 case HEADER_BUILD_ID:
655 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
656 pr_debug("Failed to read buildids, continuing...\n");
657 break;
658 default:
659 pr_debug("unknown feature %d, continuing...\n", feat);
660 }
661
662 return 0;
663}
664
665int perf_header__read(struct perf_header *self, int fd)
666{
667 struct perf_file_header f_header;
668 struct perf_file_attr f_attr;
669 u64 f_id;
670 int nr_attrs, nr_ids, i, j;
671
672 if (perf_file_header__read(&f_header, self, fd) < 0) {
673 pr_debug("incompatible file format\n");
674 return -EINVAL;
675 }
260 676
261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 677 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET); 678 lseek(fd, f_header.attrs.offset, SEEK_SET);
@@ -265,42 +681,54 @@ struct perf_header *perf_header__read(int fd)
265 struct perf_header_attr *attr; 681 struct perf_header_attr *attr;
266 off_t tmp; 682 off_t tmp;
267 683
268 do_read(fd, &f_attr, sizeof(f_attr)); 684 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
685 goto out_errno;
686
269 tmp = lseek(fd, 0, SEEK_CUR); 687 tmp = lseek(fd, 0, SEEK_CUR);
270 688
271 attr = perf_header_attr__new(&f_attr.attr); 689 attr = perf_header_attr__new(&f_attr.attr);
690 if (attr == NULL)
691 return -ENOMEM;
272 692
273 nr_ids = f_attr.ids.size / sizeof(u64); 693 nr_ids = f_attr.ids.size / sizeof(u64);
274 lseek(fd, f_attr.ids.offset, SEEK_SET); 694 lseek(fd, f_attr.ids.offset, SEEK_SET);
275 695
276 for (j = 0; j < nr_ids; j++) { 696 for (j = 0; j < nr_ids; j++) {
277 do_read(fd, &f_id, sizeof(f_id)); 697 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
698 goto out_errno;
278 699
279 perf_header_attr__add_id(attr, f_id); 700 if (perf_header_attr__add_id(attr, f_id) < 0) {
701 perf_header_attr__delete(attr);
702 return -ENOMEM;
703 }
704 }
705 if (perf_header__add_attr(self, attr) < 0) {
706 perf_header_attr__delete(attr);
707 return -ENOMEM;
280 } 708 }
281 perf_header__add_attr(self, attr); 709
282 lseek(fd, tmp, SEEK_SET); 710 lseek(fd, tmp, SEEK_SET);
283 } 711 }
284 712
285 if (f_header.event_types.size) { 713 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET); 714 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size); 715 events = malloc(f_header.event_types.size);
288 if (!events) 716 if (events == NULL)
289 die("nomem"); 717 return -ENOMEM;
290 do_read(fd, events, f_header.event_types.size); 718 if (perf_header__getbuffer64(self, fd, events,
719 f_header.event_types.size))
720 goto out_errno;
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 721 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 } 722 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295 723
296 self->data_offset = f_header.data.offset; 724 perf_header__process_sections(self, fd, perf_file_section__process);
297 self->data_size = f_header.data.size;
298 725
299 lseek(fd, self->data_offset, SEEK_SET); 726 lseek(fd, self->data_offset, SEEK_SET);
300 727
301 self->frozen = 1; 728 self->frozen = 1;
302 729 return 0;
303 return self; 730out_errno:
731 return -errno;
304} 732}
305 733
306u64 perf_header__sample_type(struct perf_header *header) 734u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..82a6af72d4cc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,9 +1,13 @@
1#ifndef _PERF_HEADER_H 1#ifndef __PERF_HEADER_H
2#define _PERF_HEADER_H 2#define __PERF_HEADER_H
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
8#include "event.h"
9
10#include <linux/bitmap.h>
7 11
8struct perf_header_attr { 12struct perf_header_attr {
9 struct perf_event_attr attr; 13 struct perf_event_attr attr;
@@ -12,36 +16,77 @@ struct perf_header_attr {
12 off_t id_offset; 16 off_t id_offset;
13}; 17};
14 18
19enum {
20 HEADER_TRACE_INFO = 1,
21 HEADER_BUILD_ID,
22 HEADER_LAST_FEATURE,
23};
24
25#define HEADER_FEAT_BITS 256
26
27struct perf_file_section {
28 u64 offset;
29 u64 size;
30};
31
32struct perf_file_header {
33 u64 magic;
34 u64 size;
35 u64 attr_size;
36 struct perf_file_section attrs;
37 struct perf_file_section data;
38 struct perf_file_section event_types;
39 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
40};
41
42struct perf_header;
43
44int perf_file_header__read(struct perf_file_header *self,
45 struct perf_header *ph, int fd);
46
15struct perf_header { 47struct perf_header {
16 int frozen; 48 int frozen;
17 int attrs, size; 49 int attrs, size;
18 struct perf_header_attr **attr; 50 struct perf_header_attr **attr;
19 s64 attr_offset; 51 s64 attr_offset;
20 u64 data_offset; 52 u64 data_offset;
21 u64 data_size; 53 u64 data_size;
22 u64 event_offset; 54 u64 event_offset;
23 u64 event_size; 55 u64 event_size;
56 bool needs_swap;
57 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
24}; 58};
25 59
26struct perf_header *perf_header__read(int fd); 60int perf_header__init(struct perf_header *self);
27void perf_header__write(struct perf_header *self, int fd); 61void perf_header__exit(struct perf_header *self);
62
63int perf_header__read(struct perf_header *self, int fd);
64int perf_header__write(struct perf_header *self, int fd, bool at_exit);
28 65
29void perf_header__add_attr(struct perf_header *self, 66int perf_header__add_attr(struct perf_header *self,
30 struct perf_header_attr *attr); 67 struct perf_header_attr *attr);
31 68
32void perf_header__push_event(u64 id, const char *name); 69int perf_header__push_event(u64 id, const char *name);
33char *perf_header__find_event(u64 id); 70char *perf_header__find_event(u64 id);
34 71
72struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
73void perf_header_attr__delete(struct perf_header_attr *self);
35 74
36struct perf_header_attr * 75int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
37perf_header_attr__new(struct perf_event_attr *attr);
38void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
39 76
40u64 perf_header__sample_type(struct perf_header *header); 77u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr * 78struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header); 79perf_header__find_attr(u64 id, struct perf_header *header);
80void perf_header__set_feat(struct perf_header *self, int feat);
81bool perf_header__has_feat(const struct perf_header *self, int feat);
43 82
83int perf_header__process_sections(struct perf_header *self, int fd,
84 int (*process)(struct perf_file_section *self,
85 struct perf_header *ph,
86 int feat, int fd));
44 87
45struct perf_header *perf_header__new(void); 88int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
89 const char *name, bool is_kallsyms);
90int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
46 91
47#endif /* _PERF_HEADER_H */ 92#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 7128783637b4..7f5c6dedd714 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -1,5 +1,5 @@
1#ifndef HELP_H 1#ifndef __PERF_HELP_H
2#define HELP_H 2#define __PERF_HELP_H
3 3
4struct cmdnames { 4struct cmdnames {
5 size_t alloc; 5 size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds, 26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds); 27 struct cmdnames *other_cmds);
28 28
29#endif /* HELP_H */ 29#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644
index 000000000000..2be33c7dbf03
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,668 @@
1#include "hist.h"
2#include "session.h"
3#include "sort.h"
4#include <math.h>
5
6struct callchain_param callchain_param = {
7 .mode = CHAIN_GRAPH_REL,
8 .min_percent = 0.5
9};
10
11/*
12 * histogram, sorted on item, collects counts
13 */
14
15struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
16 struct addr_location *al,
17 struct symbol *sym_parent,
18 u64 count, bool *hit)
19{
20 struct rb_node **p = &hists->rb_node;
21 struct rb_node *parent = NULL;
22 struct hist_entry *he;
23 struct hist_entry entry = {
24 .thread = al->thread,
25 .map = al->map,
26 .sym = al->sym,
27 .ip = al->addr,
28 .level = al->level,
29 .count = count,
30 .parent = sym_parent,
31 };
32 int cmp;
33
34 while (*p != NULL) {
35 parent = *p;
36 he = rb_entry(parent, struct hist_entry, rb_node);
37
38 cmp = hist_entry__cmp(&entry, he);
39
40 if (!cmp) {
41 *hit = true;
42 return he;
43 }
44
45 if (cmp < 0)
46 p = &(*p)->rb_left;
47 else
48 p = &(*p)->rb_right;
49 }
50
51 he = malloc(sizeof(*he));
52 if (!he)
53 return NULL;
54 *he = entry;
55 rb_link_node(&he->rb_node, parent, p);
56 rb_insert_color(&he->rb_node, hists);
57 *hit = false;
58 return he;
59}
60
61int64_t
62hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
63{
64 struct sort_entry *se;
65 int64_t cmp = 0;
66
67 list_for_each_entry(se, &hist_entry__sort_list, list) {
68 cmp = se->cmp(left, right);
69 if (cmp)
70 break;
71 }
72
73 return cmp;
74}
75
76int64_t
77hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
78{
79 struct sort_entry *se;
80 int64_t cmp = 0;
81
82 list_for_each_entry(se, &hist_entry__sort_list, list) {
83 int64_t (*f)(struct hist_entry *, struct hist_entry *);
84
85 f = se->collapse ?: se->cmp;
86
87 cmp = f(left, right);
88 if (cmp)
89 break;
90 }
91
92 return cmp;
93}
94
95void hist_entry__free(struct hist_entry *he)
96{
97 free(he);
98}
99
100/*
101 * collapse the histogram
102 */
103
104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
105{
106 struct rb_node **p = &root->rb_node;
107 struct rb_node *parent = NULL;
108 struct hist_entry *iter;
109 int64_t cmp;
110
111 while (*p != NULL) {
112 parent = *p;
113 iter = rb_entry(parent, struct hist_entry, rb_node);
114
115 cmp = hist_entry__collapse(iter, he);
116
117 if (!cmp) {
118 iter->count += he->count;
119 hist_entry__free(he);
120 return;
121 }
122
123 if (cmp < 0)
124 p = &(*p)->rb_left;
125 else
126 p = &(*p)->rb_right;
127 }
128
129 rb_link_node(&he->rb_node, parent, p);
130 rb_insert_color(&he->rb_node, root);
131}
132
133void perf_session__collapse_resort(struct rb_root *hists)
134{
135 struct rb_root tmp;
136 struct rb_node *next;
137 struct hist_entry *n;
138
139 if (!sort__need_collapse)
140 return;
141
142 tmp = RB_ROOT;
143 next = rb_first(hists);
144
145 while (next) {
146 n = rb_entry(next, struct hist_entry, rb_node);
147 next = rb_next(&n->rb_node);
148
149 rb_erase(&n->rb_node, hists);
150 collapse__insert_entry(&tmp, n);
151 }
152
153 *hists = tmp;
154}
155
156/*
157 * reverse the map, sort on count.
158 */
159
160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
163{
164 struct rb_node **p = &root->rb_node;
165 struct rb_node *parent = NULL;
166 struct hist_entry *iter;
167
168 if (symbol_conf.use_callchain)
169 callchain_param.sort(&he->sorted_chain, &he->callchain,
170 min_callchain_hits, &callchain_param);
171
172 while (*p != NULL) {
173 parent = *p;
174 iter = rb_entry(parent, struct hist_entry, rb_node);
175
176 if (he->count > iter->count)
177 p = &(*p)->rb_left;
178 else
179 p = &(*p)->rb_right;
180 }
181
182 rb_link_node(&he->rb_node, parent, p);
183 rb_insert_color(&he->rb_node, root);
184}
185
186void perf_session__output_resort(struct rb_root *hists, u64 total_samples)
187{
188 struct rb_root tmp;
189 struct rb_node *next;
190 struct hist_entry *n;
191 u64 min_callchain_hits;
192
193 min_callchain_hits =
194 total_samples * (callchain_param.min_percent / 100);
195
196 tmp = RB_ROOT;
197 next = rb_first(hists);
198
199 while (next) {
200 n = rb_entry(next, struct hist_entry, rb_node);
201 next = rb_next(&n->rb_node);
202
203 rb_erase(&n->rb_node, hists);
204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
206 }
207
208 *hists = tmp;
209}
210
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
212{
213 int i;
214 int ret = fprintf(fp, " ");
215
216 for (i = 0; i < left_margin; i++)
217 ret += fprintf(fp, " ");
218
219 return ret;
220}
221
222static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
223 int left_margin)
224{
225 int i;
226 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
227
228 for (i = 0; i < depth; i++)
229 if (depth_mask & (1 << i))
230 ret += fprintf(fp, "| ");
231 else
232 ret += fprintf(fp, " ");
233
234 ret += fprintf(fp, "\n");
235
236 return ret;
237}
238
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count,
241 u64 total_samples, int hits,
242 int left_margin)
243{
244 int i;
245 size_t ret = 0;
246
247 ret += callchain__fprintf_left_margin(fp, left_margin);
248 for (i = 0; i < depth; i++) {
249 if (depth_mask & (1 << i))
250 ret += fprintf(fp, "|");
251 else
252 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) {
254 double percent;
255
256 percent = hits * 100.0 / total_samples;
257 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
258 } else
259 ret += fprintf(fp, "%s", " ");
260 }
261 if (chain->sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name);
263 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265
266 return ret;
267}
268
269static struct symbol *rem_sq_bracket;
270static struct callchain_list rem_hits;
271
272static void init_rem_hits(void)
273{
274 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
275 if (!rem_sq_bracket) {
276 fprintf(stderr, "Not enough memory to display remaining hits\n");
277 return;
278 }
279
280 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket;
282}
283
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
285 u64 total_samples, int depth,
286 int depth_mask, int left_margin)
287{
288 struct rb_node *node, *next;
289 struct callchain_node *child;
290 struct callchain_list *chain;
291 int new_depth_mask = depth_mask;
292 u64 new_total;
293 u64 remaining;
294 size_t ret = 0;
295 int i;
296
297 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit;
299 else
300 new_total = total_samples;
301
302 remaining = new_total;
303
304 node = rb_first(&self->rb_root);
305 while (node) {
306 u64 cumul;
307
308 child = rb_entry(node, struct callchain_node, rb_node);
309 cumul = cumul_hits(child);
310 remaining -= cumul;
311
312 /*
313 * The depth mask manages the output of pipes that show
314 * the depth. We don't want to keep the pipes of the current
315 * level for the last child of this depth.
316 * Except if we have remaining filtered hits. They will
317 * supersede the last child
318 */
319 next = rb_next(node);
320 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
321 new_depth_mask &= ~(1 << (depth - 1));
322
323 /*
324 * But we keep the older depth mask for the line separator
325 * to keep the level link until we reach the last child
326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin);
329 i = 0;
330 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++,
335 new_total,
336 cumul,
337 left_margin);
338 }
339 ret += __callchain__fprintf_graph(fp, child, new_total,
340 depth + 1,
341 new_depth_mask | (1 << depth),
342 left_margin);
343 node = next;
344 }
345
346 if (callchain_param.mode == CHAIN_GRAPH_REL &&
347 remaining && remaining != new_total) {
348
349 if (!rem_sq_bracket)
350 return ret;
351
352 new_depth_mask &= ~(1 << (depth - 1));
353
354 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
355 new_depth_mask, 0, new_total,
356 remaining, left_margin);
357 }
358
359 return ret;
360}
361
362static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
363 u64 total_samples, int left_margin)
364{
365 struct callchain_list *chain;
366 bool printed = false;
367 int i = 0;
368 int ret = 0;
369
370 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue;
376
377 if (!printed) {
378 ret += callchain__fprintf_left_margin(fp, left_margin);
379 ret += fprintf(fp, "|\n");
380 ret += callchain__fprintf_left_margin(fp, left_margin);
381 ret += fprintf(fp, "---");
382
383 left_margin += 3;
384 printed = true;
385 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin);
387
388 if (chain->sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name);
390 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
392 }
393
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
395
396 return ret;
397}
398
399static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
400 u64 total_samples)
401{
402 struct callchain_list *chain;
403 size_t ret = 0;
404
405 if (!self)
406 return 0;
407
408 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
409
410
411 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue;
414 if (chain->sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name);
416 else
417 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip);
419 }
420
421 return ret;
422}
423
424static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
425 u64 total_samples, int left_margin)
426{
427 struct rb_node *rb_node;
428 struct callchain_node *chain;
429 size_t ret = 0;
430
431 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) {
433 double percent;
434
435 chain = rb_entry(rb_node, struct callchain_node, rb_node);
436 percent = chain->hit * 100.0 / total_samples;
437 switch (callchain_param.mode) {
438 case CHAIN_FLAT:
439 ret += percent_color_fprintf(fp, " %6.2f%%\n",
440 percent);
441 ret += callchain__fprintf_flat(fp, chain, total_samples);
442 break;
443 case CHAIN_GRAPH_ABS: /* Falldown */
444 case CHAIN_GRAPH_REL:
445 ret += callchain__fprintf_graph(fp, chain, total_samples,
446 left_margin);
447 case CHAIN_NONE:
448 default:
449 break;
450 }
451 ret += fprintf(fp, "\n");
452 rb_node = rb_next(rb_node);
453 }
454
455 return ret;
456}
457
458static size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *pair_session,
460 bool show_displacement,
461 long displacement, FILE *fp,
462 u64 session_total)
463{
464 struct sort_entry *se;
465 u64 count, total;
466 const char *sep = symbol_conf.field_sep;
467 size_t ret;
468
469 if (symbol_conf.exclude_other && !self->parent)
470 return 0;
471
472 if (pair_session) {
473 count = self->pair ? self->pair->count : 0;
474 total = pair_session->events_stats.total;
475 } else {
476 count = self->count;
477 total = session_total;
478 }
479
480 if (total)
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%",
482 (count * 100.0) / total);
483 else
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count);
485
486 if (symbol_conf.show_nr_samples) {
487 if (sep)
488 fprintf(fp, "%c%lld", *sep, count);
489 else
490 fprintf(fp, "%11lld", count);
491 }
492
493 if (pair_session) {
494 char bf[32];
495 double old_percent = 0, new_percent = 0, diff;
496
497 if (total > 0)
498 old_percent = (count * 100.0) / total;
499 if (session_total > 0)
500 new_percent = (self->count * 100.0) / session_total;
501
502 diff = new_percent - old_percent;
503
504 if (fabs(diff) >= 0.01)
505 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
506 else
507 snprintf(bf, sizeof(bf), " ");
508
509 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf);
511 else
512 ret += fprintf(fp, "%11.11s", bf);
513
514 if (show_displacement) {
515 if (displacement)
516 snprintf(bf, sizeof(bf), "%+4ld", displacement);
517 else
518 snprintf(bf, sizeof(bf), " ");
519
520 if (sep)
521 fprintf(fp, "%c%s", *sep, bf);
522 else
523 fprintf(fp, "%6.6s", bf);
524 }
525 }
526
527 list_for_each_entry(se, &hist_entry__sort_list, list) {
528 if (se->elide)
529 continue;
530
531 fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0);
533 }
534
535 ret += fprintf(fp, "\n");
536
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539
540 if (sort__first_dimension == SORT_COMM) {
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
542 list);
543 left_margin = se->width ? *se->width : 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546
547 hist_entry_callchain__fprintf(fp, self, session_total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct rb_root *hists,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp,
557 u64 session_total)
558{
559 struct sort_entry *se;
560 struct rb_node *nd;
561 size_t ret = 0;
562 unsigned long position = 1;
563 long displacement = 0;
564 unsigned int width;
565 const char *sep = symbol_conf.field_sep;
566 char *col_width = symbol_conf.col_width_list_str;
567
568 init_rem_hits();
569
570 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
571
572 if (symbol_conf.show_nr_samples) {
573 if (sep)
574 fprintf(fp, "%cSamples", *sep);
575 else
576 fputs(" Samples ", fp);
577 }
578
579 if (pair) {
580 if (sep)
581 ret += fprintf(fp, "%cDelta", *sep);
582 else
583 ret += fprintf(fp, " Delta ");
584
585 if (show_displacement) {
586 if (sep)
587 ret += fprintf(fp, "%cDisplacement", *sep);
588 else
589 ret += fprintf(fp, " Displ");
590 }
591 }
592
593 list_for_each_entry(se, &hist_entry__sort_list, list) {
594 if (se->elide)
595 continue;
596 if (sep) {
597 fprintf(fp, "%c%s", *sep, se->header);
598 continue;
599 }
600 width = strlen(se->header);
601 if (se->width) {
602 if (symbol_conf.col_width_list_str) {
603 if (col_width) {
604 *se->width = atoi(col_width);
605 col_width = strchr(col_width, ',');
606 if (col_width)
607 ++col_width;
608 }
609 }
610 width = *se->width = max(*se->width, width);
611 }
612 fprintf(fp, " %*s", width, se->header);
613 }
614 fprintf(fp, "\n");
615
616 if (sep)
617 goto print_entries;
618
619 fprintf(fp, "# ........");
620 if (symbol_conf.show_nr_samples)
621 fprintf(fp, " ..........");
622 if (pair) {
623 fprintf(fp, " ..........");
624 if (show_displacement)
625 fprintf(fp, " .....");
626 }
627 list_for_each_entry(se, &hist_entry__sort_list, list) {
628 unsigned int i;
629
630 if (se->elide)
631 continue;
632
633 fprintf(fp, " ");
634 if (se->width)
635 width = *se->width;
636 else
637 width = strlen(se->header);
638 for (i = 0; i < width; i++)
639 fprintf(fp, ".");
640 }
641
642 fprintf(fp, "\n#\n");
643
644print_entries:
645 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
646 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
647
648 if (show_displacement) {
649 if (h->pair != NULL)
650 displacement = ((long)h->pair->position -
651 (long)position);
652 else
653 displacement = 0;
654 ++position;
655 }
656 ret += hist_entry__fprintf(h, pair, show_displacement,
657 displacement, fp, session_total);
658 if (h->map == NULL && verbose > 1) {
659 __map_groups__fprintf_maps(&h->thread->mg,
660 MAP__FUNCTION, fp);
661 fprintf(fp, "%.10s end\n", graph_dotted_line);
662 }
663 }
664
665 free(rem_sq_bracket);
666
667 return ret;
668}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..16f360cce5bf
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,29 @@
1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H
3
4#include <linux/types.h>
5#include "callchain.h"
6
7extern struct callchain_param callchain_param;
8
9struct perf_session;
10struct hist_entry;
11struct addr_location;
12struct symbol;
13struct rb_root;
14
15struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
16 struct addr_location *al,
17 struct symbol *parent,
18 u64 count, bool *hit);
19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
21void hist_entry__free(struct hist_entry *);
22
23void perf_session__output_resort(struct rb_root *hists, u64 total_samples);
24void perf_session__collapse_resort(struct rb_root *hists);
25size_t perf_session__fprintf_hists(struct rb_root *hists,
26 struct perf_session *pair,
27 bool show_displacement, FILE *fp,
28 u64 session_total);
29#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/asm-offsets.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644
index 000000000000..58e9817ffae0
--- /dev/null
+++ b/tools/perf/util/include/asm/bitops.h
@@ -0,0 +1,18 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h
new file mode 100644
index 000000000000..7fcc6810adc2
--- /dev/null
+++ b/tools/perf/util/include/asm/bug.h
@@ -0,0 +1,22 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H
3
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5
6#define WARN(condition, format...) ({ \
7 int __ret_warn_on = !!(condition); \
8 if (unlikely(__ret_warn_on)) \
9 __WARN_printf(format); \
10 unlikely(__ret_warn_on); \
11})
12
13#define WARN_ONCE(condition, format...) ({ \
14 static int __warned; \
15 int __ret_warn_once = !!(condition); \
16 \
17 if (unlikely(__ret_warn_once)) \
18 if (WARN(!__warned, format)) \
19 __warned = 1; \
20 unlikely(__ret_warn_once); \
21})
22#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644
index 000000000000..b722abe3a626
--- /dev/null
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -0,0 +1,2 @@
1#include <asm/types.h>
2#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/swab.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644
index 000000000000..d0f72b8fcc35
--- /dev/null
+++ b/tools/perf/util/include/asm/uaccess.h
@@ -0,0 +1,14 @@
1#ifndef _PERF_ASM_UACCESS_H_
2#define _PERF_ASM_UACCESS_H_
3
4#define __get_user(src, dest) \
5({ \
6 (src) = *dest; \
7 0; \
8})
9
10#define get_user __get_user
11
12#define access_ok(type, addr, size) 1
13
14#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644
index 000000000000..94507639a8c4
--- /dev/null
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -0,0 +1,3 @@
1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h"
3#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644
index 000000000000..8d63116e9435
--- /dev/null
+++ b/tools/perf/util/include/linux/bitops.h
@@ -0,0 +1,29 @@
1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_
3
4#define __KERNEL__
5
6#define CONFIG_GENERIC_FIND_NEXT_BIT
7#define CONFIG_GENERIC_FIND_FIRST_BIT
8#include "../../../../include/linux/bitops.h"
9
10#undef __KERNEL__
11
12static inline void set_bit(int nr, unsigned long *addr)
13{
14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
15}
16
17static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
18{
19 return ((1UL << (nr % BITS_PER_LONG)) &
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21}
22
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
24 long size, unsigned long offset);
25
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
27 long size, unsigned long offset);
28
29#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644
index 000000000000..dfb0713ed47f
--- /dev/null
+++ b/tools/perf/util/include/linux/compiler.h
@@ -0,0 +1,10 @@
1#ifndef _PERF_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_
3
4#ifndef __always_inline
5#define __always_inline inline
6#endif
7#define __user
8#define __attribute_const__
9
10#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644
index 000000000000..a53d4ee1e0b7
--- /dev/null
+++ b/tools/perf/util/include/linux/ctype.h
@@ -0,0 +1 @@
#include "../util.h"
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
new file mode 100644
index 000000000000..201f57397997
--- /dev/null
+++ b/tools/perf/util/include/linux/hash.h
@@ -0,0 +1,5 @@
1#include "../../../../include/linux/hash.h"
2
3#ifndef PERF_HASH_H
4#define PERF_HASH_H
5#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index a6b87390cb52..f2611655ab51 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -1,6 +1,16 @@
1#ifndef PERF_LINUX_KERNEL_H_ 1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_ 2#define PERF_LINUX_KERNEL_H_
3 3
4#include <stdarg.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
8
9#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
10
11#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
12#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
13
4#ifndef offsetof 14#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 15#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif 16#endif
@@ -26,4 +36,71 @@
26 _max1 > _max2 ? _max1 : _max2; }) 36 _max1 > _max2 ? _max1 : _max2; })
27#endif 37#endif
28 38
39#ifndef min
40#define min(x, y) ({ \
41 typeof(x) _min1 = (x); \
42 typeof(y) _min2 = (y); \
43 (void) (&_min1 == &_min2); \
44 _min1 < _min2 ? _min1 : _min2; })
45#endif
46
47#ifndef BUG_ON
48#define BUG_ON(cond) assert(!(cond))
49#endif
50
51/*
52 * Both need more care to handle endianness
53 * (Don't use bitmap_copy_le() for now)
54 */
55#define cpu_to_le64(x) (x)
56#define cpu_to_le32(x) (x)
57
58static inline int
59vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
60{
61 int i;
62 ssize_t ssize = size;
63
64 i = vsnprintf(buf, size, fmt, args);
65
66 return (i >= ssize) ? (ssize - 1) : i;
67}
68
69static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
70{
71 va_list args;
72 ssize_t ssize = size;
73 int i;
74
75 va_start(args, fmt);
76 i = vsnprintf(buf, size, fmt, args);
77 va_end(args);
78
79 return (i >= ssize) ? (ssize - 1) : i;
80}
81
82static inline unsigned long
83simple_strtoul(const char *nptr, char **endptr, int base)
84{
85 return strtoul(nptr, endptr, base);
86}
87
88#ifndef pr_fmt
89#define pr_fmt(fmt) fmt
90#endif
91
92#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
94#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
96#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
98#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
104#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
105
29#endif 106#endif
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
new file mode 100644
index 000000000000..3b2f5900276f
--- /dev/null
+++ b/tools/perf/util/include/linux/string.h
@@ -0,0 +1 @@
#include <string.h>
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
new file mode 100644
index 000000000000..196862a81a21
--- /dev/null
+++ b/tools/perf/util/include/linux/types.h
@@ -0,0 +1,9 @@
1#ifndef _PERF_LINUX_TYPES_H_
2#define _PERF_LINUX_TYPES_H_
3
4#include <asm/types.h>
5
6#define DECLARE_BITMAP(name,bits) \
7 unsigned long name[BITS_TO_LONGS(bits)]
8
9#endif
diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h
index 0173abeef52c..b0fcb6d8a881 100644
--- a/tools/perf/util/levenshtein.h
+++ b/tools/perf/util/levenshtein.h
@@ -1,8 +1,8 @@
1#ifndef LEVENSHTEIN_H 1#ifndef __PERF_LEVENSHTEIN_H
2#define LEVENSHTEIN_H 2#define __PERF_LEVENSHTEIN_H
3 3
4int levenshtein(const char *string1, const char *string2, 4int levenshtein(const char *string1, const char *string2,
5 int swap_penalty, int substition_penalty, 5 int swap_penalty, int substition_penalty,
6 int insertion_penalty, int deletion_penalty); 6 int insertion_penalty, int deletion_penalty);
7 7
8#endif 8#endif /* __PERF_LEVENSHTEIN_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 804e02382739..e509cd59c67d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -3,6 +3,12 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h"
7
8const char *map_type__name[MAP__NR_TYPES] = {
9 [MAP__FUNCTION] = "Functions",
10 [MAP__VARIABLE] = "Variables",
11};
6 12
7static inline int is_anon_memory(const char *filename) 13static inline int is_anon_memory(const char *filename)
8{ 14{
@@ -19,13 +25,28 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
19 return n; 25 return n;
20} 26}
21 27
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) 28void map__init(struct map *self, enum map_type type,
29 u64 start, u64 end, u64 pgoff, struct dso *dso)
30{
31 self->type = type;
32 self->start = start;
33 self->end = end;
34 self->pgoff = pgoff;
35 self->dso = dso;
36 self->map_ip = map__map_ip;
37 self->unmap_ip = map__unmap_ip;
38 RB_CLEAR_NODE(&self->rb_node);
39}
40
41struct map *map__new(struct mmap_event *event, enum map_type type,
42 char *cwd, int cwdlen)
23{ 43{
24 struct map *self = malloc(sizeof(*self)); 44 struct map *self = malloc(sizeof(*self));
25 45
26 if (self != NULL) { 46 if (self != NULL) {
27 const char *filename = event->filename; 47 const char *filename = event->filename;
28 char newfilename[PATH_MAX]; 48 char newfilename[PATH_MAX];
49 struct dso *dso;
29 int anon; 50 int anon;
30 51
31 if (cwd) { 52 if (cwd) {
@@ -45,18 +66,20 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
45 filename = newfilename; 66 filename = newfilename;
46 } 67 }
47 68
48 self->start = event->start; 69 dso = dsos__findnew(filename);
49 self->end = event->start + event->len; 70 if (dso == NULL)
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete; 71 goto out_delete;
55 72
56 if (self->dso == vdso || anon) 73 map__init(self, type, event->start, event->start + event->len,
57 self->map_ip = vdso__map_ip; 74 event->pgoff, dso);
58 else 75
59 self->map_ip = map__map_ip; 76 if (anon) {
77set_identity:
78 self->map_ip = self->unmap_ip = identity__map_ip;
79 } else if (strcmp(filename, "[vdso]") == 0) {
80 dso__set_loaded(dso, self->type);
81 goto set_identity;
82 }
60 } 83 }
61 return self; 84 return self;
62out_delete: 85out_delete:
@@ -64,6 +87,103 @@ out_delete:
64 return NULL; 87 return NULL;
65} 88}
66 89
90void map__delete(struct map *self)
91{
92 free(self);
93}
94
95void map__fixup_start(struct map *self)
96{
97 struct rb_root *symbols = &self->dso->symbols[self->type];
98 struct rb_node *nd = rb_first(symbols);
99 if (nd != NULL) {
100 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
101 self->start = sym->start;
102 }
103}
104
105void map__fixup_end(struct map *self)
106{
107 struct rb_root *symbols = &self->dso->symbols[self->type];
108 struct rb_node *nd = rb_last(symbols);
109 if (nd != NULL) {
110 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
111 self->end = sym->end;
112 }
113}
114
115#define DSO__DELETED "(deleted)"
116
117int map__load(struct map *self, symbol_filter_t filter)
118{
119 const char *name = self->dso->long_name;
120 int nr;
121
122 if (dso__loaded(self->dso, self->type))
123 return 0;
124
125 nr = dso__load(self->dso, self, filter);
126 if (nr < 0) {
127 if (self->dso->has_build_id) {
128 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
129
130 build_id__sprintf(self->dso->build_id,
131 sizeof(self->dso->build_id),
132 sbuild_id);
133 pr_warning("%s with build id %s not found",
134 name, sbuild_id);
135 } else
136 pr_warning("Failed to open %s", name);
137
138 pr_warning(", continuing without symbols\n");
139 return -1;
140 } else if (nr == 0) {
141 const size_t len = strlen(name);
142 const size_t real_len = len - sizeof(DSO__DELETED);
143
144 if (len > sizeof(DSO__DELETED) &&
145 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
146 pr_warning("%.*s was updated, restart the long "
147 "running apps that use it!\n",
148 (int)real_len, name);
149 } else {
150 pr_warning("no symbols found in %s, maybe install "
151 "a debug package?\n", name);
152 }
153
154 return -1;
155 }
156 /*
157 * Only applies to the kernel, as its symtabs aren't relative like the
158 * module ones.
159 */
160 if (self->dso->kernel)
161 map__reloc_vmlinux(self);
162
163 return 0;
164}
165
166struct symbol *map__find_symbol(struct map *self, u64 addr,
167 symbol_filter_t filter)
168{
169 if (map__load(self, filter) < 0)
170 return NULL;
171
172 return dso__find_symbol(self->dso, self->type, addr);
173}
174
175struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
176 symbol_filter_t filter)
177{
178 if (map__load(self, filter) < 0)
179 return NULL;
180
181 if (!dso__sorted_by_name(self->dso, self->type))
182 dso__sort_by_name(self->dso, self->type);
183
184 return dso__find_symbol_by_name(self->dso, self->type, name);
185}
186
67struct map *map__clone(struct map *self) 187struct map *map__clone(struct map *self)
68{ 188{
69 struct map *map = malloc(sizeof(*self)); 189 struct map *map = malloc(sizeof(*self));
@@ -95,3 +215,23 @@ size_t map__fprintf(struct map *self, FILE *fp)
95 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 215 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
96 self->start, self->end, self->pgoff, self->dso->name); 216 self->start, self->end, self->pgoff, self->dso->name);
97} 217}
218
219/*
220 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
221 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
222 */
223u64 map__rip_2objdump(struct map *map, u64 rip)
224{
225 u64 addr = map->dso->adjust_symbols ?
226 map->unmap_ip(map, rip) : /* RIP -> IP */
227 rip;
228 return addr;
229}
230
231u64 map__objdump_2ip(struct map *map, u64 addr)
232{
233 u64 ip = map->dso->adjust_symbols ?
234 addr :
235 map->unmap_ip(map, addr); /* RIP -> IP */
236 return ip;
237}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 000000000000..b756368076c6
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,94 @@
1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H
3
4#include <linux/compiler.h>
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include <linux/types.h>
8
9enum map_type {
10 MAP__FUNCTION = 0,
11 MAP__VARIABLE,
12};
13
14#define MAP__NR_TYPES (MAP__VARIABLE + 1)
15
16extern const char *map_type__name[MAP__NR_TYPES];
17
18struct dso;
19struct ref_reloc_sym;
20struct map_groups;
21
22struct map {
23 union {
24 struct rb_node rb_node;
25 struct list_head node;
26 };
27 u64 start;
28 u64 end;
29 enum map_type type;
30 u64 pgoff;
31
32 /* ip -> dso rip */
33 u64 (*map_ip)(struct map *, u64);
34 /* dso rip -> ip */
35 u64 (*unmap_ip)(struct map *, u64);
36
37 struct dso *dso;
38};
39
40struct kmap {
41 struct ref_reloc_sym *ref_reloc_sym;
42 struct map_groups *kmaps;
43};
44
45static inline struct kmap *map__kmap(struct map *self)
46{
47 return (struct kmap *)(self + 1);
48}
49
50static inline u64 map__map_ip(struct map *map, u64 ip)
51{
52 return ip - map->start + map->pgoff;
53}
54
55static inline u64 map__unmap_ip(struct map *map, u64 ip)
56{
57 return ip + map->start - map->pgoff;
58}
59
60static inline u64 identity__map_ip(struct map *map __used, u64 ip)
61{
62 return ip;
63}
64
65
66/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
67u64 map__rip_2objdump(struct map *map, u64 rip);
68u64 map__objdump_2ip(struct map *map, u64 addr);
69
70struct symbol;
71struct mmap_event;
72
73typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
74
75void map__init(struct map *self, enum map_type type,
76 u64 start, u64 end, u64 pgoff, struct dso *dso);
77struct map *map__new(struct mmap_event *event, enum map_type,
78 char *cwd, int cwdlen);
79void map__delete(struct map *self);
80struct map *map__clone(struct map *self);
81int map__overlap(struct map *l, struct map *r);
82size_t map__fprintf(struct map *self, FILE *fp);
83
84int map__load(struct map *self, symbol_filter_t filter);
85struct symbol *map__find_symbol(struct map *self,
86 u64 addr, symbol_filter_t filter);
87struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
88 symbol_filter_t filter);
89void map__fixup_start(struct map *self);
90void map__fixup_end(struct map *self);
91
92void map__reloc_vmlinux(struct map *self);
93
94#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644
index 0d8c85defcd2..000000000000
--- a/tools/perf/util/module.c
+++ /dev/null
@@ -1,545 +0,0 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <libgen.h>
8#include <gelf.h>
9#include <elf.h>
10#include <dirent.h>
11#include <sys/utsname.h>
12
13static unsigned int crc32(const char *p, unsigned int len)
14{
15 int i;
16 unsigned int crc = 0;
17
18 while (len--) {
19 crc ^= *p++;
20 for (i = 0; i < 8; i++)
21 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
22 }
23 return crc;
24}
25
26/* module section methods */
27
28struct sec_dso *sec_dso__new_dso(const char *name)
29{
30 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
31
32 if (self != NULL) {
33 strcpy(self->name, name);
34 self->secs = RB_ROOT;
35 self->find_section = sec_dso__find_section;
36 }
37
38 return self;
39}
40
41static void sec_dso__delete_section(struct section *self)
42{
43 free(((void *)self));
44}
45
46void sec_dso__delete_sections(struct sec_dso *self)
47{
48 struct section *pos;
49 struct rb_node *next = rb_first(&self->secs);
50
51 while (next) {
52 pos = rb_entry(next, struct section, rb_node);
53 next = rb_next(&pos->rb_node);
54 rb_erase(&pos->rb_node, &self->secs);
55 sec_dso__delete_section(pos);
56 }
57}
58
59void sec_dso__delete_self(struct sec_dso *self)
60{
61 sec_dso__delete_sections(self);
62 free(self);
63}
64
65static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
66{
67 struct rb_node **p = &self->secs.rb_node;
68 struct rb_node *parent = NULL;
69 const u64 hash = sec->hash;
70 struct section *s;
71
72 while (*p != NULL) {
73 parent = *p;
74 s = rb_entry(parent, struct section, rb_node);
75 if (hash < s->hash)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80 rb_link_node(&sec->rb_node, parent, p);
81 rb_insert_color(&sec->rb_node, &self->secs);
82}
83
84struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
85{
86 struct rb_node *n;
87 u64 hash;
88 int len;
89
90 if (self == NULL)
91 return NULL;
92
93 len = strlen(name);
94 hash = crc32(name, len);
95
96 n = self->secs.rb_node;
97
98 while (n) {
99 struct section *s = rb_entry(n, struct section, rb_node);
100
101 if (hash < s->hash)
102 n = n->rb_left;
103 else if (hash > s->hash)
104 n = n->rb_right;
105 else {
106 if (!strcmp(name, s->name))
107 return s;
108 else
109 n = rb_next(&s->rb_node);
110 }
111 }
112
113 return NULL;
114}
115
116static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
117{
118 return fprintf(fp, "name:%s vma:%llx path:%s\n",
119 self->name, self->vma, self->path);
120}
121
122size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
123{
124 size_t ret = fprintf(fp, "dso: %s\n", self->name);
125
126 struct rb_node *nd;
127 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
128 struct section *pos = rb_entry(nd, struct section, rb_node);
129 ret += sec_dso__fprintf_section(pos, fp);
130 }
131
132 return ret;
133}
134
135static struct section *section__new(const char *name, const char *path)
136{
137 struct section *self = calloc(1, sizeof(*self));
138
139 if (!self)
140 goto out_failure;
141
142 self->name = calloc(1, strlen(name) + 1);
143 if (!self->name)
144 goto out_failure;
145
146 self->path = calloc(1, strlen(path) + 1);
147 if (!self->path)
148 goto out_failure;
149
150 strcpy(self->name, name);
151 strcpy(self->path, path);
152 self->hash = crc32(self->name, strlen(name));
153
154 return self;
155
156out_failure:
157 if (self) {
158 if (self->name)
159 free(self->name);
160 if (self->path)
161 free(self->path);
162 free(self);
163 }
164
165 return NULL;
166}
167
168/* module methods */
169
170struct mod_dso *mod_dso__new_dso(const char *name)
171{
172 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
173
174 if (self != NULL) {
175 strcpy(self->name, name);
176 self->mods = RB_ROOT;
177 self->find_module = mod_dso__find_module;
178 }
179
180 return self;
181}
182
183static void mod_dso__delete_module(struct module *self)
184{
185 free(((void *)self));
186}
187
188void mod_dso__delete_modules(struct mod_dso *self)
189{
190 struct module *pos;
191 struct rb_node *next = rb_first(&self->mods);
192
193 while (next) {
194 pos = rb_entry(next, struct module, rb_node);
195 next = rb_next(&pos->rb_node);
196 rb_erase(&pos->rb_node, &self->mods);
197 mod_dso__delete_module(pos);
198 }
199}
200
201void mod_dso__delete_self(struct mod_dso *self)
202{
203 mod_dso__delete_modules(self);
204 free(self);
205}
206
207static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
208{
209 struct rb_node **p = &self->mods.rb_node;
210 struct rb_node *parent = NULL;
211 const u64 hash = mod->hash;
212 struct module *m;
213
214 while (*p != NULL) {
215 parent = *p;
216 m = rb_entry(parent, struct module, rb_node);
217 if (hash < m->hash)
218 p = &(*p)->rb_left;
219 else
220 p = &(*p)->rb_right;
221 }
222 rb_link_node(&mod->rb_node, parent, p);
223 rb_insert_color(&mod->rb_node, &self->mods);
224}
225
226struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
227{
228 struct rb_node *n;
229 u64 hash;
230 int len;
231
232 if (self == NULL)
233 return NULL;
234
235 len = strlen(name);
236 hash = crc32(name, len);
237
238 n = self->mods.rb_node;
239
240 while (n) {
241 struct module *m = rb_entry(n, struct module, rb_node);
242
243 if (hash < m->hash)
244 n = n->rb_left;
245 else if (hash > m->hash)
246 n = n->rb_right;
247 else {
248 if (!strcmp(name, m->name))
249 return m;
250 else
251 n = rb_next(&m->rb_node);
252 }
253 }
254
255 return NULL;
256}
257
258static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
259{
260 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
261}
262
263size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
264{
265 struct rb_node *nd;
266 size_t ret;
267
268 ret = fprintf(fp, "dso: %s\n", self->name);
269
270 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
271 struct module *pos = rb_entry(nd, struct module, rb_node);
272
273 ret += mod_dso__fprintf_module(pos, fp);
274 }
275
276 return ret;
277}
278
279static struct module *module__new(const char *name, const char *path)
280{
281 struct module *self = calloc(1, sizeof(*self));
282
283 if (!self)
284 goto out_failure;
285
286 self->name = calloc(1, strlen(name) + 1);
287 if (!self->name)
288 goto out_failure;
289
290 self->path = calloc(1, strlen(path) + 1);
291 if (!self->path)
292 goto out_failure;
293
294 strcpy(self->name, name);
295 strcpy(self->path, path);
296 self->hash = crc32(self->name, strlen(name));
297
298 return self;
299
300out_failure:
301 if (self) {
302 if (self->name)
303 free(self->name);
304 if (self->path)
305 free(self->path);
306 free(self);
307 }
308
309 return NULL;
310}
311
312static int mod_dso__load_sections(struct module *mod)
313{
314 int count = 0, path_len;
315 struct dirent *entry;
316 char *line = NULL;
317 char *dir_path;
318 DIR *dir;
319 size_t n;
320
321 path_len = strlen("/sys/module/");
322 path_len += strlen(mod->name);
323 path_len += strlen("/sections/");
324
325 dir_path = calloc(1, path_len + 1);
326 if (dir_path == NULL)
327 goto out_failure;
328
329 strcat(dir_path, "/sys/module/");
330 strcat(dir_path, mod->name);
331 strcat(dir_path, "/sections/");
332
333 dir = opendir(dir_path);
334 if (dir == NULL)
335 goto out_free;
336
337 while ((entry = readdir(dir))) {
338 struct section *section;
339 char *path, *vma;
340 int line_len;
341 FILE *file;
342
343 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
344 continue;
345
346 path = calloc(1, path_len + strlen(entry->d_name) + 1);
347 if (path == NULL)
348 break;
349 strcat(path, dir_path);
350 strcat(path, entry->d_name);
351
352 file = fopen(path, "r");
353 if (file == NULL) {
354 free(path);
355 break;
356 }
357
358 line_len = getline(&line, &n, file);
359 if (line_len < 0) {
360 free(path);
361 fclose(file);
362 break;
363 }
364
365 if (!line) {
366 free(path);
367 fclose(file);
368 break;
369 }
370
371 line[--line_len] = '\0'; /* \n */
372
373 vma = strstr(line, "0x");
374 if (!vma) {
375 free(path);
376 fclose(file);
377 break;
378 }
379 vma += 2;
380
381 section = section__new(entry->d_name, path);
382 if (!section) {
383 fprintf(stderr, "load_sections: allocation error\n");
384 free(path);
385 fclose(file);
386 break;
387 }
388
389 hex2u64(vma, &section->vma);
390 sec_dso__insert_section(mod->sections, section);
391
392 free(path);
393 fclose(file);
394 count++;
395 }
396
397 closedir(dir);
398 free(line);
399 free(dir_path);
400
401 return count;
402
403out_free:
404 free(dir_path);
405
406out_failure:
407 return count;
408}
409
410static int mod_dso__load_module_paths(struct mod_dso *self)
411{
412 struct utsname uts;
413 int count = 0, len, err = -1;
414 char *line = NULL;
415 FILE *file;
416 char *dpath, *dir;
417 size_t n;
418
419 if (uname(&uts) < 0)
420 return err;
421
422 len = strlen("/lib/modules/");
423 len += strlen(uts.release);
424 len += strlen("/modules.dep");
425
426 dpath = calloc(1, len + 1);
427 if (dpath == NULL)
428 return err;
429
430 strcat(dpath, "/lib/modules/");
431 strcat(dpath, uts.release);
432 strcat(dpath, "/modules.dep");
433
434 file = fopen(dpath, "r");
435 if (file == NULL)
436 goto out_failure;
437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
443 while (!feof(file)) {
444 struct module *module;
445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
448
449 line_len = getline(&line, &n, file);
450 if (line_len < 0)
451 break;
452
453 if (!line)
454 break;
455
456 line[--line_len] = '\0'; /* \n */
457
458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
464 if (!path)
465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
483
484 name = strdup(path);
485 if (!name)
486 break;
487
488 name = strtok(name, "/");
489 tmp = name;
490
491 while (tmp) {
492 tmp = strtok(NULL, "/");
493 if (tmp)
494 name = tmp;
495 }
496
497 name = strsep(&name, ".");
498 if (!name)
499 break;
500
501 /* Quirk: replace '-' with '_' in all modules */
502 for (len = strlen(name); len; len--) {
503 if (*(name+len) == '-')
504 *(name+len) = '_';
505 }
506
507 module = module__new(name, path);
508 if (!module)
509 break;
510 mod_dso__insert_module(self, module);
511
512 module->sections = sec_dso__new_dso("sections");
513 if (!module->sections)
514 break;
515
516 module->active = mod_dso__load_sections(module);
517
518 if (module->active > 0)
519 count++;
520 }
521
522 if (feof(file))
523 err = count;
524 else
525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
526
527out_failure:
528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
536}
537
538int mod_dso__load_modules(struct mod_dso *dso)
539{
540 int err;
541
542 err = mod_dso__load_module_paths(dso);
543
544 return err;
545}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644
index 8a592ef641ca..000000000000
--- a/tools/perf/util/module.h
+++ /dev/null
@@ -1,53 +0,0 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48cbbea0..05d0c5c2030c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,4 +1,4 @@
1 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "parse-options.h" 4#include "parse-options.h"
@@ -7,10 +7,12 @@
7#include "string.h" 7#include "string.h"
8#include "cache.h" 8#include "cache.h"
9#include "header.h" 9#include "header.h"
10#include "debugfs.h"
10 11
11int nr_counters; 12int nr_counters;
12 13
13struct perf_event_attr attrs[MAX_COUNTERS]; 14struct perf_event_attr attrs[MAX_COUNTERS];
15char *filters[MAX_COUNTERS];
14 16
15struct event_symbol { 17struct event_symbol {
16 u8 type; 18 u8 type;
@@ -46,6 +48,8 @@ static struct event_symbol event_symbols[] = {
46 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
47 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
48 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
49}; 53};
50 54
51#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
@@ -74,6 +78,8 @@ static const char *sw_event_names[] = {
74 "CPU-migrations", 78 "CPU-migrations",
75 "minor-faults", 79 "minor-faults",
76 "major-faults", 80 "major-faults",
81 "alignment-faults",
82 "emulation-faults",
77}; 83};
78 84
79#define MAX_ALIASES 8 85#define MAX_ALIASES 8
@@ -148,16 +154,6 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
148 154
149#define MAX_EVENT_LENGTH 512 155#define MAX_EVENT_LENGTH 512
150 156
151int valid_debugfs_mount(const char *debugfs)
152{
153 struct statfs st_fs;
154
155 if (statfs(debugfs, &st_fs) < 0)
156 return -ENOENT;
157 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
158 return -ENOENT;
159 return 0;
160}
161 157
162struct tracepoint_path *tracepoint_id_to_path(u64 config) 158struct tracepoint_path *tracepoint_id_to_path(u64 config)
163{ 159{
@@ -170,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
170 char evt_path[MAXPATHLEN]; 166 char evt_path[MAXPATHLEN];
171 char dir_path[MAXPATHLEN]; 167 char dir_path[MAXPATHLEN];
172 168
173 if (valid_debugfs_mount(debugfs_path)) 169 if (debugfs_valid_mountpoint(debugfs_path))
174 return NULL; 170 return NULL;
175 171
176 sys_dir = opendir(debugfs_path); 172 sys_dir = opendir(debugfs_path);
@@ -201,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
201 if (id == config) { 197 if (id == config) {
202 closedir(evt_dir); 198 closedir(evt_dir);
203 closedir(sys_dir); 199 closedir(sys_dir);
204 path = calloc(1, sizeof(path)); 200 path = zalloc(sizeof(*path));
205 path->system = malloc(MAX_EVENT_LENGTH); 201 path->system = malloc(MAX_EVENT_LENGTH);
206 if (!path->system) { 202 if (!path->system) {
207 free(path); 203 free(path);
@@ -454,7 +450,8 @@ parse_single_tracepoint_event(char *sys_name,
454/* sys + ':' + event + ':' + flags*/ 450/* sys + ':' + event + ':' + flags*/
455#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
456static enum event_result 452static enum event_result
457parse_subsystem_tracepoint_event(char *sys_name, char *flags) 453parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
454 char *flags)
458{ 455{
459 char evt_path[MAXPATHLEN]; 456 char evt_path[MAXPATHLEN];
460 struct dirent *evt_ent; 457 struct dirent *evt_ent;
@@ -471,7 +468,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
471 while ((evt_ent = readdir(evt_dir))) { 468 while ((evt_ent = readdir(evt_dir))) {
472 char event_opt[MAX_EVOPT_LEN + 1]; 469 char event_opt[MAX_EVOPT_LEN + 1];
473 int len; 470 int len;
474 unsigned int rem = MAX_EVOPT_LEN;
475 471
476 if (!strcmp(evt_ent->d_name, ".") 472 if (!strcmp(evt_ent->d_name, ".")
477 || !strcmp(evt_ent->d_name, "..") 473 || !strcmp(evt_ent->d_name, "..")
@@ -479,20 +475,15 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
479 || !strcmp(evt_ent->d_name, "filter")) 475 || !strcmp(evt_ent->d_name, "filter"))
480 continue; 476 continue;
481 477
482 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, 478 if (!strglobmatch(evt_ent->d_name, evt_exp))
483 evt_ent->d_name); 479 continue;
480
481 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
482 evt_ent->d_name, flags ? ":" : "",
483 flags ?: "");
484 if (len < 0) 484 if (len < 0)
485 return EVT_FAILED; 485 return EVT_FAILED;
486 486
487 rem -= len;
488 if (flags) {
489 if (rem < strlen(flags) + 1)
490 return EVT_FAILED;
491
492 strcat(event_opt, ":");
493 strcat(event_opt, flags);
494 }
495
496 if (parse_events(NULL, event_opt, 0)) 487 if (parse_events(NULL, event_opt, 0))
497 return EVT_FAILED; 488 return EVT_FAILED;
498 } 489 }
@@ -509,7 +500,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
509 char sys_name[MAX_EVENT_LENGTH]; 500 char sys_name[MAX_EVENT_LENGTH];
510 unsigned int sys_length, evt_length; 501 unsigned int sys_length, evt_length;
511 502
512 if (valid_debugfs_mount(debugfs_path)) 503 if (debugfs_valid_mountpoint(debugfs_path))
513 return 0; 504 return 0;
514 505
515 evt_name = strchr(*strp, ':'); 506 evt_name = strchr(*strp, ':');
@@ -535,15 +526,91 @@ static enum event_result parse_tracepoint_event(const char **strp,
535 if (evt_length >= MAX_EVENT_LENGTH) 526 if (evt_length >= MAX_EVENT_LENGTH)
536 return EVT_FAILED; 527 return EVT_FAILED;
537 528
538 if (!strcmp(evt_name, "*")) { 529 if (strpbrk(evt_name, "*?")) {
539 *strp = evt_name + evt_length; 530 *strp = evt_name + evt_length;
540 return parse_subsystem_tracepoint_event(sys_name, flags); 531 return parse_multiple_tracepoint_event(sys_name, evt_name,
532 flags);
541 } else 533 } else
542 return parse_single_tracepoint_event(sys_name, evt_name, 534 return parse_single_tracepoint_event(sys_name, evt_name,
543 evt_length, flags, 535 evt_length, flags,
544 attr, strp); 536 attr, strp);
545} 537}
546 538
539static enum event_result
540parse_breakpoint_type(const char *type, const char **strp,
541 struct perf_event_attr *attr)
542{
543 int i;
544
545 for (i = 0; i < 3; i++) {
546 if (!type[i])
547 break;
548
549 switch (type[i]) {
550 case 'r':
551 attr->bp_type |= HW_BREAKPOINT_R;
552 break;
553 case 'w':
554 attr->bp_type |= HW_BREAKPOINT_W;
555 break;
556 case 'x':
557 attr->bp_type |= HW_BREAKPOINT_X;
558 break;
559 default:
560 return EVT_FAILED;
561 }
562 }
563 if (!attr->bp_type) /* Default */
564 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
565
566 *strp = type + i;
567
568 return EVT_HANDLED;
569}
570
571static enum event_result
572parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
573{
574 const char *target;
575 const char *type;
576 char *endaddr;
577 u64 addr;
578 enum event_result err;
579
580 target = strchr(*strp, ':');
581 if (!target)
582 return EVT_FAILED;
583
584 if (strncmp(*strp, "mem", target - *strp) != 0)
585 return EVT_FAILED;
586
587 target++;
588
589 addr = strtoull(target, &endaddr, 0);
590 if (target == endaddr)
591 return EVT_FAILED;
592
593 attr->bp_addr = addr;
594 *strp = endaddr;
595
596 type = strchr(target, ':');
597
598 /* If no type is defined, just rw as default */
599 if (!type) {
600 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
601 } else {
602 err = parse_breakpoint_type(++type, strp, attr);
603 if (err == EVT_FAILED)
604 return EVT_FAILED;
605 }
606
607 /* We should find a nice way to override the access type */
608 attr->bp_len = HW_BREAKPOINT_LEN_4;
609 attr->type = PERF_TYPE_BREAKPOINT;
610
611 return EVT_HANDLED;
612}
613
547static int check_events(const char *str, unsigned int i) 614static int check_events(const char *str, unsigned int i)
548{ 615{
549 int n; 616 int n;
@@ -677,6 +744,12 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
677 if (ret != EVT_FAILED) 744 if (ret != EVT_FAILED)
678 goto modifier; 745 goto modifier;
679 746
747 ret = parse_breakpoint_event(str, attr);
748 if (ret != EVT_FAILED)
749 goto modifier;
750
751 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
752 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
680 return EVT_FAILED; 753 return EVT_FAILED;
681 754
682modifier: 755modifier:
@@ -685,11 +758,11 @@ modifier:
685 return ret; 758 return ret;
686} 759}
687 760
688static void store_event_type(const char *orgname) 761static int store_event_type(const char *orgname)
689{ 762{
690 char filename[PATH_MAX], *c; 763 char filename[PATH_MAX], *c;
691 FILE *file; 764 FILE *file;
692 int id; 765 int id, n;
693 766
694 sprintf(filename, "%s/", debugfs_path); 767 sprintf(filename, "%s/", debugfs_path);
695 strncat(filename, orgname, strlen(orgname)); 768 strncat(filename, orgname, strlen(orgname));
@@ -701,21 +774,24 @@ static void store_event_type(const char *orgname)
701 774
702 file = fopen(filename, "r"); 775 file = fopen(filename, "r");
703 if (!file) 776 if (!file)
704 return; 777 return 0;
705 if (fscanf(file, "%i", &id) < 1) 778 n = fscanf(file, "%i", &id);
706 die("cannot store event ID");
707 fclose(file); 779 fclose(file);
708 perf_header__push_event(id, orgname); 780 if (n < 1) {
781 pr_err("cannot store event ID\n");
782 return -EINVAL;
783 }
784 return perf_header__push_event(id, orgname);
709} 785}
710 786
711
712int parse_events(const struct option *opt __used, const char *str, int unset __used) 787int parse_events(const struct option *opt __used, const char *str, int unset __used)
713{ 788{
714 struct perf_event_attr attr; 789 struct perf_event_attr attr;
715 enum event_result ret; 790 enum event_result ret;
716 791
717 if (strchr(str, ':')) 792 if (strchr(str, ':'))
718 store_event_type(str); 793 if (store_event_type(str) < 0)
794 return -1;
719 795
720 for (;;) { 796 for (;;) {
721 if (nr_counters == MAX_COUNTERS) 797 if (nr_counters == MAX_COUNTERS)
@@ -745,12 +821,35 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
745 return 0; 821 return 0;
746} 822}
747 823
824int parse_filter(const struct option *opt __used, const char *str,
825 int unset __used)
826{
827 int i = nr_counters - 1;
828 int len = strlen(str);
829
830 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
831 fprintf(stderr,
832 "-F option should follow a -e tracepoint option\n");
833 return -1;
834 }
835
836 filters[i] = malloc(len + 1);
837 if (!filters[i]) {
838 fprintf(stderr, "not enough memory to hold filter string\n");
839 return -1;
840 }
841 strcpy(filters[i], str);
842
843 return 0;
844}
845
748static const char * const event_type_descriptors[] = { 846static const char * const event_type_descriptors[] = {
749 "",
750 "Hardware event", 847 "Hardware event",
751 "Software event", 848 "Software event",
752 "Tracepoint event", 849 "Tracepoint event",
753 "Hardware cache event", 850 "Hardware cache event",
851 "Raw hardware event descriptor",
852 "Hardware breakpoint",
754}; 853};
755 854
756/* 855/*
@@ -764,7 +863,7 @@ static void print_tracepoint_events(void)
764 char evt_path[MAXPATHLEN]; 863 char evt_path[MAXPATHLEN];
765 char dir_path[MAXPATHLEN]; 864 char dir_path[MAXPATHLEN];
766 865
767 if (valid_debugfs_mount(debugfs_path)) 866 if (debugfs_valid_mountpoint(debugfs_path))
768 return; 867 return;
769 868
770 sys_dir = opendir(debugfs_path); 869 sys_dir = opendir(debugfs_path);
@@ -782,8 +881,8 @@ static void print_tracepoint_events(void)
782 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 881 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
783 snprintf(evt_path, MAXPATHLEN, "%s:%s", 882 snprintf(evt_path, MAXPATHLEN, "%s:%s",
784 sys_dirent.d_name, evt_dirent.d_name); 883 sys_dirent.d_name, evt_dirent.d_name);
785 fprintf(stderr, " %-42s [%s]\n", evt_path, 884 printf(" %-42s [%s]\n", evt_path,
786 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 885 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
787 } 886 }
788 closedir(evt_dir); 887 closedir(evt_dir);
789 } 888 }
@@ -799,28 +898,26 @@ void print_events(void)
799 unsigned int i, type, op, prev_type = -1; 898 unsigned int i, type, op, prev_type = -1;
800 char name[40]; 899 char name[40];
801 900
802 fprintf(stderr, "\n"); 901 printf("\n");
803 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 902 printf("List of pre-defined events (to be used in -e):\n");
804 903
805 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 904 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
806 type = syms->type + 1; 905 type = syms->type;
807 if (type >= ARRAY_SIZE(event_type_descriptors))
808 type = 0;
809 906
810 if (type != prev_type) 907 if (type != prev_type)
811 fprintf(stderr, "\n"); 908 printf("\n");
812 909
813 if (strlen(syms->alias)) 910 if (strlen(syms->alias))
814 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 911 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
815 else 912 else
816 strcpy(name, syms->symbol); 913 strcpy(name, syms->symbol);
817 fprintf(stderr, " %-42s [%s]\n", name, 914 printf(" %-42s [%s]\n", name,
818 event_type_descriptors[type]); 915 event_type_descriptors[type]);
819 916
820 prev_type = type; 917 prev_type = type;
821 } 918 }
822 919
823 fprintf(stderr, "\n"); 920 printf("\n");
824 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 921 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
825 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 922 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
826 /* skip invalid cache type */ 923 /* skip invalid cache type */
@@ -828,17 +925,22 @@ void print_events(void)
828 continue; 925 continue;
829 926
830 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 927 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
831 fprintf(stderr, " %-42s [%s]\n", 928 printf(" %-42s [%s]\n",
832 event_cache_name(type, op, i), 929 event_cache_name(type, op, i),
833 event_type_descriptors[4]); 930 event_type_descriptors[PERF_TYPE_HW_CACHE]);
834 } 931 }
835 } 932 }
836 } 933 }
837 934
838 fprintf(stderr, "\n"); 935 printf("\n");
839 fprintf(stderr, " %-42s [raw hardware event descriptor]\n", 936 printf(" %-42s [%s]\n",
840 "rNNN"); 937 "rNNN", event_type_descriptors[PERF_TYPE_RAW]);
841 fprintf(stderr, "\n"); 938 printf("\n");
939
940 printf(" %-42s [%s]\n",
941 "mem:<addr>[:access]",
942 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
943 printf("\n");
842 944
843 print_tracepoint_events(); 945 print_tracepoint_events();
844 946
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 30c608112845..b8c1f64bc935 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,5 +1,5 @@
1#ifndef _PARSE_EVENTS_H 1#ifndef __PERF_PARSE_EVENTS_H
2#define _PARSE_EVENTS_H 2#define __PERF_PARSE_EVENTS_H
3/* 3/*
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
17extern int nr_counters; 17extern int nr_counters;
18 18
19extern struct perf_event_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
20extern char *filters[MAX_COUNTERS];
20 21
21extern const char *event_name(int ctr); 22extern const char *event_name(int ctr);
22extern const char *__event_name(int type, u64 config); 23extern const char *__event_name(int type, u64 config);
23 24
24extern int parse_events(const struct option *opt, const char *str, int unset); 25extern int parse_events(const struct option *opt, const char *str, int unset);
26extern int parse_filter(const struct option *opt, const char *str, int unset);
25 27
26#define EVENTS_HELP_MAX (128*1024) 28#define EVENTS_HELP_MAX (128*1024)
27 29
@@ -31,4 +33,4 @@ extern char debugfs_path[];
31extern int valid_debugfs_mount(const char *debugfs); 33extern int valid_debugfs_mount(const char *debugfs);
32 34
33 35
34#endif /* _PARSE_EVENTS_H */ 36#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 6d8af48c925e..efebd5b476b3 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -430,6 +430,9 @@ int usage_with_options_internal(const char * const *usagestr,
430 pos = fprintf(stderr, " "); 430 pos = fprintf(stderr, " ");
431 if (opts->short_name) 431 if (opts->short_name)
432 pos += fprintf(stderr, "-%c", opts->short_name); 432 pos += fprintf(stderr, "-%c", opts->short_name);
433 else
434 pos += fprintf(stderr, " ");
435
433 if (opts->long_name && opts->short_name) 436 if (opts->long_name && opts->short_name)
434 pos += fprintf(stderr, ", "); 437 pos += fprintf(stderr, ", ");
435 if (opts->long_name) 438 if (opts->long_name)
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 2ee248ff27e5..948805af43c2 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,5 +1,5 @@
1#ifndef PARSE_OPTIONS_H 1#ifndef __PERF_PARSE_OPTIONS_H
2#define PARSE_OPTIONS_H 2#define __PERF_PARSE_OPTIONS_H
3 3
4enum parse_opt_type { 4enum parse_opt_type {
5 /* special types */ 5 /* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
174 174
175extern const char *parse_options_fix_filename(const char *prefix, const char *file); 175extern const char *parse_options_fix_filename(const char *prefix, const char *file);
176 176
177#endif 177#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
new file mode 100644
index 000000000000..7c004b6ef24f
--- /dev/null
+++ b/tools/perf/util/probe-event.c
@@ -0,0 +1,802 @@
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 "cache.h"
41#include "color.h"
42#include "parse-events.h" /* For debugfs_path */
43#include "probe-event.h"
44
45#define MAX_CMDLEN 256
46#define MAX_PROBE_ARGS 128
47#define PERFPROBE_GROUP "probe"
48
49#define semantic_error(msg ...) die("Semantic error :" msg)
50
51/* If there is no space to write, returns -E2BIG. */
52static int e_snprintf(char *str, size_t size, const char *format, ...)
53 __attribute__((format(printf, 3, 4)));
54
55static int e_snprintf(char *str, size_t size, const char *format, ...)
56{
57 int ret;
58 va_list ap;
59 va_start(ap, format);
60 ret = vsnprintf(str, size, format, ap);
61 va_end(ap);
62 if (ret >= (int)size)
63 ret = -E2BIG;
64 return ret;
65}
66
67void parse_line_range_desc(const char *arg, struct line_range *lr)
68{
69 const char *ptr;
70 char *tmp;
71 /*
72 * <Syntax>
73 * SRC:SLN[+NUM|-ELN]
74 * FUNC[:SLN[+NUM|-ELN]]
75 */
76 ptr = strchr(arg, ':');
77 if (ptr) {
78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
79 if (*tmp == '+')
80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
81 &tmp, 0);
82 else if (*tmp == '-')
83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
84 else
85 lr->end = 0;
86 pr_debug("Line range is %u to %u\n", lr->start, lr->end);
87 if (lr->end && lr->start > lr->end)
88 semantic_error("Start line must be smaller"
89 " than end line.");
90 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.",
92 *tmp);
93 tmp = strndup(arg, (ptr - arg));
94 } else
95 tmp = strdup(arg);
96
97 if (strchr(tmp, '.'))
98 lr->file = tmp;
99 else
100 lr->function = tmp;
101}
102
103/* Check the name is good for event/group */
104static bool check_event_name(const char *name)
105{
106 if (!isalpha(*name) && *name != '_')
107 return false;
108 while (*++name != '\0') {
109 if (!isalpha(*name) && !isdigit(*name) && *name != '_')
110 return false;
111 }
112 return true;
113}
114
115/* Parse probepoint definition. */
116static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
117{
118 char *ptr, *tmp;
119 char c, nc = 0;
120 /*
121 * <Syntax>
122 * perf probe [EVENT=]SRC[:LN|;PTN]
123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
124 *
125 * TODO:Group name support
126 */
127
128 ptr = strpbrk(arg, ";=@+%");
129 if (ptr && *ptr == '=') { /* Event name */
130 *ptr = '\0';
131 tmp = ptr + 1;
132 ptr = strchr(arg, ':');
133 if (ptr) /* Group name is not supported yet. */
134 semantic_error("Group name is not supported yet.");
135 if (!check_event_name(arg))
136 semantic_error("%s is bad for event name -it must "
137 "follow C symbol-naming rule.", arg);
138 pp->event = strdup(arg);
139 arg = tmp;
140 }
141
142 ptr = strpbrk(arg, ";:+@%");
143 if (ptr) {
144 nc = *ptr;
145 *ptr++ = '\0';
146 }
147
148 /* Check arg is function or file and copy it */
149 if (strchr(arg, '.')) /* File */
150 pp->file = strdup(arg);
151 else /* Function */
152 pp->function = strdup(arg);
153 DIE_IF(pp->file == NULL && pp->function == NULL);
154
155 /* Parse other options */
156 while (ptr) {
157 arg = ptr;
158 c = nc;
159 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg);
161 break;
162 }
163 ptr = strpbrk(arg, ";:+@%");
164 if (ptr) {
165 nc = *ptr;
166 *ptr++ = '\0';
167 }
168 switch (c) {
169 case ':': /* Line number */
170 pp->line = strtoul(arg, &tmp, 0);
171 if (*tmp != '\0')
172 semantic_error("There is non-digit char"
173 " in line number.");
174 break;
175 case '+': /* Byte offset from a symbol */
176 pp->offset = strtoul(arg, &tmp, 0);
177 if (*tmp != '\0')
178 semantic_error("There is non-digit character"
179 " in offset.");
180 break;
181 case '@': /* File name */
182 if (pp->file)
183 semantic_error("SRC@SRC is not allowed.");
184 pp->file = strdup(arg);
185 DIE_IF(pp->file == NULL);
186 break;
187 case '%': /* Probe places */
188 if (strcmp(arg, "return") == 0) {
189 pp->retprobe = 1;
190 } else /* Others not supported yet */
191 semantic_error("%%%s is not supported.", arg);
192 break;
193 default:
194 DIE_IF("Program has a bug.");
195 break;
196 }
197 }
198
199 /* Exclusion check */
200 if (pp->lazy_line && pp->line)
201 semantic_error("Lazy pattern can't be used with line number.");
202
203 if (pp->lazy_line && pp->offset)
204 semantic_error("Lazy pattern can't be used with offset.");
205
206 if (pp->line && pp->offset)
207 semantic_error("Offset can't be used with line number.");
208
209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
210 semantic_error("File always requires line number or "
211 "lazy pattern.");
212
213 if (pp->offset && !pp->function)
214 semantic_error("Offset requires an entry function.");
215
216 if (pp->retprobe && !pp->function)
217 semantic_error("Return probe requires an entry function.");
218
219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
220 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe.");
222
223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line);
226}
227
228/* Parse perf-probe event definition */
229void parse_perf_probe_event(const char *str, struct probe_point *pp,
230 bool *need_dwarf)
231{
232 char **argv;
233 int argc, i;
234
235 *need_dwarf = false;
236
237 argv = argv_split(str, &argc);
238 if (!argv)
239 die("argv_split failed.");
240 if (argc > MAX_PROBE_ARGS + 1)
241 semantic_error("Too many arguments");
242
243 /* Parse probe point */
244 parse_perf_probe_probepoint(argv[0], pp);
245 if (pp->file || pp->line || pp->lazy_line)
246 *need_dwarf = true;
247
248 /* Copy arguments and ensure return probe has no C argument */
249 pp->nr_args = argc - 1;
250 pp->args = zalloc(sizeof(char *) * pp->nr_args);
251 for (i = 0; i < pp->nr_args; i++) {
252 pp->args[i] = strdup(argv[i + 1]);
253 if (!pp->args[i])
254 die("Failed to copy argument.");
255 if (is_c_varname(pp->args[i])) {
256 if (pp->retprobe)
257 semantic_error("You can't specify local"
258 " variable for kretprobe");
259 *need_dwarf = true;
260 }
261 }
262
263 argv_free(argv);
264}
265
266/* Parse kprobe_events event into struct probe_point */
267void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
268{
269 char pr;
270 char *p;
271 int ret, i, argc;
272 char **argv;
273
274 pr_debug("Parsing kprobe_events: %s\n", str);
275 argv = argv_split(str, &argc);
276 if (!argv)
277 die("argv_split failed.");
278 if (argc < 2)
279 semantic_error("Too less arguments.");
280
281 /* Scan event and group name. */
282 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
283 &pr, (float *)(void *)&pp->group,
284 (float *)(void *)&pp->event);
285 if (ret != 3)
286 semantic_error("Failed to parse event name: %s", argv[0]);
287 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
288
289 pp->retprobe = (pr == 'r');
290
291 /* Scan function name and offset */
292 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
293 &pp->offset);
294 if (ret == 1)
295 pp->offset = 0;
296
297 /* kprobe_events doesn't have this information */
298 pp->line = 0;
299 pp->file = NULL;
300
301 pp->nr_args = argc - 2;
302 pp->args = zalloc(sizeof(char *) * pp->nr_args);
303 for (i = 0; i < pp->nr_args; i++) {
304 p = strchr(argv[i + 2], '=');
305 if (p) /* We don't need which register is assigned. */
306 *p = '\0';
307 pp->args[i] = strdup(argv[i + 2]);
308 if (!pp->args[i])
309 die("Failed to copy argument.");
310 }
311
312 argv_free(argv);
313}
314
315/* Synthesize only probe point (not argument) */
316int synthesize_perf_probe_point(struct probe_point *pp)
317{
318 char *buf;
319 char offs[64] = "", line[64] = "";
320 int ret;
321
322 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
323 pp->found = 1;
324 if (!buf)
325 die("Failed to allocate memory by zalloc.");
326 if (pp->offset) {
327 ret = e_snprintf(offs, 64, "+%d", pp->offset);
328 if (ret <= 0)
329 goto error;
330 }
331 if (pp->line) {
332 ret = e_snprintf(line, 64, ":%d", pp->line);
333 if (ret <= 0)
334 goto error;
335 }
336
337 if (pp->function)
338 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
339 offs, pp->retprobe ? "%return" : "", line);
340 else
341 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
342 if (ret <= 0) {
343error:
344 free(pp->probes[0]);
345 pp->probes[0] = NULL;
346 pp->found = 0;
347 }
348 return ret;
349}
350
351int synthesize_perf_probe_event(struct probe_point *pp)
352{
353 char *buf;
354 int i, len, ret;
355
356 len = synthesize_perf_probe_point(pp);
357 if (len < 0)
358 return 0;
359
360 buf = pp->probes[0];
361 for (i = 0; i < pp->nr_args; i++) {
362 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
363 pp->args[i]);
364 if (ret <= 0)
365 goto error;
366 len += ret;
367 }
368 pp->found = 1;
369
370 return pp->found;
371error:
372 free(pp->probes[0]);
373 pp->probes[0] = NULL;
374
375 return ret;
376}
377
378int synthesize_trace_kprobe_event(struct probe_point *pp)
379{
380 char *buf;
381 int i, len, ret;
382
383 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
384 if (!buf)
385 die("Failed to allocate memory by zalloc.");
386 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
387 if (ret <= 0)
388 goto error;
389 len = ret;
390
391 for (i = 0; i < pp->nr_args; i++) {
392 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
393 pp->args[i]);
394 if (ret <= 0)
395 goto error;
396 len += ret;
397 }
398 pp->found = 1;
399
400 return pp->found;
401error:
402 free(pp->probes[0]);
403 pp->probes[0] = NULL;
404
405 return ret;
406}
407
408static int open_kprobe_events(int flags, int mode)
409{
410 char buf[PATH_MAX];
411 int ret;
412
413 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
414 if (ret < 0)
415 die("Failed to make kprobe_events path.");
416
417 ret = open(buf, flags, mode);
418 if (ret < 0) {
419 if (errno == ENOENT)
420 die("kprobe_events file does not exist -"
421 " please rebuild with CONFIG_KPROBE_EVENT.");
422 else
423 die("Could not open kprobe_events file: %s",
424 strerror(errno));
425 }
426 return ret;
427}
428
429/* Get raw string list of current kprobe_events */
430static struct strlist *get_trace_kprobe_event_rawlist(int fd)
431{
432 int ret, idx;
433 FILE *fp;
434 char buf[MAX_CMDLEN];
435 char *p;
436 struct strlist *sl;
437
438 sl = strlist__new(true, NULL);
439
440 fp = fdopen(dup(fd), "r");
441 while (!feof(fp)) {
442 p = fgets(buf, MAX_CMDLEN, fp);
443 if (!p)
444 break;
445
446 idx = strlen(p) - 1;
447 if (p[idx] == '\n')
448 p[idx] = '\0';
449 ret = strlist__add(sl, buf);
450 if (ret < 0)
451 die("strlist__add failed: %s", strerror(-ret));
452 }
453 fclose(fp);
454
455 return sl;
456}
457
458/* Free and zero clear probe_point */
459static void clear_probe_point(struct probe_point *pp)
460{
461 int i;
462
463 if (pp->event)
464 free(pp->event);
465 if (pp->group)
466 free(pp->group);
467 if (pp->function)
468 free(pp->function);
469 if (pp->file)
470 free(pp->file);
471 if (pp->lazy_line)
472 free(pp->lazy_line);
473 for (i = 0; i < pp->nr_args; i++)
474 free(pp->args[i]);
475 if (pp->args)
476 free(pp->args);
477 for (i = 0; i < pp->found; i++)
478 free(pp->probes[i]);
479 memset(pp, 0, sizeof(*pp));
480}
481
482/* Show an event */
483static void show_perf_probe_event(const char *event, const char *place,
484 struct probe_point *pp)
485{
486 int i, ret;
487 char buf[128];
488
489 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
490 if (ret < 0)
491 die("Failed to copy event: %s", strerror(-ret));
492 printf(" %-40s (on %s", buf, place);
493
494 if (pp->nr_args > 0) {
495 printf(" with");
496 for (i = 0; i < pp->nr_args; i++)
497 printf(" %s", pp->args[i]);
498 }
499 printf(")\n");
500}
501
502/* List up current perf-probe events */
503void show_perf_probe_events(void)
504{
505 int fd;
506 struct probe_point pp;
507 struct strlist *rawlist;
508 struct str_node *ent;
509
510 setup_pager();
511 memset(&pp, 0, sizeof(pp));
512
513 fd = open_kprobe_events(O_RDONLY, 0);
514 rawlist = get_trace_kprobe_event_rawlist(fd);
515 close(fd);
516
517 strlist__for_each(ent, rawlist) {
518 parse_trace_kprobe_event(ent->s, &pp);
519 /* Synthesize only event probe point */
520 synthesize_perf_probe_point(&pp);
521 /* Show an event */
522 show_perf_probe_event(pp.event, pp.probes[0], &pp);
523 clear_probe_point(&pp);
524 }
525
526 strlist__delete(rawlist);
527}
528
529/* Get current perf-probe event names */
530static struct strlist *get_perf_event_names(int fd, bool include_group)
531{
532 char buf[128];
533 struct strlist *sl, *rawlist;
534 struct str_node *ent;
535 struct probe_point pp;
536
537 memset(&pp, 0, sizeof(pp));
538 rawlist = get_trace_kprobe_event_rawlist(fd);
539
540 sl = strlist__new(true, NULL);
541 strlist__for_each(ent, rawlist) {
542 parse_trace_kprobe_event(ent->s, &pp);
543 if (include_group) {
544 if (e_snprintf(buf, 128, "%s:%s", pp.group,
545 pp.event) < 0)
546 die("Failed to copy group:event name.");
547 strlist__add(sl, buf);
548 } else
549 strlist__add(sl, pp.event);
550 clear_probe_point(&pp);
551 }
552
553 strlist__delete(rawlist);
554
555 return sl;
556}
557
558static void write_trace_kprobe_event(int fd, const char *buf)
559{
560 int ret;
561
562 pr_debug("Writing event: %s\n", buf);
563 ret = write(fd, buf, strlen(buf));
564 if (ret <= 0)
565 die("Failed to write event: %s", strerror(errno));
566}
567
568static void get_new_event_name(char *buf, size_t len, const char *base,
569 struct strlist *namelist, bool allow_suffix)
570{
571 int i, ret;
572
573 /* Try no suffix */
574 ret = e_snprintf(buf, len, "%s", base);
575 if (ret < 0)
576 die("snprintf() failed: %s", strerror(-ret));
577 if (!strlist__has_entry(namelist, buf))
578 return;
579
580 if (!allow_suffix) {
581 pr_warning("Error: event \"%s\" already exists. "
582 "(Use -f to force duplicates.)\n", base);
583 die("Can't add new event.");
584 }
585
586 /* Try to add suffix */
587 for (i = 1; i < MAX_EVENT_INDEX; i++) {
588 ret = e_snprintf(buf, len, "%s_%d", base, i);
589 if (ret < 0)
590 die("snprintf() failed: %s", strerror(-ret));
591 if (!strlist__has_entry(namelist, buf))
592 break;
593 }
594 if (i == MAX_EVENT_INDEX)
595 die("Too many events are on the same function.");
596}
597
598void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
599 bool force_add)
600{
601 int i, j, fd;
602 struct probe_point *pp;
603 char buf[MAX_CMDLEN];
604 char event[64];
605 struct strlist *namelist;
606 bool allow_suffix;
607
608 fd = open_kprobe_events(O_RDWR, O_APPEND);
609 /* Get current event names */
610 namelist = get_perf_event_names(fd, false);
611
612 for (j = 0; j < nr_probes; j++) {
613 pp = probes + j;
614 if (!pp->event)
615 pp->event = strdup(pp->function);
616 if (!pp->group)
617 pp->group = strdup(PERFPROBE_GROUP);
618 DIE_IF(!pp->event || !pp->group);
619 /* If force_add is true, suffix search is allowed */
620 allow_suffix = force_add;
621 for (i = 0; i < pp->found; i++) {
622 /* Get an unused new event name */
623 get_new_event_name(event, 64, pp->event, namelist,
624 allow_suffix);
625 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
626 pp->retprobe ? 'r' : 'p',
627 pp->group, event,
628 pp->probes[i]);
629 write_trace_kprobe_event(fd, buf);
630 printf("Added new event:\n");
631 /* Get the first parameter (probe-point) */
632 sscanf(pp->probes[i], "%s", buf);
633 show_perf_probe_event(event, buf, pp);
634 /* Add added event name to namelist */
635 strlist__add(namelist, event);
636 /*
637 * Probes after the first probe which comes from same
638 * user input are always allowed to add suffix, because
639 * there might be several addresses corresponding to
640 * one code line.
641 */
642 allow_suffix = true;
643 }
644 }
645 /* Show how to use the event. */
646 printf("\nYou can now use it on all perf tools, such as:\n\n");
647 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
648
649 strlist__delete(namelist);
650 close(fd);
651}
652
653static void __del_trace_kprobe_event(int fd, struct str_node *ent)
654{
655 char *p;
656 char buf[128];
657
658 /* Convert from perf-probe event to trace-kprobe event */
659 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
660 die("Failed to copy event.");
661 p = strchr(buf + 2, ':');
662 if (!p)
663 die("Internal error: %s should have ':' but not.", ent->s);
664 *p = '/';
665
666 write_trace_kprobe_event(fd, buf);
667 printf("Remove event: %s\n", ent->s);
668}
669
670static void del_trace_kprobe_event(int fd, const char *group,
671 const char *event, struct strlist *namelist)
672{
673 char buf[128];
674 struct str_node *ent, *n;
675 int found = 0;
676
677 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
678 die("Failed to copy event.");
679
680 if (strpbrk(buf, "*?")) { /* Glob-exp */
681 strlist__for_each_safe(ent, n, namelist)
682 if (strglobmatch(ent->s, buf)) {
683 found++;
684 __del_trace_kprobe_event(fd, ent);
685 strlist__remove(namelist, ent);
686 }
687 } else {
688 ent = strlist__find(namelist, buf);
689 if (ent) {
690 found++;
691 __del_trace_kprobe_event(fd, ent);
692 strlist__remove(namelist, ent);
693 }
694 }
695 if (found == 0)
696 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
697}
698
699void del_trace_kprobe_events(struct strlist *dellist)
700{
701 int fd;
702 const char *group, *event;
703 char *p, *str;
704 struct str_node *ent;
705 struct strlist *namelist;
706
707 fd = open_kprobe_events(O_RDWR, O_APPEND);
708 /* Get current event names */
709 namelist = get_perf_event_names(fd, true);
710
711 strlist__for_each(ent, dellist) {
712 str = strdup(ent->s);
713 if (!str)
714 die("Failed to copy event.");
715 pr_debug("Parsing: %s\n", str);
716 p = strchr(str, ':');
717 if (p) {
718 group = str;
719 *p = '\0';
720 event = p + 1;
721 } else {
722 group = "*";
723 event = str;
724 }
725 pr_debug("Group: %s, Event: %s\n", group, event);
726 del_trace_kprobe_event(fd, group, event, namelist);
727 free(str);
728 }
729 strlist__delete(namelist);
730 close(fd);
731}
732
733#define LINEBUF_SIZE 256
734#define NR_ADDITIONAL_LINES 2
735
736static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
737{
738 char buf[LINEBUF_SIZE];
739 const char *color = PERF_COLOR_BLUE;
740
741 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
742 goto error;
743 if (!skip) {
744 if (show_num)
745 fprintf(stdout, "%7u %s", l, buf);
746 else
747 color_fprintf(stdout, color, " %s", buf);
748 }
749
750 while (strlen(buf) == LINEBUF_SIZE - 1 &&
751 buf[LINEBUF_SIZE - 2] != '\n') {
752 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
753 goto error;
754 if (!skip) {
755 if (show_num)
756 fprintf(stdout, "%s", buf);
757 else
758 color_fprintf(stdout, color, "%s", buf);
759 }
760 }
761 return;
762error:
763 if (feof(fp))
764 die("Source file is shorter than expected.");
765 else
766 die("File read error: %s", strerror(errno));
767}
768
769void show_line_range(struct line_range *lr)
770{
771 unsigned int l = 1;
772 struct line_node *ln;
773 FILE *fp;
774
775 setup_pager();
776
777 if (lr->function)
778 fprintf(stdout, "<%s:%d>\n", lr->function,
779 lr->start - lr->offset);
780 else
781 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
782
783 fp = fopen(lr->path, "r");
784 if (fp == NULL)
785 die("Failed to open %s: %s", lr->path, strerror(errno));
786 /* Skip to starting line number */
787 while (l < lr->start)
788 show_one_line(fp, l++, true, false);
789
790 list_for_each_entry(ln, &lr->line_list, list) {
791 while (ln->line > l)
792 show_one_line(fp, (l++) - lr->offset, false, false);
793 show_one_line(fp, (l++) - lr->offset, false, true);
794 }
795
796 if (lr->end == INT_MAX)
797 lr->end = l + NR_ADDITIONAL_LINES;
798 while (l < lr->end && !feof(fp))
799 show_one_line(fp, (l++) - lr->offset, false, false);
800
801 fclose(fp);
802}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644
index 000000000000..711287d4baea
--- /dev/null
+++ b/tools/perf/util/probe-event.h
@@ -0,0 +1,24 @@
1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H
3
4#include <stdbool.h>
5#include "probe-finder.h"
6#include "strlist.h"
7
8extern void parse_line_range_desc(const char *arg, struct line_range *lr);
9extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
10 bool *need_dwarf);
11extern int synthesize_perf_probe_point(struct probe_point *pp);
12extern int synthesize_perf_probe_event(struct probe_point *pp);
13extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
14extern int synthesize_trace_kprobe_event(struct probe_point *pp);
15extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
16 bool force_add);
17extern void del_trace_kprobe_events(struct strlist *dellist);
18extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr);
20
21/* Maximum index number of event-name postfix */
22#define MAX_EVENT_INDEX 1024
23
24#endif /*_PROBE_EVENT_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
new file mode 100644
index 000000000000..c171a243d05b
--- /dev/null
+++ b/tools/perf/util/probe-finder.c
@@ -0,0 +1,829 @@
1/*
2 * probe-finder.c : C expression to kprobe event 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#include <sys/utsname.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <getopt.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <ctype.h>
34
35#include "string.h"
36#include "event.h"
37#include "debug.h"
38#include "util.h"
39#include "probe-finder.h"
40
41
42/*
43 * Generic dwarf analysis helpers
44 */
45
46#define X86_32_MAX_REGS 8
47const char *x86_32_regs_table[X86_32_MAX_REGS] = {
48 "%ax",
49 "%cx",
50 "%dx",
51 "%bx",
52 "$stack", /* Stack address instead of %sp */
53 "%bp",
54 "%si",
55 "%di",
56};
57
58#define X86_64_MAX_REGS 16
59const char *x86_64_regs_table[X86_64_MAX_REGS] = {
60 "%ax",
61 "%dx",
62 "%cx",
63 "%bx",
64 "%si",
65 "%di",
66 "%bp",
67 "%sp",
68 "%r8",
69 "%r9",
70 "%r10",
71 "%r11",
72 "%r12",
73 "%r13",
74 "%r14",
75 "%r15",
76};
77
78/* TODO: switching by dwarf address size */
79#ifdef __x86_64__
80#define ARCH_MAX_REGS X86_64_MAX_REGS
81#define arch_regs_table x86_64_regs_table
82#else
83#define ARCH_MAX_REGS X86_32_MAX_REGS
84#define arch_regs_table x86_32_regs_table
85#endif
86
87/* Return architecture dependent register string (for kprobe-tracer) */
88static const char *get_arch_regstr(unsigned int n)
89{
90 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
91}
92
93/*
94 * Compare the tail of two strings.
95 * Return 0 if whole of either string is same as another's tail part.
96 */
97static int strtailcmp(const char *s1, const char *s2)
98{
99 int i1 = strlen(s1);
100 int i2 = strlen(s2);
101 while (--i1 >= 0 && --i2 >= 0) {
102 if (s1[i1] != s2[i2])
103 return s1[i1] - s2[i2];
104 }
105 return 0;
106}
107
108/* Line number list operations */
109
110/* Add a line to line number list */
111static void line_list__add_line(struct list_head *head, unsigned int line)
112{
113 struct line_node *ln;
114 struct list_head *p;
115
116 /* Reverse search, because new line will be the last one */
117 list_for_each_entry_reverse(ln, head, list) {
118 if (ln->line < line) {
119 p = &ln->list;
120 goto found;
121 } else if (ln->line == line) /* Already exist */
122 return ;
123 }
124 /* List is empty, or the smallest entry */
125 p = head;
126found:
127 pr_debug("line list: add a line %u\n", line);
128 ln = zalloc(sizeof(struct line_node));
129 DIE_IF(ln == NULL);
130 ln->line = line;
131 INIT_LIST_HEAD(&ln->list);
132 list_add(&ln->list, p);
133}
134
135/* Check if the line in line number list */
136static int line_list__has_line(struct list_head *head, unsigned int line)
137{
138 struct line_node *ln;
139
140 /* Reverse search, because new line will be the last one */
141 list_for_each_entry(ln, head, list)
142 if (ln->line == line)
143 return 1;
144
145 return 0;
146}
147
148/* Init line number list */
149static void line_list__init(struct list_head *head)
150{
151 INIT_LIST_HEAD(head);
152}
153
154/* Free line number list */
155static void line_list__free(struct list_head *head)
156{
157 struct line_node *ln;
158 while (!list_empty(head)) {
159 ln = list_first_entry(head, struct line_node, list);
160 list_del(&ln->list);
161 free(ln);
162 }
163}
164
165/* Dwarf wrappers */
166
167/* Find the realpath of the target file. */
168static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
169{
170 Dwarf_Files *files;
171 size_t nfiles, i;
172 const char *src = NULL;
173 int ret;
174
175 if (!fname)
176 return NULL;
177
178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
179 if (ret != 0)
180 return NULL;
181
182 for (i = 0; i < nfiles; i++) {
183 src = dwarf_filesrc(files, i, NULL, NULL);
184 if (strtailcmp(src, fname) == 0)
185 break;
186 }
187 return src;
188}
189
190struct __addr_die_search_param {
191 Dwarf_Addr addr;
192 Dwarf_Die *die_mem;
193};
194
195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
196{
197 struct __addr_die_search_param *ad = data;
198
199 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
200 dwarf_haspc(fn_die, ad->addr)) {
201 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
202 return DWARF_CB_ABORT;
203 }
204 return DWARF_CB_OK;
205}
206
207/* Search a real subprogram including this line, */
208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
209 Dwarf_Die *die_mem)
210{
211 struct __addr_die_search_param ad;
212 ad.addr = addr;
213 ad.die_mem = die_mem;
214 /* dwarf_getscopes can't find subprogram. */
215 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
216 return NULL;
217 else
218 return die_mem;
219}
220
221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
223 Dwarf_Die *die_mem)
224{
225 Dwarf_Die child_die;
226 int ret;
227
228 ret = dwarf_child(sp_die, die_mem);
229 if (ret != 0)
230 return NULL;
231
232 do {
233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
234 dwarf_haspc(die_mem, addr))
235 return die_mem;
236
237 if (die_get_inlinefunc(die_mem, addr, &child_die)) {
238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
239 return die_mem;
240 }
241 } while (dwarf_siblingof(die_mem, die_mem) == 0);
242
243 return NULL;
244}
245
246/* Compare diename and tname */
247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
248{
249 const char *name;
250 name = dwarf_diename(dw_die);
251 DIE_IF(name == NULL);
252 return strcmp(tname, name);
253}
254
255/* Get entry pc(or low pc, 1st entry of ranges) of the die */
256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
257{
258 Dwarf_Addr epc;
259 int ret;
260
261 ret = dwarf_entrypc(dw_die, &epc);
262 DIE_IF(ret == -1);
263 return epc;
264}
265
266/* Get a variable die */
267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
268 Dwarf_Die *die_mem)
269{
270 Dwarf_Die child_die;
271 int tag;
272 int ret;
273
274 ret = dwarf_child(sp_die, die_mem);
275 if (ret != 0)
276 return NULL;
277
278 do {
279 tag = dwarf_tag(die_mem);
280 if ((tag == DW_TAG_formal_parameter ||
281 tag == DW_TAG_variable) &&
282 (die_compare_name(die_mem, name) == 0))
283 return die_mem;
284
285 if (die_find_variable(die_mem, name, &child_die)) {
286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
287 return die_mem;
288 }
289 } while (dwarf_siblingof(die_mem, die_mem) == 0);
290
291 return NULL;
292}
293
294/*
295 * Probe finder related functions
296 */
297
298/* Show a location */
299static void show_location(Dwarf_Op *op, struct probe_finder *pf)
300{
301 unsigned int regn;
302 Dwarf_Word offs = 0;
303 int deref = 0, ret;
304 const char *regs;
305
306 /* TODO: support CFA */
307 /* If this is based on frame buffer, set the offset */
308 if (op->atom == DW_OP_fbreg) {
309 if (pf->fb_ops == NULL)
310 die("The attribute of frame base is not supported.\n");
311 deref = 1;
312 offs = op->number;
313 op = &pf->fb_ops[0];
314 }
315
316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
317 regn = op->atom - DW_OP_breg0;
318 offs += op->number;
319 deref = 1;
320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
321 regn = op->atom - DW_OP_reg0;
322 } else if (op->atom == DW_OP_bregx) {
323 regn = op->number;
324 offs += op->number2;
325 deref = 1;
326 } else if (op->atom == DW_OP_regx) {
327 regn = op->number;
328 } else
329 die("DW_OP %d is not supported.", op->atom);
330
331 regs = get_arch_regstr(regn);
332 if (!regs)
333 die("%u exceeds max register number.", regn);
334
335 if (deref)
336 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)",
337 pf->var, (intmax_t)offs, regs);
338 else
339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
340 DIE_IF(ret < 0);
341 DIE_IF(ret >= pf->len);
342}
343
344/* Show a variables in kprobe event format */
345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
346{
347 Dwarf_Attribute attr;
348 Dwarf_Op *expr;
349 size_t nexpr;
350 int ret;
351
352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
353 goto error;
354 /* TODO: handle more than 1 exprs */
355 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
356 if (ret <= 0 || nexpr == 0)
357 goto error;
358
359 show_location(expr, pf);
360 /* *expr will be cached in libdw. Don't free it. */
361 return ;
362error:
363 /* TODO: Support const_value */
364 die("Failed to find the location of %s at this address.\n"
365 " Perhaps, it has been optimized out.", pf->var);
366}
367
368/* Find a variable in a subprogram die */
369static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
370{
371 int ret;
372 Dwarf_Die vr_die;
373
374 /* TODO: Support struct members and arrays */
375 if (!is_c_varname(pf->var)) {
376 /* Output raw parameters */
377 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
378 DIE_IF(ret < 0);
379 DIE_IF(ret >= pf->len);
380 return ;
381 }
382
383 pr_debug("Searching '%s' variable in context.\n", pf->var);
384 /* Search child die for local variables and parameters. */
385 if (!die_find_variable(sp_die, pf->var, &vr_die))
386 die("Failed to find '%s' in this function.", pf->var);
387
388 show_variable(&vr_die, pf);
389}
390
391/* Show a probe point to output buffer */
392static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
393{
394 struct probe_point *pp = pf->pp;
395 Dwarf_Addr eaddr;
396 Dwarf_Die die_mem;
397 const char *name;
398 char tmp[MAX_PROBE_BUFFER];
399 int ret, i, len;
400 Dwarf_Attribute fb_attr;
401 size_t nops;
402
403 /* If no real subprogram, find a real one */
404 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
405 sp_die = die_get_real_subprogram(&pf->cu_die,
406 pf->addr, &die_mem);
407 if (!sp_die)
408 die("Probe point is not found in subprograms.");
409 }
410
411 /* Output name of probe point */
412 name = dwarf_diename(sp_die);
413 if (name) {
414 dwarf_entrypc(sp_die, &eaddr);
415 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
416 (unsigned long)(pf->addr - eaddr));
417 /* Copy the function name if possible */
418 if (!pp->function) {
419 pp->function = strdup(name);
420 pp->offset = (size_t)(pf->addr - eaddr);
421 }
422 } else {
423 /* This function has no name. */
424 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
425 (uintmax_t)pf->addr);
426 if (!pp->function) {
427 /* TODO: Use _stext */
428 pp->function = strdup("");
429 pp->offset = (size_t)pf->addr;
430 }
431 }
432 DIE_IF(ret < 0);
433 DIE_IF(ret >= MAX_PROBE_BUFFER);
434 len = ret;
435 pr_debug("Probe point found: %s\n", tmp);
436
437 /* Get the frame base attribute/ops */
438 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
439 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
440 if (ret <= 0 || nops == 0)
441 pf->fb_ops = NULL;
442
443 /* Find each argument */
444 /* TODO: use dwarf_cfi_addrframe */
445 for (i = 0; i < pp->nr_args; i++) {
446 pf->var = pp->args[i];
447 pf->buf = &tmp[len];
448 pf->len = MAX_PROBE_BUFFER - len;
449 find_variable(sp_die, pf);
450 len += strlen(pf->buf);
451 }
452
453 /* *pf->fb_ops will be cached in libdw. Don't free it. */
454 pf->fb_ops = NULL;
455
456 if (pp->found == MAX_PROBES)
457 die("Too many( > %d) probe point found.\n", MAX_PROBES);
458
459 pp->probes[pp->found] = strdup(tmp);
460 pp->found++;
461}
462
463/* Find probe point from its line number */
464static void find_probe_point_by_line(struct probe_finder *pf)
465{
466 Dwarf_Lines *lines;
467 Dwarf_Line *line;
468 size_t nlines, i;
469 Dwarf_Addr addr;
470 int lineno;
471 int ret;
472
473 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
474 DIE_IF(ret != 0);
475
476 for (i = 0; i < nlines; i++) {
477 line = dwarf_onesrcline(lines, i);
478 dwarf_lineno(line, &lineno);
479 if (lineno != pf->lno)
480 continue;
481
482 /* TODO: Get fileno from line, but how? */
483 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
484 continue;
485
486 ret = dwarf_lineaddr(line, &addr);
487 DIE_IF(ret != 0);
488 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
489 (int)i, lineno, (uintmax_t)addr);
490 pf->addr = addr;
491
492 show_probe_point(NULL, pf);
493 /* Continuing, because target line might be inlined. */
494 }
495}
496
497/* Find lines which match lazy pattern */
498static int find_lazy_match_lines(struct list_head *head,
499 const char *fname, const char *pat)
500{
501 char *fbuf, *p1, *p2;
502 int fd, line, nlines = 0;
503 struct stat st;
504
505 fd = open(fname, O_RDONLY);
506 if (fd < 0)
507 die("failed to open %s", fname);
508 DIE_IF(fstat(fd, &st) < 0);
509 fbuf = malloc(st.st_size + 2);
510 DIE_IF(fbuf == NULL);
511 DIE_IF(read(fd, fbuf, st.st_size) < 0);
512 close(fd);
513 fbuf[st.st_size] = '\n'; /* Dummy line */
514 fbuf[st.st_size + 1] = '\0';
515 p1 = fbuf;
516 line = 1;
517 while ((p2 = strchr(p1, '\n')) != NULL) {
518 *p2 = '\0';
519 if (strlazymatch(p1, pat)) {
520 line_list__add_line(head, line);
521 nlines++;
522 }
523 line++;
524 p1 = p2 + 1;
525 }
526 free(fbuf);
527 return nlines;
528}
529
530/* Find probe points from lazy pattern */
531static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
532{
533 Dwarf_Lines *lines;
534 Dwarf_Line *line;
535 size_t nlines, i;
536 Dwarf_Addr addr;
537 Dwarf_Die die_mem;
538 int lineno;
539 int ret;
540
541 if (list_empty(&pf->lcache)) {
542 /* Matching lazy line pattern */
543 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
544 pf->pp->lazy_line);
545 if (ret <= 0)
546 die("No matched lines found in %s.", pf->fname);
547 }
548
549 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
550 DIE_IF(ret != 0);
551 for (i = 0; i < nlines; i++) {
552 line = dwarf_onesrcline(lines, i);
553
554 dwarf_lineno(line, &lineno);
555 if (!line_list__has_line(&pf->lcache, lineno))
556 continue;
557
558 /* TODO: Get fileno from line, but how? */
559 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
560 continue;
561
562 ret = dwarf_lineaddr(line, &addr);
563 DIE_IF(ret != 0);
564 if (sp_die) {
565 /* Address filtering 1: does sp_die include addr? */
566 if (!dwarf_haspc(sp_die, addr))
567 continue;
568 /* Address filtering 2: No child include addr? */
569 if (die_get_inlinefunc(sp_die, addr, &die_mem))
570 continue;
571 }
572
573 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
574 (int)i, lineno, (unsigned long long)addr);
575 pf->addr = addr;
576
577 show_probe_point(sp_die, pf);
578 /* Continuing, because target line might be inlined. */
579 }
580 /* TODO: deallocate lines, but how? */
581}
582
583static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
584{
585 struct probe_finder *pf = (struct probe_finder *)data;
586 struct probe_point *pp = pf->pp;
587
588 if (pp->lazy_line)
589 find_probe_point_lazy(in_die, pf);
590 else {
591 /* Get probe address */
592 pf->addr = die_get_entrypc(in_die);
593 pf->addr += pp->offset;
594 pr_debug("found inline addr: 0x%jx\n",
595 (uintmax_t)pf->addr);
596
597 show_probe_point(in_die, pf);
598 }
599
600 return DWARF_CB_OK;
601}
602
603/* Search function from function name */
604static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
605{
606 struct probe_finder *pf = (struct probe_finder *)data;
607 struct probe_point *pp = pf->pp;
608
609 /* Check tag and diename */
610 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
611 die_compare_name(sp_die, pp->function) != 0)
612 return 0;
613
614 pf->fname = dwarf_decl_file(sp_die);
615 if (pp->line) { /* Function relative line */
616 dwarf_decl_line(sp_die, &pf->lno);
617 pf->lno += pp->line;
618 find_probe_point_by_line(pf);
619 } else if (!dwarf_func_inline(sp_die)) {
620 /* Real function */
621 if (pp->lazy_line)
622 find_probe_point_lazy(sp_die, pf);
623 else {
624 pf->addr = die_get_entrypc(sp_die);
625 pf->addr += pp->offset;
626 /* TODO: Check the address in this function */
627 show_probe_point(sp_die, pf);
628 }
629 } else
630 /* Inlined function: search instances */
631 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
632
633 return 1; /* Exit; no same symbol in this CU. */
634}
635
636static void find_probe_point_by_func(struct probe_finder *pf)
637{
638 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
639}
640
641/* Find a probe point */
642int find_probe_point(int fd, struct probe_point *pp)
643{
644 struct probe_finder pf = {.pp = pp};
645 Dwarf_Off off, noff;
646 size_t cuhl;
647 Dwarf_Die *diep;
648 Dwarf *dbg;
649
650 dbg = dwarf_begin(fd, DWARF_C_READ);
651 if (!dbg)
652 return -ENOENT;
653
654 pp->found = 0;
655 off = 0;
656 line_list__init(&pf.lcache);
657 /* Loop on CUs (Compilation Unit) */
658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
659 /* Get the DIE(Debugging Information Entry) of this CU */
660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
661 if (!diep)
662 continue;
663
664 /* Check if target file is included. */
665 if (pp->file)
666 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
667 else
668 pf.fname = NULL;
669
670 if (!pp->file || pf.fname) {
671 if (pp->function)
672 find_probe_point_by_func(&pf);
673 else if (pp->lazy_line)
674 find_probe_point_lazy(NULL, &pf);
675 else {
676 pf.lno = pp->line;
677 find_probe_point_by_line(&pf);
678 }
679 }
680 off = noff;
681 }
682 line_list__free(&pf.lcache);
683 dwarf_end(dbg);
684
685 return pp->found;
686}
687
688/* Find line range from its line number */
689static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
690{
691 Dwarf_Lines *lines;
692 Dwarf_Line *line;
693 size_t nlines, i;
694 Dwarf_Addr addr;
695 int lineno;
696 int ret;
697 const char *src;
698 Dwarf_Die die_mem;
699
700 line_list__init(&lf->lr->line_list);
701 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
702 DIE_IF(ret != 0);
703
704 for (i = 0; i < nlines; i++) {
705 line = dwarf_onesrcline(lines, i);
706 ret = dwarf_lineno(line, &lineno);
707 DIE_IF(ret != 0);
708 if (lf->lno_s > lineno || lf->lno_e < lineno)
709 continue;
710
711 if (sp_die) {
712 /* Address filtering 1: does sp_die include addr? */
713 ret = dwarf_lineaddr(line, &addr);
714 DIE_IF(ret != 0);
715 if (!dwarf_haspc(sp_die, addr))
716 continue;
717
718 /* Address filtering 2: No child include addr? */
719 if (die_get_inlinefunc(sp_die, addr, &die_mem))
720 continue;
721 }
722
723 /* TODO: Get fileno from line, but how? */
724 src = dwarf_linesrc(line, NULL, NULL);
725 if (strtailcmp(src, lf->fname) != 0)
726 continue;
727
728 /* Copy real path */
729 if (!lf->lr->path)
730 lf->lr->path = strdup(src);
731 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
732 }
733 /* Update status */
734 if (!list_empty(&lf->lr->line_list))
735 lf->found = 1;
736 else {
737 free(lf->lr->path);
738 lf->lr->path = NULL;
739 }
740}
741
742static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
743{
744 find_line_range_by_line(in_die, (struct line_finder *)data);
745 return DWARF_CB_ABORT; /* No need to find other instances */
746}
747
748/* Search function from function name */
749static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
750{
751 struct line_finder *lf = (struct line_finder *)data;
752 struct line_range *lr = lf->lr;
753
754 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
755 die_compare_name(sp_die, lr->function) == 0) {
756 lf->fname = dwarf_decl_file(sp_die);
757 dwarf_decl_line(sp_die, &lr->offset);
758 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
759 lf->lno_s = lr->offset + lr->start;
760 if (!lr->end)
761 lf->lno_e = INT_MAX;
762 else
763 lf->lno_e = lr->offset + lr->end;
764 lr->start = lf->lno_s;
765 lr->end = lf->lno_e;
766 if (dwarf_func_inline(sp_die))
767 dwarf_func_inline_instances(sp_die,
768 line_range_inline_cb, lf);
769 else
770 find_line_range_by_line(sp_die, lf);
771 return 1;
772 }
773 return 0;
774}
775
776static void find_line_range_by_func(struct line_finder *lf)
777{
778 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
779}
780
781int find_line_range(int fd, struct line_range *lr)
782{
783 struct line_finder lf = {.lr = lr, .found = 0};
784 int ret;
785 Dwarf_Off off = 0, noff;
786 size_t cuhl;
787 Dwarf_Die *diep;
788 Dwarf *dbg;
789
790 dbg = dwarf_begin(fd, DWARF_C_READ);
791 if (!dbg)
792 return -ENOENT;
793
794 /* Loop on CUs (Compilation Unit) */
795 while (!lf.found) {
796 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
797 if (ret != 0)
798 break;
799
800 /* Get the DIE(Debugging Information Entry) of this CU */
801 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
802 if (!diep)
803 continue;
804
805 /* Check if target file is included. */
806 if (lr->file)
807 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
808 else
809 lf.fname = 0;
810
811 if (!lr->file || lf.fname) {
812 if (lr->function)
813 find_line_range_by_func(&lf);
814 else {
815 lf.lno_s = lr->start;
816 if (!lr->end)
817 lf.lno_e = INT_MAX;
818 else
819 lf.lno_e = lr->end;
820 find_line_range_by_line(NULL, &lf);
821 }
822 }
823 off = noff;
824 }
825 pr_debug("path: %lx\n", (unsigned long)lr->path);
826 dwarf_end(dbg);
827 return lf.found;
828}
829
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
new file mode 100644
index 000000000000..21f7354397b4
--- /dev/null
+++ b/tools/perf/util/probe-finder.h
@@ -0,0 +1,92 @@
1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H
3
4#include <stdbool.h>
5#include "util.h"
6
7#define MAX_PATH_LEN 256
8#define MAX_PROBE_BUFFER 1024
9#define MAX_PROBES 128
10
11static inline int is_c_varname(const char *name)
12{
13 /* TODO */
14 return isalpha(name[0]) || name[0] == '_';
15}
16
17struct probe_point {
18 char *event; /* Event name */
19 char *group; /* Event group */
20
21 /* Inputs */
22 char *file; /* File name */
23 int line; /* Line number */
24 char *lazy_line; /* Lazy line pattern */
25
26 char *function; /* Function name */
27 int offset; /* Offset bytes */
28
29 int nr_args; /* Number of arguments */
30 char **args; /* Arguments */
31
32 int retprobe; /* Return probe */
33
34 /* Output */
35 int found; /* Number of found probe points */
36 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
37};
38
39/* Line number container */
40struct line_node {
41 struct list_head list;
42 unsigned int line;
43};
44
45/* Line range */
46struct line_range {
47 char *file; /* File name */
48 char *function; /* Function name */
49 unsigned int start; /* Start line number */
50 unsigned int end; /* End line number */
51 int offset; /* Start line offset */
52 char *path; /* Real path name */
53 struct list_head line_list; /* Visible lines */
54};
55
56#ifndef NO_DWARF_SUPPORT
57extern int find_probe_point(int fd, struct probe_point *pp);
58extern int find_line_range(int fd, struct line_range *lr);
59
60#include <dwarf.h>
61#include <libdw.h>
62
63struct probe_finder {
64 struct probe_point *pp; /* Target probe point */
65
66 /* For function searching */
67 Dwarf_Addr addr; /* Address */
68 const char *fname; /* File name */
69 int lno; /* Line number */
70 Dwarf_Die cu_die; /* Current CU */
71
72 /* For variable searching */
73 Dwarf_Op *fb_ops; /* Frame base attribute */
74 const char *var; /* Current variable name */
75 char *buf; /* Current output buffer */
76 int len; /* Length of output buffer */
77 struct list_head lcache; /* Line cache for lazy match */
78};
79
80struct line_finder {
81 struct line_range *lr; /* Target line range */
82
83 const char *fname; /* File name */
84 int lno_s; /* Start line number */
85 int lno_e; /* End line number */
86 Dwarf_Die cu_die; /* Current CU */
87 int found;
88};
89
90#endif /* NO_DWARF_SUPPORT */
91
92#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index a5454a1d1c13..b6a019733919 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -1,5 +1,5 @@
1#ifndef QUOTE_H 1#ifndef __PERF_QUOTE_H
2#define QUOTE_H 2#define __PERF_QUOTE_H
3 3
4#include <stddef.h> 4#include <stddef.h>
5#include <stdio.h> 5#include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src); 65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src); 66extern void tcl_quote_print(FILE *stream, const char *src);
67 67
68#endif 68#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index cc1837deba88..d79028727ce2 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -1,5 +1,5 @@
1#ifndef RUN_COMMAND_H 1#ifndef __PERF_RUN_COMMAND_H
2#define RUN_COMMAND_H 2#define __PERF_RUN_COMMAND_H
3 3
4enum { 4enum {
5 ERR_RUN_COMMAND_FORK = 10000, 5 ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
85int start_async(struct async *async); 85int start_async(struct async *async);
86int finish_async(struct async *async); 86int finish_async(struct async *async);
87 87
88#endif 88#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
new file mode 100644
index 000000000000..5376378e0cfc
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -0,0 +1,568 @@
1/*
2 * trace-event-perl. Feed perf trace events to an embedded Perl interpreter.
3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.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#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../../perf.h"
29#include "../util.h"
30#include "../trace-event.h"
31
32#include <EXTERN.h>
33#include <perl.h>
34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37typedef PerlInterpreter * INTERP;
38
39void xs_init(pTHX);
40
41void xs_init(pTHX)
42{
43 const char *file = __FILE__;
44 dXSUB_SYS;
45
46 newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
47 file);
48 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
49}
50
51INTERP my_perl;
52
53#define FTRACE_MAX_EVENT \
54 ((1 << (sizeof(unsigned short) * 8)) - 1)
55
56struct event *events[FTRACE_MAX_EVENT];
57
58extern struct scripting_context *scripting_context;
59
60static char *cur_field_name;
61static int zero_flag_atom;
62
63static void define_symbolic_value(const char *ev_name,
64 const char *field_name,
65 const char *field_value,
66 const char *field_str)
67{
68 unsigned long long value;
69 dSP;
70
71 value = eval_flag(field_value);
72
73 ENTER;
74 SAVETMPS;
75 PUSHMARK(SP);
76
77 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
78 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
79 XPUSHs(sv_2mortal(newSVuv(value)));
80 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
81
82 PUTBACK;
83 if (get_cv("main::define_symbolic_value", 0))
84 call_pv("main::define_symbolic_value", G_SCALAR);
85 SPAGAIN;
86 PUTBACK;
87 FREETMPS;
88 LEAVE;
89}
90
91static void define_symbolic_values(struct print_flag_sym *field,
92 const char *ev_name,
93 const char *field_name)
94{
95 define_symbolic_value(ev_name, field_name, field->value, field->str);
96 if (field->next)
97 define_symbolic_values(field->next, ev_name, field_name);
98}
99
100static void define_symbolic_field(const char *ev_name,
101 const char *field_name)
102{
103 dSP;
104
105 ENTER;
106 SAVETMPS;
107 PUSHMARK(SP);
108
109 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
110 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
111
112 PUTBACK;
113 if (get_cv("main::define_symbolic_field", 0))
114 call_pv("main::define_symbolic_field", G_SCALAR);
115 SPAGAIN;
116 PUTBACK;
117 FREETMPS;
118 LEAVE;
119}
120
121static void define_flag_value(const char *ev_name,
122 const char *field_name,
123 const char *field_value,
124 const char *field_str)
125{
126 unsigned long long value;
127 dSP;
128
129 value = eval_flag(field_value);
130
131 ENTER;
132 SAVETMPS;
133 PUSHMARK(SP);
134
135 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
136 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
137 XPUSHs(sv_2mortal(newSVuv(value)));
138 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
139
140 PUTBACK;
141 if (get_cv("main::define_flag_value", 0))
142 call_pv("main::define_flag_value", G_SCALAR);
143 SPAGAIN;
144 PUTBACK;
145 FREETMPS;
146 LEAVE;
147}
148
149static void define_flag_values(struct print_flag_sym *field,
150 const char *ev_name,
151 const char *field_name)
152{
153 define_flag_value(ev_name, field_name, field->value, field->str);
154 if (field->next)
155 define_flag_values(field->next, ev_name, field_name);
156}
157
158static void define_flag_field(const char *ev_name,
159 const char *field_name,
160 const char *delim)
161{
162 dSP;
163
164 ENTER;
165 SAVETMPS;
166 PUSHMARK(SP);
167
168 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
169 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
170 XPUSHs(sv_2mortal(newSVpv(delim, 0)));
171
172 PUTBACK;
173 if (get_cv("main::define_flag_field", 0))
174 call_pv("main::define_flag_field", G_SCALAR);
175 SPAGAIN;
176 PUTBACK;
177 FREETMPS;
178 LEAVE;
179}
180
181static void define_event_symbols(struct event *event,
182 const char *ev_name,
183 struct print_arg *args)
184{
185 switch (args->type) {
186 case PRINT_NULL:
187 break;
188 case PRINT_ATOM:
189 define_flag_value(ev_name, cur_field_name, "0",
190 args->atom.atom);
191 zero_flag_atom = 0;
192 break;
193 case PRINT_FIELD:
194 if (cur_field_name)
195 free(cur_field_name);
196 cur_field_name = strdup(args->field.name);
197 break;
198 case PRINT_FLAGS:
199 define_event_symbols(event, ev_name, args->flags.field);
200 define_flag_field(ev_name, cur_field_name, args->flags.delim);
201 define_flag_values(args->flags.flags, ev_name, cur_field_name);
202 break;
203 case PRINT_SYMBOL:
204 define_event_symbols(event, ev_name, args->symbol.field);
205 define_symbolic_field(ev_name, cur_field_name);
206 define_symbolic_values(args->symbol.symbols, ev_name,
207 cur_field_name);
208 break;
209 case PRINT_STRING:
210 break;
211 case PRINT_TYPE:
212 define_event_symbols(event, ev_name, args->typecast.item);
213 break;
214 case PRINT_OP:
215 if (strcmp(args->op.op, ":") == 0)
216 zero_flag_atom = 1;
217 define_event_symbols(event, ev_name, args->op.left);
218 define_event_symbols(event, ev_name, args->op.right);
219 break;
220 default:
221 /* we should warn... */
222 return;
223 }
224
225 if (args->next)
226 define_event_symbols(event, ev_name, args->next);
227}
228
229static inline struct event *find_cache_event(int type)
230{
231 static char ev_name[256];
232 struct event *event;
233
234 if (events[type])
235 return events[type];
236
237 events[type] = event = trace_find_event(type);
238 if (!event)
239 return NULL;
240
241 sprintf(ev_name, "%s::%s", event->system, event->name);
242
243 define_event_symbols(event, ev_name, event->print_fmt.args);
244
245 return event;
246}
247
248static void perl_process_event(int cpu, void *data,
249 int size __unused,
250 unsigned long long nsecs, char *comm)
251{
252 struct format_field *field;
253 static char handler[256];
254 unsigned long long val;
255 unsigned long s, ns;
256 struct event *event;
257 int type;
258 int pid;
259
260 dSP;
261
262 type = trace_parse_common_type(data);
263
264 event = find_cache_event(type);
265 if (!event)
266 die("ug! no event found for type %d", type);
267
268 pid = trace_parse_common_pid(data);
269
270 sprintf(handler, "%s::%s", event->system, event->name);
271
272 s = nsecs / NSECS_PER_SEC;
273 ns = nsecs - s * NSECS_PER_SEC;
274
275 scripting_context->event_data = data;
276
277 ENTER;
278 SAVETMPS;
279 PUSHMARK(SP);
280
281 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
282 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
283 XPUSHs(sv_2mortal(newSVuv(cpu)));
284 XPUSHs(sv_2mortal(newSVuv(s)));
285 XPUSHs(sv_2mortal(newSVuv(ns)));
286 XPUSHs(sv_2mortal(newSViv(pid)));
287 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
288
289 /* common fields other than pid can be accessed via xsub fns */
290
291 for (field = event->format.fields; field; field = field->next) {
292 if (field->flags & FIELD_IS_STRING) {
293 int offset;
294 if (field->flags & FIELD_IS_DYNAMIC) {
295 offset = *(int *)(data + field->offset);
296 offset &= 0xffff;
297 } else
298 offset = field->offset;
299 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
300 } else { /* FIELD_IS_NUMERIC */
301 val = read_size(data + field->offset, field->size);
302 if (field->flags & FIELD_IS_SIGNED) {
303 XPUSHs(sv_2mortal(newSViv(val)));
304 } else {
305 XPUSHs(sv_2mortal(newSVuv(val)));
306 }
307 }
308 }
309
310 PUTBACK;
311
312 if (get_cv(handler, 0))
313 call_pv(handler, G_SCALAR);
314 else if (get_cv("main::trace_unhandled", 0)) {
315 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
316 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
317 XPUSHs(sv_2mortal(newSVuv(cpu)));
318 XPUSHs(sv_2mortal(newSVuv(nsecs)));
319 XPUSHs(sv_2mortal(newSViv(pid)));
320 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
321 call_pv("main::trace_unhandled", G_SCALAR);
322 }
323 SPAGAIN;
324 PUTBACK;
325 FREETMPS;
326 LEAVE;
327}
328
329static void run_start_sub(void)
330{
331 dSP; /* access to Perl stack */
332 PUSHMARK(SP);
333
334 if (get_cv("main::trace_begin", 0))
335 call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
336}
337
338/*
339 * Start trace script
340 */
341static int perl_start_script(const char *script, int argc, const char **argv)
342{
343 const char **command_line;
344 int i, err = 0;
345
346 command_line = malloc((argc + 2) * sizeof(const char *));
347 command_line[0] = "";
348 command_line[1] = script;
349 for (i = 2; i < argc + 2; i++)
350 command_line[i] = argv[i - 2];
351
352 my_perl = perl_alloc();
353 perl_construct(my_perl);
354
355 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
356 (char **)NULL)) {
357 err = -1;
358 goto error;
359 }
360
361 if (perl_run(my_perl)) {
362 err = -1;
363 goto error;
364 }
365
366 if (SvTRUE(ERRSV)) {
367 err = -1;
368 goto error;
369 }
370
371 run_start_sub();
372
373 free(command_line);
374 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
375 return 0;
376error:
377 perl_free(my_perl);
378 free(command_line);
379
380 return err;
381}
382
383/*
384 * Stop trace script
385 */
386static int perl_stop_script(void)
387{
388 dSP; /* access to Perl stack */
389 PUSHMARK(SP);
390
391 if (get_cv("main::trace_end", 0))
392 call_pv("main::trace_end", G_DISCARD | G_NOARGS);
393
394 perl_destruct(my_perl);
395 perl_free(my_perl);
396
397 fprintf(stderr, "\nperf trace Perl script stopped\n");
398
399 return 0;
400}
401
402static int perl_generate_script(const char *outfile)
403{
404 struct event *event = NULL;
405 struct format_field *f;
406 char fname[PATH_MAX];
407 int not_first, count;
408 FILE *ofp;
409
410 sprintf(fname, "%s.pl", outfile);
411 ofp = fopen(fname, "w");
412 if (ofp == NULL) {
413 fprintf(stderr, "couldn't open %s\n", fname);
414 return -1;
415 }
416
417 fprintf(ofp, "# perf trace event handlers, "
418 "generated by perf trace -g perl\n");
419
420 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
421 " License version 2\n\n");
422
423 fprintf(ofp, "# The common_* event handler fields are the most useful "
424 "fields common to\n");
425
426 fprintf(ofp, "# all events. They don't necessarily correspond to "
427 "the 'common_*' fields\n");
428
429 fprintf(ofp, "# in the format files. Those fields not available as "
430 "handler params can\n");
431
432 fprintf(ofp, "# be retrieved using Perl functions of the form "
433 "common_*($context).\n");
434
435 fprintf(ofp, "# See Context.pm for the list of available "
436 "functions.\n\n");
437
438 fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
439 "Perf-Trace-Util/lib\";\n");
440
441 fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
442 fprintf(ofp, "use Perf::Trace::Core;\n");
443 fprintf(ofp, "use Perf::Trace::Context;\n");
444 fprintf(ofp, "use Perf::Trace::Util;\n\n");
445
446 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
447 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
448
449 while ((event = trace_find_next_event(event))) {
450 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
451 fprintf(ofp, "\tmy (");
452
453 fprintf(ofp, "$event_name, ");
454 fprintf(ofp, "$context, ");
455 fprintf(ofp, "$common_cpu, ");
456 fprintf(ofp, "$common_secs, ");
457 fprintf(ofp, "$common_nsecs,\n");
458 fprintf(ofp, "\t $common_pid, ");
459 fprintf(ofp, "$common_comm,\n\t ");
460
461 not_first = 0;
462 count = 0;
463
464 for (f = event->format.fields; f; f = f->next) {
465 if (not_first++)
466 fprintf(ofp, ", ");
467 if (++count % 5 == 0)
468 fprintf(ofp, "\n\t ");
469
470 fprintf(ofp, "$%s", f->name);
471 }
472 fprintf(ofp, ") = @_;\n\n");
473
474 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
475 "$common_secs, $common_nsecs,\n\t "
476 "$common_pid, $common_comm);\n\n");
477
478 fprintf(ofp, "\tprintf(\"");
479
480 not_first = 0;
481 count = 0;
482
483 for (f = event->format.fields; f; f = f->next) {
484 if (not_first++)
485 fprintf(ofp, ", ");
486 if (count && count % 4 == 0) {
487 fprintf(ofp, "\".\n\t \"");
488 }
489 count++;
490
491 fprintf(ofp, "%s=", f->name);
492 if (f->flags & FIELD_IS_STRING ||
493 f->flags & FIELD_IS_FLAG ||
494 f->flags & FIELD_IS_SYMBOLIC)
495 fprintf(ofp, "%%s");
496 else if (f->flags & FIELD_IS_SIGNED)
497 fprintf(ofp, "%%d");
498 else
499 fprintf(ofp, "%%u");
500 }
501
502 fprintf(ofp, "\\n\",\n\t ");
503
504 not_first = 0;
505 count = 0;
506
507 for (f = event->format.fields; f; f = f->next) {
508 if (not_first++)
509 fprintf(ofp, ", ");
510
511 if (++count % 5 == 0)
512 fprintf(ofp, "\n\t ");
513
514 if (f->flags & FIELD_IS_FLAG) {
515 if ((count - 1) % 5 != 0) {
516 fprintf(ofp, "\n\t ");
517 count = 4;
518 }
519 fprintf(ofp, "flag_str(\"");
520 fprintf(ofp, "%s::%s\", ", event->system,
521 event->name);
522 fprintf(ofp, "\"%s\", $%s)", f->name,
523 f->name);
524 } else if (f->flags & FIELD_IS_SYMBOLIC) {
525 if ((count - 1) % 5 != 0) {
526 fprintf(ofp, "\n\t ");
527 count = 4;
528 }
529 fprintf(ofp, "symbol_str(\"");
530 fprintf(ofp, "%s::%s\", ", event->system,
531 event->name);
532 fprintf(ofp, "\"%s\", $%s)", f->name,
533 f->name);
534 } else
535 fprintf(ofp, "$%s", f->name);
536 }
537
538 fprintf(ofp, ");\n");
539 fprintf(ofp, "}\n\n");
540 }
541
542 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
543 "$common_cpu, $common_secs, $common_nsecs,\n\t "
544 "$common_pid, $common_comm) = @_;\n\n");
545
546 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
547 "$common_secs, $common_nsecs,\n\t $common_pid, "
548 "$common_comm);\n}\n\n");
549
550 fprintf(ofp, "sub print_header\n{\n"
551 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
552 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
553 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
554
555 fclose(ofp);
556
557 fprintf(stderr, "generated Perl script: %s\n", fname);
558
559 return 0;
560}
561
562struct scripting_ops perl_scripting_ops = {
563 .name = "Perl",
564 .start_script = perl_start_script,
565 .stop_script = perl_stop_script,
566 .process_event = perl_process_event,
567 .generate_script = perl_generate_script,
568};
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
new file mode 100644
index 000000000000..6a72f14c5986
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -0,0 +1,580 @@
1/*
2 * trace-event-python. Feed trace events to an embedded Python interpreter.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.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#include <Python.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <errno.h>
29
30#include "../../perf.h"
31#include "../util.h"
32#include "../trace-event.h"
33
34PyMODINIT_FUNC initperf_trace_context(void);
35
36#define FTRACE_MAX_EVENT \
37 ((1 << (sizeof(unsigned short) * 8)) - 1)
38
39struct event *events[FTRACE_MAX_EVENT];
40
41#define MAX_FIELDS 64
42#define N_COMMON_FIELDS 7
43
44extern struct scripting_context *scripting_context;
45
46static char *cur_field_name;
47static int zero_flag_atom;
48
49static PyObject *main_module, *main_dict;
50
51static void handler_call_die(const char *handler_name)
52{
53 PyErr_Print();
54 Py_FatalError("problem in Python trace event handler");
55}
56
57static void define_value(enum print_arg_type field_type,
58 const char *ev_name,
59 const char *field_name,
60 const char *field_value,
61 const char *field_str)
62{
63 const char *handler_name = "define_flag_value";
64 PyObject *handler, *t, *retval;
65 unsigned long long value;
66 unsigned n = 0;
67
68 if (field_type == PRINT_SYMBOL)
69 handler_name = "define_symbolic_value";
70
71 t = PyTuple_New(4);
72 if (!t)
73 Py_FatalError("couldn't create Python tuple");
74
75 value = eval_flag(field_value);
76
77 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
78 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
79 PyTuple_SetItem(t, n++, PyInt_FromLong(value));
80 PyTuple_SetItem(t, n++, PyString_FromString(field_str));
81
82 handler = PyDict_GetItemString(main_dict, handler_name);
83 if (handler && PyCallable_Check(handler)) {
84 retval = PyObject_CallObject(handler, t);
85 if (retval == NULL)
86 handler_call_die(handler_name);
87 }
88
89 Py_DECREF(t);
90}
91
92static void define_values(enum print_arg_type field_type,
93 struct print_flag_sym *field,
94 const char *ev_name,
95 const char *field_name)
96{
97 define_value(field_type, ev_name, field_name, field->value,
98 field->str);
99
100 if (field->next)
101 define_values(field_type, field->next, ev_name, field_name);
102}
103
104static void define_field(enum print_arg_type field_type,
105 const char *ev_name,
106 const char *field_name,
107 const char *delim)
108{
109 const char *handler_name = "define_flag_field";
110 PyObject *handler, *t, *retval;
111 unsigned n = 0;
112
113 if (field_type == PRINT_SYMBOL)
114 handler_name = "define_symbolic_field";
115
116 if (field_type == PRINT_FLAGS)
117 t = PyTuple_New(3);
118 else
119 t = PyTuple_New(2);
120 if (!t)
121 Py_FatalError("couldn't create Python tuple");
122
123 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
124 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
125 if (field_type == PRINT_FLAGS)
126 PyTuple_SetItem(t, n++, PyString_FromString(delim));
127
128 handler = PyDict_GetItemString(main_dict, handler_name);
129 if (handler && PyCallable_Check(handler)) {
130 retval = PyObject_CallObject(handler, t);
131 if (retval == NULL)
132 handler_call_die(handler_name);
133 }
134
135 Py_DECREF(t);
136}
137
138static void define_event_symbols(struct event *event,
139 const char *ev_name,
140 struct print_arg *args)
141{
142 switch (args->type) {
143 case PRINT_NULL:
144 break;
145 case PRINT_ATOM:
146 define_value(PRINT_FLAGS, ev_name, cur_field_name, "0",
147 args->atom.atom);
148 zero_flag_atom = 0;
149 break;
150 case PRINT_FIELD:
151 if (cur_field_name)
152 free(cur_field_name);
153 cur_field_name = strdup(args->field.name);
154 break;
155 case PRINT_FLAGS:
156 define_event_symbols(event, ev_name, args->flags.field);
157 define_field(PRINT_FLAGS, ev_name, cur_field_name,
158 args->flags.delim);
159 define_values(PRINT_FLAGS, args->flags.flags, ev_name,
160 cur_field_name);
161 break;
162 case PRINT_SYMBOL:
163 define_event_symbols(event, ev_name, args->symbol.field);
164 define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL);
165 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
166 cur_field_name);
167 break;
168 case PRINT_STRING:
169 break;
170 case PRINT_TYPE:
171 define_event_symbols(event, ev_name, args->typecast.item);
172 break;
173 case PRINT_OP:
174 if (strcmp(args->op.op, ":") == 0)
175 zero_flag_atom = 1;
176 define_event_symbols(event, ev_name, args->op.left);
177 define_event_symbols(event, ev_name, args->op.right);
178 break;
179 default:
180 /* we should warn... */
181 return;
182 }
183
184 if (args->next)
185 define_event_symbols(event, ev_name, args->next);
186}
187
188static inline struct event *find_cache_event(int type)
189{
190 static char ev_name[256];
191 struct event *event;
192
193 if (events[type])
194 return events[type];
195
196 events[type] = event = trace_find_event(type);
197 if (!event)
198 return NULL;
199
200 sprintf(ev_name, "%s__%s", event->system, event->name);
201
202 define_event_symbols(event, ev_name, event->print_fmt.args);
203
204 return event;
205}
206
207static void python_process_event(int cpu, void *data,
208 int size __unused,
209 unsigned long long nsecs, char *comm)
210{
211 PyObject *handler, *retval, *context, *t, *obj;
212 static char handler_name[256];
213 struct format_field *field;
214 unsigned long long val;
215 unsigned long s, ns;
216 struct event *event;
217 unsigned n = 0;
218 int type;
219 int pid;
220
221 t = PyTuple_New(MAX_FIELDS);
222 if (!t)
223 Py_FatalError("couldn't create Python tuple");
224
225 type = trace_parse_common_type(data);
226
227 event = find_cache_event(type);
228 if (!event)
229 die("ug! no event found for type %d", type);
230
231 pid = trace_parse_common_pid(data);
232
233 sprintf(handler_name, "%s__%s", event->system, event->name);
234
235 s = nsecs / NSECS_PER_SEC;
236 ns = nsecs - s * NSECS_PER_SEC;
237
238 scripting_context->event_data = data;
239
240 context = PyCObject_FromVoidPtr(scripting_context, NULL);
241
242 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
243 PyTuple_SetItem(t, n++,
244 PyCObject_FromVoidPtr(scripting_context, NULL));
245 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
246 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
247 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
248 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
249 PyTuple_SetItem(t, n++, PyString_FromString(comm));
250
251 for (field = event->format.fields; field; field = field->next) {
252 if (field->flags & FIELD_IS_STRING) {
253 int offset;
254 if (field->flags & FIELD_IS_DYNAMIC) {
255 offset = *(int *)(data + field->offset);
256 offset &= 0xffff;
257 } else
258 offset = field->offset;
259 obj = PyString_FromString((char *)data + offset);
260 } else { /* FIELD_IS_NUMERIC */
261 val = read_size(data + field->offset, field->size);
262 if (field->flags & FIELD_IS_SIGNED) {
263 if ((long long)val >= LONG_MIN &&
264 (long long)val <= LONG_MAX)
265 obj = PyInt_FromLong(val);
266 else
267 obj = PyLong_FromLongLong(val);
268 } else {
269 if (val <= LONG_MAX)
270 obj = PyInt_FromLong(val);
271 else
272 obj = PyLong_FromUnsignedLongLong(val);
273 }
274 }
275 PyTuple_SetItem(t, n++, obj);
276 }
277
278 if (_PyTuple_Resize(&t, n) == -1)
279 Py_FatalError("error resizing Python tuple");
280
281 handler = PyDict_GetItemString(main_dict, handler_name);
282 if (handler && PyCallable_Check(handler)) {
283 retval = PyObject_CallObject(handler, t);
284 if (retval == NULL)
285 handler_call_die(handler_name);
286 } else {
287 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
288 if (handler && PyCallable_Check(handler)) {
289 if (_PyTuple_Resize(&t, N_COMMON_FIELDS) == -1)
290 Py_FatalError("error resizing Python tuple");
291
292 retval = PyObject_CallObject(handler, t);
293 if (retval == NULL)
294 handler_call_die("trace_unhandled");
295 }
296 }
297
298 Py_DECREF(t);
299}
300
301static int run_start_sub(void)
302{
303 PyObject *handler, *retval;
304 int err = 0;
305
306 main_module = PyImport_AddModule("__main__");
307 if (main_module == NULL)
308 return -1;
309 Py_INCREF(main_module);
310
311 main_dict = PyModule_GetDict(main_module);
312 if (main_dict == NULL) {
313 err = -1;
314 goto error;
315 }
316 Py_INCREF(main_dict);
317
318 handler = PyDict_GetItemString(main_dict, "trace_begin");
319 if (handler == NULL || !PyCallable_Check(handler))
320 goto out;
321
322 retval = PyObject_CallObject(handler, NULL);
323 if (retval == NULL)
324 handler_call_die("trace_begin");
325
326 Py_DECREF(retval);
327 return err;
328error:
329 Py_XDECREF(main_dict);
330 Py_XDECREF(main_module);
331out:
332 return err;
333}
334
335/*
336 * Start trace script
337 */
338static int python_start_script(const char *script, int argc, const char **argv)
339{
340 const char **command_line;
341 char buf[PATH_MAX];
342 int i, err = 0;
343 FILE *fp;
344
345 command_line = malloc((argc + 1) * sizeof(const char *));
346 command_line[0] = script;
347 for (i = 1; i < argc + 1; i++)
348 command_line[i] = argv[i - 1];
349
350 Py_Initialize();
351
352 initperf_trace_context();
353
354 PySys_SetArgv(argc + 1, (char **)command_line);
355
356 fp = fopen(script, "r");
357 if (!fp) {
358 sprintf(buf, "Can't open python script \"%s\"", script);
359 perror(buf);
360 err = -1;
361 goto error;
362 }
363
364 err = PyRun_SimpleFile(fp, script);
365 if (err) {
366 fprintf(stderr, "Error running python script %s\n", script);
367 goto error;
368 }
369
370 err = run_start_sub();
371 if (err) {
372 fprintf(stderr, "Error starting python script %s\n", script);
373 goto error;
374 }
375
376 free(command_line);
377 fprintf(stderr, "perf trace started with Python script %s\n\n",
378 script);
379
380 return err;
381error:
382 Py_Finalize();
383 free(command_line);
384
385 return err;
386}
387
388/*
389 * Stop trace script
390 */
391static int python_stop_script(void)
392{
393 PyObject *handler, *retval;
394 int err = 0;
395
396 handler = PyDict_GetItemString(main_dict, "trace_end");
397 if (handler == NULL || !PyCallable_Check(handler))
398 goto out;
399
400 retval = PyObject_CallObject(handler, NULL);
401 if (retval == NULL)
402 handler_call_die("trace_end");
403 else
404 Py_DECREF(retval);
405out:
406 Py_XDECREF(main_dict);
407 Py_XDECREF(main_module);
408 Py_Finalize();
409
410 fprintf(stderr, "\nperf trace Python script stopped\n");
411
412 return err;
413}
414
415static int python_generate_script(const char *outfile)
416{
417 struct event *event = NULL;
418 struct format_field *f;
419 char fname[PATH_MAX];
420 int not_first, count;
421 FILE *ofp;
422
423 sprintf(fname, "%s.py", outfile);
424 ofp = fopen(fname, "w");
425 if (ofp == NULL) {
426 fprintf(stderr, "couldn't open %s\n", fname);
427 return -1;
428 }
429 fprintf(ofp, "# perf trace event handlers, "
430 "generated by perf trace -g python\n");
431
432 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
433 " License version 2\n\n");
434
435 fprintf(ofp, "# The common_* event handler fields are the most useful "
436 "fields common to\n");
437
438 fprintf(ofp, "# all events. They don't necessarily correspond to "
439 "the 'common_*' fields\n");
440
441 fprintf(ofp, "# in the format files. Those fields not available as "
442 "handler params can\n");
443
444 fprintf(ofp, "# be retrieved using Python functions of the form "
445 "common_*(context).\n");
446
447 fprintf(ofp, "# See the perf-trace-python Documentation for the list "
448 "of available functions.\n\n");
449
450 fprintf(ofp, "import os\n");
451 fprintf(ofp, "import sys\n\n");
452
453 fprintf(ofp, "sys.path.append(os.environ['PERF_EXEC_PATH'] + \\\n");
454 fprintf(ofp, "\t'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')\n");
455 fprintf(ofp, "\nfrom perf_trace_context import *\n");
456 fprintf(ofp, "from Core import *\n\n\n");
457
458 fprintf(ofp, "def trace_begin():\n");
459 fprintf(ofp, "\tprint \"in trace_begin\"\n\n");
460
461 fprintf(ofp, "def trace_end():\n");
462 fprintf(ofp, "\tprint \"in trace_end\"\n\n");
463
464 while ((event = trace_find_next_event(event))) {
465 fprintf(ofp, "def %s__%s(", event->system, event->name);
466 fprintf(ofp, "event_name, ");
467 fprintf(ofp, "context, ");
468 fprintf(ofp, "common_cpu,\n");
469 fprintf(ofp, "\tcommon_secs, ");
470 fprintf(ofp, "common_nsecs, ");
471 fprintf(ofp, "common_pid, ");
472 fprintf(ofp, "common_comm,\n\t");
473
474 not_first = 0;
475 count = 0;
476
477 for (f = event->format.fields; f; f = f->next) {
478 if (not_first++)
479 fprintf(ofp, ", ");
480 if (++count % 5 == 0)
481 fprintf(ofp, "\n\t");
482
483 fprintf(ofp, "%s", f->name);
484 }
485 fprintf(ofp, "):\n");
486
487 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
488 "common_secs, common_nsecs,\n\t\t\t"
489 "common_pid, common_comm)\n\n");
490
491 fprintf(ofp, "\t\tprint \"");
492
493 not_first = 0;
494 count = 0;
495
496 for (f = event->format.fields; f; f = f->next) {
497 if (not_first++)
498 fprintf(ofp, ", ");
499 if (count && count % 3 == 0) {
500 fprintf(ofp, "\" \\\n\t\t\"");
501 }
502 count++;
503
504 fprintf(ofp, "%s=", f->name);
505 if (f->flags & FIELD_IS_STRING ||
506 f->flags & FIELD_IS_FLAG ||
507 f->flags & FIELD_IS_SYMBOLIC)
508 fprintf(ofp, "%%s");
509 else if (f->flags & FIELD_IS_SIGNED)
510 fprintf(ofp, "%%d");
511 else
512 fprintf(ofp, "%%u");
513 }
514
515 fprintf(ofp, "\\n\" %% \\\n\t\t(");
516
517 not_first = 0;
518 count = 0;
519
520 for (f = event->format.fields; f; f = f->next) {
521 if (not_first++)
522 fprintf(ofp, ", ");
523
524 if (++count % 5 == 0)
525 fprintf(ofp, "\n\t\t");
526
527 if (f->flags & FIELD_IS_FLAG) {
528 if ((count - 1) % 5 != 0) {
529 fprintf(ofp, "\n\t\t");
530 count = 4;
531 }
532 fprintf(ofp, "flag_str(\"");
533 fprintf(ofp, "%s__%s\", ", event->system,
534 event->name);
535 fprintf(ofp, "\"%s\", %s)", f->name,
536 f->name);
537 } else if (f->flags & FIELD_IS_SYMBOLIC) {
538 if ((count - 1) % 5 != 0) {
539 fprintf(ofp, "\n\t\t");
540 count = 4;
541 }
542 fprintf(ofp, "symbol_str(\"");
543 fprintf(ofp, "%s__%s\", ", event->system,
544 event->name);
545 fprintf(ofp, "\"%s\", %s)", f->name,
546 f->name);
547 } else
548 fprintf(ofp, "%s", f->name);
549 }
550
551 fprintf(ofp, "),\n\n");
552 }
553
554 fprintf(ofp, "def trace_unhandled(event_name, context, "
555 "common_cpu, common_secs, common_nsecs,\n\t\t"
556 "common_pid, common_comm):\n");
557
558 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
559 "common_secs, common_nsecs,\n\t\tcommon_pid, "
560 "common_comm)\n\n");
561
562 fprintf(ofp, "def print_header("
563 "event_name, cpu, secs, nsecs, pid, comm):\n"
564 "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t"
565 "(event_name, cpu, secs, nsecs, pid, comm),\n");
566
567 fclose(ofp);
568
569 fprintf(stderr, "generated Python script: %s\n", fname);
570
571 return 0;
572}
573
574struct scripting_ops python_scripting_ops = {
575 .name = "Python",
576 .start_script = python_start_script,
577 .stop_script = python_stop_script,
578 .process_event = python_process_event,
579 .generate_script = python_generate_script,
580};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644
index 000000000000..eed1cb889008
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,574 @@
1#define _FILE_OFFSET_BITS 64
2
3#include <linux/kernel.h>
4
5#include <byteswap.h>
6#include <unistd.h>
7#include <sys/types.h>
8
9#include "session.h"
10#include "sort.h"
11#include "util.h"
12
13static int perf_session__open(struct perf_session *self, bool force)
14{
15 struct stat input_stat;
16
17 self->fd = open(self->filename, O_RDONLY);
18 if (self->fd < 0) {
19 pr_err("failed to open file: %s", self->filename);
20 if (!strcmp(self->filename, "perf.data"))
21 pr_err(" (try 'perf record' first)");
22 pr_err("\n");
23 return -errno;
24 }
25
26 if (fstat(self->fd, &input_stat) < 0)
27 goto out_close;
28
29 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
30 pr_err("file %s not owned by current user or root\n",
31 self->filename);
32 goto out_close;
33 }
34
35 if (!input_stat.st_size) {
36 pr_info("zero-sized file (%s), nothing to do!\n",
37 self->filename);
38 goto out_close;
39 }
40
41 if (perf_header__read(&self->header, self->fd) < 0) {
42 pr_err("incompatible file format");
43 goto out_close;
44 }
45
46 self->size = input_stat.st_size;
47 return 0;
48
49out_close:
50 close(self->fd);
51 self->fd = -1;
52 return -1;
53}
54
55static inline int perf_session__create_kernel_maps(struct perf_session *self)
56{
57 return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
58}
59
60struct perf_session *perf_session__new(const char *filename, int mode, bool force)
61{
62 size_t len = filename ? strlen(filename) + 1 : 0;
63 struct perf_session *self = zalloc(sizeof(*self) + len);
64
65 if (self == NULL)
66 goto out;
67
68 if (perf_header__init(&self->header) < 0)
69 goto out_free;
70
71 memcpy(self->filename, filename, len);
72 self->threads = RB_ROOT;
73 self->stats_by_id = RB_ROOT;
74 self->last_match = NULL;
75 self->mmap_window = 32;
76 self->cwd = NULL;
77 self->cwdlen = 0;
78 self->unknown_events = 0;
79 map_groups__init(&self->kmaps);
80
81 if (mode == O_RDONLY) {
82 if (perf_session__open(self, force) < 0)
83 goto out_delete;
84 } else if (mode == O_WRONLY) {
85 /*
86 * In O_RDONLY mode this will be performed when reading the
87 * kernel MMAP event, in event__process_mmap().
88 */
89 if (perf_session__create_kernel_maps(self) < 0)
90 goto out_delete;
91 }
92
93 self->sample_type = perf_header__sample_type(&self->header);
94out:
95 return self;
96out_free:
97 free(self);
98 return NULL;
99out_delete:
100 perf_session__delete(self);
101 return NULL;
102}
103
104void perf_session__delete(struct perf_session *self)
105{
106 perf_header__exit(&self->header);
107 close(self->fd);
108 free(self->cwd);
109 free(self);
110}
111
112static bool symbol__match_parent_regex(struct symbol *sym)
113{
114 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
115 return 1;
116
117 return 0;
118}
119
120struct symbol **perf_session__resolve_callchain(struct perf_session *self,
121 struct thread *thread,
122 struct ip_callchain *chain,
123 struct symbol **parent)
124{
125 u8 cpumode = PERF_RECORD_MISC_USER;
126 struct symbol **syms = NULL;
127 unsigned int i;
128
129 if (symbol_conf.use_callchain) {
130 syms = calloc(chain->nr, sizeof(*syms));
131 if (!syms) {
132 fprintf(stderr, "Can't allocate memory for symbols\n");
133 exit(-1);
134 }
135 }
136
137 for (i = 0; i < chain->nr; i++) {
138 u64 ip = chain->ips[i];
139 struct addr_location al;
140
141 if (ip >= PERF_CONTEXT_MAX) {
142 switch (ip) {
143 case PERF_CONTEXT_HV:
144 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
145 case PERF_CONTEXT_KERNEL:
146 cpumode = PERF_RECORD_MISC_KERNEL; break;
147 case PERF_CONTEXT_USER:
148 cpumode = PERF_RECORD_MISC_USER; break;
149 default:
150 break;
151 }
152 continue;
153 }
154
155 thread__find_addr_location(thread, self, cpumode,
156 MAP__FUNCTION, ip, &al, NULL);
157 if (al.sym != NULL) {
158 if (sort__has_parent && !*parent &&
159 symbol__match_parent_regex(al.sym))
160 *parent = al.sym;
161 if (!symbol_conf.use_callchain)
162 break;
163 syms[i] = al.sym;
164 }
165 }
166
167 return syms;
168}
169
170static int process_event_stub(event_t *event __used,
171 struct perf_session *session __used)
172{
173 dump_printf(": unhandled!\n");
174 return 0;
175}
176
177static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
178{
179 if (handler->sample == NULL)
180 handler->sample = process_event_stub;
181 if (handler->mmap == NULL)
182 handler->mmap = process_event_stub;
183 if (handler->comm == NULL)
184 handler->comm = process_event_stub;
185 if (handler->fork == NULL)
186 handler->fork = process_event_stub;
187 if (handler->exit == NULL)
188 handler->exit = process_event_stub;
189 if (handler->lost == NULL)
190 handler->lost = process_event_stub;
191 if (handler->read == NULL)
192 handler->read = process_event_stub;
193 if (handler->throttle == NULL)
194 handler->throttle = process_event_stub;
195 if (handler->unthrottle == NULL)
196 handler->unthrottle = process_event_stub;
197}
198
199static const char *event__name[] = {
200 [0] = "TOTAL",
201 [PERF_RECORD_MMAP] = "MMAP",
202 [PERF_RECORD_LOST] = "LOST",
203 [PERF_RECORD_COMM] = "COMM",
204 [PERF_RECORD_EXIT] = "EXIT",
205 [PERF_RECORD_THROTTLE] = "THROTTLE",
206 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
207 [PERF_RECORD_FORK] = "FORK",
208 [PERF_RECORD_READ] = "READ",
209 [PERF_RECORD_SAMPLE] = "SAMPLE",
210};
211
212unsigned long event__total[PERF_RECORD_MAX];
213
214void event__print_totals(void)
215{
216 int i;
217 for (i = 0; i < PERF_RECORD_MAX; ++i)
218 pr_info("%10s events: %10ld\n",
219 event__name[i], event__total[i]);
220}
221
222void mem_bswap_64(void *src, int byte_size)
223{
224 u64 *m = src;
225
226 while (byte_size > 0) {
227 *m = bswap_64(*m);
228 byte_size -= sizeof(u64);
229 ++m;
230 }
231}
232
233static void event__all64_swap(event_t *self)
234{
235 struct perf_event_header *hdr = &self->header;
236 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
237}
238
239static void event__comm_swap(event_t *self)
240{
241 self->comm.pid = bswap_32(self->comm.pid);
242 self->comm.tid = bswap_32(self->comm.tid);
243}
244
245static void event__mmap_swap(event_t *self)
246{
247 self->mmap.pid = bswap_32(self->mmap.pid);
248 self->mmap.tid = bswap_32(self->mmap.tid);
249 self->mmap.start = bswap_64(self->mmap.start);
250 self->mmap.len = bswap_64(self->mmap.len);
251 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
252}
253
254static void event__task_swap(event_t *self)
255{
256 self->fork.pid = bswap_32(self->fork.pid);
257 self->fork.tid = bswap_32(self->fork.tid);
258 self->fork.ppid = bswap_32(self->fork.ppid);
259 self->fork.ptid = bswap_32(self->fork.ptid);
260 self->fork.time = bswap_64(self->fork.time);
261}
262
263static void event__read_swap(event_t *self)
264{
265 self->read.pid = bswap_32(self->read.pid);
266 self->read.tid = bswap_32(self->read.tid);
267 self->read.value = bswap_64(self->read.value);
268 self->read.time_enabled = bswap_64(self->read.time_enabled);
269 self->read.time_running = bswap_64(self->read.time_running);
270 self->read.id = bswap_64(self->read.id);
271}
272
273typedef void (*event__swap_op)(event_t *self);
274
275static event__swap_op event__swap_ops[] = {
276 [PERF_RECORD_MMAP] = event__mmap_swap,
277 [PERF_RECORD_COMM] = event__comm_swap,
278 [PERF_RECORD_FORK] = event__task_swap,
279 [PERF_RECORD_EXIT] = event__task_swap,
280 [PERF_RECORD_LOST] = event__all64_swap,
281 [PERF_RECORD_READ] = event__read_swap,
282 [PERF_RECORD_SAMPLE] = event__all64_swap,
283 [PERF_RECORD_MAX] = NULL,
284};
285
286static int perf_session__process_event(struct perf_session *self,
287 event_t *event,
288 struct perf_event_ops *ops,
289 u64 offset, u64 head)
290{
291 trace_event(event);
292
293 if (event->header.type < PERF_RECORD_MAX) {
294 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
295 offset + head, event->header.size,
296 event__name[event->header.type]);
297 ++event__total[0];
298 ++event__total[event->header.type];
299 }
300
301 if (self->header.needs_swap && event__swap_ops[event->header.type])
302 event__swap_ops[event->header.type](event);
303
304 switch (event->header.type) {
305 case PERF_RECORD_SAMPLE:
306 return ops->sample(event, self);
307 case PERF_RECORD_MMAP:
308 return ops->mmap(event, self);
309 case PERF_RECORD_COMM:
310 return ops->comm(event, self);
311 case PERF_RECORD_FORK:
312 return ops->fork(event, self);
313 case PERF_RECORD_EXIT:
314 return ops->exit(event, self);
315 case PERF_RECORD_LOST:
316 return ops->lost(event, self);
317 case PERF_RECORD_READ:
318 return ops->read(event, self);
319 case PERF_RECORD_THROTTLE:
320 return ops->throttle(event, self);
321 case PERF_RECORD_UNTHROTTLE:
322 return ops->unthrottle(event, self);
323 default:
324 self->unknown_events++;
325 return -1;
326 }
327}
328
329void perf_event_header__bswap(struct perf_event_header *self)
330{
331 self->type = bswap_32(self->type);
332 self->misc = bswap_16(self->misc);
333 self->size = bswap_16(self->size);
334}
335
336int perf_header__read_build_ids(struct perf_header *self,
337 int input, u64 offset, u64 size)
338{
339 struct build_id_event bev;
340 char filename[PATH_MAX];
341 u64 limit = offset + size;
342 int err = -1;
343
344 while (offset < limit) {
345 struct dso *dso;
346 ssize_t len;
347 struct list_head *head = &dsos__user;
348
349 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
350 goto out;
351
352 if (self->needs_swap)
353 perf_event_header__bswap(&bev.header);
354
355 len = bev.header.size - sizeof(bev);
356 if (read(input, filename, len) != len)
357 goto out;
358
359 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
360 head = &dsos__kernel;
361
362 dso = __dsos__findnew(head, filename);
363 if (dso != NULL) {
364 dso__set_build_id(dso, &bev.build_id);
365 if (head == &dsos__kernel && filename[0] == '[')
366 dso->kernel = 1;
367 }
368
369 offset += bev.header.size;
370 }
371 err = 0;
372out:
373 return err;
374}
375
376static struct thread *perf_session__register_idle_thread(struct perf_session *self)
377{
378 struct thread *thread = perf_session__findnew(self, 0);
379
380 if (thread == NULL || thread__set_comm(thread, "swapper")) {
381 pr_err("problem inserting idle task.\n");
382 thread = NULL;
383 }
384
385 return thread;
386}
387
388int __perf_session__process_events(struct perf_session *self,
389 u64 data_offset, u64 data_size,
390 u64 file_size, struct perf_event_ops *ops)
391{
392 int err, mmap_prot, mmap_flags;
393 u64 head, shift;
394 u64 offset = 0;
395 size_t page_size;
396 event_t *event;
397 uint32_t size;
398 char *buf;
399
400 perf_event_ops__fill_defaults(ops);
401
402 page_size = sysconf(_SC_PAGESIZE);
403
404 head = data_offset;
405 shift = page_size * (head / page_size);
406 offset += shift;
407 head -= shift;
408
409 mmap_prot = PROT_READ;
410 mmap_flags = MAP_SHARED;
411
412 if (self->header.needs_swap) {
413 mmap_prot |= PROT_WRITE;
414 mmap_flags = MAP_PRIVATE;
415 }
416remap:
417 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
418 mmap_flags, self->fd, offset);
419 if (buf == MAP_FAILED) {
420 pr_err("failed to mmap file\n");
421 err = -errno;
422 goto out_err;
423 }
424
425more:
426 event = (event_t *)(buf + head);
427
428 if (self->header.needs_swap)
429 perf_event_header__bswap(&event->header);
430 size = event->header.size;
431 if (size == 0)
432 size = 8;
433
434 if (head + event->header.size >= page_size * self->mmap_window) {
435 int munmap_ret;
436
437 shift = page_size * (head / page_size);
438
439 munmap_ret = munmap(buf, page_size * self->mmap_window);
440 assert(munmap_ret == 0);
441
442 offset += shift;
443 head -= shift;
444 goto remap;
445 }
446
447 size = event->header.size;
448
449 dump_printf("\n%#Lx [%#x]: event: %d\n",
450 offset + head, event->header.size, event->header.type);
451
452 if (size == 0 ||
453 perf_session__process_event(self, event, ops, offset, head) < 0) {
454 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
455 offset + head, event->header.size,
456 event->header.type);
457 /*
458 * assume we lost track of the stream, check alignment, and
459 * increment a single u64 in the hope to catch on again 'soon'.
460 */
461 if (unlikely(head & 7))
462 head &= ~7ULL;
463
464 size = 8;
465 }
466
467 head += size;
468
469 if (offset + head >= data_offset + data_size)
470 goto done;
471
472 if (offset + head < file_size)
473 goto more;
474done:
475 err = 0;
476out_err:
477 return err;
478}
479
480int perf_session__process_events(struct perf_session *self,
481 struct perf_event_ops *ops)
482{
483 int err;
484
485 if (perf_session__register_idle_thread(self) == NULL)
486 return -ENOMEM;
487
488 if (!symbol_conf.full_paths) {
489 char bf[PATH_MAX];
490
491 if (getcwd(bf, sizeof(bf)) == NULL) {
492 err = -errno;
493out_getcwd_err:
494 pr_err("failed to get the current directory\n");
495 goto out_err;
496 }
497 self->cwd = strdup(bf);
498 if (self->cwd == NULL) {
499 err = -ENOMEM;
500 goto out_getcwd_err;
501 }
502 self->cwdlen = strlen(self->cwd);
503 }
504
505 err = __perf_session__process_events(self, self->header.data_offset,
506 self->header.data_size,
507 self->size, ops);
508out_err:
509 return err;
510}
511
512bool perf_session__has_traces(struct perf_session *self, const char *msg)
513{
514 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
515 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
516 return false;
517 }
518
519 return true;
520}
521
522int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
523 const char *symbol_name,
524 u64 addr)
525{
526 char *bracket;
527 enum map_type i;
528
529 self->ref_reloc_sym.name = strdup(symbol_name);
530 if (self->ref_reloc_sym.name == NULL)
531 return -ENOMEM;
532
533 bracket = strchr(self->ref_reloc_sym.name, ']');
534 if (bracket)
535 *bracket = '\0';
536
537 self->ref_reloc_sym.addr = addr;
538
539 for (i = 0; i < MAP__NR_TYPES; ++i) {
540 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
541 kmap->ref_reloc_sym = &self->ref_reloc_sym;
542 }
543
544 return 0;
545}
546
547static u64 map__reloc_map_ip(struct map *map, u64 ip)
548{
549 return ip + (s64)map->pgoff;
550}
551
552static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
553{
554 return ip - (s64)map->pgoff;
555}
556
557void map__reloc_vmlinux(struct map *self)
558{
559 struct kmap *kmap = map__kmap(self);
560 s64 reloc;
561
562 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
563 return;
564
565 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
566 kmap->ref_reloc_sym->addr);
567
568 if (!reloc)
569 return;
570
571 self->map_ip = map__reloc_map_ip;
572 self->unmap_ip = map__reloc_unmap_ip;
573 self->pgoff = reloc;
574}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..5c33417eebb3
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,89 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "event.h"
5#include "header.h"
6#include "symbol.h"
7#include "thread.h"
8#include <linux/rbtree.h>
9#include "../../../include/linux/perf_event.h"
10
11struct ip_callchain;
12struct thread;
13
14struct perf_session {
15 struct perf_header header;
16 unsigned long size;
17 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads;
20 struct thread *last_match;
21 struct map *vmlinux_maps[MAP__NR_TYPES];
22 struct events_stats events_stats;
23 struct rb_root stats_by_id;
24 unsigned long event_total[PERF_RECORD_MAX];
25 unsigned long unknown_events;
26 struct rb_root hists;
27 u64 sample_type;
28 struct ref_reloc_sym ref_reloc_sym;
29 int fd;
30 int cwdlen;
31 char *cwd;
32 char filename[0];
33};
34
35typedef int (*event_op)(event_t *self, struct perf_session *session);
36
37struct perf_event_ops {
38 event_op sample,
39 mmap,
40 comm,
41 fork,
42 exit,
43 lost,
44 read,
45 throttle,
46 unthrottle;
47};
48
49struct perf_session *perf_session__new(const char *filename, int mode, bool force);
50void perf_session__delete(struct perf_session *self);
51
52void perf_event_header__bswap(struct perf_event_header *self);
53
54int __perf_session__process_events(struct perf_session *self,
55 u64 data_offset, u64 data_size, u64 size,
56 struct perf_event_ops *ops);
57int perf_session__process_events(struct perf_session *self,
58 struct perf_event_ops *event_ops);
59
60struct symbol **perf_session__resolve_callchain(struct perf_session *self,
61 struct thread *thread,
62 struct ip_callchain *chain,
63 struct symbol **parent);
64
65bool perf_session__has_traces(struct perf_session *self, const char *msg);
66
67int perf_header__read_build_ids(struct perf_header *self, int input,
68 u64 offset, u64 file_size);
69
70int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
71 const char *symbol_name,
72 u64 addr);
73
74void mem_bswap_64(void *src, int byte_size);
75
76static inline int __perf_session__create_kernel_maps(struct perf_session *self,
77 struct dso *kernel)
78{
79 return __map_groups__create_kernel_maps(&self->kmaps,
80 self->vmlinux_maps, kernel);
81}
82
83static inline struct map *
84 perf_session__new_module_map(struct perf_session *self,
85 u64 start, const char *filename)
86{
87 return map_groups__new_module(&self->kmaps, start, filename);
88}
89#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef SIGCHAIN_H 1#ifndef __PERF_SIGCHAIN_H
2#define SIGCHAIN_H 2#define __PERF_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
8 8
9void sigchain_push_common(sigchain_fun f); 9void sigchain_push_common(sigchain_fun f);
10 10
11#endif /* SIGCHAIN_H */ 11#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..cb0f327de9e8
--- /dev/null
+++ b/tools/perf/util/sort.c
@@ -0,0 +1,316 @@
1#include "sort.h"
2
3regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order;
8int sort__need_collapse = 0;
9int sort__has_parent = 0;
10
11enum sort_type sort__first_dimension;
12
13unsigned int dsos__col_width;
14unsigned int comms__col_width;
15unsigned int threads__col_width;
16static unsigned int parent_symbol__col_width;
17char * field_sep;
18
19LIST_HEAD(hist_entry__sort_list);
20
21struct sort_entry sort_thread = {
22 .header = "Command: Pid",
23 .cmp = sort__thread_cmp,
24 .print = sort__thread_print,
25 .width = &threads__col_width,
26};
27
28struct sort_entry sort_comm = {
29 .header = "Command",
30 .cmp = sort__comm_cmp,
31 .collapse = sort__comm_collapse,
32 .print = sort__comm_print,
33 .width = &comms__col_width,
34};
35
36struct sort_entry sort_dso = {
37 .header = "Shared Object",
38 .cmp = sort__dso_cmp,
39 .print = sort__dso_print,
40 .width = &dsos__col_width,
41};
42
43struct sort_entry sort_sym = {
44 .header = "Symbol",
45 .cmp = sort__sym_cmp,
46 .print = sort__sym_print,
47};
48
49struct sort_entry sort_parent = {
50 .header = "Parent symbol",
51 .cmp = sort__parent_cmp,
52 .print = sort__parent_print,
53 .width = &parent_symbol__col_width,
54};
55
56struct sort_dimension {
57 const char *name;
58 struct sort_entry *entry;
59 int taken;
60};
61
62static struct sort_dimension sort_dimensions[] = {
63 { .name = "pid", .entry = &sort_thread, },
64 { .name = "comm", .entry = &sort_comm, },
65 { .name = "dso", .entry = &sort_dso, },
66 { .name = "symbol", .entry = &sort_sym, },
67 { .name = "parent", .entry = &sort_parent, },
68};
69
70int64_t cmp_null(void *l, void *r)
71{
72 if (!l && !r)
73 return 0;
74 else if (!l)
75 return -1;
76 else
77 return 1;
78}
79
80/* --sort pid */
81
82int64_t
83sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
84{
85 return right->thread->pid - left->thread->pid;
86}
87
88int repsep_fprintf(FILE *fp, const char *fmt, ...)
89{
90 int n;
91 va_list ap;
92
93 va_start(ap, fmt);
94 if (!field_sep)
95 n = vfprintf(fp, fmt, ap);
96 else {
97 char *bf = NULL;
98 n = vasprintf(&bf, fmt, ap);
99 if (n > 0) {
100 char *sep = bf;
101
102 while (1) {
103 sep = strchr(sep, *field_sep);
104 if (sep == NULL)
105 break;
106 *sep = '.';
107 }
108 }
109 fputs(bf, fp);
110 free(bf);
111 }
112 va_end(ap);
113 return n;
114}
115
116size_t
117sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
118{
119 return repsep_fprintf(fp, "%*s:%5d", width - 6,
120 self->thread->comm ?: "", self->thread->pid);
121}
122
123size_t
124sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
125{
126 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
127}
128
129/* --sort dso */
130
131int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{
134 struct dso *dso_l = left->map ? left->map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL;
136 const char *dso_name_l, *dso_name_r;
137
138 if (!dso_l || !dso_r)
139 return cmp_null(dso_l, dso_r);
140
141 if (verbose) {
142 dso_name_l = dso_l->long_name;
143 dso_name_r = dso_r->long_name;
144 } else {
145 dso_name_l = dso_l->short_name;
146 dso_name_r = dso_r->short_name;
147 }
148
149 return strcmp(dso_name_l, dso_name_r);
150}
151
152size_t
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
154{
155 if (self->map && self->map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name :
157 self->map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name);
159 }
160
161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
162}
163
164/* --sort symbol */
165
166int64_t
167sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{
169 u64 ip_l, ip_r;
170
171 if (left->sym == right->sym)
172 return 0;
173
174 ip_l = left->sym ? left->sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip;
176
177 return (int64_t)(ip_r - ip_l);
178}
179
180
181size_t
182sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
183{
184 size_t ret = 0;
185
186 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
189 }
190
191 ret += repsep_fprintf(fp, "[%c] ", self->level);
192 if (self->sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name);
194 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
196
197 return ret;
198}
199
200/* --sort comm */
201
202int64_t
203sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
204{
205 return right->thread->pid - left->thread->pid;
206}
207
208int64_t
209sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
210{
211 char *comm_l = left->thread->comm;
212 char *comm_r = right->thread->comm;
213
214 if (!comm_l || !comm_r)
215 return cmp_null(comm_l, comm_r);
216
217 return strcmp(comm_l, comm_r);
218}
219
220/* --sort parent */
221
222int64_t
223sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
224{
225 struct symbol *sym_l = left->parent;
226 struct symbol *sym_r = right->parent;
227
228 if (!sym_l || !sym_r)
229 return cmp_null(sym_l, sym_r);
230
231 return strcmp(sym_l->name, sym_r->name);
232}
233
234size_t
235sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
236{
237 return repsep_fprintf(fp, "%-*s", width,
238 self->parent ? self->parent->name : "[other]");
239}
240
241int sort_dimension__add(const char *tok)
242{
243 unsigned int i;
244
245 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
246 struct sort_dimension *sd = &sort_dimensions[i];
247
248 if (sd->taken)
249 continue;
250
251 if (strncasecmp(tok, sd->name, strlen(tok)))
252 continue;
253
254 if (sd->entry->collapse)
255 sort__need_collapse = 1;
256
257 if (sd->entry == &sort_parent) {
258 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
259 if (ret) {
260 char err[BUFSIZ];
261
262 regerror(ret, &parent_regex, err, sizeof(err));
263 fprintf(stderr, "Invalid regex: %s\n%s",
264 parent_pattern, err);
265 exit(-1);
266 }
267 sort__has_parent = 1;
268 }
269
270 if (list_empty(&hist_entry__sort_list)) {
271 if (!strcmp(sd->name, "pid"))
272 sort__first_dimension = SORT_PID;
273 else if (!strcmp(sd->name, "comm"))
274 sort__first_dimension = SORT_COMM;
275 else if (!strcmp(sd->name, "dso"))
276 sort__first_dimension = SORT_DSO;
277 else if (!strcmp(sd->name, "symbol"))
278 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT;
281 }
282
283 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
284 sd->taken = 1;
285
286 return 0;
287 }
288
289 return -ESRCH;
290}
291
292void setup_sorting(const char * const usagestr[], const struct option *opts)
293{
294 char *tmp, *tok, *str = strdup(sort_order);
295
296 for (tok = strtok_r(str, ", ", &tmp);
297 tok; tok = strtok_r(NULL, ", ", &tmp)) {
298 if (sort_dimension__add(tok) < 0) {
299 error("Unknown --sort key: `%s'", tok);
300 usage_with_options(usagestr, opts);
301 }
302 }
303
304 free(str);
305}
306
307void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
308 const char *list_name, FILE *fp)
309{
310 if (list && strlist__nr_entries(list) == 1) {
311 if (fp != NULL)
312 fprintf(fp, "# %s: %s\n", list_name,
313 strlist__entry(list, 0)->s);
314 self->elide = true;
315 }
316}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644
index 000000000000..753f9ea99fb0
--- /dev/null
+++ b/tools/perf/util/sort.h
@@ -0,0 +1,107 @@
1#ifndef __PERF_SORT_H
2#define __PERF_SORT_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern regex_t parent_regex;
28extern char *sort_order;
29extern char default_parent_pattern[];
30extern char *parent_pattern;
31extern char default_sort_order[];
32extern int sort__need_collapse;
33extern int sort__has_parent;
34extern char *field_sep;
35extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42extern enum sort_type sort__first_dimension;
43
44struct hist_entry {
45 struct rb_node rb_node;
46 u64 count;
47 struct thread *thread;
48 struct map *map;
49 struct symbol *sym;
50 u64 ip;
51 char level;
52 struct symbol *parent;
53 struct callchain_node callchain;
54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
59};
60
61enum sort_type {
62 SORT_PID,
63 SORT_COMM,
64 SORT_DSO,
65 SORT_SYM,
66 SORT_PARENT
67};
68
69/*
70 * configurable sorting bits
71 */
72
73struct sort_entry {
74 struct list_head list;
75
76 const char *header;
77
78 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
79 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
80 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
81 unsigned int *width;
82 bool elide;
83};
84
85extern struct sort_entry sort_thread;
86extern struct list_head hist_entry__sort_list;
87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
93extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
94extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
95extern int64_t cmp_null(void *, void *);
96extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
97extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
98extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
99extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
100extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
103extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
105 const char *list_name, FILE *fp);
106
107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index d2aa86c014c1..a3d121d6c83e 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -1,5 +1,5 @@
1#ifndef STRBUF_H 1#ifndef __PERF_STRBUF_H
2#define STRBUF_H 2#define __PERF_STRBUF_H
3 3
4/* 4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary 5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
134extern int strbuf_branchname(struct strbuf *sb, const char *name); 134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); 135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 136
137#endif /* STRBUF_H */ 137#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c93eca9a7be3..a175949ed216 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,4 +1,5 @@
1#include "string.h" 1#include "string.h"
2#include "util.h"
2 3
3static int hex(char ch) 4static int hex(char ch)
4{ 5{
@@ -32,3 +33,307 @@ int hex2u64(const char *ptr, u64 *long_val)
32 33
33 return p - ptr; 34 return p - ptr;
34} 35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
46
47#define K 1024LL
48/*
49 * perf_atoll()
50 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
51 * and return its numeric value
52 */
53s64 perf_atoll(const char *str)
54{
55 unsigned int i;
56 s64 length = -1, unit = 1;
57
58 if (!isdigit(str[0]))
59 goto out_err;
60
61 for (i = 1; i < strlen(str); i++) {
62 switch (str[i]) {
63 case 'B':
64 case 'b':
65 break;
66 case 'K':
67 if (str[i + 1] != 'B')
68 goto out_err;
69 else
70 goto kilo;
71 case 'k':
72 if (str[i + 1] != 'b')
73 goto out_err;
74kilo:
75 unit = K;
76 break;
77 case 'M':
78 if (str[i + 1] != 'B')
79 goto out_err;
80 else
81 goto mega;
82 case 'm':
83 if (str[i + 1] != 'b')
84 goto out_err;
85mega:
86 unit = K * K;
87 break;
88 case 'G':
89 if (str[i + 1] != 'B')
90 goto out_err;
91 else
92 goto giga;
93 case 'g':
94 if (str[i + 1] != 'b')
95 goto out_err;
96giga:
97 unit = K * K * K;
98 break;
99 case 'T':
100 if (str[i + 1] != 'B')
101 goto out_err;
102 else
103 goto tera;
104 case 't':
105 if (str[i + 1] != 'b')
106 goto out_err;
107tera:
108 unit = K * K * K * K;
109 break;
110 case '\0': /* only specified figures */
111 unit = 1;
112 break;
113 default:
114 if (!isdigit(str[i]))
115 goto out_err;
116 break;
117 }
118 }
119
120 length = atoll(str) * unit;
121 goto out;
122
123out_err:
124 length = -1;
125out:
126 return length;
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}
229
230/* Character class matching */
231static bool __match_charclass(const char *pat, char c, const char **npat)
232{
233 bool complement = false, ret = true;
234
235 if (*pat == '!') {
236 complement = true;
237 pat++;
238 }
239 if (*pat++ == c) /* First character is special */
240 goto end;
241
242 while (*pat && *pat != ']') { /* Matching */
243 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
244 if (*(pat - 1) <= c && c <= *(pat + 1))
245 goto end;
246 if (*(pat - 1) > *(pat + 1))
247 goto error;
248 pat += 2;
249 } else if (*pat++ == c)
250 goto end;
251 }
252 if (!*pat)
253 goto error;
254 ret = false;
255
256end:
257 while (*pat && *pat != ']') /* Searching closing */
258 pat++;
259 if (!*pat)
260 goto error;
261 *npat = pat + 1;
262 return complement ? !ret : ret;
263
264error:
265 return false;
266}
267
268/* Glob/lazy pattern matching */
269static bool __match_glob(const char *str, const char *pat, bool ignore_space)
270{
271 while (*str && *pat && *pat != '*') {
272 if (ignore_space) {
273 /* Ignore spaces for lazy matching */
274 if (isspace(*str)) {
275 str++;
276 continue;
277 }
278 if (isspace(*pat)) {
279 pat++;
280 continue;
281 }
282 }
283 if (*pat == '?') { /* Matches any single character */
284 str++;
285 pat++;
286 continue;
287 } else if (*pat == '[') /* Character classes/Ranges */
288 if (__match_charclass(pat + 1, *str, &pat)) {
289 str++;
290 continue;
291 } else
292 return false;
293 else if (*pat == '\\') /* Escaped char match as normal char */
294 pat++;
295 if (*str++ != *pat++)
296 return false;
297 }
298 /* Check wild card */
299 if (*pat == '*') {
300 while (*pat == '*')
301 pat++;
302 if (!*pat) /* Tail wild card matches all */
303 return true;
304 while (*str)
305 if (strglobmatch(str++, pat))
306 return true;
307 }
308 return !*str && !*pat;
309}
310
311/**
312 * strglobmatch - glob expression pattern matching
313 * @str: the target string to match
314 * @pat: the pattern string to match
315 *
316 * This returns true if the @str matches @pat. @pat can includes wildcards
317 * ('*','?') and character classes ([CHARS], complementation and ranges are
318 * also supported). Also, this supports escape character ('\') to use special
319 * characters as normal character.
320 *
321 * Note: if @pat syntax is broken, this always returns false.
322 */
323bool strglobmatch(const char *str, const char *pat)
324{
325 return __match_glob(str, pat, false);
326}
327
328/**
329 * strlazymatch - matching pattern strings lazily with glob pattern
330 * @str: the target string to match
331 * @pat: the pattern string to match
332 *
333 * This is similar to strglobmatch, except this ignores spaces in
334 * the target string.
335 */
336bool strlazymatch(const char *str, const char *pat)
337{
338 return __match_glob(str, pat, true);
339}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..542e44de3719 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,18 @@
1#ifndef _PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define _PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include <stdbool.h>
4#include "types.h" 5#include "types.h"
5 6
6int hex2u64(const char *ptr, u64 *val); 7int hex2u64(const char *ptr, u64 *val);
8char *strxfrchar(char *s, char from, char to);
9s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
7 14
8#define _STR(x) #x 15#define _STR(x) #x
9#define STR(x) _STR(x) 16#define STR(x) _STR(x)
10 17
11#endif 18#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 7ad38171dc2b..6783a2043555 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -102,7 +102,7 @@ void strlist__remove(struct strlist *self, struct str_node *sn)
102 str_node__delete(sn, self->dupstr); 102 str_node__delete(sn, self->dupstr);
103} 103}
104 104
105bool strlist__has_entry(struct strlist *self, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
106{ 106{
107 struct rb_node **p = &self->entries.rb_node; 107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL; 108 struct rb_node *parent = NULL;
@@ -120,10 +120,10 @@ bool strlist__has_entry(struct strlist *self, const char *entry)
120 else if (rc < 0) 120 else if (rc < 0)
121 p = &(*p)->rb_right; 121 p = &(*p)->rb_right;
122 else 122 else
123 return true; 123 return sn;
124 } 124 }
125 125
126 return false; 126 return NULL;
127} 127}
128 128
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 921818e44a54..3ba839007d2c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,5 +1,5 @@
1#ifndef STRLIST_H_ 1#ifndef __PERF_STRLIST_H
2#define STRLIST_H_ 2#define __PERF_STRLIST_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
@@ -23,7 +23,12 @@ int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
24 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry); 26struct str_node *strlist__find(struct strlist *self, const char *entry);
27
28static inline bool strlist__has_entry(struct strlist *self, const char *entry)
29{
30 return strlist__find(self, entry) != NULL;
31}
27 32
28static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
29{ 34{
@@ -35,5 +40,39 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
35 return self->nr_entries; 40 return self->nr_entries;
36} 41}
37 42
43/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self)
45{
46 struct rb_node *rn = rb_first(&self->entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48}
49static inline struct str_node *strlist__next(struct str_node *sn)
50{
51 struct rb_node *rn;
52 if (!sn)
53 return NULL;
54 rn = rb_next(&sn->rb_node);
55 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
56}
57
58/**
59 * strlist_for_each - iterate over a strlist
60 * @pos: the &struct str_node to use as a loop cursor.
61 * @self: the &struct strlist for loop.
62 */
63#define strlist__for_each(pos, self) \
64 for (pos = strlist__first(self); pos; pos = strlist__next(pos))
65
66/**
67 * strlist_for_each_safe - iterate over a strlist safe against removal of
68 * str_node
69 * @pos: the &struct str_node to use as a loop cursor.
70 * @n: another &struct str_node to use as temporary storage.
71 * @self: the &struct strlist for loop.
72 */
73#define strlist__for_each_safe(pos, n, self) \
74 for (pos = strlist__first(self), n = strlist__next(pos); pos;\
75 pos = n, n = strlist__next(n))
76
38int strlist__parse_list(struct strlist *self, const char *s); 77int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index cd93195aedb3..e0781989cc31 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,5 +1,5 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_ 1#ifndef __PERF_SVGHELPER_H
2#define _INCLUDE_GUARD_SVG_HELPER_ 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -25,4 +25,4 @@ extern void svg_close(void);
25 25
26extern int svg_page_width; 26extern int svg_page_width;
27 27
28#endif 28#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 226f44a2357d..c458c4a371d1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,111 +1,234 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "sort.h"
3#include "string.h" 4#include "string.h"
4#include "symbol.h" 5#include "symbol.h"
6#include "thread.h"
5 7
6#include "debug.h" 8#include "debug.h"
7 9
10#include <asm/bug.h>
8#include <libelf.h> 11#include <libelf.h>
9#include <gelf.h> 12#include <gelf.h>
10#include <elf.h> 13#include <elf.h>
14#include <limits.h>
15#include <sys/utsname.h>
11 16
12const char *sym_hist_filter; 17#ifndef NT_GNU_BUILD_ID
18#define NT_GNU_BUILD_ID 3
19#endif
13 20
14enum dso_origin { 21enum dso_origin {
15 DSO__ORIG_KERNEL = 0, 22 DSO__ORIG_KERNEL = 0,
16 DSO__ORIG_JAVA_JIT, 23 DSO__ORIG_JAVA_JIT,
24 DSO__ORIG_BUILD_ID_CACHE,
17 DSO__ORIG_FEDORA, 25 DSO__ORIG_FEDORA,
18 DSO__ORIG_UBUNTU, 26 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID, 27 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO, 28 DSO__ORIG_DSO,
29 DSO__ORIG_KMODULE,
21 DSO__ORIG_NOT_FOUND, 30 DSO__ORIG_NOT_FOUND,
22}; 31};
23 32
24static struct symbol *symbol__new(u64 start, u64 len, 33static void dsos__add(struct list_head *head, struct dso *dso);
25 const char *name, unsigned int priv_size, 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
26 u64 obj_start, int v) 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 symbol_filter_t filter);
37static int vmlinux_path__nr_entries;
38static char **vmlinux_path;
39
40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
42 .use_modules = true,
43 .try_vmlinux_path = true,
44};
45
46bool dso__loaded(const struct dso *self, enum map_type type)
27{ 47{
28 size_t namelen = strlen(name) + 1; 48 return self->loaded & (1 << type);
29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 49}
30 50
31 if (!self) 51bool dso__sorted_by_name(const struct dso *self, enum map_type type)
32 return NULL; 52{
53 return self->sorted_by_name & (1 << type);
54}
55
56static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
57{
58 self->sorted_by_name |= (1 << type);
59}
60
61bool symbol_type__is_a(char symbol_type, enum map_type map_type)
62{
63 switch (map_type) {
64 case MAP__FUNCTION:
65 return symbol_type == 'T' || symbol_type == 'W';
66 case MAP__VARIABLE:
67 return symbol_type == 'D' || symbol_type == 'd';
68 default:
69 return false;
70 }
71}
33 72
34 if (v >= 2) 73static void symbols__fixup_end(struct rb_root *self)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 74{
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 75 struct rb_node *nd, *prevnd = rb_first(self);
76 struct symbol *curr, *prev;
37 77
38 self->obj_start= obj_start; 78 if (prevnd == NULL)
39 self->hist = NULL; 79 return;
40 self->hist_sum = 0;
41 80
42 if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 81 curr = rb_entry(prevnd, struct symbol, rb_node);
43 self->hist = calloc(sizeof(u64), len);
44 82
45 if (priv_size) { 83 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
46 memset(self, 0, priv_size); 84 prev = curr;
47 self = ((void *)self) + priv_size; 85 curr = rb_entry(nd, struct symbol, rb_node);
86
87 if (prev->end == prev->start)
88 prev->end = curr->start - 1;
48 } 89 }
90
91 /* Last entry */
92 if (curr->end == curr->start)
93 curr->end = roundup(curr->start, 4096);
94}
95
96static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
97{
98 struct map *prev, *curr;
99 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
100
101 if (prevnd == NULL)
102 return;
103
104 curr = rb_entry(prevnd, struct map, rb_node);
105
106 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
107 prev = curr;
108 curr = rb_entry(nd, struct map, rb_node);
109 prev->end = curr->start - 1;
110 }
111
112 /*
113 * We still haven't the actual symbols, so guess the
114 * last map final address.
115 */
116 curr->end = ~0UL;
117}
118
119static void map_groups__fixup_end(struct map_groups *self)
120{
121 int i;
122 for (i = 0; i < MAP__NR_TYPES; ++i)
123 __map_groups__fixup_end(self, i);
124}
125
126static struct symbol *symbol__new(u64 start, u64 len, const char *name)
127{
128 size_t namelen = strlen(name) + 1;
129 struct symbol *self = zalloc(symbol_conf.priv_size +
130 sizeof(*self) + namelen);
131 if (self == NULL)
132 return NULL;
133
134 if (symbol_conf.priv_size)
135 self = ((void *)self) + symbol_conf.priv_size;
136
49 self->start = start; 137 self->start = start;
50 self->end = len ? start + len - 1 : start; 138 self->end = len ? start + len - 1 : start;
139
140 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
141
51 memcpy(self->name, name, namelen); 142 memcpy(self->name, name, namelen);
52 143
53 return self; 144 return self;
54} 145}
55 146
56static void symbol__delete(struct symbol *self, unsigned int priv_size) 147void symbol__delete(struct symbol *self)
57{ 148{
58 free(((void *)self) - priv_size); 149 free(((void *)self) - symbol_conf.priv_size);
59} 150}
60 151
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 152static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 153{
63 if (!self->module) 154 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 155 self->start, self->end, self->name);
66 else
67 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
68 self->start, self->end, self->name, self->module->name);
69} 156}
70 157
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 158void dso__set_long_name(struct dso *self, char *name)
72{ 159{
73 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 160 if (name == NULL)
161 return;
162 self->long_name = name;
163 self->long_name_len = strlen(name);
164}
165
166static void dso__set_short_name(struct dso *self, const char *name)
167{
168 if (name == NULL)
169 return;
170 self->short_name = name;
171 self->short_name_len = strlen(name);
172}
173
174static void dso__set_basename(struct dso *self)
175{
176 dso__set_short_name(self, basename(self->long_name));
177}
178
179struct dso *dso__new(const char *name)
180{
181 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
74 182
75 if (self != NULL) { 183 if (self != NULL) {
184 int i;
76 strcpy(self->name, name); 185 strcpy(self->name, name);
77 self->syms = RB_ROOT; 186 dso__set_long_name(self, self->name);
78 self->sym_priv_size = sym_priv_size; 187 dso__set_short_name(self, self->name);
79 self->find_symbol = dso__find_symbol; 188 for (i = 0; i < MAP__NR_TYPES; ++i)
189 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
80 self->slen_calculated = 0; 190 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND; 191 self->origin = DSO__ORIG_NOT_FOUND;
192 self->loaded = 0;
193 self->sorted_by_name = 0;
194 self->has_build_id = 0;
82 } 195 }
83 196
84 return self; 197 return self;
85} 198}
86 199
87static void dso__delete_symbols(struct dso *self) 200static void symbols__delete(struct rb_root *self)
88{ 201{
89 struct symbol *pos; 202 struct symbol *pos;
90 struct rb_node *next = rb_first(&self->syms); 203 struct rb_node *next = rb_first(self);
91 204
92 while (next) { 205 while (next) {
93 pos = rb_entry(next, struct symbol, rb_node); 206 pos = rb_entry(next, struct symbol, rb_node);
94 next = rb_next(&pos->rb_node); 207 next = rb_next(&pos->rb_node);
95 rb_erase(&pos->rb_node, &self->syms); 208 rb_erase(&pos->rb_node, self);
96 symbol__delete(pos, self->sym_priv_size); 209 symbol__delete(pos);
97 } 210 }
98} 211}
99 212
100void dso__delete(struct dso *self) 213void dso__delete(struct dso *self)
101{ 214{
102 dso__delete_symbols(self); 215 int i;
216 for (i = 0; i < MAP__NR_TYPES; ++i)
217 symbols__delete(&self->symbols[i]);
218 if (self->long_name != self->name)
219 free(self->long_name);
103 free(self); 220 free(self);
104} 221}
105 222
106static void dso__insert_symbol(struct dso *self, struct symbol *sym) 223void dso__set_build_id(struct dso *self, void *build_id)
107{ 224{
108 struct rb_node **p = &self->syms.rb_node; 225 memcpy(self->build_id, build_id, sizeof(self->build_id));
226 self->has_build_id = 1;
227}
228
229static void symbols__insert(struct rb_root *self, struct symbol *sym)
230{
231 struct rb_node **p = &self->rb_node;
109 struct rb_node *parent = NULL; 232 struct rb_node *parent = NULL;
110 const u64 ip = sym->start; 233 const u64 ip = sym->start;
111 struct symbol *s; 234 struct symbol *s;
@@ -119,17 +242,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
119 p = &(*p)->rb_right; 242 p = &(*p)->rb_right;
120 } 243 }
121 rb_link_node(&sym->rb_node, parent, p); 244 rb_link_node(&sym->rb_node, parent, p);
122 rb_insert_color(&sym->rb_node, &self->syms); 245 rb_insert_color(&sym->rb_node, self);
123} 246}
124 247
125struct symbol *dso__find_symbol(struct dso *self, u64 ip) 248static struct symbol *symbols__find(struct rb_root *self, u64 ip)
126{ 249{
127 struct rb_node *n; 250 struct rb_node *n;
128 251
129 if (self == NULL) 252 if (self == NULL)
130 return NULL; 253 return NULL;
131 254
132 n = self->syms.rb_node; 255 n = self->rb_node;
133 256
134 while (n) { 257 while (n) {
135 struct symbol *s = rb_entry(n, struct symbol, rb_node); 258 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -145,12 +268,120 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
145 return NULL; 268 return NULL;
146} 269}
147 270
148size_t dso__fprintf(struct dso *self, FILE *fp) 271struct symbol_name_rb_node {
272 struct rb_node rb_node;
273 struct symbol sym;
274};
275
276static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
277{
278 struct rb_node **p = &self->rb_node;
279 struct rb_node *parent = NULL;
280 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
281
282 while (*p != NULL) {
283 parent = *p;
284 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
285 if (strcmp(sym->name, s->sym.name) < 0)
286 p = &(*p)->rb_left;
287 else
288 p = &(*p)->rb_right;
289 }
290 rb_link_node(&symn->rb_node, parent, p);
291 rb_insert_color(&symn->rb_node, self);
292}
293
294static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
295{
296 struct rb_node *nd;
297
298 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
299 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
300 symbols__insert_by_name(self, pos);
301 }
302}
303
304static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
305{
306 struct rb_node *n;
307
308 if (self == NULL)
309 return NULL;
310
311 n = self->rb_node;
312
313 while (n) {
314 struct symbol_name_rb_node *s;
315 int cmp;
316
317 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
318 cmp = strcmp(name, s->sym.name);
319
320 if (cmp < 0)
321 n = n->rb_left;
322 else if (cmp > 0)
323 n = n->rb_right;
324 else
325 return &s->sym;
326 }
327
328 return NULL;
329}
330
331struct symbol *dso__find_symbol(struct dso *self,
332 enum map_type type, u64 addr)
333{
334 return symbols__find(&self->symbols[type], addr);
335}
336
337struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
338 const char *name)
339{
340 return symbols__find_by_name(&self->symbol_names[type], name);
341}
342
343void dso__sort_by_name(struct dso *self, enum map_type type)
344{
345 dso__set_sorted_by_name(self, type);
346 return symbols__sort_by_name(&self->symbol_names[type],
347 &self->symbols[type]);
348}
349
350int build_id__sprintf(const u8 *self, int len, char *bf)
351{
352 char *bid = bf;
353 const u8 *raw = self;
354 int i;
355
356 for (i = 0; i < len; ++i) {
357 sprintf(bid, "%02x", *raw);
358 ++raw;
359 bid += 2;
360 }
361
362 return raw - self;
363}
364
365size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
149{ 366{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 367 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
368
369 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
370 return fprintf(fp, "%s", sbuild_id);
371}
151 372
373size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
374{
152 struct rb_node *nd; 375 struct rb_node *nd;
153 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 376 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
377
378 if (self->short_name != self->long_name)
379 ret += fprintf(fp, "%s, ", self->long_name);
380 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
381 self->loaded ? "" : "NOT ");
382 ret += dso__fprintf_buildid(self, fp);
383 ret += fprintf(fp, ")\n");
384 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
154 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 385 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
155 ret += symbol__fprintf(pos, fp); 386 ret += symbol__fprintf(pos, fp);
156 } 387 }
@@ -158,22 +389,23 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 389 return ret;
159} 390}
160 391
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 392int kallsyms__parse(const char *filename, void *arg,
393 int (*process_symbol)(void *arg, const char *name,
394 char type, u64 start))
162{ 395{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 396 char *line = NULL;
165 size_t n; 397 size_t n;
166 FILE *file = fopen("/proc/kallsyms", "r"); 398 int err = 0;
167 int count = 0; 399 FILE *file = fopen(filename, "r");
168 400
169 if (file == NULL) 401 if (file == NULL)
170 goto out_failure; 402 goto out_failure;
171 403
172 while (!feof(file)) { 404 while (!feof(file)) {
173 u64 start; 405 u64 start;
174 struct symbol *sym;
175 int line_len, len; 406 int line_len, len;
176 char symbol_type; 407 char symbol_type;
408 char *symbol_name;
177 409
178 line_len = getline(&line, &n, file); 410 line_len = getline(&line, &n, file);
179 if (line_len < 0) 411 if (line_len < 0)
@@ -191,64 +423,168 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
191 continue; 423 continue;
192 424
193 symbol_type = toupper(line[len]); 425 symbol_type = toupper(line[len]);
194 /* 426 symbol_name = line + len + 2;
195 * We're interested only in code ('T'ext)
196 */
197 if (symbol_type != 'T' && symbol_type != 'W')
198 continue;
199 /*
200 * Well fix up the end later, when we have all sorted.
201 */
202 sym = symbol__new(start, 0xdead, line + len + 2,
203 self->sym_priv_size, 0, v);
204 427
205 if (sym == NULL) 428 err = process_symbol(arg, symbol_name, symbol_type, start);
206 goto out_delete_line; 429 if (err)
207 430 break;
208 if (filter && filter(self, sym))
209 symbol__delete(sym, self->sym_priv_size);
210 else {
211 dso__insert_symbol(self, sym);
212 count++;
213 }
214 } 431 }
215 432
433 free(line);
434 fclose(file);
435 return err;
436
437out_failure:
438 return -1;
439}
440
441struct process_kallsyms_args {
442 struct map *map;
443 struct dso *dso;
444};
445
446static int map__process_kallsym_symbol(void *arg, const char *name,
447 char type, u64 start)
448{
449 struct symbol *sym;
450 struct process_kallsyms_args *a = arg;
451 struct rb_root *root = &a->dso->symbols[a->map->type];
452
453 if (!symbol_type__is_a(type, a->map->type))
454 return 0;
455
216 /* 456 /*
217 * Now that we have all sorted out, just set the ->end of all 457 * Will fix up the end later, when we have all symbols sorted.
218 * symbols
219 */ 458 */
220 prevnd = rb_first(&self->syms); 459 sym = symbol__new(start, 0, name);
221 460
222 if (prevnd == NULL) 461 if (sym == NULL)
223 goto out_delete_line; 462 return -ENOMEM;
463 /*
464 * We will pass the symbols to the filter later, in
465 * map__split_kallsyms, when we have split the maps per module
466 */
467 symbols__insert(root, sym);
468 return 0;
469}
224 470
225 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 471/*
226 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), 472 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
227 *curr = rb_entry(nd, struct symbol, rb_node); 473 * so that we can in the next step set the symbol ->end address and then
474 * call kernel_maps__split_kallsyms.
475 */
476static int dso__load_all_kallsyms(struct dso *self, const char *filename,
477 struct map *map)
478{
479 struct process_kallsyms_args args = { .map = map, .dso = self, };
480 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
481}
228 482
229 prev->end = curr->start - 1; 483/*
230 prevnd = nd; 484 * Split the symbols into maps, making sure there are no overlaps, i.e. the
231 } 485 * kernel range is broken in several maps, named [kernel].N, as we don't have
486 * the original ELF section names vmlinux have.
487 */
488static int dso__split_kallsyms(struct dso *self, struct map *map,
489 symbol_filter_t filter)
490{
491 struct map_groups *kmaps = map__kmap(map)->kmaps;
492 struct map *curr_map = map;
493 struct symbol *pos;
494 int count = 0;
495 struct rb_root *root = &self->symbols[map->type];
496 struct rb_node *next = rb_first(root);
497 int kernel_range = 0;
232 498
233 free(line); 499 while (next) {
234 fclose(file); 500 char *module;
501
502 pos = rb_entry(next, struct symbol, rb_node);
503 next = rb_next(&pos->rb_node);
504
505 module = strchr(pos->name, '\t');
506 if (module) {
507 if (!symbol_conf.use_modules)
508 goto discard_symbol;
509
510 *module++ = '\0';
511
512 if (strcmp(curr_map->dso->short_name, module)) {
513 curr_map = map_groups__find_by_name(kmaps, map->type, module);
514 if (curr_map == NULL) {
515 pr_debug("/proc/{kallsyms,modules} "
516 "inconsistency while looking "
517 "for \"%s\" module!\n", module);
518 return -1;
519 }
520
521 if (curr_map->dso->loaded)
522 goto discard_symbol;
523 }
524 /*
525 * So that we look just like we get from .ko files,
526 * i.e. not prelinked, relative to map->start.
527 */
528 pos->start = curr_map->map_ip(curr_map, pos->start);
529 pos->end = curr_map->map_ip(curr_map, pos->end);
530 } else if (curr_map != map) {
531 char dso_name[PATH_MAX];
532 struct dso *dso;
533
534 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
535 kernel_range++);
536
537 dso = dso__new(dso_name);
538 if (dso == NULL)
539 return -1;
540
541 curr_map = map__new2(pos->start, dso, map->type);
542 if (curr_map == NULL) {
543 dso__delete(dso);
544 return -1;
545 }
546
547 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
548 map_groups__insert(kmaps, curr_map);
549 ++kernel_range;
550 }
551
552 if (filter && filter(curr_map, pos)) {
553discard_symbol: rb_erase(&pos->rb_node, root);
554 symbol__delete(pos);
555 } else {
556 if (curr_map != map) {
557 rb_erase(&pos->rb_node, root);
558 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
559 }
560 count++;
561 }
562 }
235 563
236 return count; 564 return count;
565}
237 566
238out_delete_line: 567int dso__load_kallsyms(struct dso *self, const char *filename,
239 free(line); 568 struct map *map, symbol_filter_t filter)
240out_failure: 569{
241 return -1; 570 if (dso__load_all_kallsyms(self, filename, map) < 0)
571 return -1;
572
573 symbols__fixup_end(&self->symbols[map->type]);
574 self->origin = DSO__ORIG_KERNEL;
575
576 return dso__split_kallsyms(self, map, filter);
242} 577}
243 578
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 579static int dso__load_perf_map(struct dso *self, struct map *map,
580 symbol_filter_t filter)
245{ 581{
246 char *line = NULL; 582 char *line = NULL;
247 size_t n; 583 size_t n;
248 FILE *file; 584 FILE *file;
249 int nr_syms = 0; 585 int nr_syms = 0;
250 586
251 file = fopen(self->name, "r"); 587 file = fopen(self->long_name, "r");
252 if (file == NULL) 588 if (file == NULL)
253 goto out_failure; 589 goto out_failure;
254 590
@@ -278,16 +614,15 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
278 if (len + 2 >= line_len) 614 if (len + 2 >= line_len)
279 continue; 615 continue;
280 616
281 sym = symbol__new(start, size, line + len, 617 sym = symbol__new(start, size, line + len);
282 self->sym_priv_size, start, v);
283 618
284 if (sym == NULL) 619 if (sym == NULL)
285 goto out_delete_line; 620 goto out_delete_line;
286 621
287 if (filter && filter(self, sym)) 622 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 623 symbol__delete(sym);
289 else { 624 else {
290 dso__insert_symbol(self, sym); 625 symbols__insert(&self->symbols[map->type], sym);
291 nr_syms++; 626 nr_syms++;
292 } 627 }
293 } 628 }
@@ -327,6 +662,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
327 sym->st_shndx != SHN_UNDEF; 662 sym->st_shndx != SHN_UNDEF;
328} 663}
329 664
665static inline bool elf_sym__is_object(const GElf_Sym *sym)
666{
667 return elf_sym__type(sym) == STT_OBJECT &&
668 sym->st_name != 0 &&
669 sym->st_shndx != SHN_UNDEF;
670}
671
330static inline int elf_sym__is_label(const GElf_Sym *sym) 672static inline int elf_sym__is_label(const GElf_Sym *sym)
331{ 673{
332 return elf_sym__type(sym) == STT_NOTYPE && 674 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -347,6 +689,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
347 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 689 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
348} 690}
349 691
692static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
693 const Elf_Data *secstrs)
694{
695 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
696}
697
350static inline const char *elf_sym__name(const GElf_Sym *sym, 698static inline const char *elf_sym__name(const GElf_Sym *sym,
351 const Elf_Data *symstrs) 699 const Elf_Data *symstrs)
352{ 700{
@@ -393,7 +741,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
393 * And always look at the original dso, not at debuginfo packages, that 741 * And always look at the original dso, not at debuginfo packages, that
394 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 742 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395 */ 743 */
396static int dso__synthesize_plt_symbols(struct dso *self, int v) 744static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
745 symbol_filter_t filter)
397{ 746{
398 uint32_t nr_rel_entries, idx; 747 uint32_t nr_rel_entries, idx;
399 GElf_Sym sym; 748 GElf_Sym sym;
@@ -409,7 +758,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 758 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 759 int nr = 0, symidx, fd, err = 0;
411 760
412 fd = open(self->name, O_RDONLY); 761 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 762 if (fd < 0)
414 goto out; 763 goto out;
415 764
@@ -477,12 +826,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 826 "%s@plt", elf_sym__name(&sym, symstrs));
478 827
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 828 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 829 sympltname);
481 if (!f) 830 if (!f)
482 goto out_elf_end; 831 goto out_elf_end;
483 832
484 dso__insert_symbol(self, f); 833 if (filter && filter(map, f))
485 ++nr; 834 symbol__delete(f);
835 else {
836 symbols__insert(&self->symbols[map->type], f);
837 ++nr;
838 }
486 } 839 }
487 } else if (shdr_rel_plt.sh_type == SHT_REL) { 840 } else if (shdr_rel_plt.sh_type == SHT_REL) {
488 GElf_Rel pos_mem, *pos; 841 GElf_Rel pos_mem, *pos;
@@ -495,12 +848,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 848 "%s@plt", elf_sym__name(&sym, symstrs));
496 849
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 850 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 851 sympltname);
499 if (!f) 852 if (!f)
500 goto out_elf_end; 853 goto out_elf_end;
501 854
502 dso__insert_symbol(self, f); 855 if (filter && filter(map, f))
503 ++nr; 856 symbol__delete(f);
857 else {
858 symbols__insert(&self->symbols[map->type], f);
859 ++nr;
860 }
504 } 861 }
505 } 862 }
506 863
@@ -513,14 +870,41 @@ out_close:
513 if (err == 0) 870 if (err == 0)
514 return nr; 871 return nr;
515out: 872out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 873 pr_warning("%s: problems reading %s PLT info.\n",
517 __func__, self->name); 874 __func__, self->long_name);
518 return 0; 875 return 0;
519} 876}
520 877
521static int dso__load_sym(struct dso *self, int fd, const char *name, 878static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
522 symbol_filter_t filter, int v, struct module *mod)
523{ 879{
880 switch (type) {
881 case MAP__FUNCTION:
882 return elf_sym__is_function(self);
883 case MAP__VARIABLE:
884 return elf_sym__is_object(self);
885 default:
886 return false;
887 }
888}
889
890static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
891{
892 switch (type) {
893 case MAP__FUNCTION:
894 return elf_sec__is_text(self, secstrs);
895 case MAP__VARIABLE:
896 return elf_sec__is_data(self, secstrs);
897 default:
898 return false;
899 }
900}
901
902static int dso__load_sym(struct dso *self, struct map *map, const char *name,
903 int fd, symbol_filter_t filter, int kmodule)
904{
905 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
906 struct map *curr_map = map;
907 struct dso *curr_dso = self;
524 Elf_Data *symstrs, *secstrs; 908 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 909 uint32_t nr_syms;
526 int err = -1; 910 int err = -1;
@@ -531,19 +915,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 915 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 916 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 917 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 918 int nr = 0;
535 919
536 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 920 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 921 if (elf == NULL) {
538 if (v) 922 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
539 fprintf(stderr, "%s: cannot read %s ELF file.\n",
540 __func__, name);
541 goto out_close; 923 goto out_close;
542 } 924 }
543 925
544 if (gelf_getehdr(elf, &ehdr) == NULL) { 926 if (gelf_getehdr(elf, &ehdr) == NULL) {
545 if (v) 927 pr_err("%s: cannot get elf header.\n", __func__);
546 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
547 goto out_elf_end; 928 goto out_elf_end;
548 } 929 }
549 930
@@ -577,7 +958,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
577 nr_syms = shdr.sh_size / shdr.sh_entsize; 958 nr_syms = shdr.sh_size / shdr.sh_entsize;
578 959
579 memset(&sym, 0, sizeof(sym)); 960 memset(&sym, 0, sizeof(sym));
580 if (!kernel) { 961 if (!self->kernel) {
581 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 962 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
582 elf_section_by_name(elf, &ehdr, &shdr, 963 elf_section_by_name(elf, &ehdr, &shdr,
583 ".gnu.prelink_undo", 964 ".gnu.prelink_undo",
@@ -586,14 +967,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
586 967
587 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 968 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 969 struct symbol *f;
589 const char *elf_name; 970 const char *elf_name = elf_sym__name(&sym, symstrs);
590 char *demangled; 971 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 972 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 973 const char *section_name;
595 974
596 if (!is_label && !elf_sym__is_function(&sym)) 975 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
976 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
977 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
978
979 if (!is_label && !elf_sym__is_a(&sym, map->type))
597 continue; 980 continue;
598 981
599 sec = elf_getscn(elf, sym.st_shndx); 982 sec = elf_getscn(elf, sym.st_shndx);
@@ -602,55 +985,98 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
602 985
603 gelf_getshdr(sec, &shdr); 986 gelf_getshdr(sec, &shdr);
604 987
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 988 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
606 continue; 989 continue;
607 990
608 section_name = elf_sec__name(&shdr, secstrs); 991 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 992
611 if (self->adjust_symbols) { 993 if (self->kernel || kmodule) {
612 if (v >= 2) 994 char dso_name[PATH_MAX];
613 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
614 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
615 995
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 996 if (strcmp(section_name,
617 } 997 (curr_dso->short_name +
998 self->short_name_len)) == 0)
999 goto new_symbol;
618 1000
619 if (mod) { 1001 if (strcmp(section_name, ".text") == 0) {
620 section = mod->sections->find_section(mod->sections, section_name); 1002 curr_map = map;
621 if (section) 1003 curr_dso = self;
622 sym.st_value += section->vma; 1004 goto new_symbol;
623 else {
624 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
625 mod->name, section_name);
626 goto out_elf_end;
627 } 1005 }
1006
1007 snprintf(dso_name, sizeof(dso_name),
1008 "%s%s", self->short_name, section_name);
1009
1010 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
1011 if (curr_map == NULL) {
1012 u64 start = sym.st_value;
1013
1014 if (kmodule)
1015 start += map->start + shdr.sh_offset;
1016
1017 curr_dso = dso__new(dso_name);
1018 if (curr_dso == NULL)
1019 goto out_elf_end;
1020 curr_map = map__new2(start, curr_dso,
1021 map->type);
1022 if (curr_map == NULL) {
1023 dso__delete(curr_dso);
1024 goto out_elf_end;
1025 }
1026 curr_map->map_ip = identity__map_ip;
1027 curr_map->unmap_ip = identity__map_ip;
1028 curr_dso->origin = DSO__ORIG_KERNEL;
1029 map_groups__insert(kmap->kmaps, curr_map);
1030 dsos__add(&dsos__kernel, curr_dso);
1031 dso__set_loaded(curr_dso, map->type);
1032 } else
1033 curr_dso = curr_map->dso;
1034
1035 goto new_symbol;
1036 }
1037
1038 if (curr_dso->adjust_symbols) {
1039 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1040 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1041 (u64)sym.st_value, (u64)shdr.sh_addr,
1042 (u64)shdr.sh_offset);
1043 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
628 } 1044 }
629 /* 1045 /*
630 * We need to figure out if the object was created from C++ sources 1046 * We need to figure out if the object was created from C++ sources
631 * DWARF DW_compile_unit has this, but we don't always have access 1047 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 1048 * to it...
633 */ 1049 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 1050 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 1051 if (demangled != NULL)
637 elf_name = demangled; 1052 elf_name = demangled;
638 1053new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 1054 f = symbol__new(sym.st_value, sym.st_size, elf_name);
640 self->sym_priv_size, obj_start, v);
641 free(demangled); 1055 free(demangled);
642 if (!f) 1056 if (!f)
643 goto out_elf_end; 1057 goto out_elf_end;
644 1058
645 if (filter && filter(self, f)) 1059 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 1060 symbol__delete(f);
647 else { 1061 else {
648 f->module = mod; 1062 symbols__insert(&curr_dso->symbols[curr_map->type], f);
649 dso__insert_symbol(self, f);
650 nr++; 1063 nr++;
651 } 1064 }
652 } 1065 }
653 1066
1067 /*
1068 * For misannotated, zeroed, ASM function sizes.
1069 */
1070 if (nr > 0) {
1071 symbols__fixup_end(&self->symbols[map->type]);
1072 if (kmap) {
1073 /*
1074 * We need to fixup this here too because we create new
1075 * maps here, for things like vsyscall sections.
1076 */
1077 __map_groups__fixup_end(kmap->kmaps, map->type);
1078 }
1079 }
654 err = nr; 1080 err = nr;
655out_elf_end: 1081out_elf_end:
656 elf_end(elf); 1082 elf_end(elf);
@@ -658,63 +1084,157 @@ out_close:
658 return err; 1084 return err;
659} 1085}
660 1086
661#define BUILD_ID_SIZE 128 1087static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1088{
1089 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1090}
662 1091
663static char *dso__read_build_id(struct dso *self, int v) 1092static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
664{ 1093{
665 int i; 1094 bool have_build_id = false;
1095 struct dso *pos;
1096
1097 list_for_each_entry(pos, head, node) {
1098 if (with_hits && !pos->hit)
1099 continue;
1100 if (filename__read_build_id(pos->long_name, pos->build_id,
1101 sizeof(pos->build_id)) > 0) {
1102 have_build_id = true;
1103 pos->has_build_id = true;
1104 }
1105 }
1106
1107 return have_build_id;
1108}
1109
1110bool dsos__read_build_ids(bool with_hits)
1111{
1112 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1113 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
1114 return kbuildids || ubuildids;
1115}
1116
1117/*
1118 * Align offset to 4 bytes as needed for note name and descriptor data.
1119 */
1120#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1121
1122int filename__read_build_id(const char *filename, void *bf, size_t size)
1123{
1124 int fd, err = -1;
666 GElf_Ehdr ehdr; 1125 GElf_Ehdr ehdr;
667 GElf_Shdr shdr; 1126 GElf_Shdr shdr;
668 Elf_Data *build_id_data; 1127 Elf_Data *data;
669 Elf_Scn *sec; 1128 Elf_Scn *sec;
670 char *build_id = NULL, *bid; 1129 Elf_Kind ek;
671 unsigned char *raw; 1130 void *ptr;
672 Elf *elf; 1131 Elf *elf;
673 int fd = open(self->name, O_RDONLY);
674 1132
1133 if (size < BUILD_ID_SIZE)
1134 goto out;
1135
1136 fd = open(filename, O_RDONLY);
675 if (fd < 0) 1137 if (fd < 0)
676 goto out; 1138 goto out;
677 1139
678 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1140 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
679 if (elf == NULL) { 1141 if (elf == NULL) {
680 if (v) 1142 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
681 fprintf(stderr, "%s: cannot read %s ELF file.\n",
682 __func__, self->name);
683 goto out_close; 1143 goto out_close;
684 } 1144 }
685 1145
1146 ek = elf_kind(elf);
1147 if (ek != ELF_K_ELF)
1148 goto out_elf_end;
1149
686 if (gelf_getehdr(elf, &ehdr) == NULL) { 1150 if (gelf_getehdr(elf, &ehdr) == NULL) {
687 if (v) 1151 pr_err("%s: cannot get elf header.\n", __func__);
688 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
689 goto out_elf_end; 1152 goto out_elf_end;
690 } 1153 }
691 1154
692 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 1155 sec = elf_section_by_name(elf, &ehdr, &shdr,
693 if (sec == NULL) 1156 ".note.gnu.build-id", NULL);
694 goto out_elf_end; 1157 if (sec == NULL) {
1158 sec = elf_section_by_name(elf, &ehdr, &shdr,
1159 ".notes", NULL);
1160 if (sec == NULL)
1161 goto out_elf_end;
1162 }
695 1163
696 build_id_data = elf_getdata(sec, NULL); 1164 data = elf_getdata(sec, NULL);
697 if (build_id_data == NULL) 1165 if (data == NULL)
698 goto out_elf_end; 1166 goto out_elf_end;
699 build_id = malloc(BUILD_ID_SIZE);
700 if (build_id == NULL)
701 goto out_elf_end;
702 raw = build_id_data->d_buf + 16;
703 bid = build_id;
704 1167
705 for (i = 0; i < 20; ++i) { 1168 ptr = data->d_buf;
706 sprintf(bid, "%02x", *raw); 1169 while (ptr < (data->d_buf + data->d_size)) {
707 ++raw; 1170 GElf_Nhdr *nhdr = ptr;
708 bid += 2; 1171 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1172 descsz = NOTE_ALIGN(nhdr->n_descsz);
1173 const char *name;
1174
1175 ptr += sizeof(*nhdr);
1176 name = ptr;
1177 ptr += namesz;
1178 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1179 nhdr->n_namesz == sizeof("GNU")) {
1180 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1181 memcpy(bf, ptr, BUILD_ID_SIZE);
1182 err = BUILD_ID_SIZE;
1183 break;
1184 }
1185 }
1186 ptr += descsz;
709 } 1187 }
710 if (v >= 2)
711 printf("%s(%s): %s\n", __func__, self->name, build_id);
712out_elf_end: 1188out_elf_end:
713 elf_end(elf); 1189 elf_end(elf);
714out_close: 1190out_close:
715 close(fd); 1191 close(fd);
716out: 1192out:
717 return build_id; 1193 return err;
1194}
1195
1196int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1197{
1198 int fd, err = -1;
1199
1200 if (size < BUILD_ID_SIZE)
1201 goto out;
1202
1203 fd = open(filename, O_RDONLY);
1204 if (fd < 0)
1205 goto out;
1206
1207 while (1) {
1208 char bf[BUFSIZ];
1209 GElf_Nhdr nhdr;
1210 int namesz, descsz;
1211
1212 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1213 break;
1214
1215 namesz = NOTE_ALIGN(nhdr.n_namesz);
1216 descsz = NOTE_ALIGN(nhdr.n_descsz);
1217 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1218 nhdr.n_namesz == sizeof("GNU")) {
1219 if (read(fd, bf, namesz) != namesz)
1220 break;
1221 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1222 if (read(fd, build_id,
1223 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1224 err = 0;
1225 break;
1226 }
1227 } else if (read(fd, bf, descsz) != descsz)
1228 break;
1229 } else {
1230 int n = namesz + descsz;
1231 if (read(fd, bf, n) != n)
1232 break;
1233 }
1234 }
1235 close(fd);
1236out:
1237 return err;
718} 1238}
719 1239
720char dso__symtab_origin(const struct dso *self) 1240char dso__symtab_origin(const struct dso *self)
@@ -722,10 +1242,12 @@ char dso__symtab_origin(const struct dso *self)
722 static const char origin[] = { 1242 static const char origin[] = {
723 [DSO__ORIG_KERNEL] = 'k', 1243 [DSO__ORIG_KERNEL] = 'k',
724 [DSO__ORIG_JAVA_JIT] = 'j', 1244 [DSO__ORIG_JAVA_JIT] = 'j',
1245 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
725 [DSO__ORIG_FEDORA] = 'f', 1246 [DSO__ORIG_FEDORA] = 'f',
726 [DSO__ORIG_UBUNTU] = 'u', 1247 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 1248 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 1249 [DSO__ORIG_DSO] = 'd',
1250 [DSO__ORIG_KMODULE] = 'K',
729 }; 1251 };
730 1252
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1253 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,60 +1255,90 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 1255 return origin[self->origin];
734} 1256}
735 1257
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 1258int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
737{ 1259{
738 int size = PATH_MAX; 1260 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 1261 char *name;
1262 u8 build_id[BUILD_ID_SIZE];
1263 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
740 int ret = -1; 1264 int ret = -1;
741 int fd; 1265 int fd;
742 1266
1267 dso__set_loaded(self, map->type);
1268
1269 if (self->kernel)
1270 return dso__load_kernel_sym(self, map, filter);
1271
1272 name = malloc(size);
743 if (!name) 1273 if (!name)
744 return -1; 1274 return -1;
745 1275
746 self->adjust_symbols = 0; 1276 self->adjust_symbols = 0;
747 1277
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1278 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 1279 ret = dso__load_perf_map(self, map, filter);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1280 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 1281 DSO__ORIG_NOT_FOUND;
752 return ret; 1282 return ret;
753 } 1283 }
754 1284
755 self->origin = DSO__ORIG_FEDORA - 1; 1285 self->origin = DSO__ORIG_BUILD_ID_CACHE;
756 1286
1287 if (self->has_build_id) {
1288 build_id__sprintf(self->build_id, sizeof(self->build_id),
1289 build_id_hex);
1290 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1291 getenv("HOME"), DEBUG_CACHE_DIR,
1292 build_id_hex, build_id_hex + 2);
1293 goto open_file;
1294 }
757more: 1295more:
758 do { 1296 do {
759 self->origin++; 1297 self->origin++;
760 switch (self->origin) { 1298 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 1299 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 1300 snprintf(name, size, "/usr/lib/debug%s.debug",
1301 self->long_name);
763 break; 1302 break;
764 case DSO__ORIG_UBUNTU: 1303 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 1304 snprintf(name, size, "/usr/lib/debug%s",
1305 self->long_name);
766 break; 1306 break;
767 case DSO__ORIG_BUILDID: 1307 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 1308 if (filename__read_build_id(self->long_name, build_id,
769 if (build_id != NULL) { 1309 sizeof(build_id))) {
1310 build_id__sprintf(build_id, sizeof(build_id),
1311 build_id_hex);
770 snprintf(name, size, 1312 snprintf(name, size,
771 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1313 "/usr/lib/debug/.build-id/%.2s/%s.debug",
772 build_id, build_id + 2); 1314 build_id_hex, build_id_hex + 2);
773 free(build_id); 1315 if (self->has_build_id)
1316 goto compare_build_id;
774 break; 1317 break;
775 } 1318 }
776 self->origin++; 1319 self->origin++;
777 /* Fall thru */ 1320 /* Fall thru */
778 case DSO__ORIG_DSO: 1321 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 1322 snprintf(name, size, "%s", self->long_name);
780 break; 1323 break;
781 1324
782 default: 1325 default:
783 goto out; 1326 goto out;
784 } 1327 }
785 1328
1329 if (self->has_build_id) {
1330 if (filename__read_build_id(name, build_id,
1331 sizeof(build_id)) < 0)
1332 goto more;
1333compare_build_id:
1334 if (!dso__build_id_equal(self, build_id))
1335 goto more;
1336 }
1337open_file:
786 fd = open(name, O_RDONLY); 1338 fd = open(name, O_RDONLY);
787 } while (fd < 0); 1339 } while (fd < 0);
788 1340
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 1341 ret = dso__load_sym(self, map, name, fd, filter, 0);
790 close(fd); 1342 close(fd);
791 1343
792 /* 1344 /*
@@ -796,7 +1348,7 @@ more:
796 goto more; 1348 goto more;
797 1349
798 if (ret > 0) { 1350 if (ret > 0) {
799 int nr_plt = dso__synthesize_plt_symbols(self, v); 1351 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
800 if (nr_plt > 0) 1352 if (nr_plt > 0)
801 ret += nr_plt; 1353 ret += nr_plt;
802 } 1354 }
@@ -807,231 +1359,608 @@ out:
807 return ret; 1359 return ret;
808} 1360}
809 1361
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 1362struct map *map_groups__find_by_name(struct map_groups *self,
811 symbol_filter_t filter, int v) 1363 enum map_type type, const char *name)
812{ 1364{
813 struct module *mod = mod_dso__find_module(mods, name); 1365 struct rb_node *nd;
814 int err = 0, fd;
815 1366
816 if (mod == NULL || !mod->active) 1367 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
817 return err; 1368 struct map *map = rb_entry(nd, struct map, rb_node);
818 1369
819 fd = open(mod->path, O_RDONLY); 1370 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1371 return map;
1372 }
820 1373
821 if (fd < 0) 1374 return NULL;
822 return err; 1375}
823 1376
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1377static int dso__kernel_module_get_build_id(struct dso *self)
825 close(fd); 1378{
1379 char filename[PATH_MAX];
1380 /*
1381 * kernel module short names are of the form "[module]" and
1382 * we need just "module" here.
1383 */
1384 const char *name = self->short_name + 1;
826 1385
827 return err; 1386 snprintf(filename, sizeof(filename),
1387 "/sys/module/%.*s/notes/.note.gnu.build-id",
1388 (int)strlen(name - 1), name);
1389
1390 if (sysfs__read_build_id(filename, self->build_id,
1391 sizeof(self->build_id)) == 0)
1392 self->has_build_id = true;
1393
1394 return 0;
828} 1395}
829 1396
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1397static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
831{ 1398{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1399 struct dirent *dent;
833 struct module *pos; 1400 DIR *dir = opendir(dirname);
834 struct rb_node *next;
835 int err, count = 0;
836 1401
837 err = mod_dso__load_modules(mods); 1402 if (!dir) {
1403 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1404 return -1;
1405 }
838 1406
839 if (err <= 0) 1407 while ((dent = readdir(dir)) != NULL) {
840 return err; 1408 char path[PATH_MAX];
1409
1410 if (dent->d_type == DT_DIR) {
1411 if (!strcmp(dent->d_name, ".") ||
1412 !strcmp(dent->d_name, ".."))
1413 continue;
1414
1415 snprintf(path, sizeof(path), "%s/%s",
1416 dirname, dent->d_name);
1417 if (map_groups__set_modules_path_dir(self, path) < 0)
1418 goto failure;
1419 } else {
1420 char *dot = strrchr(dent->d_name, '.'),
1421 dso_name[PATH_MAX];
1422 struct map *map;
1423 char *long_name;
1424
1425 if (dot == NULL || strcmp(dot, ".ko"))
1426 continue;
1427 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1428 (int)(dot - dent->d_name), dent->d_name);
1429
1430 strxfrchar(dso_name, '-', '_');
1431 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1432 if (map == NULL)
1433 continue;
1434
1435 snprintf(path, sizeof(path), "%s/%s",
1436 dirname, dent->d_name);
1437
1438 long_name = strdup(path);
1439 if (long_name == NULL)
1440 goto failure;
1441 dso__set_long_name(map->dso, long_name);
1442 dso__kernel_module_get_build_id(map->dso);
1443 }
1444 }
841 1445
842 /* 1446 return 0;
843 * Iterate over modules, and load active symbols. 1447failure:
844 */ 1448 closedir(dir);
845 next = rb_first(&mods->mods); 1449 return -1;
846 while (next) { 1450}
847 pos = rb_entry(next, struct module, rb_node);
848 err = dso__load_module(self, mods, pos->name, filter, v);
849 1451
850 if (err < 0) 1452static int map_groups__set_modules_path(struct map_groups *self)
851 break; 1453{
1454 struct utsname uts;
1455 char modules_path[PATH_MAX];
852 1456
853 next = rb_next(&pos->rb_node); 1457 if (uname(&uts) < 0)
854 count += err; 1458 return -1;
855 } 1459
1460 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1461 uts.release);
1462
1463 return map_groups__set_modules_path_dir(self, modules_path);
1464}
856 1465
857 if (err < 0) { 1466/*
858 mod_dso__delete_modules(mods); 1467 * Constructor variant for modules (where we know from /proc/modules where
859 mod_dso__delete_self(mods); 1468 * they are loaded) and for vmlinux, where only after we load all the
860 return err; 1469 * symbols we'll know where it starts and ends.
1470 */
1471static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1472{
1473 struct map *self = zalloc(sizeof(*self) +
1474 (dso->kernel ? sizeof(struct kmap) : 0));
1475 if (self != NULL) {
1476 /*
1477 * ->end will be filled after we load all the symbols
1478 */
1479 map__init(self, type, start, 0, 0, dso);
861 } 1480 }
862 1481
863 return count; 1482 return self;
864} 1483}
865 1484
866static inline void dso__fill_symbol_holes(struct dso *self) 1485struct map *map_groups__new_module(struct map_groups *self, u64 start,
1486 const char *filename)
867{ 1487{
868 struct symbol *prev = NULL; 1488 struct map *map;
869 struct rb_node *nd; 1489 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
870 1490
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1491 if (dso == NULL)
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1492 return NULL;
873 1493
874 if (prev) { 1494 map = map__new2(start, dso, MAP__FUNCTION);
875 u64 hole = 0; 1495 if (map == NULL)
876 int alias = pos->start == prev->start; 1496 return NULL;
877 1497
878 if (!alias) 1498 dso->origin = DSO__ORIG_KMODULE;
879 hole = prev->start - pos->end - 1; 1499 map_groups__insert(self, map);
1500 return map;
1501}
880 1502
881 if (hole || alias) { 1503static int map_groups__create_modules(struct map_groups *self)
882 if (alias) 1504{
883 pos->end = prev->end; 1505 char *line = NULL;
884 else if (hole) 1506 size_t n;
885 pos->end = prev->start - 1; 1507 FILE *file = fopen("/proc/modules", "r");
886 } 1508 struct map *map;
887 } 1509
888 prev = pos; 1510 if (file == NULL)
1511 return -1;
1512
1513 while (!feof(file)) {
1514 char name[PATH_MAX];
1515 u64 start;
1516 char *sep;
1517 int line_len;
1518
1519 line_len = getline(&line, &n, file);
1520 if (line_len < 0)
1521 break;
1522
1523 if (!line)
1524 goto out_failure;
1525
1526 line[--line_len] = '\0'; /* \n */
1527
1528 sep = strrchr(line, 'x');
1529 if (sep == NULL)
1530 continue;
1531
1532 hex2u64(sep + 1, &start);
1533
1534 sep = strchr(line, ' ');
1535 if (sep == NULL)
1536 continue;
1537
1538 *sep = '\0';
1539
1540 snprintf(name, sizeof(name), "[%s]", line);
1541 map = map_groups__new_module(self, start, name);
1542 if (map == NULL)
1543 goto out_delete_line;
1544 dso__kernel_module_get_build_id(map->dso);
889 } 1545 }
1546
1547 free(line);
1548 fclose(file);
1549
1550 return map_groups__set_modules_path(self);
1551
1552out_delete_line:
1553 free(line);
1554out_failure:
1555 return -1;
890} 1556}
891 1557
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1558static int dso__load_vmlinux(struct dso *self, struct map *map,
893 symbol_filter_t filter, int v) 1559 const char *vmlinux, symbol_filter_t filter)
894{ 1560{
895 int err, fd = open(vmlinux, O_RDONLY); 1561 int err = -1, fd;
1562
1563 if (self->has_build_id) {
1564 u8 build_id[BUILD_ID_SIZE];
1565
1566 if (filename__read_build_id(vmlinux, build_id,
1567 sizeof(build_id)) < 0) {
1568 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1569 return -1;
1570 }
1571 if (!dso__build_id_equal(self, build_id)) {
1572 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1573 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1574
1575 build_id__sprintf(self->build_id,
1576 sizeof(self->build_id),
1577 expected_build_id);
1578 build_id__sprintf(build_id, sizeof(build_id),
1579 vmlinux_build_id);
1580 pr_debug("build_id in %s is %s while expected is %s, "
1581 "ignoring it\n", vmlinux, vmlinux_build_id,
1582 expected_build_id);
1583 return -1;
1584 }
1585 }
896 1586
1587 fd = open(vmlinux, O_RDONLY);
897 if (fd < 0) 1588 if (fd < 0)
898 return -1; 1589 return -1;
899 1590
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1591 dso__set_loaded(self, map->type);
1592 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
1593 close(fd);
901 1594
902 if (err > 0) 1595 if (err > 0)
903 dso__fill_symbol_holes(self); 1596 pr_debug("Using %s for symbols\n", vmlinux);
904 1597
905 close(fd); 1598 return err;
1599}
1600
1601int dso__load_vmlinux_path(struct dso *self, struct map *map,
1602 symbol_filter_t filter)
1603{
1604 int i, err = 0;
1605
1606 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1607 vmlinux_path__nr_entries);
1608
1609 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1610 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1611 if (err > 0) {
1612 dso__set_long_name(self, strdup(vmlinux_path[i]));
1613 break;
1614 }
1615 }
906 1616
907 return err; 1617 return err;
908} 1618}
909 1619
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1620static int dso__load_kernel_sym(struct dso *self, struct map *map,
911 symbol_filter_t filter, int v, int use_modules) 1621 symbol_filter_t filter)
912{ 1622{
913 int err = -1; 1623 int err;
1624 const char *kallsyms_filename = NULL;
1625 char *kallsyms_allocated_filename = NULL;
1626 /*
1627 * Step 1: if the user specified a vmlinux filename, use it and only
1628 * it, reporting errors to the user if it cannot be used.
1629 *
1630 * For instance, try to analyse an ARM perf.data file _without_ a
1631 * build-id, or if the user specifies the wrong path to the right
1632 * vmlinux file, obviously we can't fallback to another vmlinux (a
1633 * x86_86 one, on the machine where analysis is being performed, say),
1634 * or worse, /proc/kallsyms.
1635 *
1636 * If the specified file _has_ a build-id and there is a build-id
1637 * section in the perf.data file, we will still do the expected
1638 * validation in dso__load_vmlinux and will bail out if they don't
1639 * match.
1640 */
1641 if (symbol_conf.vmlinux_name != NULL) {
1642 err = dso__load_vmlinux(self, map,
1643 symbol_conf.vmlinux_name, filter);
1644 goto out_try_fixup;
1645 }
914 1646
915 if (vmlinux) { 1647 if (vmlinux_path != NULL) {
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1648 err = dso__load_vmlinux_path(self, map, filter);
917 if (err > 0 && use_modules) { 1649 if (err > 0)
918 int syms = dso__load_modules(self, filter, v); 1650 goto out_fixup;
1651 }
919 1652
920 if (syms < 0) { 1653 /*
921 fprintf(stderr, "dso__load_modules failed!\n"); 1654 * Say the kernel DSO was created when processing the build-id header table,
922 return syms; 1655 * we have a build-id, so check if it is the same as the running kernel,
1656 * using it if it is.
1657 */
1658 if (self->has_build_id) {
1659 u8 kallsyms_build_id[BUILD_ID_SIZE];
1660 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1661
1662 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1663 sizeof(kallsyms_build_id)) == 0) {
1664 if (dso__build_id_equal(self, kallsyms_build_id)) {
1665 kallsyms_filename = "/proc/kallsyms";
1666 goto do_kallsyms;
923 } 1667 }
924 err += syms;
925 } 1668 }
926 } 1669 /*
1670 * Now look if we have it on the build-id cache in
1671 * $HOME/.debug/[kernel.kallsyms].
1672 */
1673 build_id__sprintf(self->build_id, sizeof(self->build_id),
1674 sbuild_id);
1675
1676 if (asprintf(&kallsyms_allocated_filename,
1677 "%s/.debug/[kernel.kallsyms]/%s",
1678 getenv("HOME"), sbuild_id) == -1) {
1679 pr_err("Not enough memory for kallsyms file lookup\n");
1680 return -1;
1681 }
927 1682
928 if (err <= 0) 1683 kallsyms_filename = kallsyms_allocated_filename;
929 err = dso__load_kallsyms(self, filter, v);
930 1684
1685 if (access(kallsyms_filename, F_OK)) {
1686 pr_err("No kallsyms or vmlinux with build-id %s "
1687 "was found\n", sbuild_id);
1688 free(kallsyms_allocated_filename);
1689 return -1;
1690 }
1691 } else {
1692 /*
1693 * Last resort, if we don't have a build-id and couldn't find
1694 * any vmlinux file, try the running kernel kallsyms table.
1695 */
1696 kallsyms_filename = "/proc/kallsyms";
1697 }
1698
1699do_kallsyms:
1700 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
931 if (err > 0) 1701 if (err > 0)
932 self->origin = DSO__ORIG_KERNEL; 1702 pr_debug("Using %s for symbols\n", kallsyms_filename);
1703 free(kallsyms_allocated_filename);
1704
1705out_try_fixup:
1706 if (err > 0) {
1707out_fixup:
1708 if (kallsyms_filename != NULL)
1709 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1710 map__fixup_start(map);
1711 map__fixup_end(map);
1712 }
933 1713
934 return err; 1714 return err;
935} 1715}
936 1716
937LIST_HEAD(dsos); 1717LIST_HEAD(dsos__user);
938struct dso *kernel_dso; 1718LIST_HEAD(dsos__kernel);
939struct dso *vdso;
940struct dso *hypervisor_dso;
941
942const char *vmlinux_name = "vmlinux";
943int modules;
944 1719
945static void dsos__add(struct dso *dso) 1720static void dsos__add(struct list_head *head, struct dso *dso)
946{ 1721{
947 list_add_tail(&dso->node, &dsos); 1722 list_add_tail(&dso->node, head);
948} 1723}
949 1724
950static struct dso *dsos__find(const char *name) 1725static struct dso *dsos__find(struct list_head *head, const char *name)
951{ 1726{
952 struct dso *pos; 1727 struct dso *pos;
953 1728
954 list_for_each_entry(pos, &dsos, node) 1729 list_for_each_entry(pos, head, node)
955 if (strcmp(pos->name, name) == 0) 1730 if (strcmp(pos->long_name, name) == 0)
956 return pos; 1731 return pos;
957 return NULL; 1732 return NULL;
958} 1733}
959 1734
960struct dso *dsos__findnew(const char *name) 1735struct dso *__dsos__findnew(struct list_head *head, const char *name)
961{ 1736{
962 struct dso *dso = dsos__find(name); 1737 struct dso *dso = dsos__find(head, name);
963 int nr;
964
965 if (dso)
966 return dso;
967
968 dso = dso__new(name, 0);
969 if (!dso)
970 goto out_delete_dso;
971 1738
972 nr = dso__load(dso, NULL, verbose); 1739 if (!dso) {
973 if (nr < 0) { 1740 dso = dso__new(name);
974 eprintf("Failed to open: %s\n", name); 1741 if (dso != NULL) {
975 goto out_delete_dso; 1742 dsos__add(head, dso);
1743 dso__set_basename(dso);
1744 }
976 } 1745 }
977 if (!nr)
978 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979
980 dsos__add(dso);
981 1746
982 return dso; 1747 return dso;
1748}
983 1749
984out_delete_dso: 1750static void __dsos__fprintf(struct list_head *head, FILE *fp)
985 dso__delete(dso); 1751{
986 return NULL; 1752 struct dso *pos;
1753
1754 list_for_each_entry(pos, head, node) {
1755 int i;
1756 for (i = 0; i < MAP__NR_TYPES; ++i)
1757 dso__fprintf(pos, i, fp);
1758 }
987} 1759}
988 1760
989void dsos__fprintf(FILE *fp) 1761void dsos__fprintf(FILE *fp)
990{ 1762{
1763 __dsos__fprintf(&dsos__kernel, fp);
1764 __dsos__fprintf(&dsos__user, fp);
1765}
1766
1767static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1768 bool with_hits)
1769{
991 struct dso *pos; 1770 struct dso *pos;
1771 size_t ret = 0;
992 1772
993 list_for_each_entry(pos, &dsos, node) 1773 list_for_each_entry(pos, head, node) {
994 dso__fprintf(pos, fp); 1774 if (with_hits && !pos->hit)
1775 continue;
1776 ret += dso__fprintf_buildid(pos, fp);
1777 ret += fprintf(fp, " %s\n", pos->long_name);
1778 }
1779 return ret;
995} 1780}
996 1781
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 1782size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
998{ 1783{
999 return dso__find_symbol(dso, ip); 1784 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1785 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
1000} 1786}
1001 1787
1002int load_kernel(void) 1788struct dso *dso__new_kernel(const char *name)
1003{ 1789{
1004 int err; 1790 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1005 1791
1006 kernel_dso = dso__new("[kernel]", 0); 1792 if (self != NULL) {
1007 if (!kernel_dso) 1793 dso__set_short_name(self, "[kernel]");
1008 return -1; 1794 self->kernel = 1;
1795 }
1009 1796
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1797 return self;
1011 if (err <= 0) { 1798}
1012 dso__delete(kernel_dso);
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016 1799
1017 vdso = dso__new("[vdso]", 0); 1800void dso__read_running_kernel_build_id(struct dso *self)
1018 if (!vdso) 1801{
1019 return -1; 1802 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1803 sizeof(self->build_id)) == 0)
1804 self->has_build_id = true;
1805}
1806
1807static struct dso *dsos__create_kernel(const char *vmlinux)
1808{
1809 struct dso *kernel = dso__new_kernel(vmlinux);
1810
1811 if (kernel != NULL) {
1812 dso__read_running_kernel_build_id(kernel);
1813 dsos__add(&dsos__kernel, kernel);
1814 }
1815
1816 return kernel;
1817}
1818
1819int __map_groups__create_kernel_maps(struct map_groups *self,
1820 struct map *vmlinux_maps[MAP__NR_TYPES],
1821 struct dso *kernel)
1822{
1823 enum map_type type;
1824
1825 for (type = 0; type < MAP__NR_TYPES; ++type) {
1826 struct kmap *kmap;
1827
1828 vmlinux_maps[type] = map__new2(0, kernel, type);
1829 if (vmlinux_maps[type] == NULL)
1830 return -1;
1831
1832 vmlinux_maps[type]->map_ip =
1833 vmlinux_maps[type]->unmap_ip = identity__map_ip;
1834
1835 kmap = map__kmap(vmlinux_maps[type]);
1836 kmap->kmaps = self;
1837 map_groups__insert(self, vmlinux_maps[type]);
1838 }
1839
1840 return 0;
1841}
1842
1843static void vmlinux_path__exit(void)
1844{
1845 while (--vmlinux_path__nr_entries >= 0) {
1846 free(vmlinux_path[vmlinux_path__nr_entries]);
1847 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1848 }
1020 1849
1021 vdso->find_symbol = vdso__find_symbol; 1850 free(vmlinux_path);
1851 vmlinux_path = NULL;
1852}
1022 1853
1023 dsos__add(vdso); 1854static int vmlinux_path__init(void)
1855{
1856 struct utsname uts;
1857 char bf[PATH_MAX];
1024 1858
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1859 if (uname(&uts) < 0)
1026 if (!hypervisor_dso)
1027 return -1; 1860 return -1;
1028 dsos__add(hypervisor_dso);
1029 1861
1030 return err; 1862 vmlinux_path = malloc(sizeof(char *) * 5);
1863 if (vmlinux_path == NULL)
1864 return -1;
1865
1866 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1867 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1868 goto out_fail;
1869 ++vmlinux_path__nr_entries;
1870 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1871 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1872 goto out_fail;
1873 ++vmlinux_path__nr_entries;
1874 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1875 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1876 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1877 goto out_fail;
1878 ++vmlinux_path__nr_entries;
1879 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1880 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1881 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1882 goto out_fail;
1883 ++vmlinux_path__nr_entries;
1884 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1885 uts.release);
1886 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1887 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1888 goto out_fail;
1889 ++vmlinux_path__nr_entries;
1890
1891 return 0;
1892
1893out_fail:
1894 vmlinux_path__exit();
1895 return -1;
1031} 1896}
1032 1897
1898static int setup_list(struct strlist **list, const char *list_str,
1899 const char *list_name)
1900{
1901 if (list_str == NULL)
1902 return 0;
1903
1904 *list = strlist__new(true, list_str);
1905 if (!*list) {
1906 pr_err("problems parsing %s list\n", list_name);
1907 return -1;
1908 }
1909 return 0;
1910}
1033 1911
1034void symbol__init(void) 1912int symbol__init(void)
1035{ 1913{
1036 elf_version(EV_CURRENT); 1914 elf_version(EV_CURRENT);
1915 if (symbol_conf.sort_by_name)
1916 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1917 sizeof(struct symbol));
1918
1919 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1920 return -1;
1921
1922 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1923 pr_err("'.' is the only non valid --field-separator argument\n");
1924 return -1;
1925 }
1926
1927 if (setup_list(&symbol_conf.dso_list,
1928 symbol_conf.dso_list_str, "dso") < 0)
1929 return -1;
1930
1931 if (setup_list(&symbol_conf.comm_list,
1932 symbol_conf.comm_list_str, "comm") < 0)
1933 goto out_free_dso_list;
1934
1935 if (setup_list(&symbol_conf.sym_list,
1936 symbol_conf.sym_list_str, "symbol") < 0)
1937 goto out_free_comm_list;
1938
1939 return 0;
1940
1941out_free_dso_list:
1942 strlist__delete(symbol_conf.dso_list);
1943out_free_comm_list:
1944 strlist__delete(symbol_conf.comm_list);
1945 return -1;
1946}
1947
1948int map_groups__create_kernel_maps(struct map_groups *self,
1949 struct map *vmlinux_maps[MAP__NR_TYPES])
1950{
1951 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1952
1953 if (kernel == NULL)
1954 return -1;
1955
1956 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1957 return -1;
1958
1959 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
1960 pr_debug("Problems creating module maps, continuing anyway...\n");
1961 /*
1962 * Now that we have all the maps created, just set the ->end of them:
1963 */
1964 map_groups__fixup_end(self);
1965 return 0;
1037} 1966}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 829da9edba64..f30a37428919 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -1,13 +1,15 @@
1#ifndef _PERF_SYMBOL_ 1#ifndef __PERF_SYMBOL
2#define _PERF_SYMBOL_ 1 2#define __PERF_SYMBOL 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <stdbool.h>
5#include "types.h" 6#include "types.h"
6#include <linux/list.h> 7#include <linux/list.h>
7#include <linux/rbtree.h> 8#include <linux/rbtree.h>
8#include "module.h"
9#include "event.h" 9#include "event.h"
10 10
11#define DEBUG_CACHE_DIR ".debug"
12
11#ifdef HAVE_CPLUS_DEMANGLE 13#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int); 14extern char *cplus_demangle(const char *, int);
13 15
@@ -46,57 +48,125 @@ struct symbol {
46 struct rb_node rb_node; 48 struct rb_node rb_node;
47 u64 start; 49 u64 start;
48 u64 end; 50 u64 end;
49 u64 obj_start;
50 u64 hist_sum;
51 u64 *hist;
52 struct module *module;
53 void *priv;
54 char name[0]; 51 char name[0];
55}; 52};
56 53
54void symbol__delete(struct symbol *self);
55
56struct strlist;
57
58struct symbol_conf {
59 unsigned short priv_size;
60 bool try_vmlinux_path,
61 use_modules,
62 sort_by_name,
63 show_nr_samples,
64 use_callchain,
65 exclude_other,
66 full_paths;
67 const char *vmlinux_name,
68 *field_sep;
69 char *dso_list_str,
70 *comm_list_str,
71 *sym_list_str,
72 *col_width_list_str;
73 struct strlist *dso_list,
74 *comm_list,
75 *sym_list;
76};
77
78extern struct symbol_conf symbol_conf;
79
80static inline void *symbol__priv(struct symbol *self)
81{
82 return ((void *)self) - symbol_conf.priv_size;
83}
84
85struct ref_reloc_sym {
86 const char *name;
87 u64 addr;
88 u64 unrelocated_addr;
89};
90
91struct addr_location {
92 struct thread *thread;
93 struct map *map;
94 struct symbol *sym;
95 u64 addr;
96 char level;
97 bool filtered;
98};
99
57struct dso { 100struct dso {
58 struct list_head node; 101 struct list_head node;
59 struct rb_root syms; 102 struct rb_root symbols[MAP__NR_TYPES];
60 struct symbol *(*find_symbol)(struct dso *, u64 ip); 103 struct rb_root symbol_names[MAP__NR_TYPES];
61 unsigned int sym_priv_size; 104 u8 adjust_symbols:1;
62 unsigned char adjust_symbols; 105 u8 slen_calculated:1;
63 unsigned char slen_calculated; 106 u8 has_build_id:1;
107 u8 kernel:1;
108 u8 hit:1;
64 unsigned char origin; 109 unsigned char origin;
110 u8 sorted_by_name;
111 u8 loaded;
112 u8 build_id[BUILD_ID_SIZE];
113 const char *short_name;
114 char *long_name;
115 u16 long_name_len;
116 u16 short_name_len;
65 char name[0]; 117 char name[0];
66}; 118};
67 119
68extern const char *sym_hist_filter; 120struct dso *dso__new(const char *name);
69 121struct dso *dso__new_kernel(const char *name);
70typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
71
72struct dso *dso__new(const char *name, unsigned int sym_priv_size);
73void dso__delete(struct dso *self); 122void dso__delete(struct dso *self);
74 123
75static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) 124bool dso__loaded(const struct dso *self, enum map_type type);
125bool dso__sorted_by_name(const struct dso *self, enum map_type type);
126
127static inline void dso__set_loaded(struct dso *self, enum map_type type)
76{ 128{
77 return ((void *)sym) - self->sym_priv_size; 129 self->loaded |= (1 << type);
78} 130}
79 131
80struct symbol *dso__find_symbol(struct dso *self, u64 ip); 132void dso__sort_by_name(struct dso *self, enum map_type type);
81 133
82int dso__load_kernel(struct dso *self, const char *vmlinux, 134extern struct list_head dsos__user, dsos__kernel;
83 symbol_filter_t filter, int verbose, int modules);
84int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
85int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
86struct dso *dsos__findnew(const char *name);
87void dsos__fprintf(FILE *fp);
88 135
89size_t dso__fprintf(struct dso *self, FILE *fp); 136struct dso *__dsos__findnew(struct list_head *head, const char *name);
90char dso__symtab_origin(const struct dso *self);
91 137
92int load_kernel(void); 138static inline struct dso *dsos__findnew(const char *name)
139{
140 return __dsos__findnew(&dsos__user, name);
141}
93 142
94void symbol__init(void); 143int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
144int dso__load_vmlinux_path(struct dso *self, struct map *map,
145 symbol_filter_t filter);
146int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
147 symbol_filter_t filter);
148void dsos__fprintf(FILE *fp);
149size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
95 150
96extern struct list_head dsos; 151size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
97extern struct dso *kernel_dso; 152size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
98extern struct dso *vdso; 153char dso__symtab_origin(const struct dso *self);
99extern struct dso *hypervisor_dso; 154void dso__set_long_name(struct dso *self, char *name);
100extern const char *vmlinux_name; 155void dso__set_build_id(struct dso *self, void *build_id);
101extern int modules; 156void dso__read_running_kernel_build_id(struct dso *self);
102#endif /* _PERF_SYMBOL_ */ 157struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
158struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
159 const char *name);
160
161int filename__read_build_id(const char *filename, void *bf, size_t size);
162int sysfs__read_build_id(const char *filename, void *bf, size_t size);
163bool dsos__read_build_ids(bool with_hits);
164int build_id__sprintf(const u8 *self, int len, char *bf);
165int kallsyms__parse(const char *filename, void *arg,
166 int (*process_symbol)(void *arg, const char *name,
167 char type, u64 start));
168
169int symbol__init(void);
170bool symbol_type__is_a(char symbol_type, enum map_type map_type);
171
172#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45efb5db0d19..fa968312ee7d 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,48 +2,151 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include "session.h"
5#include "thread.h" 6#include "thread.h"
6#include "util.h" 7#include "util.h"
7#include "debug.h" 8#include "debug.h"
8 9
10void map_groups__init(struct map_groups *self)
11{
12 int i;
13 for (i = 0; i < MAP__NR_TYPES; ++i) {
14 self->maps[i] = RB_ROOT;
15 INIT_LIST_HEAD(&self->removed_maps[i]);
16 }
17}
18
9static struct thread *thread__new(pid_t pid) 19static struct thread *thread__new(pid_t pid)
10{ 20{
11 struct thread *self = calloc(1, sizeof(*self)); 21 struct thread *self = zalloc(sizeof(*self));
12 22
13 if (self != NULL) { 23 if (self != NULL) {
24 map_groups__init(&self->mg);
14 self->pid = pid; 25 self->pid = pid;
15 self->comm = malloc(32); 26 self->comm = malloc(32);
16 if (self->comm) 27 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 28 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps);
19 } 29 }
20 30
21 return self; 31 return self;
22} 32}
23 33
34static void map_groups__flush(struct map_groups *self)
35{
36 int type;
37
38 for (type = 0; type < MAP__NR_TYPES; type++) {
39 struct rb_root *root = &self->maps[type];
40 struct rb_node *next = rb_first(root);
41
42 while (next) {
43 struct map *pos = rb_entry(next, struct map, rb_node);
44 next = rb_next(&pos->rb_node);
45 rb_erase(&pos->rb_node, root);
46 /*
47 * We may have references to this map, for
48 * instance in some hist_entry instances, so
49 * just move them to a separate list.
50 */
51 list_add_tail(&pos->node, &self->removed_maps[pos->type]);
52 }
53 }
54}
55
24int thread__set_comm(struct thread *self, const char *comm) 56int thread__set_comm(struct thread *self, const char *comm)
25{ 57{
58 int err;
59
26 if (self->comm) 60 if (self->comm)
27 free(self->comm); 61 free(self->comm);
28 self->comm = strdup(comm); 62 self->comm = strdup(comm);
29 return self->comm ? 0 : -ENOMEM; 63 err = self->comm == NULL ? -ENOMEM : 0;
64 if (!err) {
65 self->comm_set = true;
66 map_groups__flush(&self->mg);
67 }
68 return err;
30} 69}
31 70
32static size_t thread__fprintf(struct thread *self, FILE *fp) 71int thread__comm_len(struct thread *self)
72{
73 if (!self->comm_len) {
74 if (!self->comm)
75 return 0;
76 self->comm_len = strlen(self->comm);
77 }
78
79 return self->comm_len;
80}
81
82size_t __map_groups__fprintf_maps(struct map_groups *self,
83 enum map_type type, FILE *fp)
84{
85 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
86 struct rb_node *nd;
87
88 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
89 struct map *pos = rb_entry(nd, struct map, rb_node);
90 printed += fprintf(fp, "Map:");
91 printed += map__fprintf(pos, fp);
92 if (verbose > 2) {
93 printed += dso__fprintf(pos->dso, type, fp);
94 printed += fprintf(fp, "--\n");
95 }
96 }
97
98 return printed;
99}
100
101size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
102{
103 size_t printed = 0, i;
104 for (i = 0; i < MAP__NR_TYPES; ++i)
105 printed += __map_groups__fprintf_maps(self, i, fp);
106 return printed;
107}
108
109static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
110 enum map_type type, FILE *fp)
33{ 111{
34 struct map *pos; 112 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 113 size_t printed = 0;
114
115 list_for_each_entry(pos, &self->removed_maps[type], node) {
116 printed += fprintf(fp, "Map:");
117 printed += map__fprintf(pos, fp);
118 if (verbose > 1) {
119 printed += dso__fprintf(pos->dso, type, fp);
120 printed += fprintf(fp, "--\n");
121 }
122 }
123 return printed;
124}
36 125
37 list_for_each_entry(pos, &self->maps, node) 126static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
38 ret += map__fprintf(pos, fp); 127{
128 size_t printed = 0, i;
129 for (i = 0; i < MAP__NR_TYPES; ++i)
130 printed += __map_groups__fprintf_removed_maps(self, i, fp);
131 return printed;
132}
39 133
40 return ret; 134static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
135{
136 size_t printed = map_groups__fprintf_maps(self, fp);
137 printed += fprintf(fp, "Removed maps:\n");
138 return printed + map_groups__fprintf_removed_maps(self, fp);
41} 139}
42 140
43struct thread * 141static size_t thread__fprintf(struct thread *self, FILE *fp)
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) 142{
143 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
144 map_groups__fprintf(&self->mg, fp);
145}
146
147struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
45{ 148{
46 struct rb_node **p = &threads->rb_node; 149 struct rb_node **p = &self->threads.rb_node;
47 struct rb_node *parent = NULL; 150 struct rb_node *parent = NULL;
48 struct thread *th; 151 struct thread *th;
49 152
@@ -52,15 +155,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
52 * so most of the time we dont have to look up 155 * so most of the time we dont have to look up
53 * the full rbtree: 156 * the full rbtree:
54 */ 157 */
55 if (*last_match && (*last_match)->pid == pid) 158 if (self->last_match && self->last_match->pid == pid)
56 return *last_match; 159 return self->last_match;
57 160
58 while (*p != NULL) { 161 while (*p != NULL) {
59 parent = *p; 162 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node); 163 th = rb_entry(parent, struct thread, rb_node);
61 164
62 if (th->pid == pid) { 165 if (th->pid == pid) {
63 *last_match = th; 166 self->last_match = th;
64 return th; 167 return th;
65 } 168 }
66 169
@@ -73,99 +176,159 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
73 th = thread__new(pid); 176 th = thread__new(pid);
74 if (th != NULL) { 177 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p); 178 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads); 179 rb_insert_color(&th->rb_node, &self->threads);
77 *last_match = th; 180 self->last_match = th;
78 } 181 }
79 182
80 return th; 183 return th;
81} 184}
82 185
83struct thread * 186static int map_groups__fixup_overlappings(struct map_groups *self,
84register_idle_thread(struct rb_root *threads, struct thread **last_match) 187 struct map *map)
85{ 188{
86 struct thread *thread = threads__findnew(0, threads, last_match); 189 struct rb_root *root = &self->maps[map->type];
190 struct rb_node *next = rb_first(root);
191
192 while (next) {
193 struct map *pos = rb_entry(next, struct map, rb_node);
194 next = rb_next(&pos->rb_node);
195
196 if (!map__overlap(pos, map))
197 continue;
198
199 if (verbose >= 2) {
200 fputs("overlapping maps:\n", stderr);
201 map__fprintf(map, stderr);
202 map__fprintf(pos, stderr);
203 }
204
205 rb_erase(&pos->rb_node, root);
206 /*
207 * We may have references to this map, for instance in some
208 * hist_entry instances, so just move them to a separate
209 * list.
210 */
211 list_add_tail(&pos->node, &self->removed_maps[map->type]);
212 /*
213 * Now check if we need to create new maps for areas not
214 * overlapped by the new map:
215 */
216 if (map->start > pos->start) {
217 struct map *before = map__clone(pos);
218
219 if (before == NULL)
220 return -ENOMEM;
221
222 before->end = map->start - 1;
223 map_groups__insert(self, before);
224 if (verbose >= 2)
225 map__fprintf(before, stderr);
226 }
227
228 if (map->end < pos->end) {
229 struct map *after = map__clone(pos);
87 230
88 if (!thread || thread__set_comm(thread, "swapper")) { 231 if (after == NULL)
89 fprintf(stderr, "problem inserting idle task.\n"); 232 return -ENOMEM;
90 exit(-1); 233
234 after->start = map->end + 1;
235 map_groups__insert(self, after);
236 if (verbose >= 2)
237 map__fprintf(after, stderr);
238 }
91 } 239 }
92 240
93 return thread; 241 return 0;
94} 242}
95 243
96void thread__insert_map(struct thread *self, struct map *map) 244void maps__insert(struct rb_root *maps, struct map *map)
97{ 245{
98 struct map *pos, *tmp; 246 struct rb_node **p = &maps->rb_node;
99 247 struct rb_node *parent = NULL;
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 248 const u64 ip = map->start;
101 if (map__overlap(pos, map)) { 249 struct map *m;
102 if (verbose >= 2) {
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107 250
108 if (map->start <= pos->start && map->end > pos->start) 251 while (*p != NULL) {
109 pos->start = map->end; 252 parent = *p;
253 m = rb_entry(parent, struct map, rb_node);
254 if (ip < m->start)
255 p = &(*p)->rb_left;
256 else
257 p = &(*p)->rb_right;
258 }
110 259
111 if (map->end >= pos->end && map->start < pos->end) 260 rb_link_node(&map->rb_node, parent, p);
112 pos->end = map->start; 261 rb_insert_color(&map->rb_node, maps);
262}
113 263
114 if (verbose >= 2) { 264struct map *maps__find(struct rb_root *maps, u64 ip)
115 printf("after collision:\n"); 265{
116 map__fprintf(pos, stdout); 266 struct rb_node **p = &maps->rb_node;
117 } 267 struct rb_node *parent = NULL;
268 struct map *m;
118 269
119 if (pos->start >= pos->end) { 270 while (*p != NULL) {
120 list_del_init(&pos->node); 271 parent = *p;
121 free(pos); 272 m = rb_entry(parent, struct map, rb_node);
122 } 273 if (ip < m->start)
123 } 274 p = &(*p)->rb_left;
275 else if (ip > m->end)
276 p = &(*p)->rb_right;
277 else
278 return m;
124 } 279 }
125 280
126 list_add_tail(&map->node, &self->maps); 281 return NULL;
127} 282}
128 283
129int thread__fork(struct thread *self, struct thread *parent) 284void thread__insert_map(struct thread *self, struct map *map)
130{ 285{
131 struct map *map; 286 map_groups__fixup_overlappings(&self->mg, map);
132 287 map_groups__insert(&self->mg, map);
133 if (self->comm) 288}
134 free(self->comm);
135 self->comm = strdup(parent->comm);
136 if (!self->comm)
137 return -ENOMEM;
138 289
139 list_for_each_entry(map, &parent->maps, node) { 290/*
291 * XXX This should not really _copy_ te maps, but refcount them.
292 */
293static int map_groups__clone(struct map_groups *self,
294 struct map_groups *parent, enum map_type type)
295{
296 struct rb_node *nd;
297 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
298 struct map *map = rb_entry(nd, struct map, rb_node);
140 struct map *new = map__clone(map); 299 struct map *new = map__clone(map);
141 if (!new) 300 if (new == NULL)
142 return -ENOMEM; 301 return -ENOMEM;
143 thread__insert_map(self, new); 302 map_groups__insert(self, new);
144 } 303 }
145
146 return 0; 304 return 0;
147} 305}
148 306
149struct map *thread__find_map(struct thread *self, u64 ip) 307int thread__fork(struct thread *self, struct thread *parent)
150{ 308{
151 struct map *pos; 309 int i;
152
153 if (self == NULL)
154 return NULL;
155 310
156 list_for_each_entry(pos, &self->maps, node) 311 if (parent->comm_set) {
157 if (ip >= pos->start && ip <= pos->end) 312 if (self->comm)
158 return pos; 313 free(self->comm);
314 self->comm = strdup(parent->comm);
315 if (!self->comm)
316 return -ENOMEM;
317 self->comm_set = true;
318 }
159 319
160 return NULL; 320 for (i = 0; i < MAP__NR_TYPES; ++i)
321 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
322 return -ENOMEM;
323 return 0;
161} 324}
162 325
163size_t threads__fprintf(FILE *fp, struct rb_root *threads) 326size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
164{ 327{
165 size_t ret = 0; 328 size_t ret = 0;
166 struct rb_node *nd; 329 struct rb_node *nd;
167 330
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 331 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 332 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 333
171 ret += thread__fprintf(pos, fp); 334 ret += thread__fprintf(pos, fp);
@@ -173,3 +336,15 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
173 336
174 return ret; 337 return ret;
175} 338}
339
340struct symbol *map_groups__find_symbol(struct map_groups *self,
341 enum map_type type, u64 addr,
342 symbol_filter_t filter)
343{
344 struct map *map = map_groups__find(self, type, addr);
345
346 if (map != NULL)
347 return map__find_symbol(map, map->map_ip(map, addr), filter);
348
349 return NULL;
350}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..dcf70303e58e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,22 +1,87 @@
1#ifndef __PERF_THREAD_H
2#define __PERF_THREAD_H
3
1#include <linux/rbtree.h> 4#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h> 5#include <unistd.h>
4#include "symbol.h" 6#include "symbol.h"
5 7
8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES];
11};
12
13size_t __map_groups__fprintf_maps(struct map_groups *self,
14 enum map_type type, FILE *fp);
15
6struct thread { 16struct thread {
7 struct rb_node rb_node; 17 struct rb_node rb_node;
8 struct list_head maps; 18 struct map_groups mg;
9 pid_t pid; 19 pid_t pid;
10 char shortname[3]; 20 char shortname[3];
21 bool comm_set;
11 char *comm; 22 char *comm;
23 int comm_len;
12}; 24};
13 25
26void map_groups__init(struct map_groups *self);
14int thread__set_comm(struct thread *self, const char *comm); 27int thread__set_comm(struct thread *self, const char *comm);
15struct thread * 28int thread__comm_len(struct thread *self);
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 29struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
17struct thread *
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map); 30void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 31int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip); 32size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 33size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
34
35void maps__insert(struct rb_root *maps, struct map *map);
36struct map *maps__find(struct rb_root *maps, u64 addr);
37
38static inline void map_groups__insert(struct map_groups *self, struct map *map)
39{
40 maps__insert(&self->maps[map->type], map);
41}
42
43static inline struct map *map_groups__find(struct map_groups *self,
44 enum map_type type, u64 addr)
45{
46 return maps__find(&self->maps[type], addr);
47}
48
49static inline struct map *thread__find_map(struct thread *self,
50 enum map_type type, u64 addr)
51{
52 return self ? map_groups__find(&self->mg, type, addr) : NULL;
53}
54
55void thread__find_addr_map(struct thread *self,
56 struct perf_session *session, u8 cpumode,
57 enum map_type type, u64 addr,
58 struct addr_location *al);
59
60void thread__find_addr_location(struct thread *self,
61 struct perf_session *session, u8 cpumode,
62 enum map_type type, u64 addr,
63 struct addr_location *al,
64 symbol_filter_t filter);
65struct symbol *map_groups__find_symbol(struct map_groups *self,
66 enum map_type type, u64 addr,
67 symbol_filter_t filter);
68
69static inline struct symbol *map_groups__find_function(struct map_groups *self,
70 u64 addr,
71 symbol_filter_t filter)
72{
73 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
74}
75
76struct map *map_groups__find_by_name(struct map_groups *self,
77 enum map_type type, const char *name);
78
79int __map_groups__create_kernel_maps(struct map_groups *self,
80 struct map *vmlinux_maps[MAP__NR_TYPES],
81 struct dso *kernel);
82int map_groups__create_kernel_maps(struct map_groups *self,
83 struct map *vmlinux_maps[MAP__NR_TYPES]);
84
85struct map *map_groups__new_module(struct map_groups *self, u64 start,
86 const char *filename);
87#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index af4b0573b37f..5ea8973ad331 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#define _GNU_SOURCE 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
@@ -33,10 +34,11 @@
33#include <ctype.h> 34#include <ctype.h>
34#include <errno.h> 35#include <errno.h>
35#include <stdbool.h> 36#include <stdbool.h>
37#include <linux/kernel.h>
36 38
37#include "../perf.h" 39#include "../perf.h"
38#include "trace-event.h" 40#include "trace-event.h"
39 41#include "debugfs.h"
40 42
41#define VERSION "0.5" 43#define VERSION "0.5"
42 44
@@ -101,32 +103,12 @@ void *malloc_or_die(unsigned int size)
101 103
102static const char *find_debugfs(void) 104static const char *find_debugfs(void)
103{ 105{
104 static char debugfs[MAX_PATH+1]; 106 const char *path = debugfs_mount(NULL);
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126 107
127 debugfs_found = 1; 108 if (!path)
109 die("Your kernel not support debugfs filesystem");
128 110
129 return debugfs; 111 return path;
130} 112}
131 113
132/* 114/*
@@ -271,6 +253,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 253 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 254 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 255 check_size = copy_file_fd(fd);
256 close(fd);
257
274 if (size != check_size) 258 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 259 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 260 path, size, check_size);
@@ -289,6 +273,7 @@ static void read_header_files(void)
289 if (size != check_size) 273 if (size != check_size)
290 die("wrong size for '%s'", path); 274 die("wrong size for '%s'", path);
291 put_tracing_file(path); 275 put_tracing_file(path);
276 close(fd);
292} 277}
293 278
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 279static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +302,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 302 die("can't read directory '%s'", sys);
318 303
319 while ((dent = readdir(dir))) { 304 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 305 if (dent->d_type != DT_DIR ||
306 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 307 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 308 !name_in_tp_list(dent->d_name, tps))
323 continue; 309 continue;
@@ -334,7 +320,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 320
335 rewinddir(dir); 321 rewinddir(dir);
336 while ((dent = readdir(dir))) { 322 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 323 if (dent->d_type != DT_DIR ||
324 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 325 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 326 !name_in_tp_list(dent->d_name, tps))
340 continue; 327 continue;
@@ -353,6 +340,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 340
354 free(format); 341 free(format);
355 } 342 }
343 closedir(dir);
356} 344}
357 345
358static void read_ftrace_files(struct tracepoint_path *tps) 346static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +382,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 382 die("can't read directory '%s'", path);
395 383
396 while ((dent = readdir(dir))) { 384 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 385 if (dent->d_type != DT_DIR ||
386 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 387 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 388 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 389 !system_in_tp_list(dent->d_name, tps))
401 continue; 390 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 391 count++;
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 } 392 }
411 393
412 write_or_die(&count, 4); 394 write_or_die(&count, 4);
413 395
414 rewinddir(dir); 396 rewinddir(dir);
415 while ((dent = readdir(dir))) { 397 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 398 if (dent->d_type != DT_DIR ||
399 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 400 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 401 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 402 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +405,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 405 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 406 ret = stat(sys, &st);
424 if (ret >= 0) { 407 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 408 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 409 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 410 }
430 free(sys); 411 free(sys);
431 } 412 }
432 413
414 closedir(dir);
433 put_tracing_file(path); 415 put_tracing_file(path);
434} 416}
435 417
@@ -483,27 +465,33 @@ static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 465get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
484{ 466{
485 struct tracepoint_path path, *ppath = &path; 467 struct tracepoint_path path, *ppath = &path;
486 int i; 468 int i, nr_tracepoints = 0;
487 469
488 for (i = 0; i < nb_events; i++) { 470 for (i = 0; i < nb_events; i++) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 471 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
490 continue; 472 continue;
473 ++nr_tracepoints;
491 ppath->next = tracepoint_id_to_path(pattrs[i].config); 474 ppath->next = tracepoint_id_to_path(pattrs[i].config);
492 if (!ppath->next) 475 if (!ppath->next)
493 die("%s\n", "No memory to alloc tracepoints list"); 476 die("%s\n", "No memory to alloc tracepoints list");
494 ppath = ppath->next; 477 ppath = ppath->next;
495 } 478 }
496 479
497 return path.next; 480 return nr_tracepoints > 0 ? path.next : NULL;
498} 481}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events) 482
483int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
500{ 484{
501 char buf[BUFSIZ]; 485 char buf[BUFSIZ];
502 struct tracepoint_path *tps; 486 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events);
487
488 /*
489 * What? No tracepoints? No sense writing anything here, bail out.
490 */
491 if (tps == NULL)
492 return -1;
503 493
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); 494 output_fd = fd;
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507 495
508 buf[0] = 23; 496 buf[0] = 23;
509 buf[1] = 8; 497 buf[1] = 8;
@@ -527,14 +515,14 @@ void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
527 write_or_die(buf, 1); 515 write_or_die(buf, 1);
528 516
529 /* save page_size */ 517 /* save page_size */
530 page_size = getpagesize(); 518 page_size = sysconf(_SC_PAGESIZE);
531 write_or_die(&page_size, 4); 519 write_or_die(&page_size, 4);
532 520
533 tps = get_tracepoints_path(pattrs, nb_events);
534
535 read_header_files(); 521 read_header_files();
536 read_ftrace_files(tps); 522 read_ftrace_files(tps);
537 read_event_files(tps); 523 read_event_files(tps);
538 read_proc_kallsyms(); 524 read_proc_kallsyms();
539 read_ftrace_printk(); 525 read_ftrace_printk();
526
527 return 0;
540} 528}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 55c9659a56e2..613c9cc90570 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -40,12 +40,19 @@ int header_page_size_size;
40int header_page_data_offset; 40int header_page_data_offset;
41int header_page_data_size; 41int header_page_data_size;
42 42
43int latency_format;
44
43static char *input_buf; 45static char *input_buf;
44static unsigned long long input_buf_ptr; 46static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz; 47static unsigned long long input_buf_siz;
46 48
47static int cpus; 49static int cpus;
48static int long_size; 50static int long_size;
51static int is_flag_field;
52static int is_symbolic_field;
53
54static struct format_field *
55find_any_field(struct event *event, const char *name);
49 56
50static void init_input_buf(char *buf, unsigned long long size) 57static void init_input_buf(char *buf, unsigned long long size)
51{ 58{
@@ -170,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
170 func_count++; 177 func_count++;
171 } 178 }
172 179
173 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); 180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
174 181
175 i = 0; 182 i = 0;
176 while (list) { 183 while (list) {
@@ -284,18 +291,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
284 char *line; 291 char *line;
285 char *next = NULL; 292 char *next = NULL;
286 char *addr_str; 293 char *addr_str;
287 int ret;
288 int i; 294 int i;
289 295
290 line = strtok_r(file, "\n", &next); 296 line = strtok_r(file, "\n", &next);
291 while (line) { 297 while (line) {
298 addr_str = strsep(&line, ":");
299 if (!line) {
300 warning("error parsing print strings");
301 break;
302 }
292 item = malloc_or_die(sizeof(*item)); 303 item = malloc_or_die(sizeof(*item));
293 ret = sscanf(line, "%as : %as",
294 (float *)(void *)&addr_str, /* workaround gcc warning */
295 (float *)(void *)&item->printk);
296 item->addr = strtoull(addr_str, NULL, 16); 304 item->addr = strtoull(addr_str, NULL, 16);
297 free(addr_str); 305 /* fmt still has a space, skip it */
298 306 item->printk = strdup(line+1);
299 item->next = list; 307 item->next = list;
300 list = item; 308 list = item;
301 line = strtok_r(NULL, "\n", &next); 309 line = strtok_r(NULL, "\n", &next);
@@ -522,7 +530,10 @@ static enum event_type __read_token(char **tok)
522 last_ch = ch; 530 last_ch = ch;
523 ch = __read_char(); 531 ch = __read_char();
524 buf[i++] = ch; 532 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\'); 533 /* the '\' '\' will cancel itself */
534 if (ch == '\\' && last_ch == '\\')
535 last_ch = 0;
536 } while (ch != quote_ch || last_ch == '\\');
526 /* remove the last quote */ 537 /* remove the last quote */
527 i--; 538 i--;
528 goto out; 539 goto out;
@@ -610,7 +621,7 @@ static enum event_type read_token_item(char **tok)
610static int test_type(enum event_type type, enum event_type expect) 621static int test_type(enum event_type type, enum event_type expect)
611{ 622{
612 if (type != expect) { 623 if (type != expect) {
613 die("Error: expected type %d but read %d", 624 warning("Error: expected type %d but read %d",
614 expect, type); 625 expect, type);
615 return -1; 626 return -1;
616 } 627 }
@@ -621,13 +632,13 @@ static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, const char *expect_tok) 632 enum event_type expect, const char *expect_tok)
622{ 633{
623 if (type != expect) { 634 if (type != expect) {
624 die("Error: expected type %d but read %d", 635 warning("Error: expected type %d but read %d",
625 expect, type); 636 expect, type);
626 return -1; 637 return -1;
627 } 638 }
628 639
629 if (strcmp(token, expect_tok) != 0) { 640 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'", 641 warning("Error: expected '%s' but read '%s'",
631 expect_tok, token); 642 expect_tok, token);
632 return -1; 643 return -1;
633 } 644 }
@@ -665,7 +676,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
665 676
666 free_token(token); 677 free_token(token);
667 678
668 return 0; 679 return ret;
669} 680}
670 681
671static int read_expected(enum event_type expect, const char *str) 682static int read_expected(enum event_type expect, const char *str)
@@ -682,10 +693,10 @@ static char *event_read_name(void)
682{ 693{
683 char *token; 694 char *token;
684 695
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0) 696 if (read_expected(EVENT_ITEM, "name") < 0)
686 return NULL; 697 return NULL;
687 698
688 if (read_expected(EVENT_OP, (char *)":") < 0) 699 if (read_expected(EVENT_OP, ":") < 0)
689 return NULL; 700 return NULL;
690 701
691 if (read_expect_type(EVENT_ITEM, &token) < 0) 702 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -703,10 +714,10 @@ static int event_read_id(void)
703 char *token; 714 char *token;
704 int id; 715 int id;
705 716
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0) 717 if (read_expected_item(EVENT_ITEM, "ID") < 0)
707 return -1; 718 return -1;
708 719
709 if (read_expected(EVENT_OP, (char *)":") < 0) 720 if (read_expected(EVENT_OP, ":") < 0)
710 return -1; 721 return -1;
711 722
712 if (read_expect_type(EVENT_ITEM, &token) < 0) 723 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -721,6 +732,24 @@ static int event_read_id(void)
721 return -1; 732 return -1;
722} 733}
723 734
735static int field_is_string(struct format_field *field)
736{
737 if ((field->flags & FIELD_IS_ARRAY) &&
738 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
739 !strstr(field->type, "s8")))
740 return 1;
741
742 return 0;
743}
744
745static int field_is_dynamic(struct format_field *field)
746{
747 if (!strcmp(field->type, "__data_loc"))
748 return 1;
749
750 return 0;
751}
752
724static int event_read_fields(struct event *event, struct format_field **fields) 753static int event_read_fields(struct event *event, struct format_field **fields)
725{ 754{
726 struct format_field *field = NULL; 755 struct format_field *field = NULL;
@@ -738,7 +767,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
738 767
739 count++; 768 count++;
740 769
741 if (test_type_token(type, token, EVENT_ITEM, (char *)"field")) 770 if (test_type_token(type, token, EVENT_ITEM, "field"))
742 goto fail; 771 goto fail;
743 free_token(token); 772 free_token(token);
744 773
@@ -753,7 +782,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
753 type = read_token(&token); 782 type = read_token(&token);
754 } 783 }
755 784
756 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0) 785 if (test_type_token(type, token, EVENT_OP, ":") < 0)
757 return -1; 786 return -1;
758 787
759 if (read_expect_type(EVENT_ITEM, &token) < 0) 788 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -865,14 +894,20 @@ static int event_read_fields(struct event *event, struct format_field **fields)
865 free(brackets); 894 free(brackets);
866 } 895 }
867 896
868 if (test_type_token(type, token, EVENT_OP, (char *)";")) 897 if (field_is_string(field)) {
898 field->flags |= FIELD_IS_STRING;
899 if (field_is_dynamic(field))
900 field->flags |= FIELD_IS_DYNAMIC;
901 }
902
903 if (test_type_token(type, token, EVENT_OP, ";"))
869 goto fail; 904 goto fail;
870 free_token(token); 905 free_token(token);
871 906
872 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 907 if (read_expected(EVENT_ITEM, "offset") < 0)
873 goto fail_expect; 908 goto fail_expect;
874 909
875 if (read_expected(EVENT_OP, (char *)":") < 0) 910 if (read_expected(EVENT_OP, ":") < 0)
876 goto fail_expect; 911 goto fail_expect;
877 912
878 if (read_expect_type(EVENT_ITEM, &token)) 913 if (read_expect_type(EVENT_ITEM, &token))
@@ -880,13 +915,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
880 field->offset = strtoul(token, NULL, 0); 915 field->offset = strtoul(token, NULL, 0);
881 free_token(token); 916 free_token(token);
882 917
883 if (read_expected(EVENT_OP, (char *)";") < 0) 918 if (read_expected(EVENT_OP, ";") < 0)
884 goto fail_expect; 919 goto fail_expect;
885 920
886 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 921 if (read_expected(EVENT_ITEM, "size") < 0)
887 goto fail_expect; 922 goto fail_expect;
888 923
889 if (read_expected(EVENT_OP, (char *)":") < 0) 924 if (read_expected(EVENT_OP, ":") < 0)
890 goto fail_expect; 925 goto fail_expect;
891 926
892 if (read_expect_type(EVENT_ITEM, &token)) 927 if (read_expect_type(EVENT_ITEM, &token))
@@ -894,11 +929,34 @@ static int event_read_fields(struct event *event, struct format_field **fields)
894 field->size = strtoul(token, NULL, 0); 929 field->size = strtoul(token, NULL, 0);
895 free_token(token); 930 free_token(token);
896 931
897 if (read_expected(EVENT_OP, (char *)";") < 0) 932 if (read_expected(EVENT_OP, ";") < 0)
898 goto fail_expect; 933 goto fail_expect;
899 934
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0) 935 type = read_token(&token);
901 goto fail; 936 if (type != EVENT_NEWLINE) {
937 /* newer versions of the kernel have a "signed" type */
938 if (test_type_token(type, token, EVENT_ITEM, "signed"))
939 goto fail;
940
941 free_token(token);
942
943 if (read_expected(EVENT_OP, ":") < 0)
944 goto fail_expect;
945
946 if (read_expect_type(EVENT_ITEM, &token))
947 goto fail;
948
949 if (strtoul(token, NULL, 0))
950 field->flags |= FIELD_IS_SIGNED;
951
952 free_token(token);
953 if (read_expected(EVENT_OP, ";") < 0)
954 goto fail_expect;
955
956 if (read_expect_type(EVENT_NEWLINE, &token))
957 goto fail;
958 }
959
902 free_token(token); 960 free_token(token);
903 961
904 *fields = field; 962 *fields = field;
@@ -921,10 +979,10 @@ static int event_read_format(struct event *event)
921 char *token; 979 char *token;
922 int ret; 980 int ret;
923 981
924 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0) 982 if (read_expected_item(EVENT_ITEM, "format") < 0)
925 return -1; 983 return -1;
926 984
927 if (read_expected(EVENT_OP, (char *)":") < 0) 985 if (read_expected(EVENT_OP, ":") < 0)
928 return -1; 986 return -1;
929 987
930 if (read_expect_type(EVENT_NEWLINE, &token)) 988 if (read_expect_type(EVENT_NEWLINE, &token))
@@ -984,7 +1042,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
984 1042
985 *tok = NULL; 1043 *tok = NULL;
986 type = process_arg(event, left, &token); 1044 type = process_arg(event, left, &token);
987 if (test_type_token(type, token, EVENT_OP, (char *)":")) 1045 if (test_type_token(type, token, EVENT_OP, ":"))
988 goto out_free; 1046 goto out_free;
989 1047
990 arg->op.op = token; 1048 arg->op.op = token;
@@ -1004,6 +1062,35 @@ out_free:
1004 return EVENT_ERROR; 1062 return EVENT_ERROR;
1005} 1063}
1006 1064
1065static enum event_type
1066process_array(struct event *event, struct print_arg *top, char **tok)
1067{
1068 struct print_arg *arg;
1069 enum event_type type;
1070 char *token = NULL;
1071
1072 arg = malloc_or_die(sizeof(*arg));
1073 memset(arg, 0, sizeof(*arg));
1074
1075 *tok = NULL;
1076 type = process_arg(event, arg, &token);
1077 if (test_type_token(type, token, EVENT_OP, "]"))
1078 goto out_free;
1079
1080 top->op.right = arg;
1081
1082 free_token(token);
1083 type = read_token_item(&token);
1084 *tok = token;
1085
1086 return type;
1087
1088out_free:
1089 free_token(*tok);
1090 free_arg(arg);
1091 return EVENT_ERROR;
1092}
1093
1007static int get_op_prio(char *op) 1094static int get_op_prio(char *op)
1008{ 1095{
1009 if (!op[1]) { 1096 if (!op[1]) {
@@ -1128,6 +1215,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1128 strcmp(token, "*") == 0 || 1215 strcmp(token, "*") == 0 ||
1129 strcmp(token, "^") == 0 || 1216 strcmp(token, "^") == 0 ||
1130 strcmp(token, "/") == 0 || 1217 strcmp(token, "/") == 0 ||
1218 strcmp(token, "<") == 0 ||
1219 strcmp(token, ">") == 0 ||
1131 strcmp(token, "==") == 0 || 1220 strcmp(token, "==") == 0 ||
1132 strcmp(token, "!=") == 0) { 1221 strcmp(token, "!=") == 0) {
1133 1222
@@ -1144,17 +1233,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1144 1233
1145 right = malloc_or_die(sizeof(*right)); 1234 right = malloc_or_die(sizeof(*right));
1146 1235
1147 type = process_arg(event, right, tok); 1236 type = read_token_item(&token);
1237 *tok = token;
1238
1239 /* could just be a type pointer */
1240 if ((strcmp(arg->op.op, "*") == 0) &&
1241 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1242 if (left->type != PRINT_ATOM)
1243 die("bad pointer type");
1244 left->atom.atom = realloc(left->atom.atom,
1245 sizeof(left->atom.atom) + 3);
1246 strcat(left->atom.atom, " *");
1247 *arg = *left;
1248 free(arg);
1249
1250 return type;
1251 }
1252
1253 type = process_arg_token(event, right, tok, type);
1148 1254
1149 arg->op.right = right; 1255 arg->op.right = right;
1150 1256
1257 } else if (strcmp(token, "[") == 0) {
1258
1259 left = malloc_or_die(sizeof(*left));
1260 *left = *arg;
1261
1262 arg->type = PRINT_OP;
1263 arg->op.op = token;
1264 arg->op.left = left;
1265
1266 arg->op.prio = 0;
1267 type = process_array(event, arg, tok);
1268
1151 } else { 1269 } else {
1152 die("unknown op '%s'", token); 1270 warning("unknown op '%s'", token);
1271 event->flags |= EVENT_FL_FAILED;
1153 /* the arg is now the left side */ 1272 /* the arg is now the left side */
1154 return EVENT_NONE; 1273 return EVENT_NONE;
1155 } 1274 }
1156 1275
1157
1158 if (type == EVENT_OP) { 1276 if (type == EVENT_OP) {
1159 int prio; 1277 int prio;
1160 1278
@@ -1178,7 +1296,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1178 char *field; 1296 char *field;
1179 char *token; 1297 char *token;
1180 1298
1181 if (read_expected(EVENT_OP, (char *)"->") < 0) 1299 if (read_expected(EVENT_OP, "->") < 0)
1182 return EVENT_ERROR; 1300 return EVENT_ERROR;
1183 1301
1184 if (read_expect_type(EVENT_ITEM, &token) < 0) 1302 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1188,6 +1306,16 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1188 arg->type = PRINT_FIELD; 1306 arg->type = PRINT_FIELD;
1189 arg->field.name = field; 1307 arg->field.name = field;
1190 1308
1309 if (is_flag_field) {
1310 arg->field.field = find_any_field(event, arg->field.name);
1311 arg->field.field->flags |= FIELD_IS_FLAG;
1312 is_flag_field = 0;
1313 } else if (is_symbolic_field) {
1314 arg->field.field = find_any_field(event, arg->field.name);
1315 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1316 is_symbolic_field = 0;
1317 }
1318
1191 type = read_token(&token); 1319 type = read_token(&token);
1192 *tok = token; 1320 *tok = token;
1193 1321
@@ -1338,25 +1466,25 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1338 do { 1466 do {
1339 free_token(token); 1467 free_token(token);
1340 type = read_token_item(&token); 1468 type = read_token_item(&token);
1341 if (test_type_token(type, token, EVENT_OP, (char *)"{")) 1469 if (test_type_token(type, token, EVENT_OP, "{"))
1342 break; 1470 break;
1343 1471
1344 arg = malloc_or_die(sizeof(*arg)); 1472 arg = malloc_or_die(sizeof(*arg));
1345 1473
1346 free_token(token); 1474 free_token(token);
1347 type = process_arg(event, arg, &token); 1475 type = process_arg(event, arg, &token);
1348 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1476 if (test_type_token(type, token, EVENT_DELIM, ","))
1349 goto out_free; 1477 goto out_free;
1350 1478
1351 field = malloc_or_die(sizeof(*field)); 1479 field = malloc_or_die(sizeof(*field));
1352 memset(field, 0, sizeof(field)); 1480 memset(field, 0, sizeof(*field));
1353 1481
1354 value = arg_eval(arg); 1482 value = arg_eval(arg);
1355 field->value = strdup(value); 1483 field->value = strdup(value);
1356 1484
1357 free_token(token); 1485 free_token(token);
1358 type = process_arg(event, arg, &token); 1486 type = process_arg(event, arg, &token);
1359 if (test_type_token(type, token, EVENT_OP, (char *)"}")) 1487 if (test_type_token(type, token, EVENT_OP, "}"))
1360 goto out_free; 1488 goto out_free;
1361 1489
1362 value = arg_eval(arg); 1490 value = arg_eval(arg);
@@ -1391,13 +1519,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1391 memset(arg, 0, sizeof(*arg)); 1519 memset(arg, 0, sizeof(*arg));
1392 arg->type = PRINT_FLAGS; 1520 arg->type = PRINT_FLAGS;
1393 1521
1394 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1522 if (read_expected_item(EVENT_DELIM, "(") < 0)
1395 return EVENT_ERROR; 1523 return EVENT_ERROR;
1396 1524
1397 field = malloc_or_die(sizeof(*field)); 1525 field = malloc_or_die(sizeof(*field));
1398 1526
1399 type = process_arg(event, field, &token); 1527 type = process_arg(event, field, &token);
1400 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1528 if (test_type_token(type, token, EVENT_DELIM, ","))
1401 goto out_free; 1529 goto out_free;
1402 1530
1403 arg->flags.field = field; 1531 arg->flags.field = field;
@@ -1408,11 +1536,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1408 type = read_token_item(&token); 1536 type = read_token_item(&token);
1409 } 1537 }
1410 1538
1411 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1539 if (test_type_token(type, token, EVENT_DELIM, ","))
1412 goto out_free; 1540 goto out_free;
1413 1541
1414 type = process_fields(event, &arg->flags.flags, &token); 1542 type = process_fields(event, &arg->flags.flags, &token);
1415 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1543 if (test_type_token(type, token, EVENT_DELIM, ")"))
1416 goto out_free; 1544 goto out_free;
1417 1545
1418 free_token(token); 1546 free_token(token);
@@ -1434,19 +1562,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
1434 memset(arg, 0, sizeof(*arg)); 1562 memset(arg, 0, sizeof(*arg));
1435 arg->type = PRINT_SYMBOL; 1563 arg->type = PRINT_SYMBOL;
1436 1564
1437 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1565 if (read_expected_item(EVENT_DELIM, "(") < 0)
1438 return EVENT_ERROR; 1566 return EVENT_ERROR;
1439 1567
1440 field = malloc_or_die(sizeof(*field)); 1568 field = malloc_or_die(sizeof(*field));
1441 1569
1442 type = process_arg(event, field, &token); 1570 type = process_arg(event, field, &token);
1443 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1571 if (test_type_token(type, token, EVENT_DELIM, ","))
1444 goto out_free; 1572 goto out_free;
1445 1573
1446 arg->symbol.field = field; 1574 arg->symbol.field = field;
1447 1575
1448 type = process_fields(event, &arg->symbol.symbols, &token); 1576 type = process_fields(event, &arg->symbol.symbols, &token);
1449 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1577 if (test_type_token(type, token, EVENT_DELIM, ")"))
1450 goto out_free; 1578 goto out_free;
1451 1579
1452 free_token(token); 1580 free_token(token);
@@ -1463,7 +1591,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1463{ 1591{
1464 struct print_arg *item_arg; 1592 struct print_arg *item_arg;
1465 enum event_type type; 1593 enum event_type type;
1466 int ptr_cast = 0;
1467 char *token; 1594 char *token;
1468 1595
1469 type = process_arg(event, arg, &token); 1596 type = process_arg(event, arg, &token);
@@ -1471,28 +1598,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1471 if (type == EVENT_ERROR) 1598 if (type == EVENT_ERROR)
1472 return EVENT_ERROR; 1599 return EVENT_ERROR;
1473 1600
1474 if (type == EVENT_OP) { 1601 if (type == EVENT_OP)
1475 /* handle the ptr casts */ 1602 type = process_op(event, arg, &token);
1476 if (!strcmp(token, "*")) {
1477 /*
1478 * FIXME: should we zapp whitespaces before ')' ?
1479 * (may require a peek_token_item())
1480 */
1481 if (__peek_char() == ')') {
1482 ptr_cast = 1;
1483 free_token(token);
1484 type = read_token_item(&token);
1485 }
1486 }
1487 if (!ptr_cast) {
1488 type = process_op(event, arg, &token);
1489 1603
1490 if (type == EVENT_ERROR) 1604 if (type == EVENT_ERROR)
1491 return EVENT_ERROR; 1605 return EVENT_ERROR;
1492 }
1493 }
1494 1606
1495 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { 1607 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1496 free_token(token); 1608 free_token(token);
1497 return EVENT_ERROR; 1609 return EVENT_ERROR;
1498 } 1610 }
@@ -1516,13 +1628,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1516 item_arg = malloc_or_die(sizeof(*item_arg)); 1628 item_arg = malloc_or_die(sizeof(*item_arg));
1517 1629
1518 arg->type = PRINT_TYPE; 1630 arg->type = PRINT_TYPE;
1519 if (ptr_cast) {
1520 char *old = arg->atom.atom;
1521
1522 arg->atom.atom = malloc_or_die(strlen(old + 3));
1523 sprintf(arg->atom.atom, "%s *", old);
1524 free(old);
1525 }
1526 arg->typecast.type = arg->atom.atom; 1631 arg->typecast.type = arg->atom.atom;
1527 arg->typecast.item = item_arg; 1632 arg->typecast.item = item_arg;
1528 type = process_arg_token(event, item_arg, &token, type); 1633 type = process_arg_token(event, item_arg, &token, type);
@@ -1540,7 +1645,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1540 enum event_type type; 1645 enum event_type type;
1541 char *token; 1646 char *token;
1542 1647
1543 if (read_expected(EVENT_DELIM, (char *)"(") < 0) 1648 if (read_expected(EVENT_DELIM, "(") < 0)
1544 return EVENT_ERROR; 1649 return EVENT_ERROR;
1545 1650
1546 if (read_expect_type(EVENT_ITEM, &token) < 0) 1651 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1550,7 +1655,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1550 arg->string.string = token; 1655 arg->string.string = token;
1551 arg->string.offset = -1; 1656 arg->string.offset = -1;
1552 1657
1553 if (read_expected(EVENT_DELIM, (char *)")") < 0) 1658 if (read_expected(EVENT_DELIM, ")") < 0)
1554 return EVENT_ERROR; 1659 return EVENT_ERROR;
1555 1660
1556 type = read_token(&token); 1661 type = read_token(&token);
@@ -1578,9 +1683,11 @@ process_arg_token(struct event *event, struct print_arg *arg,
1578 type = process_entry(event, arg, &token); 1683 type = process_entry(event, arg, &token);
1579 } else if (strcmp(token, "__print_flags") == 0) { 1684 } else if (strcmp(token, "__print_flags") == 0) {
1580 free_token(token); 1685 free_token(token);
1686 is_flag_field = 1;
1581 type = process_flags(event, arg, &token); 1687 type = process_flags(event, arg, &token);
1582 } else if (strcmp(token, "__print_symbolic") == 0) { 1688 } else if (strcmp(token, "__print_symbolic") == 0) {
1583 free_token(token); 1689 free_token(token);
1690 is_symbolic_field = 1;
1584 type = process_symbols(event, arg, &token); 1691 type = process_symbols(event, arg, &token);
1585 } else if (strcmp(token, "__get_str") == 0) { 1692 } else if (strcmp(token, "__get_str") == 0) {
1586 free_token(token); 1693 free_token(token);
@@ -1637,12 +1744,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
1637 1744
1638static int event_read_print_args(struct event *event, struct print_arg **list) 1745static int event_read_print_args(struct event *event, struct print_arg **list)
1639{ 1746{
1640 enum event_type type; 1747 enum event_type type = EVENT_ERROR;
1641 struct print_arg *arg; 1748 struct print_arg *arg;
1642 char *token; 1749 char *token;
1643 int args = 0; 1750 int args = 0;
1644 1751
1645 do { 1752 do {
1753 if (type == EVENT_NEWLINE) {
1754 free_token(token);
1755 type = read_token_item(&token);
1756 continue;
1757 }
1758
1646 arg = malloc_or_die(sizeof(*arg)); 1759 arg = malloc_or_die(sizeof(*arg));
1647 memset(arg, 0, sizeof(*arg)); 1760 memset(arg, 0, sizeof(*arg));
1648 1761
@@ -1683,18 +1796,19 @@ static int event_read_print(struct event *event)
1683 char *token; 1796 char *token;
1684 int ret; 1797 int ret;
1685 1798
1686 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0) 1799 if (read_expected_item(EVENT_ITEM, "print") < 0)
1687 return -1; 1800 return -1;
1688 1801
1689 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0) 1802 if (read_expected(EVENT_ITEM, "fmt") < 0)
1690 return -1; 1803 return -1;
1691 1804
1692 if (read_expected(EVENT_OP, (char *)":") < 0) 1805 if (read_expected(EVENT_OP, ":") < 0)
1693 return -1; 1806 return -1;
1694 1807
1695 if (read_expect_type(EVENT_DQUOTE, &token) < 0) 1808 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1696 goto fail; 1809 goto fail;
1697 1810
1811 concat:
1698 event->print_fmt.format = token; 1812 event->print_fmt.format = token;
1699 event->print_fmt.args = NULL; 1813 event->print_fmt.args = NULL;
1700 1814
@@ -1704,7 +1818,22 @@ static int event_read_print(struct event *event)
1704 if (type == EVENT_NONE) 1818 if (type == EVENT_NONE)
1705 return 0; 1819 return 0;
1706 1820
1707 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1821 /* Handle concatination of print lines */
1822 if (type == EVENT_DQUOTE) {
1823 char *cat;
1824
1825 cat = malloc_or_die(strlen(event->print_fmt.format) +
1826 strlen(token) + 1);
1827 strcpy(cat, event->print_fmt.format);
1828 strcat(cat, token);
1829 free_token(token);
1830 free_token(event->print_fmt.format);
1831 event->print_fmt.format = NULL;
1832 token = cat;
1833 goto concat;
1834 }
1835
1836 if (test_type_token(type, token, EVENT_DELIM, ","))
1708 goto fail; 1837 goto fail;
1709 1838
1710 free_token(token); 1839 free_token(token);
@@ -1713,7 +1842,7 @@ static int event_read_print(struct event *event)
1713 if (ret < 0) 1842 if (ret < 0)
1714 return -1; 1843 return -1;
1715 1844
1716 return 0; 1845 return ret;
1717 1846
1718 fail: 1847 fail:
1719 free_token(token); 1848 free_token(token);
@@ -1759,7 +1888,7 @@ find_any_field(struct event *event, const char *name)
1759 return find_field(event, name); 1888 return find_field(event, name);
1760} 1889}
1761 1890
1762static unsigned long long read_size(void *ptr, int size) 1891unsigned long long read_size(void *ptr, int size)
1763{ 1892{
1764 switch (size) { 1893 switch (size) {
1765 case 1: 1894 case 1:
@@ -1796,6 +1925,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data)
1796 if (!field) 1925 if (!field)
1797 return NULL; 1926 return NULL;
1798 1927
1928 if (field->flags & FIELD_IS_DYNAMIC) {
1929 int offset;
1930
1931 offset = *(int *)(data + field->offset);
1932 offset &= 0xffff;
1933
1934 return data + offset;
1935 }
1936
1799 return data + field->offset; 1937 return data + field->offset;
1800} 1938}
1801 1939
@@ -1822,37 +1960,67 @@ static int get_common_info(const char *type, int *offset, int *size)
1822 return 0; 1960 return 0;
1823} 1961}
1824 1962
1825int trace_parse_common_type(void *data) 1963static int __parse_common(void *data, int *size, int *offset,
1964 const char *name)
1826{ 1965{
1827 static int type_offset;
1828 static int type_size;
1829 int ret; 1966 int ret;
1830 1967
1831 if (!type_size) { 1968 if (!*size) {
1832 ret = get_common_info("common_type", 1969 ret = get_common_info(name, offset, size);
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0) 1970 if (ret < 0)
1836 return ret; 1971 return ret;
1837 } 1972 }
1838 return read_size(data + type_offset, type_size); 1973 return read_size(data + *offset, *size);
1839} 1974}
1840 1975
1841static int parse_common_pid(void *data) 1976int trace_parse_common_type(void *data)
1977{
1978 static int type_offset;
1979 static int type_size;
1980
1981 return __parse_common(data, &type_size, &type_offset,
1982 "common_type");
1983}
1984
1985int trace_parse_common_pid(void *data)
1842{ 1986{
1843 static int pid_offset; 1987 static int pid_offset;
1844 static int pid_size; 1988 static int pid_size;
1989
1990 return __parse_common(data, &pid_size, &pid_offset,
1991 "common_pid");
1992}
1993
1994int parse_common_pc(void *data)
1995{
1996 static int pc_offset;
1997 static int pc_size;
1998
1999 return __parse_common(data, &pc_size, &pc_offset,
2000 "common_preempt_count");
2001}
2002
2003int parse_common_flags(void *data)
2004{
2005 static int flags_offset;
2006 static int flags_size;
2007
2008 return __parse_common(data, &flags_size, &flags_offset,
2009 "common_flags");
2010}
2011
2012int parse_common_lock_depth(void *data)
2013{
2014 static int ld_offset;
2015 static int ld_size;
1845 int ret; 2016 int ret;
1846 2017
1847 if (!pid_size) { 2018 ret = __parse_common(data, &ld_size, &ld_offset,
1848 ret = get_common_info("common_pid", 2019 "common_lock_depth");
1849 &pid_offset, 2020 if (ret < 0)
1850 &pid_size); 2021 return -1;
1851 if (ret < 0)
1852 return ret;
1853 }
1854 2022
1855 return read_size(data + pid_offset, pid_size); 2023 return ret;
1856} 2024}
1857 2025
1858struct event *trace_find_event(int id) 2026struct event *trace_find_event(int id)
@@ -1866,11 +2034,20 @@ struct event *trace_find_event(int id)
1866 return event; 2034 return event;
1867} 2035}
1868 2036
2037struct event *trace_find_next_event(struct event *event)
2038{
2039 if (!event)
2040 return event_list;
2041
2042 return event->next;
2043}
2044
1869static unsigned long long eval_num_arg(void *data, int size, 2045static unsigned long long eval_num_arg(void *data, int size,
1870 struct event *event, struct print_arg *arg) 2046 struct event *event, struct print_arg *arg)
1871{ 2047{
1872 unsigned long long val = 0; 2048 unsigned long long val = 0;
1873 unsigned long long left, right; 2049 unsigned long long left, right;
2050 struct print_arg *larg;
1874 2051
1875 switch (arg->type) { 2052 switch (arg->type) {
1876 case PRINT_NULL: 2053 case PRINT_NULL:
@@ -1897,6 +2074,26 @@ static unsigned long long eval_num_arg(void *data, int size,
1897 return 0; 2074 return 0;
1898 break; 2075 break;
1899 case PRINT_OP: 2076 case PRINT_OP:
2077 if (strcmp(arg->op.op, "[") == 0) {
2078 /*
2079 * Arrays are special, since we don't want
2080 * to read the arg as is.
2081 */
2082 if (arg->op.left->type != PRINT_FIELD)
2083 goto default_op; /* oops, all bets off */
2084 larg = arg->op.left;
2085 if (!larg->field.field) {
2086 larg->field.field =
2087 find_any_field(event, larg->field.name);
2088 if (!larg->field.field)
2089 die("field %s not found", larg->field.name);
2090 }
2091 right = eval_num_arg(data, size, event, arg->op.right);
2092 val = read_size(data + larg->field.field->offset +
2093 right * long_size, long_size);
2094 break;
2095 }
2096 default_op:
1900 left = eval_num_arg(data, size, event, arg->op.left); 2097 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right); 2098 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) { 2099 switch (arg->op.op[0]) {
@@ -1947,6 +2144,12 @@ static unsigned long long eval_num_arg(void *data, int size,
1947 die("unknown op '%s'", arg->op.op); 2144 die("unknown op '%s'", arg->op.op);
1948 val = left == right; 2145 val = left == right;
1949 break; 2146 break;
2147 case '-':
2148 val = left - right;
2149 break;
2150 case '+':
2151 val = left + right;
2152 break;
1950 default: 2153 default:
1951 die("unknown op '%s'", arg->op.op); 2154 die("unknown op '%s'", arg->op.op);
1952 } 2155 }
@@ -1978,7 +2181,7 @@ static const struct flag flags[] = {
1978 { "HRTIMER_RESTART", 1 }, 2181 { "HRTIMER_RESTART", 1 },
1979}; 2182};
1980 2183
1981static unsigned long long eval_flag(const char *flag) 2184unsigned long long eval_flag(const char *flag)
1982{ 2185{
1983 int i; 2186 int i;
1984 2187
@@ -2145,8 +2348,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
2145 case 'u': 2348 case 'u':
2146 case 'x': 2349 case 'x':
2147 case 'i': 2350 case 'i':
2148 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & 2351 /* the pointers are always 4 bytes aligned */
2149 ~(long_size - 1)); 2352 bptr = (void *)(((unsigned long)bptr + 3) &
2353 ~3);
2150 switch (ls) { 2354 switch (ls) {
2151 case 0: 2355 case 0:
2152 case 1: 2356 case 1:
@@ -2270,7 +2474,27 @@ static void pretty_print(void *data, int size, struct event *event)
2270 2474
2271 for (; *ptr; ptr++) { 2475 for (; *ptr; ptr++) {
2272 ls = 0; 2476 ls = 0;
2273 if (*ptr == '%') { 2477 if (*ptr == '\\') {
2478 ptr++;
2479 switch (*ptr) {
2480 case 'n':
2481 printf("\n");
2482 break;
2483 case 't':
2484 printf("\t");
2485 break;
2486 case 'r':
2487 printf("\r");
2488 break;
2489 case '\\':
2490 printf("\\");
2491 break;
2492 default:
2493 printf("%c", *ptr);
2494 break;
2495 }
2496
2497 } else if (*ptr == '%') {
2274 saveptr = ptr; 2498 saveptr = ptr;
2275 show_func = 0; 2499 show_func = 0;
2276 cont_process: 2500 cont_process:
@@ -2377,6 +2601,41 @@ static inline int log10_cpu(int nb)
2377 return 1; 2601 return 1;
2378} 2602}
2379 2603
2604static void print_lat_fmt(void *data, int size __unused)
2605{
2606 unsigned int lat_flags;
2607 unsigned int pc;
2608 int lock_depth;
2609 int hardirq;
2610 int softirq;
2611
2612 lat_flags = parse_common_flags(data);
2613 pc = parse_common_pc(data);
2614 lock_depth = parse_common_lock_depth(data);
2615
2616 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2617 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2618
2619 printf("%c%c%c",
2620 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2621 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2622 'X' : '.',
2623 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2624 'N' : '.',
2625 (hardirq && softirq) ? 'H' :
2626 hardirq ? 'h' : softirq ? 's' : '.');
2627
2628 if (pc)
2629 printf("%x", pc);
2630 else
2631 printf(".");
2632
2633 if (lock_depth < 0)
2634 printf(".");
2635 else
2636 printf("%d", lock_depth);
2637}
2638
2380/* taken from Linux, written by Frederic Weisbecker */ 2639/* taken from Linux, written by Frederic Weisbecker */
2381static void print_graph_cpu(int cpu) 2640static void print_graph_cpu(int cpu)
2382{ 2641{
@@ -2452,7 +2711,7 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2452 if (!(event->flags & EVENT_FL_ISFUNCRET)) 2711 if (!(event->flags & EVENT_FL_ISFUNCRET))
2453 return NULL; 2712 return NULL;
2454 2713
2455 pid = parse_common_pid(next->data); 2714 pid = trace_parse_common_pid(next->data);
2456 field = find_field(event, "func"); 2715 field = find_field(event, "func");
2457 if (!field) 2716 if (!field)
2458 die("function return does not have field func"); 2717 die("function return does not have field func");
@@ -2620,6 +2879,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
2620 2879
2621 printf(" | "); 2880 printf(" | ");
2622 2881
2882 if (latency_format) {
2883 print_lat_fmt(data, size);
2884 printf(" | ");
2885 }
2886
2623 field = find_field(event, "func"); 2887 field = find_field(event, "func");
2624 if (!field) 2888 if (!field)
2625 die("function entry does not have func field"); 2889 die("function entry does not have func field");
@@ -2663,6 +2927,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2663 2927
2664 printf(" | "); 2928 printf(" | ");
2665 2929
2930 if (latency_format) {
2931 print_lat_fmt(data, size);
2932 printf(" | ");
2933 }
2934
2666 field = find_field(event, "rettime"); 2935 field = find_field(event, "rettime");
2667 if (!field) 2936 if (!field)
2668 die("can't find rettime in return graph"); 2937 die("can't find rettime in return graph");
@@ -2724,19 +2993,30 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2724 2993
2725 event = trace_find_event(type); 2994 event = trace_find_event(type);
2726 if (!event) { 2995 if (!event) {
2727 printf("ug! no event found for type %d\n", type); 2996 warning("ug! no event found for type %d", type);
2728 return; 2997 return;
2729 } 2998 }
2730 2999
2731 pid = parse_common_pid(data); 3000 pid = trace_parse_common_pid(data);
2732 3001
2733 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) 3002 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2734 return pretty_print_func_graph(data, size, event, cpu, 3003 return pretty_print_func_graph(data, size, event, cpu,
2735 pid, comm, secs, usecs); 3004 pid, comm, secs, usecs);
2736 3005
2737 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ", 3006 if (latency_format) {
2738 comm, pid, cpu, 3007 printf("%8.8s-%-5d %3d",
2739 secs, nsecs, event->name); 3008 comm, pid, cpu);
3009 print_lat_fmt(data, size);
3010 } else
3011 printf("%16s-%-5d [%03d]", comm, pid, cpu);
3012
3013 printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
3014
3015 if (event->flags & EVENT_FL_FAILED) {
3016 printf("EVENT '%s' FAILED TO PARSE\n",
3017 event->name);
3018 return;
3019 }
2740 3020
2741 pretty_print(data, size, event); 3021 pretty_print(data, size, event);
2742 printf("\n"); 3022 printf("\n");
@@ -2807,46 +3087,71 @@ static void print_args(struct print_arg *args)
2807 } 3087 }
2808} 3088}
2809 3089
2810static void parse_header_field(char *type, 3090static void parse_header_field(const char *field,
2811 int *offset, int *size) 3091 int *offset, int *size)
2812{ 3092{
2813 char *token; 3093 char *token;
3094 int type;
2814 3095
2815 if (read_expected(EVENT_ITEM, (char *)"field") < 0) 3096 if (read_expected(EVENT_ITEM, "field") < 0)
2816 return; 3097 return;
2817 if (read_expected(EVENT_OP, (char *)":") < 0) 3098 if (read_expected(EVENT_OP, ":") < 0)
2818 return; 3099 return;
3100
2819 /* type */ 3101 /* type */
2820 if (read_expect_type(EVENT_ITEM, &token) < 0) 3102 if (read_expect_type(EVENT_ITEM, &token) < 0)
2821 return; 3103 goto fail;
2822 free_token(token); 3104 free_token(token);
2823 3105
2824 if (read_expected(EVENT_ITEM, type) < 0) 3106 if (read_expected(EVENT_ITEM, field) < 0)
2825 return; 3107 return;
2826 if (read_expected(EVENT_OP, (char *)";") < 0) 3108 if (read_expected(EVENT_OP, ";") < 0)
2827 return; 3109 return;
2828 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 3110 if (read_expected(EVENT_ITEM, "offset") < 0)
2829 return; 3111 return;
2830 if (read_expected(EVENT_OP, (char *)":") < 0) 3112 if (read_expected(EVENT_OP, ":") < 0)
2831 return; 3113 return;
2832 if (read_expect_type(EVENT_ITEM, &token) < 0) 3114 if (read_expect_type(EVENT_ITEM, &token) < 0)
2833 return; 3115 goto fail;
2834 *offset = atoi(token); 3116 *offset = atoi(token);
2835 free_token(token); 3117 free_token(token);
2836 if (read_expected(EVENT_OP, (char *)";") < 0) 3118 if (read_expected(EVENT_OP, ";") < 0)
2837 return; 3119 return;
2838 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 3120 if (read_expected(EVENT_ITEM, "size") < 0)
2839 return; 3121 return;
2840 if (read_expected(EVENT_OP, (char *)":") < 0) 3122 if (read_expected(EVENT_OP, ":") < 0)
2841 return; 3123 return;
2842 if (read_expect_type(EVENT_ITEM, &token) < 0) 3124 if (read_expect_type(EVENT_ITEM, &token) < 0)
2843 return; 3125 goto fail;
2844 *size = atoi(token); 3126 *size = atoi(token);
2845 free_token(token); 3127 free_token(token);
2846 if (read_expected(EVENT_OP, (char *)";") < 0) 3128 if (read_expected(EVENT_OP, ";") < 0)
2847 return;
2848 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2849 return; 3129 return;
3130 type = read_token(&token);
3131 if (type != EVENT_NEWLINE) {
3132 /* newer versions of the kernel have a "signed" type */
3133 if (type != EVENT_ITEM)
3134 goto fail;
3135
3136 if (strcmp(token, "signed") != 0)
3137 goto fail;
3138
3139 free_token(token);
3140
3141 if (read_expected(EVENT_OP, ":") < 0)
3142 return;
3143
3144 if (read_expect_type(EVENT_ITEM, &token))
3145 goto fail;
3146
3147 free_token(token);
3148 if (read_expected(EVENT_OP, ";") < 0)
3149 return;
3150
3151 if (read_expect_type(EVENT_NEWLINE, &token))
3152 goto fail;
3153 }
3154 fail:
2850 free_token(token); 3155 free_token(token);
2851} 3156}
2852 3157
@@ -2854,11 +3159,11 @@ int parse_header_page(char *buf, unsigned long size)
2854{ 3159{
2855 init_input_buf(buf, size); 3160 init_input_buf(buf, size);
2856 3161
2857 parse_header_field((char *)"timestamp", &header_page_ts_offset, 3162 parse_header_field("timestamp", &header_page_ts_offset,
2858 &header_page_ts_size); 3163 &header_page_ts_size);
2859 parse_header_field((char *)"commit", &header_page_size_offset, 3164 parse_header_field("commit", &header_page_size_offset,
2860 &header_page_size_size); 3165 &header_page_size_size);
2861 parse_header_field((char *)"data", &header_page_data_offset, 3166 parse_header_field("data", &header_page_data_offset,
2862 &header_page_data_size); 3167 &header_page_data_size);
2863 3168
2864 return 0; 3169 return 0;
@@ -2909,6 +3214,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
2909 if (ret < 0) 3214 if (ret < 0)
2910 die("failed to read ftrace event print fmt"); 3215 die("failed to read ftrace event print fmt");
2911 3216
3217 /* New ftrace handles args */
3218 if (ret > 0)
3219 return 0;
2912 /* 3220 /*
2913 * The arguments for ftrace files are parsed by the fields. 3221 * The arguments for ftrace files are parsed by the fields.
2914 * Set up the fields as their arguments. 3222 * Set up the fields as their arguments.
@@ -2926,7 +3234,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
2926 return 0; 3234 return 0;
2927} 3235}
2928 3236
2929int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) 3237int parse_event_file(char *buf, unsigned long size, char *sys)
2930{ 3238{
2931 struct event *event; 3239 struct event *event;
2932 int ret; 3240 int ret;
@@ -2946,12 +3254,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2946 die("failed to read event id"); 3254 die("failed to read event id");
2947 3255
2948 ret = event_read_format(event); 3256 ret = event_read_format(event);
2949 if (ret < 0) 3257 if (ret < 0) {
2950 die("failed to read event format"); 3258 warning("failed to read event format for %s", event->name);
3259 goto event_failed;
3260 }
2951 3261
2952 ret = event_read_print(event); 3262 ret = event_read_print(event);
2953 if (ret < 0) 3263 if (ret < 0) {
2954 die("failed to read event print fmt"); 3264 warning("failed to read event print fmt for %s", event->name);
3265 goto event_failed;
3266 }
3267
3268 event->system = strdup(sys);
2955 3269
2956#define PRINT_ARGS 0 3270#define PRINT_ARGS 0
2957 if (PRINT_ARGS && event->print_fmt.args) 3271 if (PRINT_ARGS && event->print_fmt.args)
@@ -2959,6 +3273,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2959 3273
2960 add_event(event); 3274 add_event(event);
2961 return 0; 3275 return 0;
3276
3277 event_failed:
3278 event->flags |= EVENT_FL_FAILED;
3279 /* still add it even if it failed */
3280 add_event(event);
3281 return -1;
2962} 3282}
2963 3283
2964void parse_set_info(int nr_cpus, int long_sz) 3284void parse_set_info(int nr_cpus, int long_sz)
@@ -2966,3 +3286,18 @@ void parse_set_info(int nr_cpus, int long_sz)
2966 cpus = nr_cpus; 3286 cpus = nr_cpus;
2967 long_size = long_sz; 3287 long_size = long_sz;
2968} 3288}
3289
3290int common_pc(struct scripting_context *context)
3291{
3292 return parse_common_pc(context->event_data);
3293}
3294
3295int common_flags(struct scripting_context *context)
3296{
3297 return parse_common_flags(context->event_data);
3298}
3299
3300int common_lock_depth(struct scripting_context *context)
3301{
3302 return parse_common_lock_depth(context->event_data);
3303}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1b5c847d2c22..7cd1193918c7 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _LARGEFILE64_SOURCE 21#define _FILE_OFFSET_BITS 64
22 22
23#include <dirent.h> 23#include <dirent.h>
24#include <stdio.h> 24#include <stdio.h>
@@ -83,7 +83,7 @@ static char *read_string(void)
83 char *str = NULL; 83 char *str = NULL;
84 int size = 0; 84 int size = 0;
85 int i; 85 int i;
86 int r; 86 off_t r;
87 87
88 for (;;) { 88 for (;;) {
89 r = read(input_fd, buf, BUFSIZ); 89 r = read(input_fd, buf, BUFSIZ);
@@ -118,7 +118,7 @@ static char *read_string(void)
118 118
119 /* move the file descriptor to the end of the string */ 119 /* move the file descriptor to the end of the string */
120 r = lseek(input_fd, -(r - i), SEEK_CUR); 120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0) 121 if (r == (off_t)-1)
122 die("lseek"); 122 die("lseek");
123 123
124 if (str) { 124 if (str) {
@@ -145,8 +145,9 @@ static void read_proc_kallsyms(void)
145 if (!size) 145 if (!size)
146 return; 146 return;
147 147
148 buf = malloc_or_die(size); 148 buf = malloc_or_die(size + 1);
149 read_or_die(buf, size); 149 read_or_die(buf, size);
150 buf[size] = '\0';
150 151
151 parse_proc_kallsyms(buf, size); 152 parse_proc_kallsyms(buf, size);
152 153
@@ -281,8 +282,8 @@ static void update_cpu_data_index(int cpu)
281 282
282static void get_next_page(int cpu) 283static void get_next_page(int cpu)
283{ 284{
284 off64_t save_seek; 285 off_t save_seek;
285 off64_t ret; 286 off_t ret;
286 287
287 if (!cpu_data[cpu].page) 288 if (!cpu_data[cpu].page)
288 return; 289 return;
@@ -297,17 +298,17 @@ static void get_next_page(int cpu)
297 update_cpu_data_index(cpu); 298 update_cpu_data_index(cpu);
298 299
299 /* other parts of the code may expect the pointer to not move */ 300 /* other parts of the code may expect the pointer to not move */
300 save_seek = lseek64(input_fd, 0, SEEK_CUR); 301 save_seek = lseek(input_fd, 0, SEEK_CUR);
301 302
302 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 303 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
303 if (ret < 0) 304 if (ret == (off_t)-1)
304 die("failed to lseek"); 305 die("failed to lseek");
305 ret = read(input_fd, cpu_data[cpu].page, page_size); 306 ret = read(input_fd, cpu_data[cpu].page, page_size);
306 if (ret < 0) 307 if (ret < 0)
307 die("failed to read page"); 308 die("failed to read page");
308 309
309 /* reset the file pointer back */ 310 /* reset the file pointer back */
310 lseek64(input_fd, save_seek, SEEK_SET); 311 lseek(input_fd, save_seek, SEEK_SET);
311 312
312 return; 313 return;
313 } 314 }
@@ -458,9 +459,8 @@ struct record *trace_read_data(int cpu)
458 return data; 459 return data;
459} 460}
460 461
461void trace_report(void) 462void trace_report(int fd)
462{ 463{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ]; 464 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 465 char test[] = { 23, 8, 68 };
466 char *version; 466 char *version;
@@ -468,17 +468,15 @@ void trace_report(void)
468 int show_funcs = 0; 468 int show_funcs = 0;
469 int show_printk = 0; 469 int show_printk = 0;
470 470
471 input_fd = open(input_file, O_RDONLY); 471 input_fd = fd;
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474 472
475 read_or_die(buf, 3); 473 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0) 474 if (memcmp(buf, test, 3) != 0)
477 die("not an trace data file"); 475 die("no trace data in the file");
478 476
479 read_or_die(buf, 7); 477 read_or_die(buf, 7);
480 if (memcmp(buf, "tracing", 7) != 0) 478 if (memcmp(buf, "tracing", 7) != 0)
481 die("not a trace file (missing tracing)"); 479 die("not a trace file (missing 'tracing' tag)");
482 480
483 version = read_string(); 481 version = read_string();
484 if (show_version) 482 if (show_version)
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
new file mode 100644
index 000000000000..7ea983acfaea
--- /dev/null
+++ b/tools/perf/util/trace-event-scripting.c
@@ -0,0 +1,167 @@
1/*
2 * trace-event-scripting. Scripting engine common and initialization code.
3 *
4 * Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.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#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../perf.h"
29#include "util.h"
30#include "trace-event.h"
31
32struct scripting_context *scripting_context;
33
34static int stop_script_unsupported(void)
35{
36 return 0;
37}
38
39static void process_event_unsupported(int cpu __unused,
40 void *data __unused,
41 int size __unused,
42 unsigned long long nsecs __unused,
43 char *comm __unused)
44{
45}
46
47static void print_python_unsupported_msg(void)
48{
49 fprintf(stderr, "Python scripting not supported."
50 " Install libpython and rebuild perf to enable it.\n"
51 "For example:\n # apt-get install python-dev (ubuntu)"
52 "\n # yum install python-devel (Fedora)"
53 "\n etc.\n");
54}
55
56static int python_start_script_unsupported(const char *script __unused,
57 int argc __unused,
58 const char **argv __unused)
59{
60 print_python_unsupported_msg();
61
62 return -1;
63}
64
65static int python_generate_script_unsupported(const char *outfile __unused)
66{
67 print_python_unsupported_msg();
68
69 return -1;
70}
71
72struct scripting_ops python_scripting_unsupported_ops = {
73 .name = "Python",
74 .start_script = python_start_script_unsupported,
75 .stop_script = stop_script_unsupported,
76 .process_event = process_event_unsupported,
77 .generate_script = python_generate_script_unsupported,
78};
79
80static void register_python_scripting(struct scripting_ops *scripting_ops)
81{
82 int err;
83 err = script_spec_register("Python", scripting_ops);
84 if (err)
85 die("error registering Python script extension");
86
87 err = script_spec_register("py", scripting_ops);
88 if (err)
89 die("error registering py script extension");
90
91 scripting_context = malloc(sizeof(struct scripting_context));
92}
93
94#ifdef NO_LIBPYTHON
95void setup_python_scripting(void)
96{
97 register_python_scripting(&python_scripting_unsupported_ops);
98}
99#else
100struct scripting_ops python_scripting_ops;
101
102void setup_python_scripting(void)
103{
104 register_python_scripting(&python_scripting_ops);
105}
106#endif
107
108static void print_perl_unsupported_msg(void)
109{
110 fprintf(stderr, "Perl scripting not supported."
111 " Install libperl and rebuild perf to enable it.\n"
112 "For example:\n # apt-get install libperl-dev (ubuntu)"
113 "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
114 "\n etc.\n");
115}
116
117static int perl_start_script_unsupported(const char *script __unused,
118 int argc __unused,
119 const char **argv __unused)
120{
121 print_perl_unsupported_msg();
122
123 return -1;
124}
125
126static int perl_generate_script_unsupported(const char *outfile __unused)
127{
128 print_perl_unsupported_msg();
129
130 return -1;
131}
132
133struct scripting_ops perl_scripting_unsupported_ops = {
134 .name = "Perl",
135 .start_script = perl_start_script_unsupported,
136 .stop_script = stop_script_unsupported,
137 .process_event = process_event_unsupported,
138 .generate_script = perl_generate_script_unsupported,
139};
140
141static void register_perl_scripting(struct scripting_ops *scripting_ops)
142{
143 int err;
144 err = script_spec_register("Perl", scripting_ops);
145 if (err)
146 die("error registering Perl script extension");
147
148 err = script_spec_register("pl", scripting_ops);
149 if (err)
150 die("error registering pl script extension");
151
152 scripting_context = malloc(sizeof(struct scripting_context));
153}
154
155#ifdef NO_LIBPERL
156void setup_perl_scripting(void)
157{
158 register_perl_scripting(&perl_scripting_unsupported_ops);
159}
160#else
161struct scripting_ops perl_scripting_ops;
162
163void setup_perl_scripting(void)
164{
165 register_perl_scripting(&perl_scripting_ops);
166}
167#endif
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 693f815c9429..c3269b937db4 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,5 +1,5 @@
1#ifndef _TRACE_EVENTS_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define _TRACE_EVENTS_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include "parse-events.h" 4#include "parse-events.h"
5 5
@@ -26,6 +26,11 @@ enum {
26enum format_flags { 26enum format_flags {
27 FIELD_IS_ARRAY = 1, 27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2, 28 FIELD_IS_POINTER = 2,
29 FIELD_IS_SIGNED = 4,
30 FIELD_IS_STRING = 8,
31 FIELD_IS_DYNAMIC = 16,
32 FIELD_IS_FLAG = 32,
33 FIELD_IS_SYMBOLIC = 64,
29}; 34};
30 35
31struct format_field { 36struct format_field {
@@ -132,15 +137,18 @@ struct event {
132 int flags; 137 int flags;
133 struct format format; 138 struct format format;
134 struct print_fmt print_fmt; 139 struct print_fmt print_fmt;
140 char *system;
135}; 141};
136 142
137enum { 143enum {
138 EVENT_FL_ISFTRACE = 1, 144 EVENT_FL_ISFTRACE = 0x01,
139 EVENT_FL_ISPRINT = 2, 145 EVENT_FL_ISPRINT = 0x02,
140 EVENT_FL_ISBPRINT = 4, 146 EVENT_FL_ISBPRINT = 0x04,
141 EVENT_FL_ISFUNC = 8, 147 EVENT_FL_ISFUNC = 0x08,
142 EVENT_FL_ISFUNCENT = 16, 148 EVENT_FL_ISFUNCENT = 0x10,
143 EVENT_FL_ISFUNCRET = 32, 149 EVENT_FL_ISFUNCRET = 0x20,
150
151 EVENT_FL_FAILED = 0x80000000
144}; 152};
145 153
146struct record { 154struct record {
@@ -154,7 +162,7 @@ struct record *trace_read_data(int cpu);
154 162
155void parse_set_info(int nr_cpus, int long_sz); 163void parse_set_info(int nr_cpus, int long_sz);
156 164
157void trace_report(void); 165void trace_report(int fd);
158 166
159void *malloc_or_die(unsigned int size); 167void *malloc_or_die(unsigned int size);
160 168
@@ -166,7 +174,7 @@ void print_funcs(void);
166void print_printk(void); 174void print_printk(void);
167 175
168int parse_ftrace_file(char *buf, unsigned long size); 176int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system); 177int parse_event_file(char *buf, unsigned long size, char *sys);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs, 178void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm); 179 char *comm);
172 180
@@ -233,13 +241,53 @@ extern int header_page_size_size;
233extern int header_page_data_offset; 241extern int header_page_data_offset;
234extern int header_page_data_size; 242extern int header_page_data_size;
235 243
244extern int latency_format;
245
236int parse_header_page(char *buf, unsigned long size); 246int parse_header_page(char *buf, unsigned long size);
237int trace_parse_common_type(void *data); 247int trace_parse_common_type(void *data);
248int trace_parse_common_pid(void *data);
249int parse_common_pc(void *data);
250int parse_common_flags(void *data);
251int parse_common_lock_depth(void *data);
238struct event *trace_find_event(int id); 252struct event *trace_find_event(int id);
253struct event *trace_find_next_event(struct event *event);
254unsigned long long read_size(void *ptr, int size);
239unsigned long long 255unsigned long long
240raw_field_value(struct event *event, const char *name, void *data); 256raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data); 257void *raw_field_ptr(struct event *event, const char *name, void *data);
258unsigned long long eval_flag(const char *flag);
259
260int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
261
262/* taken from kernel/trace/trace.h */
263enum trace_flag_type {
264 TRACE_FLAG_IRQS_OFF = 0x01,
265 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
266 TRACE_FLAG_NEED_RESCHED = 0x04,
267 TRACE_FLAG_HARDIRQ = 0x08,
268 TRACE_FLAG_SOFTIRQ = 0x10,
269};
270
271struct scripting_ops {
272 const char *name;
273 int (*start_script) (const char *script, int argc, const char **argv);
274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm);
277 int (*generate_script) (const char *outfile);
278};
279
280int script_spec_register(const char *spec, struct scripting_ops *ops);
281
282void setup_perl_scripting(void);
283void setup_python_scripting(void);
284
285struct scripting_context {
286 void *event_data;
287};
242 288
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events); 289int common_pc(struct scripting_context *context);
290int common_flags(struct scripting_context *context);
291int common_lock_depth(struct scripting_context *context);
244 292
245#endif /* _TRACE_EVENTS_H */ 293#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5e75f9005940..7d6b8331f898 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_TYPES_H 1#ifndef __PERF_TYPES_H
2#define _PERF_TYPES_H 2#define __PERF_TYPES_H
3 3
4/* 4/*
5 * We define u64 as unsigned long long for every architecture 5 * We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short s16;
14typedef unsigned char u8; 14typedef unsigned char u8;
15typedef signed char s8; 15typedef signed char s8;
16 16
17#endif /* _PERF_TYPES_H */ 17#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 000000000000..f9b890fde681
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,94 @@
1#include "util.h"
2#include <sys/mman.h>
3
4int mkdir_p(char *path, mode_t mode)
5{
6 struct stat st;
7 int err;
8 char *d = path;
9
10 if (*d != '/')
11 return -1;
12
13 if (stat(path, &st) == 0)
14 return 0;
15
16 while (*++d == '/');
17
18 while ((d = strchr(d, '/'))) {
19 *d = '\0';
20 err = stat(path, &st) && mkdir(path, mode);
21 *d++ = '/';
22 if (err)
23 return -1;
24 while (*d == '/')
25 ++d;
26 }
27 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
28}
29
30static int slow_copyfile(const char *from, const char *to)
31{
32 int err = 0;
33 char *line = NULL;
34 size_t n;
35 FILE *from_fp = fopen(from, "r"), *to_fp;
36
37 if (from_fp == NULL)
38 goto out;
39
40 to_fp = fopen(to, "w");
41 if (to_fp == NULL)
42 goto out_fclose_from;
43
44 while (getline(&line, &n, from_fp) > 0)
45 if (fputs(line, to_fp) == EOF)
46 goto out_fclose_to;
47 err = 0;
48out_fclose_to:
49 fclose(to_fp);
50 free(line);
51out_fclose_from:
52 fclose(from_fp);
53out:
54 return err;
55}
56
57int copyfile(const char *from, const char *to)
58{
59 int fromfd, tofd;
60 struct stat st;
61 void *addr;
62 int err = -1;
63
64 if (stat(from, &st))
65 goto out;
66
67 if (st.st_size == 0) /* /proc? do it slowly... */
68 return slow_copyfile(from, to);
69
70 fromfd = open(from, O_RDONLY);
71 if (fromfd < 0)
72 goto out;
73
74 tofd = creat(to, 0755);
75 if (tofd < 0)
76 goto out_close_from;
77
78 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
79 if (addr == MAP_FAILED)
80 goto out_close_to;
81
82 if (write(tofd, addr, st.st_size) == st.st_size)
83 err = 0;
84
85 munmap(addr, st.st_size);
86out_close_to:
87 close(tofd);
88 if (err)
89 unlink(to);
90out_close_from:
91 close(fromfd);
92out:
93 return err;
94}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 9de2329dd44d..0f5b2a6f1080 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -84,6 +84,9 @@
84#include <iconv.h> 84#include <iconv.h>
85#endif 85#endif
86 86
87extern const char *graph_line;
88extern const char *graph_dotted_line;
89
87/* On most systems <limits.h> would have given us this, but 90/* On most systems <limits.h> would have given us this, but
88 * not on some systems (e.g. GNU/Hurd). 91 * not on some systems (e.g. GNU/Hurd).
89 */ 92 */
@@ -134,6 +137,15 @@ extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1,
134extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); 137extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
135extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); 138extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
136 139
140#include "../../../include/linux/stringify.h"
141
142#define DIE_IF(cnd) \
143 do { if (cnd) \
144 die(" at (" __FILE__ ":" __stringify(__LINE__) "): " \
145 __stringify(cnd) "\n"); \
146 } while (0)
147
148
137extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); 149extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
138 150
139extern int prefixcmp(const char *str, const char *prefix); 151extern int prefixcmp(const char *str, const char *prefix);
@@ -278,17 +290,15 @@ static inline char *gitstrchrnul(const char *s, int c)
278 * Wrappers: 290 * Wrappers:
279 */ 291 */
280extern char *xstrdup(const char *str); 292extern char *xstrdup(const char *str);
281extern void *xmalloc(size_t size); 293extern void *xmalloc(size_t size) __attribute__((weak));
282extern void *xmemdupz(const void *data, size_t len); 294extern void *xmemdupz(const void *data, size_t len);
283extern char *xstrndup(const char *str, size_t len); 295extern char *xstrndup(const char *str, size_t len);
284extern void *xrealloc(void *ptr, size_t size); 296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
285extern void *xcalloc(size_t nmemb, size_t size); 297
286extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 298static inline void *zalloc(size_t size)
287extern ssize_t xread(int fd, void *buf, size_t len); 299{
288extern ssize_t xwrite(int fd, const void *buf, size_t len); 300 return calloc(1, size);
289extern int xdup(int fd); 301}
290extern FILE *xfdopen(int fd, const char *mode);
291extern int xmkstemp(char *template);
292 302
293static inline size_t xsize_t(off_t len) 303static inline size_t xsize_t(off_t len)
294{ 304{
@@ -306,6 +316,7 @@ static inline int has_extension(const char *filename, const char *ext)
306#undef isascii 316#undef isascii
307#undef isspace 317#undef isspace
308#undef isdigit 318#undef isdigit
319#undef isxdigit
309#undef isalpha 320#undef isalpha
310#undef isprint 321#undef isprint
311#undef isalnum 322#undef isalnum
@@ -323,6 +334,8 @@ extern unsigned char sane_ctype[256];
323#define isascii(x) (((x) & ~0x7f) == 0) 334#define isascii(x) (((x) & ~0x7f) == 0)
324#define isspace(x) sane_istest(x,GIT_SPACE) 335#define isspace(x) sane_istest(x,GIT_SPACE)
325#define isdigit(x) sane_istest(x,GIT_DIGIT) 336#define isdigit(x) sane_istest(x,GIT_DIGIT)
337#define isxdigit(x) \
338 (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
326#define isalpha(x) sane_istest(x,GIT_ALPHA) 339#define isalpha(x) sane_istest(x,GIT_ALPHA)
327#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 340#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
328#define isprint(x) sane_istest(x,GIT_PRINT) 341#define isprint(x) sane_istest(x,GIT_PRINT)
@@ -390,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size,
390#endif 403#endif
391#endif 404#endif
392 405
406int mkdir_p(char *path, mode_t mode);
407int copyfile(const char *from, const char *to);
408
393#endif 409#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 1c15e39f99e3..cfa55d686e3b 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
172 free(counterwidth);
172} 173}
173 174
174static void perf_read_values__display_raw(FILE *fp, 175static void perf_read_values__display_raw(FILE *fp,
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index cadf8cf2a590..2fa967e1a88a 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define _PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
24void perf_read_values_display(FILE *fp, struct perf_read_values *values, 24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw); 25 int raw);
26 26
27#endif /* _PERF_VALUES_H */ 27#endif /* __PERF_VALUES_H */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 4574ac28396f..bf44ca85d23b 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -79,43 +79,12 @@ void *xrealloc(void *ptr, size_t size)
79 return ret; 79 return ret;
80} 80}
81 81
82void *xcalloc(size_t nmemb, size_t size)
83{
84 void *ret = calloc(nmemb, size);
85 if (!ret && (!nmemb || !size))
86 ret = calloc(1, 1);
87 if (!ret) {
88 release_pack_memory(nmemb * size, -1);
89 ret = calloc(nmemb, size);
90 if (!ret && (!nmemb || !size))
91 ret = calloc(1, 1);
92 if (!ret)
93 die("Out of memory, calloc failed");
94 }
95 return ret;
96}
97
98void *xmmap(void *start, size_t length,
99 int prot, int flags, int fd, off_t offset)
100{
101 void *ret = mmap(start, length, prot, flags, fd, offset);
102 if (ret == MAP_FAILED) {
103 if (!length)
104 return NULL;
105 release_pack_memory(length, fd);
106 ret = mmap(start, length, prot, flags, fd, offset);
107 if (ret == MAP_FAILED)
108 die("Out of memory? mmap failed: %s", strerror(errno));
109 }
110 return ret;
111}
112
113/* 82/*
114 * xread() is the same a read(), but it automatically restarts read() 83 * xread() is the same a read(), but it automatically restarts read()
115 * operations with a recoverable error (EAGAIN and EINTR). xread() 84 * operations with a recoverable error (EAGAIN and EINTR). xread()
116 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. 85 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
117 */ 86 */
118ssize_t xread(int fd, void *buf, size_t len) 87static ssize_t xread(int fd, void *buf, size_t len)
119{ 88{
120 ssize_t nr; 89 ssize_t nr;
121 while (1) { 90 while (1) {
@@ -131,7 +100,7 @@ ssize_t xread(int fd, void *buf, size_t len)
131 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT 100 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
132 * GUARANTEE that "len" bytes is written even if the operation is successful. 101 * GUARANTEE that "len" bytes is written even if the operation is successful.
133 */ 102 */
134ssize_t xwrite(int fd, const void *buf, size_t len) 103static ssize_t xwrite(int fd, const void *buf, size_t len)
135{ 104{
136 ssize_t nr; 105 ssize_t nr;
137 while (1) { 106 while (1) {
@@ -179,29 +148,3 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
179 148
180 return total; 149 return total;
181} 150}
182
183int xdup(int fd)
184{
185 int ret = dup(fd);
186 if (ret < 0)
187 die("dup failed: %s", strerror(errno));
188 return ret;
189}
190
191FILE *xfdopen(int fd, const char *mode)
192{
193 FILE *stream = fdopen(fd, mode);
194 if (stream == NULL)
195 die("Out of memory? fdopen failed: %s", strerror(errno));
196 return stream;
197}
198
199int xmkstemp(char *template)
200{
201 int fd;
202
203 fd = mkstemp(template);
204 if (fd < 0)
205 die("Unable to create temporary file: %s", strerror(errno));
206 return fd;
207}