aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2010-01-28 16:38:25 -0500
committerGrant Likely <grant.likely@secretlab.ca>2010-01-28 16:38:25 -0500
commit0ada0a73120c28cc432bcdbac061781465c2f48f (patch)
treed17cadd4ea47e25d9e48e7d409a39c84268fbd27 /tools/perf/util
parent6016a363f6b56b46b24655bcfc0499b715851cf3 (diff)
parent92dcffb916d309aa01778bf8963a6932e4014d07 (diff)
Merge commit 'v2.6.33-rc5' into secretlab/test-devicetree
Diffstat (limited to 'tools/perf/util')
-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/ctype.c8
-rw-r--r--tools/perf/util/data_map.c252
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/debug.h9
-rw-r--r--tools/perf/util/debugfs.c241
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/event.c456
-rw-r--r--tools/perf/util/event.h101
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c406
-rw-r--r--tools/perf/util/header.h76
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/hist.c662
-rw-r--r--tools/perf/util/hist.h27
-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/kernel.h76
-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.c126
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.c170
-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.c677
-rw-r--r--tools/perf/util/probe-event.h22
-rw-r--r--tools/perf/util/probe-finder.c730
-rw-r--r--tools/perf/util/probe-finder.h65
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/session.c150
-rw-r--r--tools/perf/util/session.h61
-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.c219
-rw-r--r--tools/perf/util/string.h12
-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.c1384
-rw-r--r--tools/perf/util/symbol.h111
-rw-r--r--tools/perf/util/thread.c260
-rw-r--r--tools/perf/util/thread.h64
-rw-r--r--tools/perf/util/trace-event-info.c26
-rw-r--r--tools/perf/util/trace-event-parse.c577
-rw-r--r--tools/perf/util/trace-event-perl.c661
-rw-r--r--tools/perf/util/trace-event-perl.h55
-rw-r--r--tools/perf/util/trace-event-read.c14
-rw-r--r--tools/perf/util/trace-event.h64
-rw-r--r--tools/perf/util/types.h6
-rw-r--r--tools/perf/util/util.h31
-rw-r--r--tools/perf/util/values.h6
-rw-r--r--tools/perf/util/wrapper.c61
70 files changed, 7691 insertions, 1475 deletions
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/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/data_map.c b/tools/perf/util/data_map.c
new file mode 100644
index 000000000000..b557b836de3d
--- /dev/null
+++ b/tools/perf/util/data_map.c
@@ -0,0 +1,252 @@
1#include "symbol.h"
2#include "util.h"
3#include "debug.h"
4#include "thread.h"
5#include "session.h"
6
7static int process_event_stub(event_t *event __used,
8 struct perf_session *session __used)
9{
10 dump_printf(": unhandled!\n");
11 return 0;
12}
13
14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15{
16 if (!handler->process_sample_event)
17 handler->process_sample_event = process_event_stub;
18 if (!handler->process_mmap_event)
19 handler->process_mmap_event = process_event_stub;
20 if (!handler->process_comm_event)
21 handler->process_comm_event = process_event_stub;
22 if (!handler->process_fork_event)
23 handler->process_fork_event = process_event_stub;
24 if (!handler->process_exit_event)
25 handler->process_exit_event = process_event_stub;
26 if (!handler->process_lost_event)
27 handler->process_lost_event = process_event_stub;
28 if (!handler->process_read_event)
29 handler->process_read_event = process_event_stub;
30 if (!handler->process_throttle_event)
31 handler->process_throttle_event = process_event_stub;
32 if (!handler->process_unthrottle_event)
33 handler->process_unthrottle_event = process_event_stub;
34}
35
36static const char *event__name[] = {
37 [0] = "TOTAL",
38 [PERF_RECORD_MMAP] = "MMAP",
39 [PERF_RECORD_LOST] = "LOST",
40 [PERF_RECORD_COMM] = "COMM",
41 [PERF_RECORD_EXIT] = "EXIT",
42 [PERF_RECORD_THROTTLE] = "THROTTLE",
43 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44 [PERF_RECORD_FORK] = "FORK",
45 [PERF_RECORD_READ] = "READ",
46 [PERF_RECORD_SAMPLE] = "SAMPLE",
47};
48
49unsigned long event__total[PERF_RECORD_MAX];
50
51void event__print_totals(void)
52{
53 int i;
54 for (i = 0; i < PERF_RECORD_MAX; ++i)
55 pr_info("%10s events: %10ld\n",
56 event__name[i], event__total[i]);
57}
58
59static int process_event(event_t *event, struct perf_session *session,
60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
62{
63 trace_event(event);
64
65 if (event->header.type < PERF_RECORD_MAX) {
66 dump_printf("%p [%p]: PERF_RECORD_%s",
67 (void *)(offset + head),
68 (void *)(long)(event->header.size),
69 event__name[event->header.type]);
70 ++event__total[0];
71 ++event__total[event->header.type];
72 }
73
74 switch (event->header.type) {
75 case PERF_RECORD_SAMPLE:
76 return ops->process_sample_event(event, session);
77 case PERF_RECORD_MMAP:
78 return ops->process_mmap_event(event, session);
79 case PERF_RECORD_COMM:
80 return ops->process_comm_event(event, session);
81 case PERF_RECORD_FORK:
82 return ops->process_fork_event(event, session);
83 case PERF_RECORD_EXIT:
84 return ops->process_exit_event(event, session);
85 case PERF_RECORD_LOST:
86 return ops->process_lost_event(event, session);
87 case PERF_RECORD_READ:
88 return ops->process_read_event(event, session);
89 case PERF_RECORD_THROTTLE:
90 return ops->process_throttle_event(event, session);
91 case PERF_RECORD_UNTHROTTLE:
92 return ops->process_unthrottle_event(event, session);
93 default:
94 ops->total_unknown++;
95 return -1;
96 }
97}
98
99int perf_header__read_build_ids(int input, u64 offset, u64 size)
100{
101 struct build_id_event bev;
102 char filename[PATH_MAX];
103 u64 limit = offset + size;
104 int err = -1;
105
106 while (offset < limit) {
107 struct dso *dso;
108 ssize_t len;
109
110 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111 goto out;
112
113 len = bev.header.size - sizeof(bev);
114 if (read(input, filename, len) != len)
115 goto out;
116
117 dso = dsos__findnew(filename);
118 if (dso != NULL)
119 dso__set_build_id(dso, &bev.build_id);
120
121 offset += bev.header.size;
122 }
123 err = 0;
124out:
125 return err;
126}
127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
142{
143 int err;
144 unsigned long head, shift;
145 unsigned long offset = 0;
146 size_t page_size;
147 event_t *event;
148 uint32_t size;
149 char *buf;
150
151 if (perf_session__register_idle_thread(self) == NULL)
152 return -ENOMEM;
153
154 perf_event_ops__fill_defaults(ops);
155
156 page_size = getpagesize();
157
158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
160
161 err = -EINVAL;
162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
163 goto out_err;
164
165 if (!ops->full_paths) {
166 char bf[PATH_MAX];
167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
178 }
179 self->cwdlen = strlen(self->cwd);
180 }
181
182 shift = page_size * (head / page_size);
183 offset += shift;
184 head -= shift;
185
186remap:
187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
188 MAP_SHARED, self->fd, offset);
189 if (buf == MAP_FAILED) {
190 pr_err("failed to mmap file\n");
191 err = -errno;
192 goto out_err;
193 }
194
195more:
196 event = (event_t *)(buf + head);
197
198 size = event->header.size;
199 if (!size)
200 size = 8;
201
202 if (head + event->header.size >= page_size * self->mmap_window) {
203 int munmap_ret;
204
205 shift = page_size * (head / page_size);
206
207 munmap_ret = munmap(buf, page_size * self->mmap_window);
208 assert(munmap_ret == 0);
209
210 offset += shift;
211 head -= shift;
212 goto remap;
213 }
214
215 size = event->header.size;
216
217 dump_printf("\n%p [%p]: event: %d\n",
218 (void *)(offset + head),
219 (void *)(long)event->header.size,
220 event->header.type);
221
222 if (!size || process_event(event, self, ops, offset, head) < 0) {
223
224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
225 (void *)(offset + head),
226 (void *)(long)(event->header.size),
227 event->header.type);
228
229 /*
230 * assume we lost track of the stream, check alignment, and
231 * increment a single u64 in the hope to catch on again 'soon'.
232 */
233
234 if (unlikely(head & 7))
235 head &= ~7ULL;
236
237 size = 8;
238 }
239
240 head += size;
241
242 if (offset + head >= self->header.data_offset + self->header.data_size)
243 goto done;
244
245 if (offset + head < self->size)
246 goto more;
247
248done:
249 err = 0;
250out_err:
251 return err;
252}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index e8ca98fe0bd4..28d520d5a1fb 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -13,12 +13,12 @@
13int verbose = 0; 13int verbose = 0;
14int dump_trace = 0; 14int dump_trace = 0;
15 15
16int eprintf(const char *fmt, ...) 16int eprintf(int level, const char *fmt, ...)
17{ 17{
18 va_list args; 18 va_list args;
19 int ret = 0; 19 int ret = 0;
20 20
21 if (verbose) { 21 if (verbose >= level) {
22 va_start(args, fmt); 22 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args); 23 ret = vfprintf(stderr, fmt, args);
24 va_end(args); 24 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..06b73ee02c49
--- /dev/null
+++ b/tools/perf/util/debugfs.c
@@ -0,0 +1,241 @@
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 */
110
111int debugfs_mount(const char *mountpoint)
112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1;
118 return 0;
119 }
120
121 /* if not mounted and no argument */
122 if (mountpoint == NULL) {
123 /* see if environment variable set */
124 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
125 /* if no environment variable, use default */
126 if (mountpoint == NULL)
127 mountpoint = "/sys/kernel/debug";
128 }
129
130 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
132
133 /* mount it */
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137}
138
139/* umount the debugfs */
140
141int debugfs_umount(void)
142{
143 char umountcmd[128];
144 int ret;
145
146 /* if it was already mounted, leave it */
147 if (debugfs_premounted)
148 return 0;
149
150 /* make sure it's a valid mount point */
151 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
152 if (ret)
153 return ret;
154
155 snprintf(umountcmd, sizeof(umountcmd),
156 "/bin/umount %s", debugfs_mountpoint);
157 return system(umountcmd);
158}
159
160int debugfs_write(const char *entry, const char *value)
161{
162 char path[MAX_PATH+1];
163 int ret, count;
164 int fd;
165
166 /* construct the path */
167 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
168
169 /* verify that it exists */
170 ret = debugfs_valid_entry(path);
171 if (ret)
172 return ret;
173
174 /* get how many chars we're going to write */
175 count = strlen(value);
176
177 /* open the debugfs entry */
178 fd = open(path, O_RDWR);
179 if (fd < 0)
180 return -errno;
181
182 while (count > 0) {
183 /* write it */
184 ret = write(fd, value, count);
185 if (ret <= 0) {
186 if (ret == EAGAIN)
187 continue;
188 close(fd);
189 return -errno;
190 }
191 count -= ret;
192 }
193
194 /* close it */
195 close(fd);
196
197 /* return success */
198 return 0;
199}
200
201/*
202 * read a debugfs entry
203 * returns the number of chars read or a negative errno
204 */
205int debugfs_read(const char *entry, char *buffer, size_t size)
206{
207 char path[MAX_PATH+1];
208 int ret;
209 int fd;
210
211 /* construct the path */
212 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
213
214 /* verify that it exists */
215 ret = debugfs_valid_entry(path);
216 if (ret)
217 return ret;
218
219 /* open the debugfs entry */
220 fd = open(path, O_RDONLY);
221 if (fd < 0)
222 return -errno;
223
224 do {
225 /* read it */
226 ret = read(fd, buffer, size);
227 if (ret == 0) {
228 close(fd);
229 return EOF;
230 }
231 } while (ret < 0 && errno == EAGAIN);
232
233 /* close it */
234 close(fd);
235
236 /* make *sure* there's a null character at the end */
237 buffer[ret] = '\0';
238
239 /* return the number of chars read */
240 return ret;
241}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
new file mode 100644
index 000000000000..3cd14f9ae784
--- /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 int 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..bb0fd6da2d56
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,456 @@
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 int (*process)(event_t *event,
12 struct perf_session *session),
13 struct perf_session *session)
14{
15 event_t ev;
16 char filename[PATH_MAX];
17 char bf[BUFSIZ];
18 FILE *fp;
19 size_t size = 0;
20 DIR *tasks;
21 struct dirent dirent, *next;
22 pid_t tgid = 0;
23
24 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
25
26 fp = fopen(filename, "r");
27 if (fp == NULL) {
28out_race:
29 /*
30 * We raced with a task exiting - just return:
31 */
32 pr_debug("couldn't open %s\n", filename);
33 return 0;
34 }
35
36 memset(&ev.comm, 0, sizeof(ev.comm));
37 while (!ev.comm.comm[0] || !ev.comm.pid) {
38 if (fgets(bf, sizeof(bf), fp) == NULL)
39 goto out_failure;
40
41 if (memcmp(bf, "Name:", 5) == 0) {
42 char *name = bf + 5;
43 while (*name && isspace(*name))
44 ++name;
45 size = strlen(name) - 1;
46 memcpy(ev.comm.comm, name, size++);
47 } else if (memcmp(bf, "Tgid:", 5) == 0) {
48 char *tgids = bf + 5;
49 while (*tgids && isspace(*tgids))
50 ++tgids;
51 tgid = ev.comm.pid = atoi(tgids);
52 }
53 }
54
55 ev.comm.header.type = PERF_RECORD_COMM;
56 size = ALIGN(size, sizeof(u64));
57 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
58
59 if (!full) {
60 ev.comm.tid = pid;
61
62 process(&ev, session);
63 goto out_fclose;
64 }
65
66 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
67
68 tasks = opendir(filename);
69 if (tasks == NULL)
70 goto out_race;
71
72 while (!readdir_r(tasks, &dirent, &next) && next) {
73 char *end;
74 pid = strtol(dirent.d_name, &end, 10);
75 if (*end)
76 continue;
77
78 ev.comm.tid = pid;
79
80 process(&ev, session);
81 }
82 closedir(tasks);
83
84out_fclose:
85 fclose(fp);
86 return tgid;
87
88out_failure:
89 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
90 return -1;
91}
92
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
94 int (*process)(event_t *event,
95 struct perf_session *session),
96 struct perf_session *session)
97{
98 char filename[PATH_MAX];
99 FILE *fp;
100
101 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
102
103 fp = fopen(filename, "r");
104 if (fp == NULL) {
105 /*
106 * We raced with a task exiting - just return:
107 */
108 pr_debug("couldn't open %s\n", filename);
109 return -1;
110 }
111
112 while (1) {
113 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP },
116 };
117 int n;
118 size_t size;
119 if (fgets(bf, sizeof(bf), fp) == NULL)
120 break;
121
122 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
123 n = hex2u64(pbf, &ev.mmap.start);
124 if (n < 0)
125 continue;
126 pbf += n + 1;
127 n = hex2u64(pbf, &ev.mmap.len);
128 if (n < 0)
129 continue;
130 pbf += n + 3;
131 if (*pbf == 'x') { /* vm_exec */
132 char *execname = strchr(bf, '/');
133
134 /* Catch VDSO */
135 if (execname == NULL)
136 execname = strstr(bf, "[vdso]");
137
138 if (execname == NULL)
139 continue;
140
141 size = strlen(execname);
142 execname[size - 1] = '\0'; /* Remove \n */
143 memcpy(ev.mmap.filename, execname, size);
144 size = ALIGN(size, sizeof(u64));
145 ev.mmap.len -= ev.mmap.start;
146 ev.mmap.header.size = (sizeof(ev.mmap) -
147 (sizeof(ev.mmap.filename) - size));
148 ev.mmap.pid = tgid;
149 ev.mmap.tid = pid;
150
151 process(&ev, session);
152 }
153 }
154
155 fclose(fp);
156 return 0;
157}
158
159int event__synthesize_thread(pid_t pid,
160 int (*process)(event_t *event,
161 struct perf_session *session),
162 struct perf_session *session)
163{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
165 if (tgid == -1)
166 return -1;
167 return event__synthesize_mmap_events(pid, tgid, process, session);
168}
169
170void event__synthesize_threads(int (*process)(event_t *event,
171 struct perf_session *session),
172 struct perf_session *session)
173{
174 DIR *proc;
175 struct dirent dirent, *next;
176
177 proc = opendir("/proc");
178
179 while (!readdir_r(proc, &dirent, &next) && next) {
180 char *end;
181 pid_t pid = strtol(dirent.d_name, &end, 10);
182
183 if (*end) /* only interested in proper numerical dirents */
184 continue;
185
186 event__synthesize_thread(pid, process, session);
187 }
188
189 closedir(proc);
190}
191
192static void thread__comm_adjust(struct thread *self)
193{
194 char *comm = self->comm;
195
196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm);
200
201 if (slen > comms__col_width) {
202 comms__col_width = slen;
203 threads__col_width = slen + 6;
204 }
205 }
206}
207
208static int thread__set_comm_adjust(struct thread *self, const char *comm)
209{
210 int ret = thread__set_comm(self, comm);
211
212 if (ret)
213 return ret;
214
215 thread__comm_adjust(self);
216
217 return 0;
218}
219
220int event__process_comm(event_t *self, struct perf_session *session)
221{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid);
223
224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
225
226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
228 return -1;
229 }
230
231 return 0;
232}
233
234int event__process_lost(event_t *self, struct perf_session *session)
235{
236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
237 session->events_stats.lost += self->lost.lost;
238 return 0;
239}
240
241int event__process_mmap(event_t *self, struct perf_session *session)
242{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid);
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
245 session->cwd, session->cwdlen);
246
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
248 self->mmap.pid, self->mmap.tid,
249 (void *)(long)self->mmap.start,
250 (void *)(long)self->mmap.len,
251 (void *)(long)self->mmap.pgoff,
252 self->mmap.filename);
253
254 if (thread == NULL || map == NULL)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
256 else
257 thread__insert_map(thread, map);
258
259 return 0;
260}
261
262int event__process_task(event_t *self, struct perf_session *session)
263{
264 struct thread *thread = perf_session__findnew(session, self->fork.pid);
265 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
266
267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
268 self->fork.ppid, self->fork.ptid);
269 /*
270 * A thread clone will have the same PID for both parent and child.
271 */
272 if (thread == parent)
273 return 0;
274
275 if (self->header.type == PERF_RECORD_EXIT)
276 return 0;
277
278 if (thread == NULL || parent == NULL ||
279 thread__fork(thread, parent) < 0) {
280 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
281 return -1;
282 }
283
284 return 0;
285}
286
287void thread__find_addr_location(struct thread *self,
288 struct perf_session *session, u8 cpumode,
289 enum map_type type, u64 addr,
290 struct addr_location *al,
291 symbol_filter_t filter)
292{
293 struct map_groups *mg = &self->mg;
294
295 al->thread = self;
296 al->addr = addr;
297
298 if (cpumode & PERF_RECORD_MISC_KERNEL) {
299 al->level = 'k';
300 mg = &session->kmaps;
301 } else if (cpumode & PERF_RECORD_MISC_USER)
302 al->level = '.';
303 else {
304 al->level = 'H';
305 al->map = NULL;
306 al->sym = NULL;
307 return;
308 }
309try_again:
310 al->map = map_groups__find(mg, type, al->addr);
311 if (al->map == NULL) {
312 /*
313 * If this is outside of all known maps, and is a negative
314 * address, try to look it up in the kernel dso, as it might be
315 * a vsyscall or vdso (which executes in user-mode).
316 *
317 * XXX This is nasty, we should have a symbol list in the
318 * "[vdso]" dso, but for now lets use the old trick of looking
319 * in the whole kernel symbol list.
320 */
321 if ((long long)al->addr < 0 && mg != &session->kmaps) {
322 mg = &session->kmaps;
323 goto try_again;
324 }
325 al->sym = NULL;
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr);
328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
329 }
330}
331
332static void dso__calc_col_width(struct dso *self)
333{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name);
338 if (slen > dsos__col_width)
339 dsos__col_width = slen;
340 }
341
342 self->slen_calculated = 1;
343}
344
345int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter)
347{
348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
349 struct thread *thread = perf_session__findnew(session, self->ip.pid);
350
351 if (thread == NULL)
352 return -1;
353
354 if (symbol_conf.comm_list &&
355 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
356 goto out_filtered;
357
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
359
360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
361 self->ip.ip, al, filter);
362 dump_printf(" ...... dso: %s\n",
363 al->map ? al->map->dso->long_name :
364 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /*
366 * We have to do this here as we may have a dso with no symbol hit that
367 * has a name longer than the ones with symbols sampled.
368 */
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
370 dso__calc_col_width(al->map->dso);
371
372 if (symbol_conf.dso_list &&
373 (!al->map || !al->map->dso ||
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
375 (al->map->dso->short_name != al->map->dso->long_name &&
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
377 goto out_filtered;
378
379 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered;
382
383 al->filtered = false;
384 return 0;
385
386out_filtered:
387 al->filtered = true;
388 return 0;
389}
390
391int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
392{
393 u64 *array = event->sample.array;
394
395 if (type & PERF_SAMPLE_IP) {
396 data->ip = event->ip.ip;
397 array++;
398 }
399
400 if (type & PERF_SAMPLE_TID) {
401 u32 *p = (u32 *)array;
402 data->pid = p[0];
403 data->tid = p[1];
404 array++;
405 }
406
407 if (type & PERF_SAMPLE_TIME) {
408 data->time = *array;
409 array++;
410 }
411
412 if (type & PERF_SAMPLE_ADDR) {
413 data->addr = *array;
414 array++;
415 }
416
417 if (type & PERF_SAMPLE_ID) {
418 data->id = *array;
419 array++;
420 }
421
422 if (type & PERF_SAMPLE_STREAM_ID) {
423 data->stream_id = *array;
424 array++;
425 }
426
427 if (type & PERF_SAMPLE_CPU) {
428 u32 *p = (u32 *)array;
429 data->cpu = *p;
430 array++;
431 }
432
433 if (type & PERF_SAMPLE_PERIOD) {
434 data->period = *array;
435 array++;
436 }
437
438 if (type & PERF_SAMPLE_READ) {
439 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
440 return -1;
441 }
442
443 if (type & PERF_SAMPLE_CALLCHAIN) {
444 data->callchain = (struct ip_callchain *)array;
445 array += 1 + data->callchain->nr;
446 }
447
448 if (type & PERF_SAMPLE_RAW) {
449 u32 *p = (u32 *)array;
450 data->raw_size = *p;
451 p++;
452 data->raw_data = p;
453 }
454
455 return 0;
456}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..690a96d0467c 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
3#include "../perf.h" 4#include "../perf.h"
4#include "util.h" 5#include "util.h"
5#include <linux/list.h> 6#include <linux/list.h>
6 7#include <linux/rbtree.h>
7enum {
8 SHOW_KERNEL = 1,
9 SHOW_USER = 2,
10 SHOW_HV = 4,
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,12 +94,31 @@ typedef union event_union {
77 struct sample_event sample; 94 struct sample_event sample;
78} event_t; 95} event_t;
79 96
97struct events_stats {
98 u64 total;
99 u64 lost;
100};
101
102void event__print_totals(void);
103
104enum map_type {
105 MAP__FUNCTION = 0,
106 MAP__VARIABLE,
107};
108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
80struct map { 111struct map {
81 struct list_head node; 112 union {
113 struct rb_node rb_node;
114 struct list_head node;
115 };
82 u64 start; 116 u64 start;
83 u64 end; 117 u64 end;
118 enum map_type type;
84 u64 pgoff; 119 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64); 120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
86 struct dso *dso; 122 struct dso *dso;
87}; 123};
88 124
@@ -91,14 +127,57 @@ static inline u64 map__map_ip(struct map *map, u64 ip)
91 return ip - map->start + map->pgoff; 127 return ip - map->start + map->pgoff;
92} 128}
93 129
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip) 130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
95{ 136{
96 return ip; 137 return ip;
97} 138}
98 139
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); 140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
100struct map *map__clone(struct map *self); 149struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r); 150int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
103 152
104#endif 153struct perf_session;
154
155int map__load(struct map *self, struct perf_session *session,
156 symbol_filter_t filter);
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
158 u64 addr, symbol_filter_t filter);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
162void map__fixup_start(struct map *self);
163void map__fixup_end(struct map *self);
164
165int event__synthesize_thread(pid_t pid,
166 int (*process)(event_t *event,
167 struct perf_session *session),
168 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event,
170 struct perf_session *session),
171 struct perf_session *session);
172
173int event__process_comm(event_t *self, struct perf_session *session);
174int event__process_lost(event_t *self, struct perf_session *session);
175int event__process_mmap(event_t *self, struct perf_session *session);
176int event__process_task(event_t *self, struct perf_session *session);
177
178struct addr_location;
179int event__preprocess_sample(const event_t *self, struct perf_session *session,
180 struct addr_location *al, symbol_filter_t filter);
181int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
182
183#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..8a0bca55106f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2,9 +2,15 @@
2#include <unistd.h> 2#include <unistd.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <stdlib.h> 4#include <stdlib.h>
5#include <linux/list.h>
5 6
6#include "util.h" 7#include "util.h"
7#include "header.h" 8#include "header.h"
9#include "../perf.h"
10#include "trace-event.h"
11#include "session.h"
12#include "symbol.h"
13#include "debug.h"
8 14
9/* 15/*
10 * Create new perf.data header attribute: 16 * Create new perf.data header attribute:
@@ -13,75 +19,80 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
13{ 19{
14 struct perf_header_attr *self = malloc(sizeof(*self)); 20 struct perf_header_attr *self = malloc(sizeof(*self));
15 21
16 if (!self) 22 if (self != NULL) {
17 die("nomem"); 23 self->attr = *attr;
18 24 self->ids = 0;
19 self->attr = *attr; 25 self->size = 1;
20 self->ids = 0; 26 self->id = malloc(sizeof(u64));
21 self->size = 1; 27 if (self->id == NULL) {
22 self->id = malloc(sizeof(u64)); 28 free(self);
23 29 self = NULL;
24 if (!self->id) 30 }
25 die("nomem"); 31 }
26 32
27 return self; 33 return self;
28} 34}
29 35
30void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 36void perf_header_attr__delete(struct perf_header_attr *self)
37{
38 free(self->id);
39 free(self);
40}
41
42int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
31{ 43{
32 int pos = self->ids; 44 int pos = self->ids;
33 45
34 self->ids++; 46 self->ids++;
35 if (self->ids > self->size) { 47 if (self->ids > self->size) {
36 self->size *= 2; 48 int nsize = self->size * 2;
37 self->id = realloc(self->id, self->size * sizeof(u64)); 49 u64 *nid = realloc(self->id, nsize * sizeof(u64));
38 if (!self->id) 50
39 die("nomem"); 51 if (nid == NULL)
52 return -1;
53
54 self->size = nsize;
55 self->id = nid;
40 } 56 }
41 self->id[pos] = id; 57 self->id[pos] = id;
58 return 0;
42} 59}
43 60
44/* 61int perf_header__init(struct perf_header *self)
45 * Create new perf.data header:
46 */
47struct perf_header *perf_header__new(void)
48{ 62{
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; 63 self->size = 1;
58 self->attr = malloc(sizeof(void *)); 64 self->attr = malloc(sizeof(void *));
59 65 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} 66}
68 67
69void perf_header__add_attr(struct perf_header *self, 68void perf_header__exit(struct perf_header *self)
70 struct perf_header_attr *attr)
71{ 69{
72 int pos = self->attrs; 70 int i;
71 for (i = 0; i < self->attrs; ++i)
72 perf_header_attr__delete(self->attr[i]);
73 free(self->attr);
74}
73 75
76int perf_header__add_attr(struct perf_header *self,
77 struct perf_header_attr *attr)
78{
74 if (self->frozen) 79 if (self->frozen)
75 die("frozen"); 80 return -1;
76 81
77 self->attrs++; 82 if (self->attrs == self->size) {
78 if (self->attrs > self->size) { 83 int nsize = self->size * 2;
79 self->size *= 2; 84 struct perf_header_attr **nattr;
80 self->attr = realloc(self->attr, self->size * sizeof(void *)); 85
81 if (!self->attr) 86 nattr = realloc(self->attr, nsize * sizeof(void *));
82 die("nomem"); 87 if (nattr == NULL)
88 return -1;
89
90 self->size = nsize;
91 self->attr = nattr;
83 } 92 }
84 self->attr[pos] = attr; 93
94 self->attr[self->attrs++] = attr;
95 return 0;
85} 96}
86 97
87#define MAX_EVENT_NAME 64 98#define MAX_EVENT_NAME 64
@@ -97,7 +108,7 @@ static struct perf_trace_event_type *events;
97void perf_header__push_event(u64 id, const char *name) 108void perf_header__push_event(u64 id, const char *name)
98{ 109{
99 if (strlen(name) > MAX_EVENT_NAME) 110 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name); 111 pr_warning("Event %s will be truncated\n", name);
101 112
102 if (!events) { 113 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type)); 114 events = malloc(sizeof(struct perf_trace_event_type));
@@ -128,44 +139,142 @@ static const char *__perf_magic = "PERFFILE";
128 139
129#define PERF_MAGIC (*(u64 *)__perf_magic) 140#define PERF_MAGIC (*(u64 *)__perf_magic)
130 141
131struct perf_file_section {
132 u64 offset;
133 u64 size;
134};
135
136struct perf_file_attr { 142struct perf_file_attr {
137 struct perf_event_attr attr; 143 struct perf_event_attr attr;
138 struct perf_file_section ids; 144 struct perf_file_section ids;
139}; 145};
140 146
141struct perf_file_header { 147void perf_header__set_feat(struct perf_header *self, int feat)
142 u64 magic; 148{
143 u64 size; 149 set_bit(feat, self->adds_features);
144 u64 attr_size; 150}
145 struct perf_file_section attrs; 151
146 struct perf_file_section data; 152bool perf_header__has_feat(const struct perf_header *self, int feat)
147 struct perf_file_section event_types; 153{
148}; 154 return test_bit(feat, self->adds_features);
155}
149 156
150static void do_write(int fd, void *buf, size_t size) 157static int do_write(int fd, const void *buf, size_t size)
151{ 158{
152 while (size) { 159 while (size) {
153 int ret = write(fd, buf, size); 160 int ret = write(fd, buf, size);
154 161
155 if (ret < 0) 162 if (ret < 0)
156 die("failed to write"); 163 return -errno;
157 164
158 size -= ret; 165 size -= ret;
159 buf += ret; 166 buf += ret;
160 } 167 }
168
169 return 0;
170}
171
172static int __dsos__write_buildid_table(struct list_head *head, int fd)
173{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN];
177
178 list_for_each_entry(pos, head, node) {
179 int err;
180 struct build_id_event b;
181 size_t len;
182
183 if (!pos->has_build_id)
184 continue;
185 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
189 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b));
191 if (err < 0)
192 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1);
194 if (err < 0)
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0)
198 return err;
199 }
200
201 return 0;
202}
203
204static int dsos__write_buildid_table(int fd)
205{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd);
207 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd);
209 return err;
210}
211
212static int perf_header__adds_write(struct perf_header *self, int fd)
213{
214 int nr_sections;
215 struct perf_file_section *feat_sec;
216 int sec_size;
217 u64 sec_start;
218 int idx = 0, err;
219
220 if (dsos__read_build_ids())
221 perf_header__set_feat(self, HEADER_BUILD_ID);
222
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
224 if (!nr_sections)
225 return 0;
226
227 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
228 if (feat_sec == NULL)
229 return -ENOMEM;
230
231 sec_size = sizeof(*feat_sec) * nr_sections;
232
233 sec_start = self->data_offset + self->data_size;
234 lseek(fd, sec_start + sec_size, SEEK_SET);
235
236 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
237 struct perf_file_section *trace_sec;
238
239 trace_sec = &feat_sec[idx++];
240
241 /* Write trace info */
242 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
243 read_tracing_data(fd, attrs, nr_counters);
244 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
245 }
246
247
248 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
249 struct perf_file_section *buildid_sec;
250
251 buildid_sec = &feat_sec[idx++];
252
253 /* Write build-ids */
254 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
255 err = dsos__write_buildid_table(fd);
256 if (err < 0) {
257 pr_debug("failed to write buildid table\n");
258 goto out_free;
259 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
261 }
262
263 lseek(fd, sec_start, SEEK_SET);
264 err = do_write(fd, feat_sec, sec_size);
265 if (err < 0)
266 pr_debug("failed to write feature section\n");
267out_free:
268 free(feat_sec);
269 return err;
161} 270}
162 271
163void perf_header__write(struct perf_header *self, int fd) 272int perf_header__write(struct perf_header *self, int fd, bool at_exit)
164{ 273{
165 struct perf_file_header f_header; 274 struct perf_file_header f_header;
166 struct perf_file_attr f_attr; 275 struct perf_file_attr f_attr;
167 struct perf_header_attr *attr; 276 struct perf_header_attr *attr;
168 int i; 277 int i, err;
169 278
170 lseek(fd, sizeof(f_header), SEEK_SET); 279 lseek(fd, sizeof(f_header), SEEK_SET);
171 280
@@ -174,7 +283,11 @@ void perf_header__write(struct perf_header *self, int fd)
174 attr = self->attr[i]; 283 attr = self->attr[i];
175 284
176 attr->id_offset = lseek(fd, 0, SEEK_CUR); 285 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177 do_write(fd, attr->id, attr->ids * sizeof(u64)); 286 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
287 if (err < 0) {
288 pr_debug("failed to write perf header\n");
289 return err;
290 }
178 } 291 }
179 292
180 293
@@ -190,17 +303,31 @@ void perf_header__write(struct perf_header *self, int fd)
190 .size = attr->ids * sizeof(u64), 303 .size = attr->ids * sizeof(u64),
191 } 304 }
192 }; 305 };
193 do_write(fd, &f_attr, sizeof(f_attr)); 306 err = do_write(fd, &f_attr, sizeof(f_attr));
307 if (err < 0) {
308 pr_debug("failed to write perf header attribute\n");
309 return err;
310 }
194 } 311 }
195 312
196 self->event_offset = lseek(fd, 0, SEEK_CUR); 313 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type); 314 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events) 315 if (events) {
199 do_write(fd, events, self->event_size); 316 err = do_write(fd, events, self->event_size);
200 317 if (err < 0) {
318 pr_debug("failed to write perf header events\n");
319 return err;
320 }
321 }
201 322
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 323 self->data_offset = lseek(fd, 0, SEEK_CUR);
203 324
325 if (at_exit) {
326 err = perf_header__adds_write(self, fd);
327 if (err < 0)
328 return err;
329 }
330
204 f_header = (struct perf_file_header){ 331 f_header = (struct perf_file_header){
205 .magic = PERF_MAGIC, 332 .magic = PERF_MAGIC,
206 .size = sizeof(f_header), 333 .size = sizeof(f_header),
@@ -219,11 +346,18 @@ void perf_header__write(struct perf_header *self, int fd)
219 }, 346 },
220 }; 347 };
221 348
349 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
350
222 lseek(fd, 0, SEEK_SET); 351 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header)); 352 err = do_write(fd, &f_header, sizeof(f_header));
353 if (err < 0) {
354 pr_debug("failed to write perf header\n");
355 return err;
356 }
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 357 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225 358
226 self->frozen = 1; 359 self->frozen = 1;
360 return 0;
227} 361}
228 362
229static void do_read(int fd, void *buf, size_t size) 363static void do_read(int fd, void *buf, size_t size)
@@ -241,22 +375,109 @@ static void do_read(int fd, void *buf, size_t size)
241 } 375 }
242} 376}
243 377
244struct perf_header *perf_header__read(int fd) 378int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self,
380 int feat, int fd))
381{
382 struct perf_file_section *feat_sec;
383 int nr_sections;
384 int sec_size;
385 int idx = 0;
386 int err = 0, feat = 1;
387
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections)
390 return 0;
391
392 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
393 if (!feat_sec)
394 return -1;
395
396 sec_size = sizeof(*feat_sec) * nr_sections;
397
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399
400 do_read(fd, feat_sec, sec_size);
401
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++];
405
406 err = process(sec, feat, fd);
407 if (err < 0)
408 break;
409 }
410 ++feat;
411 }
412
413 free(feat_sec);
414 return err;
415};
416
417int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd)
419{
420 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422
423 if (self->magic != PERF_MAGIC ||
424 self->attr_size != sizeof(struct perf_file_attr))
425 return -1;
426
427 if (self->size != sizeof(*self)) {
428 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features))
430 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
431 else
432 return -1;
433 }
434
435 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features));
437
438 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size;
442 return 0;
443}
444
445static int perf_file_section__process(struct perf_file_section *self,
446 int feat, int fd)
447{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat);
451 return 0;
452 }
453
454 switch (feat) {
455 case HEADER_TRACE_INFO:
456 trace_report(fd);
457 break;
458
459 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n");
462 break;
463 default:
464 pr_debug("unknown feature %d, continuing...\n", feat);
465 }
466
467 return 0;
468}
469
470int perf_header__read(struct perf_header *self, int fd)
245{ 471{
246 struct perf_header *self = perf_header__new();
247 struct perf_file_header f_header; 472 struct perf_file_header f_header;
248 struct perf_file_attr f_attr; 473 struct perf_file_attr f_attr;
249 u64 f_id; 474 u64 f_id;
250
251 int nr_attrs, nr_ids, i, j; 475 int nr_attrs, nr_ids, i, j;
252 476
253 lseek(fd, 0, SEEK_SET); 477 if (perf_file_header__read(&f_header, self, fd) < 0) {
254 do_read(fd, &f_header, sizeof(f_header)); 478 pr_debug("incompatible file format\n");
255 479 return -EINVAL;
256 if (f_header.magic != PERF_MAGIC || 480 }
257 f_header.size != sizeof(f_header) ||
258 f_header.attr_size != sizeof(f_attr))
259 die("incompatible file format");
260 481
261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 482 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET); 483 lseek(fd, f_header.attrs.offset, SEEK_SET);
@@ -269,6 +490,8 @@ struct perf_header *perf_header__read(int fd)
269 tmp = lseek(fd, 0, SEEK_CUR); 490 tmp = lseek(fd, 0, SEEK_CUR);
270 491
271 attr = perf_header_attr__new(&f_attr.attr); 492 attr = perf_header_attr__new(&f_attr.attr);
493 if (attr == NULL)
494 return -ENOMEM;
272 495
273 nr_ids = f_attr.ids.size / sizeof(u64); 496 nr_ids = f_attr.ids.size / sizeof(u64);
274 lseek(fd, f_attr.ids.offset, SEEK_SET); 497 lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -276,31 +499,34 @@ struct perf_header *perf_header__read(int fd)
276 for (j = 0; j < nr_ids; j++) { 499 for (j = 0; j < nr_ids; j++) {
277 do_read(fd, &f_id, sizeof(f_id)); 500 do_read(fd, &f_id, sizeof(f_id));
278 501
279 perf_header_attr__add_id(attr, f_id); 502 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr);
504 return -ENOMEM;
505 }
506 }
507 if (perf_header__add_attr(self, attr) < 0) {
508 perf_header_attr__delete(attr);
509 return -ENOMEM;
280 } 510 }
281 perf_header__add_attr(self, attr); 511
282 lseek(fd, tmp, SEEK_SET); 512 lseek(fd, tmp, SEEK_SET);
283 } 513 }
284 514
285 if (f_header.event_types.size) { 515 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET); 516 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size); 517 events = malloc(f_header.event_types.size);
288 if (!events) 518 if (events == NULL)
289 die("nomem"); 519 return -ENOMEM;
290 do_read(fd, events, f_header.event_types.size); 520 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 } 522 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295 523
296 self->data_offset = f_header.data.offset; 524 perf_header__process_sections(self, fd, perf_file_section__process);
297 self->data_size = f_header.data.size;
298 525
299 lseek(fd, self->data_offset, SEEK_SET); 526 lseek(fd, self->data_offset, SEEK_SET);
300 527
301 self->frozen = 1; 528 self->frozen = 1;
302 529 return 0;
303 return self;
304} 530}
305 531
306u64 perf_header__sample_type(struct perf_header *header) 532u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..d118d05d3abe 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,10 +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"
7 8
9#include <linux/bitmap.h>
10
8struct perf_header_attr { 11struct perf_header_attr {
9 struct perf_event_attr attr; 12 struct perf_event_attr attr;
10 int ids, size; 13 int ids, size;
@@ -12,36 +15,71 @@ struct perf_header_attr {
12 off_t id_offset; 15 off_t id_offset;
13}; 16};
14 17
18enum {
19 HEADER_TRACE_INFO = 1,
20 HEADER_BUILD_ID,
21 HEADER_LAST_FEATURE,
22};
23
24#define HEADER_FEAT_BITS 256
25
26struct perf_file_section {
27 u64 offset;
28 u64 size;
29};
30
31struct perf_file_header {
32 u64 magic;
33 u64 size;
34 u64 attr_size;
35 struct perf_file_section attrs;
36 struct perf_file_section data;
37 struct perf_file_section event_types;
38 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
39};
40
41struct perf_header;
42
43int perf_file_header__read(struct perf_file_header *self,
44 struct perf_header *ph, int fd);
45
15struct perf_header { 46struct perf_header {
16 int frozen; 47 int frozen;
17 int attrs, size; 48 int attrs, size;
18 struct perf_header_attr **attr; 49 struct perf_header_attr **attr;
19 s64 attr_offset; 50 s64 attr_offset;
20 u64 data_offset; 51 u64 data_offset;
21 u64 data_size; 52 u64 data_size;
22 u64 event_offset; 53 u64 event_offset;
23 u64 event_size; 54 u64 event_size;
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
24}; 56};
25 57
26struct perf_header *perf_header__read(int fd); 58int perf_header__init(struct perf_header *self);
27void perf_header__write(struct perf_header *self, int fd); 59void perf_header__exit(struct perf_header *self);
60
61int perf_header__read(struct perf_header *self, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
28 63
29void perf_header__add_attr(struct perf_header *self, 64int perf_header__add_attr(struct perf_header *self,
30 struct perf_header_attr *attr); 65 struct perf_header_attr *attr);
31 66
32void perf_header__push_event(u64 id, const char *name); 67void perf_header__push_event(u64 id, const char *name);
33char *perf_header__find_event(u64 id); 68char *perf_header__find_event(u64 id);
34 69
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
71void perf_header_attr__delete(struct perf_header_attr *self);
35 72
36struct perf_header_attr * 73int 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 74
40u64 perf_header__sample_type(struct perf_header *header); 75u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr * 76struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header); 77perf_header__find_attr(u64 id, struct perf_header *header);
78void perf_header__set_feat(struct perf_header *self, int feat);
79bool perf_header__has_feat(const struct perf_header *self, int feat);
43 80
81int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self,
83 int feat, int fd));
44 84
45struct perf_header *perf_header__new(void); 85#endif /* __PERF_HEADER_H */
46
47#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..e8daf5ca6fd2
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,662 @@
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 perf_session *self,
16 struct addr_location *al,
17 struct symbol *sym_parent,
18 u64 count, bool *hit)
19{
20 struct rb_node **p = &self->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, &self->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 perf_session *self)
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(&self->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, &self->hists);
150 collapse__insert_entry(&tmp, n);
151 }
152
153 self->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 perf_session *self, 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(&self->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, &self->hists);
204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
206 }
207
208 self->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 seperator
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 *session,
460 struct perf_session *pair_session,
461 bool show_displacement,
462 long displacement, FILE *fp)
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->events_stats.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->events_stats.total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.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->events_stats.total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct perf_session *self,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp)
557{
558 struct sort_entry *se;
559 struct rb_node *nd;
560 size_t ret = 0;
561 unsigned long position = 1;
562 long displacement = 0;
563 unsigned int width;
564 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str;
566
567 init_rem_hits();
568
569 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
570
571 if (symbol_conf.show_nr_samples) {
572 if (sep)
573 fprintf(fp, "%cSamples", *sep);
574 else
575 fputs(" Samples ", fp);
576 }
577
578 if (pair) {
579 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep);
581 else
582 ret += fprintf(fp, " Delta ");
583
584 if (show_displacement) {
585 if (sep)
586 ret += fprintf(fp, "%cDisplacement", *sep);
587 else
588 ret += fprintf(fp, " Displ");
589 }
590 }
591
592 list_for_each_entry(se, &hist_entry__sort_list, list) {
593 if (se->elide)
594 continue;
595 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header);
597 continue;
598 }
599 width = strlen(se->header);
600 if (se->width) {
601 if (symbol_conf.col_width_list_str) {
602 if (col_width) {
603 *se->width = atoi(col_width);
604 col_width = strchr(col_width, ',');
605 if (col_width)
606 ++col_width;
607 }
608 }
609 width = *se->width = max(*se->width, width);
610 }
611 fprintf(fp, " %*s", width, se->header);
612 }
613 fprintf(fp, "\n");
614
615 if (sep)
616 goto print_entries;
617
618 fprintf(fp, "# ........");
619 if (symbol_conf.show_nr_samples)
620 fprintf(fp, " ..........");
621 if (pair) {
622 fprintf(fp, " ..........");
623 if (show_displacement)
624 fprintf(fp, " .....");
625 }
626 list_for_each_entry(se, &hist_entry__sort_list, list) {
627 unsigned int i;
628
629 if (se->elide)
630 continue;
631
632 fprintf(fp, " ");
633 if (se->width)
634 width = *se->width;
635 else
636 width = strlen(se->header);
637 for (i = 0; i < width; i++)
638 fprintf(fp, ".");
639 }
640
641 fprintf(fp, "\n#\n");
642
643print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646
647 if (show_displacement) {
648 if (h->pair != NULL)
649 displacement = ((long)h->pair->position -
650 (long)position);
651 else
652 displacement = 0;
653 ++position;
654 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp);
657 }
658
659 free(rem_sq_bracket);
660
661 return ret;
662}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..e5f99b24048b
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,27 @@
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;
13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
15 struct addr_location *al,
16 struct symbol *parent,
17 u64 count, bool *hit);
18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
20void hist_entry__free(struct hist_entry *);
21
22void perf_session__output_resort(struct perf_session *self, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self);
24size_t perf_session__fprintf_hists(struct perf_session *self,
25 struct perf_session *pair,
26 bool show_displacement, FILE *fp);
27#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/kernel.h b/tools/perf/util/include/linux/kernel.h
index a6b87390cb52..21c0274c02fa 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,70 @@
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
29#endif 105#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..c4d55a0da2ea 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -3,6 +3,7 @@
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"
6 7
7static inline int is_anon_memory(const char *filename) 8static inline int is_anon_memory(const char *filename)
8{ 9{
@@ -19,13 +20,28 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
19 return n; 20 return n;
20} 21}
21 22
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) 23void map__init(struct map *self, enum map_type type,
24 u64 start, u64 end, u64 pgoff, struct dso *dso)
25{
26 self->type = type;
27 self->start = start;
28 self->end = end;
29 self->pgoff = pgoff;
30 self->dso = dso;
31 self->map_ip = map__map_ip;
32 self->unmap_ip = map__unmap_ip;
33 RB_CLEAR_NODE(&self->rb_node);
34}
35
36struct map *map__new(struct mmap_event *event, enum map_type type,
37 char *cwd, int cwdlen)
23{ 38{
24 struct map *self = malloc(sizeof(*self)); 39 struct map *self = malloc(sizeof(*self));
25 40
26 if (self != NULL) { 41 if (self != NULL) {
27 const char *filename = event->filename; 42 const char *filename = event->filename;
28 char newfilename[PATH_MAX]; 43 char newfilename[PATH_MAX];
44 struct dso *dso;
29 int anon; 45 int anon;
30 46
31 if (cwd) { 47 if (cwd) {
@@ -45,18 +61,15 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
45 filename = newfilename; 61 filename = newfilename;
46 } 62 }
47 63
48 self->start = event->start; 64 dso = dsos__findnew(filename);
49 self->end = event->start + event->len; 65 if (dso == NULL)
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete; 66 goto out_delete;
55 67
68 map__init(self, type, event->start, event->start + event->len,
69 event->pgoff, dso);
70
56 if (self->dso == vdso || anon) 71 if (self->dso == vdso || anon)
57 self->map_ip = vdso__map_ip; 72 self->map_ip = self->unmap_ip = identity__map_ip;
58 else
59 self->map_ip = map__map_ip;
60 } 73 }
61 return self; 74 return self;
62out_delete: 75out_delete:
@@ -64,6 +77,99 @@ out_delete:
64 return NULL; 77 return NULL;
65} 78}
66 79
80void map__delete(struct map *self)
81{
82 free(self);
83}
84
85void map__fixup_start(struct map *self)
86{
87 struct rb_root *symbols = &self->dso->symbols[self->type];
88 struct rb_node *nd = rb_first(symbols);
89 if (nd != NULL) {
90 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
91 self->start = sym->start;
92 }
93}
94
95void map__fixup_end(struct map *self)
96{
97 struct rb_root *symbols = &self->dso->symbols[self->type];
98 struct rb_node *nd = rb_last(symbols);
99 if (nd != NULL) {
100 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
101 self->end = sym->end;
102 }
103}
104
105#define DSO__DELETED "(deleted)"
106
107int map__load(struct map *self, struct perf_session *session,
108 symbol_filter_t filter)
109{
110 const char *name = self->dso->long_name;
111 int nr;
112
113 if (dso__loaded(self->dso, self->type))
114 return 0;
115
116 nr = dso__load(self->dso, self, session, filter);
117 if (nr < 0) {
118 if (self->dso->has_build_id) {
119 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
120
121 build_id__sprintf(self->dso->build_id,
122 sizeof(self->dso->build_id),
123 sbuild_id);
124 pr_warning("%s with build id %s not found",
125 name, sbuild_id);
126 } else
127 pr_warning("Failed to open %s", name);
128
129 pr_warning(", continuing without symbols\n");
130 return -1;
131 } else if (nr == 0) {
132 const size_t len = strlen(name);
133 const size_t real_len = len - sizeof(DSO__DELETED);
134
135 if (len > sizeof(DSO__DELETED) &&
136 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
137 pr_warning("%.*s was updated, restart the long "
138 "running apps that use it!\n",
139 (int)real_len, name);
140 } else {
141 pr_warning("no symbols found in %s, maybe install "
142 "a debug package?\n", name);
143 }
144
145 return -1;
146 }
147
148 return 0;
149}
150
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
152 u64 addr, symbol_filter_t filter)
153{
154 if (map__load(self, session, filter) < 0)
155 return NULL;
156
157 return dso__find_symbol(self->dso, self->type, addr);
158}
159
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter)
163{
164 if (map__load(self, session, filter) < 0)
165 return NULL;
166
167 if (!dso__sorted_by_name(self->dso, self->type))
168 dso__sort_by_name(self->dso, self->type);
169
170 return dso__find_symbol_by_name(self->dso, self->type, name);
171}
172
67struct map *map__clone(struct map *self) 173struct map *map__clone(struct map *self)
68{ 174{
69 struct map *map = malloc(sizeof(*self)); 175 struct map *map = malloc(sizeof(*self));
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..e5bc0fb016b2 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);
@@ -471,7 +467,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
471 while ((evt_ent = readdir(evt_dir))) { 467 while ((evt_ent = readdir(evt_dir))) {
472 char event_opt[MAX_EVOPT_LEN + 1]; 468 char event_opt[MAX_EVOPT_LEN + 1];
473 int len; 469 int len;
474 unsigned int rem = MAX_EVOPT_LEN;
475 470
476 if (!strcmp(evt_ent->d_name, ".") 471 if (!strcmp(evt_ent->d_name, ".")
477 || !strcmp(evt_ent->d_name, "..") 472 || !strcmp(evt_ent->d_name, "..")
@@ -479,20 +474,12 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
479 || !strcmp(evt_ent->d_name, "filter")) 474 || !strcmp(evt_ent->d_name, "filter"))
480 continue; 475 continue;
481 476
482 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, 477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
483 evt_ent->d_name); 478 evt_ent->d_name, flags ? ":" : "",
479 flags ?: "");
484 if (len < 0) 480 if (len < 0)
485 return EVT_FAILED; 481 return EVT_FAILED;
486 482
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)) 483 if (parse_events(NULL, event_opt, 0))
497 return EVT_FAILED; 484 return EVT_FAILED;
498 } 485 }
@@ -509,7 +496,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
509 char sys_name[MAX_EVENT_LENGTH]; 496 char sys_name[MAX_EVENT_LENGTH];
510 unsigned int sys_length, evt_length; 497 unsigned int sys_length, evt_length;
511 498
512 if (valid_debugfs_mount(debugfs_path)) 499 if (debugfs_valid_mountpoint(debugfs_path))
513 return 0; 500 return 0;
514 501
515 evt_name = strchr(*strp, ':'); 502 evt_name = strchr(*strp, ':');
@@ -544,6 +531,81 @@ static enum event_result parse_tracepoint_event(const char **strp,
544 attr, strp); 531 attr, strp);
545} 532}
546 533
534static enum event_result
535parse_breakpoint_type(const char *type, const char **strp,
536 struct perf_event_attr *attr)
537{
538 int i;
539
540 for (i = 0; i < 3; i++) {
541 if (!type[i])
542 break;
543
544 switch (type[i]) {
545 case 'r':
546 attr->bp_type |= HW_BREAKPOINT_R;
547 break;
548 case 'w':
549 attr->bp_type |= HW_BREAKPOINT_W;
550 break;
551 case 'x':
552 attr->bp_type |= HW_BREAKPOINT_X;
553 break;
554 default:
555 return EVT_FAILED;
556 }
557 }
558 if (!attr->bp_type) /* Default */
559 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
560
561 *strp = type + i;
562
563 return EVT_HANDLED;
564}
565
566static enum event_result
567parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
568{
569 const char *target;
570 const char *type;
571 char *endaddr;
572 u64 addr;
573 enum event_result err;
574
575 target = strchr(*strp, ':');
576 if (!target)
577 return EVT_FAILED;
578
579 if (strncmp(*strp, "mem", target - *strp) != 0)
580 return EVT_FAILED;
581
582 target++;
583
584 addr = strtoull(target, &endaddr, 0);
585 if (target == endaddr)
586 return EVT_FAILED;
587
588 attr->bp_addr = addr;
589 *strp = endaddr;
590
591 type = strchr(target, ':');
592
593 /* If no type is defined, just rw as default */
594 if (!type) {
595 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
596 } else {
597 err = parse_breakpoint_type(++type, strp, attr);
598 if (err == EVT_FAILED)
599 return EVT_FAILED;
600 }
601
602 /* We should find a nice way to override the access type */
603 attr->bp_len = HW_BREAKPOINT_LEN_4;
604 attr->type = PERF_TYPE_BREAKPOINT;
605
606 return EVT_HANDLED;
607}
608
547static int check_events(const char *str, unsigned int i) 609static int check_events(const char *str, unsigned int i)
548{ 610{
549 int n; 611 int n;
@@ -677,6 +739,12 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
677 if (ret != EVT_FAILED) 739 if (ret != EVT_FAILED)
678 goto modifier; 740 goto modifier;
679 741
742 ret = parse_breakpoint_event(str, attr);
743 if (ret != EVT_FAILED)
744 goto modifier;
745
746 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
747 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
680 return EVT_FAILED; 748 return EVT_FAILED;
681 749
682modifier: 750modifier:
@@ -708,7 +776,6 @@ static void store_event_type(const char *orgname)
708 perf_header__push_event(id, orgname); 776 perf_header__push_event(id, orgname);
709} 777}
710 778
711
712int parse_events(const struct option *opt __used, const char *str, int unset __used) 779int parse_events(const struct option *opt __used, const char *str, int unset __used)
713{ 780{
714 struct perf_event_attr attr; 781 struct perf_event_attr attr;
@@ -745,6 +812,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
745 return 0; 812 return 0;
746} 813}
747 814
815int parse_filter(const struct option *opt __used, const char *str,
816 int unset __used)
817{
818 int i = nr_counters - 1;
819 int len = strlen(str);
820
821 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
822 fprintf(stderr,
823 "-F option should follow a -e tracepoint option\n");
824 return -1;
825 }
826
827 filters[i] = malloc(len + 1);
828 if (!filters[i]) {
829 fprintf(stderr, "not enough memory to hold filter string\n");
830 return -1;
831 }
832 strcpy(filters[i], str);
833
834 return 0;
835}
836
748static const char * const event_type_descriptors[] = { 837static const char * const event_type_descriptors[] = {
749 "", 838 "",
750 "Hardware event", 839 "Hardware event",
@@ -764,7 +853,7 @@ static void print_tracepoint_events(void)
764 char evt_path[MAXPATHLEN]; 853 char evt_path[MAXPATHLEN];
765 char dir_path[MAXPATHLEN]; 854 char dir_path[MAXPATHLEN];
766 855
767 if (valid_debugfs_mount(debugfs_path)) 856 if (debugfs_valid_mountpoint(debugfs_path))
768 return; 857 return;
769 858
770 sys_dir = opendir(debugfs_path); 859 sys_dir = opendir(debugfs_path);
@@ -782,7 +871,7 @@ static void print_tracepoint_events(void)
782 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 871 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
783 snprintf(evt_path, MAXPATHLEN, "%s:%s", 872 snprintf(evt_path, MAXPATHLEN, "%s:%s",
784 sys_dirent.d_name, evt_dirent.d_name); 873 sys_dirent.d_name, evt_dirent.d_name);
785 fprintf(stderr, " %-42s [%s]\n", evt_path, 874 printf(" %-42s [%s]\n", evt_path,
786 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
787 } 876 }
788 closedir(evt_dir); 877 closedir(evt_dir);
@@ -799,8 +888,8 @@ void print_events(void)
799 unsigned int i, type, op, prev_type = -1; 888 unsigned int i, type, op, prev_type = -1;
800 char name[40]; 889 char name[40];
801 890
802 fprintf(stderr, "\n"); 891 printf("\n");
803 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 892 printf("List of pre-defined events (to be used in -e):\n");
804 893
805 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
806 type = syms->type + 1; 895 type = syms->type + 1;
@@ -808,19 +897,19 @@ void print_events(void)
808 type = 0; 897 type = 0;
809 898
810 if (type != prev_type) 899 if (type != prev_type)
811 fprintf(stderr, "\n"); 900 printf("\n");
812 901
813 if (strlen(syms->alias)) 902 if (strlen(syms->alias))
814 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 903 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
815 else 904 else
816 strcpy(name, syms->symbol); 905 strcpy(name, syms->symbol);
817 fprintf(stderr, " %-42s [%s]\n", name, 906 printf(" %-42s [%s]\n", name,
818 event_type_descriptors[type]); 907 event_type_descriptors[type]);
819 908
820 prev_type = type; 909 prev_type = type;
821 } 910 }
822 911
823 fprintf(stderr, "\n"); 912 printf("\n");
824 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 913 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
825 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 914 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
826 /* skip invalid cache type */ 915 /* skip invalid cache type */
@@ -828,17 +917,20 @@ void print_events(void)
828 continue; 917 continue;
829 918
830 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
831 fprintf(stderr, " %-42s [%s]\n", 920 printf(" %-42s [%s]\n",
832 event_cache_name(type, op, i), 921 event_cache_name(type, op, i),
833 event_type_descriptors[4]); 922 event_type_descriptors[4]);
834 } 923 }
835 } 924 }
836 } 925 }
837 926
838 fprintf(stderr, "\n"); 927 printf("\n");
839 fprintf(stderr, " %-42s [raw hardware event descriptor]\n", 928 printf(" %-42s [raw hardware event descriptor]\n",
840 "rNNN"); 929 "rNNN");
841 fprintf(stderr, "\n"); 930 printf("\n");
931
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]");
933 printf("\n");
842 934
843 print_tracepoint_events(); 935 print_tracepoint_events();
844 936
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..29465d440043
--- /dev/null
+++ b/tools/perf/util/probe-event.c
@@ -0,0 +1,677 @@
1/*
2 * probe-event.c : perf-probe definition to kprobe_events format converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#define _GNU_SOURCE
23#include <sys/utsname.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <errno.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <limits.h>
34
35#undef _GNU_SOURCE
36#include "event.h"
37#include "string.h"
38#include "strlist.h"
39#include "debug.h"
40#include "parse-events.h" /* For debugfs_path */
41#include "probe-event.h"
42
43#define MAX_CMDLEN 256
44#define MAX_PROBE_ARGS 128
45#define PERFPROBE_GROUP "probe"
46
47#define semantic_error(msg ...) die("Semantic error :" msg)
48
49/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...)
51 __attribute__((format(printf, 3, 4)));
52
53static int e_snprintf(char *str, size_t size, const char *format, ...)
54{
55 int ret;
56 va_list ap;
57 va_start(ap, format);
58 ret = vsnprintf(str, size, format, ap);
59 va_end(ap);
60 if (ret >= (int)size)
61 ret = -E2BIG;
62 return ret;
63}
64
65/* Check the name is good for event/group */
66static bool check_event_name(const char *name)
67{
68 if (!isalpha(*name) && *name != '_')
69 return false;
70 while (*++name != '\0') {
71 if (!isalpha(*name) && !isdigit(*name) && *name != '_')
72 return false;
73 }
74 return true;
75}
76
77/* Parse probepoint definition. */
78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
79{
80 char *ptr, *tmp;
81 char c, nc = 0;
82 /*
83 * <Syntax>
84 * perf probe [EVENT=]SRC:LN
85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
86 *
87 * TODO:Group name support
88 */
89
90 ptr = strchr(arg, '=');
91 if (ptr) { /* Event name */
92 *ptr = '\0';
93 tmp = ptr + 1;
94 ptr = strchr(arg, ':');
95 if (ptr) /* Group name is not supported yet. */
96 semantic_error("Group name is not supported yet.");
97 if (!check_event_name(arg))
98 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg);
100 pp->event = strdup(arg);
101 arg = tmp;
102 }
103
104 ptr = strpbrk(arg, ":+@%");
105 if (ptr) {
106 nc = *ptr;
107 *ptr++ = '\0';
108 }
109
110 /* Check arg is function or file and copy it */
111 if (strchr(arg, '.')) /* File */
112 pp->file = strdup(arg);
113 else /* Function */
114 pp->function = strdup(arg);
115 DIE_IF(pp->file == NULL && pp->function == NULL);
116
117 /* Parse other options */
118 while (ptr) {
119 arg = ptr;
120 c = nc;
121 ptr = strpbrk(arg, ":+@%");
122 if (ptr) {
123 nc = *ptr;
124 *ptr++ = '\0';
125 }
126 switch (c) {
127 case ':': /* Line number */
128 pp->line = strtoul(arg, &tmp, 0);
129 if (*tmp != '\0')
130 semantic_error("There is non-digit charactor"
131 " in line number.");
132 break;
133 case '+': /* Byte offset from a symbol */
134 pp->offset = strtoul(arg, &tmp, 0);
135 if (*tmp != '\0')
136 semantic_error("There is non-digit charactor"
137 " in offset.");
138 break;
139 case '@': /* File name */
140 if (pp->file)
141 semantic_error("SRC@SRC is not allowed.");
142 pp->file = strdup(arg);
143 DIE_IF(pp->file == NULL);
144 if (ptr)
145 semantic_error("@SRC must be the last "
146 "option.");
147 break;
148 case '%': /* Probe places */
149 if (strcmp(arg, "return") == 0) {
150 pp->retprobe = 1;
151 } else /* Others not supported yet */
152 semantic_error("%%%s is not supported.", arg);
153 break;
154 default:
155 DIE_IF("Program has a bug.");
156 break;
157 }
158 }
159
160 /* Exclusion check */
161 if (pp->line && pp->offset)
162 semantic_error("Offset can't be used with line number.");
163
164 if (!pp->line && pp->file && !pp->function)
165 semantic_error("File always requires line number.");
166
167 if (pp->offset && !pp->function)
168 semantic_error("Offset requires an entry function.");
169
170 if (pp->retprobe && !pp->function)
171 semantic_error("Return probe requires an entry function.");
172
173 if ((pp->offset || pp->line) && pp->retprobe)
174 semantic_error("Offset/Line can't be used with return probe.");
175
176 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
177 pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
178}
179
180/* Parse perf-probe event definition */
181void parse_perf_probe_event(const char *str, struct probe_point *pp,
182 bool *need_dwarf)
183{
184 char **argv;
185 int argc, i;
186
187 *need_dwarf = false;
188
189 argv = argv_split(str, &argc);
190 if (!argv)
191 die("argv_split failed.");
192 if (argc > MAX_PROBE_ARGS + 1)
193 semantic_error("Too many arguments");
194
195 /* Parse probe point */
196 parse_perf_probe_probepoint(argv[0], pp);
197 if (pp->file || pp->line)
198 *need_dwarf = true;
199
200 /* Copy arguments and ensure return probe has no C argument */
201 pp->nr_args = argc - 1;
202 pp->args = zalloc(sizeof(char *) * pp->nr_args);
203 for (i = 0; i < pp->nr_args; i++) {
204 pp->args[i] = strdup(argv[i + 1]);
205 if (!pp->args[i])
206 die("Failed to copy argument.");
207 if (is_c_varname(pp->args[i])) {
208 if (pp->retprobe)
209 semantic_error("You can't specify local"
210 " variable for kretprobe");
211 *need_dwarf = true;
212 }
213 }
214
215 argv_free(argv);
216}
217
218/* Parse kprobe_events event into struct probe_point */
219void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
220{
221 char pr;
222 char *p;
223 int ret, i, argc;
224 char **argv;
225
226 pr_debug("Parsing kprobe_events: %s\n", str);
227 argv = argv_split(str, &argc);
228 if (!argv)
229 die("argv_split failed.");
230 if (argc < 2)
231 semantic_error("Too less arguments.");
232
233 /* Scan event and group name. */
234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
235 &pr, (float *)(void *)&pp->group,
236 (float *)(void *)&pp->event);
237 if (ret != 3)
238 semantic_error("Failed to parse event name: %s", argv[0]);
239 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
240
241 pp->retprobe = (pr == 'r');
242
243 /* Scan function name and offset */
244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
245 &pp->offset);
246 if (ret == 1)
247 pp->offset = 0;
248
249 /* kprobe_events doesn't have this information */
250 pp->line = 0;
251 pp->file = NULL;
252
253 pp->nr_args = argc - 2;
254 pp->args = zalloc(sizeof(char *) * pp->nr_args);
255 for (i = 0; i < pp->nr_args; i++) {
256 p = strchr(argv[i + 2], '=');
257 if (p) /* We don't need which register is assigned. */
258 *p = '\0';
259 pp->args[i] = strdup(argv[i + 2]);
260 if (!pp->args[i])
261 die("Failed to copy argument.");
262 }
263
264 argv_free(argv);
265}
266
267/* Synthesize only probe point (not argument) */
268int synthesize_perf_probe_point(struct probe_point *pp)
269{
270 char *buf;
271 char offs[64] = "", line[64] = "";
272 int ret;
273
274 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
275 if (!buf)
276 die("Failed to allocate memory by zalloc.");
277 if (pp->offset) {
278 ret = e_snprintf(offs, 64, "+%d", pp->offset);
279 if (ret <= 0)
280 goto error;
281 }
282 if (pp->line) {
283 ret = e_snprintf(line, 64, ":%d", pp->line);
284 if (ret <= 0)
285 goto error;
286 }
287
288 if (pp->function)
289 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
290 offs, pp->retprobe ? "%return" : "", line);
291 else
292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
293 if (ret <= 0) {
294error:
295 free(pp->probes[0]);
296 pp->probes[0] = NULL;
297 }
298 return ret;
299}
300
301int synthesize_perf_probe_event(struct probe_point *pp)
302{
303 char *buf;
304 int i, len, ret;
305
306 len = synthesize_perf_probe_point(pp);
307 if (len < 0)
308 return 0;
309
310 buf = pp->probes[0];
311 for (i = 0; i < pp->nr_args; i++) {
312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
313 pp->args[i]);
314 if (ret <= 0)
315 goto error;
316 len += ret;
317 }
318 pp->found = 1;
319
320 return pp->found;
321error:
322 free(pp->probes[0]);
323 pp->probes[0] = NULL;
324
325 return ret;
326}
327
328int synthesize_trace_kprobe_event(struct probe_point *pp)
329{
330 char *buf;
331 int i, len, ret;
332
333 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
334 if (!buf)
335 die("Failed to allocate memory by zalloc.");
336 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
337 if (ret <= 0)
338 goto error;
339 len = ret;
340
341 for (i = 0; i < pp->nr_args; i++) {
342 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
343 pp->args[i]);
344 if (ret <= 0)
345 goto error;
346 len += ret;
347 }
348 pp->found = 1;
349
350 return pp->found;
351error:
352 free(pp->probes[0]);
353 pp->probes[0] = NULL;
354
355 return ret;
356}
357
358static int open_kprobe_events(int flags, int mode)
359{
360 char buf[PATH_MAX];
361 int ret;
362
363 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
364 if (ret < 0)
365 die("Failed to make kprobe_events path.");
366
367 ret = open(buf, flags, mode);
368 if (ret < 0) {
369 if (errno == ENOENT)
370 die("kprobe_events file does not exist -"
371 " please rebuild with CONFIG_KPROBE_TRACER.");
372 else
373 die("Could not open kprobe_events file: %s",
374 strerror(errno));
375 }
376 return ret;
377}
378
379/* Get raw string list of current kprobe_events */
380static struct strlist *get_trace_kprobe_event_rawlist(int fd)
381{
382 int ret, idx;
383 FILE *fp;
384 char buf[MAX_CMDLEN];
385 char *p;
386 struct strlist *sl;
387
388 sl = strlist__new(true, NULL);
389
390 fp = fdopen(dup(fd), "r");
391 while (!feof(fp)) {
392 p = fgets(buf, MAX_CMDLEN, fp);
393 if (!p)
394 break;
395
396 idx = strlen(p) - 1;
397 if (p[idx] == '\n')
398 p[idx] = '\0';
399 ret = strlist__add(sl, buf);
400 if (ret < 0)
401 die("strlist__add failed: %s", strerror(-ret));
402 }
403 fclose(fp);
404
405 return sl;
406}
407
408/* Free and zero clear probe_point */
409static void clear_probe_point(struct probe_point *pp)
410{
411 int i;
412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
417 if (pp->function)
418 free(pp->function);
419 if (pp->file)
420 free(pp->file);
421 for (i = 0; i < pp->nr_args; i++)
422 free(pp->args[i]);
423 if (pp->args)
424 free(pp->args);
425 for (i = 0; i < pp->found; i++)
426 free(pp->probes[i]);
427 memset(pp, 0, sizeof(*pp));
428}
429
430/* Show an event */
431static void show_perf_probe_event(const char *event, const char *place,
432 struct probe_point *pp)
433{
434 int i, ret;
435 char buf[128];
436
437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
438 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret));
440 printf(" %-40s (on %s", buf, place);
441
442 if (pp->nr_args > 0) {
443 printf(" with");
444 for (i = 0; i < pp->nr_args; i++)
445 printf(" %s", pp->args[i]);
446 }
447 printf(")\n");
448}
449
450/* List up current perf-probe events */
451void show_perf_probe_events(void)
452{
453 int fd;
454 struct probe_point pp;
455 struct strlist *rawlist;
456 struct str_node *ent;
457
458 fd = open_kprobe_events(O_RDONLY, 0);
459 rawlist = get_trace_kprobe_event_rawlist(fd);
460 close(fd);
461
462 strlist__for_each(ent, rawlist) {
463 parse_trace_kprobe_event(ent->s, &pp);
464 /* Synthesize only event probe point */
465 synthesize_perf_probe_point(&pp);
466 /* Show an event */
467 show_perf_probe_event(pp.event, pp.probes[0], &pp);
468 clear_probe_point(&pp);
469 }
470
471 strlist__delete(rawlist);
472}
473
474/* Get current perf-probe event names */
475static struct strlist *get_perf_event_names(int fd, bool include_group)
476{
477 char buf[128];
478 struct strlist *sl, *rawlist;
479 struct str_node *ent;
480 struct probe_point pp;
481
482 memset(&pp, 0, sizeof(pp));
483 rawlist = get_trace_kprobe_event_rawlist(fd);
484
485 sl = strlist__new(true, NULL);
486 strlist__for_each(ent, rawlist) {
487 parse_trace_kprobe_event(ent->s, &pp);
488 if (include_group) {
489 if (e_snprintf(buf, 128, "%s:%s", pp.group,
490 pp.event) < 0)
491 die("Failed to copy group:event name.");
492 strlist__add(sl, buf);
493 } else
494 strlist__add(sl, pp.event);
495 clear_probe_point(&pp);
496 }
497
498 strlist__delete(rawlist);
499
500 return sl;
501}
502
503static void write_trace_kprobe_event(int fd, const char *buf)
504{
505 int ret;
506
507 pr_debug("Writing event: %s\n", buf);
508 ret = write(fd, buf, strlen(buf));
509 if (ret <= 0)
510 die("Failed to write event: %s", strerror(errno));
511}
512
513static void get_new_event_name(char *buf, size_t len, const char *base,
514 struct strlist *namelist, bool allow_suffix)
515{
516 int i, ret;
517
518 /* Try no suffix */
519 ret = e_snprintf(buf, len, "%s", base);
520 if (ret < 0)
521 die("snprintf() failed: %s", strerror(-ret));
522 if (!strlist__has_entry(namelist, buf))
523 return;
524
525 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event.");
529 }
530
531 /* Try to add suffix */
532 for (i = 1; i < MAX_EVENT_INDEX; i++) {
533 ret = e_snprintf(buf, len, "%s_%d", base, i);
534 if (ret < 0)
535 die("snprintf() failed: %s", strerror(-ret));
536 if (!strlist__has_entry(namelist, buf))
537 break;
538 }
539 if (i == MAX_EVENT_INDEX)
540 die("Too many events are on the same function.");
541}
542
543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
544 bool force_add)
545{
546 int i, j, fd;
547 struct probe_point *pp;
548 char buf[MAX_CMDLEN];
549 char event[64];
550 struct strlist *namelist;
551 bool allow_suffix;
552
553 fd = open_kprobe_events(O_RDWR, O_APPEND);
554 /* Get current event names */
555 namelist = get_perf_event_names(fd, false);
556
557 for (j = 0; j < nr_probes; j++) {
558 pp = probes + j;
559 if (!pp->event)
560 pp->event = strdup(pp->function);
561 if (!pp->group)
562 pp->group = strdup(PERFPROBE_GROUP);
563 DIE_IF(!pp->event || !pp->group);
564 /* If force_add is true, suffix search is allowed */
565 allow_suffix = force_add;
566 for (i = 0; i < pp->found; i++) {
567 /* Get an unused new event name */
568 get_new_event_name(event, 64, pp->event, namelist,
569 allow_suffix);
570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
571 pp->retprobe ? 'r' : 'p',
572 pp->group, event,
573 pp->probes[i]);
574 write_trace_kprobe_event(fd, buf);
575 printf("Added new event:\n");
576 /* Get the first parameter (probe-point) */
577 sscanf(pp->probes[i], "%s", buf);
578 show_perf_probe_event(event, buf, pp);
579 /* Add added event name to namelist */
580 strlist__add(namelist, event);
581 /*
582 * Probes after the first probe which comes from same
583 * user input are always allowed to add suffix, because
584 * there might be several addresses corresponding to
585 * one code line.
586 */
587 allow_suffix = true;
588 }
589 }
590 /* Show how to use the event. */
591 printf("\nYou can now use it on all perf tools, such as:\n\n");
592 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
593
594 strlist__delete(namelist);
595 close(fd);
596}
597
598static void __del_trace_kprobe_event(int fd, struct str_node *ent)
599{
600 char *p;
601 char buf[128];
602
603 /* Convert from perf-probe event to trace-kprobe event */
604 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
605 die("Failed to copy event.");
606 p = strchr(buf + 2, ':');
607 if (!p)
608 die("Internal error: %s should have ':' but not.", ent->s);
609 *p = '/';
610
611 write_trace_kprobe_event(fd, buf);
612 printf("Remove event: %s\n", ent->s);
613}
614
615static void del_trace_kprobe_event(int fd, const char *group,
616 const char *event, struct strlist *namelist)
617{
618 char buf[128];
619 struct str_node *ent, *n;
620 int found = 0;
621
622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
623 die("Failed to copy event.");
624
625 if (strpbrk(buf, "*?")) { /* Glob-exp */
626 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) {
628 found++;
629 __del_trace_kprobe_event(fd, ent);
630 strlist__remove(namelist, ent);
631 }
632 } else {
633 ent = strlist__find(namelist, buf);
634 if (ent) {
635 found++;
636 __del_trace_kprobe_event(fd, ent);
637 strlist__remove(namelist, ent);
638 }
639 }
640 if (found == 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
642}
643
644void del_trace_kprobe_events(struct strlist *dellist)
645{
646 int fd;
647 const char *group, *event;
648 char *p, *str;
649 struct str_node *ent;
650 struct strlist *namelist;
651
652 fd = open_kprobe_events(O_RDWR, O_APPEND);
653 /* Get current event names */
654 namelist = get_perf_event_names(fd, true);
655
656 strlist__for_each(ent, dellist) {
657 str = strdup(ent->s);
658 if (!str)
659 die("Failed to copy event.");
660 pr_debug("Parsing: %s\n", str);
661 p = strchr(str, ':');
662 if (p) {
663 group = str;
664 *p = '\0';
665 event = p + 1;
666 } else {
667 group = "*";
668 event = str;
669 }
670 pr_debug("Group: %s, Event: %s\n", group, event);
671 del_trace_kprobe_event(fd, group, event, namelist);
672 free(str);
673 }
674 strlist__delete(namelist);
675 close(fd);
676}
677
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644
index 000000000000..7f1d499118c0
--- /dev/null
+++ b/tools/perf/util/probe-event.h
@@ -0,0 +1,22 @@
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_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp);
11extern int synthesize_perf_probe_event(struct probe_point *pp);
12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
13extern int synthesize_trace_kprobe_event(struct probe_point *pp);
14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add);
16extern void del_trace_kprobe_events(struct strlist *dellist);
17extern void show_perf_probe_events(void);
18
19/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024
21
22#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..4b852c0d16a5
--- /dev/null
+++ b/tools/perf/util/probe-finder.c
@@ -0,0 +1,730 @@
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 "event.h"
36#include "debug.h"
37#include "util.h"
38#include "probe-finder.h"
39
40
41/* Dwarf_Die Linkage to parent Die */
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
50/*
51 * Generic dwarf analysis helpers
52 */
53
54#define X86_32_MAX_REGS 8
55const char *x86_32_regs_table[X86_32_MAX_REGS] = {
56 "%ax",
57 "%cx",
58 "%dx",
59 "%bx",
60 "$stack", /* Stack address instead of %sp */
61 "%bp",
62 "%si",
63 "%di",
64};
65
66#define X86_64_MAX_REGS 16
67const char *x86_64_regs_table[X86_64_MAX_REGS] = {
68 "%ax",
69 "%dx",
70 "%cx",
71 "%bx",
72 "%si",
73 "%di",
74 "%bp",
75 "%sp",
76 "%r8",
77 "%r9",
78 "%r10",
79 "%r11",
80 "%r12",
81 "%r13",
82 "%r14",
83 "%r15",
84};
85
86/* TODO: switching by dwarf address size */
87#ifdef __x86_64__
88#define ARCH_MAX_REGS X86_64_MAX_REGS
89#define arch_regs_table x86_64_regs_table
90#else
91#define ARCH_MAX_REGS X86_32_MAX_REGS
92#define arch_regs_table x86_32_regs_table
93#endif
94
95/* Return architecture dependent register string (for kprobe-tracer) */
96static const char *get_arch_regstr(unsigned int n)
97{
98 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
99}
100
101/*
102 * Compare the tail of two strings.
103 * Return 0 if whole of either string is same as another's tail part.
104 */
105static int strtailcmp(const char *s1, const char *s2)
106{
107 int i1 = strlen(s1);
108 int i2 = strlen(s2);
109 while (--i1 >= 0 && --i2 >= 0) {
110 if (s1[i1] != s2[i2])
111 return s1[i1] - s2[i2];
112 }
113 return 0;
114}
115
116/* Find the fileno of the target file. */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
118{
119 Dwarf_Signed cnt, i;
120 Dwarf_Unsigned found = 0;
121 char **srcs;
122 int ret;
123
124 if (!fname)
125 return 0;
126
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
128 if (ret == DW_DLV_OK) {
129 for (i = 0; i < cnt && !found; i++) {
130 if (strtailcmp(srcs[i], fname) == 0)
131 found = i + 1;
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
133 }
134 for (; i < cnt; i++)
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 }
138 if (found)
139 pr_debug("found fno: %d\n", (int)found);
140 return found;
141}
142
143/* Compare diename and tname */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname)
145{
146 char *name;
147 int ret;
148 ret = dwarf_diename(dw_die, &name, &__dw_error);
149 DIE_IF(ret == DW_DLV_ERROR);
150 if (ret == DW_DLV_OK) {
151 ret = strcmp(tname, name);
152 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
153 } else
154 ret = -1;
155 return ret;
156}
157
158/* Check the address is in the subprogram(function). */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
160 Dwarf_Signed *offs)
161{
162 Dwarf_Addr lopc, hipc;
163 int ret;
164
165 /* TODO: check ranges */
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
167 DIE_IF(ret == DW_DLV_ERROR);
168 if (ret == DW_DLV_NO_ENTRY)
169 return 0;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
171 DIE_IF(ret != DW_DLV_OK);
172 if (lopc <= addr && addr < hipc) {
173 *offs = addr - lopc;
174 return 1;
175 } else
176 return 0;
177}
178
179/* Check the die is inlined function */
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
181{
182 /* TODO: check strictly */
183 Dwarf_Bool inl;
184 int ret;
185
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
187 DIE_IF(ret == DW_DLV_ERROR);
188 return inl;
189}
190
191/* Get the offset of abstruct_origin */
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
193{
194 Dwarf_Attribute attr;
195 Dwarf_Off cu_offs;
196 int ret;
197
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
199 DIE_IF(ret != DW_DLV_OK);
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error);
201 DIE_IF(ret != DW_DLV_OK);
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
203 return cu_offs;
204}
205
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
208{
209 Dwarf_Attribute attr;
210 Dwarf_Addr addr;
211 Dwarf_Off offs;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret;
215
216 /* Try to get entry pc */
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
218 DIE_IF(ret == DW_DLV_ERROR);
219 if (ret == DW_DLV_OK) {
220 ret = dwarf_formaddr(attr, &addr, &__dw_error);
221 DIE_IF(ret != DW_DLV_OK);
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
223 return addr;
224 }
225
226 /* Try to get low pc */
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
228 DIE_IF(ret == DW_DLV_ERROR);
229 if (ret == DW_DLV_OK)
230 return addr;
231
232 /* Try to get ranges */
233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
234 DIE_IF(ret != DW_DLV_OK);
235 ret = dwarf_formref(attr, &offs, &__dw_error);
236 DIE_IF(ret != DW_DLV_OK);
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
238 &__dw_error);
239 DIE_IF(ret != DW_DLV_OK);
240 addr = ranges[0].dwr_addr1;
241 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
242 return addr;
243}
244
245/*
246 * Search a Die from Die tree.
247 * Note: cur_link->die should be deallocated in this function.
248 */
249static int __search_die_tree(struct die_link *cur_link,
250 int (*die_cb)(struct die_link *, void *),
251 void *data)
252{
253 Dwarf_Die new_die;
254 struct die_link new_link;
255 int ret;
256
257 if (!die_cb)
258 return 0;
259
260 /* Check current die */
261 while (!(ret = die_cb(cur_link, data))) {
262 /* Check child die */
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
264 DIE_IF(ret == DW_DLV_ERROR);
265 if (ret == DW_DLV_OK) {
266 new_link.parent = cur_link;
267 new_link.die = new_die;
268 ret = __search_die_tree(&new_link, die_cb, data);
269 if (ret)
270 break;
271 }
272
273 /* Move to next sibling */
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
275 &__dw_error);
276 DIE_IF(ret == DW_DLV_ERROR);
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
278 cur_link->die = new_die;
279 if (ret == DW_DLV_NO_ENTRY)
280 return 0;
281 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
283 return ret;
284}
285
286/* Search a die in its children's die tree */
287static int search_die_from_children(Dwarf_Die parent_die,
288 int (*die_cb)(struct die_link *, void *),
289 void *data)
290{
291 struct die_link new_link;
292 int ret;
293
294 new_link.parent = NULL;
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
296 DIE_IF(ret == DW_DLV_ERROR);
297 if (ret == DW_DLV_OK)
298 return __search_die_tree(&new_link, die_cb, data);
299 else
300 return 0;
301}
302
303/* Find a locdesc corresponding to the address */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
305 Dwarf_Addr addr)
306{
307 Dwarf_Signed lcnt;
308 Dwarf_Locdesc **llbuf;
309 int ret, i;
310
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
312 DIE_IF(ret != DW_DLV_OK);
313 ret = DW_DLV_NO_ENTRY;
314 for (i = 0; i < lcnt; ++i) {
315 if (llbuf[i]->ld_lopc <= addr &&
316 llbuf[i]->ld_hipc > addr) {
317 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
318 desc->ld_s =
319 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
320 DIE_IF(desc->ld_s == NULL);
321 memcpy(desc->ld_s, llbuf[i]->ld_s,
322 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
323 ret = DW_DLV_OK;
324 break;
325 }
326 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
327 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
328 }
329 /* Releasing loop */
330 for (; i < lcnt; ++i) {
331 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
332 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
333 }
334 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
335 return ret;
336}
337
338/* Get decl_file attribute value (file number) */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
340{
341 Dwarf_Attribute attr;
342 Dwarf_Unsigned fno;
343 int ret;
344
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
346 DIE_IF(ret != DW_DLV_OK);
347 dwarf_formudata(attr, &fno, &__dw_error);
348 DIE_IF(ret != DW_DLV_OK);
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
350 return fno;
351}
352
353/* Get decl_line attribute value (line number) */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
355{
356 Dwarf_Attribute attr;
357 Dwarf_Unsigned lno;
358 int ret;
359
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
361 DIE_IF(ret != DW_DLV_OK);
362 dwarf_formudata(attr, &lno, &__dw_error);
363 DIE_IF(ret != DW_DLV_OK);
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
365 return lno;
366}
367
368/*
369 * Probe finder related functions
370 */
371
372/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
374{
375 Dwarf_Small op;
376 Dwarf_Unsigned regn;
377 Dwarf_Signed offs;
378 int deref = 0, ret;
379 const char *regs;
380
381 op = loc->lr_atom;
382
383 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) {
385 deref = 1;
386 offs = (Dwarf_Signed)loc->lr_number;
387 op = pf->fbloc.ld_s[0].lr_atom;
388 loc = &pf->fbloc.ld_s[0];
389 } else
390 offs = 0;
391
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
393 regn = op - DW_OP_breg0;
394 offs += (Dwarf_Signed)loc->lr_number;
395 deref = 1;
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
397 regn = op - DW_OP_reg0;
398 } else if (op == DW_OP_bregx) {
399 regn = loc->lr_number;
400 offs += (Dwarf_Signed)loc->lr_number2;
401 deref = 1;
402 } else if (op == DW_OP_regx) {
403 regn = loc->lr_number;
404 } else
405 die("Dwarf_OP %d is not supported.\n", op);
406
407 regs = get_arch_regstr(regn);
408 if (!regs)
409 die("%lld exceeds max register number.\n", regn);
410
411 if (deref)
412 ret = snprintf(pf->buf, pf->len,
413 " %s=%+lld(%s)", pf->var, offs, regs);
414 else
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
416 DIE_IF(ret < 0);
417 DIE_IF(ret >= pf->len);
418}
419
420/* Show a variables in kprobe event format */
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
422{
423 Dwarf_Attribute attr;
424 Dwarf_Locdesc ld;
425 int ret;
426
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
428 if (ret != DW_DLV_OK)
429 goto error;
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
431 if (ret != DW_DLV_OK)
432 goto error;
433 /* TODO? */
434 DIE_IF(ld.ld_cents != 1);
435 show_location(&ld.ld_s[0], pf);
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ;
439error:
440 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var);
442}
443
444static int variable_callback(struct die_link *dlink, void *data)
445{
446 struct probe_finder *pf = (struct probe_finder *)data;
447 Dwarf_Half tag;
448 int ret;
449
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
451 DIE_IF(ret == DW_DLV_ERROR);
452 if ((tag == DW_TAG_formal_parameter ||
453 tag == DW_TAG_variable) &&
454 (die_compare_name(dlink->die, pf->var) == 0)) {
455 show_variable(dlink->die, pf);
456 return 1;
457 }
458 /* TODO: Support struct members and arrays */
459 return 0;
460}
461
462/* Find a variable in a subprogram die */
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
464{
465 int ret;
466
467 if (!is_c_varname(pf->var)) {
468 /* Output raw parameters */
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
470 DIE_IF(ret < 0);
471 DIE_IF(ret >= pf->len);
472 return ;
473 }
474
475 pr_debug("Searching '%s' variable in context.\n", pf->var);
476 /* Search child die for local variables and parameters. */
477 ret = search_die_from_children(sp_die, variable_callback, pf);
478 if (!ret)
479 die("Failed to find '%s' in this function.\n", pf->var);
480}
481
482/* Get a frame base on the address */
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
484{
485 Dwarf_Attribute attr;
486 int ret;
487
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
489 DIE_IF(ret != DW_DLV_OK);
490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
491 DIE_IF(ret != DW_DLV_OK);
492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
493}
494
495static void free_current_frame_base(struct probe_finder *pf)
496{
497 free(pf->fbloc.ld_s);
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
499}
500
501/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
503 struct probe_finder *pf)
504{
505 struct probe_point *pp = pf->pp;
506 char *name;
507 char tmp[MAX_PROBE_BUFFER];
508 int ret, i, len;
509
510 /* Output name of probe point */
511 ret = dwarf_diename(sp_die, &name, &__dw_error);
512 DIE_IF(ret == DW_DLV_ERROR);
513 if (ret == DW_DLV_OK) {
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
515 (unsigned int)offs);
516 /* Copy the function name if possible */
517 if (!pp->function) {
518 pp->function = strdup(name);
519 pp->offset = offs;
520 }
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
522 } else {
523 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
525 if (!pp->function) {
526 /* TODO: Use _stext */
527 pp->function = strdup("");
528 pp->offset = (int)pf->addr;
529 }
530 }
531 DIE_IF(ret < 0);
532 DIE_IF(ret >= MAX_PROBE_BUFFER);
533 len = ret;
534 pr_debug("Probe point found: %s\n", tmp);
535
536 /* Find each argument */
537 get_current_frame_base(sp_die, pf);
538 for (i = 0; i < pp->nr_args; i++) {
539 pf->var = pp->args[i];
540 pf->buf = &tmp[len];
541 pf->len = MAX_PROBE_BUFFER - len;
542 find_variable(sp_die, pf);
543 len += strlen(pf->buf);
544 }
545 free_current_frame_base(pf);
546
547 pp->probes[pp->found] = strdup(tmp);
548 pp->found++;
549}
550
551static int probeaddr_callback(struct die_link *dlink, void *data)
552{
553 struct probe_finder *pf = (struct probe_finder *)data;
554 Dwarf_Half tag;
555 Dwarf_Signed offs;
556 int ret;
557
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
559 DIE_IF(ret == DW_DLV_ERROR);
560 /* Check the address is in this subprogram */
561 if (tag == DW_TAG_subprogram &&
562 die_within_subprogram(dlink->die, pf->addr, &offs)) {
563 show_probepoint(dlink->die, offs, pf);
564 return 1;
565 }
566 return 0;
567}
568
569/* Find probe point from its line number */
570static void find_by_line(struct probe_finder *pf)
571{
572 Dwarf_Signed cnt, i, clm;
573 Dwarf_Line *lines;
574 Dwarf_Unsigned lineno = 0;
575 Dwarf_Addr addr;
576 Dwarf_Unsigned fno;
577 int ret;
578
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error);
580 DIE_IF(ret != DW_DLV_OK);
581
582 for (i = 0; i < cnt; i++) {
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
584 DIE_IF(ret != DW_DLV_OK);
585 if (fno != pf->fno)
586 continue;
587
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
589 DIE_IF(ret != DW_DLV_OK);
590 if (lineno != pf->lno)
591 continue;
592
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error);
594 DIE_IF(ret != DW_DLV_OK);
595
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
597 DIE_IF(ret != DW_DLV_OK);
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i, (unsigned)lineno, (int)clm, addr);
600 pf->addr = addr;
601 /* Search a real subprogram including this line, */
602 ret = search_die_from_children(pf->cu_die,
603 probeaddr_callback, pf);
604 if (ret == 0)
605 die("Probe point is not found in subprograms.\n");
606 /* Continuing, because target line might be inlined. */
607 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
609}
610
611/* Search function from function name */
612static int probefunc_callback(struct die_link *dlink, void *data)
613{
614 struct probe_finder *pf = (struct probe_finder *)data;
615 struct probe_point *pp = pf->pp;
616 struct die_link *lk;
617 Dwarf_Signed offs;
618 Dwarf_Half tag;
619 int ret;
620
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
622 DIE_IF(ret == DW_DLV_ERROR);
623 if (tag == DW_TAG_subprogram) {
624 if (die_compare_name(dlink->die, pp->function) == 0) {
625 if (pp->line) { /* Function relative line */
626 pf->fno = die_get_decl_file(dlink->die);
627 pf->lno = die_get_decl_line(dlink->die)
628 + pp->line;
629 find_by_line(pf);
630 return 1;
631 }
632 if (die_inlined_subprogram(dlink->die)) {
633 /* Inlined function, save it. */
634 ret = dwarf_die_CU_offset(dlink->die,
635 &pf->inl_offs,
636 &__dw_error);
637 DIE_IF(ret != DW_DLV_OK);
638 pr_debug("inline definition offset %lld\n",
639 pf->inl_offs);
640 return 0; /* Continue to search */
641 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf);
647 return 1; /* Exit; no same symbol in this CU. */
648 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
651 /* Get probe address */
652 pf->addr = die_get_entrypc(dlink->die);
653 pf->addr += pp->offset;
654 pr_debug("found inline addr: 0x%llx\n", pf->addr);
655 /* Inlined function. Get a real subprogram */
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
657 tag = 0;
658 dwarf_tag(lk->die, &tag, &__dw_error);
659 DIE_IF(ret == DW_DLV_ERROR);
660 if (tag == DW_TAG_subprogram &&
661 !die_inlined_subprogram(lk->die))
662 goto found;
663 }
664 die("Failed to find real subprogram.\n");
665found:
666 /* Get offset from subprogram */
667 ret = die_within_subprogram(lk->die, pf->addr, &offs);
668 DIE_IF(!ret);
669 show_probepoint(lk->die, offs, pf);
670 /* Continue to search */
671 }
672 }
673 return 0;
674}
675
676static void find_by_func(struct probe_finder *pf)
677{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf);
679}
680
681/* Find a probe point */
682int find_probepoint(int fd, struct probe_point *pp)
683{
684 Dwarf_Half addr_size = 0;
685 Dwarf_Unsigned next_cuh = 0;
686 int cu_number = 0, ret;
687 struct probe_finder pf = {.pp = pp};
688
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
690 if (ret != DW_DLV_OK)
691 return -ENOENT;
692
693 pp->found = 0;
694 while (++cu_number) {
695 /* Search CU (Compilation Unit) */
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
697 &addr_size, &next_cuh, &__dw_error);
698 DIE_IF(ret == DW_DLV_ERROR);
699 if (ret == DW_DLV_NO_ENTRY)
700 break;
701
702 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
704 DIE_IF(ret != DW_DLV_OK);
705
706 /* Check if target file is included. */
707 if (pp->file)
708 pf.fno = cu_find_fileno(pf.cu_die, pp->file);
709
710 if (!pp->file || pf.fno) {
711 /* Save CU base address (for frame_base) */
712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
713 DIE_IF(ret == DW_DLV_ERROR);
714 if (ret == DW_DLV_NO_ENTRY)
715 pf.cu_base = 0;
716 if (pp->function)
717 find_by_func(&pf);
718 else {
719 pf.lno = pp->line;
720 find_by_line(&pf);
721 }
722 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
724 }
725 ret = dwarf_finish(__dw_debug, &__dw_error);
726 DIE_IF(ret != DW_DLV_OK);
727
728 return pp->found;
729}
730
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
new file mode 100644
index 000000000000..a4086aaddb73
--- /dev/null
+++ b/tools/perf/util/probe-finder.h
@@ -0,0 +1,65 @@
1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H
3
4#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128
7
8static inline int is_c_varname(const char *name)
9{
10 /* TODO */
11 return isalpha(name[0]) || name[0] == '_';
12}
13
14struct probe_point {
15 char *event; /* Event name */
16 char *group; /* Event group */
17
18 /* Inputs */
19 char *file; /* File name */
20 int line; /* Line number */
21
22 char *function; /* Function name */
23 int offset; /* Offset bytes */
24
25 int nr_args; /* Number of arguments */
26 char **args; /* Arguments */
27
28 int retprobe; /* Return probe */
29
30 /* Output */
31 int found; /* Number of found probe points */
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33};
34
35#ifndef NO_LIBDWARF
36extern int find_probepoint(int fd, struct probe_point *pp);
37
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
39#ifndef _MIPS_SZLONG
40# define _MIPS_SZLONG 0
41#endif
42
43#include <dwarf.h>
44#include <libdwarf.h>
45
46struct probe_finder {
47 struct probe_point *pp; /* Target probe point */
48
49 /* For function searching */
50 Dwarf_Addr addr; /* Address */
51 Dwarf_Unsigned fno; /* File number */
52 Dwarf_Unsigned lno; /* Line number */
53 Dwarf_Off inl_offs; /* Inline offset */
54 Dwarf_Die cu_die; /* Current CU */
55
56 /* For variable searching */
57 Dwarf_Addr cu_base; /* Current CU base address */
58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
59 const char *var; /* Current variable name */
60 char *buf; /* Current output buffer */
61 int len; /* Length of output buffer */
62};
63#endif /* NO_LIBDWARF */
64
65#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/session.c b/tools/perf/util/session.c
new file mode 100644
index 000000000000..ce3a6c8abe76
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,150 @@
1#include <linux/kernel.h>
2
3#include <unistd.h>
4#include <sys/types.h>
5
6#include "session.h"
7#include "sort.h"
8#include "util.h"
9
10static int perf_session__open(struct perf_session *self, bool force)
11{
12 struct stat input_stat;
13
14 self->fd = open(self->filename, O_RDONLY);
15 if (self->fd < 0) {
16 pr_err("failed to open file: %s", self->filename);
17 if (!strcmp(self->filename, "perf.data"))
18 pr_err(" (try 'perf record' first)");
19 pr_err("\n");
20 return -errno;
21 }
22
23 if (fstat(self->fd, &input_stat) < 0)
24 goto out_close;
25
26 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
27 pr_err("file %s not owned by current user or root\n",
28 self->filename);
29 goto out_close;
30 }
31
32 if (!input_stat.st_size) {
33 pr_info("zero-sized file (%s), nothing to do!\n",
34 self->filename);
35 goto out_close;
36 }
37
38 if (perf_header__read(&self->header, self->fd) < 0) {
39 pr_err("incompatible file format");
40 goto out_close;
41 }
42
43 self->size = input_stat.st_size;
44 return 0;
45
46out_close:
47 close(self->fd);
48 self->fd = -1;
49 return -1;
50}
51
52struct perf_session *perf_session__new(const char *filename, int mode, bool force)
53{
54 size_t len = filename ? strlen(filename) + 1 : 0;
55 struct perf_session *self = zalloc(sizeof(*self) + len);
56
57 if (self == NULL)
58 goto out;
59
60 if (perf_header__init(&self->header) < 0)
61 goto out_free;
62
63 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT;
65 self->last_match = NULL;
66 self->mmap_window = 32;
67 self->cwd = NULL;
68 self->cwdlen = 0;
69 map_groups__init(&self->kmaps);
70
71 if (perf_session__create_kernel_maps(self) < 0)
72 goto out_delete;
73
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0)
75 goto out_delete;
76out:
77 return self;
78out_free:
79 free(self);
80 return NULL;
81out_delete:
82 perf_session__delete(self);
83 return NULL;
84}
85
86void perf_session__delete(struct perf_session *self)
87{
88 perf_header__exit(&self->header);
89 close(self->fd);
90 free(self->cwd);
91 free(self);
92}
93
94static bool symbol__match_parent_regex(struct symbol *sym)
95{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
97 return 1;
98
99 return 0;
100}
101
102struct symbol **perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread,
104 struct ip_callchain *chain,
105 struct symbol **parent)
106{
107 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i;
110
111 if (symbol_conf.use_callchain) {
112 syms = calloc(chain->nr, sizeof(*syms));
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118
119 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i];
121 struct addr_location al;
122
123 if (ip >= PERF_CONTEXT_MAX) {
124 switch (ip) {
125 case PERF_CONTEXT_HV:
126 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
127 case PERF_CONTEXT_KERNEL:
128 cpumode = PERF_RECORD_MISC_KERNEL; break;
129 case PERF_CONTEXT_USER:
130 cpumode = PERF_RECORD_MISC_USER; break;
131 default:
132 break;
133 }
134 continue;
135 }
136
137 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL);
139 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym))
142 *parent = al.sym;
143 if (!symbol_conf.use_callchain)
144 break;
145 syms[i] = al.sym;
146 }
147 }
148
149 return syms;
150}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..32eaa1bada06
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,61 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "event.h"
5#include "header.h"
6#include "thread.h"
7#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h"
9
10struct ip_callchain;
11struct thread;
12struct symbol;
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 events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX];
23 struct rb_root hists;
24 u64 sample_type;
25 int fd;
26 int cwdlen;
27 char *cwd;
28 char filename[0];
29};
30
31typedef int (*event_op)(event_t *self, struct perf_session *session);
32
33struct perf_event_ops {
34 event_op process_sample_event;
35 event_op process_mmap_event;
36 event_op process_comm_event;
37 event_op process_fork_event;
38 event_op process_exit_event;
39 event_op process_lost_event;
40 event_op process_read_event;
41 event_op process_throttle_event;
42 event_op process_unthrottle_event;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46};
47
48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self);
50
51int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops);
53
54struct symbol **perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread,
56 struct ip_callchain *chain,
57 struct symbol **parent);
58
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
60
61#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..5352d7dccc61 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,221 @@ 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/* Glob expression pattern matching */
231bool strglobmatch(const char *str, const char *pat)
232{
233 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') {
235 str++;
236 pat++;
237 } else
238 if (*str++ != *pat++)
239 return false;
240 }
241 /* Check wild card */
242 if (*pat == '*') {
243 while (*pat == '*')
244 pat++;
245 if (!*pat) /* Tail wild card matches all */
246 return true;
247 while (*str)
248 if (strglobmatch(str++, pat))
249 return true;
250 }
251 return !*str && !*pat;
252}
253
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..02ede58c54b4 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,17 @@
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);
7 13
8#define _STR(x) #x 14#define _STR(x) #x
9#define STR(x) _STR(x) 15#define STR(x) _STR(x)
10 16
11#endif 17#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..ab92763edb03 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,15 +1,23 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "session.h"
4#include "sort.h"
3#include "string.h" 5#include "string.h"
4#include "symbol.h" 6#include "symbol.h"
7#include "thread.h"
5 8
6#include "debug.h" 9#include "debug.h"
7 10
11#include <asm/bug.h>
8#include <libelf.h> 12#include <libelf.h>
9#include <gelf.h> 13#include <gelf.h>
10#include <elf.h> 14#include <elf.h>
15#include <limits.h>
16#include <sys/utsname.h>
11 17
12const char *sym_hist_filter; 18#ifndef NT_GNU_BUILD_ID
19#define NT_GNU_BUILD_ID 3
20#endif
13 21
14enum dso_origin { 22enum dso_origin {
15 DSO__ORIG_KERNEL = 0, 23 DSO__ORIG_KERNEL = 0,
@@ -18,94 +26,206 @@ enum dso_origin {
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 struct perf_session *session, 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_loaded(struct dso *self, enum map_type type)
57{
58 self->loaded |= (1 << type);
59}
60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{
63 self->sorted_by_name |= (1 << type);
64}
65
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{
68 switch (map_type) {
69 case MAP__FUNCTION:
70 return symbol_type == 'T' || symbol_type == 'W';
71 case MAP__VARIABLE:
72 return symbol_type == 'D' || symbol_type == 'd';
73 default:
74 return false;
75 }
76}
77
78static void symbols__fixup_end(struct rb_root *self)
79{
80 struct rb_node *nd, *prevnd = rb_first(self);
81 struct symbol *curr, *prev;
82
83 if (prevnd == NULL)
84 return;
85
86 curr = rb_entry(prevnd, struct symbol, rb_node);
87
88 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
89 prev = curr;
90 curr = rb_entry(nd, struct symbol, rb_node);
91
92 if (prev->end == prev->start)
93 prev->end = curr->start - 1;
94 }
95
96 /* Last entry */
97 if (curr->end == curr->start)
98 curr->end = roundup(curr->start, 4096);
99}
33 100
34 if (v >= 2) 101static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 102{
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 103 struct map *prev, *curr;
104 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
37 105
38 self->obj_start= obj_start; 106 if (prevnd == NULL)
39 self->hist = NULL; 107 return;
40 self->hist_sum = 0;
41 108
42 if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 109 curr = rb_entry(prevnd, struct map, rb_node);
43 self->hist = calloc(sizeof(u64), len);
44 110
45 if (priv_size) { 111 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
46 memset(self, 0, priv_size); 112 prev = curr;
47 self = ((void *)self) + priv_size; 113 curr = rb_entry(nd, struct map, rb_node);
114 prev->end = curr->start - 1;
48 } 115 }
116
117 /*
118 * We still haven't the actual symbols, so guess the
119 * last map final address.
120 */
121 curr->end = ~0UL;
122}
123
124static void map_groups__fixup_end(struct map_groups *self)
125{
126 int i;
127 for (i = 0; i < MAP__NR_TYPES; ++i)
128 __map_groups__fixup_end(self, i);
129}
130
131static struct symbol *symbol__new(u64 start, u64 len, const char *name)
132{
133 size_t namelen = strlen(name) + 1;
134 struct symbol *self = zalloc(symbol_conf.priv_size +
135 sizeof(*self) + namelen);
136 if (self == NULL)
137 return NULL;
138
139 if (symbol_conf.priv_size)
140 self = ((void *)self) + symbol_conf.priv_size;
141
49 self->start = start; 142 self->start = start;
50 self->end = len ? start + len - 1 : start; 143 self->end = len ? start + len - 1 : start;
144
145 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
146
51 memcpy(self->name, name, namelen); 147 memcpy(self->name, name, namelen);
52 148
53 return self; 149 return self;
54} 150}
55 151
56static void symbol__delete(struct symbol *self, unsigned int priv_size) 152static void symbol__delete(struct symbol *self)
57{ 153{
58 free(((void *)self) - priv_size); 154 free(((void *)self) - symbol_conf.priv_size);
59} 155}
60 156
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 157static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 158{
63 if (!self->module) 159 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 160 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} 161}
70 162
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 163static void dso__set_long_name(struct dso *self, char *name)
164{
165 if (name == NULL)
166 return;
167 self->long_name = name;
168 self->long_name_len = strlen(name);
169}
170
171static void dso__set_basename(struct dso *self)
172{
173 self->short_name = basename(self->long_name);
174}
175
176struct dso *dso__new(const char *name)
72{ 177{
73 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
74 179
75 if (self != NULL) { 180 if (self != NULL) {
181 int i;
76 strcpy(self->name, name); 182 strcpy(self->name, name);
77 self->syms = RB_ROOT; 183 dso__set_long_name(self, self->name);
78 self->sym_priv_size = sym_priv_size; 184 self->short_name = self->name;
79 self->find_symbol = dso__find_symbol; 185 for (i = 0; i < MAP__NR_TYPES; ++i)
186 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
80 self->slen_calculated = 0; 187 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND; 188 self->origin = DSO__ORIG_NOT_FOUND;
189 self->loaded = 0;
190 self->sorted_by_name = 0;
191 self->has_build_id = 0;
82 } 192 }
83 193
84 return self; 194 return self;
85} 195}
86 196
87static void dso__delete_symbols(struct dso *self) 197static void symbols__delete(struct rb_root *self)
88{ 198{
89 struct symbol *pos; 199 struct symbol *pos;
90 struct rb_node *next = rb_first(&self->syms); 200 struct rb_node *next = rb_first(self);
91 201
92 while (next) { 202 while (next) {
93 pos = rb_entry(next, struct symbol, rb_node); 203 pos = rb_entry(next, struct symbol, rb_node);
94 next = rb_next(&pos->rb_node); 204 next = rb_next(&pos->rb_node);
95 rb_erase(&pos->rb_node, &self->syms); 205 rb_erase(&pos->rb_node, self);
96 symbol__delete(pos, self->sym_priv_size); 206 symbol__delete(pos);
97 } 207 }
98} 208}
99 209
100void dso__delete(struct dso *self) 210void dso__delete(struct dso *self)
101{ 211{
102 dso__delete_symbols(self); 212 int i;
213 for (i = 0; i < MAP__NR_TYPES; ++i)
214 symbols__delete(&self->symbols[i]);
215 if (self->long_name != self->name)
216 free(self->long_name);
103 free(self); 217 free(self);
104} 218}
105 219
106static void dso__insert_symbol(struct dso *self, struct symbol *sym) 220void dso__set_build_id(struct dso *self, void *build_id)
107{ 221{
108 struct rb_node **p = &self->syms.rb_node; 222 memcpy(self->build_id, build_id, sizeof(self->build_id));
223 self->has_build_id = 1;
224}
225
226static void symbols__insert(struct rb_root *self, struct symbol *sym)
227{
228 struct rb_node **p = &self->rb_node;
109 struct rb_node *parent = NULL; 229 struct rb_node *parent = NULL;
110 const u64 ip = sym->start; 230 const u64 ip = sym->start;
111 struct symbol *s; 231 struct symbol *s;
@@ -119,17 +239,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
119 p = &(*p)->rb_right; 239 p = &(*p)->rb_right;
120 } 240 }
121 rb_link_node(&sym->rb_node, parent, p); 241 rb_link_node(&sym->rb_node, parent, p);
122 rb_insert_color(&sym->rb_node, &self->syms); 242 rb_insert_color(&sym->rb_node, self);
123} 243}
124 244
125struct symbol *dso__find_symbol(struct dso *self, u64 ip) 245static struct symbol *symbols__find(struct rb_root *self, u64 ip)
126{ 246{
127 struct rb_node *n; 247 struct rb_node *n;
128 248
129 if (self == NULL) 249 if (self == NULL)
130 return NULL; 250 return NULL;
131 251
132 n = self->syms.rb_node; 252 n = self->rb_node;
133 253
134 while (n) { 254 while (n) {
135 struct symbol *s = rb_entry(n, struct symbol, rb_node); 255 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -145,12 +265,116 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
145 return NULL; 265 return NULL;
146} 266}
147 267
148size_t dso__fprintf(struct dso *self, FILE *fp) 268struct symbol_name_rb_node {
269 struct rb_node rb_node;
270 struct symbol sym;
271};
272
273static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
149{ 274{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 275 struct rb_node **p = &self->rb_node;
276 struct rb_node *parent = NULL;
277 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
151 278
279 while (*p != NULL) {
280 parent = *p;
281 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
282 if (strcmp(sym->name, s->sym.name) < 0)
283 p = &(*p)->rb_left;
284 else
285 p = &(*p)->rb_right;
286 }
287 rb_link_node(&symn->rb_node, parent, p);
288 rb_insert_color(&symn->rb_node, self);
289}
290
291static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
292{
152 struct rb_node *nd; 293 struct rb_node *nd;
153 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 294
295 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
296 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
297 symbols__insert_by_name(self, pos);
298 }
299}
300
301static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
302{
303 struct rb_node *n;
304
305 if (self == NULL)
306 return NULL;
307
308 n = self->rb_node;
309
310 while (n) {
311 struct symbol_name_rb_node *s;
312 int cmp;
313
314 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
315 cmp = strcmp(name, s->sym.name);
316
317 if (cmp < 0)
318 n = n->rb_left;
319 else if (cmp > 0)
320 n = n->rb_right;
321 else
322 return &s->sym;
323 }
324
325 return NULL;
326}
327
328struct symbol *dso__find_symbol(struct dso *self,
329 enum map_type type, u64 addr)
330{
331 return symbols__find(&self->symbols[type], addr);
332}
333
334struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
335 const char *name)
336{
337 return symbols__find_by_name(&self->symbol_names[type], name);
338}
339
340void dso__sort_by_name(struct dso *self, enum map_type type)
341{
342 dso__set_sorted_by_name(self, type);
343 return symbols__sort_by_name(&self->symbol_names[type],
344 &self->symbols[type]);
345}
346
347int build_id__sprintf(u8 *self, int len, char *bf)
348{
349 char *bid = bf;
350 u8 *raw = self;
351 int i;
352
353 for (i = 0; i < len; ++i) {
354 sprintf(bid, "%02x", *raw);
355 ++raw;
356 bid += 2;
357 }
358
359 return raw - self;
360}
361
362size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
363{
364 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
365
366 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
367 return fprintf(fp, "%s", sbuild_id);
368}
369
370size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
371{
372 struct rb_node *nd;
373 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
374
375 ret += dso__fprintf_buildid(self, fp);
376 ret += fprintf(fp, ")\n");
377 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
154 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 378 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
155 ret += symbol__fprintf(pos, fp); 379 ret += symbol__fprintf(pos, fp);
156 } 380 }
@@ -158,13 +382,17 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 382 return ret;
159} 383}
160 384
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 385/*
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
387 * so that we can in the next step set the symbol ->end address and then
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
162{ 391{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 392 char *line = NULL;
165 size_t n; 393 size_t n;
394 struct rb_root *root = &self->symbols[map->type];
166 FILE *file = fopen("/proc/kallsyms", "r"); 395 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
168 396
169 if (file == NULL) 397 if (file == NULL)
170 goto out_failure; 398 goto out_failure;
@@ -174,6 +402,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
174 struct symbol *sym; 402 struct symbol *sym;
175 int line_len, len; 403 int line_len, len;
176 char symbol_type; 404 char symbol_type;
405 char *symbol_name;
177 406
178 line_len = getline(&line, &n, file); 407 line_len = getline(&line, &n, file);
179 if (line_len < 0) 408 if (line_len < 0)
@@ -191,49 +420,28 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
191 continue; 420 continue;
192 421
193 symbol_type = toupper(line[len]); 422 symbol_type = toupper(line[len]);
194 /* 423 if (!symbol_type__is_a(symbol_type, map->type))
195 * We're interested only in code ('T'ext)
196 */
197 if (symbol_type != 'T' && symbol_type != 'W')
198 continue; 424 continue;
425
426 symbol_name = line + len + 2;
199 /* 427 /*
200 * Well fix up the end later, when we have all sorted. 428 * Will fix up the end later, when we have all symbols sorted.
201 */ 429 */
202 sym = symbol__new(start, 0xdead, line + len + 2, 430 sym = symbol__new(start, 0, symbol_name);
203 self->sym_priv_size, 0, v);
204 431
205 if (sym == NULL) 432 if (sym == NULL)
206 goto out_delete_line; 433 goto out_delete_line;
207 434 /*
208 if (filter && filter(self, sym)) 435 * We will pass the symbols to the filter later, in
209 symbol__delete(sym, self->sym_priv_size); 436 * map__split_kallsyms, when we have split the maps per module
210 else { 437 */
211 dso__insert_symbol(self, sym); 438 symbols__insert(root, sym);
212 count++;
213 }
214 }
215
216 /*
217 * Now that we have all sorted out, just set the ->end of all
218 * symbols
219 */
220 prevnd = rb_first(&self->syms);
221
222 if (prevnd == NULL)
223 goto out_delete_line;
224
225 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
226 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
227 *curr = rb_entry(nd, struct symbol, rb_node);
228
229 prev->end = curr->start - 1;
230 prevnd = nd;
231 } 439 }
232 440
233 free(line); 441 free(line);
234 fclose(file); 442 fclose(file);
235 443
236 return count; 444 return 0;
237 445
238out_delete_line: 446out_delete_line:
239 free(line); 447 free(line);
@@ -241,14 +449,107 @@ out_failure:
241 return -1; 449 return -1;
242} 450}
243 451
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 452/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the
454 * kernel range is broken in several maps, named [kernel].N, as we don't have
455 * the original ELF section names vmlinux have.
456 */
457static int dso__split_kallsyms(struct dso *self, struct map *map,
458 struct perf_session *session, symbol_filter_t filter)
459{
460 struct map *curr_map = map;
461 struct symbol *pos;
462 int count = 0;
463 struct rb_root *root = &self->symbols[map->type];
464 struct rb_node *next = rb_first(root);
465 int kernel_range = 0;
466
467 while (next) {
468 char *module;
469
470 pos = rb_entry(next, struct symbol, rb_node);
471 next = rb_next(&pos->rb_node);
472
473 module = strchr(pos->name, '\t');
474 if (module) {
475 if (!symbol_conf.use_modules)
476 goto discard_symbol;
477
478 *module++ = '\0';
479
480 if (strcmp(self->name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
482 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} "
484 "inconsistency!\n");
485 return -1;
486 }
487 }
488 /*
489 * So that we look just like we get from .ko files,
490 * i.e. not prelinked, relative to map->start.
491 */
492 pos->start = curr_map->map_ip(curr_map, pos->start);
493 pos->end = curr_map->map_ip(curr_map, pos->end);
494 } else if (curr_map != map) {
495 char dso_name[PATH_MAX];
496 struct dso *dso;
497
498 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
499 kernel_range++);
500
501 dso = dso__new(dso_name);
502 if (dso == NULL)
503 return -1;
504
505 curr_map = map__new2(pos->start, dso, map->type);
506 if (map == NULL) {
507 dso__delete(dso);
508 return -1;
509 }
510
511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
512 map_groups__insert(&session->kmaps, curr_map);
513 ++kernel_range;
514 }
515
516 if (filter && filter(curr_map, pos)) {
517discard_symbol: rb_erase(&pos->rb_node, root);
518 symbol__delete(pos);
519 } else {
520 if (curr_map != map) {
521 rb_erase(&pos->rb_node, root);
522 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
523 }
524 count++;
525 }
526 }
527
528 return count;
529}
530
531
532static int dso__load_kallsyms(struct dso *self, struct map *map,
533 struct perf_session *session, symbol_filter_t filter)
534{
535 if (dso__load_all_kallsyms(self, map) < 0)
536 return -1;
537
538 symbols__fixup_end(&self->symbols[map->type]);
539 self->origin = DSO__ORIG_KERNEL;
540
541 return dso__split_kallsyms(self, map, session, filter);
542}
543
544static int dso__load_perf_map(struct dso *self, struct map *map,
545 symbol_filter_t filter)
245{ 546{
246 char *line = NULL; 547 char *line = NULL;
247 size_t n; 548 size_t n;
248 FILE *file; 549 FILE *file;
249 int nr_syms = 0; 550 int nr_syms = 0;
250 551
251 file = fopen(self->name, "r"); 552 file = fopen(self->long_name, "r");
252 if (file == NULL) 553 if (file == NULL)
253 goto out_failure; 554 goto out_failure;
254 555
@@ -278,16 +579,15 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
278 if (len + 2 >= line_len) 579 if (len + 2 >= line_len)
279 continue; 580 continue;
280 581
281 sym = symbol__new(start, size, line + len, 582 sym = symbol__new(start, size, line + len);
282 self->sym_priv_size, start, v);
283 583
284 if (sym == NULL) 584 if (sym == NULL)
285 goto out_delete_line; 585 goto out_delete_line;
286 586
287 if (filter && filter(self, sym)) 587 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 588 symbol__delete(sym);
289 else { 589 else {
290 dso__insert_symbol(self, sym); 590 symbols__insert(&self->symbols[map->type], sym);
291 nr_syms++; 591 nr_syms++;
292 } 592 }
293 } 593 }
@@ -327,6 +627,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
327 sym->st_shndx != SHN_UNDEF; 627 sym->st_shndx != SHN_UNDEF;
328} 628}
329 629
630static inline bool elf_sym__is_object(const GElf_Sym *sym)
631{
632 return elf_sym__type(sym) == STT_OBJECT &&
633 sym->st_name != 0 &&
634 sym->st_shndx != SHN_UNDEF;
635}
636
330static inline int elf_sym__is_label(const GElf_Sym *sym) 637static inline int elf_sym__is_label(const GElf_Sym *sym)
331{ 638{
332 return elf_sym__type(sym) == STT_NOTYPE && 639 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -347,6 +654,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
347 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 654 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
348} 655}
349 656
657static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
658 const Elf_Data *secstrs)
659{
660 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
661}
662
350static inline const char *elf_sym__name(const GElf_Sym *sym, 663static inline const char *elf_sym__name(const GElf_Sym *sym,
351 const Elf_Data *symstrs) 664 const Elf_Data *symstrs)
352{ 665{
@@ -393,7 +706,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 706 * 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). 707 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395 */ 708 */
396static int dso__synthesize_plt_symbols(struct dso *self, int v) 709static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
710 symbol_filter_t filter)
397{ 711{
398 uint32_t nr_rel_entries, idx; 712 uint32_t nr_rel_entries, idx;
399 GElf_Sym sym; 713 GElf_Sym sym;
@@ -409,7 +723,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 723 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 724 int nr = 0, symidx, fd, err = 0;
411 725
412 fd = open(self->name, O_RDONLY); 726 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 727 if (fd < 0)
414 goto out; 728 goto out;
415 729
@@ -477,12 +791,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 791 "%s@plt", elf_sym__name(&sym, symstrs));
478 792
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 793 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 794 sympltname);
481 if (!f) 795 if (!f)
482 goto out_elf_end; 796 goto out_elf_end;
483 797
484 dso__insert_symbol(self, f); 798 if (filter && filter(map, f))
485 ++nr; 799 symbol__delete(f);
800 else {
801 symbols__insert(&self->symbols[map->type], f);
802 ++nr;
803 }
486 } 804 }
487 } else if (shdr_rel_plt.sh_type == SHT_REL) { 805 } else if (shdr_rel_plt.sh_type == SHT_REL) {
488 GElf_Rel pos_mem, *pos; 806 GElf_Rel pos_mem, *pos;
@@ -495,12 +813,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 813 "%s@plt", elf_sym__name(&sym, symstrs));
496 814
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 815 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 816 sympltname);
499 if (!f) 817 if (!f)
500 goto out_elf_end; 818 goto out_elf_end;
501 819
502 dso__insert_symbol(self, f); 820 if (filter && filter(map, f))
503 ++nr; 821 symbol__delete(f);
822 else {
823 symbols__insert(&self->symbols[map->type], f);
824 ++nr;
825 }
504 } 826 }
505 } 827 }
506 828
@@ -513,14 +835,42 @@ out_close:
513 if (err == 0) 835 if (err == 0)
514 return nr; 836 return nr;
515out: 837out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 838 pr_warning("%s: problems reading %s PLT info.\n",
517 __func__, self->name); 839 __func__, self->long_name);
518 return 0; 840 return 0;
519} 841}
520 842
521static int dso__load_sym(struct dso *self, int fd, const char *name, 843static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
522 symbol_filter_t filter, int v, struct module *mod)
523{ 844{
845 switch (type) {
846 case MAP__FUNCTION:
847 return elf_sym__is_function(self);
848 case MAP__VARIABLE:
849 return elf_sym__is_object(self);
850 default:
851 return false;
852 }
853}
854
855static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
856{
857 switch (type) {
858 case MAP__FUNCTION:
859 return elf_sec__is_text(self, secstrs);
860 case MAP__VARIABLE:
861 return elf_sec__is_data(self, secstrs);
862 default:
863 return false;
864 }
865}
866
867static int dso__load_sym(struct dso *self, struct map *map,
868 struct perf_session *session, const char *name, int fd,
869 symbol_filter_t filter, int kernel, int kmodule)
870{
871 struct map *curr_map = map;
872 struct dso *curr_dso = self;
873 size_t dso_name_len = strlen(self->short_name);
524 Elf_Data *symstrs, *secstrs; 874 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 875 uint32_t nr_syms;
526 int err = -1; 876 int err = -1;
@@ -531,19 +881,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 881 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 882 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 883 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 884 int nr = 0;
535 885
536 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 886 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 887 if (elf == NULL) {
538 if (v) 888 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; 889 goto out_close;
542 } 890 }
543 891
544 if (gelf_getehdr(elf, &ehdr) == NULL) { 892 if (gelf_getehdr(elf, &ehdr) == NULL) {
545 if (v) 893 pr_err("%s: cannot get elf header.\n", __func__);
546 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
547 goto out_elf_end; 894 goto out_elf_end;
548 } 895 }
549 896
@@ -587,13 +934,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
587 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 935 struct symbol *f;
589 const char *elf_name; 936 const char *elf_name;
590 char *demangled; 937 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 938 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 939 const char *section_name;
595 940
596 if (!is_label && !elf_sym__is_function(&sym)) 941 if (!is_label && !elf_sym__is_a(&sym, map->type))
597 continue; 942 continue;
598 943
599 sec = elf_getscn(elf, sym.st_shndx); 944 sec = elf_getscn(elf, sym.st_shndx);
@@ -602,55 +947,88 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
602 947
603 gelf_getshdr(sec, &shdr); 948 gelf_getshdr(sec, &shdr);
604 949
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
606 continue; 951 continue;
607 952
953 elf_name = elf_sym__name(&sym, symstrs);
608 section_name = elf_sec__name(&shdr, secstrs); 954 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 955
611 if (self->adjust_symbols) { 956 if (kernel || kmodule) {
612 if (v >= 2) 957 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 958
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 959 if (strcmp(section_name,
617 } 960 curr_dso->short_name + dso_name_len) == 0)
961 goto new_symbol;
618 962
619 if (mod) { 963 if (strcmp(section_name, ".text") == 0) {
620 section = mod->sections->find_section(mod->sections, section_name); 964 curr_map = map;
621 if (section) 965 curr_dso = self;
622 sym.st_value += section->vma; 966 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 } 967 }
968
969 snprintf(dso_name, sizeof(dso_name),
970 "%s%s", self->short_name, section_name);
971
972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
973 if (curr_map == NULL) {
974 u64 start = sym.st_value;
975
976 if (kmodule)
977 start += map->start + shdr.sh_offset;
978
979 curr_dso = dso__new(dso_name);
980 if (curr_dso == NULL)
981 goto out_elf_end;
982 curr_map = map__new2(start, curr_dso,
983 MAP__FUNCTION);
984 if (curr_map == NULL) {
985 dso__delete(curr_dso);
986 goto out_elf_end;
987 }
988 curr_map->map_ip = identity__map_ip;
989 curr_map->unmap_ip = identity__map_ip;
990 curr_dso->origin = DSO__ORIG_KERNEL;
991 map_groups__insert(&session->kmaps, curr_map);
992 dsos__add(&dsos__kernel, curr_dso);
993 } else
994 curr_dso = curr_map->dso;
995
996 goto new_symbol;
997 }
998
999 if (curr_dso->adjust_symbols) {
1000 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
1001 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
1002 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
1003 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
628 } 1004 }
629 /* 1005 /*
630 * We need to figure out if the object was created from C++ sources 1006 * 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 1007 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 1008 * to it...
633 */ 1009 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 1010 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 1011 if (demangled != NULL)
637 elf_name = demangled; 1012 elf_name = demangled;
638 1013new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 1014 f = symbol__new(sym.st_value, sym.st_size, elf_name);
640 self->sym_priv_size, obj_start, v);
641 free(demangled); 1015 free(demangled);
642 if (!f) 1016 if (!f)
643 goto out_elf_end; 1017 goto out_elf_end;
644 1018
645 if (filter && filter(self, f)) 1019 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 1020 symbol__delete(f);
647 else { 1021 else {
648 f->module = mod; 1022 symbols__insert(&curr_dso->symbols[curr_map->type], f);
649 dso__insert_symbol(self, f);
650 nr++; 1023 nr++;
651 } 1024 }
652 } 1025 }
653 1026
1027 /*
1028 * For misannotated, zeroed, ASM function sizes.
1029 */
1030 if (nr > 0)
1031 symbols__fixup_end(&self->symbols[map->type]);
654 err = nr; 1032 err = nr;
655out_elf_end: 1033out_elf_end:
656 elf_end(elf); 1034 elf_end(elf);
@@ -658,63 +1036,154 @@ out_close:
658 return err; 1036 return err;
659} 1037}
660 1038
661#define BUILD_ID_SIZE 128 1039static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1040{
1041 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1042}
662 1043
663static char *dso__read_build_id(struct dso *self, int v) 1044static bool __dsos__read_build_ids(struct list_head *head)
664{ 1045{
665 int i; 1046 bool have_build_id = false;
1047 struct dso *pos;
1048
1049 list_for_each_entry(pos, head, node)
1050 if (filename__read_build_id(pos->long_name, pos->build_id,
1051 sizeof(pos->build_id)) > 0) {
1052 have_build_id = true;
1053 pos->has_build_id = true;
1054 }
1055
1056 return have_build_id;
1057}
1058
1059bool dsos__read_build_ids(void)
1060{
1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
1062 ubuildids = __dsos__read_build_ids(&dsos__user);
1063 return kbuildids || ubuildids;
1064}
1065
1066/*
1067 * Align offset to 4 bytes as needed for note name and descriptor data.
1068 */
1069#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1070
1071int filename__read_build_id(const char *filename, void *bf, size_t size)
1072{
1073 int fd, err = -1;
666 GElf_Ehdr ehdr; 1074 GElf_Ehdr ehdr;
667 GElf_Shdr shdr; 1075 GElf_Shdr shdr;
668 Elf_Data *build_id_data; 1076 Elf_Data *data;
669 Elf_Scn *sec; 1077 Elf_Scn *sec;
670 char *build_id = NULL, *bid; 1078 Elf_Kind ek;
671 unsigned char *raw; 1079 void *ptr;
672 Elf *elf; 1080 Elf *elf;
673 int fd = open(self->name, O_RDONLY);
674 1081
1082 if (size < BUILD_ID_SIZE)
1083 goto out;
1084
1085 fd = open(filename, O_RDONLY);
675 if (fd < 0) 1086 if (fd < 0)
676 goto out; 1087 goto out;
677 1088
678 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1089 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
679 if (elf == NULL) { 1090 if (elf == NULL) {
680 if (v) 1091 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; 1092 goto out_close;
684 } 1093 }
685 1094
1095 ek = elf_kind(elf);
1096 if (ek != ELF_K_ELF)
1097 goto out_elf_end;
1098
686 if (gelf_getehdr(elf, &ehdr) == NULL) { 1099 if (gelf_getehdr(elf, &ehdr) == NULL) {
687 if (v) 1100 pr_err("%s: cannot get elf header.\n", __func__);
688 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
689 goto out_elf_end; 1101 goto out_elf_end;
690 } 1102 }
691 1103
692 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 1104 sec = elf_section_by_name(elf, &ehdr, &shdr,
693 if (sec == NULL) 1105 ".note.gnu.build-id", NULL);
694 goto out_elf_end; 1106 if (sec == NULL) {
1107 sec = elf_section_by_name(elf, &ehdr, &shdr,
1108 ".notes", NULL);
1109 if (sec == NULL)
1110 goto out_elf_end;
1111 }
695 1112
696 build_id_data = elf_getdata(sec, NULL); 1113 data = elf_getdata(sec, NULL);
697 if (build_id_data == NULL) 1114 if (data == NULL)
698 goto out_elf_end;
699 build_id = malloc(BUILD_ID_SIZE);
700 if (build_id == NULL)
701 goto out_elf_end; 1115 goto out_elf_end;
702 raw = build_id_data->d_buf + 16;
703 bid = build_id;
704 1116
705 for (i = 0; i < 20; ++i) { 1117 ptr = data->d_buf;
706 sprintf(bid, "%02x", *raw); 1118 while (ptr < (data->d_buf + data->d_size)) {
707 ++raw; 1119 GElf_Nhdr *nhdr = ptr;
708 bid += 2; 1120 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1121 descsz = NOTE_ALIGN(nhdr->n_descsz);
1122 const char *name;
1123
1124 ptr += sizeof(*nhdr);
1125 name = ptr;
1126 ptr += namesz;
1127 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1128 nhdr->n_namesz == sizeof("GNU")) {
1129 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1130 memcpy(bf, ptr, BUILD_ID_SIZE);
1131 err = BUILD_ID_SIZE;
1132 break;
1133 }
1134 }
1135 ptr += descsz;
709 } 1136 }
710 if (v >= 2)
711 printf("%s(%s): %s\n", __func__, self->name, build_id);
712out_elf_end: 1137out_elf_end:
713 elf_end(elf); 1138 elf_end(elf);
714out_close: 1139out_close:
715 close(fd); 1140 close(fd);
716out: 1141out:
717 return build_id; 1142 return err;
1143}
1144
1145int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1146{
1147 int fd, err = -1;
1148
1149 if (size < BUILD_ID_SIZE)
1150 goto out;
1151
1152 fd = open(filename, O_RDONLY);
1153 if (fd < 0)
1154 goto out;
1155
1156 while (1) {
1157 char bf[BUFSIZ];
1158 GElf_Nhdr nhdr;
1159 int namesz, descsz;
1160
1161 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1162 break;
1163
1164 namesz = NOTE_ALIGN(nhdr.n_namesz);
1165 descsz = NOTE_ALIGN(nhdr.n_descsz);
1166 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1167 nhdr.n_namesz == sizeof("GNU")) {
1168 if (read(fd, bf, namesz) != namesz)
1169 break;
1170 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1171 if (read(fd, build_id,
1172 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1173 err = 0;
1174 break;
1175 }
1176 } else if (read(fd, bf, descsz) != descsz)
1177 break;
1178 } else {
1179 int n = namesz + descsz;
1180 if (read(fd, bf, n) != n)
1181 break;
1182 }
1183 }
1184 close(fd);
1185out:
1186 return err;
718} 1187}
719 1188
720char dso__symtab_origin(const struct dso *self) 1189char dso__symtab_origin(const struct dso *self)
@@ -726,6 +1195,7 @@ char dso__symtab_origin(const struct dso *self)
726 [DSO__ORIG_UBUNTU] = 'u', 1195 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 1196 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 1197 [DSO__ORIG_DSO] = 'd',
1198 [DSO__ORIG_KMODULE] = 'K',
729 }; 1199 };
730 1200
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1201 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,20 +1203,28 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 1203 return origin[self->origin];
734} 1204}
735 1205
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 1206int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1207 symbol_filter_t filter)
737{ 1208{
738 int size = PATH_MAX; 1209 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 1210 char *name;
1211 u8 build_id[BUILD_ID_SIZE];
740 int ret = -1; 1212 int ret = -1;
741 int fd; 1213 int fd;
742 1214
1215 dso__set_loaded(self, map->type);
1216
1217 if (self->kernel)
1218 return dso__load_kernel_sym(self, map, session, filter);
1219
1220 name = malloc(size);
743 if (!name) 1221 if (!name)
744 return -1; 1222 return -1;
745 1223
746 self->adjust_symbols = 0; 1224 self->adjust_symbols = 0;
747 1225
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1226 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 1227 ret = dso__load_perf_map(self, map, filter);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1228 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 1229 DSO__ORIG_NOT_FOUND;
752 return ret; 1230 return ret;
@@ -759,34 +1237,50 @@ more:
759 self->origin++; 1237 self->origin++;
760 switch (self->origin) { 1238 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 1239 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 1240 snprintf(name, size, "/usr/lib/debug%s.debug",
1241 self->long_name);
763 break; 1242 break;
764 case DSO__ORIG_UBUNTU: 1243 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 1244 snprintf(name, size, "/usr/lib/debug%s",
1245 self->long_name);
766 break; 1246 break;
767 case DSO__ORIG_BUILDID: 1247 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 1248 if (filename__read_build_id(self->long_name, build_id,
769 if (build_id != NULL) { 1249 sizeof(build_id))) {
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1251
1252 build_id__sprintf(build_id, sizeof(build_id),
1253 build_id_hex);
770 snprintf(name, size, 1254 snprintf(name, size,
771 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1255 "/usr/lib/debug/.build-id/%.2s/%s.debug",
772 build_id, build_id + 2); 1256 build_id_hex, build_id_hex + 2);
773 free(build_id); 1257 if (self->has_build_id)
1258 goto compare_build_id;
774 break; 1259 break;
775 } 1260 }
776 self->origin++; 1261 self->origin++;
777 /* Fall thru */ 1262 /* Fall thru */
778 case DSO__ORIG_DSO: 1263 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 1264 snprintf(name, size, "%s", self->long_name);
780 break; 1265 break;
781 1266
782 default: 1267 default:
783 goto out; 1268 goto out;
784 } 1269 }
785 1270
1271 if (self->has_build_id) {
1272 if (filename__read_build_id(name, build_id,
1273 sizeof(build_id)) < 0)
1274 goto more;
1275compare_build_id:
1276 if (!dso__build_id_equal(self, build_id))
1277 goto more;
1278 }
1279
786 fd = open(name, O_RDONLY); 1280 fd = open(name, O_RDONLY);
787 } while (fd < 0); 1281 } while (fd < 0);
788 1282
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 1283 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
790 close(fd); 1284 close(fd);
791 1285
792 /* 1286 /*
@@ -796,7 +1290,7 @@ more:
796 goto more; 1290 goto more;
797 1291
798 if (ret > 0) { 1292 if (ret > 0) {
799 int nr_plt = dso__synthesize_plt_symbols(self, v); 1293 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
800 if (nr_plt > 0) 1294 if (nr_plt > 0)
801 ret += nr_plt; 1295 ret += nr_plt;
802 } 1296 }
@@ -807,151 +1301,281 @@ out:
807 return ret; 1301 return ret;
808} 1302}
809 1303
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 1304struct map *map_groups__find_by_name(struct map_groups *self,
811 symbol_filter_t filter, int v) 1305 enum map_type type, const char *name)
812{ 1306{
813 struct module *mod = mod_dso__find_module(mods, name); 1307 struct rb_node *nd;
814 int err = 0, fd;
815 1308
816 if (mod == NULL || !mod->active) 1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
817 return err; 1310 struct map *map = rb_entry(nd, struct map, rb_node);
818 1311
819 fd = open(mod->path, O_RDONLY); 1312 if (map->dso && strcmp(map->dso->name, name) == 0)
1313 return map;
1314 }
820 1315
821 if (fd < 0) 1316 return NULL;
822 return err; 1317}
823 1318
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
825 close(fd); 1320{
1321 struct dirent *dent;
1322 DIR *dir = opendir(dirname);
826 1323
827 return err; 1324 if (!dir) {
1325 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1326 return -1;
1327 }
1328
1329 while ((dent = readdir(dir)) != NULL) {
1330 char path[PATH_MAX];
1331
1332 if (dent->d_type == DT_DIR) {
1333 if (!strcmp(dent->d_name, ".") ||
1334 !strcmp(dent->d_name, ".."))
1335 continue;
1336
1337 snprintf(path, sizeof(path), "%s/%s",
1338 dirname, dent->d_name);
1339 if (perf_session__set_modules_path_dir(self, path) < 0)
1340 goto failure;
1341 } else {
1342 char *dot = strrchr(dent->d_name, '.'),
1343 dso_name[PATH_MAX];
1344 struct map *map;
1345 char *long_name;
1346
1347 if (dot == NULL || strcmp(dot, ".ko"))
1348 continue;
1349 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1350 (int)(dot - dent->d_name), dent->d_name);
1351
1352 strxfrchar(dso_name, '-', '_');
1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1354 if (map == NULL)
1355 continue;
1356
1357 snprintf(path, sizeof(path), "%s/%s",
1358 dirname, dent->d_name);
1359
1360 long_name = strdup(path);
1361 if (long_name == NULL)
1362 goto failure;
1363 dso__set_long_name(map->dso, long_name);
1364 }
1365 }
1366
1367 return 0;
1368failure:
1369 closedir(dir);
1370 return -1;
828} 1371}
829 1372
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1373static int perf_session__set_modules_path(struct perf_session *self)
831{ 1374{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1375 struct utsname uts;
833 struct module *pos; 1376 char modules_path[PATH_MAX];
834 struct rb_node *next;
835 int err, count = 0;
836 1377
837 err = mod_dso__load_modules(mods); 1378 if (uname(&uts) < 0)
1379 return -1;
838 1380
839 if (err <= 0) 1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
840 return err; 1382 uts.release);
841 1383
842 /* 1384 return perf_session__set_modules_path_dir(self, modules_path);
843 * Iterate over modules, and load active symbols. 1385}
844 */
845 next = rb_first(&mods->mods);
846 while (next) {
847 pos = rb_entry(next, struct module, rb_node);
848 err = dso__load_module(self, mods, pos->name, filter, v);
849
850 if (err < 0)
851 break;
852 1386
853 next = rb_next(&pos->rb_node); 1387/*
854 count += err; 1388 * Constructor variant for modules (where we know from /proc/modules where
855 } 1389 * they are loaded) and for vmlinux, where only after we load all the
1390 * symbols we'll know where it starts and ends.
1391 */
1392static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1393{
1394 struct map *self = malloc(sizeof(*self));
856 1395
857 if (err < 0) { 1396 if (self != NULL) {
858 mod_dso__delete_modules(mods); 1397 /*
859 mod_dso__delete_self(mods); 1398 * ->end will be filled after we load all the symbols
860 return err; 1399 */
1400 map__init(self, type, start, 0, 0, dso);
861 } 1401 }
862 1402
863 return count; 1403 return self;
864} 1404}
865 1405
866static inline void dso__fill_symbol_holes(struct dso *self) 1406static int perf_session__create_module_maps(struct perf_session *self)
867{ 1407{
868 struct symbol *prev = NULL; 1408 char *line = NULL;
869 struct rb_node *nd; 1409 size_t n;
1410 FILE *file = fopen("/proc/modules", "r");
1411 struct map *map;
870 1412
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1413 if (file == NULL)
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1414 return -1;
873 1415
874 if (prev) { 1416 while (!feof(file)) {
875 u64 hole = 0; 1417 char name[PATH_MAX];
876 int alias = pos->start == prev->start; 1418 u64 start;
1419 struct dso *dso;
1420 char *sep;
1421 int line_len;
877 1422
878 if (!alias) 1423 line_len = getline(&line, &n, file);
879 hole = prev->start - pos->end - 1; 1424 if (line_len < 0)
1425 break;
880 1426
881 if (hole || alias) { 1427 if (!line)
882 if (alias) 1428 goto out_failure;
883 pos->end = prev->end; 1429
884 else if (hole) 1430 line[--line_len] = '\0'; /* \n */
885 pos->end = prev->start - 1; 1431
886 } 1432 sep = strrchr(line, 'x');
1433 if (sep == NULL)
1434 continue;
1435
1436 hex2u64(sep + 1, &start);
1437
1438 sep = strchr(line, ' ');
1439 if (sep == NULL)
1440 continue;
1441
1442 *sep = '\0';
1443
1444 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name);
1446
1447 if (dso == NULL)
1448 goto out_delete_line;
1449
1450 map = map__new2(start, dso, MAP__FUNCTION);
1451 if (map == NULL) {
1452 dso__delete(dso);
1453 goto out_delete_line;
887 } 1454 }
888 prev = pos; 1455
1456 snprintf(name, sizeof(name),
1457 "/sys/module/%s/notes/.note.gnu.build-id", line);
1458 if (sysfs__read_build_id(name, dso->build_id,
1459 sizeof(dso->build_id)) == 0)
1460 dso->has_build_id = true;
1461
1462 dso->origin = DSO__ORIG_KMODULE;
1463 map_groups__insert(&self->kmaps, map);
1464 dsos__add(&dsos__kernel, dso);
889 } 1465 }
1466
1467 free(line);
1468 fclose(file);
1469
1470 return perf_session__set_modules_path(self);
1471
1472out_delete_line:
1473 free(line);
1474out_failure:
1475 return -1;
890} 1476}
891 1477
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1478static int dso__load_vmlinux(struct dso *self, struct map *map,
893 symbol_filter_t filter, int v) 1479 struct perf_session *session,
1480 const char *vmlinux, symbol_filter_t filter)
894{ 1481{
895 int err, fd = open(vmlinux, O_RDONLY); 1482 int err = -1, fd;
896 1483
897 if (fd < 0) 1484 if (self->has_build_id) {
898 return -1; 1485 u8 build_id[BUILD_ID_SIZE];
899 1486
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1487 if (filename__read_build_id(vmlinux, build_id,
1488 sizeof(build_id)) < 0) {
1489 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1490 return -1;
1491 }
1492 if (!dso__build_id_equal(self, build_id)) {
1493 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1494 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1495
1496 build_id__sprintf(self->build_id,
1497 sizeof(self->build_id),
1498 expected_build_id);
1499 build_id__sprintf(build_id, sizeof(build_id),
1500 vmlinux_build_id);
1501 pr_debug("build_id in %s is %s while expected is %s, "
1502 "ignoring it\n", vmlinux, vmlinux_build_id,
1503 expected_build_id);
1504 return -1;
1505 }
1506 }
901 1507
902 if (err > 0) 1508 fd = open(vmlinux, O_RDONLY);
903 dso__fill_symbol_holes(self); 1509 if (fd < 0)
1510 return -1;
904 1511
1512 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
905 close(fd); 1514 close(fd);
906 1515
907 return err; 1516 return err;
908} 1517}
909 1518
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1519static int dso__load_kernel_sym(struct dso *self, struct map *map,
911 symbol_filter_t filter, int v, int use_modules) 1520 struct perf_session *session, symbol_filter_t filter)
912{ 1521{
913 int err = -1; 1522 int err;
914 1523 bool is_kallsyms;
915 if (vmlinux) { 1524
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1525 if (vmlinux_path != NULL) {
917 if (err > 0 && use_modules) { 1526 int i;
918 int syms = dso__load_modules(self, filter, v); 1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
919 1528 vmlinux_path__nr_entries);
920 if (syms < 0) { 1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
921 fprintf(stderr, "dso__load_modules failed!\n"); 1530 err = dso__load_vmlinux(self, map, session,
922 return syms; 1531 vmlinux_path[i], filter);
1532 if (err > 0) {
1533 pr_debug("Using %s for symbols\n",
1534 vmlinux_path[i]);
1535 dso__set_long_name(self,
1536 strdup(vmlinux_path[i]));
1537 goto out_fixup;
923 } 1538 }
924 err += syms;
925 } 1539 }
926 } 1540 }
927 1541
928 if (err <= 0) 1542 is_kallsyms = self->long_name[0] == '[';
929 err = dso__load_kallsyms(self, filter, v); 1543 if (is_kallsyms)
1544 goto do_kallsyms;
930 1545
931 if (err > 0) 1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
932 self->origin = DSO__ORIG_KERNEL; 1547 if (err <= 0) {
1548 pr_info("The file %s cannot be used, "
1549 "trying to use /proc/kallsyms...", self->long_name);
1550do_kallsyms:
1551 err = dso__load_kallsyms(self, map, session, filter);
1552 if (err > 0 && !is_kallsyms)
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1554 }
1555
1556 if (err > 0) {
1557out_fixup:
1558 map__fixup_start(map);
1559 map__fixup_end(map);
1560 }
933 1561
934 return err; 1562 return err;
935} 1563}
936 1564
937LIST_HEAD(dsos); 1565LIST_HEAD(dsos__user);
938struct dso *kernel_dso; 1566LIST_HEAD(dsos__kernel);
939struct dso *vdso; 1567struct dso *vdso;
940struct dso *hypervisor_dso;
941 1568
942const char *vmlinux_name = "vmlinux"; 1569static void dsos__add(struct list_head *head, struct dso *dso)
943int modules;
944
945static void dsos__add(struct dso *dso)
946{ 1570{
947 list_add_tail(&dso->node, &dsos); 1571 list_add_tail(&dso->node, head);
948} 1572}
949 1573
950static struct dso *dsos__find(const char *name) 1574static struct dso *dsos__find(struct list_head *head, const char *name)
951{ 1575{
952 struct dso *pos; 1576 struct dso *pos;
953 1577
954 list_for_each_entry(pos, &dsos, node) 1578 list_for_each_entry(pos, head, node)
955 if (strcmp(pos->name, name) == 0) 1579 if (strcmp(pos->name, name) == 0)
956 return pos; 1580 return pos;
957 return NULL; 1581 return NULL;
@@ -959,79 +1583,227 @@ static struct dso *dsos__find(const char *name)
959 1583
960struct dso *dsos__findnew(const char *name) 1584struct dso *dsos__findnew(const char *name)
961{ 1585{
962 struct dso *dso = dsos__find(name); 1586 struct dso *dso = dsos__find(&dsos__user, 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 1587
972 nr = dso__load(dso, NULL, verbose); 1588 if (!dso) {
973 if (nr < 0) { 1589 dso = dso__new(name);
974 eprintf("Failed to open: %s\n", name); 1590 if (dso != NULL) {
975 goto out_delete_dso; 1591 dsos__add(&dsos__user, dso);
1592 dso__set_basename(dso);
1593 }
976 } 1594 }
977 if (!nr)
978 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979
980 dsos__add(dso);
981 1595
982 return dso; 1596 return dso;
1597}
983 1598
984out_delete_dso: 1599static void __dsos__fprintf(struct list_head *head, FILE *fp)
985 dso__delete(dso); 1600{
986 return NULL; 1601 struct dso *pos;
1602
1603 list_for_each_entry(pos, head, node) {
1604 int i;
1605 for (i = 0; i < MAP__NR_TYPES; ++i)
1606 dso__fprintf(pos, i, fp);
1607 }
987} 1608}
988 1609
989void dsos__fprintf(FILE *fp) 1610void dsos__fprintf(FILE *fp)
990{ 1611{
1612 __dsos__fprintf(&dsos__kernel, fp);
1613 __dsos__fprintf(&dsos__user, fp);
1614}
1615
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
1617{
991 struct dso *pos; 1618 struct dso *pos;
1619 size_t ret = 0;
992 1620
993 list_for_each_entry(pos, &dsos, node) 1621 list_for_each_entry(pos, head, node) {
994 dso__fprintf(pos, fp); 1622 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name);
1624 }
1625 return ret;
995} 1626}
996 1627
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 1628size_t dsos__fprintf_buildid(FILE *fp)
998{ 1629{
999 return dso__find_symbol(dso, ip); 1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1631 __dsos__fprintf_buildid(&dsos__user, fp));
1000} 1632}
1001 1633
1002int load_kernel(void) 1634static struct dso *dsos__create_kernel( const char *vmlinux)
1003{ 1635{
1004 int err; 1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1637
1638 if (kernel == NULL)
1639 return NULL;
1640
1641 kernel->short_name = "[kernel]";
1642 kernel->kernel = 1;
1643
1644 vdso = dso__new("[vdso]");
1645 if (vdso == NULL)
1646 goto out_delete_kernel_dso;
1647 dso__set_loaded(vdso, MAP__FUNCTION);
1648
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1650 sizeof(kernel->build_id)) == 0)
1651 kernel->has_build_id = true;
1652
1653 dsos__add(&dsos__kernel, kernel);
1654 dsos__add(&dsos__user, vdso);
1005 1655
1006 kernel_dso = dso__new("[kernel]", 0); 1656 return kernel;
1007 if (!kernel_dso) 1657
1658out_delete_kernel_dso:
1659 dso__delete(kernel);
1660 return NULL;
1661}
1662
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1664{
1665 struct map *functions, *variables;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667
1668 if (kernel == NULL)
1008 return -1; 1669 return -1;
1009 1670
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1671 functions = map__new2(0, kernel, MAP__FUNCTION);
1011 if (err <= 0) { 1672 if (functions == NULL)
1012 dso__delete(kernel_dso); 1673 return -1;
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016 1674
1017 vdso = dso__new("[vdso]", 0); 1675 variables = map__new2(0, kernel, MAP__VARIABLE);
1018 if (!vdso) 1676 if (variables == NULL) {
1677 map__delete(functions);
1019 return -1; 1678 return -1;
1679 }
1020 1680
1021 vdso->find_symbol = vdso__find_symbol; 1681 functions->map_ip = functions->unmap_ip =
1682 variables->map_ip = variables->unmap_ip = identity__map_ip;
1683 map_groups__insert(self, functions);
1684 map_groups__insert(self, variables);
1022 1685
1023 dsos__add(vdso); 1686 return 0;
1687}
1688
1689static void vmlinux_path__exit(void)
1690{
1691 while (--vmlinux_path__nr_entries >= 0) {
1692 free(vmlinux_path[vmlinux_path__nr_entries]);
1693 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1694 }
1024 1695
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1696 free(vmlinux_path);
1026 if (!hypervisor_dso) 1697 vmlinux_path = NULL;
1698}
1699
1700static int vmlinux_path__init(void)
1701{
1702 struct utsname uts;
1703 char bf[PATH_MAX];
1704
1705 if (uname(&uts) < 0)
1027 return -1; 1706 return -1;
1028 dsos__add(hypervisor_dso);
1029 1707
1030 return err; 1708 vmlinux_path = malloc(sizeof(char *) * 5);
1709 if (vmlinux_path == NULL)
1710 return -1;
1711
1712 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1713 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1714 goto out_fail;
1715 ++vmlinux_path__nr_entries;
1716 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1717 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1718 goto out_fail;
1719 ++vmlinux_path__nr_entries;
1720 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1721 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1722 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1723 goto out_fail;
1724 ++vmlinux_path__nr_entries;
1725 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1726 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1727 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1728 goto out_fail;
1729 ++vmlinux_path__nr_entries;
1730 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1731 uts.release);
1732 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1733 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1734 goto out_fail;
1735 ++vmlinux_path__nr_entries;
1736
1737 return 0;
1738
1739out_fail:
1740 vmlinux_path__exit();
1741 return -1;
1031} 1742}
1032 1743
1744static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name)
1746{
1747 if (list_str == NULL)
1748 return 0;
1033 1749
1034void symbol__init(void) 1750 *list = strlist__new(true, list_str);
1751 if (!*list) {
1752 pr_err("problems parsing %s list\n", list_name);
1753 return -1;
1754 }
1755 return 0;
1756}
1757
1758int symbol__init(void)
1035{ 1759{
1036 elf_version(EV_CURRENT); 1760 elf_version(EV_CURRENT);
1761 if (symbol_conf.sort_by_name)
1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1763 sizeof(struct symbol));
1764
1765 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1766 return -1;
1767
1768 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1769 pr_err("'.' is the only non valid --field-separator argument\n");
1770 return -1;
1771 }
1772
1773 if (setup_list(&symbol_conf.dso_list,
1774 symbol_conf.dso_list_str, "dso") < 0)
1775 return -1;
1776
1777 if (setup_list(&symbol_conf.comm_list,
1778 symbol_conf.comm_list_str, "comm") < 0)
1779 goto out_free_dso_list;
1780
1781 if (setup_list(&symbol_conf.sym_list,
1782 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list;
1784
1785 return 0;
1786
1787out_free_dso_list:
1788 strlist__delete(symbol_conf.dso_list);
1789out_free_comm_list:
1790 strlist__delete(symbol_conf.comm_list);
1791 return -1;
1792}
1793
1794int perf_session__create_kernel_maps(struct perf_session *self)
1795{
1796 if (map_groups__create_kernel_maps(&self->kmaps,
1797 symbol_conf.vmlinux_name) < 0)
1798 return -1;
1799
1800 if (symbol_conf.use_modules &&
1801 perf_session__create_module_maps(self) < 0)
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1804 /*
1805 * Now that we have all the maps created, just set the ->end of them:
1806 */
1807 map_groups__fixup_end(&self->kmaps);
1808 return 0;
1037} 1809}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 829da9edba64..8aded2356f79 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -1,11 +1,11 @@
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#ifdef HAVE_CPLUS_DEMANGLE 11#ifdef HAVE_CPLUS_DEMANGLE
@@ -46,57 +46,96 @@ struct symbol {
46 struct rb_node rb_node; 46 struct rb_node rb_node;
47 u64 start; 47 u64 start;
48 u64 end; 48 u64 end;
49 u64 obj_start;
50 u64 hist_sum;
51 u64 *hist;
52 struct module *module;
53 void *priv;
54 char name[0]; 49 char name[0];
55}; 50};
56 51
52struct strlist;
53
54struct symbol_conf {
55 unsigned short priv_size;
56 bool try_vmlinux_path,
57 use_modules,
58 sort_by_name,
59 show_nr_samples,
60 use_callchain,
61 exclude_other;
62 const char *vmlinux_name,
63 *field_sep;
64 char *dso_list_str,
65 *comm_list_str,
66 *sym_list_str,
67 *col_width_list_str;
68 struct strlist *dso_list,
69 *comm_list,
70 *sym_list;
71};
72
73extern struct symbol_conf symbol_conf;
74
75static inline void *symbol__priv(struct symbol *self)
76{
77 return ((void *)self) - symbol_conf.priv_size;
78}
79
80struct addr_location {
81 struct thread *thread;
82 struct map *map;
83 struct symbol *sym;
84 u64 addr;
85 char level;
86 bool filtered;
87};
88
57struct dso { 89struct dso {
58 struct list_head node; 90 struct list_head node;
59 struct rb_root syms; 91 struct rb_root symbols[MAP__NR_TYPES];
60 struct symbol *(*find_symbol)(struct dso *, u64 ip); 92 struct rb_root symbol_names[MAP__NR_TYPES];
61 unsigned int sym_priv_size; 93 u8 adjust_symbols:1;
62 unsigned char adjust_symbols; 94 u8 slen_calculated:1;
63 unsigned char slen_calculated; 95 u8 has_build_id:1;
96 u8 kernel:1;
64 unsigned char origin; 97 unsigned char origin;
98 u8 sorted_by_name;
99 u8 loaded;
100 u8 build_id[BUILD_ID_SIZE];
101 u16 long_name_len;
102 const char *short_name;
103 char *long_name;
65 char name[0]; 104 char name[0];
66}; 105};
67 106
68extern const char *sym_hist_filter; 107struct dso *dso__new(const char *name);
69
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); 108void dso__delete(struct dso *self);
74 109
75static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) 110bool dso__loaded(const struct dso *self, enum map_type type);
76{ 111bool dso__sorted_by_name(const struct dso *self, enum map_type type);
77 return ((void *)sym) - self->sym_priv_size; 112
78} 113void dso__sort_by_name(struct dso *self, enum map_type type);
79 114
80struct symbol *dso__find_symbol(struct dso *self, u64 ip); 115struct perf_session;
81 116
82int dso__load_kernel(struct dso *self, const char *vmlinux,
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); 117struct dso *dsos__findnew(const char *name);
118int dso__load(struct dso *self, struct map *map, struct perf_session *session,
119 symbol_filter_t filter);
87void dsos__fprintf(FILE *fp); 120void dsos__fprintf(FILE *fp);
121size_t dsos__fprintf_buildid(FILE *fp);
88 122
89size_t dso__fprintf(struct dso *self, FILE *fp); 123size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
90char dso__symtab_origin(const struct dso *self); 125char dso__symtab_origin(const struct dso *self);
126void dso__set_build_id(struct dso *self, void *build_id);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name);
91 130
92int load_kernel(void); 131int filename__read_build_id(const char *filename, void *bf, size_t size);
132int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void);
134int build_id__sprintf(u8 *self, int len, char *bf);
93 135
94void symbol__init(void); 136int symbol__init(void);
137int perf_session__create_kernel_maps(struct perf_session *self);
95 138
96extern struct list_head dsos; 139extern struct list_head dsos__user, dsos__kernel;
97extern struct dso *kernel_dso;
98extern struct dso *vdso; 140extern struct dso *vdso;
99extern struct dso *hypervisor_dso; 141#endif /* __PERF_SYMBOL */
100extern const char *vmlinux_name;
101extern int modules;
102#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45efb5db0d19..4a08dcf50b68 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,20 +2,30 @@
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;
@@ -29,21 +39,90 @@ int thread__set_comm(struct thread *self, const char *comm)
29 return self->comm ? 0 : -ENOMEM; 39 return self->comm ? 0 : -ENOMEM;
30} 40}
31 41
32static size_t thread__fprintf(struct thread *self, FILE *fp) 42int thread__comm_len(struct thread *self)
43{
44 if (!self->comm_len) {
45 if (!self->comm)
46 return 0;
47 self->comm_len = strlen(self->comm);
48 }
49
50 return self->comm_len;
51}
52
53static const char *map_type__name[MAP__NR_TYPES] = {
54 [MAP__FUNCTION] = "Functions",
55 [MAP__VARIABLE] = "Variables",
56};
57
58static size_t __map_groups__fprintf_maps(struct map_groups *self,
59 enum map_type type, FILE *fp)
60{
61 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
62 struct rb_node *nd;
63
64 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
65 struct map *pos = rb_entry(nd, struct map, rb_node);
66 printed += fprintf(fp, "Map:");
67 printed += map__fprintf(pos, fp);
68 if (verbose > 1) {
69 printed += dso__fprintf(pos->dso, type, fp);
70 printed += fprintf(fp, "--\n");
71 }
72 }
73
74 return printed;
75}
76
77size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
78{
79 size_t printed = 0, i;
80 for (i = 0; i < MAP__NR_TYPES; ++i)
81 printed += __map_groups__fprintf_maps(self, i, fp);
82 return printed;
83}
84
85static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
86 enum map_type type, FILE *fp)
33{ 87{
34 struct map *pos; 88 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 89 size_t printed = 0;
90
91 list_for_each_entry(pos, &self->removed_maps[type], node) {
92 printed += fprintf(fp, "Map:");
93 printed += map__fprintf(pos, fp);
94 if (verbose > 1) {
95 printed += dso__fprintf(pos->dso, type, fp);
96 printed += fprintf(fp, "--\n");
97 }
98 }
99 return printed;
100}
36 101
37 list_for_each_entry(pos, &self->maps, node) 102static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
38 ret += map__fprintf(pos, fp); 103{
104 size_t printed = 0, i;
105 for (i = 0; i < MAP__NR_TYPES; ++i)
106 printed += __map_groups__fprintf_removed_maps(self, i, fp);
107 return printed;
108}
39 109
40 return ret; 110static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
111{
112 size_t printed = map_groups__fprintf_maps(self, fp);
113 printed += fprintf(fp, "Removed maps:\n");
114 return printed + map_groups__fprintf_removed_maps(self, fp);
115}
116
117static size_t thread__fprintf(struct thread *self, FILE *fp)
118{
119 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
120 map_groups__fprintf(&self->mg, fp);
41} 121}
42 122
43struct thread * 123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{ 124{
46 struct rb_node **p = &threads->rb_node; 125 struct rb_node **p = &self->threads.rb_node;
47 struct rb_node *parent = NULL; 126 struct rb_node *parent = NULL;
48 struct thread *th; 127 struct thread *th;
49 128
@@ -52,15 +131,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 131 * so most of the time we dont have to look up
53 * the full rbtree: 132 * the full rbtree:
54 */ 133 */
55 if (*last_match && (*last_match)->pid == pid) 134 if (self->last_match && self->last_match->pid == pid)
56 return *last_match; 135 return self->last_match;
57 136
58 while (*p != NULL) { 137 while (*p != NULL) {
59 parent = *p; 138 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node); 139 th = rb_entry(parent, struct thread, rb_node);
61 140
62 if (th->pid == pid) { 141 if (th->pid == pid) {
63 *last_match = th; 142 self->last_match = th;
64 return th; 143 return th;
65 } 144 }
66 145
@@ -73,99 +152,127 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
73 th = thread__new(pid); 152 th = thread__new(pid);
74 if (th != NULL) { 153 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p); 154 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads); 155 rb_insert_color(&th->rb_node, &self->threads);
77 *last_match = th; 156 self->last_match = th;
78 } 157 }
79 158
80 return th; 159 return th;
81} 160}
82 161
83struct thread * 162static void map_groups__remove_overlappings(struct map_groups *self,
84register_idle_thread(struct rb_root *threads, struct thread **last_match) 163 struct map *map)
85{ 164{
86 struct thread *thread = threads__findnew(0, threads, last_match); 165 struct rb_root *root = &self->maps[map->type];
166 struct rb_node *next = rb_first(root);
87 167
88 if (!thread || thread__set_comm(thread, "swapper")) { 168 while (next) {
89 fprintf(stderr, "problem inserting idle task.\n"); 169 struct map *pos = rb_entry(next, struct map, rb_node);
90 exit(-1); 170 next = rb_next(&pos->rb_node);
91 } 171
172 if (!map__overlap(pos, map))
173 continue;
92 174
93 return thread; 175 if (verbose >= 2) {
176 fputs("overlapping maps:\n", stderr);
177 map__fprintf(map, stderr);
178 map__fprintf(pos, stderr);
179 }
180
181 rb_erase(&pos->rb_node, root);
182 /*
183 * We may have references to this map, for instance in some
184 * hist_entry instances, so just move them to a separate
185 * list.
186 */
187 list_add_tail(&pos->node, &self->removed_maps[map->type]);
188 }
94} 189}
95 190
96void thread__insert_map(struct thread *self, struct map *map) 191void maps__insert(struct rb_root *maps, struct map *map)
97{ 192{
98 struct map *pos, *tmp; 193 struct rb_node **p = &maps->rb_node;
99 194 struct rb_node *parent = NULL;
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 195 const u64 ip = map->start;
101 if (map__overlap(pos, map)) { 196 struct map *m;
102 if (verbose >= 2) {
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107 197
108 if (map->start <= pos->start && map->end > pos->start) 198 while (*p != NULL) {
109 pos->start = map->end; 199 parent = *p;
200 m = rb_entry(parent, struct map, rb_node);
201 if (ip < m->start)
202 p = &(*p)->rb_left;
203 else
204 p = &(*p)->rb_right;
205 }
110 206
111 if (map->end >= pos->end && map->start < pos->end) 207 rb_link_node(&map->rb_node, parent, p);
112 pos->end = map->start; 208 rb_insert_color(&map->rb_node, maps);
209}
113 210
114 if (verbose >= 2) { 211struct map *maps__find(struct rb_root *maps, u64 ip)
115 printf("after collision:\n"); 212{
116 map__fprintf(pos, stdout); 213 struct rb_node **p = &maps->rb_node;
117 } 214 struct rb_node *parent = NULL;
215 struct map *m;
118 216
119 if (pos->start >= pos->end) { 217 while (*p != NULL) {
120 list_del_init(&pos->node); 218 parent = *p;
121 free(pos); 219 m = rb_entry(parent, struct map, rb_node);
122 } 220 if (ip < m->start)
123 } 221 p = &(*p)->rb_left;
222 else if (ip > m->end)
223 p = &(*p)->rb_right;
224 else
225 return m;
124 } 226 }
125 227
126 list_add_tail(&map->node, &self->maps); 228 return NULL;
127} 229}
128 230
129int thread__fork(struct thread *self, struct thread *parent) 231void thread__insert_map(struct thread *self, struct map *map)
130{ 232{
131 struct map *map; 233 map_groups__remove_overlappings(&self->mg, map);
132 234 map_groups__insert(&self->mg, map);
133 if (self->comm) 235}
134 free(self->comm);
135 self->comm = strdup(parent->comm);
136 if (!self->comm)
137 return -ENOMEM;
138 236
139 list_for_each_entry(map, &parent->maps, node) { 237/*
238 * XXX This should not really _copy_ te maps, but refcount them.
239 */
240static int map_groups__clone(struct map_groups *self,
241 struct map_groups *parent, enum map_type type)
242{
243 struct rb_node *nd;
244 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
245 struct map *map = rb_entry(nd, struct map, rb_node);
140 struct map *new = map__clone(map); 246 struct map *new = map__clone(map);
141 if (!new) 247 if (new == NULL)
142 return -ENOMEM; 248 return -ENOMEM;
143 thread__insert_map(self, new); 249 map_groups__insert(self, new);
144 } 250 }
145
146 return 0; 251 return 0;
147} 252}
148 253
149struct map *thread__find_map(struct thread *self, u64 ip) 254int thread__fork(struct thread *self, struct thread *parent)
150{ 255{
151 struct map *pos; 256 int i;
152 257
153 if (self == NULL) 258 if (self->comm)
154 return NULL; 259 free(self->comm);
155 260 self->comm = strdup(parent->comm);
156 list_for_each_entry(pos, &self->maps, node) 261 if (!self->comm)
157 if (ip >= pos->start && ip <= pos->end) 262 return -ENOMEM;
158 return pos;
159 263
160 return NULL; 264 for (i = 0; i < MAP__NR_TYPES; ++i)
265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
266 return -ENOMEM;
267 return 0;
161} 268}
162 269
163size_t threads__fprintf(FILE *fp, struct rb_root *threads) 270size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
164{ 271{
165 size_t ret = 0; 272 size_t ret = 0;
166 struct rb_node *nd; 273 struct rb_node *nd;
167 274
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 275 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 276 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 277
171 ret += thread__fprintf(pos, fp); 278 ret += thread__fprintf(pos, fp);
@@ -173,3 +280,16 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
173 280
174 return ret; 281 return ret;
175} 282}
283
284struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
286 enum map_type type, u64 addr,
287 symbol_filter_t filter)
288{
289 struct map *map = map_groups__find(self, type, addr);
290
291 if (map != NULL)
292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
293
294 return NULL;
295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..c206f72c8881 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,22 +1,70 @@
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
6struct thread { 13struct thread {
7 struct rb_node rb_node; 14 struct rb_node rb_node;
8 struct list_head maps; 15 struct map_groups mg;
9 pid_t pid; 16 pid_t pid;
10 char shortname[3]; 17 char shortname[3];
11 char *comm; 18 char *comm;
19 int comm_len;
12}; 20};
13 21
22void map_groups__init(struct map_groups *self);
14int thread__set_comm(struct thread *self, const char *comm); 23int thread__set_comm(struct thread *self, const char *comm);
15struct thread * 24int thread__comm_len(struct thread *self);
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 25struct 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); 26void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 27int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip); 28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 29size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
30
31void maps__insert(struct rb_root *maps, struct map *map);
32struct map *maps__find(struct rb_root *maps, u64 addr);
33
34static inline void map_groups__insert(struct map_groups *self, struct map *map)
35{
36 maps__insert(&self->maps[map->type], map);
37}
38
39static inline struct map *map_groups__find(struct map_groups *self,
40 enum map_type type, u64 addr)
41{
42 return maps__find(&self->maps[type], addr);
43}
44
45static inline struct map *thread__find_map(struct thread *self,
46 enum map_type type, u64 addr)
47{
48 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49}
50
51void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr,
54 struct addr_location *al,
55 symbol_filter_t filter);
56struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
58 enum map_type type, u64 addr,
59 symbol_filter_t filter);
60
61static inline struct symbol *
62map_groups__find_function(struct map_groups *self, struct perf_session *session,
63 u64 addr, symbol_filter_t filter)
64{
65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
70#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index af4b0573b37f..cace35595530 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -33,11 +33,11 @@
33#include <ctype.h> 33#include <ctype.h>
34#include <errno.h> 34#include <errno.h>
35#include <stdbool.h> 35#include <stdbool.h>
36#include <linux/kernel.h>
36 37
37#include "../perf.h" 38#include "../perf.h"
38#include "trace-event.h" 39#include "trace-event.h"
39 40
40
41#define VERSION "0.5" 41#define VERSION "0.5"
42 42
43#define _STR(x) #x 43#define _STR(x) #x
@@ -483,27 +483,33 @@ static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
484{ 484{
485 struct tracepoint_path path, *ppath = &path; 485 struct tracepoint_path path, *ppath = &path;
486 int i; 486 int i, nr_tracepoints = 0;
487 487
488 for (i = 0; i < nb_events; i++) { 488 for (i = 0; i < nb_events; i++) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
490 continue; 490 continue;
491 ++nr_tracepoints;
491 ppath->next = tracepoint_id_to_path(pattrs[i].config); 492 ppath->next = tracepoint_id_to_path(pattrs[i].config);
492 if (!ppath->next) 493 if (!ppath->next)
493 die("%s\n", "No memory to alloc tracepoints list"); 494 die("%s\n", "No memory to alloc tracepoints list");
494 ppath = ppath->next; 495 ppath = ppath->next;
495 } 496 }
496 497
497 return path.next; 498 return nr_tracepoints > 0 ? path.next : NULL;
498} 499}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events) 500
501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
500{ 502{
501 char buf[BUFSIZ]; 503 char buf[BUFSIZ];
502 struct tracepoint_path *tps; 504 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events);
505
506 /*
507 * What? No tracepoints? No sense writing anything here, bail out.
508 */
509 if (tps == NULL)
510 return -1;
503 511
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); 512 output_fd = fd;
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507 513
508 buf[0] = 23; 514 buf[0] = 23;
509 buf[1] = 8; 515 buf[1] = 8;
@@ -530,11 +536,11 @@ void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
530 page_size = getpagesize(); 536 page_size = getpagesize();
531 write_or_die(&page_size, 4); 537 write_or_die(&page_size, 4);
532 538
533 tps = get_tracepoints_path(pattrs, nb_events);
534
535 read_header_files(); 539 read_header_files();
536 read_ftrace_files(tps); 540 read_ftrace_files(tps);
537 read_event_files(tps); 541 read_event_files(tps);
538 read_proc_kallsyms(); 542 read_proc_kallsyms();
539 read_ftrace_printk(); 543 read_ftrace_printk();
544
545 return 0;
540} 546}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 55c9659a56e2..c5c32be040bf 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:
@@ -1822,37 +1951,67 @@ static int get_common_info(const char *type, int *offset, int *size)
1822 return 0; 1951 return 0;
1823} 1952}
1824 1953
1825int trace_parse_common_type(void *data) 1954static int __parse_common(void *data, int *size, int *offset,
1955 const char *name)
1826{ 1956{
1827 static int type_offset;
1828 static int type_size;
1829 int ret; 1957 int ret;
1830 1958
1831 if (!type_size) { 1959 if (!*size) {
1832 ret = get_common_info("common_type", 1960 ret = get_common_info(name, offset, size);
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0) 1961 if (ret < 0)
1836 return ret; 1962 return ret;
1837 } 1963 }
1838 return read_size(data + type_offset, type_size); 1964 return read_size(data + *offset, *size);
1965}
1966
1967int trace_parse_common_type(void *data)
1968{
1969 static int type_offset;
1970 static int type_size;
1971
1972 return __parse_common(data, &type_size, &type_offset,
1973 "common_type");
1839} 1974}
1840 1975
1841static int parse_common_pid(void *data) 1976int trace_parse_common_pid(void *data)
1842{ 1977{
1843 static int pid_offset; 1978 static int pid_offset;
1844 static int pid_size; 1979 static int pid_size;
1980
1981 return __parse_common(data, &pid_size, &pid_offset,
1982 "common_pid");
1983}
1984
1985int parse_common_pc(void *data)
1986{
1987 static int pc_offset;
1988 static int pc_size;
1989
1990 return __parse_common(data, &pc_size, &pc_offset,
1991 "common_preempt_count");
1992}
1993
1994int parse_common_flags(void *data)
1995{
1996 static int flags_offset;
1997 static int flags_size;
1998
1999 return __parse_common(data, &flags_size, &flags_offset,
2000 "common_flags");
2001}
2002
2003int parse_common_lock_depth(void *data)
2004{
2005 static int ld_offset;
2006 static int ld_size;
1845 int ret; 2007 int ret;
1846 2008
1847 if (!pid_size) { 2009 ret = __parse_common(data, &ld_size, &ld_offset,
1848 ret = get_common_info("common_pid", 2010 "common_lock_depth");
1849 &pid_offset, 2011 if (ret < 0)
1850 &pid_size); 2012 return -1;
1851 if (ret < 0)
1852 return ret;
1853 }
1854 2013
1855 return read_size(data + pid_offset, pid_size); 2014 return ret;
1856} 2015}
1857 2016
1858struct event *trace_find_event(int id) 2017struct event *trace_find_event(int id)
@@ -1866,11 +2025,20 @@ struct event *trace_find_event(int id)
1866 return event; 2025 return event;
1867} 2026}
1868 2027
2028struct event *trace_find_next_event(struct event *event)
2029{
2030 if (!event)
2031 return event_list;
2032
2033 return event->next;
2034}
2035
1869static unsigned long long eval_num_arg(void *data, int size, 2036static unsigned long long eval_num_arg(void *data, int size,
1870 struct event *event, struct print_arg *arg) 2037 struct event *event, struct print_arg *arg)
1871{ 2038{
1872 unsigned long long val = 0; 2039 unsigned long long val = 0;
1873 unsigned long long left, right; 2040 unsigned long long left, right;
2041 struct print_arg *larg;
1874 2042
1875 switch (arg->type) { 2043 switch (arg->type) {
1876 case PRINT_NULL: 2044 case PRINT_NULL:
@@ -1897,6 +2065,26 @@ static unsigned long long eval_num_arg(void *data, int size,
1897 return 0; 2065 return 0;
1898 break; 2066 break;
1899 case PRINT_OP: 2067 case PRINT_OP:
2068 if (strcmp(arg->op.op, "[") == 0) {
2069 /*
2070 * Arrays are special, since we don't want
2071 * to read the arg as is.
2072 */
2073 if (arg->op.left->type != PRINT_FIELD)
2074 goto default_op; /* oops, all bets off */
2075 larg = arg->op.left;
2076 if (!larg->field.field) {
2077 larg->field.field =
2078 find_any_field(event, larg->field.name);
2079 if (!larg->field.field)
2080 die("field %s not found", larg->field.name);
2081 }
2082 right = eval_num_arg(data, size, event, arg->op.right);
2083 val = read_size(data + larg->field.field->offset +
2084 right * long_size, long_size);
2085 break;
2086 }
2087 default_op:
1900 left = eval_num_arg(data, size, event, arg->op.left); 2088 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right); 2089 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) { 2090 switch (arg->op.op[0]) {
@@ -1947,6 +2135,12 @@ static unsigned long long eval_num_arg(void *data, int size,
1947 die("unknown op '%s'", arg->op.op); 2135 die("unknown op '%s'", arg->op.op);
1948 val = left == right; 2136 val = left == right;
1949 break; 2137 break;
2138 case '-':
2139 val = left - right;
2140 break;
2141 case '+':
2142 val = left + right;
2143 break;
1950 default: 2144 default:
1951 die("unknown op '%s'", arg->op.op); 2145 die("unknown op '%s'", arg->op.op);
1952 } 2146 }
@@ -1978,7 +2172,7 @@ static const struct flag flags[] = {
1978 { "HRTIMER_RESTART", 1 }, 2172 { "HRTIMER_RESTART", 1 },
1979}; 2173};
1980 2174
1981static unsigned long long eval_flag(const char *flag) 2175unsigned long long eval_flag(const char *flag)
1982{ 2176{
1983 int i; 2177 int i;
1984 2178
@@ -2145,8 +2339,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
2145 case 'u': 2339 case 'u':
2146 case 'x': 2340 case 'x':
2147 case 'i': 2341 case 'i':
2148 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & 2342 /* the pointers are always 4 bytes aligned */
2149 ~(long_size - 1)); 2343 bptr = (void *)(((unsigned long)bptr + 3) &
2344 ~3);
2150 switch (ls) { 2345 switch (ls) {
2151 case 0: 2346 case 0:
2152 case 1: 2347 case 1:
@@ -2270,7 +2465,27 @@ static void pretty_print(void *data, int size, struct event *event)
2270 2465
2271 for (; *ptr; ptr++) { 2466 for (; *ptr; ptr++) {
2272 ls = 0; 2467 ls = 0;
2273 if (*ptr == '%') { 2468 if (*ptr == '\\') {
2469 ptr++;
2470 switch (*ptr) {
2471 case 'n':
2472 printf("\n");
2473 break;
2474 case 't':
2475 printf("\t");
2476 break;
2477 case 'r':
2478 printf("\r");
2479 break;
2480 case '\\':
2481 printf("\\");
2482 break;
2483 default:
2484 printf("%c", *ptr);
2485 break;
2486 }
2487
2488 } else if (*ptr == '%') {
2274 saveptr = ptr; 2489 saveptr = ptr;
2275 show_func = 0; 2490 show_func = 0;
2276 cont_process: 2491 cont_process:
@@ -2377,6 +2592,41 @@ static inline int log10_cpu(int nb)
2377 return 1; 2592 return 1;
2378} 2593}
2379 2594
2595static void print_lat_fmt(void *data, int size __unused)
2596{
2597 unsigned int lat_flags;
2598 unsigned int pc;
2599 int lock_depth;
2600 int hardirq;
2601 int softirq;
2602
2603 lat_flags = parse_common_flags(data);
2604 pc = parse_common_pc(data);
2605 lock_depth = parse_common_lock_depth(data);
2606
2607 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2608 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2609
2610 printf("%c%c%c",
2611 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2612 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2613 'X' : '.',
2614 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2615 'N' : '.',
2616 (hardirq && softirq) ? 'H' :
2617 hardirq ? 'h' : softirq ? 's' : '.');
2618
2619 if (pc)
2620 printf("%x", pc);
2621 else
2622 printf(".");
2623
2624 if (lock_depth < 0)
2625 printf(".");
2626 else
2627 printf("%d", lock_depth);
2628}
2629
2380/* taken from Linux, written by Frederic Weisbecker */ 2630/* taken from Linux, written by Frederic Weisbecker */
2381static void print_graph_cpu(int cpu) 2631static void print_graph_cpu(int cpu)
2382{ 2632{
@@ -2452,7 +2702,7 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2452 if (!(event->flags & EVENT_FL_ISFUNCRET)) 2702 if (!(event->flags & EVENT_FL_ISFUNCRET))
2453 return NULL; 2703 return NULL;
2454 2704
2455 pid = parse_common_pid(next->data); 2705 pid = trace_parse_common_pid(next->data);
2456 field = find_field(event, "func"); 2706 field = find_field(event, "func");
2457 if (!field) 2707 if (!field)
2458 die("function return does not have field func"); 2708 die("function return does not have field func");
@@ -2620,6 +2870,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
2620 2870
2621 printf(" | "); 2871 printf(" | ");
2622 2872
2873 if (latency_format) {
2874 print_lat_fmt(data, size);
2875 printf(" | ");
2876 }
2877
2623 field = find_field(event, "func"); 2878 field = find_field(event, "func");
2624 if (!field) 2879 if (!field)
2625 die("function entry does not have func field"); 2880 die("function entry does not have func field");
@@ -2663,6 +2918,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2663 2918
2664 printf(" | "); 2919 printf(" | ");
2665 2920
2921 if (latency_format) {
2922 print_lat_fmt(data, size);
2923 printf(" | ");
2924 }
2925
2666 field = find_field(event, "rettime"); 2926 field = find_field(event, "rettime");
2667 if (!field) 2927 if (!field)
2668 die("can't find rettime in return graph"); 2928 die("can't find rettime in return graph");
@@ -2724,19 +2984,30 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2724 2984
2725 event = trace_find_event(type); 2985 event = trace_find_event(type);
2726 if (!event) { 2986 if (!event) {
2727 printf("ug! no event found for type %d\n", type); 2987 warning("ug! no event found for type %d", type);
2728 return; 2988 return;
2729 } 2989 }
2730 2990
2731 pid = parse_common_pid(data); 2991 pid = trace_parse_common_pid(data);
2732 2992
2733 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) 2993 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2734 return pretty_print_func_graph(data, size, event, cpu, 2994 return pretty_print_func_graph(data, size, event, cpu,
2735 pid, comm, secs, usecs); 2995 pid, comm, secs, usecs);
2736 2996
2737 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ", 2997 if (latency_format) {
2738 comm, pid, cpu, 2998 printf("%8.8s-%-5d %3d",
2739 secs, nsecs, event->name); 2999 comm, pid, cpu);
3000 print_lat_fmt(data, size);
3001 } else
3002 printf("%16s-%-5d [%03d]", comm, pid, cpu);
3003
3004 printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
3005
3006 if (event->flags & EVENT_FL_FAILED) {
3007 printf("EVENT '%s' FAILED TO PARSE\n",
3008 event->name);
3009 return;
3010 }
2740 3011
2741 pretty_print(data, size, event); 3012 pretty_print(data, size, event);
2742 printf("\n"); 3013 printf("\n");
@@ -2807,46 +3078,71 @@ static void print_args(struct print_arg *args)
2807 } 3078 }
2808} 3079}
2809 3080
2810static void parse_header_field(char *type, 3081static void parse_header_field(const char *field,
2811 int *offset, int *size) 3082 int *offset, int *size)
2812{ 3083{
2813 char *token; 3084 char *token;
3085 int type;
2814 3086
2815 if (read_expected(EVENT_ITEM, (char *)"field") < 0) 3087 if (read_expected(EVENT_ITEM, "field") < 0)
2816 return; 3088 return;
2817 if (read_expected(EVENT_OP, (char *)":") < 0) 3089 if (read_expected(EVENT_OP, ":") < 0)
2818 return; 3090 return;
3091
2819 /* type */ 3092 /* type */
2820 if (read_expect_type(EVENT_ITEM, &token) < 0) 3093 if (read_expect_type(EVENT_ITEM, &token) < 0)
2821 return; 3094 goto fail;
2822 free_token(token); 3095 free_token(token);
2823 3096
2824 if (read_expected(EVENT_ITEM, type) < 0) 3097 if (read_expected(EVENT_ITEM, field) < 0)
2825 return; 3098 return;
2826 if (read_expected(EVENT_OP, (char *)";") < 0) 3099 if (read_expected(EVENT_OP, ";") < 0)
2827 return; 3100 return;
2828 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 3101 if (read_expected(EVENT_ITEM, "offset") < 0)
2829 return; 3102 return;
2830 if (read_expected(EVENT_OP, (char *)":") < 0) 3103 if (read_expected(EVENT_OP, ":") < 0)
2831 return; 3104 return;
2832 if (read_expect_type(EVENT_ITEM, &token) < 0) 3105 if (read_expect_type(EVENT_ITEM, &token) < 0)
2833 return; 3106 goto fail;
2834 *offset = atoi(token); 3107 *offset = atoi(token);
2835 free_token(token); 3108 free_token(token);
2836 if (read_expected(EVENT_OP, (char *)";") < 0) 3109 if (read_expected(EVENT_OP, ";") < 0)
2837 return; 3110 return;
2838 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 3111 if (read_expected(EVENT_ITEM, "size") < 0)
2839 return; 3112 return;
2840 if (read_expected(EVENT_OP, (char *)":") < 0) 3113 if (read_expected(EVENT_OP, ":") < 0)
2841 return; 3114 return;
2842 if (read_expect_type(EVENT_ITEM, &token) < 0) 3115 if (read_expect_type(EVENT_ITEM, &token) < 0)
2843 return; 3116 goto fail;
2844 *size = atoi(token); 3117 *size = atoi(token);
2845 free_token(token); 3118 free_token(token);
2846 if (read_expected(EVENT_OP, (char *)";") < 0) 3119 if (read_expected(EVENT_OP, ";") < 0)
2847 return;
2848 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2849 return; 3120 return;
3121 type = read_token(&token);
3122 if (type != EVENT_NEWLINE) {
3123 /* newer versions of the kernel have a "signed" type */
3124 if (type != EVENT_ITEM)
3125 goto fail;
3126
3127 if (strcmp(token, "signed") != 0)
3128 goto fail;
3129
3130 free_token(token);
3131
3132 if (read_expected(EVENT_OP, ":") < 0)
3133 return;
3134
3135 if (read_expect_type(EVENT_ITEM, &token))
3136 goto fail;
3137
3138 free_token(token);
3139 if (read_expected(EVENT_OP, ";") < 0)
3140 return;
3141
3142 if (read_expect_type(EVENT_NEWLINE, &token))
3143 goto fail;
3144 }
3145 fail:
2850 free_token(token); 3146 free_token(token);
2851} 3147}
2852 3148
@@ -2854,11 +3150,11 @@ int parse_header_page(char *buf, unsigned long size)
2854{ 3150{
2855 init_input_buf(buf, size); 3151 init_input_buf(buf, size);
2856 3152
2857 parse_header_field((char *)"timestamp", &header_page_ts_offset, 3153 parse_header_field("timestamp", &header_page_ts_offset,
2858 &header_page_ts_size); 3154 &header_page_ts_size);
2859 parse_header_field((char *)"commit", &header_page_size_offset, 3155 parse_header_field("commit", &header_page_size_offset,
2860 &header_page_size_size); 3156 &header_page_size_size);
2861 parse_header_field((char *)"data", &header_page_data_offset, 3157 parse_header_field("data", &header_page_data_offset,
2862 &header_page_data_size); 3158 &header_page_data_size);
2863 3159
2864 return 0; 3160 return 0;
@@ -2909,6 +3205,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
2909 if (ret < 0) 3205 if (ret < 0)
2910 die("failed to read ftrace event print fmt"); 3206 die("failed to read ftrace event print fmt");
2911 3207
3208 /* New ftrace handles args */
3209 if (ret > 0)
3210 return 0;
2912 /* 3211 /*
2913 * The arguments for ftrace files are parsed by the fields. 3212 * The arguments for ftrace files are parsed by the fields.
2914 * Set up the fields as their arguments. 3213 * Set up the fields as their arguments.
@@ -2926,7 +3225,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
2926 return 0; 3225 return 0;
2927} 3226}
2928 3227
2929int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) 3228int parse_event_file(char *buf, unsigned long size, char *sys)
2930{ 3229{
2931 struct event *event; 3230 struct event *event;
2932 int ret; 3231 int ret;
@@ -2946,12 +3245,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2946 die("failed to read event id"); 3245 die("failed to read event id");
2947 3246
2948 ret = event_read_format(event); 3247 ret = event_read_format(event);
2949 if (ret < 0) 3248 if (ret < 0) {
2950 die("failed to read event format"); 3249 warning("failed to read event format for %s", event->name);
3250 goto event_failed;
3251 }
2951 3252
2952 ret = event_read_print(event); 3253 ret = event_read_print(event);
2953 if (ret < 0) 3254 if (ret < 0) {
2954 die("failed to read event print fmt"); 3255 warning("failed to read event print fmt for %s", event->name);
3256 goto event_failed;
3257 }
3258
3259 event->system = strdup(sys);
2955 3260
2956#define PRINT_ARGS 0 3261#define PRINT_ARGS 0
2957 if (PRINT_ARGS && event->print_fmt.args) 3262 if (PRINT_ARGS && event->print_fmt.args)
@@ -2959,6 +3264,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2959 3264
2960 add_event(event); 3265 add_event(event);
2961 return 0; 3266 return 0;
3267
3268 event_failed:
3269 event->flags |= EVENT_FL_FAILED;
3270 /* still add it even if it failed */
3271 add_event(event);
3272 return -1;
2962} 3273}
2963 3274
2964void parse_set_info(int nr_cpus, int long_sz) 3275void parse_set_info(int nr_cpus, int long_sz)
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
new file mode 100644
index 000000000000..6d6d76b8a21e
--- /dev/null
+++ b/tools/perf/util/trace-event-perl.c
@@ -0,0 +1,661 @@
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#include "trace-event-perl.h"
32
33void xs_init(pTHX);
34
35void xs_init(pTHX)
36{
37 const char *file = __FILE__;
38 dXSUB_SYS;
39
40 newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
41 file);
42 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
43}
44
45INTERP my_perl;
46
47#define FTRACE_MAX_EVENT \
48 ((1 << (sizeof(unsigned short) * 8)) - 1)
49
50struct event *events[FTRACE_MAX_EVENT];
51
52static struct scripting_context *scripting_context;
53
54static char *cur_field_name;
55static int zero_flag_atom;
56
57static void define_symbolic_value(const char *ev_name,
58 const char *field_name,
59 const char *field_value,
60 const char *field_str)
61{
62 unsigned long long value;
63 dSP;
64
65 value = eval_flag(field_value);
66
67 ENTER;
68 SAVETMPS;
69 PUSHMARK(SP);
70
71 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
72 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
73 XPUSHs(sv_2mortal(newSVuv(value)));
74 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
75
76 PUTBACK;
77 if (get_cv("main::define_symbolic_value", 0))
78 call_pv("main::define_symbolic_value", G_SCALAR);
79 SPAGAIN;
80 PUTBACK;
81 FREETMPS;
82 LEAVE;
83}
84
85static void define_symbolic_values(struct print_flag_sym *field,
86 const char *ev_name,
87 const char *field_name)
88{
89 define_symbolic_value(ev_name, field_name, field->value, field->str);
90 if (field->next)
91 define_symbolic_values(field->next, ev_name, field_name);
92}
93
94static void define_symbolic_field(const char *ev_name,
95 const char *field_name)
96{
97 dSP;
98
99 ENTER;
100 SAVETMPS;
101 PUSHMARK(SP);
102
103 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
104 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
105
106 PUTBACK;
107 if (get_cv("main::define_symbolic_field", 0))
108 call_pv("main::define_symbolic_field", G_SCALAR);
109 SPAGAIN;
110 PUTBACK;
111 FREETMPS;
112 LEAVE;
113}
114
115static void define_flag_value(const char *ev_name,
116 const char *field_name,
117 const char *field_value,
118 const char *field_str)
119{
120 unsigned long long value;
121 dSP;
122
123 value = eval_flag(field_value);
124
125 ENTER;
126 SAVETMPS;
127 PUSHMARK(SP);
128
129 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
130 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
131 XPUSHs(sv_2mortal(newSVuv(value)));
132 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
133
134 PUTBACK;
135 if (get_cv("main::define_flag_value", 0))
136 call_pv("main::define_flag_value", G_SCALAR);
137 SPAGAIN;
138 PUTBACK;
139 FREETMPS;
140 LEAVE;
141}
142
143static void define_flag_values(struct print_flag_sym *field,
144 const char *ev_name,
145 const char *field_name)
146{
147 define_flag_value(ev_name, field_name, field->value, field->str);
148 if (field->next)
149 define_flag_values(field->next, ev_name, field_name);
150}
151
152static void define_flag_field(const char *ev_name,
153 const char *field_name,
154 const char *delim)
155{
156 dSP;
157
158 ENTER;
159 SAVETMPS;
160 PUSHMARK(SP);
161
162 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
163 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
164 XPUSHs(sv_2mortal(newSVpv(delim, 0)));
165
166 PUTBACK;
167 if (get_cv("main::define_flag_field", 0))
168 call_pv("main::define_flag_field", G_SCALAR);
169 SPAGAIN;
170 PUTBACK;
171 FREETMPS;
172 LEAVE;
173}
174
175static void define_event_symbols(struct event *event,
176 const char *ev_name,
177 struct print_arg *args)
178{
179 switch (args->type) {
180 case PRINT_NULL:
181 break;
182 case PRINT_ATOM:
183 define_flag_value(ev_name, cur_field_name, "0",
184 args->atom.atom);
185 zero_flag_atom = 0;
186 break;
187 case PRINT_FIELD:
188 if (cur_field_name)
189 free(cur_field_name);
190 cur_field_name = strdup(args->field.name);
191 break;
192 case PRINT_FLAGS:
193 define_event_symbols(event, ev_name, args->flags.field);
194 define_flag_field(ev_name, cur_field_name, args->flags.delim);
195 define_flag_values(args->flags.flags, ev_name, cur_field_name);
196 break;
197 case PRINT_SYMBOL:
198 define_event_symbols(event, ev_name, args->symbol.field);
199 define_symbolic_field(ev_name, cur_field_name);
200 define_symbolic_values(args->symbol.symbols, ev_name,
201 cur_field_name);
202 break;
203 case PRINT_STRING:
204 break;
205 case PRINT_TYPE:
206 define_event_symbols(event, ev_name, args->typecast.item);
207 break;
208 case PRINT_OP:
209 if (strcmp(args->op.op, ":") == 0)
210 zero_flag_atom = 1;
211 define_event_symbols(event, ev_name, args->op.left);
212 define_event_symbols(event, ev_name, args->op.right);
213 break;
214 default:
215 /* we should warn... */
216 return;
217 }
218
219 if (args->next)
220 define_event_symbols(event, ev_name, args->next);
221}
222
223static inline struct event *find_cache_event(int type)
224{
225 static char ev_name[256];
226 struct event *event;
227
228 if (events[type])
229 return events[type];
230
231 events[type] = event = trace_find_event(type);
232 if (!event)
233 return NULL;
234
235 sprintf(ev_name, "%s::%s", event->system, event->name);
236
237 define_event_symbols(event, ev_name, event->print_fmt.args);
238
239 return event;
240}
241
242int common_pc(struct scripting_context *context)
243{
244 int pc;
245
246 pc = parse_common_pc(context->event_data);
247
248 return pc;
249}
250
251int common_flags(struct scripting_context *context)
252{
253 int flags;
254
255 flags = parse_common_flags(context->event_data);
256
257 return flags;
258}
259
260int common_lock_depth(struct scripting_context *context)
261{
262 int lock_depth;
263
264 lock_depth = parse_common_lock_depth(context->event_data);
265
266 return lock_depth;
267}
268
269static void perl_process_event(int cpu, void *data,
270 int size __unused,
271 unsigned long long nsecs, char *comm)
272{
273 struct format_field *field;
274 static char handler[256];
275 unsigned long long val;
276 unsigned long s, ns;
277 struct event *event;
278 int type;
279 int pid;
280
281 dSP;
282
283 type = trace_parse_common_type(data);
284
285 event = find_cache_event(type);
286 if (!event)
287 die("ug! no event found for type %d", type);
288
289 pid = trace_parse_common_pid(data);
290
291 sprintf(handler, "%s::%s", event->system, event->name);
292
293 s = nsecs / NSECS_PER_SEC;
294 ns = nsecs - s * NSECS_PER_SEC;
295
296 scripting_context->event_data = data;
297
298 ENTER;
299 SAVETMPS;
300 PUSHMARK(SP);
301
302 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
303 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
304 XPUSHs(sv_2mortal(newSVuv(cpu)));
305 XPUSHs(sv_2mortal(newSVuv(s)));
306 XPUSHs(sv_2mortal(newSVuv(ns)));
307 XPUSHs(sv_2mortal(newSViv(pid)));
308 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
309
310 /* common fields other than pid can be accessed via xsub fns */
311
312 for (field = event->format.fields; field; field = field->next) {
313 if (field->flags & FIELD_IS_STRING) {
314 int offset;
315 if (field->flags & FIELD_IS_DYNAMIC) {
316 offset = *(int *)(data + field->offset);
317 offset &= 0xffff;
318 } else
319 offset = field->offset;
320 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
321 } else { /* FIELD_IS_NUMERIC */
322 val = read_size(data + field->offset, field->size);
323 if (field->flags & FIELD_IS_SIGNED) {
324 XPUSHs(sv_2mortal(newSViv(val)));
325 } else {
326 XPUSHs(sv_2mortal(newSVuv(val)));
327 }
328 }
329 }
330
331 PUTBACK;
332
333 if (get_cv(handler, 0))
334 call_pv(handler, G_SCALAR);
335 else if (get_cv("main::trace_unhandled", 0)) {
336 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
337 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
338 XPUSHs(sv_2mortal(newSVuv(cpu)));
339 XPUSHs(sv_2mortal(newSVuv(nsecs)));
340 XPUSHs(sv_2mortal(newSViv(pid)));
341 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
342 call_pv("main::trace_unhandled", G_SCALAR);
343 }
344 SPAGAIN;
345 PUTBACK;
346 FREETMPS;
347 LEAVE;
348}
349
350static void run_start_sub(void)
351{
352 dSP; /* access to Perl stack */
353 PUSHMARK(SP);
354
355 if (get_cv("main::trace_begin", 0))
356 call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
357}
358
359/*
360 * Start trace script
361 */
362static int perl_start_script(const char *script, int argc, const char **argv)
363{
364 const char **command_line;
365 int i, err = 0;
366
367 command_line = malloc((argc + 2) * sizeof(const char *));
368 command_line[0] = "";
369 command_line[1] = script;
370 for (i = 2; i < argc + 2; i++)
371 command_line[i] = argv[i - 2];
372
373 my_perl = perl_alloc();
374 perl_construct(my_perl);
375
376 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
377 (char **)NULL)) {
378 err = -1;
379 goto error;
380 }
381
382 if (perl_run(my_perl)) {
383 err = -1;
384 goto error;
385 }
386
387 if (SvTRUE(ERRSV)) {
388 err = -1;
389 goto error;
390 }
391
392 run_start_sub();
393
394 free(command_line);
395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
396 return 0;
397error:
398 perl_free(my_perl);
399 free(command_line);
400
401 return err;
402}
403
404/*
405 * Stop trace script
406 */
407static int perl_stop_script(void)
408{
409 dSP; /* access to Perl stack */
410 PUSHMARK(SP);
411
412 if (get_cv("main::trace_end", 0))
413 call_pv("main::trace_end", G_DISCARD | G_NOARGS);
414
415 perl_destruct(my_perl);
416 perl_free(my_perl);
417
418 fprintf(stderr, "\nperf trace Perl script stopped\n");
419
420 return 0;
421}
422
423static int perl_generate_script(const char *outfile)
424{
425 struct event *event = NULL;
426 struct format_field *f;
427 char fname[PATH_MAX];
428 int not_first, count;
429 FILE *ofp;
430
431 sprintf(fname, "%s.pl", outfile);
432 ofp = fopen(fname, "w");
433 if (ofp == NULL) {
434 fprintf(stderr, "couldn't open %s\n", fname);
435 return -1;
436 }
437
438 fprintf(ofp, "# perf trace event handlers, "
439 "generated by perf trace -g perl\n");
440
441 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
442 " License version 2\n\n");
443
444 fprintf(ofp, "# The common_* event handler fields are the most useful "
445 "fields common to\n");
446
447 fprintf(ofp, "# all events. They don't necessarily correspond to "
448 "the 'common_*' fields\n");
449
450 fprintf(ofp, "# in the format files. Those fields not available as "
451 "handler params can\n");
452
453 fprintf(ofp, "# be retrieved using Perl functions of the form "
454 "common_*($context).\n");
455
456 fprintf(ofp, "# See Context.pm for the list of available "
457 "functions.\n\n");
458
459 fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
460 "Perf-Trace-Util/lib\";\n");
461
462 fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
463 fprintf(ofp, "use Perf::Trace::Core;\n");
464 fprintf(ofp, "use Perf::Trace::Context;\n");
465 fprintf(ofp, "use Perf::Trace::Util;\n\n");
466
467 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
468 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
469
470 while ((event = trace_find_next_event(event))) {
471 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
472 fprintf(ofp, "\tmy (");
473
474 fprintf(ofp, "$event_name, ");
475 fprintf(ofp, "$context, ");
476 fprintf(ofp, "$common_cpu, ");
477 fprintf(ofp, "$common_secs, ");
478 fprintf(ofp, "$common_nsecs,\n");
479 fprintf(ofp, "\t $common_pid, ");
480 fprintf(ofp, "$common_comm,\n\t ");
481
482 not_first = 0;
483 count = 0;
484
485 for (f = event->format.fields; f; f = f->next) {
486 if (not_first++)
487 fprintf(ofp, ", ");
488 if (++count % 5 == 0)
489 fprintf(ofp, "\n\t ");
490
491 fprintf(ofp, "$%s", f->name);
492 }
493 fprintf(ofp, ") = @_;\n\n");
494
495 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
496 "$common_secs, $common_nsecs,\n\t "
497 "$common_pid, $common_comm);\n\n");
498
499 fprintf(ofp, "\tprintf(\"");
500
501 not_first = 0;
502 count = 0;
503
504 for (f = event->format.fields; f; f = f->next) {
505 if (not_first++)
506 fprintf(ofp, ", ");
507 if (count && count % 4 == 0) {
508 fprintf(ofp, "\".\n\t \"");
509 }
510 count++;
511
512 fprintf(ofp, "%s=", f->name);
513 if (f->flags & FIELD_IS_STRING ||
514 f->flags & FIELD_IS_FLAG ||
515 f->flags & FIELD_IS_SYMBOLIC)
516 fprintf(ofp, "%%s");
517 else if (f->flags & FIELD_IS_SIGNED)
518 fprintf(ofp, "%%d");
519 else
520 fprintf(ofp, "%%u");
521 }
522
523 fprintf(ofp, "\\n\",\n\t ");
524
525 not_first = 0;
526 count = 0;
527
528 for (f = event->format.fields; f; f = f->next) {
529 if (not_first++)
530 fprintf(ofp, ", ");
531
532 if (++count % 5 == 0)
533 fprintf(ofp, "\n\t ");
534
535 if (f->flags & FIELD_IS_FLAG) {
536 if ((count - 1) % 5 != 0) {
537 fprintf(ofp, "\n\t ");
538 count = 4;
539 }
540 fprintf(ofp, "flag_str(\"");
541 fprintf(ofp, "%s::%s\", ", event->system,
542 event->name);
543 fprintf(ofp, "\"%s\", $%s)", f->name,
544 f->name);
545 } else if (f->flags & FIELD_IS_SYMBOLIC) {
546 if ((count - 1) % 5 != 0) {
547 fprintf(ofp, "\n\t ");
548 count = 4;
549 }
550 fprintf(ofp, "symbol_str(\"");
551 fprintf(ofp, "%s::%s\", ", event->system,
552 event->name);
553 fprintf(ofp, "\"%s\", $%s)", f->name,
554 f->name);
555 } else
556 fprintf(ofp, "$%s", f->name);
557 }
558
559 fprintf(ofp, ");\n");
560 fprintf(ofp, "}\n\n");
561 }
562
563 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
564 "$common_cpu, $common_secs, $common_nsecs,\n\t "
565 "$common_pid, $common_comm) = @_;\n\n");
566
567 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
568 "$common_secs, $common_nsecs,\n\t $common_pid, "
569 "$common_comm);\n}\n\n");
570
571 fprintf(ofp, "sub print_header\n{\n"
572 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
573 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
574 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
575
576 fclose(ofp);
577
578 fprintf(stderr, "generated Perl script: %s\n", fname);
579
580 return 0;
581}
582
583struct scripting_ops perl_scripting_ops = {
584 .name = "Perl",
585 .start_script = perl_start_script,
586 .stop_script = perl_stop_script,
587 .process_event = perl_process_event,
588 .generate_script = perl_generate_script,
589};
590
591static void print_unsupported_msg(void)
592{
593 fprintf(stderr, "Perl scripting not supported."
594 " Install libperl and rebuild perf to enable it.\n"
595 "For example:\n # apt-get install libperl-dev (ubuntu)"
596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
598}
599
600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609static int perl_stop_script_unsupported(void)
610{
611 return 0;
612}
613
614static void perl_process_event_unsupported(int cpu __unused,
615 void *data __unused,
616 int size __unused,
617 unsigned long long nsecs __unused,
618 char *comm __unused)
619{
620}
621
622static int perl_generate_script_unsupported(const char *outfile __unused)
623{
624 print_unsupported_msg();
625
626 return -1;
627}
628
629struct scripting_ops perl_scripting_unsupported_ops = {
630 .name = "Perl",
631 .start_script = perl_start_script_unsupported,
632 .stop_script = perl_stop_script_unsupported,
633 .process_event = perl_process_event_unsupported,
634 .generate_script = perl_generate_script_unsupported,
635};
636
637static void register_perl_scripting(struct scripting_ops *scripting_ops)
638{
639 int err;
640 err = script_spec_register("Perl", scripting_ops);
641 if (err)
642 die("error registering Perl script extension");
643
644 err = script_spec_register("pl", scripting_ops);
645 if (err)
646 die("error registering pl script extension");
647
648 scripting_context = malloc(sizeof(struct scripting_context));
649}
650
651#ifdef NO_LIBPERL
652void setup_perl_scripting(void)
653{
654 register_perl_scripting(&perl_scripting_unsupported_ops);
655}
656#else
657void setup_perl_scripting(void)
658{
659 register_perl_scripting(&perl_scripting_ops);
660}
661#endif
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
new file mode 100644
index 000000000000..e88fb26137bb
--- /dev/null
+++ b/tools/perf/util/trace-event-perl.h
@@ -0,0 +1,55 @@
1#ifndef __PERF_TRACE_EVENT_PERL_H
2#define __PERF_TRACE_EVENT_PERL_H
3#ifdef NO_LIBPERL
4typedef int INTERP;
5#define dSP
6#define ENTER
7#define SAVETMPS
8#define PUTBACK
9#define SPAGAIN
10#define FREETMPS
11#define LEAVE
12#define SP
13#define ERRSV
14#define G_SCALAR (0)
15#define G_DISCARD (0)
16#define G_NOARGS (0)
17#define PUSHMARK(a)
18#define SvTRUE(a) (0)
19#define XPUSHs(s)
20#define sv_2mortal(a)
21#define newSVpv(a,b)
22#define newSVuv(a)
23#define newSViv(a)
24#define get_cv(a,b) (0)
25#define call_pv(a,b) (0)
26#define perl_alloc() (0)
27#define perl_construct(a) (0)
28#define perl_parse(a,b,c,d,e) (0)
29#define perl_run(a) (0)
30#define perl_destruct(a) (0)
31#define perl_free(a) (0)
32#define pTHX void
33#define CV void
34#define dXSUB_SYS
35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
39#else
40#include <EXTERN.h>
41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
44typedef PerlInterpreter * INTERP;
45#endif
46
47struct scripting_context {
48 void *event_data;
49};
50
51int common_pc(struct scripting_context *context);
52int common_flags(struct scripting_context *context);
53int common_lock_depth(struct scripting_context *context);
54
55#endif /* __PERF_TRACE_EVENT_PERL_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1b5c847d2c22..1744422cafcb 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -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
@@ -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.h b/tools/perf/util/trace-event.h
index 693f815c9429..6ad405620c9b 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,45 @@ 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);
242 281
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events); 282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void);
244 284
245#endif /* _TRACE_EVENTS_H */ 285#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.h b/tools/perf/util/util.h
index 9de2329dd44d..c673d8825883 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)
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}