aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2009-09-22 19:49:27 -0400
committerAnton Vorontsov <avorontsov@ru.mvista.com>2009-09-22 19:49:27 -0400
commitf056878332a91ed984a116bad4e7d49aefff9e6e (patch)
tree572f4757c8e7811d45e0be0c2ae529c78fb63441 /tools/perf/util
parent3961f7c3cf247eee5df7fabadc7a40f2deeb98f3 (diff)
parent7fa07729e439a6184bd824746d06a49cca553f15 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: drivers/power/wm97xx_battery.c
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/abspath.c3
-rw-r--r--tools/perf/util/alias.c2
-rw-r--r--tools/perf/util/cache.h3
-rw-r--r--tools/perf/util/callchain.c345
-rw-r--r--tools/perf/util/callchain.h61
-rw-r--r--tools/perf/util/color.c47
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/config.c40
-rw-r--r--tools/perf/util/debug.c95
-rw-r--r--tools/perf/util/debug.h8
-rw-r--r--tools/perf/util/event.h104
-rw-r--r--tools/perf/util/exec_cmd.c6
-rw-r--r--tools/perf/util/header.c339
-rw-r--r--tools/perf/util/header.h47
-rw-r--r--tools/perf/util/help.c41
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/include/asm/system.h1
-rw-r--r--tools/perf/util/include/linux/kernel.h29
-rw-r--r--tools/perf/util/include/linux/list.h18
-rw-r--r--tools/perf/util/include/linux/module.h6
-rw-r--r--tools/perf/util/include/linux/poison.h1
-rw-r--r--tools/perf/util/include/linux/prefetch.h6
-rw-r--r--tools/perf/util/include/linux/rbtree.h1
-rw-r--r--tools/perf/util/list.h603
-rw-r--r--tools/perf/util/map.c97
-rw-r--r--tools/perf/util/module.c509
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/pager.c5
-rw-r--r--tools/perf/util/parse-events.c788
-rw-r--r--tools/perf/util/parse-events.h23
-rw-r--r--tools/perf/util/parse-options.c27
-rw-r--r--tools/perf/util/parse-options.h29
-rw-r--r--tools/perf/util/path.c25
-rw-r--r--tools/perf/util/quote.c48
-rw-r--r--tools/perf/util/quote.h2
-rw-r--r--tools/perf/util/rbtree.c383
-rw-r--r--tools/perf/util/rbtree.h171
-rw-r--r--tools/perf/util/run-command.c101
-rw-r--r--tools/perf/util/run-command.h5
-rw-r--r--tools/perf/util/strbuf.c15
-rw-r--r--tools/perf/util/strbuf.h10
-rw-r--r--tools/perf/util/string.h5
-rw-r--r--tools/perf/util/strlist.c200
-rw-r--r--tools/perf/util/strlist.h39
-rw-r--r--tools/perf/util/svghelper.c488
-rw-r--r--tools/perf/util/svghelper.h28
-rw-r--r--tools/perf/util/symbol.c596
-rw-r--r--tools/perf/util/symbol.h55
-rw-r--r--tools/perf/util/thread.c175
-rw-r--r--tools/perf/util/thread.h22
-rw-r--r--tools/perf/util/trace-event-info.c540
-rw-r--r--tools/perf/util/trace-event-parse.c2967
-rw-r--r--tools/perf/util/trace-event-read.c514
-rw-r--r--tools/perf/util/trace-event.h245
-rw-r--r--tools/perf/util/types.h17
-rw-r--r--tools/perf/util/util.h23
-rw-r--r--tools/perf/util/values.c230
-rw-r--r--tools/perf/util/values.h27
-rw-r--r--tools/perf/util/wrapper.c5
59 files changed, 8645 insertions, 1640 deletions
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
index 61d33b81fc97..a791dd467261 100644
--- a/tools/perf/util/abspath.c
+++ b/tools/perf/util/abspath.c
@@ -50,7 +50,8 @@ const char *make_absolute_path(const char *path)
50 die ("Could not get current working directory"); 50 die ("Could not get current working directory");
51 51
52 if (last_elem) { 52 if (last_elem) {
53 int len = strlen(buf); 53 len = strlen(buf);
54
54 if (len + strlen(last_elem) + 2 > PATH_MAX) 55 if (len + strlen(last_elem) + 2 > PATH_MAX)
55 die ("Too long path name: '%s/%s'", 56 die ("Too long path name: '%s/%s'",
56 buf, last_elem); 57 buf, last_elem);
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
index 9b3dd2b428df..b8144e80bb1e 100644
--- a/tools/perf/util/alias.c
+++ b/tools/perf/util/alias.c
@@ -3,7 +3,7 @@
3static const char *alias_key; 3static const char *alias_key;
4static char *alias_val; 4static char *alias_val;
5 5
6static int alias_lookup_cb(const char *k, const char *v, void *cb) 6static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
7{ 7{
8 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) { 8 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
9 if (!v) 9 if (!v)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 393d6146d13b..6f8ea9d210b6 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -3,6 +3,7 @@
3 3
4#include "util.h" 4#include "util.h"
5#include "strbuf.h" 5#include "strbuf.h"
6#include "../perf.h"
6 7
7#define PERF_DIR_ENVIRONMENT "PERF_DIR" 8#define PERF_DIR_ENVIRONMENT "PERF_DIR"
8#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
@@ -17,6 +18,7 @@
17#define PERFATTRIBUTES_FILE ".perfattributes" 18#define PERFATTRIBUTES_FILE ".perfattributes"
18#define INFOATTRIBUTES_FILE "info/attributes" 19#define INFOATTRIBUTES_FILE "info/attributes"
19#define ATTRIBUTE_MACRO_PREFIX "[attr]" 20#define ATTRIBUTE_MACRO_PREFIX "[attr]"
21#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
20 22
21typedef int (*config_fn_t)(const char *, const char *, void *); 23typedef int (*config_fn_t)(const char *, const char *, void *);
22extern int perf_default_config(const char *, const char *, void *); 24extern int perf_default_config(const char *, const char *, void *);
@@ -50,7 +52,6 @@ extern const char *perf_mailmap_file;
50extern void maybe_flush_or_die(FILE *, const char *); 52extern void maybe_flush_or_die(FILE *, const char *);
51extern int copy_fd(int ifd, int ofd); 53extern int copy_fd(int ifd, int ofd);
52extern int copy_file(const char *dst, const char *src, int mode); 54extern int copy_file(const char *dst, const char *src, int mode);
53extern ssize_t read_in_full(int fd, void *buf, size_t count);
54extern ssize_t write_in_full(int fd, const void *buf, size_t count); 55extern ssize_t write_in_full(int fd, const void *buf, size_t count);
55extern void write_or_die(int fd, const void *buf, size_t count); 56extern void write_or_die(int fd, const void *buf, size_t count);
56extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); 57extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
new file mode 100644
index 000000000000..3b8380f1b478
--- /dev/null
+++ b/tools/perf/util/callchain.c
@@ -0,0 +1,345 @@
1/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree.
6 *
7 * Using a radix for code path provides a fast retrieval and factorizes
8 * memory use. Also that lets us use the paths in a hierarchical graph view.
9 *
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <errno.h>
16#include <math.h>
17
18#include "callchain.h"
19
20#define chain_for_each_child(child, parent) \
21 list_for_each_entry(child, &parent->children, brothers)
22
23static void
24rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
25 enum chain_mode mode)
26{
27 struct rb_node **p = &root->rb_node;
28 struct rb_node *parent = NULL;
29 struct callchain_node *rnode;
30 u64 chain_cumul = cumul_hits(chain);
31
32 while (*p) {
33 u64 rnode_cumul;
34
35 parent = *p;
36 rnode = rb_entry(parent, struct callchain_node, rb_node);
37 rnode_cumul = cumul_hits(rnode);
38
39 switch (mode) {
40 case CHAIN_FLAT:
41 if (rnode->hit < chain->hit)
42 p = &(*p)->rb_left;
43 else
44 p = &(*p)->rb_right;
45 break;
46 case CHAIN_GRAPH_ABS: /* Falldown */
47 case CHAIN_GRAPH_REL:
48 if (rnode_cumul < chain_cumul)
49 p = &(*p)->rb_left;
50 else
51 p = &(*p)->rb_right;
52 break;
53 case CHAIN_NONE:
54 default:
55 break;
56 }
57 }
58
59 rb_link_node(&chain->rb_node, parent, p);
60 rb_insert_color(&chain->rb_node, root);
61}
62
63static void
64__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
65 u64 min_hit)
66{
67 struct callchain_node *child;
68
69 chain_for_each_child(child, node)
70 __sort_chain_flat(rb_root, child, min_hit);
71
72 if (node->hit && node->hit >= min_hit)
73 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
74}
75
76/*
77 * Once we get every callchains from the stream, we can now
78 * sort them by hit
79 */
80static void
81sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
82 u64 min_hit, struct callchain_param *param __used)
83{
84 __sort_chain_flat(rb_root, node, min_hit);
85}
86
87static void __sort_chain_graph_abs(struct callchain_node *node,
88 u64 min_hit)
89{
90 struct callchain_node *child;
91
92 node->rb_root = RB_ROOT;
93
94 chain_for_each_child(child, node) {
95 __sort_chain_graph_abs(child, min_hit);
96 if (cumul_hits(child) >= min_hit)
97 rb_insert_callchain(&node->rb_root, child,
98 CHAIN_GRAPH_ABS);
99 }
100}
101
102static void
103sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
104 u64 min_hit, struct callchain_param *param __used)
105{
106 __sort_chain_graph_abs(chain_root, min_hit);
107 rb_root->rb_node = chain_root->rb_root.rb_node;
108}
109
110static void __sort_chain_graph_rel(struct callchain_node *node,
111 double min_percent)
112{
113 struct callchain_node *child;
114 u64 min_hit;
115
116 node->rb_root = RB_ROOT;
117 min_hit = ceil(node->children_hit * min_percent);
118
119 chain_for_each_child(child, node) {
120 __sort_chain_graph_rel(child, min_percent);
121 if (cumul_hits(child) >= min_hit)
122 rb_insert_callchain(&node->rb_root, child,
123 CHAIN_GRAPH_REL);
124 }
125}
126
127static void
128sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
129 u64 min_hit __used, struct callchain_param *param)
130{
131 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
132 rb_root->rb_node = chain_root->rb_root.rb_node;
133}
134
135int register_callchain_param(struct callchain_param *param)
136{
137 switch (param->mode) {
138 case CHAIN_GRAPH_ABS:
139 param->sort = sort_chain_graph_abs;
140 break;
141 case CHAIN_GRAPH_REL:
142 param->sort = sort_chain_graph_rel;
143 break;
144 case CHAIN_FLAT:
145 param->sort = sort_chain_flat;
146 break;
147 case CHAIN_NONE:
148 default:
149 return -1;
150 }
151 return 0;
152}
153
154/*
155 * Create a child for a parent. If inherit_children, then the new child
156 * will become the new parent of it's parent children
157 */
158static struct callchain_node *
159create_child(struct callchain_node *parent, bool inherit_children)
160{
161 struct callchain_node *new;
162
163 new = malloc(sizeof(*new));
164 if (!new) {
165 perror("not enough memory to create child for code path tree");
166 return NULL;
167 }
168 new->parent = parent;
169 INIT_LIST_HEAD(&new->children);
170 INIT_LIST_HEAD(&new->val);
171
172 if (inherit_children) {
173 struct callchain_node *next;
174
175 list_splice(&parent->children, &new->children);
176 INIT_LIST_HEAD(&parent->children);
177
178 chain_for_each_child(next, new)
179 next->parent = new;
180 }
181 list_add_tail(&new->brothers, &parent->children);
182
183 return new;
184}
185
186/*
187 * Fill the node with callchain values
188 */
189static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain,
191 int start, struct symbol **syms)
192{
193 unsigned int i;
194
195 for (i = start; i < chain->nr; i++) {
196 struct callchain_list *call;
197
198 call = malloc(sizeof(*call));
199 if (!call) {
200 perror("not enough memory for the code path tree");
201 return;
202 }
203 call->ip = chain->ips[i];
204 call->sym = syms[i];
205 list_add_tail(&call->list, &node->val);
206 }
207 node->val_nr = chain->nr - start;
208 if (!node->val_nr)
209 printf("Warning: empty node in callchain tree\n");
210}
211
212static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain,
214 int start, struct symbol **syms)
215{
216 struct callchain_node *new;
217
218 new = create_child(parent, false);
219 fill_node(new, chain, start, syms);
220
221 new->children_hit = 0;
222 new->hit = 1;
223}
224
225/*
226 * Split the parent in two parts (a new child is created) and
227 * give a part of its callchain to the created child.
228 * Then create another child to host the given callchain of new branch
229 */
230static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local,
233 struct symbol **syms)
234{
235 struct callchain_node *new;
236 struct list_head *old_tail;
237 unsigned int idx_total = idx_parents + idx_local;
238
239 /* split */
240 new = create_child(parent, true);
241
242 /* split the callchain and move a part to the new child */
243 old_tail = parent->val.prev;
244 list_del_range(&to_split->list, old_tail);
245 new->val.next = &to_split->list;
246 new->val.prev = old_tail;
247 to_split->list.prev = &new->val;
248 old_tail->next = &new->val;
249
250 /* split the hits */
251 new->hit = parent->hit;
252 new->children_hit = parent->children_hit;
253 parent->children_hit = cumul_hits(new);
254 new->val_nr = parent->val_nr - idx_local;
255 parent->val_nr = idx_local;
256
257 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) {
259 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms);
261 parent->children_hit++;
262 } else {
263 parent->hit = 1;
264 }
265}
266
267static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain,
269 unsigned int start, struct symbol **syms);
270
271static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
273 struct symbol **syms, unsigned int start)
274{
275 struct callchain_node *rnode;
276
277 /* lookup in childrens */
278 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms);
280
281 if (!ret)
282 goto inc_children_hit;
283 }
284 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms);
286
287inc_children_hit:
288 root->children_hit++;
289}
290
291static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain,
293 unsigned int start, struct symbol **syms)
294{
295 struct callchain_list *cnode;
296 unsigned int i = start;
297 bool found = false;
298
299 /*
300 * Lookup in the current node
301 * If we have a symbol, then compare the start to match
302 * anywhere inside a function.
303 */
304 list_for_each_entry(cnode, &root->val, list) {
305 if (i == chain->nr)
306 break;
307 if (cnode->sym && syms[i]) {
308 if (cnode->sym->start != syms[i]->start)
309 break;
310 } else if (cnode->ip != chain->ips[i])
311 break;
312 if (!found)
313 found = true;
314 i++;
315 }
316
317 /* matches not, relay on the parent */
318 if (!found)
319 return -1;
320
321 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms);
324 return 0;
325 }
326
327 /* we match 100% of the path, increment the hit */
328 if (i - start == root->val_nr && i == chain->nr) {
329 root->hit++;
330 return 0;
331 }
332
333 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i);
335
336 return 0;
337}
338
339void append_chain(struct callchain_node *root, struct ip_callchain *chain,
340 struct symbol **syms)
341{
342 if (!chain->nr)
343 return;
344 __append_chain_children(root, chain, syms, 0);
345}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
new file mode 100644
index 000000000000..43cf3ea9e088
--- /dev/null
+++ b/tools/perf/util/callchain.h
@@ -0,0 +1,61 @@
1#ifndef __PERF_CALLCHAIN_H
2#define __PERF_CALLCHAIN_H
3
4#include "../perf.h"
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include "util.h"
8#include "symbol.h"
9
10enum chain_mode {
11 CHAIN_NONE,
12 CHAIN_FLAT,
13 CHAIN_GRAPH_ABS,
14 CHAIN_GRAPH_REL
15};
16
17struct callchain_node {
18 struct callchain_node *parent;
19 struct list_head brothers;
20 struct list_head children;
21 struct list_head val;
22 struct rb_node rb_node; /* to sort nodes in an rbtree */
23 struct rb_root rb_root; /* sorted tree of children */
24 unsigned int val_nr;
25 u64 hit;
26 u64 children_hit;
27};
28
29struct callchain_param;
30
31typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
32 u64, struct callchain_param *);
33
34struct callchain_param {
35 enum chain_mode mode;
36 double min_percent;
37 sort_chain_func_t sort;
38};
39
40struct callchain_list {
41 u64 ip;
42 struct symbol *sym;
43 struct list_head list;
44};
45
46static inline void callchain_init(struct callchain_node *node)
47{
48 INIT_LIST_HEAD(&node->brothers);
49 INIT_LIST_HEAD(&node->children);
50 INIT_LIST_HEAD(&node->val);
51}
52
53static inline u64 cumul_hits(struct callchain_node *node)
54{
55 return node->hit + node->children_hit;
56}
57
58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms);
61#endif
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 9a8c20ccc53e..e88bca55a599 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -11,7 +11,8 @@ static int parse_color(const char *name, int len)
11 }; 11 };
12 char *end; 12 char *end;
13 int i; 13 int i;
14 for (i = 0; i < ARRAY_SIZE(color_names); i++) { 14
15 for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
15 const char *str = color_names[i]; 16 const char *str = color_names[i];
16 if (!strncasecmp(name, str, len) && !str[len]) 17 if (!strncasecmp(name, str, len) && !str[len])
17 return i - 1; 18 return i - 1;
@@ -28,7 +29,8 @@ static int parse_attr(const char *name, int len)
28 static const char * const attr_names[] = { 29 static const char * const attr_names[] = {
29 "bold", "dim", "ul", "blink", "reverse" 30 "bold", "dim", "ul", "blink", "reverse"
30 }; 31 };
31 int i; 32 unsigned int i;
33
32 for (i = 0; i < ARRAY_SIZE(attr_names); i++) { 34 for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
33 const char *str = attr_names[i]; 35 const char *str = attr_names[i];
34 if (!strncasecmp(name, str, len) && !str[len]) 36 if (!strncasecmp(name, str, len) && !str[len])
@@ -164,7 +166,7 @@ int perf_color_default_config(const char *var, const char *value, void *cb)
164 return perf_default_config(var, value, cb); 166 return perf_default_config(var, value, cb);
165} 167}
166 168
167static int color_vfprintf(FILE *fp, const char *color, const char *fmt, 169static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
168 va_list args, const char *trail) 170 va_list args, const char *trail)
169{ 171{
170 int r = 0; 172 int r = 0;
@@ -189,6 +191,10 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
189 return r; 191 return r;
190} 192}
191 193
194int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
195{
196 return __color_vfprintf(fp, color, fmt, args, NULL);
197}
192 198
193 199
194int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) 200int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
@@ -197,7 +203,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
197 int r; 203 int r;
198 204
199 va_start(args, fmt); 205 va_start(args, fmt);
200 r = color_vfprintf(fp, color, fmt, args, NULL); 206 r = color_vfprintf(fp, color, fmt, args);
201 va_end(args); 207 va_end(args);
202 return r; 208 return r;
203} 209}
@@ -207,7 +213,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
207 va_list args; 213 va_list args;
208 int r; 214 int r;
209 va_start(args, fmt); 215 va_start(args, fmt);
210 r = color_vfprintf(fp, color, fmt, args, "\n"); 216 r = __color_vfprintf(fp, color, fmt, args, "\n");
211 va_end(args); 217 va_end(args);
212 return r; 218 return r;
213} 219}
@@ -222,10 +228,12 @@ int color_fwrite_lines(FILE *fp, const char *color,
222{ 228{
223 if (!*color) 229 if (!*color)
224 return fwrite(buf, count, 1, fp) != 1; 230 return fwrite(buf, count, 1, fp) != 1;
231
225 while (count) { 232 while (count) {
226 char *p = memchr(buf, '\n', count); 233 char *p = memchr(buf, '\n', count);
234
227 if (p != buf && (fputs(color, fp) < 0 || 235 if (p != buf && (fputs(color, fp) < 0 ||
228 fwrite(buf, p ? p - buf : count, 1, fp) != 1 || 236 fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
229 fputs(PERF_COLOR_RESET, fp) < 0)) 237 fputs(PERF_COLOR_RESET, fp) < 0))
230 return -1; 238 return -1;
231 if (!p) 239 if (!p)
@@ -238,4 +246,31 @@ int color_fwrite_lines(FILE *fp, const char *color,
238 return 0; 246 return 0;
239} 247}
240 248
249const char *get_percent_color(double percent)
250{
251 const char *color = PERF_COLOR_NORMAL;
241 252
253 /*
254 * We color high-overhead entries in red, mid-overhead
255 * entries in green - and keep the low overhead places
256 * normal:
257 */
258 if (percent >= MIN_RED)
259 color = PERF_COLOR_RED;
260 else {
261 if (percent > MIN_GREEN)
262 color = PERF_COLOR_GREEN;
263 }
264 return color;
265}
266
267int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
268{
269 int r;
270 const char *color;
271
272 color = get_percent_color(percent);
273 r = color_fprintf(fp, color, fmt, percent);
274
275 return r;
276}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 5abfd379582b..58d597564b99 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -15,6 +15,9 @@
15#define PERF_COLOR_CYAN "\033[36m" 15#define PERF_COLOR_CYAN "\033[36m"
16#define PERF_COLOR_BG_RED "\033[41m" 16#define PERF_COLOR_BG_RED "\033[41m"
17 17
18#define MIN_GREEN 0.5
19#define MIN_RED 5.0
20
18/* 21/*
19 * This variable stores the value of color.ui 22 * This variable stores the value of color.ui
20 */ 23 */
@@ -29,8 +32,11 @@ int perf_color_default_config(const char *var, const char *value, void *cb);
29int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); 32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
30void color_parse(const char *value, const char *var, char *dst); 33void color_parse(const char *value, const char *var, char *dst);
31void color_parse_mem(const char *value, int len, const char *var, char *dst); 34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
32int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
33int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 37int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
34int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 38int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent);
35 41
36#endif /* COLOR_H */ 42#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3dd13faa6a27..8784649109ce 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -47,10 +47,12 @@ static int get_next_char(void)
47static char *parse_value(void) 47static char *parse_value(void)
48{ 48{
49 static char value[1024]; 49 static char value[1024];
50 int quote = 0, comment = 0, len = 0, space = 0; 50 int quote = 0, comment = 0, space = 0;
51 size_t len = 0;
51 52
52 for (;;) { 53 for (;;) {
53 int c = get_next_char(); 54 int c = get_next_char();
55
54 if (len >= sizeof(value) - 1) 56 if (len >= sizeof(value) - 1)
55 return NULL; 57 return NULL;
56 if (c == '\n') { 58 if (c == '\n') {
@@ -158,17 +160,18 @@ static int get_extended_base_var(char *name, int baselen, int c)
158 name[baselen++] = '.'; 160 name[baselen++] = '.';
159 161
160 for (;;) { 162 for (;;) {
161 int c = get_next_char(); 163 int ch = get_next_char();
162 if (c == '\n') 164
165 if (ch == '\n')
163 return -1; 166 return -1;
164 if (c == '"') 167 if (ch == '"')
165 break; 168 break;
166 if (c == '\\') { 169 if (ch == '\\') {
167 c = get_next_char(); 170 ch = get_next_char();
168 if (c == '\n') 171 if (ch == '\n')
169 return -1; 172 return -1;
170 } 173 }
171 name[baselen++] = c; 174 name[baselen++] = ch;
172 if (baselen > MAXNAME / 2) 175 if (baselen > MAXNAME / 2)
173 return -1; 176 return -1;
174 } 177 }
@@ -353,13 +356,13 @@ int perf_config_string(const char **dest, const char *var, const char *value)
353 return 0; 356 return 0;
354} 357}
355 358
356static int perf_default_core_config(const char *var, const char *value) 359static int perf_default_core_config(const char *var __used, const char *value __used)
357{ 360{
358 /* Add other config variables here and to Documentation/config.txt. */ 361 /* Add other config variables here and to Documentation/config.txt. */
359 return 0; 362 return 0;
360} 363}
361 364
362int perf_default_config(const char *var, const char *value, void *dummy) 365int perf_default_config(const char *var, const char *value, void *dummy __used)
363{ 366{
364 if (!prefixcmp(var, "core.")) 367 if (!prefixcmp(var, "core."))
365 return perf_default_core_config(var, value); 368 return perf_default_core_config(var, value);
@@ -471,10 +474,10 @@ static int matches(const char* key, const char* value)
471 !regexec(store.value_regex, value, 0, NULL, 0))); 474 !regexec(store.value_regex, value, 0, NULL, 0)));
472} 475}
473 476
474static int store_aux(const char* key, const char* value, void *cb) 477static int store_aux(const char* key, const char* value, void *cb __used)
475{ 478{
479 int section_len;
476 const char *ep; 480 const char *ep;
477 size_t section_len;
478 481
479 switch (store.state) { 482 switch (store.state) {
480 case KEY_SEEN: 483 case KEY_SEEN:
@@ -528,6 +531,8 @@ static int store_aux(const char* key, const char* value, void *cb)
528 store.offset[store.seen] = ftell(config_file); 531 store.offset[store.seen] = ftell(config_file);
529 } 532 }
530 } 533 }
534 default:
535 break;
531 } 536 }
532 return 0; 537 return 0;
533} 538}
@@ -551,7 +556,7 @@ static int store_write_section(int fd, const char* key)
551 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); 556 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
552 } 557 }
553 558
554 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 559 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
555 strbuf_release(&sb); 560 strbuf_release(&sb);
556 561
557 return success; 562 return success;
@@ -599,7 +604,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
599 } 604 }
600 strbuf_addf(&sb, "%s\n", quote); 605 strbuf_addf(&sb, "%s\n", quote);
601 606
602 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 607 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
603 strbuf_release(&sb); 608 strbuf_release(&sb);
604 609
605 return success; 610 return success;
@@ -617,6 +622,7 @@ contline:
617 switch (contents[offset]) { 622 switch (contents[offset]) {
618 case '=': equal_offset = offset; break; 623 case '=': equal_offset = offset; break;
619 case ']': bracket_offset = offset; break; 624 case ']': bracket_offset = offset; break;
625 default: break;
620 } 626 }
621 if (offset > 0 && contents[offset-1] == '\\') { 627 if (offset > 0 && contents[offset-1] == '\\') {
622 offset_ = offset; 628 offset_ = offset;
@@ -740,9 +746,9 @@ int perf_config_set_multivar(const char* key, const char* value,
740 goto write_err_out; 746 goto write_err_out;
741 } else { 747 } else {
742 struct stat st; 748 struct stat st;
743 char* contents; 749 char *contents;
744 size_t contents_sz, copy_begin, copy_end; 750 ssize_t contents_sz, copy_begin, copy_end;
745 int i, new_line = 0; 751 int new_line = 0;
746 752
747 if (value_regex == NULL) 753 if (value_regex == NULL)
748 store.value_regex = NULL; 754 store.value_regex = NULL;
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
new file mode 100644
index 000000000000..e8ca98fe0bd4
--- /dev/null
+++ b/tools/perf/util/debug.c
@@ -0,0 +1,95 @@
1/* For general debugging purposes */
2
3#include "../perf.h"
4
5#include <string.h>
6#include <stdarg.h>
7#include <stdio.h>
8
9#include "color.h"
10#include "event.h"
11#include "debug.h"
12
13int verbose = 0;
14int dump_trace = 0;
15
16int eprintf(const char *fmt, ...)
17{
18 va_list args;
19 int ret = 0;
20
21 if (verbose) {
22 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args);
24 va_end(args);
25 }
26
27 return ret;
28}
29
30int dump_printf(const char *fmt, ...)
31{
32 va_list args;
33 int ret = 0;
34
35 if (dump_trace) {
36 va_start(args, fmt);
37 ret = vprintf(fmt, args);
38 va_end(args);
39 }
40
41 return ret;
42}
43
44static int dump_printf_color(const char *fmt, const char *color, ...)
45{
46 va_list args;
47 int ret = 0;
48
49 if (dump_trace) {
50 va_start(args, color);
51 ret = color_vfprintf(stdout, color, fmt, args);
52 va_end(args);
53 }
54
55 return ret;
56}
57
58
59void trace_event(event_t *event)
60{
61 unsigned char *raw_event = (void *)event;
62 const char *color = PERF_COLOR_BLUE;
63 int i, j;
64
65 if (!dump_trace)
66 return;
67
68 dump_printf(".");
69 dump_printf_color("\n. ... raw event: size %d bytes\n", color,
70 event->header.size);
71
72 for (i = 0; i < event->header.size; i++) {
73 if ((i & 15) == 0) {
74 dump_printf(".");
75 dump_printf_color(" %04x: ", color, i);
76 }
77
78 dump_printf_color(" %02x", color, raw_event[i]);
79
80 if (((i & 15) == 15) || i == event->header.size-1) {
81 dump_printf_color(" ", color);
82 for (j = 0; j < 15-(i & 15); j++)
83 dump_printf_color(" ", color);
84 for (j = 0; j < (i & 15); j++) {
85 if (isprint(raw_event[i-15+j]))
86 dump_printf_color("%c", color,
87 raw_event[i-15+j]);
88 else
89 dump_printf_color(".", color);
90 }
91 dump_printf_color("\n", color);
92 }
93 }
94 dump_printf(".\n");
95}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
new file mode 100644
index 000000000000..437eea58ce40
--- /dev/null
+++ b/tools/perf/util/debug.h
@@ -0,0 +1,8 @@
1/* For debugging general purposes */
2
3extern int verbose;
4extern int dump_trace;
5
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
new file mode 100644
index 000000000000..2c9c26d6ded0
--- /dev/null
+++ b/tools/perf/util/event.h
@@ -0,0 +1,104 @@
1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H
3#include "../perf.h"
4#include "util.h"
5#include <linux/list.h>
6
7enum {
8 SHOW_KERNEL = 1,
9 SHOW_USER = 2,
10 SHOW_HV = 4,
11};
12
13/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
15 */
16struct ip_event {
17 struct perf_event_header header;
18 u64 ip;
19 u32 pid, tid;
20 unsigned char __more_data[];
21};
22
23struct mmap_event {
24 struct perf_event_header header;
25 u32 pid, tid;
26 u64 start;
27 u64 len;
28 u64 pgoff;
29 char filename[PATH_MAX];
30};
31
32struct comm_event {
33 struct perf_event_header header;
34 u32 pid, tid;
35 char comm[16];
36};
37
38struct fork_event {
39 struct perf_event_header header;
40 u32 pid, ppid;
41 u32 tid, ptid;
42 u64 time;
43};
44
45struct lost_event {
46 struct perf_event_header header;
47 u64 id;
48 u64 lost;
49};
50
51/*
52 * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
53 */
54struct read_event {
55 struct perf_event_header header;
56 u32 pid, tid;
57 u64 value;
58 u64 time_enabled;
59 u64 time_running;
60 u64 id;
61};
62
63struct sample_event{
64 struct perf_event_header header;
65 u64 array[];
66};
67
68
69typedef union event_union {
70 struct perf_event_header header;
71 struct ip_event ip;
72 struct mmap_event mmap;
73 struct comm_event comm;
74 struct fork_event fork;
75 struct lost_event lost;
76 struct read_event read;
77 struct sample_event sample;
78} event_t;
79
80struct map {
81 struct list_head node;
82 u64 start;
83 u64 end;
84 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64);
86 struct dso *dso;
87};
88
89static inline u64 map__map_ip(struct map *map, u64 ip)
90{
91 return ip - map->start + map->pgoff;
92}
93
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
95{
96 return ip;
97}
98
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
100struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp);
103
104#endif
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index d39292263153..2745605dba11 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -1,9 +1,11 @@
1#include "cache.h" 1#include "cache.h"
2#include "exec_cmd.h" 2#include "exec_cmd.h"
3#include "quote.h" 3#include "quote.h"
4
5#include <string.h>
6
4#define MAX_ARGS 32 7#define MAX_ARGS 32
5 8
6extern char **environ;
7static const char *argv_exec_path; 9static const char *argv_exec_path;
8static const char *argv0_path; 10static const char *argv0_path;
9 11
@@ -51,7 +53,7 @@ const char *perf_extract_argv0_path(const char *argv0)
51 slash--; 53 slash--;
52 54
53 if (slash >= argv0) { 55 if (slash >= argv0) {
54 argv0_path = strndup(argv0, slash - argv0); 56 argv0_path = xstrndup(argv0, slash - argv0);
55 return slash + 1; 57 return slash + 1;
56 } 58 }
57 59
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
new file mode 100644
index 000000000000..e306857b2c2b
--- /dev/null
+++ b/tools/perf/util/header.c
@@ -0,0 +1,339 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5
6#include "util.h"
7#include "header.h"
8
9/*
10 * Create new perf.data header attribute:
11 */
12struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
13{
14 struct perf_header_attr *self = malloc(sizeof(*self));
15
16 if (!self)
17 die("nomem");
18
19 self->attr = *attr;
20 self->ids = 0;
21 self->size = 1;
22 self->id = malloc(sizeof(u64));
23
24 if (!self->id)
25 die("nomem");
26
27 return self;
28}
29
30void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
31{
32 int pos = self->ids;
33
34 self->ids++;
35 if (self->ids > self->size) {
36 self->size *= 2;
37 self->id = realloc(self->id, self->size * sizeof(u64));
38 if (!self->id)
39 die("nomem");
40 }
41 self->id[pos] = id;
42}
43
44/*
45 * Create new perf.data header:
46 */
47struct perf_header *perf_header__new(void)
48{
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;
58 self->attr = malloc(sizeof(void *));
59
60 if (!self->attr)
61 die("nomem");
62
63 self->data_offset = 0;
64 self->data_size = 0;
65
66 return self;
67}
68
69void perf_header__add_attr(struct perf_header *self,
70 struct perf_header_attr *attr)
71{
72 int pos = self->attrs;
73
74 if (self->frozen)
75 die("frozen");
76
77 self->attrs++;
78 if (self->attrs > self->size) {
79 self->size *= 2;
80 self->attr = realloc(self->attr, self->size * sizeof(void *));
81 if (!self->attr)
82 die("nomem");
83 }
84 self->attr[pos] = attr;
85}
86
87#define MAX_EVENT_NAME 64
88
89struct perf_trace_event_type {
90 u64 event_id;
91 char name[MAX_EVENT_NAME];
92};
93
94static int event_count;
95static struct perf_trace_event_type *events;
96
97void perf_header__push_event(u64 id, const char *name)
98{
99 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name);
101
102 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type));
104 if (!events)
105 die("nomem");
106 } else {
107 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
108 if (!events)
109 die("nomem");
110 }
111 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
112 events[event_count].event_id = id;
113 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
114 event_count++;
115}
116
117char *perf_header__find_event(u64 id)
118{
119 int i;
120 for (i = 0 ; i < event_count; i++) {
121 if (events[i].event_id == id)
122 return events[i].name;
123 }
124 return NULL;
125}
126
127static const char *__perf_magic = "PERFFILE";
128
129#define PERF_MAGIC (*(u64 *)__perf_magic)
130
131struct perf_file_section {
132 u64 offset;
133 u64 size;
134};
135
136struct perf_file_attr {
137 struct perf_event_attr attr;
138 struct perf_file_section ids;
139};
140
141struct perf_file_header {
142 u64 magic;
143 u64 size;
144 u64 attr_size;
145 struct perf_file_section attrs;
146 struct perf_file_section data;
147 struct perf_file_section event_types;
148};
149
150static void do_write(int fd, void *buf, size_t size)
151{
152 while (size) {
153 int ret = write(fd, buf, size);
154
155 if (ret < 0)
156 die("failed to write");
157
158 size -= ret;
159 buf += ret;
160 }
161}
162
163void perf_header__write(struct perf_header *self, int fd)
164{
165 struct perf_file_header f_header;
166 struct perf_file_attr f_attr;
167 struct perf_header_attr *attr;
168 int i;
169
170 lseek(fd, sizeof(f_header), SEEK_SET);
171
172
173 for (i = 0; i < self->attrs; i++) {
174 attr = self->attr[i];
175
176 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177 do_write(fd, attr->id, attr->ids * sizeof(u64));
178 }
179
180
181 self->attr_offset = lseek(fd, 0, SEEK_CUR);
182
183 for (i = 0; i < self->attrs; i++) {
184 attr = self->attr[i];
185
186 f_attr = (struct perf_file_attr){
187 .attr = attr->attr,
188 .ids = {
189 .offset = attr->id_offset,
190 .size = attr->ids * sizeof(u64),
191 }
192 };
193 do_write(fd, &f_attr, sizeof(f_attr));
194 }
195
196 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events)
199 do_write(fd, events, self->event_size);
200
201
202 self->data_offset = lseek(fd, 0, SEEK_CUR);
203
204 f_header = (struct perf_file_header){
205 .magic = PERF_MAGIC,
206 .size = sizeof(f_header),
207 .attr_size = sizeof(f_attr),
208 .attrs = {
209 .offset = self->attr_offset,
210 .size = self->attrs * sizeof(f_attr),
211 },
212 .data = {
213 .offset = self->data_offset,
214 .size = self->data_size,
215 },
216 .event_types = {
217 .offset = self->event_offset,
218 .size = self->event_size,
219 },
220 };
221
222 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header));
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225
226 self->frozen = 1;
227}
228
229static void do_read(int fd, void *buf, size_t size)
230{
231 while (size) {
232 int ret = read(fd, buf, size);
233
234 if (ret < 0)
235 die("failed to read");
236 if (ret == 0)
237 die("failed to read: missing data");
238
239 size -= ret;
240 buf += ret;
241 }
242}
243
244struct perf_header *perf_header__read(int fd)
245{
246 struct perf_header *self = perf_header__new();
247 struct perf_file_header f_header;
248 struct perf_file_attr f_attr;
249 u64 f_id;
250
251 int nr_attrs, nr_ids, i, j;
252
253 lseek(fd, 0, SEEK_SET);
254 do_read(fd, &f_header, sizeof(f_header));
255
256 if (f_header.magic != PERF_MAGIC ||
257 f_header.size != sizeof(f_header) ||
258 f_header.attr_size != sizeof(f_attr))
259 die("incompatible file format");
260
261 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET);
263
264 for (i = 0; i < nr_attrs; i++) {
265 struct perf_header_attr *attr;
266 off_t tmp;
267
268 do_read(fd, &f_attr, sizeof(f_attr));
269 tmp = lseek(fd, 0, SEEK_CUR);
270
271 attr = perf_header_attr__new(&f_attr.attr);
272
273 nr_ids = f_attr.ids.size / sizeof(u64);
274 lseek(fd, f_attr.ids.offset, SEEK_SET);
275
276 for (j = 0; j < nr_ids; j++) {
277 do_read(fd, &f_id, sizeof(f_id));
278
279 perf_header_attr__add_id(attr, f_id);
280 }
281 perf_header__add_attr(self, attr);
282 lseek(fd, tmp, SEEK_SET);
283 }
284
285 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size);
288 if (!events)
289 die("nomem");
290 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295
296 self->data_offset = f_header.data.offset;
297 self->data_size = f_header.data.size;
298
299 lseek(fd, self->data_offset, SEEK_SET);
300
301 self->frozen = 1;
302
303 return self;
304}
305
306u64 perf_header__sample_type(struct perf_header *header)
307{
308 u64 type = 0;
309 int i;
310
311 for (i = 0; i < header->attrs; i++) {
312 struct perf_header_attr *attr = header->attr[i];
313
314 if (!type)
315 type = attr->attr.sample_type;
316 else if (type != attr->attr.sample_type)
317 die("non matching sample_type");
318 }
319
320 return type;
321}
322
323struct perf_event_attr *
324perf_header__find_attr(u64 id, struct perf_header *header)
325{
326 int i;
327
328 for (i = 0; i < header->attrs; i++) {
329 struct perf_header_attr *attr = header->attr[i];
330 int j;
331
332 for (j = 0; j < attr->ids; j++) {
333 if (attr->id[j] == id)
334 return &attr->attr;
335 }
336 }
337
338 return NULL;
339}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644
index 000000000000..a0761bc7863c
--- /dev/null
+++ b/tools/perf/util/header.h
@@ -0,0 +1,47 @@
1#ifndef _PERF_HEADER_H
2#define _PERF_HEADER_H
3
4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h>
6#include "types.h"
7
8struct perf_header_attr {
9 struct perf_event_attr attr;
10 int ids, size;
11 u64 *id;
12 off_t id_offset;
13};
14
15struct perf_header {
16 int frozen;
17 int attrs, size;
18 struct perf_header_attr **attr;
19 s64 attr_offset;
20 u64 data_offset;
21 u64 data_size;
22 u64 event_offset;
23 u64 event_size;
24};
25
26struct perf_header *perf_header__read(int fd);
27void perf_header__write(struct perf_header *self, int fd);
28
29void perf_header__add_attr(struct perf_header *self,
30 struct perf_header_attr *attr);
31
32void perf_header__push_event(u64 id, const char *name);
33char *perf_header__find_event(u64 id);
34
35
36struct perf_header_attr *
37perf_header_attr__new(struct perf_event_attr *attr);
38void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
39
40u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header);
43
44
45struct perf_header *perf_header__new(void);
46
47#endif /* _PERF_HEADER_H */
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index 6653f7dd1d78..fbb00978b2e2 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -26,7 +26,7 @@ static int term_columns(void)
26 return 80; 26 return 80;
27} 27}
28 28
29void add_cmdname(struct cmdnames *cmds, const char *name, int len) 29void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
30{ 30{
31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1); 31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
32 32
@@ -40,7 +40,8 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)
40 40
41static void clean_cmdnames(struct cmdnames *cmds) 41static void clean_cmdnames(struct cmdnames *cmds)
42{ 42{
43 int i; 43 unsigned int i;
44
44 for (i = 0; i < cmds->cnt; ++i) 45 for (i = 0; i < cmds->cnt; ++i)
45 free(cmds->names[i]); 46 free(cmds->names[i]);
46 free(cmds->names); 47 free(cmds->names);
@@ -57,7 +58,7 @@ static int cmdname_compare(const void *a_, const void *b_)
57 58
58static void uniq(struct cmdnames *cmds) 59static void uniq(struct cmdnames *cmds)
59{ 60{
60 int i, j; 61 unsigned int i, j;
61 62
62 if (!cmds->cnt) 63 if (!cmds->cnt)
63 return; 64 return;
@@ -71,7 +72,7 @@ static void uniq(struct cmdnames *cmds)
71 72
72void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) 73void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
73{ 74{
74 int ci, cj, ei; 75 size_t ci, cj, ei;
75 int cmp; 76 int cmp;
76 77
77 ci = cj = ei = 0; 78 ci = cj = ei = 0;
@@ -106,8 +107,9 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
106 printf(" "); 107 printf(" ");
107 108
108 for (j = 0; j < cols; j++) { 109 for (j = 0; j < cols; j++) {
109 int n = j * rows + i; 110 unsigned int n = j * rows + i;
110 int size = space; 111 unsigned int size = space;
112
111 if (n >= cmds->cnt) 113 if (n >= cmds->cnt)
112 break; 114 break;
113 if (j == cols-1 || n + rows >= cmds->cnt) 115 if (j == cols-1 || n + rows >= cmds->cnt)
@@ -126,21 +128,6 @@ static int is_executable(const char *name)
126 !S_ISREG(st.st_mode)) 128 !S_ISREG(st.st_mode))
127 return 0; 129 return 0;
128 130
129#ifdef __MINGW32__
130 /* cannot trust the executable bit, peek into the file instead */
131 char buf[3] = { 0 };
132 int n;
133 int fd = open(name, O_RDONLY);
134 st.st_mode &= ~S_IXUSR;
135 if (fd >= 0) {
136 n = read(fd, buf, 2);
137 if (n == 2)
138 /* DOS executables start with "MZ" */
139 if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
140 st.st_mode |= S_IXUSR;
141 close(fd);
142 }
143#endif
144 return st.st_mode & S_IXUSR; 131 return st.st_mode & S_IXUSR;
145} 132}
146 133
@@ -223,7 +210,7 @@ void load_command_list(const char *prefix,
223void list_commands(const char *title, struct cmdnames *main_cmds, 210void list_commands(const char *title, struct cmdnames *main_cmds,
224 struct cmdnames *other_cmds) 211 struct cmdnames *other_cmds)
225{ 212{
226 int i, longest = 0; 213 unsigned int i, longest = 0;
227 214
228 for (i = 0; i < main_cmds->cnt; i++) 215 for (i = 0; i < main_cmds->cnt; i++)
229 if (longest < main_cmds->names[i]->len) 216 if (longest < main_cmds->names[i]->len)
@@ -254,7 +241,8 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
254 241
255int is_in_cmdlist(struct cmdnames *c, const char *s) 242int is_in_cmdlist(struct cmdnames *c, const char *s)
256{ 243{
257 int i; 244 unsigned int i;
245
258 for (i = 0; i < c->cnt; i++) 246 for (i = 0; i < c->cnt; i++)
259 if (!strcmp(s, c->names[i]->name)) 247 if (!strcmp(s, c->names[i]->name))
260 return 1; 248 return 1;
@@ -286,7 +274,8 @@ static int levenshtein_compare(const void *p1, const void *p2)
286 274
287static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) 275static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
288{ 276{
289 int i; 277 unsigned int i;
278
290 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc); 279 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
291 280
292 for (i = 0; i < old->cnt; i++) 281 for (i = 0; i < old->cnt; i++)
@@ -298,7 +287,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
298 287
299const char *help_unknown_cmd(const char *cmd) 288const char *help_unknown_cmd(const char *cmd)
300{ 289{
301 int i, n = 0, best_similarity = 0; 290 unsigned int i, n = 0, best_similarity = 0;
302 struct cmdnames main_cmds, other_cmds; 291 struct cmdnames main_cmds, other_cmds;
303 292
304 memset(&main_cmds, 0, sizeof(main_cmds)); 293 memset(&main_cmds, 0, sizeof(main_cmds));
@@ -360,7 +349,7 @@ const char *help_unknown_cmd(const char *cmd)
360 exit(1); 349 exit(1);
361} 350}
362 351
363int cmd_version(int argc, const char **argv, const char *prefix) 352int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
364{ 353{
365 printf("perf version %s\n", perf_version_string); 354 printf("perf version %s\n", perf_version_string);
366 return 0; 355 return 0;
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 56bc15406ffc..7128783637b4 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -2,8 +2,8 @@
2#define HELP_H 2#define HELP_H
3 3
4struct cmdnames { 4struct cmdnames {
5 int alloc; 5 size_t alloc;
6 int cnt; 6 size_t cnt;
7 struct cmdname { 7 struct cmdname {
8 size_t len; /* also used for similarity index in help.c */ 8 size_t len; /* also used for similarity index in help.c */
9 char name[FLEX_ARRAY]; 9 char name[FLEX_ARRAY];
@@ -19,7 +19,7 @@ static inline void mput_char(char c, unsigned int num)
19void load_command_list(const char *prefix, 19void load_command_list(const char *prefix,
20 struct cmdnames *main_cmds, 20 struct cmdnames *main_cmds,
21 struct cmdnames *other_cmds); 21 struct cmdnames *other_cmds);
22void add_cmdname(struct cmdnames *cmds, const char *name, int len); 22void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
23/* Here we require that excludes is a sorted list. */ 23/* Here we require that excludes is a sorted list. */
24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); 24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
25int is_in_cmdlist(struct cmdnames *c, const char *s); 25int is_in_cmdlist(struct cmdnames *c, const char *s);
diff --git a/tools/perf/util/include/asm/system.h b/tools/perf/util/include/asm/system.h
new file mode 100644
index 000000000000..710cecca972d
--- /dev/null
+++ b/tools/perf/util/include/asm/system.h
@@ -0,0 +1 @@
/* Empty */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
new file mode 100644
index 000000000000..a6b87390cb52
--- /dev/null
+++ b/tools/perf/util/include/linux/kernel.h
@@ -0,0 +1,29 @@
1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_
3
4#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif
7
8#ifndef container_of
9/**
10 * container_of - cast a member of a structure out to the containing structure
11 * @ptr: the pointer to the member.
12 * @type: the type of the container struct this is embedded in.
13 * @member: the name of the member within the struct.
14 *
15 */
16#define container_of(ptr, type, member) ({ \
17 const typeof(((type *)0)->member) * __mptr = (ptr); \
18 (type *)((char *)__mptr - offsetof(type, member)); })
19#endif
20
21#ifndef max
22#define max(x, y) ({ \
23 typeof(x) _max1 = (x); \
24 typeof(y) _max2 = (y); \
25 (void) (&_max1 == &_max2); \
26 _max1 > _max2 ? _max1 : _max2; })
27#endif
28
29#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
new file mode 100644
index 000000000000..dbe4b814382a
--- /dev/null
+++ b/tools/perf/util/include/linux/list.h
@@ -0,0 +1,18 @@
1#include "../../../../include/linux/list.h"
2
3#ifndef PERF_LIST_H
4#define PERF_LIST_H
5/**
6 * list_del_range - deletes range of entries from list.
7 * @begin: first element in the range to delete from the list.
8 * @end: last element in the range to delete from the list.
9 * Note: list_empty on the range of entries does not return true after this,
10 * the entries is in an undefined state.
11 */
12static inline void list_del_range(struct list_head *begin,
13 struct list_head *end)
14{
15 begin->prev->next = end->next;
16 end->next->prev = begin->prev;
17}
18#endif
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/module.h
new file mode 100644
index 000000000000..b43e2dc21e04
--- /dev/null
+++ b/tools/perf/util/include/linux/module.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/poison.h b/tools/perf/util/include/linux/poison.h
new file mode 100644
index 000000000000..fef6dbc9ce13
--- /dev/null
+++ b/tools/perf/util/include/linux/poison.h
@@ -0,0 +1 @@
#include "../../../../include/linux/poison.h"
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
new file mode 100644
index 000000000000..7841e485d8c3
--- /dev/null
+++ b/tools/perf/util/include/linux/prefetch.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_PREFETCH_H
2#define PERF_LINUX_PREFETCH_H
3
4static inline void prefetch(void *a __attribute__((unused))) { }
5
6#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
new file mode 100644
index 000000000000..7a243a143037
--- /dev/null
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -0,0 +1 @@
#include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/list.h b/tools/perf/util/list.h
deleted file mode 100644
index e2548e8072cf..000000000000
--- a/tools/perf/util/list.h
+++ /dev/null
@@ -1,603 +0,0 @@
1#ifndef _LINUX_LIST_H
2#define _LINUX_LIST_H
3/*
4 Copyright (C) Cast of dozens, comes from the Linux kernel
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
9*/
10
11#include <stddef.h>
12
13/*
14 * These are non-NULL pointers that will result in page faults
15 * under normal circumstances, used to verify that nobody uses
16 * non-initialized list entries.
17 */
18#define LIST_POISON1 ((void *)0x00100100)
19#define LIST_POISON2 ((void *)0x00200200)
20
21/**
22 * container_of - cast a member of a structure out to the containing structure
23 * @ptr: the pointer to the member.
24 * @type: the type of the container struct this is embedded in.
25 * @member: the name of the member within the struct.
26 *
27 */
28#define container_of(ptr, type, member) ({ \
29 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
30 (type *)( (char *)__mptr - offsetof(type,member) );})
31
32/*
33 * Simple doubly linked list implementation.
34 *
35 * Some of the internal functions ("__xxx") are useful when
36 * manipulating whole lists rather than single entries, as
37 * sometimes we already know the next/prev entries and we can
38 * generate better code by using them directly rather than
39 * using the generic single-entry routines.
40 */
41
42struct list_head {
43 struct list_head *next, *prev;
44};
45
46#define LIST_HEAD_INIT(name) { &(name), &(name) }
47
48#define LIST_HEAD(name) \
49 struct list_head name = LIST_HEAD_INIT(name)
50
51static inline void INIT_LIST_HEAD(struct list_head *list)
52{
53 list->next = list;
54 list->prev = list;
55}
56
57/*
58 * Insert a new entry between two known consecutive entries.
59 *
60 * This is only for internal list manipulation where we know
61 * the prev/next entries already!
62 */
63static inline void __list_add(struct list_head *new,
64 struct list_head *prev,
65 struct list_head *next)
66{
67 next->prev = new;
68 new->next = next;
69 new->prev = prev;
70 prev->next = new;
71}
72
73/**
74 * list_add - add a new entry
75 * @new: new entry to be added
76 * @head: list head to add it after
77 *
78 * Insert a new entry after the specified head.
79 * This is good for implementing stacks.
80 */
81static inline void list_add(struct list_head *new, struct list_head *head)
82{
83 __list_add(new, head, head->next);
84}
85
86/**
87 * list_add_tail - add a new entry
88 * @new: new entry to be added
89 * @head: list head to add it before
90 *
91 * Insert a new entry before the specified head.
92 * This is useful for implementing queues.
93 */
94static inline void list_add_tail(struct list_head *new, struct list_head *head)
95{
96 __list_add(new, head->prev, head);
97}
98
99/*
100 * Delete a list entry by making the prev/next entries
101 * point to each other.
102 *
103 * This is only for internal list manipulation where we know
104 * the prev/next entries already!
105 */
106static inline void __list_del(struct list_head * prev, struct list_head * next)
107{
108 next->prev = prev;
109 prev->next = next;
110}
111
112/**
113 * list_del - deletes entry from list.
114 * @entry: the element to delete from the list.
115 * Note: list_empty on entry does not return true after this, the entry is
116 * in an undefined state.
117 */
118static inline void list_del(struct list_head *entry)
119{
120 __list_del(entry->prev, entry->next);
121 entry->next = LIST_POISON1;
122 entry->prev = LIST_POISON2;
123}
124
125/**
126 * list_del_range - deletes range of entries from list.
127 * @beging: first element in the range to delete from the list.
128 * @beging: first element in the range to delete from the list.
129 * Note: list_empty on the range of entries does not return true after this,
130 * the entries is in an undefined state.
131 */
132static inline void list_del_range(struct list_head *begin,
133 struct list_head *end)
134{
135 begin->prev->next = end->next;
136 end->next->prev = begin->prev;
137}
138
139/**
140 * list_replace - replace old entry by new one
141 * @old : the element to be replaced
142 * @new : the new element to insert
143 * Note: if 'old' was empty, it will be overwritten.
144 */
145static inline void list_replace(struct list_head *old,
146 struct list_head *new)
147{
148 new->next = old->next;
149 new->next->prev = new;
150 new->prev = old->prev;
151 new->prev->next = new;
152}
153
154static inline void list_replace_init(struct list_head *old,
155 struct list_head *new)
156{
157 list_replace(old, new);
158 INIT_LIST_HEAD(old);
159}
160
161/**
162 * list_del_init - deletes entry from list and reinitialize it.
163 * @entry: the element to delete from the list.
164 */
165static inline void list_del_init(struct list_head *entry)
166{
167 __list_del(entry->prev, entry->next);
168 INIT_LIST_HEAD(entry);
169}
170
171/**
172 * list_move - delete from one list and add as another's head
173 * @list: the entry to move
174 * @head: the head that will precede our entry
175 */
176static inline void list_move(struct list_head *list, struct list_head *head)
177{
178 __list_del(list->prev, list->next);
179 list_add(list, head);
180}
181
182/**
183 * list_move_tail - delete from one list and add as another's tail
184 * @list: the entry to move
185 * @head: the head that will follow our entry
186 */
187static inline void list_move_tail(struct list_head *list,
188 struct list_head *head)
189{
190 __list_del(list->prev, list->next);
191 list_add_tail(list, head);
192}
193
194/**
195 * list_is_last - tests whether @list is the last entry in list @head
196 * @list: the entry to test
197 * @head: the head of the list
198 */
199static inline int list_is_last(const struct list_head *list,
200 const struct list_head *head)
201{
202 return list->next == head;
203}
204
205/**
206 * list_empty - tests whether a list is empty
207 * @head: the list to test.
208 */
209static inline int list_empty(const struct list_head *head)
210{
211 return head->next == head;
212}
213
214/**
215 * list_empty_careful - tests whether a list is empty and not being modified
216 * @head: the list to test
217 *
218 * Description:
219 * tests whether a list is empty _and_ checks that no other CPU might be
220 * in the process of modifying either member (next or prev)
221 *
222 * NOTE: using list_empty_careful() without synchronization
223 * can only be safe if the only activity that can happen
224 * to the list entry is list_del_init(). Eg. it cannot be used
225 * if another CPU could re-list_add() it.
226 */
227static inline int list_empty_careful(const struct list_head *head)
228{
229 struct list_head *next = head->next;
230 return (next == head) && (next == head->prev);
231}
232
233static inline void __list_splice(struct list_head *list,
234 struct list_head *head)
235{
236 struct list_head *first = list->next;
237 struct list_head *last = list->prev;
238 struct list_head *at = head->next;
239
240 first->prev = head;
241 head->next = first;
242
243 last->next = at;
244 at->prev = last;
245}
246
247/**
248 * list_splice - join two lists
249 * @list: the new list to add.
250 * @head: the place to add it in the first list.
251 */
252static inline void list_splice(struct list_head *list, struct list_head *head)
253{
254 if (!list_empty(list))
255 __list_splice(list, head);
256}
257
258/**
259 * list_splice_init - join two lists and reinitialise the emptied list.
260 * @list: the new list to add.
261 * @head: the place to add it in the first list.
262 *
263 * The list at @list is reinitialised
264 */
265static inline void list_splice_init(struct list_head *list,
266 struct list_head *head)
267{
268 if (!list_empty(list)) {
269 __list_splice(list, head);
270 INIT_LIST_HEAD(list);
271 }
272}
273
274/**
275 * list_entry - get the struct for this entry
276 * @ptr: the &struct list_head pointer.
277 * @type: the type of the struct this is embedded in.
278 * @member: the name of the list_struct within the struct.
279 */
280#define list_entry(ptr, type, member) \
281 container_of(ptr, type, member)
282
283/**
284 * list_first_entry - get the first element from a list
285 * @ptr: the list head to take the element from.
286 * @type: the type of the struct this is embedded in.
287 * @member: the name of the list_struct within the struct.
288 *
289 * Note, that list is expected to be not empty.
290 */
291#define list_first_entry(ptr, type, member) \
292 list_entry((ptr)->next, type, member)
293
294/**
295 * list_for_each - iterate over a list
296 * @pos: the &struct list_head to use as a loop cursor.
297 * @head: the head for your list.
298 */
299#define list_for_each(pos, head) \
300 for (pos = (head)->next; pos != (head); \
301 pos = pos->next)
302
303/**
304 * __list_for_each - iterate over a list
305 * @pos: the &struct list_head to use as a loop cursor.
306 * @head: the head for your list.
307 *
308 * This variant differs from list_for_each() in that it's the
309 * simplest possible list iteration code, no prefetching is done.
310 * Use this for code that knows the list to be very short (empty
311 * or 1 entry) most of the time.
312 */
313#define __list_for_each(pos, head) \
314 for (pos = (head)->next; pos != (head); pos = pos->next)
315
316/**
317 * list_for_each_prev - iterate over a list backwards
318 * @pos: the &struct list_head to use as a loop cursor.
319 * @head: the head for your list.
320 */
321#define list_for_each_prev(pos, head) \
322 for (pos = (head)->prev; pos != (head); \
323 pos = pos->prev)
324
325/**
326 * list_for_each_safe - iterate over a list safe against removal of list entry
327 * @pos: the &struct list_head to use as a loop cursor.
328 * @n: another &struct list_head to use as temporary storage
329 * @head: the head for your list.
330 */
331#define list_for_each_safe(pos, n, head) \
332 for (pos = (head)->next, n = pos->next; pos != (head); \
333 pos = n, n = pos->next)
334
335/**
336 * list_for_each_entry - iterate over list of given type
337 * @pos: the type * to use as a loop cursor.
338 * @head: the head for your list.
339 * @member: the name of the list_struct within the struct.
340 */
341#define list_for_each_entry(pos, head, member) \
342 for (pos = list_entry((head)->next, typeof(*pos), member); \
343 &pos->member != (head); \
344 pos = list_entry(pos->member.next, typeof(*pos), member))
345
346/**
347 * list_for_each_entry_reverse - iterate backwards over list of given type.
348 * @pos: the type * to use as a loop cursor.
349 * @head: the head for your list.
350 * @member: the name of the list_struct within the struct.
351 */
352#define list_for_each_entry_reverse(pos, head, member) \
353 for (pos = list_entry((head)->prev, typeof(*pos), member); \
354 &pos->member != (head); \
355 pos = list_entry(pos->member.prev, typeof(*pos), member))
356
357/**
358 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
359 * @pos: the type * to use as a start point
360 * @head: the head of the list
361 * @member: the name of the list_struct within the struct.
362 *
363 * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
364 */
365#define list_prepare_entry(pos, head, member) \
366 ((pos) ? : list_entry(head, typeof(*pos), member))
367
368/**
369 * list_for_each_entry_continue - continue iteration over list of given type
370 * @pos: the type * to use as a loop cursor.
371 * @head: the head for your list.
372 * @member: the name of the list_struct within the struct.
373 *
374 * Continue to iterate over list of given type, continuing after
375 * the current position.
376 */
377#define list_for_each_entry_continue(pos, head, member) \
378 for (pos = list_entry(pos->member.next, typeof(*pos), member); \
379 &pos->member != (head); \
380 pos = list_entry(pos->member.next, typeof(*pos), member))
381
382/**
383 * list_for_each_entry_from - iterate over list of given type from the current point
384 * @pos: the type * to use as a loop cursor.
385 * @head: the head for your list.
386 * @member: the name of the list_struct within the struct.
387 *
388 * Iterate over list of given type, continuing from current position.
389 */
390#define list_for_each_entry_from(pos, head, member) \
391 for (; &pos->member != (head); \
392 pos = list_entry(pos->member.next, typeof(*pos), member))
393
394/**
395 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
396 * @pos: the type * to use as a loop cursor.
397 * @n: another type * to use as temporary storage
398 * @head: the head for your list.
399 * @member: the name of the list_struct within the struct.
400 */
401#define list_for_each_entry_safe(pos, n, head, member) \
402 for (pos = list_entry((head)->next, typeof(*pos), member), \
403 n = list_entry(pos->member.next, typeof(*pos), member); \
404 &pos->member != (head); \
405 pos = n, n = list_entry(n->member.next, typeof(*n), member))
406
407/**
408 * list_for_each_entry_safe_continue
409 * @pos: the type * to use as a loop cursor.
410 * @n: another type * to use as temporary storage
411 * @head: the head for your list.
412 * @member: the name of the list_struct within the struct.
413 *
414 * Iterate over list of given type, continuing after current point,
415 * safe against removal of list entry.
416 */
417#define list_for_each_entry_safe_continue(pos, n, head, member) \
418 for (pos = list_entry(pos->member.next, typeof(*pos), member), \
419 n = list_entry(pos->member.next, typeof(*pos), member); \
420 &pos->member != (head); \
421 pos = n, n = list_entry(n->member.next, typeof(*n), member))
422
423/**
424 * list_for_each_entry_safe_from
425 * @pos: the type * to use as a loop cursor.
426 * @n: another type * to use as temporary storage
427 * @head: the head for your list.
428 * @member: the name of the list_struct within the struct.
429 *
430 * Iterate over list of given type from current point, safe against
431 * removal of list entry.
432 */
433#define list_for_each_entry_safe_from(pos, n, head, member) \
434 for (n = list_entry(pos->member.next, typeof(*pos), member); \
435 &pos->member != (head); \
436 pos = n, n = list_entry(n->member.next, typeof(*n), member))
437
438/**
439 * list_for_each_entry_safe_reverse
440 * @pos: the type * to use as a loop cursor.
441 * @n: another type * to use as temporary storage
442 * @head: the head for your list.
443 * @member: the name of the list_struct within the struct.
444 *
445 * Iterate backwards over list of given type, safe against removal
446 * of list entry.
447 */
448#define list_for_each_entry_safe_reverse(pos, n, head, member) \
449 for (pos = list_entry((head)->prev, typeof(*pos), member), \
450 n = list_entry(pos->member.prev, typeof(*pos), member); \
451 &pos->member != (head); \
452 pos = n, n = list_entry(n->member.prev, typeof(*n), member))
453
454/*
455 * Double linked lists with a single pointer list head.
456 * Mostly useful for hash tables where the two pointer list head is
457 * too wasteful.
458 * You lose the ability to access the tail in O(1).
459 */
460
461struct hlist_head {
462 struct hlist_node *first;
463};
464
465struct hlist_node {
466 struct hlist_node *next, **pprev;
467};
468
469#define HLIST_HEAD_INIT { .first = NULL }
470#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
471#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
472static inline void INIT_HLIST_NODE(struct hlist_node *h)
473{
474 h->next = NULL;
475 h->pprev = NULL;
476}
477
478static inline int hlist_unhashed(const struct hlist_node *h)
479{
480 return !h->pprev;
481}
482
483static inline int hlist_empty(const struct hlist_head *h)
484{
485 return !h->first;
486}
487
488static inline void __hlist_del(struct hlist_node *n)
489{
490 struct hlist_node *next = n->next;
491 struct hlist_node **pprev = n->pprev;
492 *pprev = next;
493 if (next)
494 next->pprev = pprev;
495}
496
497static inline void hlist_del(struct hlist_node *n)
498{
499 __hlist_del(n);
500 n->next = LIST_POISON1;
501 n->pprev = LIST_POISON2;
502}
503
504static inline void hlist_del_init(struct hlist_node *n)
505{
506 if (!hlist_unhashed(n)) {
507 __hlist_del(n);
508 INIT_HLIST_NODE(n);
509 }
510}
511
512static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
513{
514 struct hlist_node *first = h->first;
515 n->next = first;
516 if (first)
517 first->pprev = &n->next;
518 h->first = n;
519 n->pprev = &h->first;
520}
521
522/* next must be != NULL */
523static inline void hlist_add_before(struct hlist_node *n,
524 struct hlist_node *next)
525{
526 n->pprev = next->pprev;
527 n->next = next;
528 next->pprev = &n->next;
529 *(n->pprev) = n;
530}
531
532static inline void hlist_add_after(struct hlist_node *n,
533 struct hlist_node *next)
534{
535 next->next = n->next;
536 n->next = next;
537 next->pprev = &n->next;
538
539 if(next->next)
540 next->next->pprev = &next->next;
541}
542
543#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
544
545#define hlist_for_each(pos, head) \
546 for (pos = (head)->first; pos; \
547 pos = pos->next)
548
549#define hlist_for_each_safe(pos, n, head) \
550 for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
551 pos = n)
552
553/**
554 * hlist_for_each_entry - iterate over list of given type
555 * @tpos: the type * to use as a loop cursor.
556 * @pos: the &struct hlist_node to use as a loop cursor.
557 * @head: the head for your list.
558 * @member: the name of the hlist_node within the struct.
559 */
560#define hlist_for_each_entry(tpos, pos, head, member) \
561 for (pos = (head)->first; \
562 pos && \
563 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
564 pos = pos->next)
565
566/**
567 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
568 * @tpos: the type * to use as a loop cursor.
569 * @pos: the &struct hlist_node to use as a loop cursor.
570 * @member: the name of the hlist_node within the struct.
571 */
572#define hlist_for_each_entry_continue(tpos, pos, member) \
573 for (pos = (pos)->next; \
574 pos && \
575 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
576 pos = pos->next)
577
578/**
579 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
580 * @tpos: the type * to use as a loop cursor.
581 * @pos: the &struct hlist_node to use as a loop cursor.
582 * @member: the name of the hlist_node within the struct.
583 */
584#define hlist_for_each_entry_from(tpos, pos, member) \
585 for (; pos && \
586 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
587 pos = pos->next)
588
589/**
590 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
591 * @tpos: the type * to use as a loop cursor.
592 * @pos: the &struct hlist_node to use as a loop cursor.
593 * @n: another &struct hlist_node to use as temporary storage
594 * @head: the head for your list.
595 * @member: the name of the hlist_node within the struct.
596 */
597#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
598 for (pos = (head)->first; \
599 pos && ({ n = pos->next; 1; }) && \
600 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
601 pos = n)
602
603#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
new file mode 100644
index 000000000000..804e02382739
--- /dev/null
+++ b/tools/perf/util/map.c
@@ -0,0 +1,97 @@
1#include "event.h"
2#include "symbol.h"
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6
7static inline int is_anon_memory(const char *filename)
8{
9 return strcmp(filename, "//anon") == 0;
10}
11
12static int strcommon(const char *pathname, char *cwd, int cwdlen)
13{
14 int n = 0;
15
16 while (n < cwdlen && pathname[n] == cwd[n])
17 ++n;
18
19 return n;
20}
21
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
23{
24 struct map *self = malloc(sizeof(*self));
25
26 if (self != NULL) {
27 const char *filename = event->filename;
28 char newfilename[PATH_MAX];
29 int anon;
30
31 if (cwd) {
32 int n = strcommon(filename, cwd, cwdlen);
33
34 if (n == cwdlen) {
35 snprintf(newfilename, sizeof(newfilename),
36 ".%s", filename + n);
37 filename = newfilename;
38 }
39 }
40
41 anon = is_anon_memory(filename);
42
43 if (anon) {
44 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
45 filename = newfilename;
46 }
47
48 self->start = event->start;
49 self->end = event->start + event->len;
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete;
55
56 if (self->dso == vdso || anon)
57 self->map_ip = vdso__map_ip;
58 else
59 self->map_ip = map__map_ip;
60 }
61 return self;
62out_delete:
63 free(self);
64 return NULL;
65}
66
67struct map *map__clone(struct map *self)
68{
69 struct map *map = malloc(sizeof(*self));
70
71 if (!map)
72 return NULL;
73
74 memcpy(map, self, sizeof(*self));
75
76 return map;
77}
78
79int map__overlap(struct map *l, struct map *r)
80{
81 if (l->start > r->start) {
82 struct map *t = l;
83 l = r;
84 r = t;
85 }
86
87 if (l->end > r->start)
88 return 1;
89
90 return 0;
91}
92
93size_t map__fprintf(struct map *self, FILE *fp)
94{
95 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
96 self->start, self->end, self->pgoff, self->dso->name);
97}
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
new file mode 100644
index 000000000000..3d567fe59c79
--- /dev/null
+++ b/tools/perf/util/module.c
@@ -0,0 +1,509 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <gelf.h>
8#include <elf.h>
9#include <dirent.h>
10#include <sys/utsname.h>
11
12static unsigned int crc32(const char *p, unsigned int len)
13{
14 int i;
15 unsigned int crc = 0;
16
17 while (len--) {
18 crc ^= *p++;
19 for (i = 0; i < 8; i++)
20 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
21 }
22 return crc;
23}
24
25/* module section methods */
26
27struct sec_dso *sec_dso__new_dso(const char *name)
28{
29 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
30
31 if (self != NULL) {
32 strcpy(self->name, name);
33 self->secs = RB_ROOT;
34 self->find_section = sec_dso__find_section;
35 }
36
37 return self;
38}
39
40static void sec_dso__delete_section(struct section *self)
41{
42 free(((void *)self));
43}
44
45void sec_dso__delete_sections(struct sec_dso *self)
46{
47 struct section *pos;
48 struct rb_node *next = rb_first(&self->secs);
49
50 while (next) {
51 pos = rb_entry(next, struct section, rb_node);
52 next = rb_next(&pos->rb_node);
53 rb_erase(&pos->rb_node, &self->secs);
54 sec_dso__delete_section(pos);
55 }
56}
57
58void sec_dso__delete_self(struct sec_dso *self)
59{
60 sec_dso__delete_sections(self);
61 free(self);
62}
63
64static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
65{
66 struct rb_node **p = &self->secs.rb_node;
67 struct rb_node *parent = NULL;
68 const u64 hash = sec->hash;
69 struct section *s;
70
71 while (*p != NULL) {
72 parent = *p;
73 s = rb_entry(parent, struct section, rb_node);
74 if (hash < s->hash)
75 p = &(*p)->rb_left;
76 else
77 p = &(*p)->rb_right;
78 }
79 rb_link_node(&sec->rb_node, parent, p);
80 rb_insert_color(&sec->rb_node, &self->secs);
81}
82
83struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
84{
85 struct rb_node *n;
86 u64 hash;
87 int len;
88
89 if (self == NULL)
90 return NULL;
91
92 len = strlen(name);
93 hash = crc32(name, len);
94
95 n = self->secs.rb_node;
96
97 while (n) {
98 struct section *s = rb_entry(n, struct section, rb_node);
99
100 if (hash < s->hash)
101 n = n->rb_left;
102 else if (hash > s->hash)
103 n = n->rb_right;
104 else {
105 if (!strcmp(name, s->name))
106 return s;
107 else
108 n = rb_next(&s->rb_node);
109 }
110 }
111
112 return NULL;
113}
114
115static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
116{
117 return fprintf(fp, "name:%s vma:%llx path:%s\n",
118 self->name, self->vma, self->path);
119}
120
121size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
122{
123 size_t ret = fprintf(fp, "dso: %s\n", self->name);
124
125 struct rb_node *nd;
126 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
127 struct section *pos = rb_entry(nd, struct section, rb_node);
128 ret += sec_dso__fprintf_section(pos, fp);
129 }
130
131 return ret;
132}
133
134static struct section *section__new(const char *name, const char *path)
135{
136 struct section *self = calloc(1, sizeof(*self));
137
138 if (!self)
139 goto out_failure;
140
141 self->name = calloc(1, strlen(name) + 1);
142 if (!self->name)
143 goto out_failure;
144
145 self->path = calloc(1, strlen(path) + 1);
146 if (!self->path)
147 goto out_failure;
148
149 strcpy(self->name, name);
150 strcpy(self->path, path);
151 self->hash = crc32(self->name, strlen(name));
152
153 return self;
154
155out_failure:
156 if (self) {
157 if (self->name)
158 free(self->name);
159 if (self->path)
160 free(self->path);
161 free(self);
162 }
163
164 return NULL;
165}
166
167/* module methods */
168
169struct mod_dso *mod_dso__new_dso(const char *name)
170{
171 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
172
173 if (self != NULL) {
174 strcpy(self->name, name);
175 self->mods = RB_ROOT;
176 self->find_module = mod_dso__find_module;
177 }
178
179 return self;
180}
181
182static void mod_dso__delete_module(struct module *self)
183{
184 free(((void *)self));
185}
186
187void mod_dso__delete_modules(struct mod_dso *self)
188{
189 struct module *pos;
190 struct rb_node *next = rb_first(&self->mods);
191
192 while (next) {
193 pos = rb_entry(next, struct module, rb_node);
194 next = rb_next(&pos->rb_node);
195 rb_erase(&pos->rb_node, &self->mods);
196 mod_dso__delete_module(pos);
197 }
198}
199
200void mod_dso__delete_self(struct mod_dso *self)
201{
202 mod_dso__delete_modules(self);
203 free(self);
204}
205
206static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
207{
208 struct rb_node **p = &self->mods.rb_node;
209 struct rb_node *parent = NULL;
210 const u64 hash = mod->hash;
211 struct module *m;
212
213 while (*p != NULL) {
214 parent = *p;
215 m = rb_entry(parent, struct module, rb_node);
216 if (hash < m->hash)
217 p = &(*p)->rb_left;
218 else
219 p = &(*p)->rb_right;
220 }
221 rb_link_node(&mod->rb_node, parent, p);
222 rb_insert_color(&mod->rb_node, &self->mods);
223}
224
225struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
226{
227 struct rb_node *n;
228 u64 hash;
229 int len;
230
231 if (self == NULL)
232 return NULL;
233
234 len = strlen(name);
235 hash = crc32(name, len);
236
237 n = self->mods.rb_node;
238
239 while (n) {
240 struct module *m = rb_entry(n, struct module, rb_node);
241
242 if (hash < m->hash)
243 n = n->rb_left;
244 else if (hash > m->hash)
245 n = n->rb_right;
246 else {
247 if (!strcmp(name, m->name))
248 return m;
249 else
250 n = rb_next(&m->rb_node);
251 }
252 }
253
254 return NULL;
255}
256
257static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
258{
259 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
260}
261
262size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
263{
264 struct rb_node *nd;
265 size_t ret;
266
267 ret = fprintf(fp, "dso: %s\n", self->name);
268
269 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
270 struct module *pos = rb_entry(nd, struct module, rb_node);
271
272 ret += mod_dso__fprintf_module(pos, fp);
273 }
274
275 return ret;
276}
277
278static struct module *module__new(const char *name, const char *path)
279{
280 struct module *self = calloc(1, sizeof(*self));
281
282 if (!self)
283 goto out_failure;
284
285 self->name = calloc(1, strlen(name) + 1);
286 if (!self->name)
287 goto out_failure;
288
289 self->path = calloc(1, strlen(path) + 1);
290 if (!self->path)
291 goto out_failure;
292
293 strcpy(self->name, name);
294 strcpy(self->path, path);
295 self->hash = crc32(self->name, strlen(name));
296
297 return self;
298
299out_failure:
300 if (self) {
301 if (self->name)
302 free(self->name);
303 if (self->path)
304 free(self->path);
305 free(self);
306 }
307
308 return NULL;
309}
310
311static int mod_dso__load_sections(struct module *mod)
312{
313 int count = 0, path_len;
314 struct dirent *entry;
315 char *line = NULL;
316 char *dir_path;
317 DIR *dir;
318 size_t n;
319
320 path_len = strlen("/sys/module/");
321 path_len += strlen(mod->name);
322 path_len += strlen("/sections/");
323
324 dir_path = calloc(1, path_len + 1);
325 if (dir_path == NULL)
326 goto out_failure;
327
328 strcat(dir_path, "/sys/module/");
329 strcat(dir_path, mod->name);
330 strcat(dir_path, "/sections/");
331
332 dir = opendir(dir_path);
333 if (dir == NULL)
334 goto out_free;
335
336 while ((entry = readdir(dir))) {
337 struct section *section;
338 char *path, *vma;
339 int line_len;
340 FILE *file;
341
342 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
343 continue;
344
345 path = calloc(1, path_len + strlen(entry->d_name) + 1);
346 if (path == NULL)
347 break;
348 strcat(path, dir_path);
349 strcat(path, entry->d_name);
350
351 file = fopen(path, "r");
352 if (file == NULL) {
353 free(path);
354 break;
355 }
356
357 line_len = getline(&line, &n, file);
358 if (line_len < 0) {
359 free(path);
360 fclose(file);
361 break;
362 }
363
364 if (!line) {
365 free(path);
366 fclose(file);
367 break;
368 }
369
370 line[--line_len] = '\0'; /* \n */
371
372 vma = strstr(line, "0x");
373 if (!vma) {
374 free(path);
375 fclose(file);
376 break;
377 }
378 vma += 2;
379
380 section = section__new(entry->d_name, path);
381 if (!section) {
382 fprintf(stderr, "load_sections: allocation error\n");
383 free(path);
384 fclose(file);
385 break;
386 }
387
388 hex2u64(vma, &section->vma);
389 sec_dso__insert_section(mod->sections, section);
390
391 free(path);
392 fclose(file);
393 count++;
394 }
395
396 closedir(dir);
397 free(line);
398 free(dir_path);
399
400 return count;
401
402out_free:
403 free(dir_path);
404
405out_failure:
406 return count;
407}
408
409static int mod_dso__load_module_paths(struct mod_dso *self)
410{
411 struct utsname uts;
412 int count = 0, len;
413 char *line = NULL;
414 FILE *file;
415 char *path;
416 size_t n;
417
418 if (uname(&uts) < 0)
419 goto out_failure;
420
421 len = strlen("/lib/modules/");
422 len += strlen(uts.release);
423 len += strlen("/modules.dep");
424
425 path = calloc(1, len);
426 if (path == NULL)
427 goto out_failure;
428
429 strcat(path, "/lib/modules/");
430 strcat(path, uts.release);
431 strcat(path, "/modules.dep");
432
433 file = fopen(path, "r");
434 free(path);
435 if (file == NULL)
436 goto out_failure;
437
438 while (!feof(file)) {
439 char *name, *tmp;
440 struct module *module;
441 int line_len;
442
443 line_len = getline(&line, &n, file);
444 if (line_len < 0)
445 break;
446
447 if (!line)
448 goto out_failure;
449
450 line[--line_len] = '\0'; /* \n */
451
452 path = strtok(line, ":");
453 if (!path)
454 goto out_failure;
455
456 name = strdup(path);
457 name = strtok(name, "/");
458
459 tmp = name;
460
461 while (tmp) {
462 tmp = strtok(NULL, "/");
463 if (tmp)
464 name = tmp;
465 }
466 name = strsep(&name, ".");
467
468 /* Quirk: replace '-' with '_' in sound modules */
469 for (len = strlen(name); len; len--) {
470 if (*(name+len) == '-')
471 *(name+len) = '_';
472 }
473
474 module = module__new(name, path);
475 if (!module) {
476 fprintf(stderr, "load_module_paths: allocation error\n");
477 goto out_failure;
478 }
479 mod_dso__insert_module(self, module);
480
481 module->sections = sec_dso__new_dso("sections");
482 if (!module->sections) {
483 fprintf(stderr, "load_module_paths: allocation error\n");
484 goto out_failure;
485 }
486
487 module->active = mod_dso__load_sections(module);
488
489 if (module->active > 0)
490 count++;
491 }
492
493 free(line);
494 fclose(file);
495
496 return count;
497
498out_failure:
499 return -1;
500}
501
502int mod_dso__load_modules(struct mod_dso *dso)
503{
504 int err;
505
506 err = mod_dso__load_module_paths(dso);
507
508 return err;
509}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
new file mode 100644
index 000000000000..8a592ef641ca
--- /dev/null
+++ b/tools/perf/util/module.h
@@ -0,0 +1,53 @@
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/pager.c b/tools/perf/util/pager.c
index a28bccae5458..1915de20dcac 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -9,7 +9,6 @@
9 9
10static int spawned_pager; 10static int spawned_pager;
11 11
12#ifndef __MINGW32__
13static void pager_preexec(void) 12static void pager_preexec(void)
14{ 13{
15 /* 14 /*
@@ -24,7 +23,6 @@ static void pager_preexec(void)
24 23
25 setenv("LESS", "FRSX", 0); 24 setenv("LESS", "FRSX", 0);
26} 25}
27#endif
28 26
29static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; 27static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
30static struct child_process pager_process; 28static struct child_process pager_process;
@@ -70,9 +68,8 @@ void setup_pager(void)
70 pager_argv[2] = pager; 68 pager_argv[2] = pager;
71 pager_process.argv = pager_argv; 69 pager_process.argv = pager_argv;
72 pager_process.in = -1; 70 pager_process.in = -1;
73#ifndef __MINGW32__
74 pager_process.preexec_cb = pager_preexec; 71 pager_process.preexec_cb = pager_preexec;
75#endif 72
76 if (start_command(&pager_process)) 73 if (start_command(&pager_process))
77 return; 74 return;
78 75
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 35d04da38d6a..13ab4b842d49 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,58 +1,62 @@
1 1
2#include "../perf.h"
3#include "util.h" 2#include "util.h"
3#include "../perf.h"
4#include "parse-options.h" 4#include "parse-options.h"
5#include "parse-events.h" 5#include "parse-events.h"
6#include "exec_cmd.h" 6#include "exec_cmd.h"
7#include "string.h" 7#include "string.h"
8 8#include "cache.h"
9extern char *strcasestr(const char *haystack, const char *needle); 9#include "header.h"
10 10
11int nr_counters; 11int nr_counters;
12 12
13struct perf_counter_attr attrs[MAX_COUNTERS]; 13struct perf_event_attr attrs[MAX_COUNTERS];
14 14
15struct event_symbol { 15struct event_symbol {
16 u8 type; 16 u8 type;
17 u64 config; 17 u64 config;
18 char *symbol; 18 const char *symbol;
19 const char *alias;
20};
21
22enum event_result {
23 EVT_FAILED,
24 EVT_HANDLED,
25 EVT_HANDLED_ALL
19}; 26};
20 27
21#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y 28char debugfs_path[MAXPATHLEN];
22#define CR(x, y) .type = PERF_TYPE_##x, .config = y 29
30#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
31#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
23 32
24static struct event_symbol event_symbols[] = { 33static struct event_symbol event_symbols[] = {
25 { C(HARDWARE, HW_CPU_CYCLES), "cpu-cycles", }, 34 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
26 { C(HARDWARE, HW_CPU_CYCLES), "cycles", }, 35 { CHW(INSTRUCTIONS), "instructions", "" },
27 { C(HARDWARE, HW_INSTRUCTIONS), "instructions", }, 36 { CHW(CACHE_REFERENCES), "cache-references", "" },
28 { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", }, 37 { CHW(CACHE_MISSES), "cache-misses", "" },
29 { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", }, 38 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
30 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", }, 39 { CHW(BRANCH_MISSES), "branch-misses", "" },
31 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", }, 40 { CHW(BUS_CYCLES), "bus-cycles", "" },
32 { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", }, 41
33 { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", }, 42 { CSW(CPU_CLOCK), "cpu-clock", "" },
34 43 { CSW(TASK_CLOCK), "task-clock", "" },
35 { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", }, 44 { CSW(PAGE_FAULTS), "page-faults", "faults" },
36 { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", }, 45 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
37 { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", }, 46 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
38 { C(SOFTWARE, SW_PAGE_FAULTS), "faults", }, 47 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
39 { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", }, 48 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
40 { C(SOFTWARE, SW_PAGE_FAULTS_MAJ), "major-faults", },
41 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "context-switches", },
42 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "cs", },
43 { C(SOFTWARE, SW_CPU_MIGRATIONS), "cpu-migrations", },
44 { C(SOFTWARE, SW_CPU_MIGRATIONS), "migrations", },
45}; 49};
46 50
47#define __PERF_COUNTER_FIELD(config, name) \ 51#define __PERF_EVENT_FIELD(config, name) \
48 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) 52 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT)
49 53
50#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) 54#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW)
51#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) 55#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG)
52#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) 56#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
53#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) 57#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
54 58
55static char *hw_event_names[] = { 59static const char *hw_event_names[] = {
56 "cycles", 60 "cycles",
57 "instructions", 61 "instructions",
58 "cache-references", 62 "cache-references",
@@ -62,7 +66,7 @@ static char *hw_event_names[] = {
62 "bus-cycles", 66 "bus-cycles",
63}; 67};
64 68
65static char *sw_event_names[] = { 69static const char *sw_event_names[] = {
66 "cpu-clock-msecs", 70 "cpu-clock-msecs",
67 "task-clock-msecs", 71 "task-clock-msecs",
68 "page-faults", 72 "page-faults",
@@ -74,33 +78,213 @@ static char *sw_event_names[] = {
74 78
75#define MAX_ALIASES 8 79#define MAX_ALIASES 8
76 80
77static char *hw_cache [][MAX_ALIASES] = { 81static const char *hw_cache[][MAX_ALIASES] = {
78 { "L1-data" , "l1-d", "l1d" }, 82 { "L1-dcache", "l1-d", "l1d", "L1-data", },
79 { "L1-instruction" , "l1-i", "l1i" }, 83 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
80 { "L2" , "l2" }, 84 { "LLC", "L2" },
81 { "Data-TLB" , "dtlb", "d-tlb" }, 85 { "dTLB", "d-tlb", "Data-TLB", },
82 { "Instruction-TLB" , "itlb", "i-tlb" }, 86 { "iTLB", "i-tlb", "Instruction-TLB", },
83 { "Branch" , "bpu" , "btb", "bpc" }, 87 { "branch", "branches", "bpu", "btb", "bpc", },
88};
89
90static const char *hw_cache_op[][MAX_ALIASES] = {
91 { "load", "loads", "read", },
92 { "store", "stores", "write", },
93 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
84}; 94};
85 95
86static char *hw_cache_op [][MAX_ALIASES] = { 96static const char *hw_cache_result[][MAX_ALIASES] = {
87 { "Load" , "read" }, 97 { "refs", "Reference", "ops", "access", },
88 { "Store" , "write" }, 98 { "misses", "miss", },
89 { "Prefetch" , "speculative-read", "speculative-load" },
90}; 99};
91 100
92static char *hw_cache_result [][MAX_ALIASES] = { 101#define C(x) PERF_COUNT_HW_CACHE_##x
93 { "Reference" , "ops", "access" }, 102#define CACHE_READ (1 << C(OP_READ))
94 { "Miss" }, 103#define CACHE_WRITE (1 << C(OP_WRITE))
104#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
105#define COP(x) (1 << x)
106
107/*
108 * cache operartion stat
109 * L1I : Read and prefetch only
110 * ITLB and BPU : Read-only
111 */
112static unsigned long hw_cache_stat[C(MAX)] = {
113 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
114 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
115 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
116 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
117 [C(ITLB)] = (CACHE_READ),
118 [C(BPU)] = (CACHE_READ),
95}; 119};
96 120
97char *event_name(int counter) 121#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
122 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
123 if (sys_dirent.d_type == DT_DIR && \
124 (strcmp(sys_dirent.d_name, ".")) && \
125 (strcmp(sys_dirent.d_name, "..")))
126
127static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
128{
129 char evt_path[MAXPATHLEN];
130 int fd;
131
132 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
133 sys_dir->d_name, evt_dir->d_name);
134 fd = open(evt_path, O_RDONLY);
135 if (fd < 0)
136 return -EINVAL;
137 close(fd);
138
139 return 0;
140}
141
142#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \
143 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
144 if (evt_dirent.d_type == DT_DIR && \
145 (strcmp(evt_dirent.d_name, ".")) && \
146 (strcmp(evt_dirent.d_name, "..")) && \
147 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
148
149#define MAX_EVENT_LENGTH 512
150
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
162struct tracepoint_path *tracepoint_id_to_path(u64 config)
163{
164 struct tracepoint_path *path = NULL;
165 DIR *sys_dir, *evt_dir;
166 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
167 char id_buf[4];
168 int sys_dir_fd, fd;
169 u64 id;
170 char evt_path[MAXPATHLEN];
171
172 if (valid_debugfs_mount(debugfs_path))
173 return NULL;
174
175 sys_dir = opendir(debugfs_path);
176 if (!sys_dir)
177 goto cleanup;
178 sys_dir_fd = dirfd(sys_dir);
179
180 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
181 int dfd = openat(sys_dir_fd, sys_dirent.d_name,
182 O_RDONLY|O_DIRECTORY), evt_dir_fd;
183 if (dfd == -1)
184 continue;
185 evt_dir = fdopendir(dfd);
186 if (!evt_dir) {
187 close(dfd);
188 continue;
189 }
190 evt_dir_fd = dirfd(evt_dir);
191 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
192 snprintf(evt_path, MAXPATHLEN, "%s/id",
193 evt_dirent.d_name);
194 fd = openat(evt_dir_fd, evt_path, O_RDONLY);
195 if (fd < 0)
196 continue;
197 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
198 close(fd);
199 continue;
200 }
201 close(fd);
202 id = atoll(id_buf);
203 if (id == config) {
204 closedir(evt_dir);
205 closedir(sys_dir);
206 path = calloc(1, sizeof(path));
207 path->system = malloc(MAX_EVENT_LENGTH);
208 if (!path->system) {
209 free(path);
210 return NULL;
211 }
212 path->name = malloc(MAX_EVENT_LENGTH);
213 if (!path->name) {
214 free(path->system);
215 free(path);
216 return NULL;
217 }
218 strncpy(path->system, sys_dirent.d_name,
219 MAX_EVENT_LENGTH);
220 strncpy(path->name, evt_dirent.d_name,
221 MAX_EVENT_LENGTH);
222 return path;
223 }
224 }
225 closedir(evt_dir);
226 }
227
228cleanup:
229 closedir(sys_dir);
230 return NULL;
231}
232
233#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
234static const char *tracepoint_id_to_name(u64 config)
235{
236 static char buf[TP_PATH_LEN];
237 struct tracepoint_path *path;
238
239 path = tracepoint_id_to_path(config);
240 if (path) {
241 snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
242 free(path->name);
243 free(path->system);
244 free(path);
245 } else
246 snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
247
248 return buf;
249}
250
251static int is_cache_op_valid(u8 cache_type, u8 cache_op)
252{
253 if (hw_cache_stat[cache_type] & COP(cache_op))
254 return 1; /* valid */
255 else
256 return 0; /* invalid */
257}
258
259static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
260{
261 static char name[50];
262
263 if (cache_result) {
264 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
265 hw_cache_op[cache_op][0],
266 hw_cache_result[cache_result][0]);
267 } else {
268 sprintf(name, "%s-%s", hw_cache[cache_type][0],
269 hw_cache_op[cache_op][1]);
270 }
271
272 return name;
273}
274
275const char *event_name(int counter)
98{ 276{
99 u64 config = attrs[counter].config; 277 u64 config = attrs[counter].config;
100 int type = attrs[counter].type; 278 int type = attrs[counter].type;
279
280 return __event_name(type, config);
281}
282
283const char *__event_name(int type, u64 config)
284{
101 static char buf[32]; 285 static char buf[32];
102 286
103 if (attrs[counter].type == PERF_TYPE_RAW) { 287 if (type == PERF_TYPE_RAW) {
104 sprintf(buf, "raw 0x%llx", config); 288 sprintf(buf, "raw 0x%llx", config);
105 return buf; 289 return buf;
106 } 290 }
@@ -113,7 +297,6 @@ char *event_name(int counter)
113 297
114 case PERF_TYPE_HW_CACHE: { 298 case PERF_TYPE_HW_CACHE: {
115 u8 cache_type, cache_op, cache_result; 299 u8 cache_type, cache_op, cache_result;
116 static char name[100];
117 300
118 cache_type = (config >> 0) & 0xff; 301 cache_type = (config >> 0) & 0xff;
119 if (cache_type > PERF_COUNT_HW_CACHE_MAX) 302 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
@@ -127,12 +310,10 @@ char *event_name(int counter)
127 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) 310 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
128 return "unknown-ext-hardware-cache-result"; 311 return "unknown-ext-hardware-cache-result";
129 312
130 sprintf(name, "%s-Cache-%s-%ses", 313 if (!is_cache_op_valid(cache_type, cache_op))
131 hw_cache[cache_type][0], 314 return "invalid-cache";
132 hw_cache_op[cache_op][0],
133 hw_cache_result[cache_result][0]);
134 315
135 return name; 316 return event_cache_name(cache_type, cache_op, cache_result);
136 } 317 }
137 318
138 case PERF_TYPE_SOFTWARE: 319 case PERF_TYPE_SOFTWARE:
@@ -140,6 +321,9 @@ char *event_name(int counter)
140 return sw_event_names[config]; 321 return sw_event_names[config];
141 return "unknown-software"; 322 return "unknown-software";
142 323
324 case PERF_TYPE_TRACEPOINT:
325 return tracepoint_id_to_name(config);
326
143 default: 327 default:
144 break; 328 break;
145 } 329 }
@@ -147,43 +331,74 @@ char *event_name(int counter)
147 return "unknown"; 331 return "unknown";
148} 332}
149 333
150static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) 334static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
151{ 335{
152 int i, j; 336 int i, j;
337 int n, longest = -1;
153 338
154 for (i = 0; i < size; i++) { 339 for (i = 0; i < size; i++) {
155 for (j = 0; j < MAX_ALIASES; j++) { 340 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
156 if (!names[i][j]) 341 n = strlen(names[i][j]);
157 break; 342 if (n > longest && !strncasecmp(*str, names[i][j], n))
158 if (strcasestr(str, names[i][j])) 343 longest = n;
159 return i; 344 }
345 if (longest > 0) {
346 *str += longest;
347 return i;
160 } 348 }
161 } 349 }
162 350
163 return -1; 351 return -1;
164} 352}
165 353
166static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) 354static enum event_result
355parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
167{ 356{
168 int cache_type = -1, cache_op = 0, cache_result = 0; 357 const char *s = *str;
358 int cache_type = -1, cache_op = -1, cache_result = -1;
169 359
170 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); 360 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
171 /* 361 /*
172 * No fallback - if we cannot get a clear cache type 362 * No fallback - if we cannot get a clear cache type
173 * then bail out: 363 * then bail out:
174 */ 364 */
175 if (cache_type == -1) 365 if (cache_type == -1)
176 return -EINVAL; 366 return EVT_FAILED;
367
368 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
369 ++s;
370
371 if (cache_op == -1) {
372 cache_op = parse_aliases(&s, hw_cache_op,
373 PERF_COUNT_HW_CACHE_OP_MAX);
374 if (cache_op >= 0) {
375 if (!is_cache_op_valid(cache_type, cache_op))
376 return 0;
377 continue;
378 }
379 }
380
381 if (cache_result == -1) {
382 cache_result = parse_aliases(&s, hw_cache_result,
383 PERF_COUNT_HW_CACHE_RESULT_MAX);
384 if (cache_result >= 0)
385 continue;
386 }
387
388 /*
389 * Can't parse this as a cache op or result, so back up
390 * to the '-'.
391 */
392 --s;
393 break;
394 }
177 395
178 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
179 /* 396 /*
180 * Fall back to reads: 397 * Fall back to reads:
181 */ 398 */
182 if (cache_op == -1) 399 if (cache_op == -1)
183 cache_op = PERF_COUNT_HW_CACHE_OP_READ; 400 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
184 401
185 cache_result = parse_aliases(str, hw_cache_result,
186 PERF_COUNT_HW_CACHE_RESULT_MAX);
187 /* 402 /*
188 * Fall back to accesses: 403 * Fall back to accesses:
189 */ 404 */
@@ -193,82 +408,338 @@ static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *a
193 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 408 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
194 attr->type = PERF_TYPE_HW_CACHE; 409 attr->type = PERF_TYPE_HW_CACHE;
195 410
196 return 0; 411 *str = s;
412 return EVT_HANDLED;
197} 413}
198 414
199/* 415static enum event_result
200 * Each event can have multiple symbolic names. 416parse_single_tracepoint_event(char *sys_name,
201 * Symbolic names are (almost) exactly matched. 417 const char *evt_name,
202 */ 418 unsigned int evt_length,
203static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) 419 char *flags,
420 struct perf_event_attr *attr,
421 const char **strp)
204{ 422{
205 u64 config, id; 423 char evt_path[MAXPATHLEN];
206 int type; 424 char id_buf[4];
207 unsigned int i; 425 u64 id;
208 const char *sep, *pstr; 426 int fd;
427
428 if (flags) {
429 if (!strncmp(flags, "record", strlen(flags))) {
430 attr->sample_type |= PERF_SAMPLE_RAW;
431 attr->sample_type |= PERF_SAMPLE_TIME;
432 attr->sample_type |= PERF_SAMPLE_CPU;
433 }
434 }
209 435
210 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { 436 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
211 attr->type = PERF_TYPE_RAW; 437 sys_name, evt_name);
212 attr->config = config;
213 438
214 return 0; 439 fd = open(evt_path, O_RDONLY);
440 if (fd < 0)
441 return EVT_FAILED;
442
443 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
444 close(fd);
445 return EVT_FAILED;
446 }
447
448 close(fd);
449 id = atoll(id_buf);
450 attr->config = id;
451 attr->type = PERF_TYPE_TRACEPOINT;
452 *strp = evt_name + evt_length;
453
454 return EVT_HANDLED;
455}
456
457/* sys + ':' + event + ':' + flags*/
458#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
459static enum event_result
460parse_subsystem_tracepoint_event(char *sys_name, char *flags)
461{
462 char evt_path[MAXPATHLEN];
463 struct dirent *evt_ent;
464 DIR *evt_dir;
465
466 snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name);
467 evt_dir = opendir(evt_path);
468
469 if (!evt_dir) {
470 perror("Can't open event dir");
471 return EVT_FAILED;
215 } 472 }
216 473
217 pstr = str; 474 while ((evt_ent = readdir(evt_dir))) {
218 sep = strchr(pstr, ':'); 475 char event_opt[MAX_EVOPT_LEN + 1];
219 if (sep) { 476 int len;
220 type = atoi(pstr); 477 unsigned int rem = MAX_EVOPT_LEN;
221 pstr = sep + 1; 478
222 id = atoi(pstr); 479 if (!strcmp(evt_ent->d_name, ".")
223 sep = strchr(pstr, ':'); 480 || !strcmp(evt_ent->d_name, "..")
224 if (sep) { 481 || !strcmp(evt_ent->d_name, "enable")
225 pstr = sep + 1; 482 || !strcmp(evt_ent->d_name, "filter"))
226 if (strchr(pstr, 'k')) 483 continue;
227 attr->exclude_user = 1; 484
228 if (strchr(pstr, 'u')) 485 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name,
229 attr->exclude_kernel = 1; 486 evt_ent->d_name);
487 if (len < 0)
488 return EVT_FAILED;
489
490 rem -= len;
491 if (flags) {
492 if (rem < strlen(flags) + 1)
493 return EVT_FAILED;
494
495 strcat(event_opt, ":");
496 strcat(event_opt, flags);
230 } 497 }
231 attr->type = type;
232 attr->config = id;
233 498
499 if (parse_events(NULL, event_opt, 0))
500 return EVT_FAILED;
501 }
502
503 return EVT_HANDLED_ALL;
504}
505
506
507static enum event_result parse_tracepoint_event(const char **strp,
508 struct perf_event_attr *attr)
509{
510 const char *evt_name;
511 char *flags;
512 char sys_name[MAX_EVENT_LENGTH];
513 unsigned int sys_length, evt_length;
514
515 if (valid_debugfs_mount(debugfs_path))
516 return 0;
517
518 evt_name = strchr(*strp, ':');
519 if (!evt_name)
520 return EVT_FAILED;
521
522 sys_length = evt_name - *strp;
523 if (sys_length >= MAX_EVENT_LENGTH)
234 return 0; 524 return 0;
525
526 strncpy(sys_name, *strp, sys_length);
527 sys_name[sys_length] = '\0';
528 evt_name = evt_name + 1;
529
530 flags = strchr(evt_name, ':');
531 if (flags) {
532 /* split it out: */
533 evt_name = strndup(evt_name, flags - evt_name);
534 flags++;
235 } 535 }
236 536
237 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 537 evt_length = strlen(evt_name);
238 if (!strncmp(str, event_symbols[i].symbol, 538 if (evt_length >= MAX_EVENT_LENGTH)
239 strlen(event_symbols[i].symbol))) { 539 return EVT_FAILED;
540
541 if (!strcmp(evt_name, "*")) {
542 *strp = evt_name + evt_length;
543 return parse_subsystem_tracepoint_event(sys_name, flags);
544 } else
545 return parse_single_tracepoint_event(sys_name, evt_name,
546 evt_length, flags,
547 attr, strp);
548}
549
550static int check_events(const char *str, unsigned int i)
551{
552 int n;
553
554 n = strlen(event_symbols[i].symbol);
555 if (!strncmp(str, event_symbols[i].symbol, n))
556 return n;
557
558 n = strlen(event_symbols[i].alias);
559 if (n)
560 if (!strncmp(str, event_symbols[i].alias, n))
561 return n;
562 return 0;
563}
564
565static enum event_result
566parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
567{
568 const char *str = *strp;
569 unsigned int i;
570 int n;
240 571
572 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
573 n = check_events(str, i);
574 if (n > 0) {
241 attr->type = event_symbols[i].type; 575 attr->type = event_symbols[i].type;
242 attr->config = event_symbols[i].config; 576 attr->config = event_symbols[i].config;
577 *strp = str + n;
578 return EVT_HANDLED;
579 }
580 }
581 return EVT_FAILED;
582}
583
584static enum event_result
585parse_raw_event(const char **strp, struct perf_event_attr *attr)
586{
587 const char *str = *strp;
588 u64 config;
589 int n;
590
591 if (*str != 'r')
592 return EVT_FAILED;
593 n = hex2u64(str + 1, &config);
594 if (n > 0) {
595 *strp = str + n + 1;
596 attr->type = PERF_TYPE_RAW;
597 attr->config = config;
598 return EVT_HANDLED;
599 }
600 return EVT_FAILED;
601}
243 602
244 return 0; 603static enum event_result
604parse_numeric_event(const char **strp, struct perf_event_attr *attr)
605{
606 const char *str = *strp;
607 char *endp;
608 unsigned long type;
609 u64 config;
610
611 type = strtoul(str, &endp, 0);
612 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
613 str = endp + 1;
614 config = strtoul(str, &endp, 0);
615 if (endp > str) {
616 attr->type = type;
617 attr->config = config;
618 *strp = endp;
619 return EVT_HANDLED;
245 } 620 }
246 } 621 }
622 return EVT_FAILED;
623}
624
625static enum event_result
626parse_event_modifier(const char **strp, struct perf_event_attr *attr)
627{
628 const char *str = *strp;
629 int eu = 1, ek = 1, eh = 1;
630
631 if (*str++ != ':')
632 return 0;
633 while (*str) {
634 if (*str == 'u')
635 eu = 0;
636 else if (*str == 'k')
637 ek = 0;
638 else if (*str == 'h')
639 eh = 0;
640 else
641 break;
642 ++str;
643 }
644 if (str >= *strp + 2) {
645 *strp = str;
646 attr->exclude_user = eu;
647 attr->exclude_kernel = ek;
648 attr->exclude_hv = eh;
649 return 1;
650 }
651 return 0;
652}
653
654/*
655 * Each event can have multiple symbolic names.
656 * Symbolic names are (almost) exactly matched.
657 */
658static enum event_result
659parse_event_symbols(const char **str, struct perf_event_attr *attr)
660{
661 enum event_result ret;
662
663 ret = parse_tracepoint_event(str, attr);
664 if (ret != EVT_FAILED)
665 goto modifier;
666
667 ret = parse_raw_event(str, attr);
668 if (ret != EVT_FAILED)
669 goto modifier;
670
671 ret = parse_numeric_event(str, attr);
672 if (ret != EVT_FAILED)
673 goto modifier;
674
675 ret = parse_symbolic_event(str, attr);
676 if (ret != EVT_FAILED)
677 goto modifier;
678
679 ret = parse_generic_hw_event(str, attr);
680 if (ret != EVT_FAILED)
681 goto modifier;
682
683 return EVT_FAILED;
684
685modifier:
686 parse_event_modifier(str, attr);
687
688 return ret;
689}
247 690
248 return parse_generic_hw_symbols(str, attr); 691static void store_event_type(const char *orgname)
692{
693 char filename[PATH_MAX], *c;
694 FILE *file;
695 int id;
696
697 sprintf(filename, "/sys/kernel/debug/tracing/events/%s/id", orgname);
698 c = strchr(filename, ':');
699 if (c)
700 *c = '/';
701
702 file = fopen(filename, "r");
703 if (!file)
704 return;
705 if (fscanf(file, "%i", &id) < 1)
706 die("cannot store event ID");
707 fclose(file);
708 perf_header__push_event(id, orgname);
249} 709}
250 710
251int parse_events(const struct option *opt, const char *str, int unset) 711
712int parse_events(const struct option *opt __used, const char *str, int unset __used)
252{ 713{
253 struct perf_counter_attr attr; 714 struct perf_event_attr attr;
254 int ret; 715 enum event_result ret;
716
717 if (strchr(str, ':'))
718 store_event_type(str);
255 719
256 memset(&attr, 0, sizeof(attr)); 720 for (;;) {
257again: 721 if (nr_counters == MAX_COUNTERS)
258 if (nr_counters == MAX_COUNTERS) 722 return -1;
259 return -1;
260 723
261 ret = parse_event_symbols(str, &attr); 724 memset(&attr, 0, sizeof(attr));
262 if (ret < 0) 725 ret = parse_event_symbols(&str, &attr);
263 return ret; 726 if (ret == EVT_FAILED)
727 return -1;
264 728
265 attrs[nr_counters] = attr; 729 if (!(*str == 0 || *str == ',' || isspace(*str)))
266 nr_counters++; 730 return -1;
731
732 if (ret != EVT_HANDLED_ALL) {
733 attrs[nr_counters] = attr;
734 nr_counters++;
735 }
267 736
268 str = strstr(str, ","); 737 if (*str == 0)
269 if (str) { 738 break;
270 str++; 739 if (*str == ',')
271 goto again; 740 ++str;
741 while (isspace(*str))
742 ++str;
272 } 743 }
273 744
274 return 0; 745 return 0;
@@ -283,34 +754,99 @@ static const char * const event_type_descriptors[] = {
283}; 754};
284 755
285/* 756/*
757 * Print the events from <debugfs_mount_point>/tracing/events
758 */
759
760static void print_tracepoint_events(void)
761{
762 DIR *sys_dir, *evt_dir;
763 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
764 int sys_dir_fd;
765 char evt_path[MAXPATHLEN];
766
767 if (valid_debugfs_mount(debugfs_path))
768 return;
769
770 sys_dir = opendir(debugfs_path);
771 if (!sys_dir)
772 goto cleanup;
773 sys_dir_fd = dirfd(sys_dir);
774
775 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
776 int dfd = openat(sys_dir_fd, sys_dirent.d_name,
777 O_RDONLY|O_DIRECTORY), evt_dir_fd;
778 if (dfd == -1)
779 continue;
780 evt_dir = fdopendir(dfd);
781 if (!evt_dir) {
782 close(dfd);
783 continue;
784 }
785 evt_dir_fd = dirfd(evt_dir);
786 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
787 snprintf(evt_path, MAXPATHLEN, "%s:%s",
788 sys_dirent.d_name, evt_dirent.d_name);
789 fprintf(stderr, " %-42s [%s]\n", evt_path,
790 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
791 }
792 closedir(evt_dir);
793 }
794
795cleanup:
796 closedir(sys_dir);
797}
798
799/*
286 * Print the help text for the event symbols: 800 * Print the help text for the event symbols:
287 */ 801 */
288void print_events(void) 802void print_events(void)
289{ 803{
290 struct event_symbol *syms = event_symbols; 804 struct event_symbol *syms = event_symbols;
291 unsigned int i, type, prev_type = -1; 805 unsigned int i, type, op, prev_type = -1;
806 char name[40];
292 807
293 fprintf(stderr, "\n"); 808 fprintf(stderr, "\n");
294 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 809 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
295 810
296 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 811 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
297 type = syms->type + 1; 812 type = syms->type + 1;
298 if (type > ARRAY_SIZE(event_type_descriptors)) 813 if (type >= ARRAY_SIZE(event_type_descriptors))
299 type = 0; 814 type = 0;
300 815
301 if (type != prev_type) 816 if (type != prev_type)
302 fprintf(stderr, "\n"); 817 fprintf(stderr, "\n");
303 818
304 fprintf(stderr, " %-30s [%s]\n", syms->symbol, 819 if (strlen(syms->alias))
820 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
821 else
822 strcpy(name, syms->symbol);
823 fprintf(stderr, " %-42s [%s]\n", name,
305 event_type_descriptors[type]); 824 event_type_descriptors[type]);
306 825
307 prev_type = type; 826 prev_type = type;
308 } 827 }
309 828
310 fprintf(stderr, "\n"); 829 fprintf(stderr, "\n");
311 fprintf(stderr, " %-30s [raw hardware event descriptor]\n", 830 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
831 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
832 /* skip invalid cache type */
833 if (!is_cache_op_valid(type, op))
834 continue;
835
836 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
837 fprintf(stderr, " %-42s [%s]\n",
838 event_cache_name(type, op, i),
839 event_type_descriptors[4]);
840 }
841 }
842 }
843
844 fprintf(stderr, "\n");
845 fprintf(stderr, " %-42s [raw hardware event descriptor]\n",
312 "rNNN"); 846 "rNNN");
313 fprintf(stderr, "\n"); 847 fprintf(stderr, "\n");
314 848
849 print_tracepoint_events();
850
315 exit(129); 851 exit(129);
316} 852}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e3d552908e60..30c608112845 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,13 +1,25 @@
1 1#ifndef _PARSE_EVENTS_H
2#define _PARSE_EVENTS_H
2/* 3/*
3 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
4 */ 5 */
5 6
7struct option;
8
9struct tracepoint_path {
10 char *system;
11 char *name;
12 struct tracepoint_path *next;
13};
14
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16
6extern int nr_counters; 17extern int nr_counters;
7 18
8extern struct perf_counter_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
9 20
10extern char *event_name(int ctr); 21extern const char *event_name(int ctr);
22extern const char *__event_name(int type, u64 config);
11 23
12extern int parse_events(const struct option *opt, const char *str, int unset); 24extern int parse_events(const struct option *opt, const char *str, int unset);
13 25
@@ -15,3 +27,8 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
15 27
16extern void print_events(void); 28extern void print_events(void);
17 29
30extern char debugfs_path[];
31extern int valid_debugfs_mount(const char *debugfs);
32
33
34#endif /* _PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index b3affb1658d2..6d8af48c925e 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -20,7 +20,8 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
20 if (p->opt) { 20 if (p->opt) {
21 *arg = p->opt; 21 *arg = p->opt;
22 p->opt = NULL; 22 p->opt = NULL;
23 } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) { 23 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
24 **(p->argv + 1) == '-')) {
24 *arg = (const char *)opt->defval; 25 *arg = (const char *)opt->defval;
25 } else if (p->argc > 1) { 26 } else if (p->argc > 1) {
26 p->argc--; 27 p->argc--;
@@ -52,6 +53,12 @@ static int get_value(struct parse_opt_ctx_t *p,
52 case OPTION_SET_INT: 53 case OPTION_SET_INT:
53 case OPTION_SET_PTR: 54 case OPTION_SET_PTR:
54 return opterror(opt, "takes no value", flags); 55 return opterror(opt, "takes no value", flags);
56 case OPTION_END:
57 case OPTION_ARGUMENT:
58 case OPTION_GROUP:
59 case OPTION_STRING:
60 case OPTION_INTEGER:
61 case OPTION_LONG:
55 default: 62 default:
56 break; 63 break;
57 } 64 }
@@ -129,6 +136,9 @@ static int get_value(struct parse_opt_ctx_t *p,
129 return opterror(opt, "expects a numerical value", flags); 136 return opterror(opt, "expects a numerical value", flags);
130 return 0; 137 return 0;
131 138
139 case OPTION_END:
140 case OPTION_ARGUMENT:
141 case OPTION_GROUP:
132 default: 142 default:
133 die("should not happen, someone must be hit on the forehead"); 143 die("should not happen, someone must be hit on the forehead");
134 } 144 }
@@ -295,6 +305,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
295 return parse_options_usage(usagestr, options); 305 return parse_options_usage(usagestr, options);
296 case -2: 306 case -2:
297 goto unknown; 307 goto unknown;
308 default:
309 break;
298 } 310 }
299 if (ctx->opt) 311 if (ctx->opt)
300 check_typos(arg + 1, options); 312 check_typos(arg + 1, options);
@@ -313,6 +325,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
313 ctx->argv[0] = strdup(ctx->opt - 1); 325 ctx->argv[0] = strdup(ctx->opt - 1);
314 *(char *)ctx->argv[0] = '-'; 326 *(char *)ctx->argv[0] = '-';
315 goto unknown; 327 goto unknown;
328 default:
329 break;
316 } 330 }
317 } 331 }
318 continue; 332 continue;
@@ -335,6 +349,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
335 return parse_options_usage(usagestr, options); 349 return parse_options_usage(usagestr, options);
336 case -2: 350 case -2:
337 goto unknown; 351 goto unknown;
352 default:
353 break;
338 } 354 }
339 continue; 355 continue;
340unknown: 356unknown:
@@ -455,6 +471,13 @@ int usage_with_options_internal(const char * const *usagestr,
455 } 471 }
456 break; 472 break;
457 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ 473 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
474 case OPTION_END:
475 case OPTION_GROUP:
476 case OPTION_BIT:
477 case OPTION_BOOLEAN:
478 case OPTION_SET_INT:
479 case OPTION_SET_PTR:
480 case OPTION_LONG:
458 break; 481 break;
459 } 482 }
460 483
@@ -485,7 +508,7 @@ int parse_options_usage(const char * const *usagestr,
485} 508}
486 509
487 510
488int parse_opt_verbosity_cb(const struct option *opt, const char *arg, 511int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
489 int unset) 512 int unset)
490{ 513{
491 int *target = opt->value; 514 int *target = opt->value;
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index a1039a6ce0eb..2ee248ff27e5 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -90,21 +90,24 @@ struct option {
90 intptr_t defval; 90 intptr_t defval;
91}; 91};
92 92
93#define OPT_END() { OPTION_END } 93#define OPT_END() { .type = OPTION_END }
94#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) } 94#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
95#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) } 95#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
96#define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) } 96#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (b) }
97#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) } 97#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
98#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) } 98#define OPT_SET_INT(s, l, v, h, i) { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) } 99#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
100#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) } 100#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
101#define OPT_LONG(s, l, v, h) { OPTION_LONG, (s), (l), (v), NULL, (h) } 101#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
102#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) } 102#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) }
103#define OPT_DATE(s, l, v, h) \ 103#define OPT_DATE(s, l, v, h) \
104 { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \ 104 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
105 parse_opt_approxidate_cb }
106#define OPT_CALLBACK(s, l, v, a, h, f) \ 105#define OPT_CALLBACK(s, l, v, a, h, f) \
107 { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) } 106 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
107#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
108 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
109#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
110 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
108 111
109/* parse_options() will filter out the processed options and leave the 112/* parse_options() will filter out the processed options and leave the
110 * non-option argments in argv[]. 113 * non-option argments in argv[].
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index a501a40dd2cb..fd1f2faaade4 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -17,7 +17,7 @@ static char bad_path[] = "/bad-path/";
17 * Two hacks: 17 * Two hacks:
18 */ 18 */
19 19
20static char *get_perf_dir(void) 20static const char *get_perf_dir(void)
21{ 21{
22 return "."; 22 return ".";
23} 23}
@@ -38,8 +38,9 @@ size_t strlcpy(char *dest, const char *src, size_t size)
38static char *get_pathname(void) 38static char *get_pathname(void)
39{ 39{
40 static char pathname_array[4][PATH_MAX]; 40 static char pathname_array[4][PATH_MAX];
41 static int index; 41 static int idx;
42 return pathname_array[3 & ++index]; 42
43 return pathname_array[3 & ++idx];
43} 44}
44 45
45static char *cleanup_path(char *path) 46static char *cleanup_path(char *path)
@@ -161,20 +162,24 @@ int perf_mkstemp(char *path, size_t len, const char *template)
161} 162}
162 163
163 164
164const char *make_relative_path(const char *abs, const char *base) 165const char *make_relative_path(const char *abs_path, const char *base)
165{ 166{
166 static char buf[PATH_MAX + 1]; 167 static char buf[PATH_MAX + 1];
167 int baselen; 168 int baselen;
169
168 if (!base) 170 if (!base)
169 return abs; 171 return abs_path;
172
170 baselen = strlen(base); 173 baselen = strlen(base);
171 if (prefixcmp(abs, base)) 174 if (prefixcmp(abs_path, base))
172 return abs; 175 return abs_path;
173 if (abs[baselen] == '/') 176 if (abs_path[baselen] == '/')
174 baselen++; 177 baselen++;
175 else if (base[baselen - 1] != '/') 178 else if (base[baselen - 1] != '/')
176 return abs; 179 return abs_path;
177 strcpy(buf, abs + baselen); 180
181 strcpy(buf, abs_path + baselen);
182
178 return buf; 183 return buf;
179} 184}
180 185
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index f18c5212bc92..2726fe40eb5d 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -162,12 +162,16 @@ static inline int sq_must_quote(char c)
162 return sq_lookup[(unsigned char)c] + quote_path_fully > 0; 162 return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
163} 163}
164 164
165/* returns the longest prefix not needing a quote up to maxlen if positive. 165/*
166 This stops at the first \0 because it's marked as a character needing an 166 * Returns the longest prefix not needing a quote up to maxlen if
167 escape */ 167 * positive.
168static size_t next_quote_pos(const char *s, ssize_t maxlen) 168 * This stops at the first \0 because it's marked as a character
169 * needing an escape.
170 */
171static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
169{ 172{
170 size_t len; 173 ssize_t len;
174
171 if (maxlen < 0) { 175 if (maxlen < 0) {
172 for (len = 0; !sq_must_quote(s[len]); len++); 176 for (len = 0; !sq_must_quote(s[len]); len++);
173 } else { 177 } else {
@@ -192,22 +196,22 @@ static size_t next_quote_pos(const char *s, ssize_t maxlen)
192static size_t quote_c_style_counted(const char *name, ssize_t maxlen, 196static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
193 struct strbuf *sb, FILE *fp, int no_dq) 197 struct strbuf *sb, FILE *fp, int no_dq)
194{ 198{
195#undef EMIT 199#define EMIT(c) \
196#define EMIT(c) \ 200 do { \
197 do { \ 201 if (sb) strbuf_addch(sb, (c)); \
198 if (sb) strbuf_addch(sb, (c)); \ 202 if (fp) fputc((c), fp); \
199 if (fp) fputc((c), fp); \ 203 count++; \
200 count++; \
201 } while (0) 204 } while (0)
202#define EMITBUF(s, l) \ 205
203 do { \ 206#define EMITBUF(s, l) \
204 int __ret; \ 207 do { \
205 if (sb) strbuf_add(sb, (s), (l)); \ 208 int __ret; \
206 if (fp) __ret = fwrite((s), (l), 1, fp); \ 209 if (sb) strbuf_add(sb, (s), (l)); \
207 count += (l); \ 210 if (fp) __ret = fwrite((s), (l), 1, fp); \
211 count += (l); \
208 } while (0) 212 } while (0)
209 213
210 size_t len, count = 0; 214 ssize_t len, count = 0;
211 const char *p = name; 215 const char *p = name;
212 216
213 for (;;) { 217 for (;;) {
@@ -273,8 +277,8 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)
273 fputc(terminator, fp); 277 fputc(terminator, fp);
274} 278}
275 279
276extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, 280void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
277 const char *name, FILE *fp, int terminator) 281 const char *name, FILE *fp, int terminator)
278{ 282{
279 int needquote = 0; 283 int needquote = 0;
280 284
@@ -306,7 +310,7 @@ char *quote_path_relative(const char *in, int len,
306 len = strlen(in); 310 len = strlen(in);
307 311
308 /* "../" prefix itself does not need quoting, but "in" might. */ 312 /* "../" prefix itself does not need quoting, but "in" might. */
309 needquote = next_quote_pos(in, len) < len; 313 needquote = (next_quote_pos(in, len) < len);
310 strbuf_setlen(out, 0); 314 strbuf_setlen(out, 0);
311 strbuf_grow(out, len); 315 strbuf_grow(out, len);
312 316
@@ -314,7 +318,7 @@ char *quote_path_relative(const char *in, int len,
314 strbuf_addch(out, '"'); 318 strbuf_addch(out, '"');
315 if (prefix) { 319 if (prefix) {
316 int off = 0; 320 int off = 0;
317 while (prefix[off] && off < len && prefix[off] == in[off]) 321 while (off < len && prefix[off] && prefix[off] == in[off])
318 if (prefix[off] == '/') { 322 if (prefix[off] == '/') {
319 prefix += off + 1; 323 prefix += off + 1;
320 in += off + 1; 324 in += off + 1;
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index 5dfad89816db..a5454a1d1c13 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -53,7 +53,7 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq
53extern void quote_two_c_style(struct strbuf *, const char *, const char *, int); 53extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
54 54
55extern void write_name_quoted(const char *name, FILE *, int terminator); 55extern void write_name_quoted(const char *name, FILE *, int terminator);
56extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, 56extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
57 const char *name, FILE *, int terminator); 57 const char *name, FILE *, int terminator);
58 58
59/* quote path as relative to the given prefix */ 59/* quote path as relative to the given prefix */
diff --git a/tools/perf/util/rbtree.c b/tools/perf/util/rbtree.c
deleted file mode 100644
index b15ba9c7cb3f..000000000000
--- a/tools/perf/util/rbtree.c
+++ /dev/null
@@ -1,383 +0,0 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4 (C) 2002 David Woodhouse <dwmw2@infradead.org>
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 linux/lib/rbtree.c
21*/
22
23#include "rbtree.h"
24
25static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
26{
27 struct rb_node *right = node->rb_right;
28 struct rb_node *parent = rb_parent(node);
29
30 if ((node->rb_right = right->rb_left))
31 rb_set_parent(right->rb_left, node);
32 right->rb_left = node;
33
34 rb_set_parent(right, parent);
35
36 if (parent)
37 {
38 if (node == parent->rb_left)
39 parent->rb_left = right;
40 else
41 parent->rb_right = right;
42 }
43 else
44 root->rb_node = right;
45 rb_set_parent(node, right);
46}
47
48static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
49{
50 struct rb_node *left = node->rb_left;
51 struct rb_node *parent = rb_parent(node);
52
53 if ((node->rb_left = left->rb_right))
54 rb_set_parent(left->rb_right, node);
55 left->rb_right = node;
56
57 rb_set_parent(left, parent);
58
59 if (parent)
60 {
61 if (node == parent->rb_right)
62 parent->rb_right = left;
63 else
64 parent->rb_left = left;
65 }
66 else
67 root->rb_node = left;
68 rb_set_parent(node, left);
69}
70
71void rb_insert_color(struct rb_node *node, struct rb_root *root)
72{
73 struct rb_node *parent, *gparent;
74
75 while ((parent = rb_parent(node)) && rb_is_red(parent))
76 {
77 gparent = rb_parent(parent);
78
79 if (parent == gparent->rb_left)
80 {
81 {
82 register struct rb_node *uncle = gparent->rb_right;
83 if (uncle && rb_is_red(uncle))
84 {
85 rb_set_black(uncle);
86 rb_set_black(parent);
87 rb_set_red(gparent);
88 node = gparent;
89 continue;
90 }
91 }
92
93 if (parent->rb_right == node)
94 {
95 register struct rb_node *tmp;
96 __rb_rotate_left(parent, root);
97 tmp = parent;
98 parent = node;
99 node = tmp;
100 }
101
102 rb_set_black(parent);
103 rb_set_red(gparent);
104 __rb_rotate_right(gparent, root);
105 } else {
106 {
107 register struct rb_node *uncle = gparent->rb_left;
108 if (uncle && rb_is_red(uncle))
109 {
110 rb_set_black(uncle);
111 rb_set_black(parent);
112 rb_set_red(gparent);
113 node = gparent;
114 continue;
115 }
116 }
117
118 if (parent->rb_left == node)
119 {
120 register struct rb_node *tmp;
121 __rb_rotate_right(parent, root);
122 tmp = parent;
123 parent = node;
124 node = tmp;
125 }
126
127 rb_set_black(parent);
128 rb_set_red(gparent);
129 __rb_rotate_left(gparent, root);
130 }
131 }
132
133 rb_set_black(root->rb_node);
134}
135
136static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
137 struct rb_root *root)
138{
139 struct rb_node *other;
140
141 while ((!node || rb_is_black(node)) && node != root->rb_node)
142 {
143 if (parent->rb_left == node)
144 {
145 other = parent->rb_right;
146 if (rb_is_red(other))
147 {
148 rb_set_black(other);
149 rb_set_red(parent);
150 __rb_rotate_left(parent, root);
151 other = parent->rb_right;
152 }
153 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
154 (!other->rb_right || rb_is_black(other->rb_right)))
155 {
156 rb_set_red(other);
157 node = parent;
158 parent = rb_parent(node);
159 }
160 else
161 {
162 if (!other->rb_right || rb_is_black(other->rb_right))
163 {
164 rb_set_black(other->rb_left);
165 rb_set_red(other);
166 __rb_rotate_right(other, root);
167 other = parent->rb_right;
168 }
169 rb_set_color(other, rb_color(parent));
170 rb_set_black(parent);
171 rb_set_black(other->rb_right);
172 __rb_rotate_left(parent, root);
173 node = root->rb_node;
174 break;
175 }
176 }
177 else
178 {
179 other = parent->rb_left;
180 if (rb_is_red(other))
181 {
182 rb_set_black(other);
183 rb_set_red(parent);
184 __rb_rotate_right(parent, root);
185 other = parent->rb_left;
186 }
187 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
188 (!other->rb_right || rb_is_black(other->rb_right)))
189 {
190 rb_set_red(other);
191 node = parent;
192 parent = rb_parent(node);
193 }
194 else
195 {
196 if (!other->rb_left || rb_is_black(other->rb_left))
197 {
198 rb_set_black(other->rb_right);
199 rb_set_red(other);
200 __rb_rotate_left(other, root);
201 other = parent->rb_left;
202 }
203 rb_set_color(other, rb_color(parent));
204 rb_set_black(parent);
205 rb_set_black(other->rb_left);
206 __rb_rotate_right(parent, root);
207 node = root->rb_node;
208 break;
209 }
210 }
211 }
212 if (node)
213 rb_set_black(node);
214}
215
216void rb_erase(struct rb_node *node, struct rb_root *root)
217{
218 struct rb_node *child, *parent;
219 int color;
220
221 if (!node->rb_left)
222 child = node->rb_right;
223 else if (!node->rb_right)
224 child = node->rb_left;
225 else
226 {
227 struct rb_node *old = node, *left;
228
229 node = node->rb_right;
230 while ((left = node->rb_left) != NULL)
231 node = left;
232 child = node->rb_right;
233 parent = rb_parent(node);
234 color = rb_color(node);
235
236 if (child)
237 rb_set_parent(child, parent);
238 if (parent == old) {
239 parent->rb_right = child;
240 parent = node;
241 } else
242 parent->rb_left = child;
243
244 node->rb_parent_color = old->rb_parent_color;
245 node->rb_right = old->rb_right;
246 node->rb_left = old->rb_left;
247
248 if (rb_parent(old))
249 {
250 if (rb_parent(old)->rb_left == old)
251 rb_parent(old)->rb_left = node;
252 else
253 rb_parent(old)->rb_right = node;
254 } else
255 root->rb_node = node;
256
257 rb_set_parent(old->rb_left, node);
258 if (old->rb_right)
259 rb_set_parent(old->rb_right, node);
260 goto color;
261 }
262
263 parent = rb_parent(node);
264 color = rb_color(node);
265
266 if (child)
267 rb_set_parent(child, parent);
268 if (parent)
269 {
270 if (parent->rb_left == node)
271 parent->rb_left = child;
272 else
273 parent->rb_right = child;
274 }
275 else
276 root->rb_node = child;
277
278 color:
279 if (color == RB_BLACK)
280 __rb_erase_color(child, parent, root);
281}
282
283/*
284 * This function returns the first node (in sort order) of the tree.
285 */
286struct rb_node *rb_first(const struct rb_root *root)
287{
288 struct rb_node *n;
289
290 n = root->rb_node;
291 if (!n)
292 return NULL;
293 while (n->rb_left)
294 n = n->rb_left;
295 return n;
296}
297
298struct rb_node *rb_last(const struct rb_root *root)
299{
300 struct rb_node *n;
301
302 n = root->rb_node;
303 if (!n)
304 return NULL;
305 while (n->rb_right)
306 n = n->rb_right;
307 return n;
308}
309
310struct rb_node *rb_next(const struct rb_node *node)
311{
312 struct rb_node *parent;
313
314 if (rb_parent(node) == node)
315 return NULL;
316
317 /* If we have a right-hand child, go down and then left as far
318 as we can. */
319 if (node->rb_right) {
320 node = node->rb_right;
321 while (node->rb_left)
322 node=node->rb_left;
323 return (struct rb_node *)node;
324 }
325
326 /* No right-hand children. Everything down and left is
327 smaller than us, so any 'next' node must be in the general
328 direction of our parent. Go up the tree; any time the
329 ancestor is a right-hand child of its parent, keep going
330 up. First time it's a left-hand child of its parent, said
331 parent is our 'next' node. */
332 while ((parent = rb_parent(node)) && node == parent->rb_right)
333 node = parent;
334
335 return parent;
336}
337
338struct rb_node *rb_prev(const struct rb_node *node)
339{
340 struct rb_node *parent;
341
342 if (rb_parent(node) == node)
343 return NULL;
344
345 /* If we have a left-hand child, go down and then right as far
346 as we can. */
347 if (node->rb_left) {
348 node = node->rb_left;
349 while (node->rb_right)
350 node=node->rb_right;
351 return (struct rb_node *)node;
352 }
353
354 /* No left-hand children. Go up till we find an ancestor which
355 is a right-hand child of its parent */
356 while ((parent = rb_parent(node)) && node == parent->rb_left)
357 node = parent;
358
359 return parent;
360}
361
362void rb_replace_node(struct rb_node *victim, struct rb_node *new,
363 struct rb_root *root)
364{
365 struct rb_node *parent = rb_parent(victim);
366
367 /* Set the surrounding nodes to point to the replacement */
368 if (parent) {
369 if (victim == parent->rb_left)
370 parent->rb_left = new;
371 else
372 parent->rb_right = new;
373 } else {
374 root->rb_node = new;
375 }
376 if (victim->rb_left)
377 rb_set_parent(victim->rb_left, new);
378 if (victim->rb_right)
379 rb_set_parent(victim->rb_right, new);
380
381 /* Copy the pointers/colour from the victim to the replacement */
382 *new = *victim;
383}
diff --git a/tools/perf/util/rbtree.h b/tools/perf/util/rbtree.h
deleted file mode 100644
index 6bdc488a47fb..000000000000
--- a/tools/perf/util/rbtree.h
+++ /dev/null
@@ -1,171 +0,0 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 linux/include/linux/rbtree.h
20
21 To use rbtrees you'll have to implement your own insert and search cores.
22 This will avoid us to use callbacks and to drop drammatically performances.
23 I know it's not the cleaner way, but in C (not in C++) to get
24 performances and genericity...
25
26 Some example of insert and search follows here. The search is a plain
27 normal search over an ordered tree. The insert instead must be implemented
28 int two steps: as first thing the code must insert the element in
29 order as a red leaf in the tree, then the support library function
30 rb_insert_color() must be called. Such function will do the
31 not trivial work to rebalance the rbtree if necessary.
32
33-----------------------------------------------------------------------
34static inline struct page * rb_search_page_cache(struct inode * inode,
35 unsigned long offset)
36{
37 struct rb_node * n = inode->i_rb_page_cache.rb_node;
38 struct page * page;
39
40 while (n)
41 {
42 page = rb_entry(n, struct page, rb_page_cache);
43
44 if (offset < page->offset)
45 n = n->rb_left;
46 else if (offset > page->offset)
47 n = n->rb_right;
48 else
49 return page;
50 }
51 return NULL;
52}
53
54static inline struct page * __rb_insert_page_cache(struct inode * inode,
55 unsigned long offset,
56 struct rb_node * node)
57{
58 struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
59 struct rb_node * parent = NULL;
60 struct page * page;
61
62 while (*p)
63 {
64 parent = *p;
65 page = rb_entry(parent, struct page, rb_page_cache);
66
67 if (offset < page->offset)
68 p = &(*p)->rb_left;
69 else if (offset > page->offset)
70 p = &(*p)->rb_right;
71 else
72 return page;
73 }
74
75 rb_link_node(node, parent, p);
76
77 return NULL;
78}
79
80static inline struct page * rb_insert_page_cache(struct inode * inode,
81 unsigned long offset,
82 struct rb_node * node)
83{
84 struct page * ret;
85 if ((ret = __rb_insert_page_cache(inode, offset, node)))
86 goto out;
87 rb_insert_color(node, &inode->i_rb_page_cache);
88 out:
89 return ret;
90}
91-----------------------------------------------------------------------
92*/
93
94#ifndef _LINUX_RBTREE_H
95#define _LINUX_RBTREE_H
96
97#include <stddef.h>
98
99/**
100 * container_of - cast a member of a structure out to the containing structure
101 * @ptr: the pointer to the member.
102 * @type: the type of the container struct this is embedded in.
103 * @member: the name of the member within the struct.
104 *
105 */
106#define container_of(ptr, type, member) ({ \
107 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
108 (type *)( (char *)__mptr - offsetof(type,member) );})
109
110struct rb_node
111{
112 unsigned long rb_parent_color;
113#define RB_RED 0
114#define RB_BLACK 1
115 struct rb_node *rb_right;
116 struct rb_node *rb_left;
117} __attribute__((aligned(sizeof(long))));
118 /* The alignment might seem pointless, but allegedly CRIS needs it */
119
120struct rb_root
121{
122 struct rb_node *rb_node;
123};
124
125
126#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
127#define rb_color(r) ((r)->rb_parent_color & 1)
128#define rb_is_red(r) (!rb_color(r))
129#define rb_is_black(r) rb_color(r)
130#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
131#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
132
133static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
134{
135 rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
136}
137static inline void rb_set_color(struct rb_node *rb, int color)
138{
139 rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
140}
141
142#define RB_ROOT (struct rb_root) { NULL, }
143#define rb_entry(ptr, type, member) container_of(ptr, type, member)
144
145#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
146#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
147#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
148
149extern void rb_insert_color(struct rb_node *, struct rb_root *);
150extern void rb_erase(struct rb_node *, struct rb_root *);
151
152/* Find logical next and previous nodes in a tree */
153extern struct rb_node *rb_next(const struct rb_node *);
154extern struct rb_node *rb_prev(const struct rb_node *);
155extern struct rb_node *rb_first(const struct rb_root *);
156extern struct rb_node *rb_last(const struct rb_root *);
157
158/* Fast replacement of a single node without remove/rebalance/add/rebalance */
159extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
160 struct rb_root *root);
161
162static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
163 struct rb_node ** rb_link)
164{
165 node->rb_parent_color = (unsigned long )parent;
166 node->rb_left = node->rb_right = NULL;
167
168 *rb_link = node;
169}
170
171#endif /* _LINUX_RBTREE_H */
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
index b2f5e854f40a..2b615acf94d7 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/perf/util/run-command.c
@@ -65,7 +65,6 @@ int start_command(struct child_process *cmd)
65 cmd->err = fderr[0]; 65 cmd->err = fderr[0];
66 } 66 }
67 67
68#ifndef __MINGW32__
69 fflush(NULL); 68 fflush(NULL);
70 cmd->pid = fork(); 69 cmd->pid = fork();
71 if (!cmd->pid) { 70 if (!cmd->pid) {
@@ -118,71 +117,6 @@ int start_command(struct child_process *cmd)
118 } 117 }
119 exit(127); 118 exit(127);
120 } 119 }
121#else
122 int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
123 const char **sargv = cmd->argv;
124 char **env = environ;
125
126 if (cmd->no_stdin) {
127 s0 = dup(0);
128 dup_devnull(0);
129 } else if (need_in) {
130 s0 = dup(0);
131 dup2(fdin[0], 0);
132 } else if (cmd->in) {
133 s0 = dup(0);
134 dup2(cmd->in, 0);
135 }
136
137 if (cmd->no_stderr) {
138 s2 = dup(2);
139 dup_devnull(2);
140 } else if (need_err) {
141 s2 = dup(2);
142 dup2(fderr[1], 2);
143 }
144
145 if (cmd->no_stdout) {
146 s1 = dup(1);
147 dup_devnull(1);
148 } else if (cmd->stdout_to_stderr) {
149 s1 = dup(1);
150 dup2(2, 1);
151 } else if (need_out) {
152 s1 = dup(1);
153 dup2(fdout[1], 1);
154 } else if (cmd->out > 1) {
155 s1 = dup(1);
156 dup2(cmd->out, 1);
157 }
158
159 if (cmd->dir)
160 die("chdir in start_command() not implemented");
161 if (cmd->env) {
162 env = copy_environ();
163 for (; *cmd->env; cmd->env++)
164 env = env_setenv(env, *cmd->env);
165 }
166
167 if (cmd->perf_cmd) {
168 cmd->argv = prepare_perf_cmd(cmd->argv);
169 }
170
171 cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
172
173 if (cmd->env)
174 free_environ(env);
175 if (cmd->perf_cmd)
176 free(cmd->argv);
177
178 cmd->argv = sargv;
179 if (s0 >= 0)
180 dup2(s0, 0), close(s0);
181 if (s1 >= 0)
182 dup2(s1, 1), close(s1);
183 if (s2 >= 0)
184 dup2(s2, 2), close(s2);
185#endif
186 120
187 if (cmd->pid < 0) { 121 if (cmd->pid < 0) {
188 int err = errno; 122 int err = errno;
@@ -288,14 +222,6 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
288 return run_command(&cmd); 222 return run_command(&cmd);
289} 223}
290 224
291#ifdef __MINGW32__
292static __stdcall unsigned run_thread(void *data)
293{
294 struct async *async = data;
295 return async->proc(async->fd_for_proc, async->data);
296}
297#endif
298
299int start_async(struct async *async) 225int start_async(struct async *async)
300{ 226{
301 int pipe_out[2]; 227 int pipe_out[2];
@@ -304,7 +230,6 @@ int start_async(struct async *async)
304 return error("cannot create pipe: %s", strerror(errno)); 230 return error("cannot create pipe: %s", strerror(errno));
305 async->out = pipe_out[0]; 231 async->out = pipe_out[0];
306 232
307#ifndef __MINGW32__
308 /* Flush stdio before fork() to avoid cloning buffers */ 233 /* Flush stdio before fork() to avoid cloning buffers */
309 fflush(NULL); 234 fflush(NULL);
310 235
@@ -319,33 +244,17 @@ int start_async(struct async *async)
319 exit(!!async->proc(pipe_out[1], async->data)); 244 exit(!!async->proc(pipe_out[1], async->data));
320 } 245 }
321 close(pipe_out[1]); 246 close(pipe_out[1]);
322#else 247
323 async->fd_for_proc = pipe_out[1];
324 async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
325 if (!async->tid) {
326 error("cannot create thread: %s", strerror(errno));
327 close_pair(pipe_out);
328 return -1;
329 }
330#endif
331 return 0; 248 return 0;
332} 249}
333 250
334int finish_async(struct async *async) 251int finish_async(struct async *async)
335{ 252{
336#ifndef __MINGW32__
337 int ret = 0; 253 int ret = 0;
338 254
339 if (wait_or_whine(async->pid)) 255 if (wait_or_whine(async->pid))
340 ret = error("waitpid (async) failed"); 256 ret = error("waitpid (async) failed");
341#else 257
342 DWORD ret = 0;
343 if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
344 ret = error("waiting for thread failed: %lu", GetLastError());
345 else if (!GetExitCodeThread(async->tid, &ret))
346 ret = error("cannot get thread exit code: %lu", GetLastError());
347 CloseHandle(async->tid);
348#endif
349 return ret; 258 return ret;
350} 259}
351 260
@@ -353,7 +262,7 @@ int run_hook(const char *index_file, const char *name, ...)
353{ 262{
354 struct child_process hook; 263 struct child_process hook;
355 const char **argv = NULL, *env[2]; 264 const char **argv = NULL, *env[2];
356 char index[PATH_MAX]; 265 char idx[PATH_MAX];
357 va_list args; 266 va_list args;
358 int ret; 267 int ret;
359 size_t i = 0, alloc = 0; 268 size_t i = 0, alloc = 0;
@@ -375,8 +284,8 @@ int run_hook(const char *index_file, const char *name, ...)
375 hook.no_stdin = 1; 284 hook.no_stdin = 1;
376 hook.stdout_to_stderr = 1; 285 hook.stdout_to_stderr = 1;
377 if (index_file) { 286 if (index_file) {
378 snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file); 287 snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file);
379 env[0] = index; 288 env[0] = idx;
380 env[1] = NULL; 289 env[1] = NULL;
381 hook.env = env; 290 hook.env = env;
382 } 291 }
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index 328289f23669..cc1837deba88 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -79,12 +79,7 @@ struct async {
79 int (*proc)(int fd, void *data); 79 int (*proc)(int fd, void *data);
80 void *data; 80 void *data;
81 int out; /* caller reads from here and closes it */ 81 int out; /* caller reads from here and closes it */
82#ifndef __MINGW32__
83 pid_t pid; 82 pid_t pid;
84#else
85 HANDLE tid;
86 int fd_for_proc;
87#endif
88}; 83};
89 84
90int start_async(struct async *async); 85int start_async(struct async *async);
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index eaba09306802..5249d5a1b0c2 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -16,7 +16,7 @@ int prefixcmp(const char *str, const char *prefix)
16 */ 16 */
17char strbuf_slopbuf[1]; 17char strbuf_slopbuf[1];
18 18
19void strbuf_init(struct strbuf *sb, size_t hint) 19void strbuf_init(struct strbuf *sb, ssize_t hint)
20{ 20{
21 sb->alloc = sb->len = 0; 21 sb->alloc = sb->len = 0;
22 sb->buf = strbuf_slopbuf; 22 sb->buf = strbuf_slopbuf;
@@ -92,7 +92,8 @@ void strbuf_ltrim(struct strbuf *sb)
92 92
93void strbuf_tolower(struct strbuf *sb) 93void strbuf_tolower(struct strbuf *sb)
94{ 94{
95 int i; 95 unsigned int i;
96
96 for (i = 0; i < sb->len; i++) 97 for (i = 0; i < sb->len; i++)
97 sb->buf[i] = tolower(sb->buf[i]); 98 sb->buf[i] = tolower(sb->buf[i]);
98} 99}
@@ -259,12 +260,12 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
259 res = fread(sb->buf + sb->len, 1, size, f); 260 res = fread(sb->buf + sb->len, 1, size, f);
260 if (res > 0) 261 if (res > 0)
261 strbuf_setlen(sb, sb->len + res); 262 strbuf_setlen(sb, sb->len + res);
262 else if (res < 0 && oldalloc == 0) 263 else if (oldalloc == 0)
263 strbuf_release(sb); 264 strbuf_release(sb);
264 return res; 265 return res;
265} 266}
266 267
267ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) 268ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
268{ 269{
269 size_t oldlen = sb->len; 270 size_t oldlen = sb->len;
270 size_t oldalloc = sb->alloc; 271 size_t oldalloc = sb->alloc;
@@ -293,7 +294,7 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
293 294
294#define STRBUF_MAXLINK (2*PATH_MAX) 295#define STRBUF_MAXLINK (2*PATH_MAX)
295 296
296int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) 297int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
297{ 298{
298 size_t oldalloc = sb->alloc; 299 size_t oldalloc = sb->alloc;
299 300
@@ -301,7 +302,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
301 hint = 32; 302 hint = 32;
302 303
303 while (hint < STRBUF_MAXLINK) { 304 while (hint < STRBUF_MAXLINK) {
304 int len; 305 ssize_t len;
305 306
306 strbuf_grow(sb, hint); 307 strbuf_grow(sb, hint);
307 len = readlink(path, sb->buf, hint); 308 len = readlink(path, sb->buf, hint);
@@ -343,7 +344,7 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
343 return 0; 344 return 0;
344} 345}
345 346
346int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) 347int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
347{ 348{
348 int fd, len; 349 int fd, len;
349 350
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index 9ee908a3ec5d..d2aa86c014c1 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -50,7 +50,7 @@ struct strbuf {
50#define STRBUF_INIT { 0, 0, strbuf_slopbuf } 50#define STRBUF_INIT { 0, 0, strbuf_slopbuf }
51 51
52/*----- strbuf life cycle -----*/ 52/*----- strbuf life cycle -----*/
53extern void strbuf_init(struct strbuf *, size_t); 53extern void strbuf_init(struct strbuf *buf, ssize_t hint);
54extern void strbuf_release(struct strbuf *); 54extern void strbuf_release(struct strbuf *);
55extern char *strbuf_detach(struct strbuf *, size_t *); 55extern char *strbuf_detach(struct strbuf *, size_t *);
56extern void strbuf_attach(struct strbuf *, void *, size_t, size_t); 56extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
@@ -61,7 +61,7 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
61} 61}
62 62
63/*----- strbuf size related -----*/ 63/*----- strbuf size related -----*/
64static inline size_t strbuf_avail(const struct strbuf *sb) { 64static inline ssize_t strbuf_avail(const struct strbuf *sb) {
65 return sb->alloc ? sb->alloc - sb->len - 1 : 0; 65 return sb->alloc ? sb->alloc - sb->len - 1 : 0;
66} 66}
67 67
@@ -122,9 +122,9 @@ extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
122 122
123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); 123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
124/* XXX: if read fails, any partial read is undone */ 124/* XXX: if read fails, any partial read is undone */
125extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); 125extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
126extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); 126extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
127extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); 127extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
128 128
129extern int strbuf_getline(struct strbuf *, FILE *, int); 129extern int strbuf_getline(struct strbuf *, FILE *, int);
130 130
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 37b03255b425..bf39dfadfd24 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,8 +1,11 @@
1#ifndef _PERF_STRING_H_ 1#ifndef _PERF_STRING_H_
2#define _PERF_STRING_H_ 2#define _PERF_STRING_H_
3 3
4#include "../types.h" 4#include "types.h"
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7 7
8#define _STR(x) #x
9#define STR(x) _STR(x)
10
8#endif 11#endif
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
new file mode 100644
index 000000000000..7ad38171dc2b
--- /dev/null
+++ b/tools/perf/util/strlist.c
@@ -0,0 +1,200 @@
1/*
2 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Licensed under the GPLv2.
5 */
6
7#include "strlist.h"
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13static struct str_node *str_node__new(const char *s, bool dupstr)
14{
15 struct str_node *self = malloc(sizeof(*self));
16
17 if (self != NULL) {
18 if (dupstr) {
19 s = strdup(s);
20 if (s == NULL)
21 goto out_delete;
22 }
23 self->s = s;
24 }
25
26 return self;
27
28out_delete:
29 free(self);
30 return NULL;
31}
32
33static void str_node__delete(struct str_node *self, bool dupstr)
34{
35 if (dupstr)
36 free((void *)self->s);
37 free(self);
38}
39
40int strlist__add(struct strlist *self, const char *new_entry)
41{
42 struct rb_node **p = &self->entries.rb_node;
43 struct rb_node *parent = NULL;
44 struct str_node *sn;
45
46 while (*p != NULL) {
47 int rc;
48
49 parent = *p;
50 sn = rb_entry(parent, struct str_node, rb_node);
51 rc = strcmp(sn->s, new_entry);
52
53 if (rc > 0)
54 p = &(*p)->rb_left;
55 else if (rc < 0)
56 p = &(*p)->rb_right;
57 else
58 return -EEXIST;
59 }
60
61 sn = str_node__new(new_entry, self->dupstr);
62 if (sn == NULL)
63 return -ENOMEM;
64
65 rb_link_node(&sn->rb_node, parent, p);
66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
68
69 return 0;
70}
71
72int strlist__load(struct strlist *self, const char *filename)
73{
74 char entry[1024];
75 int err;
76 FILE *fp = fopen(filename, "r");
77
78 if (fp == NULL)
79 return errno;
80
81 while (fgets(entry, sizeof(entry), fp) != NULL) {
82 const size_t len = strlen(entry);
83
84 if (len == 0)
85 continue;
86 entry[len - 1] = '\0';
87
88 err = strlist__add(self, entry);
89 if (err != 0)
90 goto out;
91 }
92
93 err = 0;
94out:
95 fclose(fp);
96 return err;
97}
98
99void strlist__remove(struct strlist *self, struct str_node *sn)
100{
101 rb_erase(&sn->rb_node, &self->entries);
102 str_node__delete(sn, self->dupstr);
103}
104
105bool strlist__has_entry(struct strlist *self, const char *entry)
106{
107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL;
109
110 while (*p != NULL) {
111 struct str_node *sn;
112 int rc;
113
114 parent = *p;
115 sn = rb_entry(parent, struct str_node, rb_node);
116 rc = strcmp(sn->s, entry);
117
118 if (rc > 0)
119 p = &(*p)->rb_left;
120 else if (rc < 0)
121 p = &(*p)->rb_right;
122 else
123 return true;
124 }
125
126 return false;
127}
128
129static int strlist__parse_list_entry(struct strlist *self, const char *s)
130{
131 if (strncmp(s, "file://", 7) == 0)
132 return strlist__load(self, s + 7);
133
134 return strlist__add(self, s);
135}
136
137int strlist__parse_list(struct strlist *self, const char *s)
138{
139 char *sep;
140 int err;
141
142 while ((sep = strchr(s, ',')) != NULL) {
143 *sep = '\0';
144 err = strlist__parse_list_entry(self, s);
145 *sep = ',';
146 if (err != 0)
147 return err;
148 s = sep + 1;
149 }
150
151 return *s ? strlist__parse_list_entry(self, s) : 0;
152}
153
154struct strlist *strlist__new(bool dupstr, const char *slist)
155{
156 struct strlist *self = malloc(sizeof(*self));
157
158 if (self != NULL) {
159 self->entries = RB_ROOT;
160 self->dupstr = dupstr;
161 self->nr_entries = 0;
162 if (slist && strlist__parse_list(self, slist) != 0)
163 goto out_error;
164 }
165
166 return self;
167out_error:
168 free(self);
169 return NULL;
170}
171
172void strlist__delete(struct strlist *self)
173{
174 if (self != NULL) {
175 struct str_node *pos;
176 struct rb_node *next = rb_first(&self->entries);
177
178 while (next) {
179 pos = rb_entry(next, struct str_node, rb_node);
180 next = rb_next(&pos->rb_node);
181 strlist__remove(self, pos);
182 }
183 self->entries = RB_ROOT;
184 free(self);
185 }
186}
187
188struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
189{
190 struct rb_node *nd;
191
192 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
193 struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
194
195 if (!idx--)
196 return pos;
197 }
198
199 return NULL;
200}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
new file mode 100644
index 000000000000..921818e44a54
--- /dev/null
+++ b/tools/perf/util/strlist.h
@@ -0,0 +1,39 @@
1#ifndef STRLIST_H_
2#define STRLIST_H_
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7struct str_node {
8 struct rb_node rb_node;
9 const char *s;
10};
11
12struct strlist {
13 struct rb_root entries;
14 unsigned int nr_entries;
15 bool dupstr;
16};
17
18struct strlist *strlist__new(bool dupstr, const char *slist);
19void strlist__delete(struct strlist *self);
20
21void strlist__remove(struct strlist *self, struct str_node *sn);
22int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str);
24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry);
27
28static inline bool strlist__empty(const struct strlist *self)
29{
30 return self->nr_entries == 0;
31}
32
33static inline unsigned int strlist__nr_entries(const struct strlist *self)
34{
35 return self->nr_entries;
36}
37
38int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
new file mode 100644
index 000000000000..a778fd0f4ae4
--- /dev/null
+++ b/tools/perf/util/svghelper.c
@@ -0,0 +1,488 @@
1/*
2 * svghelper.c - helper functions for outputting svg
3 *
4 * (C) Copyright 2009 Intel Corporation
5 *
6 * Authors:
7 * Arjan van de Ven <arjan@linux.intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
12 * of the License.
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <string.h>
19
20#include "svghelper.h"
21
22static u64 first_time, last_time;
23static u64 turbo_frequency, max_freq;
24
25
26#define SLOT_MULT 30.0
27#define SLOT_HEIGHT 25.0
28
29int svg_page_width = 1000;
30
31#define MIN_TEXT_SIZE 0.001
32
33static u64 total_height;
34static FILE *svgfile;
35
36static double cpu2slot(int cpu)
37{
38 return 2 * cpu + 1;
39}
40
41static double cpu2y(int cpu)
42{
43 return cpu2slot(cpu) * SLOT_MULT;
44}
45
46static double time2pixels(u64 time)
47{
48 double X;
49
50 X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time);
51 return X;
52}
53
54/*
55 * Round text sizes so that the svg viewer only needs a discrete
56 * number of renderings of the font
57 */
58static double round_text_size(double size)
59{
60 int loop = 100;
61 double target = 10.0;
62
63 if (size >= 10.0)
64 return size;
65 while (loop--) {
66 if (size >= target)
67 return target;
68 target = target / 2.0;
69 }
70 return size;
71}
72
73void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
74{
75 int new_width;
76
77 svgfile = fopen(filename, "w");
78 if (!svgfile) {
79 fprintf(stderr, "Cannot open %s for output\n", filename);
80 return;
81 }
82 first_time = start;
83 first_time = first_time / 100000000 * 100000000;
84 last_time = end;
85
86 /*
87 * if the recording is short, we default to a width of 1000, but
88 * for longer recordings we want at least 200 units of width per second
89 */
90 new_width = (last_time - first_time) / 5000000;
91
92 if (new_width > svg_page_width)
93 svg_page_width = new_width;
94
95 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
96 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
97 fprintf(svgfile, "<svg width=\"%i\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
98
99 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
100
101 fprintf(svgfile, " rect { stroke-width: 1; }\n");
102 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
103 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
104 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
105 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
106 fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
107 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
108 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
109 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
110 fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n");
111 fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n");
112 fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n");
113 fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n");
114 fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n");
115 fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n");
116 fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n");
117
118 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
119}
120
121void svg_box(int Yslot, u64 start, u64 end, const char *type)
122{
123 if (!svgfile)
124 return;
125
126 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
127 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
128}
129
130void svg_sample(int Yslot, int cpu, u64 start, u64 end)
131{
132 double text_size;
133 if (!svgfile)
134 return;
135
136 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n",
137 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT);
138
139 text_size = (time2pixels(end)-time2pixels(start));
140 if (cpu > 9)
141 text_size = text_size/2;
142 if (text_size > 1.25)
143 text_size = 1.25;
144 text_size = round_text_size(text_size);
145
146 if (text_size > MIN_TEXT_SIZE)
147 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n",
148 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
149
150}
151
152static char *time_to_string(u64 duration)
153{
154 static char text[80];
155
156 text[0] = 0;
157
158 if (duration < 1000) /* less than 1 usec */
159 return text;
160
161 if (duration < 1000 * 1000) { /* less than 1 msec */
162 sprintf(text, "%4.1f us", duration / 1000.0);
163 return text;
164 }
165 sprintf(text, "%4.1f ms", duration / 1000.0 / 1000);
166
167 return text;
168}
169
170void svg_waiting(int Yslot, u64 start, u64 end)
171{
172 char *text;
173 const char *style;
174 double font_size;
175
176 if (!svgfile)
177 return;
178
179 style = "waiting";
180
181 if (end-start > 10 * 1000000) /* 10 msec */
182 style = "WAITING";
183
184 text = time_to_string(end-start);
185
186 font_size = 1.0 * (time2pixels(end)-time2pixels(start));
187
188 if (font_size > 3)
189 font_size = 3;
190
191 font_size = round_text_size(font_size);
192
193 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
194 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
195 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
196 if (font_size > MIN_TEXT_SIZE)
197 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n",
198 font_size, text);
199 fprintf(svgfile, "</g>\n");
200}
201
202static char *cpu_model(void)
203{
204 static char cpu_m[255];
205 char buf[256];
206 FILE *file;
207
208 cpu_m[0] = 0;
209 /* CPU type */
210 file = fopen("/proc/cpuinfo", "r");
211 if (file) {
212 while (fgets(buf, 255, file)) {
213 if (strstr(buf, "model name")) {
214 strncpy(cpu_m, &buf[13], 255);
215 break;
216 }
217 }
218 fclose(file);
219 }
220 return cpu_m;
221}
222
223void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
224{
225 char cpu_string[80];
226 if (!svgfile)
227 return;
228
229 max_freq = __max_freq;
230 turbo_frequency = __turbo_freq;
231
232 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n",
233 time2pixels(first_time),
234 time2pixels(last_time)-time2pixels(first_time),
235 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
236
237 sprintf(cpu_string, "CPU %i", (int)cpu+1);
238 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
239 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
240
241 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n",
242 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
243}
244
245void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name)
246{
247 double width;
248
249 if (!svgfile)
250 return;
251
252
253 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
254 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
255 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
256 width = time2pixels(end)-time2pixels(start);
257 if (width > 6)
258 width = 6;
259
260 width = round_text_size(width);
261
262 if (width > MIN_TEXT_SIZE)
263 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n",
264 width, name);
265
266 fprintf(svgfile, "</g>\n");
267}
268
269void svg_cstate(int cpu, u64 start, u64 end, int type)
270{
271 double width;
272 char style[128];
273
274 if (!svgfile)
275 return;
276
277
278 if (type > 6)
279 type = 6;
280 sprintf(style, "c%i", type);
281
282 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n",
283 style,
284 time2pixels(start), time2pixels(end)-time2pixels(start),
285 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
286
287 width = (time2pixels(end)-time2pixels(start))/2.0;
288 if (width > 6)
289 width = 6;
290
291 width = round_text_size(width);
292
293 if (width > MIN_TEXT_SIZE)
294 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n",
295 time2pixels(start), cpu2y(cpu)+width, width, type);
296}
297
298static char *HzToHuman(unsigned long hz)
299{
300 static char buffer[1024];
301 unsigned long long Hz;
302
303 memset(buffer, 0, 1024);
304
305 Hz = hz;
306
307 /* default: just put the Number in */
308 sprintf(buffer, "%9lli", Hz);
309
310 if (Hz > 1000)
311 sprintf(buffer, " %6lli Mhz", (Hz+500)/1000);
312
313 if (Hz > 1500000)
314 sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000);
315
316 if (Hz == turbo_frequency)
317 sprintf(buffer, "Turbo");
318
319 return buffer;
320}
321
322void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
323{
324 double height = 0;
325
326 if (!svgfile)
327 return;
328
329 if (max_freq)
330 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
331 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
332 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n",
333 time2pixels(start), time2pixels(end), height, height);
334 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n",
335 time2pixels(start), height+0.9, HzToHuman(freq));
336
337}
338
339
340void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2)
341{
342 double height;
343
344 if (!svgfile)
345 return;
346
347
348 if (row1 < row2) {
349 if (row1) {
350 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
351 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
352 if (desc2)
353 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
354 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
355 }
356 if (row2) {
357 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
358 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
359 if (desc1)
360 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
361 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
362 }
363 } else {
364 if (row2) {
365 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
366 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
367 if (desc1)
368 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
369 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
370 }
371 if (row1) {
372 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
373 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
374 if (desc2)
375 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
376 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
377 }
378 }
379 height = row1 * SLOT_MULT;
380 if (row2 > row1)
381 height += SLOT_HEIGHT;
382 if (row1)
383 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
384 time2pixels(start), height);
385}
386
387void svg_wakeline(u64 start, int row1, int row2)
388{
389 double height;
390
391 if (!svgfile)
392 return;
393
394
395 if (row1 < row2)
396 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
397 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
398 else
399 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
400 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
401
402 height = row1 * SLOT_MULT;
403 if (row2 > row1)
404 height += SLOT_HEIGHT;
405 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
406 time2pixels(start), height);
407}
408
409void svg_interrupt(u64 start, int row)
410{
411 if (!svgfile)
412 return;
413
414 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
415 time2pixels(start), row * SLOT_MULT);
416 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
417 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
418}
419
420void svg_text(int Yslot, u64 start, const char *text)
421{
422 if (!svgfile)
423 return;
424
425 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
426 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
427}
428
429static void svg_legenda_box(int X, const char *text, const char *style)
430{
431 double boxsize;
432 boxsize = SLOT_HEIGHT / 2;
433
434 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
435 X, boxsize, boxsize, style);
436 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n",
437 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
438}
439
440void svg_legenda(void)
441{
442 if (!svgfile)
443 return;
444
445 svg_legenda_box(0, "Running", "sample");
446 svg_legenda_box(100, "Idle","rect.c1");
447 svg_legenda_box(200, "Deeper Idle", "rect.c3");
448 svg_legenda_box(350, "Deepest Idle", "rect.c6");
449 svg_legenda_box(550, "Sleeping", "process2");
450 svg_legenda_box(650, "Waiting for cpu", "waiting");
451 svg_legenda_box(800, "Blocked on IO", "blocked");
452}
453
454void svg_time_grid(void)
455{
456 u64 i;
457
458 if (!svgfile)
459 return;
460
461 i = first_time;
462 while (i < last_time) {
463 int color = 220;
464 double thickness = 0.075;
465 if ((i % 100000000) == 0) {
466 thickness = 0.5;
467 color = 192;
468 }
469 if ((i % 1000000000) == 0) {
470 thickness = 2.0;
471 color = 128;
472 }
473
474 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
475 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
476
477 i += 10000000;
478 }
479}
480
481void svg_close(void)
482{
483 if (svgfile) {
484 fprintf(svgfile, "</svg>\n");
485 fclose(svgfile);
486 svgfile = NULL;
487 }
488}
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
new file mode 100644
index 000000000000..cd93195aedb3
--- /dev/null
+++ b/tools/perf/util/svghelper.h
@@ -0,0 +1,28 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_
2#define _INCLUDE_GUARD_SVG_HELPER_
3
4#include "types.h"
5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_sample(int Yslot, int cpu, u64 start, u64 end);
9extern void svg_waiting(int Yslot, u64 start, u64 end);
10extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
11
12
13extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name);
14extern void svg_cstate(int cpu, u64 start, u64 end, int type);
15extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
16
17
18extern void svg_time_grid(void);
19extern void svg_legenda(void);
20extern void svg_wakeline(u64 start, int row1, int row2);
21extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2);
22extern void svg_interrupt(u64 start, int row);
23extern void svg_text(int Yslot, u64 start, const char *text);
24extern void svg_close(void);
25
26extern int svg_page_width;
27
28#endif
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 86e14375e74e..fd3d9c8e90fc 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -3,15 +3,27 @@
3#include "string.h" 3#include "string.h"
4#include "symbol.h" 4#include "symbol.h"
5 5
6#include "debug.h"
7
6#include <libelf.h> 8#include <libelf.h>
7#include <gelf.h> 9#include <gelf.h>
8#include <elf.h> 10#include <elf.h>
9 11
10const char *sym_hist_filter; 12const char *sym_hist_filter;
11 13
14enum dso_origin {
15 DSO__ORIG_KERNEL = 0,
16 DSO__ORIG_JAVA_JIT,
17 DSO__ORIG_FEDORA,
18 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO,
21 DSO__ORIG_NOT_FOUND,
22};
23
12static struct symbol *symbol__new(u64 start, u64 len, 24static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 25 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 26 u64 obj_start, int v)
15{ 27{
16 size_t namelen = strlen(name) + 1; 28 size_t namelen = strlen(name) + 1;
17 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -19,7 +31,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
19 if (!self) 31 if (!self)
20 return NULL; 32 return NULL;
21 33
22 if (verbose >= 2) 34 if (v >= 2)
23 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
24 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
25 37
@@ -35,7 +47,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
35 self = ((void *)self) + priv_size; 47 self = ((void *)self) + priv_size;
36 } 48 }
37 self->start = start; 49 self->start = start;
38 self->end = start + len - 1; 50 self->end = len ? start + len - 1 : start;
39 memcpy(self->name, name, namelen); 51 memcpy(self->name, name, namelen);
40 52
41 return self; 53 return self;
@@ -48,8 +60,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
48 60
49static size_t symbol__fprintf(struct symbol *self, FILE *fp) 61static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50{ 62{
51 return fprintf(fp, " %llx-%llx %s\n", 63 if (!self->module)
64 return fprintf(fp, " %llx-%llx %s\n",
52 self->start, self->end, self->name); 65 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);
53} 69}
54 70
55struct dso *dso__new(const char *name, unsigned int sym_priv_size) 71struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -61,6 +77,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
61 self->syms = RB_ROOT; 77 self->syms = RB_ROOT;
62 self->sym_priv_size = sym_priv_size; 78 self->sym_priv_size = sym_priv_size;
63 self->find_symbol = dso__find_symbol; 79 self->find_symbol = dso__find_symbol;
80 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND;
64 } 82 }
65 83
66 return self; 84 return self;
@@ -140,12 +158,13 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
140 return ret; 158 return ret;
141} 159}
142 160
143static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) 161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
144{ 162{
145 struct rb_node *nd, *prevnd; 163 struct rb_node *nd, *prevnd;
146 char *line = NULL; 164 char *line = NULL;
147 size_t n; 165 size_t n;
148 FILE *file = fopen("/proc/kallsyms", "r"); 166 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
149 168
150 if (file == NULL) 169 if (file == NULL)
151 goto out_failure; 170 goto out_failure;
@@ -181,15 +200,17 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
181 * Well fix up the end later, when we have all sorted. 200 * Well fix up the end later, when we have all sorted.
182 */ 201 */
183 sym = symbol__new(start, 0xdead, line + len + 2, 202 sym = symbol__new(start, 0xdead, line + len + 2,
184 self->sym_priv_size, 0, verbose); 203 self->sym_priv_size, 0, v);
185 204
186 if (sym == NULL) 205 if (sym == NULL)
187 goto out_delete_line; 206 goto out_delete_line;
188 207
189 if (filter && filter(self, sym)) 208 if (filter && filter(self, sym))
190 symbol__delete(sym, self->sym_priv_size); 209 symbol__delete(sym, self->sym_priv_size);
191 else 210 else {
192 dso__insert_symbol(self, sym); 211 dso__insert_symbol(self, sym);
212 count++;
213 }
193 } 214 }
194 215
195 /* 216 /*
@@ -212,7 +233,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
212 free(line); 233 free(line);
213 fclose(file); 234 fclose(file);
214 235
215 return 0; 236 return count;
216 237
217out_delete_line: 238out_delete_line:
218 free(line); 239 free(line);
@@ -220,7 +241,7 @@ out_failure:
220 return -1; 241 return -1;
221} 242}
222 243
223static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) 244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
224{ 245{
225 char *line = NULL; 246 char *line = NULL;
226 size_t n; 247 size_t n;
@@ -258,7 +279,7 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verb
258 continue; 279 continue;
259 280
260 sym = symbol__new(start, size, line + len, 281 sym = symbol__new(start, size, line + len,
261 self->sym_priv_size, start, verbose); 282 self->sym_priv_size, start, v);
262 283
263 if (sym == NULL) 284 if (sym == NULL)
264 goto out_delete_line; 285 goto out_delete_line;
@@ -286,13 +307,13 @@ out_failure:
286 * elf_symtab__for_each_symbol - iterate thru all the symbols 307 * elf_symtab__for_each_symbol - iterate thru all the symbols
287 * 308 *
288 * @self: struct elf_symtab instance to iterate 309 * @self: struct elf_symtab instance to iterate
289 * @index: uint32_t index 310 * @idx: uint32_t idx
290 * @sym: GElf_Sym iterator 311 * @sym: GElf_Sym iterator
291 */ 312 */
292#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ 313#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
293 for (index = 0, gelf_getsym(syms, index, &sym);\ 314 for (idx = 0, gelf_getsym(syms, idx, &sym);\
294 index < nr_syms; \ 315 idx < nr_syms; \
295 index++, gelf_getsym(syms, index, &sym)) 316 idx++, gelf_getsym(syms, idx, &sym))
296 317
297static inline uint8_t elf_sym__type(const GElf_Sym *sym) 318static inline uint8_t elf_sym__type(const GElf_Sym *sym)
298{ 319{
@@ -307,6 +328,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
307 sym->st_size != 0; 328 sym->st_size != 0;
308} 329}
309 330
331static inline int elf_sym__is_label(const GElf_Sym *sym)
332{
333 return elf_sym__type(sym) == STT_NOTYPE &&
334 sym->st_name != 0 &&
335 sym->st_shndx != SHN_UNDEF &&
336 sym->st_shndx != SHN_ABS;
337}
338
339static inline const char *elf_sec__name(const GElf_Shdr *shdr,
340 const Elf_Data *secstrs)
341{
342 return secstrs->d_buf + shdr->sh_name;
343}
344
345static inline int elf_sec__is_text(const GElf_Shdr *shdr,
346 const Elf_Data *secstrs)
347{
348 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
349}
350
310static inline const char *elf_sym__name(const GElf_Sym *sym, 351static inline const char *elf_sym__name(const GElf_Sym *sym,
311 const Elf_Data *symstrs) 352 const Elf_Data *symstrs)
312{ 353{
@@ -315,7 +356,7 @@ static inline const char *elf_sym__name(const GElf_Sym *sym,
315 356
316static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 357static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
317 GElf_Shdr *shp, const char *name, 358 GElf_Shdr *shp, const char *name,
318 size_t *index) 359 size_t *idx)
319{ 360{
320 Elf_Scn *sec = NULL; 361 Elf_Scn *sec = NULL;
321 size_t cnt = 1; 362 size_t cnt = 1;
@@ -326,8 +367,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
326 gelf_getshdr(sec, shp); 367 gelf_getshdr(sec, shp);
327 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 368 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
328 if (!strcmp(name, str)) { 369 if (!strcmp(name, str)) {
329 if (index) 370 if (idx)
330 *index = cnt; 371 *idx = cnt;
331 break; 372 break;
332 } 373 }
333 ++cnt; 374 ++cnt;
@@ -346,56 +387,81 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
346 idx < nr_entries; \ 387 idx < nr_entries; \
347 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 388 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
348 389
349static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 390/*
350 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 391 * We need to check if we have a .dynsym, so that we can handle the
351 GElf_Shdr *shdr_dynsym, 392 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
352 size_t dynsym_idx, int verbose) 393 * .dynsym or .symtab).
394 * And always look at the original dso, not at debuginfo packages, that
395 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
396 */
397static int dso__synthesize_plt_symbols(struct dso *self, int v)
353{ 398{
354 uint32_t nr_rel_entries, idx; 399 uint32_t nr_rel_entries, idx;
355 GElf_Sym sym; 400 GElf_Sym sym;
356 u64 plt_offset; 401 u64 plt_offset;
357 GElf_Shdr shdr_plt; 402 GElf_Shdr shdr_plt;
358 struct symbol *f; 403 struct symbol *f;
359 GElf_Shdr shdr_rel_plt; 404 GElf_Shdr shdr_rel_plt, shdr_dynsym;
360 Elf_Data *reldata, *syms, *symstrs; 405 Elf_Data *reldata, *syms, *symstrs;
361 Elf_Scn *scn_plt_rel, *scn_symstrs; 406 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
407 size_t dynsym_idx;
408 GElf_Ehdr ehdr;
362 char sympltname[1024]; 409 char sympltname[1024];
363 int nr = 0, symidx; 410 Elf *elf;
411 int nr = 0, symidx, fd, err = 0;
412
413 fd = open(self->name, O_RDONLY);
414 if (fd < 0)
415 goto out;
416
417 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
418 if (elf == NULL)
419 goto out_close;
420
421 if (gelf_getehdr(elf, &ehdr) == NULL)
422 goto out_elf_end;
364 423
365 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 424 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
425 ".dynsym", &dynsym_idx);
426 if (scn_dynsym == NULL)
427 goto out_elf_end;
428
429 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
366 ".rela.plt", NULL); 430 ".rela.plt", NULL);
367 if (scn_plt_rel == NULL) { 431 if (scn_plt_rel == NULL) {
368 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 432 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
369 ".rel.plt", NULL); 433 ".rel.plt", NULL);
370 if (scn_plt_rel == NULL) 434 if (scn_plt_rel == NULL)
371 return 0; 435 goto out_elf_end;
372 } 436 }
373 437
438 err = -1;
439
374 if (shdr_rel_plt.sh_link != dynsym_idx) 440 if (shdr_rel_plt.sh_link != dynsym_idx)
375 return 0; 441 goto out_elf_end;
376 442
377 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 443 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
378 return 0; 444 goto out_elf_end;
379 445
380 /* 446 /*
381 * Fetch the relocation section to find the indexes to the GOT 447 * Fetch the relocation section to find the idxes to the GOT
382 * and the symbols in the .dynsym they refer to. 448 * and the symbols in the .dynsym they refer to.
383 */ 449 */
384 reldata = elf_getdata(scn_plt_rel, NULL); 450 reldata = elf_getdata(scn_plt_rel, NULL);
385 if (reldata == NULL) 451 if (reldata == NULL)
386 return -1; 452 goto out_elf_end;
387 453
388 syms = elf_getdata(scn_dynsym, NULL); 454 syms = elf_getdata(scn_dynsym, NULL);
389 if (syms == NULL) 455 if (syms == NULL)
390 return -1; 456 goto out_elf_end;
391 457
392 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 458 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
393 if (scn_symstrs == NULL) 459 if (scn_symstrs == NULL)
394 return -1; 460 goto out_elf_end;
395 461
396 symstrs = elf_getdata(scn_symstrs, NULL); 462 symstrs = elf_getdata(scn_symstrs, NULL);
397 if (symstrs == NULL) 463 if (symstrs == NULL)
398 return -1; 464 goto out_elf_end;
399 465
400 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 466 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
401 plt_offset = shdr_plt.sh_offset; 467 plt_offset = shdr_plt.sh_offset;
@@ -412,9 +478,9 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
412 "%s@plt", elf_sym__name(&sym, symstrs)); 478 "%s@plt", elf_sym__name(&sym, symstrs));
413 479
414 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 480 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
415 sympltname, self->sym_priv_size, 0, verbose); 481 sympltname, self->sym_priv_size, 0, v);
416 if (!f) 482 if (!f)
417 return -1; 483 goto out_elf_end;
418 484
419 dso__insert_symbol(self, f); 485 dso__insert_symbol(self, f);
420 ++nr; 486 ++nr;
@@ -430,79 +496,63 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
430 "%s@plt", elf_sym__name(&sym, symstrs)); 496 "%s@plt", elf_sym__name(&sym, symstrs));
431 497
432 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 498 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
433 sympltname, self->sym_priv_size, 0, verbose); 499 sympltname, self->sym_priv_size, 0, v);
434 if (!f) 500 if (!f)
435 return -1; 501 goto out_elf_end;
436 502
437 dso__insert_symbol(self, f); 503 dso__insert_symbol(self, f);
438 ++nr; 504 ++nr;
439 } 505 }
440 } else {
441 /*
442 * TODO: There are still one more shdr_rel_plt.sh_type
443 * I have to investigate, but probably should be ignored.
444 */
445 } 506 }
446 507
447 return nr; 508 err = 0;
509out_elf_end:
510 elf_end(elf);
511out_close:
512 close(fd);
513
514 if (err == 0)
515 return nr;
516out:
517 fprintf(stderr, "%s: problems reading %s PLT info.\n",
518 __func__, self->name);
519 return 0;
448} 520}
449 521
450static int dso__load_sym(struct dso *self, int fd, const char *name, 522static int dso__load_sym(struct dso *self, int fd, const char *name,
451 symbol_filter_t filter, int verbose) 523 symbol_filter_t filter, int v, struct module *mod)
452{ 524{
453 Elf_Data *symstrs; 525 Elf_Data *symstrs, *secstrs;
454 uint32_t nr_syms; 526 uint32_t nr_syms;
455 int err = -1; 527 int err = -1;
456 uint32_t index; 528 uint32_t idx;
457 GElf_Ehdr ehdr; 529 GElf_Ehdr ehdr;
458 GElf_Shdr shdr; 530 GElf_Shdr shdr;
459 Elf_Data *syms; 531 Elf_Data *syms;
460 GElf_Sym sym; 532 GElf_Sym sym;
461 Elf_Scn *sec, *sec_dynsym; 533 Elf_Scn *sec, *sec_strndx;
462 Elf *elf; 534 Elf *elf;
463 size_t dynsym_idx; 535 int nr = 0, kernel = !strcmp("[kernel]", self->name);
464 int nr = 0;
465 536
466 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 537 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467 if (elf == NULL) { 538 if (elf == NULL) {
468 if (verbose) 539 if (v)
469 fprintf(stderr, "%s: cannot read %s ELF file.\n", 540 fprintf(stderr, "%s: cannot read %s ELF file.\n",
470 __func__, name); 541 __func__, name);
471 goto out_close; 542 goto out_close;
472 } 543 }
473 544
474 if (gelf_getehdr(elf, &ehdr) == NULL) { 545 if (gelf_getehdr(elf, &ehdr) == NULL) {
475 if (verbose) 546 if (v)
476 fprintf(stderr, "%s: cannot get elf header.\n", __func__); 547 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
477 goto out_elf_end; 548 goto out_elf_end;
478 } 549 }
479 550
480 /*
481 * We need to check if we have a .dynsym, so that we can handle the
482 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
483 * .dynsym or .symtab)
484 */
485 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
486 ".dynsym", &dynsym_idx);
487 if (sec_dynsym != NULL) {
488 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
489 sec_dynsym, &shdr,
490 dynsym_idx, verbose);
491 if (nr < 0)
492 goto out_elf_end;
493 }
494
495 /*
496 * But if we have a full .symtab (that is a superset of .dynsym) we
497 * should add the symbols not in the .dynsyn
498 */
499 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 551 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
500 if (sec == NULL) { 552 if (sec == NULL) {
501 if (sec_dynsym == NULL) 553 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
554 if (sec == NULL)
502 goto out_elf_end; 555 goto out_elf_end;
503
504 sec = sec_dynsym;
505 gelf_getshdr(sec, &shdr);
506 } 556 }
507 557
508 syms = elf_getdata(sec, NULL); 558 syms = elf_getdata(sec, NULL);
@@ -517,15 +567,34 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
517 if (symstrs == NULL) 567 if (symstrs == NULL)
518 goto out_elf_end; 568 goto out_elf_end;
519 569
570 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
571 if (sec_strndx == NULL)
572 goto out_elf_end;
573
574 secstrs = elf_getdata(sec_strndx, NULL);
575 if (secstrs == NULL)
576 goto out_elf_end;
577
520 nr_syms = shdr.sh_size / shdr.sh_entsize; 578 nr_syms = shdr.sh_size / shdr.sh_entsize;
521 579
522 memset(&sym, 0, sizeof(sym)); 580 memset(&sym, 0, sizeof(sym));
523 581 if (!kernel) {
524 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 582 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
583 elf_section_by_name(elf, &ehdr, &shdr,
584 ".gnu.prelink_undo",
585 NULL) != NULL);
586 } else self->adjust_symbols = 0;
587
588 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
525 struct symbol *f; 589 struct symbol *f;
590 const char *elf_name;
591 char *demangled;
526 u64 obj_start; 592 u64 obj_start;
593 struct section *section = NULL;
594 int is_label = elf_sym__is_label(&sym);
595 const char *section_name;
527 596
528 if (!elf_sym__is_function(&sym)) 597 if (!is_label && !elf_sym__is_function(&sym))
529 continue; 598 continue;
530 599
531 sec = elf_getscn(elf, sym.st_shndx); 600 sec = elf_getscn(elf, sym.st_shndx);
@@ -533,19 +602,51 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
533 goto out_elf_end; 602 goto out_elf_end;
534 603
535 gelf_getshdr(sec, &shdr); 604 gelf_getshdr(sec, &shdr);
605
606 if (is_label && !elf_sec__is_text(&shdr, secstrs))
607 continue;
608
609 section_name = elf_sec__name(&shdr, secstrs);
536 obj_start = sym.st_value; 610 obj_start = sym.st_value;
537 611
538 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 612 if (self->adjust_symbols) {
613 if (v >= 2)
614 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
615 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
539 616
540 f = symbol__new(sym.st_value, sym.st_size, 617 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
541 elf_sym__name(&sym, symstrs), 618 }
542 self->sym_priv_size, obj_start, verbose); 619
620 if (mod) {
621 section = mod->sections->find_section(mod->sections, section_name);
622 if (section)
623 sym.st_value += section->vma;
624 else {
625 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
626 mod->name, section_name);
627 goto out_elf_end;
628 }
629 }
630 /*
631 * We need to figure out if the object was created from C++ sources
632 * DWARF DW_compile_unit has this, but we don't always have access
633 * to it...
634 */
635 elf_name = elf_sym__name(&sym, symstrs);
636 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
637 if (demangled != NULL)
638 elf_name = demangled;
639
640 f = symbol__new(sym.st_value, sym.st_size, elf_name,
641 self->sym_priv_size, obj_start, v);
642 free(demangled);
543 if (!f) 643 if (!f)
544 goto out_elf_end; 644 goto out_elf_end;
545 645
546 if (filter && filter(self, f)) 646 if (filter && filter(self, f))
547 symbol__delete(f, self->sym_priv_size); 647 symbol__delete(f, self->sym_priv_size);
548 else { 648 else {
649 f->module = mod;
549 dso__insert_symbol(self, f); 650 dso__insert_symbol(self, f);
550 nr++; 651 nr++;
551 } 652 }
@@ -558,42 +659,135 @@ out_close:
558 return err; 659 return err;
559} 660}
560 661
561int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 662#define BUILD_ID_SIZE 128
663
664static char *dso__read_build_id(struct dso *self, int v)
665{
666 int i;
667 GElf_Ehdr ehdr;
668 GElf_Shdr shdr;
669 Elf_Data *build_id_data;
670 Elf_Scn *sec;
671 char *build_id = NULL, *bid;
672 unsigned char *raw;
673 Elf *elf;
674 int fd = open(self->name, O_RDONLY);
675
676 if (fd < 0)
677 goto out;
678
679 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
680 if (elf == NULL) {
681 if (v)
682 fprintf(stderr, "%s: cannot read %s ELF file.\n",
683 __func__, self->name);
684 goto out_close;
685 }
686
687 if (gelf_getehdr(elf, &ehdr) == NULL) {
688 if (v)
689 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
690 goto out_elf_end;
691 }
692
693 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
694 if (sec == NULL)
695 goto out_elf_end;
696
697 build_id_data = elf_getdata(sec, NULL);
698 if (build_id_data == NULL)
699 goto out_elf_end;
700 build_id = malloc(BUILD_ID_SIZE);
701 if (build_id == NULL)
702 goto out_elf_end;
703 raw = build_id_data->d_buf + 16;
704 bid = build_id;
705
706 for (i = 0; i < 20; ++i) {
707 sprintf(bid, "%02x", *raw);
708 ++raw;
709 bid += 2;
710 }
711 if (v >= 2)
712 printf("%s(%s): %s\n", __func__, self->name, build_id);
713out_elf_end:
714 elf_end(elf);
715out_close:
716 close(fd);
717out:
718 return build_id;
719}
720
721char dso__symtab_origin(const struct dso *self)
562{ 722{
563 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 723 static const char origin[] = {
564 char *name = malloc(size); 724 [DSO__ORIG_KERNEL] = 'k',
565 int variant = 0; 725 [DSO__ORIG_JAVA_JIT] = 'j',
726 [DSO__ORIG_FEDORA] = 'f',
727 [DSO__ORIG_UBUNTU] = 'u',
728 [DSO__ORIG_BUILDID] = 'b',
729 [DSO__ORIG_DSO] = 'd',
730 };
731
732 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
733 return '!';
734 return origin[self->origin];
735}
736
737int dso__load(struct dso *self, symbol_filter_t filter, int v)
738{
739 int size = PATH_MAX;
740 char *name = malloc(size), *build_id = NULL;
566 int ret = -1; 741 int ret = -1;
567 int fd; 742 int fd;
568 743
569 if (!name) 744 if (!name)
570 return -1; 745 return -1;
571 746
572 if (strncmp(self->name, "/tmp/perf-", 10) == 0) 747 self->adjust_symbols = 0;
573 return dso__load_perf_map(self, filter, verbose); 748
749 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
750 ret = dso__load_perf_map(self, filter, v);
751 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
752 DSO__ORIG_NOT_FOUND;
753 return ret;
754 }
755
756 self->origin = DSO__ORIG_FEDORA - 1;
574 757
575more: 758more:
576 do { 759 do {
577 switch (variant) { 760 self->origin++;
578 case 0: /* Fedora */ 761 switch (self->origin) {
762 case DSO__ORIG_FEDORA:
579 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 763 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
580 break; 764 break;
581 case 1: /* Ubuntu */ 765 case DSO__ORIG_UBUNTU:
582 snprintf(name, size, "/usr/lib/debug%s", self->name); 766 snprintf(name, size, "/usr/lib/debug%s", self->name);
583 break; 767 break;
584 case 2: /* Sane people */ 768 case DSO__ORIG_BUILDID:
769 build_id = dso__read_build_id(self, v);
770 if (build_id != NULL) {
771 snprintf(name, size,
772 "/usr/lib/debug/.build-id/%.2s/%s.debug",
773 build_id, build_id + 2);
774 free(build_id);
775 break;
776 }
777 self->origin++;
778 /* Fall thru */
779 case DSO__ORIG_DSO:
585 snprintf(name, size, "%s", self->name); 780 snprintf(name, size, "%s", self->name);
586 break; 781 break;
587 782
588 default: 783 default:
589 goto out; 784 goto out;
590 } 785 }
591 variant++;
592 786
593 fd = open(name, O_RDONLY); 787 fd = open(name, O_RDONLY);
594 } while (fd < 0); 788 } while (fd < 0);
595 789
596 ret = dso__load_sym(self, fd, name, filter, verbose); 790 ret = dso__load_sym(self, fd, name, filter, v, NULL);
597 close(fd); 791 close(fd);
598 792
599 /* 793 /*
@@ -602,39 +796,233 @@ more:
602 if (!ret) 796 if (!ret)
603 goto more; 797 goto more;
604 798
799 if (ret > 0) {
800 int nr_plt = dso__synthesize_plt_symbols(self, v);
801 if (nr_plt > 0)
802 ret += nr_plt;
803 }
605out: 804out:
606 free(name); 805 free(name);
806 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
807 return 0;
607 return ret; 808 return ret;
608} 809}
609 810
811static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
812 symbol_filter_t filter, int v)
813{
814 struct module *mod = mod_dso__find_module(mods, name);
815 int err = 0, fd;
816
817 if (mod == NULL || !mod->active)
818 return err;
819
820 fd = open(mod->path, O_RDONLY);
821
822 if (fd < 0)
823 return err;
824
825 err = dso__load_sym(self, fd, name, filter, v, mod);
826 close(fd);
827
828 return err;
829}
830
831int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
832{
833 struct mod_dso *mods = mod_dso__new_dso("modules");
834 struct module *pos;
835 struct rb_node *next;
836 int err;
837
838 err = mod_dso__load_modules(mods);
839
840 if (err <= 0)
841 return err;
842
843 /*
844 * Iterate over modules, and load active symbols.
845 */
846 next = rb_first(&mods->mods);
847 while (next) {
848 pos = rb_entry(next, struct module, rb_node);
849 err = dso__load_module(self, mods, pos->name, filter, v);
850
851 if (err < 0)
852 break;
853
854 next = rb_next(&pos->rb_node);
855 }
856
857 if (err < 0) {
858 mod_dso__delete_modules(mods);
859 mod_dso__delete_self(mods);
860 }
861
862 return err;
863}
864
865static inline void dso__fill_symbol_holes(struct dso *self)
866{
867 struct symbol *prev = NULL;
868 struct rb_node *nd;
869
870 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
871 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
872
873 if (prev) {
874 u64 hole = 0;
875 int alias = pos->start == prev->start;
876
877 if (!alias)
878 hole = prev->start - pos->end - 1;
879
880 if (hole || alias) {
881 if (alias)
882 pos->end = prev->end;
883 else if (hole)
884 pos->end = prev->start - 1;
885 }
886 }
887 prev = pos;
888 }
889}
890
610static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 891static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
611 symbol_filter_t filter, int verbose) 892 symbol_filter_t filter, int v)
612{ 893{
613 int err, fd = open(vmlinux, O_RDONLY); 894 int err, fd = open(vmlinux, O_RDONLY);
614 895
615 if (fd < 0) 896 if (fd < 0)
616 return -1; 897 return -1;
617 898
618 err = dso__load_sym(self, fd, vmlinux, filter, verbose); 899 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
900
901 if (err > 0)
902 dso__fill_symbol_holes(self);
903
619 close(fd); 904 close(fd);
620 905
621 return err; 906 return err;
622} 907}
623 908
624int dso__load_kernel(struct dso *self, const char *vmlinux, 909int dso__load_kernel(struct dso *self, const char *vmlinux,
625 symbol_filter_t filter, int verbose) 910 symbol_filter_t filter, int v, int use_modules)
626{ 911{
627 int err = -1; 912 int err = -1;
628 913
629 if (vmlinux) 914 if (vmlinux) {
630 err = dso__load_vmlinux(self, vmlinux, filter, verbose); 915 err = dso__load_vmlinux(self, vmlinux, filter, v);
916 if (err > 0 && use_modules)
917 err = dso__load_modules(self, filter, v);
918 }
631 919
632 if (err) 920 if (err <= 0)
633 err = dso__load_kallsyms(self, filter, verbose); 921 err = dso__load_kallsyms(self, filter, v);
922
923 if (err > 0)
924 self->origin = DSO__ORIG_KERNEL;
634 925
635 return err; 926 return err;
636} 927}
637 928
929LIST_HEAD(dsos);
930struct dso *kernel_dso;
931struct dso *vdso;
932struct dso *hypervisor_dso;
933
934const char *vmlinux_name = "vmlinux";
935int modules;
936
937static void dsos__add(struct dso *dso)
938{
939 list_add_tail(&dso->node, &dsos);
940}
941
942static struct dso *dsos__find(const char *name)
943{
944 struct dso *pos;
945
946 list_for_each_entry(pos, &dsos, node)
947 if (strcmp(pos->name, name) == 0)
948 return pos;
949 return NULL;
950}
951
952struct dso *dsos__findnew(const char *name)
953{
954 struct dso *dso = dsos__find(name);
955 int nr;
956
957 if (dso)
958 return dso;
959
960 dso = dso__new(name, 0);
961 if (!dso)
962 goto out_delete_dso;
963
964 nr = dso__load(dso, NULL, verbose);
965 if (nr < 0) {
966 eprintf("Failed to open: %s\n", name);
967 goto out_delete_dso;
968 }
969 if (!nr)
970 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
971
972 dsos__add(dso);
973
974 return dso;
975
976out_delete_dso:
977 dso__delete(dso);
978 return NULL;
979}
980
981void dsos__fprintf(FILE *fp)
982{
983 struct dso *pos;
984
985 list_for_each_entry(pos, &dsos, node)
986 dso__fprintf(pos, fp);
987}
988
989static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
990{
991 return dso__find_symbol(dso, ip);
992}
993
994int load_kernel(void)
995{
996 int err;
997
998 kernel_dso = dso__new("[kernel]", 0);
999 if (!kernel_dso)
1000 return -1;
1001
1002 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1003 if (err <= 0) {
1004 dso__delete(kernel_dso);
1005 kernel_dso = NULL;
1006 } else
1007 dsos__add(kernel_dso);
1008
1009 vdso = dso__new("[vdso]", 0);
1010 if (!vdso)
1011 return -1;
1012
1013 vdso->find_symbol = vdso__find_symbol;
1014
1015 dsos__add(vdso);
1016
1017 hypervisor_dso = dso__new("[hypervisor]", 0);
1018 if (!hypervisor_dso)
1019 return -1;
1020 dsos__add(hypervisor_dso);
1021
1022 return err;
1023}
1024
1025
638void symbol__init(void) 1026void symbol__init(void)
639{ 1027{
640 elf_version(EV_CURRENT); 1028 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ea332e56e458..6e8490716408 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -2,9 +2,35 @@
2#define _PERF_SYMBOL_ 1 2#define _PERF_SYMBOL_ 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include "../types.h" 5#include "types.h"
6#include "list.h" 6#include <linux/list.h>
7#include "rbtree.h" 7#include <linux/rbtree.h>
8#include "module.h"
9#include "event.h"
10
11#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int);
13
14static inline char *bfd_demangle(void __used *v, const char *c, int i)
15{
16 return cplus_demangle(c, i);
17}
18#else
19#ifdef NO_DEMANGLE
20static inline char *bfd_demangle(void __used *v, const char __used *c,
21 int __used i)
22{
23 return NULL;
24}
25#else
26#include <bfd.h>
27#endif
28#endif
29
30#ifndef DMGL_PARAMS
31#define DMGL_PARAMS (1 << 0) /* Include function args */
32#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
33#endif
8 34
9struct symbol { 35struct symbol {
10 struct rb_node rb_node; 36 struct rb_node rb_node;
@@ -13,6 +39,7 @@ struct symbol {
13 u64 obj_start; 39 u64 obj_start;
14 u64 hist_sum; 40 u64 hist_sum;
15 u64 *hist; 41 u64 *hist;
42 struct module *module;
16 void *priv; 43 void *priv;
17 char name[0]; 44 char name[0];
18}; 45};
@@ -20,12 +47,15 @@ struct symbol {
20struct dso { 47struct dso {
21 struct list_head node; 48 struct list_head node;
22 struct rb_root syms; 49 struct rb_root syms;
23 unsigned int sym_priv_size;
24 struct symbol *(*find_symbol)(struct dso *, u64 ip); 50 struct symbol *(*find_symbol)(struct dso *, u64 ip);
51 unsigned int sym_priv_size;
52 unsigned char adjust_symbols;
53 unsigned char slen_calculated;
54 unsigned char origin;
25 char name[0]; 55 char name[0];
26}; 56};
27 57
28const char *sym_hist_filter; 58extern const char *sym_hist_filter;
29 59
30typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); 60typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
31 61
@@ -40,10 +70,23 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
40struct symbol *dso__find_symbol(struct dso *self, u64 ip); 70struct symbol *dso__find_symbol(struct dso *self, u64 ip);
41 71
42int dso__load_kernel(struct dso *self, const char *vmlinux, 72int dso__load_kernel(struct dso *self, const char *vmlinux,
43 symbol_filter_t filter, int verbose); 73 symbol_filter_t filter, int verbose, int modules);
74int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
44int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 75int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
76struct dso *dsos__findnew(const char *name);
77void dsos__fprintf(FILE *fp);
45 78
46size_t dso__fprintf(struct dso *self, FILE *fp); 79size_t dso__fprintf(struct dso *self, FILE *fp);
80char dso__symtab_origin(const struct dso *self);
81
82int load_kernel(void);
47 83
48void symbol__init(void); 84void symbol__init(void);
85
86extern struct list_head dsos;
87extern struct dso *kernel_dso;
88extern struct dso *vdso;
89extern struct dso *hypervisor_dso;
90extern const char *vmlinux_name;
91extern int modules;
49#endif /* _PERF_SYMBOL_ */ 92#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
new file mode 100644
index 000000000000..45efb5db0d19
--- /dev/null
+++ b/tools/perf/util/thread.c
@@ -0,0 +1,175 @@
1#include "../perf.h"
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include "thread.h"
6#include "util.h"
7#include "debug.h"
8
9static struct thread *thread__new(pid_t pid)
10{
11 struct thread *self = calloc(1, sizeof(*self));
12
13 if (self != NULL) {
14 self->pid = pid;
15 self->comm = malloc(32);
16 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps);
19 }
20
21 return self;
22}
23
24int thread__set_comm(struct thread *self, const char *comm)
25{
26 if (self->comm)
27 free(self->comm);
28 self->comm = strdup(comm);
29 return self->comm ? 0 : -ENOMEM;
30}
31
32static size_t thread__fprintf(struct thread *self, FILE *fp)
33{
34 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
36
37 list_for_each_entry(pos, &self->maps, node)
38 ret += map__fprintf(pos, fp);
39
40 return ret;
41}
42
43struct thread *
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{
46 struct rb_node **p = &threads->rb_node;
47 struct rb_node *parent = NULL;
48 struct thread *th;
49
50 /*
51 * Font-end cache - PID lookups come in blocks,
52 * so most of the time we dont have to look up
53 * the full rbtree:
54 */
55 if (*last_match && (*last_match)->pid == pid)
56 return *last_match;
57
58 while (*p != NULL) {
59 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node);
61
62 if (th->pid == pid) {
63 *last_match = th;
64 return th;
65 }
66
67 if (pid < th->pid)
68 p = &(*p)->rb_left;
69 else
70 p = &(*p)->rb_right;
71 }
72
73 th = thread__new(pid);
74 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads);
77 *last_match = th;
78 }
79
80 return th;
81}
82
83struct thread *
84register_idle_thread(struct rb_root *threads, struct thread **last_match)
85{
86 struct thread *thread = threads__findnew(0, threads, last_match);
87
88 if (!thread || thread__set_comm(thread, "swapper")) {
89 fprintf(stderr, "problem inserting idle task.\n");
90 exit(-1);
91 }
92
93 return thread;
94}
95
96void thread__insert_map(struct thread *self, struct map *map)
97{
98 struct map *pos, *tmp;
99
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
101 if (map__overlap(pos, map)) {
102 if (verbose >= 2) {
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107
108 if (map->start <= pos->start && map->end > pos->start)
109 pos->start = map->end;
110
111 if (map->end >= pos->end && map->start < pos->end)
112 pos->end = map->start;
113
114 if (verbose >= 2) {
115 printf("after collision:\n");
116 map__fprintf(pos, stdout);
117 }
118
119 if (pos->start >= pos->end) {
120 list_del_init(&pos->node);
121 free(pos);
122 }
123 }
124 }
125
126 list_add_tail(&map->node, &self->maps);
127}
128
129int thread__fork(struct thread *self, struct thread *parent)
130{
131 struct map *map;
132
133 if (self->comm)
134 free(self->comm);
135 self->comm = strdup(parent->comm);
136 if (!self->comm)
137 return -ENOMEM;
138
139 list_for_each_entry(map, &parent->maps, node) {
140 struct map *new = map__clone(map);
141 if (!new)
142 return -ENOMEM;
143 thread__insert_map(self, new);
144 }
145
146 return 0;
147}
148
149struct map *thread__find_map(struct thread *self, u64 ip)
150{
151 struct map *pos;
152
153 if (self == NULL)
154 return NULL;
155
156 list_for_each_entry(pos, &self->maps, node)
157 if (ip >= pos->start && ip <= pos->end)
158 return pos;
159
160 return NULL;
161}
162
163size_t threads__fprintf(FILE *fp, struct rb_root *threads)
164{
165 size_t ret = 0;
166 struct rb_node *nd;
167
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170
171 ret += thread__fprintf(pos, fp);
172 }
173
174 return ret;
175}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
new file mode 100644
index 000000000000..32aea3c1c2ad
--- /dev/null
+++ b/tools/perf/util/thread.h
@@ -0,0 +1,22 @@
1#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h>
4#include "symbol.h"
5
6struct thread {
7 struct rb_node rb_node;
8 struct list_head maps;
9 pid_t pid;
10 char shortname[3];
11 char *comm;
12};
13
14int thread__set_comm(struct thread *self, const char *comm);
15struct thread *
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match);
17struct thread *
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
new file mode 100644
index 000000000000..af4b0573b37f
--- /dev/null
+++ b/tools/perf/util/trace-event-info.c
@@ -0,0 +1,540 @@
1/*
2 * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _GNU_SOURCE
22#include <dirent.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <pthread.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <ctype.h>
34#include <errno.h>
35#include <stdbool.h>
36
37#include "../perf.h"
38#include "trace-event.h"
39
40
41#define VERSION "0.5"
42
43#define _STR(x) #x
44#define STR(x) _STR(x)
45#define MAX_PATH 256
46
47#define TRACE_CTRL "tracing_on"
48#define TRACE "trace"
49#define AVAILABLE "available_tracers"
50#define CURRENT "current_tracer"
51#define ITER_CTRL "trace_options"
52#define MAX_LATENCY "tracing_max_latency"
53
54unsigned int page_size;
55
56static const char *output_file = "trace.info";
57static int output_fd;
58
59struct event_list {
60 struct event_list *next;
61 const char *event;
62};
63
64struct events {
65 struct events *sibling;
66 struct events *children;
67 struct events *next;
68 char *name;
69};
70
71
72
73static void die(const char *fmt, ...)
74{
75 va_list ap;
76 int ret = errno;
77
78 if (errno)
79 perror("trace-cmd");
80 else
81 ret = -1;
82
83 va_start(ap, fmt);
84 fprintf(stderr, " ");
85 vfprintf(stderr, fmt, ap);
86 va_end(ap);
87
88 fprintf(stderr, "\n");
89 exit(ret);
90}
91
92void *malloc_or_die(unsigned int size)
93{
94 void *data;
95
96 data = malloc(size);
97 if (!data)
98 die("malloc");
99 return data;
100}
101
102static const char *find_debugfs(void)
103{
104 static char debugfs[MAX_PATH+1];
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126
127 debugfs_found = 1;
128
129 return debugfs;
130}
131
132/*
133 * Finds the path to the debugfs/tracing
134 * Allocates the string and stores it.
135 */
136static const char *find_tracing_dir(void)
137{
138 static char *tracing;
139 static int tracing_found;
140 const char *debugfs;
141
142 if (tracing_found)
143 return tracing;
144
145 debugfs = find_debugfs();
146
147 tracing = malloc_or_die(strlen(debugfs) + 9);
148
149 sprintf(tracing, "%s/tracing", debugfs);
150
151 tracing_found = 1;
152 return tracing;
153}
154
155static char *get_tracing_file(const char *name)
156{
157 const char *tracing;
158 char *file;
159
160 tracing = find_tracing_dir();
161 if (!tracing)
162 return NULL;
163
164 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
165
166 sprintf(file, "%s/%s", tracing, name);
167 return file;
168}
169
170static void put_tracing_file(char *file)
171{
172 free(file);
173}
174
175static ssize_t write_or_die(const void *buf, size_t len)
176{
177 int ret;
178
179 ret = write(output_fd, buf, len);
180 if (ret < 0)
181 die("writing to '%s'", output_file);
182
183 return ret;
184}
185
186int bigendian(void)
187{
188 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
189 unsigned int *ptr;
190
191 ptr = (unsigned int *)(void *)str;
192 return *ptr == 0x01020304;
193}
194
195static unsigned long long copy_file_fd(int fd)
196{
197 unsigned long long size = 0;
198 char buf[BUFSIZ];
199 int r;
200
201 do {
202 r = read(fd, buf, BUFSIZ);
203 if (r > 0) {
204 size += r;
205 write_or_die(buf, r);
206 }
207 } while (r > 0);
208
209 return size;
210}
211
212static unsigned long long copy_file(const char *file)
213{
214 unsigned long long size = 0;
215 int fd;
216
217 fd = open(file, O_RDONLY);
218 if (fd < 0)
219 die("Can't read '%s'", file);
220 size = copy_file_fd(fd);
221 close(fd);
222
223 return size;
224}
225
226static unsigned long get_size_fd(int fd)
227{
228 unsigned long long size = 0;
229 char buf[BUFSIZ];
230 int r;
231
232 do {
233 r = read(fd, buf, BUFSIZ);
234 if (r > 0)
235 size += r;
236 } while (r > 0);
237
238 lseek(fd, 0, SEEK_SET);
239
240 return size;
241}
242
243static unsigned long get_size(const char *file)
244{
245 unsigned long long size = 0;
246 int fd;
247
248 fd = open(file, O_RDONLY);
249 if (fd < 0)
250 die("Can't read '%s'", file);
251 size = get_size_fd(fd);
252 close(fd);
253
254 return size;
255}
256
257static void read_header_files(void)
258{
259 unsigned long long size, check_size;
260 char *path;
261 int fd;
262
263 path = get_tracing_file("events/header_page");
264 fd = open(path, O_RDONLY);
265 if (fd < 0)
266 die("can't read '%s'", path);
267
268 /* unfortunately, you can not stat debugfs files for size */
269 size = get_size_fd(fd);
270
271 write_or_die("header_page", 12);
272 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd);
274 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size);
277 put_tracing_file(path);
278
279 path = get_tracing_file("events/header_event");
280 fd = open(path, O_RDONLY);
281 if (fd < 0)
282 die("can't read '%s'", path);
283
284 size = get_size_fd(fd);
285
286 write_or_die("header_event", 13);
287 write_or_die(&size, 8);
288 check_size = copy_file_fd(fd);
289 if (size != check_size)
290 die("wrong size for '%s'", path);
291 put_tracing_file(path);
292}
293
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
295{
296 while (tps) {
297 if (!strcmp(sys, tps->name))
298 return true;
299 tps = tps->next;
300 }
301
302 return false;
303}
304
305static void copy_event_system(const char *sys, struct tracepoint_path *tps)
306{
307 unsigned long long size, check_size;
308 struct dirent *dent;
309 struct stat st;
310 char *format;
311 DIR *dir;
312 int count = 0;
313 int ret;
314
315 dir = opendir(sys);
316 if (!dir)
317 die("can't read directory '%s'", sys);
318
319 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps))
323 continue;
324 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
325 sprintf(format, "%s/%s/format", sys, dent->d_name);
326 ret = stat(format, &st);
327 free(format);
328 if (ret < 0)
329 continue;
330 count++;
331 }
332
333 write_or_die(&count, 4);
334
335 rewinddir(dir);
336 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps))
340 continue;
341 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
342 sprintf(format, "%s/%s/format", sys, dent->d_name);
343 ret = stat(format, &st);
344
345 if (ret >= 0) {
346 /* unfortunately, you can not stat debugfs files for size */
347 size = get_size(format);
348 write_or_die(&size, 8);
349 check_size = copy_file(format);
350 if (size != check_size)
351 die("error in size of file '%s'", format);
352 }
353
354 free(format);
355 }
356}
357
358static void read_ftrace_files(struct tracepoint_path *tps)
359{
360 char *path;
361
362 path = get_tracing_file("events/ftrace");
363
364 copy_event_system(path, tps);
365
366 put_tracing_file(path);
367}
368
369static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
370{
371 while (tps) {
372 if (!strcmp(sys, tps->system))
373 return true;
374 tps = tps->next;
375 }
376
377 return false;
378}
379
380static void read_event_files(struct tracepoint_path *tps)
381{
382 struct dirent *dent;
383 struct stat st;
384 char *path;
385 char *sys;
386 DIR *dir;
387 int count = 0;
388 int ret;
389
390 path = get_tracing_file("events");
391
392 dir = opendir(path);
393 if (!dir)
394 die("can't read directory '%s'", path);
395
396 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps))
401 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 }
411
412 write_or_die(&count, 4);
413
414 rewinddir(dir);
415 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps))
420 continue;
421 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
422 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st);
424 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) {
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
427 copy_event_system(sys, tps);
428 }
429 }
430 free(sys);
431 }
432
433 put_tracing_file(path);
434}
435
436static void read_proc_kallsyms(void)
437{
438 unsigned int size, check_size;
439 const char *path = "/proc/kallsyms";
440 struct stat st;
441 int ret;
442
443 ret = stat(path, &st);
444 if (ret < 0) {
445 /* not found */
446 size = 0;
447 write_or_die(&size, 4);
448 return;
449 }
450 size = get_size(path);
451 write_or_die(&size, 4);
452 check_size = copy_file(path);
453 if (size != check_size)
454 die("error in size of file '%s'", path);
455
456}
457
458static void read_ftrace_printk(void)
459{
460 unsigned int size, check_size;
461 char *path;
462 struct stat st;
463 int ret;
464
465 path = get_tracing_file("printk_formats");
466 ret = stat(path, &st);
467 if (ret < 0) {
468 /* not found */
469 size = 0;
470 write_or_die(&size, 4);
471 goto out;
472 }
473 size = get_size(path);
474 write_or_die(&size, 4);
475 check_size = copy_file(path);
476 if (size != check_size)
477 die("error in size of file '%s'", path);
478out:
479 put_tracing_file(path);
480}
481
482static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
484{
485 struct tracepoint_path path, *ppath = &path;
486 int i;
487
488 for (i = 0; i < nb_events; i++) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
490 continue;
491 ppath->next = tracepoint_id_to_path(pattrs[i].config);
492 if (!ppath->next)
493 die("%s\n", "No memory to alloc tracepoints list");
494 ppath = ppath->next;
495 }
496
497 return path.next;
498}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
500{
501 char buf[BUFSIZ];
502 struct tracepoint_path *tps;
503
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507
508 buf[0] = 23;
509 buf[1] = 8;
510 buf[2] = 68;
511 memcpy(buf + 3, "tracing", 7);
512
513 write_or_die(buf, 10);
514
515 write_or_die(VERSION, strlen(VERSION) + 1);
516
517 /* save endian */
518 if (bigendian())
519 buf[0] = 1;
520 else
521 buf[0] = 0;
522
523 write_or_die(buf, 1);
524
525 /* save size of long */
526 buf[0] = sizeof(long);
527 write_or_die(buf, 1);
528
529 /* save page_size */
530 page_size = getpagesize();
531 write_or_die(&page_size, 4);
532
533 tps = get_tracepoints_path(pattrs, nb_events);
534
535 read_header_files();
536 read_ftrace_files(tps);
537 read_event_files(tps);
538 read_proc_kallsyms();
539 read_ftrace_printk();
540}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
new file mode 100644
index 000000000000..f6a8437141c8
--- /dev/null
+++ b/tools/perf/util/trace-event-parse.c
@@ -0,0 +1,2967 @@
1/*
2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by Frederic Weisbecker.
23 */
24#define _GNU_SOURCE
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include <errno.h>
30
31#undef _GNU_SOURCE
32#include "../perf.h"
33#include "util.h"
34#include "trace-event.h"
35
36int header_page_ts_offset;
37int header_page_ts_size;
38int header_page_size_offset;
39int header_page_size_size;
40int header_page_data_offset;
41int header_page_data_size;
42
43static char *input_buf;
44static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz;
46
47static int cpus;
48static int long_size;
49
50static void init_input_buf(char *buf, unsigned long long size)
51{
52 input_buf = buf;
53 input_buf_siz = size;
54 input_buf_ptr = 0;
55}
56
57struct cmdline {
58 char *comm;
59 int pid;
60};
61
62static struct cmdline *cmdlines;
63static int cmdline_count;
64
65static int cmdline_cmp(const void *a, const void *b)
66{
67 const struct cmdline *ca = a;
68 const struct cmdline *cb = b;
69
70 if (ca->pid < cb->pid)
71 return -1;
72 if (ca->pid > cb->pid)
73 return 1;
74
75 return 0;
76}
77
78void parse_cmdlines(char *file, int size __unused)
79{
80 struct cmdline_list {
81 struct cmdline_list *next;
82 char *comm;
83 int pid;
84 } *list = NULL, *item;
85 char *line;
86 char *next = NULL;
87 int i;
88
89 line = strtok_r(file, "\n", &next);
90 while (line) {
91 item = malloc_or_die(sizeof(*item));
92 sscanf(line, "%d %as", &item->pid,
93 (float *)(void *)&item->comm); /* workaround gcc warning */
94 item->next = list;
95 list = item;
96 line = strtok_r(NULL, "\n", &next);
97 cmdline_count++;
98 }
99
100 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
101
102 i = 0;
103 while (list) {
104 cmdlines[i].pid = list->pid;
105 cmdlines[i].comm = list->comm;
106 i++;
107 item = list;
108 list = list->next;
109 free(item);
110 }
111
112 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
113}
114
115static struct func_map {
116 unsigned long long addr;
117 char *func;
118 char *mod;
119} *func_list;
120static unsigned int func_count;
121
122static int func_cmp(const void *a, const void *b)
123{
124 const struct func_map *fa = a;
125 const struct func_map *fb = b;
126
127 if (fa->addr < fb->addr)
128 return -1;
129 if (fa->addr > fb->addr)
130 return 1;
131
132 return 0;
133}
134
135void parse_proc_kallsyms(char *file, unsigned int size __unused)
136{
137 struct func_list {
138 struct func_list *next;
139 unsigned long long addr;
140 char *func;
141 char *mod;
142 } *list = NULL, *item;
143 char *line;
144 char *next = NULL;
145 char *addr_str;
146 char ch;
147 int ret;
148 int i;
149
150 line = strtok_r(file, "\n", &next);
151 while (line) {
152 item = malloc_or_die(sizeof(*item));
153 item->mod = NULL;
154 ret = sscanf(line, "%as %c %as\t[%as",
155 (float *)(void *)&addr_str, /* workaround gcc warning */
156 &ch,
157 (float *)(void *)&item->func,
158 (float *)(void *)&item->mod);
159 item->addr = strtoull(addr_str, NULL, 16);
160 free(addr_str);
161
162 /* truncate the extra ']' */
163 if (item->mod)
164 item->mod[strlen(item->mod) - 1] = 0;
165
166
167 item->next = list;
168 list = item;
169 line = strtok_r(NULL, "\n", &next);
170 func_count++;
171 }
172
173 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1);
174
175 i = 0;
176 while (list) {
177 func_list[i].func = list->func;
178 func_list[i].addr = list->addr;
179 func_list[i].mod = list->mod;
180 i++;
181 item = list;
182 list = list->next;
183 free(item);
184 }
185
186 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
187
188 /*
189 * Add a special record at the end.
190 */
191 func_list[func_count].func = NULL;
192 func_list[func_count].addr = 0;
193 func_list[func_count].mod = NULL;
194}
195
196/*
197 * We are searching for a record in between, not an exact
198 * match.
199 */
200static int func_bcmp(const void *a, const void *b)
201{
202 const struct func_map *fa = a;
203 const struct func_map *fb = b;
204
205 if ((fa->addr == fb->addr) ||
206
207 (fa->addr > fb->addr &&
208 fa->addr < (fb+1)->addr))
209 return 0;
210
211 if (fa->addr < fb->addr)
212 return -1;
213
214 return 1;
215}
216
217static struct func_map *find_func(unsigned long long addr)
218{
219 struct func_map *func;
220 struct func_map key;
221
222 key.addr = addr;
223
224 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
225 func_bcmp);
226
227 return func;
228}
229
230void print_funcs(void)
231{
232 int i;
233
234 for (i = 0; i < (int)func_count; i++) {
235 printf("%016llx %s",
236 func_list[i].addr,
237 func_list[i].func);
238 if (func_list[i].mod)
239 printf(" [%s]\n", func_list[i].mod);
240 else
241 printf("\n");
242 }
243}
244
245static struct printk_map {
246 unsigned long long addr;
247 char *printk;
248} *printk_list;
249static unsigned int printk_count;
250
251static int printk_cmp(const void *a, const void *b)
252{
253 const struct func_map *fa = a;
254 const struct func_map *fb = b;
255
256 if (fa->addr < fb->addr)
257 return -1;
258 if (fa->addr > fb->addr)
259 return 1;
260
261 return 0;
262}
263
264static struct printk_map *find_printk(unsigned long long addr)
265{
266 struct printk_map *printk;
267 struct printk_map key;
268
269 key.addr = addr;
270
271 printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
272 printk_cmp);
273
274 return printk;
275}
276
277void parse_ftrace_printk(char *file, unsigned int size __unused)
278{
279 struct printk_list {
280 struct printk_list *next;
281 unsigned long long addr;
282 char *printk;
283 } *list = NULL, *item;
284 char *line;
285 char *next = NULL;
286 char *addr_str;
287 int ret;
288 int i;
289
290 line = strtok_r(file, "\n", &next);
291 while (line) {
292 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);
297 free(addr_str);
298
299 item->next = list;
300 list = item;
301 line = strtok_r(NULL, "\n", &next);
302 printk_count++;
303 }
304
305 printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
306
307 i = 0;
308 while (list) {
309 printk_list[i].printk = list->printk;
310 printk_list[i].addr = list->addr;
311 i++;
312 item = list;
313 list = list->next;
314 free(item);
315 }
316
317 qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
318}
319
320void print_printk(void)
321{
322 int i;
323
324 for (i = 0; i < (int)printk_count; i++) {
325 printf("%016llx %s\n",
326 printk_list[i].addr,
327 printk_list[i].printk);
328 }
329}
330
331static struct event *alloc_event(void)
332{
333 struct event *event;
334
335 event = malloc_or_die(sizeof(*event));
336 memset(event, 0, sizeof(*event));
337
338 return event;
339}
340
341enum event_type {
342 EVENT_ERROR,
343 EVENT_NONE,
344 EVENT_SPACE,
345 EVENT_NEWLINE,
346 EVENT_OP,
347 EVENT_DELIM,
348 EVENT_ITEM,
349 EVENT_DQUOTE,
350 EVENT_SQUOTE,
351};
352
353static struct event *event_list;
354
355static void add_event(struct event *event)
356{
357 event->next = event_list;
358 event_list = event;
359}
360
361static int event_item_type(enum event_type type)
362{
363 switch (type) {
364 case EVENT_ITEM ... EVENT_SQUOTE:
365 return 1;
366 case EVENT_ERROR ... EVENT_DELIM:
367 default:
368 return 0;
369 }
370}
371
372static void free_arg(struct print_arg *arg)
373{
374 if (!arg)
375 return;
376
377 switch (arg->type) {
378 case PRINT_ATOM:
379 if (arg->atom.atom)
380 free(arg->atom.atom);
381 break;
382 case PRINT_NULL:
383 case PRINT_FIELD ... PRINT_OP:
384 default:
385 /* todo */
386 break;
387 }
388
389 free(arg);
390}
391
392static enum event_type get_type(int ch)
393{
394 if (ch == '\n')
395 return EVENT_NEWLINE;
396 if (isspace(ch))
397 return EVENT_SPACE;
398 if (isalnum(ch) || ch == '_')
399 return EVENT_ITEM;
400 if (ch == '\'')
401 return EVENT_SQUOTE;
402 if (ch == '"')
403 return EVENT_DQUOTE;
404 if (!isprint(ch))
405 return EVENT_NONE;
406 if (ch == '(' || ch == ')' || ch == ',')
407 return EVENT_DELIM;
408
409 return EVENT_OP;
410}
411
412static int __read_char(void)
413{
414 if (input_buf_ptr >= input_buf_siz)
415 return -1;
416
417 return input_buf[input_buf_ptr++];
418}
419
420static int __peek_char(void)
421{
422 if (input_buf_ptr >= input_buf_siz)
423 return -1;
424
425 return input_buf[input_buf_ptr];
426}
427
428static enum event_type __read_token(char **tok)
429{
430 char buf[BUFSIZ];
431 int ch, last_ch, quote_ch, next_ch;
432 int i = 0;
433 int tok_size = 0;
434 enum event_type type;
435
436 *tok = NULL;
437
438
439 ch = __read_char();
440 if (ch < 0)
441 return EVENT_NONE;
442
443 type = get_type(ch);
444 if (type == EVENT_NONE)
445 return type;
446
447 buf[i++] = ch;
448
449 switch (type) {
450 case EVENT_NEWLINE:
451 case EVENT_DELIM:
452 *tok = malloc_or_die(2);
453 (*tok)[0] = ch;
454 (*tok)[1] = 0;
455 return type;
456
457 case EVENT_OP:
458 switch (ch) {
459 case '-':
460 next_ch = __peek_char();
461 if (next_ch == '>') {
462 buf[i++] = __read_char();
463 break;
464 }
465 /* fall through */
466 case '+':
467 case '|':
468 case '&':
469 case '>':
470 case '<':
471 last_ch = ch;
472 ch = __peek_char();
473 if (ch != last_ch)
474 goto test_equal;
475 buf[i++] = __read_char();
476 switch (last_ch) {
477 case '>':
478 case '<':
479 goto test_equal;
480 default:
481 break;
482 }
483 break;
484 case '!':
485 case '=':
486 goto test_equal;
487 default: /* what should we do instead? */
488 break;
489 }
490 buf[i] = 0;
491 *tok = strdup(buf);
492 return type;
493
494 test_equal:
495 ch = __peek_char();
496 if (ch == '=')
497 buf[i++] = __read_char();
498 break;
499
500 case EVENT_DQUOTE:
501 case EVENT_SQUOTE:
502 /* don't keep quotes */
503 i--;
504 quote_ch = ch;
505 last_ch = 0;
506 do {
507 if (i == (BUFSIZ - 1)) {
508 buf[i] = 0;
509 if (*tok) {
510 *tok = realloc(*tok, tok_size + BUFSIZ);
511 if (!*tok)
512 return EVENT_NONE;
513 strcat(*tok, buf);
514 } else
515 *tok = strdup(buf);
516
517 if (!*tok)
518 return EVENT_NONE;
519 tok_size += BUFSIZ;
520 i = 0;
521 }
522 last_ch = ch;
523 ch = __read_char();
524 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\');
526 /* remove the last quote */
527 i--;
528 goto out;
529
530 case EVENT_ERROR ... EVENT_SPACE:
531 case EVENT_ITEM:
532 default:
533 break;
534 }
535
536 while (get_type(__peek_char()) == type) {
537 if (i == (BUFSIZ - 1)) {
538 buf[i] = 0;
539 if (*tok) {
540 *tok = realloc(*tok, tok_size + BUFSIZ);
541 if (!*tok)
542 return EVENT_NONE;
543 strcat(*tok, buf);
544 } else
545 *tok = strdup(buf);
546
547 if (!*tok)
548 return EVENT_NONE;
549 tok_size += BUFSIZ;
550 i = 0;
551 }
552 ch = __read_char();
553 buf[i++] = ch;
554 }
555
556 out:
557 buf[i] = 0;
558 if (*tok) {
559 *tok = realloc(*tok, tok_size + i);
560 if (!*tok)
561 return EVENT_NONE;
562 strcat(*tok, buf);
563 } else
564 *tok = strdup(buf);
565 if (!*tok)
566 return EVENT_NONE;
567
568 return type;
569}
570
571static void free_token(char *tok)
572{
573 if (tok)
574 free(tok);
575}
576
577static enum event_type read_token(char **tok)
578{
579 enum event_type type;
580
581 for (;;) {
582 type = __read_token(tok);
583 if (type != EVENT_SPACE)
584 return type;
585
586 free_token(*tok);
587 }
588
589 /* not reached */
590 return EVENT_NONE;
591}
592
593/* no newline */
594static enum event_type read_token_item(char **tok)
595{
596 enum event_type type;
597
598 for (;;) {
599 type = __read_token(tok);
600 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
601 return type;
602
603 free_token(*tok);
604 }
605
606 /* not reached */
607 return EVENT_NONE;
608}
609
610static int test_type(enum event_type type, enum event_type expect)
611{
612 if (type != expect) {
613 die("Error: expected type %d but read %d",
614 expect, type);
615 return -1;
616 }
617 return 0;
618}
619
620static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, char *expect_tok)
622{
623 if (type != expect) {
624 die("Error: expected type %d but read %d",
625 expect, type);
626 return -1;
627 }
628
629 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'",
631 expect_tok, token);
632 return -1;
633 }
634 return 0;
635}
636
637static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
638{
639 enum event_type type;
640
641 if (newline_ok)
642 type = read_token(tok);
643 else
644 type = read_token_item(tok);
645 return test_type(type, expect);
646}
647
648static int read_expect_type(enum event_type expect, char **tok)
649{
650 return __read_expect_type(expect, tok, 1);
651}
652
653static int __read_expected(enum event_type expect, char *str, int newline_ok)
654{
655 enum event_type type;
656 char *token;
657 int ret;
658
659 if (newline_ok)
660 type = read_token(&token);
661 else
662 type = read_token_item(&token);
663
664 ret = test_type_token(type, token, expect, str);
665
666 free_token(token);
667
668 return 0;
669}
670
671static int read_expected(enum event_type expect, char *str)
672{
673 return __read_expected(expect, str, 1);
674}
675
676static int read_expected_item(enum event_type expect, char *str)
677{
678 return __read_expected(expect, str, 0);
679}
680
681static char *event_read_name(void)
682{
683 char *token;
684
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0)
686 return NULL;
687
688 if (read_expected(EVENT_OP, (char *)":") < 0)
689 return NULL;
690
691 if (read_expect_type(EVENT_ITEM, &token) < 0)
692 goto fail;
693
694 return token;
695
696 fail:
697 free_token(token);
698 return NULL;
699}
700
701static int event_read_id(void)
702{
703 char *token;
704 int id;
705
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0)
707 return -1;
708
709 if (read_expected(EVENT_OP, (char *)":") < 0)
710 return -1;
711
712 if (read_expect_type(EVENT_ITEM, &token) < 0)
713 goto fail;
714
715 id = strtoul(token, NULL, 0);
716 free_token(token);
717 return id;
718
719 fail:
720 free_token(token);
721 return -1;
722}
723
724static int event_read_fields(struct event *event, struct format_field **fields)
725{
726 struct format_field *field = NULL;
727 enum event_type type;
728 char *token;
729 char *last_token;
730 int count = 0;
731
732 do {
733 type = read_token(&token);
734 if (type == EVENT_NEWLINE) {
735 free_token(token);
736 return count;
737 }
738
739 count++;
740
741 if (test_type_token(type, token, EVENT_ITEM, (char *)"field"))
742 goto fail;
743 free_token(token);
744
745 type = read_token(&token);
746 /*
747 * The ftrace fields may still use the "special" name.
748 * Just ignore it.
749 */
750 if (event->flags & EVENT_FL_ISFTRACE &&
751 type == EVENT_ITEM && strcmp(token, "special") == 0) {
752 free_token(token);
753 type = read_token(&token);
754 }
755
756 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0)
757 return -1;
758
759 if (read_expect_type(EVENT_ITEM, &token) < 0)
760 goto fail;
761
762 last_token = token;
763
764 field = malloc_or_die(sizeof(*field));
765 memset(field, 0, sizeof(*field));
766
767 /* read the rest of the type */
768 for (;;) {
769 type = read_token(&token);
770 if (type == EVENT_ITEM ||
771 (type == EVENT_OP && strcmp(token, "*") == 0) ||
772 /*
773 * Some of the ftrace fields are broken and have
774 * an illegal "." in them.
775 */
776 (event->flags & EVENT_FL_ISFTRACE &&
777 type == EVENT_OP && strcmp(token, ".") == 0)) {
778
779 if (strcmp(token, "*") == 0)
780 field->flags |= FIELD_IS_POINTER;
781
782 if (field->type) {
783 field->type = realloc(field->type,
784 strlen(field->type) +
785 strlen(last_token) + 2);
786 strcat(field->type, " ");
787 strcat(field->type, last_token);
788 } else
789 field->type = last_token;
790 last_token = token;
791 continue;
792 }
793
794 break;
795 }
796
797 if (!field->type) {
798 die("no type found");
799 goto fail;
800 }
801 field->name = last_token;
802
803 if (test_type(type, EVENT_OP))
804 goto fail;
805
806 if (strcmp(token, "[") == 0) {
807 enum event_type last_type = type;
808 char *brackets = token;
809 int len;
810
811 field->flags |= FIELD_IS_ARRAY;
812
813 type = read_token(&token);
814 while (strcmp(token, "]") != 0) {
815 if (last_type == EVENT_ITEM &&
816 type == EVENT_ITEM)
817 len = 2;
818 else
819 len = 1;
820 last_type = type;
821
822 brackets = realloc(brackets,
823 strlen(brackets) +
824 strlen(token) + len);
825 if (len == 2)
826 strcat(brackets, " ");
827 strcat(brackets, token);
828 free_token(token);
829 type = read_token(&token);
830 if (type == EVENT_NONE) {
831 die("failed to find token");
832 goto fail;
833 }
834 }
835
836 free_token(token);
837
838 brackets = realloc(brackets, strlen(brackets) + 2);
839 strcat(brackets, "]");
840
841 /* add brackets to type */
842
843 type = read_token(&token);
844 /*
845 * If the next token is not an OP, then it is of
846 * the format: type [] item;
847 */
848 if (type == EVENT_ITEM) {
849 field->type = realloc(field->type,
850 strlen(field->type) +
851 strlen(field->name) +
852 strlen(brackets) + 2);
853 strcat(field->type, " ");
854 strcat(field->type, field->name);
855 free_token(field->name);
856 strcat(field->type, brackets);
857 field->name = token;
858 type = read_token(&token);
859 } else {
860 field->type = realloc(field->type,
861 strlen(field->type) +
862 strlen(brackets) + 1);
863 strcat(field->type, brackets);
864 }
865 free(brackets);
866 }
867
868 if (test_type_token(type, token, EVENT_OP, (char *)";"))
869 goto fail;
870 free_token(token);
871
872 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
873 goto fail_expect;
874
875 if (read_expected(EVENT_OP, (char *)":") < 0)
876 goto fail_expect;
877
878 if (read_expect_type(EVENT_ITEM, &token))
879 goto fail;
880 field->offset = strtoul(token, NULL, 0);
881 free_token(token);
882
883 if (read_expected(EVENT_OP, (char *)";") < 0)
884 goto fail_expect;
885
886 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
887 goto fail_expect;
888
889 if (read_expected(EVENT_OP, (char *)":") < 0)
890 goto fail_expect;
891
892 if (read_expect_type(EVENT_ITEM, &token))
893 goto fail;
894 field->size = strtoul(token, NULL, 0);
895 free_token(token);
896
897 if (read_expected(EVENT_OP, (char *)";") < 0)
898 goto fail_expect;
899
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
901 goto fail;
902 free_token(token);
903
904 *fields = field;
905 fields = &field->next;
906
907 } while (1);
908
909 return 0;
910
911fail:
912 free_token(token);
913fail_expect:
914 if (field)
915 free(field);
916 return -1;
917}
918
919static int event_read_format(struct event *event)
920{
921 char *token;
922 int ret;
923
924 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0)
925 return -1;
926
927 if (read_expected(EVENT_OP, (char *)":") < 0)
928 return -1;
929
930 if (read_expect_type(EVENT_NEWLINE, &token))
931 goto fail;
932 free_token(token);
933
934 ret = event_read_fields(event, &event->format.common_fields);
935 if (ret < 0)
936 return ret;
937 event->format.nr_common = ret;
938
939 ret = event_read_fields(event, &event->format.fields);
940 if (ret < 0)
941 return ret;
942 event->format.nr_fields = ret;
943
944 return 0;
945
946 fail:
947 free_token(token);
948 return -1;
949}
950
951enum event_type
952process_arg_token(struct event *event, struct print_arg *arg,
953 char **tok, enum event_type type);
954
955static enum event_type
956process_arg(struct event *event, struct print_arg *arg, char **tok)
957{
958 enum event_type type;
959 char *token;
960
961 type = read_token(&token);
962 *tok = token;
963
964 return process_arg_token(event, arg, tok, type);
965}
966
967static enum event_type
968process_cond(struct event *event, struct print_arg *top, char **tok)
969{
970 struct print_arg *arg, *left, *right;
971 enum event_type type;
972 char *token = NULL;
973
974 arg = malloc_or_die(sizeof(*arg));
975 memset(arg, 0, sizeof(*arg));
976
977 left = malloc_or_die(sizeof(*left));
978
979 right = malloc_or_die(sizeof(*right));
980
981 arg->type = PRINT_OP;
982 arg->op.left = left;
983 arg->op.right = right;
984
985 *tok = NULL;
986 type = process_arg(event, left, &token);
987 if (test_type_token(type, token, EVENT_OP, (char *)":"))
988 goto out_free;
989
990 arg->op.op = token;
991
992 type = process_arg(event, right, &token);
993
994 top->op.right = arg;
995
996 *tok = token;
997 return type;
998
999out_free:
1000 free_token(*tok);
1001 free(right);
1002 free(left);
1003 free_arg(arg);
1004 return EVENT_ERROR;
1005}
1006
1007static int get_op_prio(char *op)
1008{
1009 if (!op[1]) {
1010 switch (op[0]) {
1011 case '*':
1012 case '/':
1013 case '%':
1014 return 6;
1015 case '+':
1016 case '-':
1017 return 7;
1018 /* '>>' and '<<' are 8 */
1019 case '<':
1020 case '>':
1021 return 9;
1022 /* '==' and '!=' are 10 */
1023 case '&':
1024 return 11;
1025 case '^':
1026 return 12;
1027 case '|':
1028 return 13;
1029 case '?':
1030 return 16;
1031 default:
1032 die("unknown op '%c'", op[0]);
1033 return -1;
1034 }
1035 } else {
1036 if (strcmp(op, "++") == 0 ||
1037 strcmp(op, "--") == 0) {
1038 return 3;
1039 } else if (strcmp(op, ">>") == 0 ||
1040 strcmp(op, "<<") == 0) {
1041 return 8;
1042 } else if (strcmp(op, ">=") == 0 ||
1043 strcmp(op, "<=") == 0) {
1044 return 9;
1045 } else if (strcmp(op, "==") == 0 ||
1046 strcmp(op, "!=") == 0) {
1047 return 10;
1048 } else if (strcmp(op, "&&") == 0) {
1049 return 14;
1050 } else if (strcmp(op, "||") == 0) {
1051 return 15;
1052 } else {
1053 die("unknown op '%s'", op);
1054 return -1;
1055 }
1056 }
1057}
1058
1059static void set_op_prio(struct print_arg *arg)
1060{
1061
1062 /* single ops are the greatest */
1063 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
1064 arg->op.prio = 0;
1065 return;
1066 }
1067
1068 arg->op.prio = get_op_prio(arg->op.op);
1069}
1070
1071static enum event_type
1072process_op(struct event *event, struct print_arg *arg, char **tok)
1073{
1074 struct print_arg *left, *right = NULL;
1075 enum event_type type;
1076 char *token;
1077
1078 /* the op is passed in via tok */
1079 token = *tok;
1080
1081 if (arg->type == PRINT_OP && !arg->op.left) {
1082 /* handle single op */
1083 if (token[1]) {
1084 die("bad op token %s", token);
1085 return EVENT_ERROR;
1086 }
1087 switch (token[0]) {
1088 case '!':
1089 case '+':
1090 case '-':
1091 break;
1092 default:
1093 die("bad op token %s", token);
1094 return EVENT_ERROR;
1095 }
1096
1097 /* make an empty left */
1098 left = malloc_or_die(sizeof(*left));
1099 left->type = PRINT_NULL;
1100 arg->op.left = left;
1101
1102 right = malloc_or_die(sizeof(*right));
1103 arg->op.right = right;
1104
1105 type = process_arg(event, right, tok);
1106
1107 } else if (strcmp(token, "?") == 0) {
1108
1109 left = malloc_or_die(sizeof(*left));
1110 /* copy the top arg to the left */
1111 *left = *arg;
1112
1113 arg->type = PRINT_OP;
1114 arg->op.op = token;
1115 arg->op.left = left;
1116 arg->op.prio = 0;
1117
1118 type = process_cond(event, arg, tok);
1119
1120 } else if (strcmp(token, ">>") == 0 ||
1121 strcmp(token, "<<") == 0 ||
1122 strcmp(token, "&") == 0 ||
1123 strcmp(token, "|") == 0 ||
1124 strcmp(token, "&&") == 0 ||
1125 strcmp(token, "||") == 0 ||
1126 strcmp(token, "-") == 0 ||
1127 strcmp(token, "+") == 0 ||
1128 strcmp(token, "*") == 0 ||
1129 strcmp(token, "^") == 0 ||
1130 strcmp(token, "/") == 0 ||
1131 strcmp(token, "==") == 0 ||
1132 strcmp(token, "!=") == 0) {
1133
1134 left = malloc_or_die(sizeof(*left));
1135
1136 /* copy the top arg to the left */
1137 *left = *arg;
1138
1139 arg->type = PRINT_OP;
1140 arg->op.op = token;
1141 arg->op.left = left;
1142
1143 set_op_prio(arg);
1144
1145 right = malloc_or_die(sizeof(*right));
1146
1147 type = process_arg(event, right, tok);
1148
1149 arg->op.right = right;
1150
1151 } else {
1152 die("unknown op '%s'", token);
1153 /* the arg is now the left side */
1154 return EVENT_NONE;
1155 }
1156
1157
1158 if (type == EVENT_OP) {
1159 int prio;
1160
1161 /* higher prios need to be closer to the root */
1162 prio = get_op_prio(*tok);
1163
1164 if (prio > arg->op.prio)
1165 return process_op(event, arg, tok);
1166
1167 return process_op(event, right, tok);
1168 }
1169
1170 return type;
1171}
1172
1173static enum event_type
1174process_entry(struct event *event __unused, struct print_arg *arg,
1175 char **tok)
1176{
1177 enum event_type type;
1178 char *field;
1179 char *token;
1180
1181 if (read_expected(EVENT_OP, (char *)"->") < 0)
1182 return EVENT_ERROR;
1183
1184 if (read_expect_type(EVENT_ITEM, &token) < 0)
1185 goto fail;
1186 field = token;
1187
1188 arg->type = PRINT_FIELD;
1189 arg->field.name = field;
1190
1191 type = read_token(&token);
1192 *tok = token;
1193
1194 return type;
1195
1196fail:
1197 free_token(token);
1198 return EVENT_ERROR;
1199}
1200
1201static char *arg_eval (struct print_arg *arg);
1202
1203static long long arg_num_eval(struct print_arg *arg)
1204{
1205 long long left, right;
1206 long long val = 0;
1207
1208 switch (arg->type) {
1209 case PRINT_ATOM:
1210 val = strtoll(arg->atom.atom, NULL, 0);
1211 break;
1212 case PRINT_TYPE:
1213 val = arg_num_eval(arg->typecast.item);
1214 break;
1215 case PRINT_OP:
1216 switch (arg->op.op[0]) {
1217 case '|':
1218 left = arg_num_eval(arg->op.left);
1219 right = arg_num_eval(arg->op.right);
1220 if (arg->op.op[1])
1221 val = left || right;
1222 else
1223 val = left | right;
1224 break;
1225 case '&':
1226 left = arg_num_eval(arg->op.left);
1227 right = arg_num_eval(arg->op.right);
1228 if (arg->op.op[1])
1229 val = left && right;
1230 else
1231 val = left & right;
1232 break;
1233 case '<':
1234 left = arg_num_eval(arg->op.left);
1235 right = arg_num_eval(arg->op.right);
1236 switch (arg->op.op[1]) {
1237 case 0:
1238 val = left < right;
1239 break;
1240 case '<':
1241 val = left << right;
1242 break;
1243 case '=':
1244 val = left <= right;
1245 break;
1246 default:
1247 die("unknown op '%s'", arg->op.op);
1248 }
1249 break;
1250 case '>':
1251 left = arg_num_eval(arg->op.left);
1252 right = arg_num_eval(arg->op.right);
1253 switch (arg->op.op[1]) {
1254 case 0:
1255 val = left > right;
1256 break;
1257 case '>':
1258 val = left >> right;
1259 break;
1260 case '=':
1261 val = left >= right;
1262 break;
1263 default:
1264 die("unknown op '%s'", arg->op.op);
1265 }
1266 break;
1267 case '=':
1268 left = arg_num_eval(arg->op.left);
1269 right = arg_num_eval(arg->op.right);
1270
1271 if (arg->op.op[1] != '=')
1272 die("unknown op '%s'", arg->op.op);
1273
1274 val = left == right;
1275 break;
1276 case '!':
1277 left = arg_num_eval(arg->op.left);
1278 right = arg_num_eval(arg->op.right);
1279
1280 switch (arg->op.op[1]) {
1281 case '=':
1282 val = left != right;
1283 break;
1284 default:
1285 die("unknown op '%s'", arg->op.op);
1286 }
1287 break;
1288 default:
1289 die("unknown op '%s'", arg->op.op);
1290 }
1291 break;
1292
1293 case PRINT_NULL:
1294 case PRINT_FIELD ... PRINT_SYMBOL:
1295 case PRINT_STRING:
1296 default:
1297 die("invalid eval type %d", arg->type);
1298
1299 }
1300 return val;
1301}
1302
1303static char *arg_eval (struct print_arg *arg)
1304{
1305 long long val;
1306 static char buf[20];
1307
1308 switch (arg->type) {
1309 case PRINT_ATOM:
1310 return arg->atom.atom;
1311 case PRINT_TYPE:
1312 return arg_eval(arg->typecast.item);
1313 case PRINT_OP:
1314 val = arg_num_eval(arg);
1315 sprintf(buf, "%lld", val);
1316 return buf;
1317
1318 case PRINT_NULL:
1319 case PRINT_FIELD ... PRINT_SYMBOL:
1320 case PRINT_STRING:
1321 default:
1322 die("invalid eval type %d", arg->type);
1323 break;
1324 }
1325
1326 return NULL;
1327}
1328
1329static enum event_type
1330process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1331{
1332 enum event_type type;
1333 struct print_arg *arg = NULL;
1334 struct print_flag_sym *field;
1335 char *token = NULL;
1336 char *value;
1337
1338 do {
1339 free_token(token);
1340 type = read_token_item(&token);
1341 if (test_type_token(type, token, EVENT_OP, (char *)"{"))
1342 break;
1343
1344 arg = malloc_or_die(sizeof(*arg));
1345
1346 free_token(token);
1347 type = process_arg(event, arg, &token);
1348 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1349 goto out_free;
1350
1351 field = malloc_or_die(sizeof(*field));
1352 memset(field, 0, sizeof(field));
1353
1354 value = arg_eval(arg);
1355 field->value = strdup(value);
1356
1357 free_token(token);
1358 type = process_arg(event, arg, &token);
1359 if (test_type_token(type, token, EVENT_OP, (char *)"}"))
1360 goto out_free;
1361
1362 value = arg_eval(arg);
1363 field->str = strdup(value);
1364 free_arg(arg);
1365 arg = NULL;
1366
1367 *list = field;
1368 list = &field->next;
1369
1370 free_token(token);
1371 type = read_token_item(&token);
1372 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1373
1374 *tok = token;
1375 return type;
1376
1377out_free:
1378 free_arg(arg);
1379 free_token(token);
1380
1381 return EVENT_ERROR;
1382}
1383
1384static enum event_type
1385process_flags(struct event *event, struct print_arg *arg, char **tok)
1386{
1387 struct print_arg *field;
1388 enum event_type type;
1389 char *token;
1390
1391 memset(arg, 0, sizeof(*arg));
1392 arg->type = PRINT_FLAGS;
1393
1394 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
1395 return EVENT_ERROR;
1396
1397 field = malloc_or_die(sizeof(*field));
1398
1399 type = process_arg(event, field, &token);
1400 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1401 goto out_free;
1402
1403 arg->flags.field = field;
1404
1405 type = read_token_item(&token);
1406 if (event_item_type(type)) {
1407 arg->flags.delim = token;
1408 type = read_token_item(&token);
1409 }
1410
1411 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1412 goto out_free;
1413
1414 type = process_fields(event, &arg->flags.flags, &token);
1415 if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
1416 goto out_free;
1417
1418 free_token(token);
1419 type = read_token_item(tok);
1420 return type;
1421
1422out_free:
1423 free_token(token);
1424 return EVENT_ERROR;
1425}
1426
1427static enum event_type
1428process_symbols(struct event *event, struct print_arg *arg, char **tok)
1429{
1430 struct print_arg *field;
1431 enum event_type type;
1432 char *token;
1433
1434 memset(arg, 0, sizeof(*arg));
1435 arg->type = PRINT_SYMBOL;
1436
1437 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
1438 return EVENT_ERROR;
1439
1440 field = malloc_or_die(sizeof(*field));
1441
1442 type = process_arg(event, field, &token);
1443 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1444 goto out_free;
1445
1446 arg->symbol.field = field;
1447
1448 type = process_fields(event, &arg->symbol.symbols, &token);
1449 if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
1450 goto out_free;
1451
1452 free_token(token);
1453 type = read_token_item(tok);
1454 return type;
1455
1456out_free:
1457 free_token(token);
1458 return EVENT_ERROR;
1459}
1460
1461static enum event_type
1462process_paren(struct event *event, struct print_arg *arg, char **tok)
1463{
1464 struct print_arg *item_arg;
1465 enum event_type type;
1466 int ptr_cast = 0;
1467 char *token;
1468
1469 type = process_arg(event, arg, &token);
1470
1471 if (type == EVENT_ERROR)
1472 return EVENT_ERROR;
1473
1474 if (type == EVENT_OP) {
1475 /* handle the ptr casts */
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
1490 if (type == EVENT_ERROR)
1491 return EVENT_ERROR;
1492 }
1493 }
1494
1495 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) {
1496 free_token(token);
1497 return EVENT_ERROR;
1498 }
1499
1500 free_token(token);
1501 type = read_token_item(&token);
1502
1503 /*
1504 * If the next token is an item or another open paren, then
1505 * this was a typecast.
1506 */
1507 if (event_item_type(type) ||
1508 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1509
1510 /* make this a typecast and contine */
1511
1512 /* prevous must be an atom */
1513 if (arg->type != PRINT_ATOM)
1514 die("previous needed to be PRINT_ATOM");
1515
1516 item_arg = malloc_or_die(sizeof(*item_arg));
1517
1518 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;
1527 arg->typecast.item = item_arg;
1528 type = process_arg_token(event, item_arg, &token, type);
1529
1530 }
1531
1532 *tok = token;
1533 return type;
1534}
1535
1536
1537static enum event_type
1538process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1539{
1540 enum event_type type;
1541 char *token;
1542
1543 if (read_expected(EVENT_DELIM, (char *)"(") < 0)
1544 return EVENT_ERROR;
1545
1546 if (read_expect_type(EVENT_ITEM, &token) < 0)
1547 goto fail;
1548
1549 arg->type = PRINT_STRING;
1550 arg->string.string = token;
1551 arg->string.offset = -1;
1552
1553 if (read_expected(EVENT_DELIM, (char *)")") < 0)
1554 return EVENT_ERROR;
1555
1556 type = read_token(&token);
1557 *tok = token;
1558
1559 return type;
1560fail:
1561 free_token(token);
1562 return EVENT_ERROR;
1563}
1564
1565enum event_type
1566process_arg_token(struct event *event, struct print_arg *arg,
1567 char **tok, enum event_type type)
1568{
1569 char *token;
1570 char *atom;
1571
1572 token = *tok;
1573
1574 switch (type) {
1575 case EVENT_ITEM:
1576 if (strcmp(token, "REC") == 0) {
1577 free_token(token);
1578 type = process_entry(event, arg, &token);
1579 } else if (strcmp(token, "__print_flags") == 0) {
1580 free_token(token);
1581 type = process_flags(event, arg, &token);
1582 } else if (strcmp(token, "__print_symbolic") == 0) {
1583 free_token(token);
1584 type = process_symbols(event, arg, &token);
1585 } else if (strcmp(token, "__get_str") == 0) {
1586 free_token(token);
1587 type = process_str(event, arg, &token);
1588 } else {
1589 atom = token;
1590 /* test the next token */
1591 type = read_token_item(&token);
1592
1593 /* atoms can be more than one token long */
1594 while (type == EVENT_ITEM) {
1595 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1596 strcat(atom, " ");
1597 strcat(atom, token);
1598 free_token(token);
1599 type = read_token_item(&token);
1600 }
1601
1602 /* todo, test for function */
1603
1604 arg->type = PRINT_ATOM;
1605 arg->atom.atom = atom;
1606 }
1607 break;
1608 case EVENT_DQUOTE:
1609 case EVENT_SQUOTE:
1610 arg->type = PRINT_ATOM;
1611 arg->atom.atom = token;
1612 type = read_token_item(&token);
1613 break;
1614 case EVENT_DELIM:
1615 if (strcmp(token, "(") == 0) {
1616 free_token(token);
1617 type = process_paren(event, arg, &token);
1618 break;
1619 }
1620 case EVENT_OP:
1621 /* handle single ops */
1622 arg->type = PRINT_OP;
1623 arg->op.op = token;
1624 arg->op.left = NULL;
1625 type = process_op(event, arg, &token);
1626
1627 break;
1628
1629 case EVENT_ERROR ... EVENT_NEWLINE:
1630 default:
1631 die("unexpected type %d", type);
1632 }
1633 *tok = token;
1634
1635 return type;
1636}
1637
1638static int event_read_print_args(struct event *event, struct print_arg **list)
1639{
1640 enum event_type type;
1641 struct print_arg *arg;
1642 char *token;
1643 int args = 0;
1644
1645 do {
1646 arg = malloc_or_die(sizeof(*arg));
1647 memset(arg, 0, sizeof(*arg));
1648
1649 type = process_arg(event, arg, &token);
1650
1651 if (type == EVENT_ERROR) {
1652 free_arg(arg);
1653 return -1;
1654 }
1655
1656 *list = arg;
1657 args++;
1658
1659 if (type == EVENT_OP) {
1660 type = process_op(event, arg, &token);
1661 list = &arg->next;
1662 continue;
1663 }
1664
1665 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1666 free_token(token);
1667 *list = arg;
1668 list = &arg->next;
1669 continue;
1670 }
1671 break;
1672 } while (type != EVENT_NONE);
1673
1674 if (type != EVENT_NONE)
1675 free_token(token);
1676
1677 return args;
1678}
1679
1680static int event_read_print(struct event *event)
1681{
1682 enum event_type type;
1683 char *token;
1684 int ret;
1685
1686 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0)
1687 return -1;
1688
1689 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0)
1690 return -1;
1691
1692 if (read_expected(EVENT_OP, (char *)":") < 0)
1693 return -1;
1694
1695 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1696 goto fail;
1697
1698 event->print_fmt.format = token;
1699 event->print_fmt.args = NULL;
1700
1701 /* ok to have no arg */
1702 type = read_token_item(&token);
1703
1704 if (type == EVENT_NONE)
1705 return 0;
1706
1707 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1708 goto fail;
1709
1710 free_token(token);
1711
1712 ret = event_read_print_args(event, &event->print_fmt.args);
1713 if (ret < 0)
1714 return -1;
1715
1716 return 0;
1717
1718 fail:
1719 free_token(token);
1720 return -1;
1721}
1722
1723static struct format_field *
1724find_common_field(struct event *event, const char *name)
1725{
1726 struct format_field *format;
1727
1728 for (format = event->format.common_fields;
1729 format; format = format->next) {
1730 if (strcmp(format->name, name) == 0)
1731 break;
1732 }
1733
1734 return format;
1735}
1736
1737static struct format_field *
1738find_field(struct event *event, const char *name)
1739{
1740 struct format_field *format;
1741
1742 for (format = event->format.fields;
1743 format; format = format->next) {
1744 if (strcmp(format->name, name) == 0)
1745 break;
1746 }
1747
1748 return format;
1749}
1750
1751static struct format_field *
1752find_any_field(struct event *event, const char *name)
1753{
1754 struct format_field *format;
1755
1756 format = find_common_field(event, name);
1757 if (format)
1758 return format;
1759 return find_field(event, name);
1760}
1761
1762static unsigned long long read_size(void *ptr, int size)
1763{
1764 switch (size) {
1765 case 1:
1766 return *(unsigned char *)ptr;
1767 case 2:
1768 return data2host2(ptr);
1769 case 4:
1770 return data2host4(ptr);
1771 case 8:
1772 return data2host8(ptr);
1773 default:
1774 /* BUG! */
1775 return 0;
1776 }
1777}
1778
1779unsigned long long
1780raw_field_value(struct event *event, const char *name, void *data)
1781{
1782 struct format_field *field;
1783
1784 field = find_any_field(event, name);
1785 if (!field)
1786 return 0ULL;
1787
1788 return read_size(data + field->offset, field->size);
1789}
1790
1791void *raw_field_ptr(struct event *event, const char *name, void *data)
1792{
1793 struct format_field *field;
1794
1795 field = find_any_field(event, name);
1796 if (!field)
1797 return NULL;
1798
1799 return data + field->offset;
1800}
1801
1802static int get_common_info(const char *type, int *offset, int *size)
1803{
1804 struct event *event;
1805 struct format_field *field;
1806
1807 /*
1808 * All events should have the same common elements.
1809 * Pick any event to find where the type is;
1810 */
1811 if (!event_list)
1812 die("no event_list!");
1813
1814 event = event_list;
1815 field = find_common_field(event, type);
1816 if (!field)
1817 die("field '%s' not found", type);
1818
1819 *offset = field->offset;
1820 *size = field->size;
1821
1822 return 0;
1823}
1824
1825int trace_parse_common_type(void *data)
1826{
1827 static int type_offset;
1828 static int type_size;
1829 int ret;
1830
1831 if (!type_size) {
1832 ret = get_common_info("common_type",
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0)
1836 return ret;
1837 }
1838 return read_size(data + type_offset, type_size);
1839}
1840
1841static int parse_common_pid(void *data)
1842{
1843 static int pid_offset;
1844 static int pid_size;
1845 int ret;
1846
1847 if (!pid_size) {
1848 ret = get_common_info("common_pid",
1849 &pid_offset,
1850 &pid_size);
1851 if (ret < 0)
1852 return ret;
1853 }
1854
1855 return read_size(data + pid_offset, pid_size);
1856}
1857
1858struct event *trace_find_event(int id)
1859{
1860 struct event *event;
1861
1862 for (event = event_list; event; event = event->next) {
1863 if (event->id == id)
1864 break;
1865 }
1866 return event;
1867}
1868
1869static unsigned long long eval_num_arg(void *data, int size,
1870 struct event *event, struct print_arg *arg)
1871{
1872 unsigned long long val = 0;
1873 unsigned long long left, right;
1874
1875 switch (arg->type) {
1876 case PRINT_NULL:
1877 /* ?? */
1878 return 0;
1879 case PRINT_ATOM:
1880 return strtoull(arg->atom.atom, NULL, 0);
1881 case PRINT_FIELD:
1882 if (!arg->field.field) {
1883 arg->field.field = find_any_field(event, arg->field.name);
1884 if (!arg->field.field)
1885 die("field %s not found", arg->field.name);
1886 }
1887 /* must be a number */
1888 val = read_size(data + arg->field.field->offset,
1889 arg->field.field->size);
1890 break;
1891 case PRINT_FLAGS:
1892 case PRINT_SYMBOL:
1893 break;
1894 case PRINT_TYPE:
1895 return eval_num_arg(data, size, event, arg->typecast.item);
1896 case PRINT_STRING:
1897 return 0;
1898 break;
1899 case PRINT_OP:
1900 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) {
1903 case '|':
1904 if (arg->op.op[1])
1905 val = left || right;
1906 else
1907 val = left | right;
1908 break;
1909 case '&':
1910 if (arg->op.op[1])
1911 val = left && right;
1912 else
1913 val = left & right;
1914 break;
1915 case '<':
1916 switch (arg->op.op[1]) {
1917 case 0:
1918 val = left < right;
1919 break;
1920 case '<':
1921 val = left << right;
1922 break;
1923 case '=':
1924 val = left <= right;
1925 break;
1926 default:
1927 die("unknown op '%s'", arg->op.op);
1928 }
1929 break;
1930 case '>':
1931 switch (arg->op.op[1]) {
1932 case 0:
1933 val = left > right;
1934 break;
1935 case '>':
1936 val = left >> right;
1937 break;
1938 case '=':
1939 val = left >= right;
1940 break;
1941 default:
1942 die("unknown op '%s'", arg->op.op);
1943 }
1944 break;
1945 case '=':
1946 if (arg->op.op[1] != '=')
1947 die("unknown op '%s'", arg->op.op);
1948 val = left == right;
1949 break;
1950 default:
1951 die("unknown op '%s'", arg->op.op);
1952 }
1953 break;
1954 default: /* not sure what to do there */
1955 return 0;
1956 }
1957 return val;
1958}
1959
1960struct flag {
1961 const char *name;
1962 unsigned long long value;
1963};
1964
1965static const struct flag flags[] = {
1966 { "HI_SOFTIRQ", 0 },
1967 { "TIMER_SOFTIRQ", 1 },
1968 { "NET_TX_SOFTIRQ", 2 },
1969 { "NET_RX_SOFTIRQ", 3 },
1970 { "BLOCK_SOFTIRQ", 4 },
1971 { "TASKLET_SOFTIRQ", 5 },
1972 { "SCHED_SOFTIRQ", 6 },
1973 { "HRTIMER_SOFTIRQ", 7 },
1974 { "RCU_SOFTIRQ", 8 },
1975
1976 { "HRTIMER_NORESTART", 0 },
1977 { "HRTIMER_RESTART", 1 },
1978};
1979
1980static unsigned long long eval_flag(const char *flag)
1981{
1982 int i;
1983
1984 /*
1985 * Some flags in the format files do not get converted.
1986 * If the flag is not numeric, see if it is something that
1987 * we already know about.
1988 */
1989 if (isdigit(flag[0]))
1990 return strtoull(flag, NULL, 0);
1991
1992 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
1993 if (strcmp(flags[i].name, flag) == 0)
1994 return flags[i].value;
1995
1996 return 0;
1997}
1998
1999static void print_str_arg(void *data, int size,
2000 struct event *event, struct print_arg *arg)
2001{
2002 struct print_flag_sym *flag;
2003 unsigned long long val, fval;
2004 char *str;
2005 int print;
2006
2007 switch (arg->type) {
2008 case PRINT_NULL:
2009 /* ?? */
2010 return;
2011 case PRINT_ATOM:
2012 printf("%s", arg->atom.atom);
2013 return;
2014 case PRINT_FIELD:
2015 if (!arg->field.field) {
2016 arg->field.field = find_any_field(event, arg->field.name);
2017 if (!arg->field.field)
2018 die("field %s not found", arg->field.name);
2019 }
2020 str = malloc_or_die(arg->field.field->size + 1);
2021 memcpy(str, data + arg->field.field->offset,
2022 arg->field.field->size);
2023 str[arg->field.field->size] = 0;
2024 printf("%s", str);
2025 free(str);
2026 break;
2027 case PRINT_FLAGS:
2028 val = eval_num_arg(data, size, event, arg->flags.field);
2029 print = 0;
2030 for (flag = arg->flags.flags; flag; flag = flag->next) {
2031 fval = eval_flag(flag->value);
2032 if (!val && !fval) {
2033 printf("%s", flag->str);
2034 break;
2035 }
2036 if (fval && (val & fval) == fval) {
2037 if (print && arg->flags.delim)
2038 printf("%s", arg->flags.delim);
2039 printf("%s", flag->str);
2040 print = 1;
2041 val &= ~fval;
2042 }
2043 }
2044 break;
2045 case PRINT_SYMBOL:
2046 val = eval_num_arg(data, size, event, arg->symbol.field);
2047 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2048 fval = eval_flag(flag->value);
2049 if (val == fval) {
2050 printf("%s", flag->str);
2051 break;
2052 }
2053 }
2054 break;
2055
2056 case PRINT_TYPE:
2057 break;
2058 case PRINT_STRING: {
2059 int str_offset;
2060
2061 if (arg->string.offset == -1) {
2062 struct format_field *f;
2063
2064 f = find_any_field(event, arg->string.string);
2065 arg->string.offset = f->offset;
2066 }
2067 str_offset = *(int *)(data + arg->string.offset);
2068 str_offset &= 0xffff;
2069 printf("%s", ((char *)data) + str_offset);
2070 break;
2071 }
2072 case PRINT_OP:
2073 /*
2074 * The only op for string should be ? :
2075 */
2076 if (arg->op.op[0] != '?')
2077 return;
2078 val = eval_num_arg(data, size, event, arg->op.left);
2079 if (val)
2080 print_str_arg(data, size, event, arg->op.right->op.left);
2081 else
2082 print_str_arg(data, size, event, arg->op.right->op.right);
2083 break;
2084 default:
2085 /* well... */
2086 break;
2087 }
2088}
2089
2090static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2091{
2092 static struct format_field *field, *ip_field;
2093 struct print_arg *args, *arg, **next;
2094 unsigned long long ip, val;
2095 char *ptr;
2096 void *bptr;
2097
2098 if (!field) {
2099 field = find_field(event, "buf");
2100 if (!field)
2101 die("can't find buffer field for binary printk");
2102 ip_field = find_field(event, "ip");
2103 if (!ip_field)
2104 die("can't find ip field for binary printk");
2105 }
2106
2107 ip = read_size(data + ip_field->offset, ip_field->size);
2108
2109 /*
2110 * The first arg is the IP pointer.
2111 */
2112 args = malloc_or_die(sizeof(*args));
2113 arg = args;
2114 arg->next = NULL;
2115 next = &arg->next;
2116
2117 arg->type = PRINT_ATOM;
2118 arg->atom.atom = malloc_or_die(32);
2119 sprintf(arg->atom.atom, "%lld", ip);
2120
2121 /* skip the first "%pf : " */
2122 for (ptr = fmt + 6, bptr = data + field->offset;
2123 bptr < data + size && *ptr; ptr++) {
2124 int ls = 0;
2125
2126 if (*ptr == '%') {
2127 process_again:
2128 ptr++;
2129 switch (*ptr) {
2130 case '%':
2131 break;
2132 case 'l':
2133 ls++;
2134 goto process_again;
2135 case 'L':
2136 ls = 2;
2137 goto process_again;
2138 case '0' ... '9':
2139 goto process_again;
2140 case 'p':
2141 ls = 1;
2142 /* fall through */
2143 case 'd':
2144 case 'u':
2145 case 'x':
2146 case 'i':
2147 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
2148 ~(long_size - 1));
2149 switch (ls) {
2150 case 0:
2151 case 1:
2152 ls = long_size;
2153 break;
2154 case 2:
2155 ls = 8;
2156 default:
2157 break;
2158 }
2159 val = read_size(bptr, ls);
2160 bptr += ls;
2161 arg = malloc_or_die(sizeof(*arg));
2162 arg->next = NULL;
2163 arg->type = PRINT_ATOM;
2164 arg->atom.atom = malloc_or_die(32);
2165 sprintf(arg->atom.atom, "%lld", val);
2166 *next = arg;
2167 next = &arg->next;
2168 break;
2169 case 's':
2170 arg = malloc_or_die(sizeof(*arg));
2171 arg->next = NULL;
2172 arg->type = PRINT_STRING;
2173 arg->string.string = strdup(bptr);
2174 bptr += strlen(bptr) + 1;
2175 *next = arg;
2176 next = &arg->next;
2177 default:
2178 break;
2179 }
2180 }
2181 }
2182
2183 return args;
2184}
2185
2186static void free_args(struct print_arg *args)
2187{
2188 struct print_arg *next;
2189
2190 while (args) {
2191 next = args->next;
2192
2193 if (args->type == PRINT_ATOM)
2194 free(args->atom.atom);
2195 else
2196 free(args->string.string);
2197 free(args);
2198 args = next;
2199 }
2200}
2201
2202static char *get_bprint_format(void *data, int size __unused, struct event *event)
2203{
2204 unsigned long long addr;
2205 static struct format_field *field;
2206 struct printk_map *printk;
2207 char *format;
2208 char *p;
2209
2210 if (!field) {
2211 field = find_field(event, "fmt");
2212 if (!field)
2213 die("can't find format field for binary printk");
2214 printf("field->offset = %d size=%d\n", field->offset, field->size);
2215 }
2216
2217 addr = read_size(data + field->offset, field->size);
2218
2219 printk = find_printk(addr);
2220 if (!printk) {
2221 format = malloc_or_die(45);
2222 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2223 addr);
2224 return format;
2225 }
2226
2227 p = printk->printk;
2228 /* Remove any quotes. */
2229 if (*p == '"')
2230 p++;
2231 format = malloc_or_die(strlen(p) + 10);
2232 sprintf(format, "%s : %s", "%pf", p);
2233 /* remove ending quotes and new line since we will add one too */
2234 p = format + strlen(format) - 1;
2235 if (*p == '"')
2236 *p = 0;
2237
2238 p -= 2;
2239 if (strcmp(p, "\\n") == 0)
2240 *p = 0;
2241
2242 return format;
2243}
2244
2245static void pretty_print(void *data, int size, struct event *event)
2246{
2247 struct print_fmt *print_fmt = &event->print_fmt;
2248 struct print_arg *arg = print_fmt->args;
2249 struct print_arg *args = NULL;
2250 const char *ptr = print_fmt->format;
2251 unsigned long long val;
2252 struct func_map *func;
2253 const char *saveptr;
2254 char *bprint_fmt = NULL;
2255 char format[32];
2256 int show_func;
2257 int len;
2258 int ls;
2259
2260 if (event->flags & EVENT_FL_ISFUNC)
2261 ptr = " %pF <-- %pF";
2262
2263 if (event->flags & EVENT_FL_ISBPRINT) {
2264 bprint_fmt = get_bprint_format(data, size, event);
2265 args = make_bprint_args(bprint_fmt, data, size, event);
2266 arg = args;
2267 ptr = bprint_fmt;
2268 }
2269
2270 for (; *ptr; ptr++) {
2271 ls = 0;
2272 if (*ptr == '%') {
2273 saveptr = ptr;
2274 show_func = 0;
2275 cont_process:
2276 ptr++;
2277 switch (*ptr) {
2278 case '%':
2279 printf("%%");
2280 break;
2281 case 'l':
2282 ls++;
2283 goto cont_process;
2284 case 'L':
2285 ls = 2;
2286 goto cont_process;
2287 case 'z':
2288 case 'Z':
2289 case '0' ... '9':
2290 goto cont_process;
2291 case 'p':
2292 if (long_size == 4)
2293 ls = 1;
2294 else
2295 ls = 2;
2296
2297 if (*(ptr+1) == 'F' ||
2298 *(ptr+1) == 'f') {
2299 ptr++;
2300 show_func = *ptr;
2301 }
2302
2303 /* fall through */
2304 case 'd':
2305 case 'i':
2306 case 'x':
2307 case 'X':
2308 case 'u':
2309 if (!arg)
2310 die("no argument match");
2311
2312 len = ((unsigned long)ptr + 1) -
2313 (unsigned long)saveptr;
2314
2315 /* should never happen */
2316 if (len > 32)
2317 die("bad format!");
2318
2319 memcpy(format, saveptr, len);
2320 format[len] = 0;
2321
2322 val = eval_num_arg(data, size, event, arg);
2323 arg = arg->next;
2324
2325 if (show_func) {
2326 func = find_func(val);
2327 if (func) {
2328 printf("%s", func->func);
2329 if (show_func == 'F')
2330 printf("+0x%llx",
2331 val - func->addr);
2332 break;
2333 }
2334 }
2335 switch (ls) {
2336 case 0:
2337 printf(format, (int)val);
2338 break;
2339 case 1:
2340 printf(format, (long)val);
2341 break;
2342 case 2:
2343 printf(format, (long long)val);
2344 break;
2345 default:
2346 die("bad count (%d)", ls);
2347 }
2348 break;
2349 case 's':
2350 if (!arg)
2351 die("no matching argument");
2352
2353 print_str_arg(data, size, event, arg);
2354 arg = arg->next;
2355 break;
2356 default:
2357 printf(">%c<", *ptr);
2358
2359 }
2360 } else
2361 printf("%c", *ptr);
2362 }
2363
2364 if (args) {
2365 free_args(args);
2366 free(bprint_fmt);
2367 }
2368}
2369
2370static inline int log10_cpu(int nb)
2371{
2372 if (nb / 100)
2373 return 3;
2374 if (nb / 10)
2375 return 2;
2376 return 1;
2377}
2378
2379/* taken from Linux, written by Frederic Weisbecker */
2380static void print_graph_cpu(int cpu)
2381{
2382 int i;
2383 int log10_this = log10_cpu(cpu);
2384 int log10_all = log10_cpu(cpus);
2385
2386
2387 /*
2388 * Start with a space character - to make it stand out
2389 * to the right a bit when trace output is pasted into
2390 * email:
2391 */
2392 printf(" ");
2393
2394 /*
2395 * Tricky - we space the CPU field according to the max
2396 * number of online CPUs. On a 2-cpu system it would take
2397 * a maximum of 1 digit - on a 128 cpu system it would
2398 * take up to 3 digits:
2399 */
2400 for (i = 0; i < log10_all - log10_this; i++)
2401 printf(" ");
2402
2403 printf("%d) ", cpu);
2404}
2405
2406#define TRACE_GRAPH_PROCINFO_LENGTH 14
2407#define TRACE_GRAPH_INDENT 2
2408
2409static void print_graph_proc(int pid, const char *comm)
2410{
2411 /* sign + log10(MAX_INT) + '\0' */
2412 char pid_str[11];
2413 int spaces = 0;
2414 int len;
2415 int i;
2416
2417 sprintf(pid_str, "%d", pid);
2418
2419 /* 1 stands for the "-" character */
2420 len = strlen(comm) + strlen(pid_str) + 1;
2421
2422 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2423 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2424
2425 /* First spaces to align center */
2426 for (i = 0; i < spaces / 2; i++)
2427 printf(" ");
2428
2429 printf("%s-%s", comm, pid_str);
2430
2431 /* Last spaces to align center */
2432 for (i = 0; i < spaces - (spaces / 2); i++)
2433 printf(" ");
2434}
2435
2436static struct record *
2437get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2438 struct record *next)
2439{
2440 struct format_field *field;
2441 struct event *event;
2442 unsigned long val;
2443 int type;
2444 int pid;
2445
2446 type = trace_parse_common_type(next->data);
2447 event = trace_find_event(type);
2448 if (!event)
2449 return NULL;
2450
2451 if (!(event->flags & EVENT_FL_ISFUNCRET))
2452 return NULL;
2453
2454 pid = parse_common_pid(next->data);
2455 field = find_field(event, "func");
2456 if (!field)
2457 die("function return does not have field func");
2458
2459 val = read_size(next->data + field->offset, field->size);
2460
2461 if (cur_pid != pid || cur_func != val)
2462 return NULL;
2463
2464 /* this is a leaf, now advance the iterator */
2465 return trace_read_data(cpu);
2466}
2467
2468/* Signal a overhead of time execution to the output */
2469static void print_graph_overhead(unsigned long long duration)
2470{
2471 /* Non nested entry or return */
2472 if (duration == ~0ULL)
2473 return (void)printf(" ");
2474
2475 /* Duration exceeded 100 msecs */
2476 if (duration > 100000ULL)
2477 return (void)printf("! ");
2478
2479 /* Duration exceeded 10 msecs */
2480 if (duration > 10000ULL)
2481 return (void)printf("+ ");
2482
2483 printf(" ");
2484}
2485
2486static void print_graph_duration(unsigned long long duration)
2487{
2488 unsigned long usecs = duration / 1000;
2489 unsigned long nsecs_rem = duration % 1000;
2490 /* log10(ULONG_MAX) + '\0' */
2491 char msecs_str[21];
2492 char nsecs_str[5];
2493 int len;
2494 int i;
2495
2496 sprintf(msecs_str, "%lu", usecs);
2497
2498 /* Print msecs */
2499 len = printf("%lu", usecs);
2500
2501 /* Print nsecs (we don't want to exceed 7 numbers) */
2502 if (len < 7) {
2503 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2504 len += printf(".%s", nsecs_str);
2505 }
2506
2507 printf(" us ");
2508
2509 /* Print remaining spaces to fit the row's width */
2510 for (i = len; i < 7; i++)
2511 printf(" ");
2512
2513 printf("| ");
2514}
2515
2516static void
2517print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2518{
2519 unsigned long long rettime, calltime;
2520 unsigned long long duration, depth;
2521 unsigned long long val;
2522 struct format_field *field;
2523 struct func_map *func;
2524 struct event *ret_event;
2525 int type;
2526 int i;
2527
2528 type = trace_parse_common_type(ret_rec->data);
2529 ret_event = trace_find_event(type);
2530
2531 field = find_field(ret_event, "rettime");
2532 if (!field)
2533 die("can't find rettime in return graph");
2534 rettime = read_size(ret_rec->data + field->offset, field->size);
2535
2536 field = find_field(ret_event, "calltime");
2537 if (!field)
2538 die("can't find rettime in return graph");
2539 calltime = read_size(ret_rec->data + field->offset, field->size);
2540
2541 duration = rettime - calltime;
2542
2543 /* Overhead */
2544 print_graph_overhead(duration);
2545
2546 /* Duration */
2547 print_graph_duration(duration);
2548
2549 field = find_field(event, "depth");
2550 if (!field)
2551 die("can't find depth in entry graph");
2552 depth = read_size(data + field->offset, field->size);
2553
2554 /* Function */
2555 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2556 printf(" ");
2557
2558 field = find_field(event, "func");
2559 if (!field)
2560 die("can't find func in entry graph");
2561 val = read_size(data + field->offset, field->size);
2562 func = find_func(val);
2563
2564 if (func)
2565 printf("%s();", func->func);
2566 else
2567 printf("%llx();", val);
2568}
2569
2570static void print_graph_nested(struct event *event, void *data)
2571{
2572 struct format_field *field;
2573 unsigned long long depth;
2574 unsigned long long val;
2575 struct func_map *func;
2576 int i;
2577
2578 /* No overhead */
2579 print_graph_overhead(-1);
2580
2581 /* No time */
2582 printf(" | ");
2583
2584 field = find_field(event, "depth");
2585 if (!field)
2586 die("can't find depth in entry graph");
2587 depth = read_size(data + field->offset, field->size);
2588
2589 /* Function */
2590 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2591 printf(" ");
2592
2593 field = find_field(event, "func");
2594 if (!field)
2595 die("can't find func in entry graph");
2596 val = read_size(data + field->offset, field->size);
2597 func = find_func(val);
2598
2599 if (func)
2600 printf("%s() {", func->func);
2601 else
2602 printf("%llx() {", val);
2603}
2604
2605static void
2606pretty_print_func_ent(void *data, int size, struct event *event,
2607 int cpu, int pid, const char *comm,
2608 unsigned long secs, unsigned long usecs)
2609{
2610 struct format_field *field;
2611 struct record *rec;
2612 void *copy_data;
2613 unsigned long val;
2614
2615 printf("%5lu.%06lu | ", secs, usecs);
2616
2617 print_graph_cpu(cpu);
2618 print_graph_proc(pid, comm);
2619
2620 printf(" | ");
2621
2622 field = find_field(event, "func");
2623 if (!field)
2624 die("function entry does not have func field");
2625
2626 val = read_size(data + field->offset, field->size);
2627
2628 /*
2629 * peek_data may unmap the data pointer. Copy it first.
2630 */
2631 copy_data = malloc_or_die(size);
2632 memcpy(copy_data, data, size);
2633 data = copy_data;
2634
2635 rec = trace_peek_data(cpu);
2636 if (rec) {
2637 rec = get_return_for_leaf(cpu, pid, val, rec);
2638 if (rec) {
2639 print_graph_entry_leaf(event, data, rec);
2640 goto out_free;
2641 }
2642 }
2643 print_graph_nested(event, data);
2644out_free:
2645 free(data);
2646}
2647
2648static void
2649pretty_print_func_ret(void *data, int size __unused, struct event *event,
2650 int cpu, int pid, const char *comm,
2651 unsigned long secs, unsigned long usecs)
2652{
2653 unsigned long long rettime, calltime;
2654 unsigned long long duration, depth;
2655 struct format_field *field;
2656 int i;
2657
2658 printf("%5lu.%06lu | ", secs, usecs);
2659
2660 print_graph_cpu(cpu);
2661 print_graph_proc(pid, comm);
2662
2663 printf(" | ");
2664
2665 field = find_field(event, "rettime");
2666 if (!field)
2667 die("can't find rettime in return graph");
2668 rettime = read_size(data + field->offset, field->size);
2669
2670 field = find_field(event, "calltime");
2671 if (!field)
2672 die("can't find calltime in return graph");
2673 calltime = read_size(data + field->offset, field->size);
2674
2675 duration = rettime - calltime;
2676
2677 /* Overhead */
2678 print_graph_overhead(duration);
2679
2680 /* Duration */
2681 print_graph_duration(duration);
2682
2683 field = find_field(event, "depth");
2684 if (!field)
2685 die("can't find depth in entry graph");
2686 depth = read_size(data + field->offset, field->size);
2687
2688 /* Function */
2689 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2690 printf(" ");
2691
2692 printf("}");
2693}
2694
2695static void
2696pretty_print_func_graph(void *data, int size, struct event *event,
2697 int cpu, int pid, const char *comm,
2698 unsigned long secs, unsigned long usecs)
2699{
2700 if (event->flags & EVENT_FL_ISFUNCENT)
2701 pretty_print_func_ent(data, size, event,
2702 cpu, pid, comm, secs, usecs);
2703 else if (event->flags & EVENT_FL_ISFUNCRET)
2704 pretty_print_func_ret(data, size, event,
2705 cpu, pid, comm, secs, usecs);
2706 printf("\n");
2707}
2708
2709void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2710 char *comm)
2711{
2712 struct event *event;
2713 unsigned long secs;
2714 unsigned long usecs;
2715 int type;
2716 int pid;
2717
2718 secs = nsecs / NSECS_PER_SEC;
2719 nsecs -= secs * NSECS_PER_SEC;
2720 usecs = nsecs / NSECS_PER_USEC;
2721
2722 type = trace_parse_common_type(data);
2723
2724 event = trace_find_event(type);
2725 if (!event) {
2726 printf("ug! no event found for type %d\n", type);
2727 return;
2728 }
2729
2730 pid = parse_common_pid(data);
2731
2732 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2733 return pretty_print_func_graph(data, size, event, cpu,
2734 pid, comm, secs, usecs);
2735
2736 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
2737 comm, pid, cpu,
2738 secs, nsecs, event->name);
2739
2740 pretty_print(data, size, event);
2741 printf("\n");
2742}
2743
2744static void print_fields(struct print_flag_sym *field)
2745{
2746 printf("{ %s, %s }", field->value, field->str);
2747 if (field->next) {
2748 printf(", ");
2749 print_fields(field->next);
2750 }
2751}
2752
2753static void print_args(struct print_arg *args)
2754{
2755 int print_paren = 1;
2756
2757 switch (args->type) {
2758 case PRINT_NULL:
2759 printf("null");
2760 break;
2761 case PRINT_ATOM:
2762 printf("%s", args->atom.atom);
2763 break;
2764 case PRINT_FIELD:
2765 printf("REC->%s", args->field.name);
2766 break;
2767 case PRINT_FLAGS:
2768 printf("__print_flags(");
2769 print_args(args->flags.field);
2770 printf(", %s, ", args->flags.delim);
2771 print_fields(args->flags.flags);
2772 printf(")");
2773 break;
2774 case PRINT_SYMBOL:
2775 printf("__print_symbolic(");
2776 print_args(args->symbol.field);
2777 printf(", ");
2778 print_fields(args->symbol.symbols);
2779 printf(")");
2780 break;
2781 case PRINT_STRING:
2782 printf("__get_str(%s)", args->string.string);
2783 break;
2784 case PRINT_TYPE:
2785 printf("(%s)", args->typecast.type);
2786 print_args(args->typecast.item);
2787 break;
2788 case PRINT_OP:
2789 if (strcmp(args->op.op, ":") == 0)
2790 print_paren = 0;
2791 if (print_paren)
2792 printf("(");
2793 print_args(args->op.left);
2794 printf(" %s ", args->op.op);
2795 print_args(args->op.right);
2796 if (print_paren)
2797 printf(")");
2798 break;
2799 default:
2800 /* we should warn... */
2801 return;
2802 }
2803 if (args->next) {
2804 printf("\n");
2805 print_args(args->next);
2806 }
2807}
2808
2809static void parse_header_field(char *type,
2810 int *offset, int *size)
2811{
2812 char *token;
2813
2814 if (read_expected(EVENT_ITEM, (char *)"field") < 0)
2815 return;
2816 if (read_expected(EVENT_OP, (char *)":") < 0)
2817 return;
2818 /* type */
2819 if (read_expect_type(EVENT_ITEM, &token) < 0)
2820 return;
2821 free_token(token);
2822
2823 if (read_expected(EVENT_ITEM, type) < 0)
2824 return;
2825 if (read_expected(EVENT_OP, (char *)";") < 0)
2826 return;
2827 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
2828 return;
2829 if (read_expected(EVENT_OP, (char *)":") < 0)
2830 return;
2831 if (read_expect_type(EVENT_ITEM, &token) < 0)
2832 return;
2833 *offset = atoi(token);
2834 free_token(token);
2835 if (read_expected(EVENT_OP, (char *)";") < 0)
2836 return;
2837 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
2838 return;
2839 if (read_expected(EVENT_OP, (char *)":") < 0)
2840 return;
2841 if (read_expect_type(EVENT_ITEM, &token) < 0)
2842 return;
2843 *size = atoi(token);
2844 free_token(token);
2845 if (read_expected(EVENT_OP, (char *)";") < 0)
2846 return;
2847 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2848 return;
2849 free_token(token);
2850}
2851
2852int parse_header_page(char *buf, unsigned long size)
2853{
2854 init_input_buf(buf, size);
2855
2856 parse_header_field((char *)"timestamp", &header_page_ts_offset,
2857 &header_page_ts_size);
2858 parse_header_field((char *)"commit", &header_page_size_offset,
2859 &header_page_size_size);
2860 parse_header_field((char *)"data", &header_page_data_offset,
2861 &header_page_data_size);
2862
2863 return 0;
2864}
2865
2866int parse_ftrace_file(char *buf, unsigned long size)
2867{
2868 struct format_field *field;
2869 struct print_arg *arg, **list;
2870 struct event *event;
2871 int ret;
2872
2873 init_input_buf(buf, size);
2874
2875 event = alloc_event();
2876 if (!event)
2877 return -ENOMEM;
2878
2879 event->flags |= EVENT_FL_ISFTRACE;
2880
2881 event->name = event_read_name();
2882 if (!event->name)
2883 die("failed to read ftrace event name");
2884
2885 if (strcmp(event->name, "function") == 0)
2886 event->flags |= EVENT_FL_ISFUNC;
2887
2888 else if (strcmp(event->name, "funcgraph_entry") == 0)
2889 event->flags |= EVENT_FL_ISFUNCENT;
2890
2891 else if (strcmp(event->name, "funcgraph_exit") == 0)
2892 event->flags |= EVENT_FL_ISFUNCRET;
2893
2894 else if (strcmp(event->name, "bprint") == 0)
2895 event->flags |= EVENT_FL_ISBPRINT;
2896
2897 event->id = event_read_id();
2898 if (event->id < 0)
2899 die("failed to read ftrace event id");
2900
2901 add_event(event);
2902
2903 ret = event_read_format(event);
2904 if (ret < 0)
2905 die("failed to read ftrace event format");
2906
2907 ret = event_read_print(event);
2908 if (ret < 0)
2909 die("failed to read ftrace event print fmt");
2910
2911 /*
2912 * The arguments for ftrace files are parsed by the fields.
2913 * Set up the fields as their arguments.
2914 */
2915 list = &event->print_fmt.args;
2916 for (field = event->format.fields; field; field = field->next) {
2917 arg = malloc_or_die(sizeof(*arg));
2918 memset(arg, 0, sizeof(*arg));
2919 *list = arg;
2920 list = &arg->next;
2921 arg->type = PRINT_FIELD;
2922 arg->field.name = field->name;
2923 arg->field.field = field;
2924 }
2925 return 0;
2926}
2927
2928int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
2929{
2930 struct event *event;
2931 int ret;
2932
2933 init_input_buf(buf, size);
2934
2935 event = alloc_event();
2936 if (!event)
2937 return -ENOMEM;
2938
2939 event->name = event_read_name();
2940 if (!event->name)
2941 die("failed to read event name");
2942
2943 event->id = event_read_id();
2944 if (event->id < 0)
2945 die("failed to read event id");
2946
2947 ret = event_read_format(event);
2948 if (ret < 0)
2949 die("failed to read event format");
2950
2951 ret = event_read_print(event);
2952 if (ret < 0)
2953 die("failed to read event print fmt");
2954
2955#define PRINT_ARGS 0
2956 if (PRINT_ARGS && event->print_fmt.args)
2957 print_args(event->print_fmt.args);
2958
2959 add_event(event);
2960 return 0;
2961}
2962
2963void parse_set_info(int nr_cpus, int long_sz)
2964{
2965 cpus = nr_cpus;
2966 long_size = long_sz;
2967}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
new file mode 100644
index 000000000000..1b5c847d2c22
--- /dev/null
+++ b/tools/perf/util/trace-event-read.c
@@ -0,0 +1,514 @@
1/*
2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _LARGEFILE64_SOURCE
22
23#include <dirent.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <stdarg.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/wait.h>
32#include <sys/mman.h>
33#include <pthread.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <ctype.h>
37#include <errno.h>
38
39#include "../perf.h"
40#include "util.h"
41#include "trace-event.h"
42
43static int input_fd;
44
45static int read_page;
46
47int file_bigendian;
48int host_bigendian;
49static int long_size;
50
51static unsigned long page_size;
52
53static int read_or_die(void *data, int size)
54{
55 int r;
56
57 r = read(input_fd, data, size);
58 if (r != size)
59 die("reading input file (size expected=%d received=%d)",
60 size, r);
61 return r;
62}
63
64static unsigned int read4(void)
65{
66 unsigned int data;
67
68 read_or_die(&data, 4);
69 return __data2host4(data);
70}
71
72static unsigned long long read8(void)
73{
74 unsigned long long data;
75
76 read_or_die(&data, 8);
77 return __data2host8(data);
78}
79
80static char *read_string(void)
81{
82 char buf[BUFSIZ];
83 char *str = NULL;
84 int size = 0;
85 int i;
86 int r;
87
88 for (;;) {
89 r = read(input_fd, buf, BUFSIZ);
90 if (r < 0)
91 die("reading input file");
92
93 if (!r)
94 die("no data");
95
96 for (i = 0; i < r; i++) {
97 if (!buf[i])
98 break;
99 }
100 if (i < r)
101 break;
102
103 if (str) {
104 size += BUFSIZ;
105 str = realloc(str, size);
106 if (!str)
107 die("malloc of size %d", size);
108 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
109 } else {
110 size = BUFSIZ;
111 str = malloc_or_die(size);
112 memcpy(str, buf, size);
113 }
114 }
115
116 /* trailing \0: */
117 i++;
118
119 /* move the file descriptor to the end of the string */
120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0)
122 die("lseek");
123
124 if (str) {
125 size += i;
126 str = realloc(str, size);
127 if (!str)
128 die("malloc of size %d", size);
129 memcpy(str + (size - i), buf, i);
130 } else {
131 size = i;
132 str = malloc_or_die(i);
133 memcpy(str, buf, i);
134 }
135
136 return str;
137}
138
139static void read_proc_kallsyms(void)
140{
141 unsigned int size;
142 char *buf;
143
144 size = read4();
145 if (!size)
146 return;
147
148 buf = malloc_or_die(size);
149 read_or_die(buf, size);
150
151 parse_proc_kallsyms(buf, size);
152
153 free(buf);
154}
155
156static void read_ftrace_printk(void)
157{
158 unsigned int size;
159 char *buf;
160
161 size = read4();
162 if (!size)
163 return;
164
165 buf = malloc_or_die(size);
166 read_or_die(buf, size);
167
168 parse_ftrace_printk(buf, size);
169
170 free(buf);
171}
172
173static void read_header_files(void)
174{
175 unsigned long long size;
176 char *header_page;
177 char *header_event;
178 char buf[BUFSIZ];
179
180 read_or_die(buf, 12);
181
182 if (memcmp(buf, "header_page", 12) != 0)
183 die("did not read header page");
184
185 size = read8();
186 header_page = malloc_or_die(size);
187 read_or_die(header_page, size);
188 parse_header_page(header_page, size);
189 free(header_page);
190
191 /*
192 * The size field in the page is of type long,
193 * use that instead, since it represents the kernel.
194 */
195 long_size = header_page_size_size;
196
197 read_or_die(buf, 13);
198 if (memcmp(buf, "header_event", 13) != 0)
199 die("did not read header event");
200
201 size = read8();
202 header_event = malloc_or_die(size);
203 read_or_die(header_event, size);
204 free(header_event);
205}
206
207static void read_ftrace_file(unsigned long long size)
208{
209 char *buf;
210
211 buf = malloc_or_die(size);
212 read_or_die(buf, size);
213 parse_ftrace_file(buf, size);
214 free(buf);
215}
216
217static void read_event_file(char *sys, unsigned long long size)
218{
219 char *buf;
220
221 buf = malloc_or_die(size);
222 read_or_die(buf, size);
223 parse_event_file(buf, size, sys);
224 free(buf);
225}
226
227static void read_ftrace_files(void)
228{
229 unsigned long long size;
230 int count;
231 int i;
232
233 count = read4();
234
235 for (i = 0; i < count; i++) {
236 size = read8();
237 read_ftrace_file(size);
238 }
239}
240
241static void read_event_files(void)
242{
243 unsigned long long size;
244 char *sys;
245 int systems;
246 int count;
247 int i,x;
248
249 systems = read4();
250
251 for (i = 0; i < systems; i++) {
252 sys = read_string();
253
254 count = read4();
255 for (x=0; x < count; x++) {
256 size = read8();
257 read_event_file(sys, size);
258 }
259 }
260}
261
262struct cpu_data {
263 unsigned long long offset;
264 unsigned long long size;
265 unsigned long long timestamp;
266 struct record *next;
267 char *page;
268 int cpu;
269 int index;
270 int page_size;
271};
272
273static struct cpu_data *cpu_data;
274
275static void update_cpu_data_index(int cpu)
276{
277 cpu_data[cpu].offset += page_size;
278 cpu_data[cpu].size -= page_size;
279 cpu_data[cpu].index = 0;
280}
281
282static void get_next_page(int cpu)
283{
284 off64_t save_seek;
285 off64_t ret;
286
287 if (!cpu_data[cpu].page)
288 return;
289
290 if (read_page) {
291 if (cpu_data[cpu].size <= page_size) {
292 free(cpu_data[cpu].page);
293 cpu_data[cpu].page = NULL;
294 return;
295 }
296
297 update_cpu_data_index(cpu);
298
299 /* other parts of the code may expect the pointer to not move */
300 save_seek = lseek64(input_fd, 0, SEEK_CUR);
301
302 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET);
303 if (ret < 0)
304 die("failed to lseek");
305 ret = read(input_fd, cpu_data[cpu].page, page_size);
306 if (ret < 0)
307 die("failed to read page");
308
309 /* reset the file pointer back */
310 lseek64(input_fd, save_seek, SEEK_SET);
311
312 return;
313 }
314
315 munmap(cpu_data[cpu].page, page_size);
316 cpu_data[cpu].page = NULL;
317
318 if (cpu_data[cpu].size <= page_size)
319 return;
320
321 update_cpu_data_index(cpu);
322
323 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
324 input_fd, cpu_data[cpu].offset);
325 if (cpu_data[cpu].page == MAP_FAILED)
326 die("failed to mmap cpu %d at offset 0x%llx",
327 cpu, cpu_data[cpu].offset);
328}
329
330static unsigned int type_len4host(unsigned int type_len_ts)
331{
332 if (file_bigendian)
333 return (type_len_ts >> 27) & ((1 << 5) - 1);
334 else
335 return type_len_ts & ((1 << 5) - 1);
336}
337
338static unsigned int ts4host(unsigned int type_len_ts)
339{
340 if (file_bigendian)
341 return type_len_ts & ((1 << 27) - 1);
342 else
343 return type_len_ts >> 5;
344}
345
346static int calc_index(void *ptr, int cpu)
347{
348 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
349}
350
351struct record *trace_peek_data(int cpu)
352{
353 struct record *data;
354 void *page = cpu_data[cpu].page;
355 int idx = cpu_data[cpu].index;
356 void *ptr = page + idx;
357 unsigned long long extend;
358 unsigned int type_len_ts;
359 unsigned int type_len;
360 unsigned int delta;
361 unsigned int length = 0;
362
363 if (cpu_data[cpu].next)
364 return cpu_data[cpu].next;
365
366 if (!page)
367 return NULL;
368
369 if (!idx) {
370 /* FIXME: handle header page */
371 if (header_page_ts_size != 8)
372 die("expected a long long type for timestamp");
373 cpu_data[cpu].timestamp = data2host8(ptr);
374 ptr += 8;
375 switch (header_page_size_size) {
376 case 4:
377 cpu_data[cpu].page_size = data2host4(ptr);
378 ptr += 4;
379 break;
380 case 8:
381 cpu_data[cpu].page_size = data2host8(ptr);
382 ptr += 8;
383 break;
384 default:
385 die("bad long size");
386 }
387 ptr = cpu_data[cpu].page + header_page_data_offset;
388 }
389
390read_again:
391 idx = calc_index(ptr, cpu);
392
393 if (idx >= cpu_data[cpu].page_size) {
394 get_next_page(cpu);
395 return trace_peek_data(cpu);
396 }
397
398 type_len_ts = data2host4(ptr);
399 ptr += 4;
400
401 type_len = type_len4host(type_len_ts);
402 delta = ts4host(type_len_ts);
403
404 switch (type_len) {
405 case RINGBUF_TYPE_PADDING:
406 if (!delta)
407 die("error, hit unexpected end of page");
408 length = data2host4(ptr);
409 ptr += 4;
410 length *= 4;
411 ptr += length;
412 goto read_again;
413
414 case RINGBUF_TYPE_TIME_EXTEND:
415 extend = data2host4(ptr);
416 ptr += 4;
417 extend <<= TS_SHIFT;
418 extend += delta;
419 cpu_data[cpu].timestamp += extend;
420 goto read_again;
421
422 case RINGBUF_TYPE_TIME_STAMP:
423 ptr += 12;
424 break;
425 case 0:
426 length = data2host4(ptr);
427 ptr += 4;
428 die("here! length=%d", length);
429 break;
430 default:
431 length = type_len * 4;
432 break;
433 }
434
435 cpu_data[cpu].timestamp += delta;
436
437 data = malloc_or_die(sizeof(*data));
438 memset(data, 0, sizeof(*data));
439
440 data->ts = cpu_data[cpu].timestamp;
441 data->size = length;
442 data->data = ptr;
443 ptr += length;
444
445 cpu_data[cpu].index = calc_index(ptr, cpu);
446 cpu_data[cpu].next = data;
447
448 return data;
449}
450
451struct record *trace_read_data(int cpu)
452{
453 struct record *data;
454
455 data = trace_peek_data(cpu);
456 cpu_data[cpu].next = NULL;
457
458 return data;
459}
460
461void trace_report(void)
462{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 };
466 char *version;
467 int show_version = 0;
468 int show_funcs = 0;
469 int show_printk = 0;
470
471 input_fd = open(input_file, O_RDONLY);
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474
475 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0)
477 die("not an trace data file");
478
479 read_or_die(buf, 7);
480 if (memcmp(buf, "tracing", 7) != 0)
481 die("not a trace file (missing tracing)");
482
483 version = read_string();
484 if (show_version)
485 printf("version = %s\n", version);
486 free(version);
487
488 read_or_die(buf, 1);
489 file_bigendian = buf[0];
490 host_bigendian = bigendian();
491
492 read_or_die(buf, 1);
493 long_size = buf[0];
494
495 page_size = read4();
496
497 read_header_files();
498
499 read_ftrace_files();
500 read_event_files();
501 read_proc_kallsyms();
502 read_ftrace_printk();
503
504 if (show_funcs) {
505 print_funcs();
506 return;
507 }
508 if (show_printk) {
509 print_printk();
510 return;
511 }
512
513 return;
514}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
new file mode 100644
index 000000000000..693f815c9429
--- /dev/null
+++ b/tools/perf/util/trace-event.h
@@ -0,0 +1,245 @@
1#ifndef _TRACE_EVENTS_H
2#define _TRACE_EVENTS_H
3
4#include "parse-events.h"
5
6#define __unused __attribute__((unused))
7
8
9#ifndef PAGE_MASK
10#define PAGE_MASK (page_size - 1)
11#endif
12
13enum {
14 RINGBUF_TYPE_PADDING = 29,
15 RINGBUF_TYPE_TIME_EXTEND = 30,
16 RINGBUF_TYPE_TIME_STAMP = 31,
17};
18
19#ifndef TS_SHIFT
20#define TS_SHIFT 27
21#endif
22
23#define NSECS_PER_SEC 1000000000ULL
24#define NSECS_PER_USEC 1000ULL
25
26enum format_flags {
27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2,
29};
30
31struct format_field {
32 struct format_field *next;
33 char *type;
34 char *name;
35 int offset;
36 int size;
37 unsigned long flags;
38};
39
40struct format {
41 int nr_common;
42 int nr_fields;
43 struct format_field *common_fields;
44 struct format_field *fields;
45};
46
47struct print_arg_atom {
48 char *atom;
49};
50
51struct print_arg_string {
52 char *string;
53 int offset;
54};
55
56struct print_arg_field {
57 char *name;
58 struct format_field *field;
59};
60
61struct print_flag_sym {
62 struct print_flag_sym *next;
63 char *value;
64 char *str;
65};
66
67struct print_arg_typecast {
68 char *type;
69 struct print_arg *item;
70};
71
72struct print_arg_flags {
73 struct print_arg *field;
74 char *delim;
75 struct print_flag_sym *flags;
76};
77
78struct print_arg_symbol {
79 struct print_arg *field;
80 struct print_flag_sym *symbols;
81};
82
83struct print_arg;
84
85struct print_arg_op {
86 char *op;
87 int prio;
88 struct print_arg *left;
89 struct print_arg *right;
90};
91
92struct print_arg_func {
93 char *name;
94 struct print_arg *args;
95};
96
97enum print_arg_type {
98 PRINT_NULL,
99 PRINT_ATOM,
100 PRINT_FIELD,
101 PRINT_FLAGS,
102 PRINT_SYMBOL,
103 PRINT_TYPE,
104 PRINT_STRING,
105 PRINT_OP,
106};
107
108struct print_arg {
109 struct print_arg *next;
110 enum print_arg_type type;
111 union {
112 struct print_arg_atom atom;
113 struct print_arg_field field;
114 struct print_arg_typecast typecast;
115 struct print_arg_flags flags;
116 struct print_arg_symbol symbol;
117 struct print_arg_func func;
118 struct print_arg_string string;
119 struct print_arg_op op;
120 };
121};
122
123struct print_fmt {
124 char *format;
125 struct print_arg *args;
126};
127
128struct event {
129 struct event *next;
130 char *name;
131 int id;
132 int flags;
133 struct format format;
134 struct print_fmt print_fmt;
135};
136
137enum {
138 EVENT_FL_ISFTRACE = 1,
139 EVENT_FL_ISPRINT = 2,
140 EVENT_FL_ISBPRINT = 4,
141 EVENT_FL_ISFUNC = 8,
142 EVENT_FL_ISFUNCENT = 16,
143 EVENT_FL_ISFUNCRET = 32,
144};
145
146struct record {
147 unsigned long long ts;
148 int size;
149 void *data;
150};
151
152struct record *trace_peek_data(int cpu);
153struct record *trace_read_data(int cpu);
154
155void parse_set_info(int nr_cpus, int long_sz);
156
157void trace_report(void);
158
159void *malloc_or_die(unsigned int size);
160
161void parse_cmdlines(char *file, int size);
162void parse_proc_kallsyms(char *file, unsigned int size);
163void parse_ftrace_printk(char *file, unsigned int size);
164
165void print_funcs(void);
166void print_printk(void);
167
168int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm);
172
173extern int file_bigendian;
174extern int host_bigendian;
175
176int bigendian(void);
177
178static inline unsigned short __data2host2(unsigned short data)
179{
180 unsigned short swap;
181
182 if (host_bigendian == file_bigendian)
183 return data;
184
185 swap = ((data & 0xffULL) << 8) |
186 ((data & (0xffULL << 8)) >> 8);
187
188 return swap;
189}
190
191static inline unsigned int __data2host4(unsigned int data)
192{
193 unsigned int swap;
194
195 if (host_bigendian == file_bigendian)
196 return data;
197
198 swap = ((data & 0xffULL) << 24) |
199 ((data & (0xffULL << 8)) << 8) |
200 ((data & (0xffULL << 16)) >> 8) |
201 ((data & (0xffULL << 24)) >> 24);
202
203 return swap;
204}
205
206static inline unsigned long long __data2host8(unsigned long long data)
207{
208 unsigned long long swap;
209
210 if (host_bigendian == file_bigendian)
211 return data;
212
213 swap = ((data & 0xffULL) << 56) |
214 ((data & (0xffULL << 8)) << 40) |
215 ((data & (0xffULL << 16)) << 24) |
216 ((data & (0xffULL << 24)) << 8) |
217 ((data & (0xffULL << 32)) >> 8) |
218 ((data & (0xffULL << 40)) >> 24) |
219 ((data & (0xffULL << 48)) >> 40) |
220 ((data & (0xffULL << 56)) >> 56);
221
222 return swap;
223}
224
225#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
226#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
227#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr)
228
229extern int header_page_ts_offset;
230extern int header_page_ts_size;
231extern int header_page_size_offset;
232extern int header_page_size_size;
233extern int header_page_data_offset;
234extern int header_page_data_size;
235
236int parse_header_page(char *buf, unsigned long size);
237int trace_parse_common_type(void *data);
238struct event *trace_find_event(int id);
239unsigned long long
240raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data);
242
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events);
244
245#endif /* _TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
new file mode 100644
index 000000000000..5e75f9005940
--- /dev/null
+++ b/tools/perf/util/types.h
@@ -0,0 +1,17 @@
1#ifndef _PERF_TYPES_H
2#define _PERF_TYPES_H
3
4/*
5 * We define u64 as unsigned long long for every architecture
6 * so that we can print it with %Lx without getting warnings.
7 */
8typedef unsigned long long u64;
9typedef signed long long s64;
10typedef unsigned int u32;
11typedef signed int s32;
12typedef unsigned short u16;
13typedef signed short s16;
14typedef unsigned char u8;
15typedef signed char s8;
16
17#endif /* _PERF_TYPES_H */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b8cfed776d81..9de2329dd44d 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -39,10 +39,6 @@
39/* Approximation of the length of the decimal representation of this type. */ 39/* Approximation of the length of the decimal representation of this type. */
40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) 40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
41 41
42#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
43#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
44#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
45#endif
46#define _ALL_SOURCE 1 42#define _ALL_SOURCE 1
47#define _GNU_SOURCE 1 43#define _GNU_SOURCE 1
48#define _BSD_SOURCE 1 44#define _BSD_SOURCE 1
@@ -50,6 +46,7 @@
50#include <unistd.h> 46#include <unistd.h>
51#include <stdio.h> 47#include <stdio.h>
52#include <sys/stat.h> 48#include <sys/stat.h>
49#include <sys/statfs.h>
53#include <fcntl.h> 50#include <fcntl.h>
54#include <stddef.h> 51#include <stddef.h>
55#include <stdlib.h> 52#include <stdlib.h>
@@ -67,7 +64,6 @@
67#include <assert.h> 64#include <assert.h>
68#include <regex.h> 65#include <regex.h>
69#include <utime.h> 66#include <utime.h>
70#ifndef __MINGW32__
71#include <sys/wait.h> 67#include <sys/wait.h>
72#include <sys/poll.h> 68#include <sys/poll.h>
73#include <sys/socket.h> 69#include <sys/socket.h>
@@ -81,20 +77,8 @@
81#include <netdb.h> 77#include <netdb.h>
82#include <pwd.h> 78#include <pwd.h>
83#include <inttypes.h> 79#include <inttypes.h>
84#if defined(__CYGWIN__) 80#include "../../../include/linux/magic.h"
85#undef _XOPEN_SOURCE 81
86#include <grp.h>
87#define _XOPEN_SOURCE 600
88#include "compat/cygwin.h"
89#else
90#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
91#include <grp.h>
92#define _ALL_SOURCE 1
93#endif
94#else /* __MINGW32__ */
95/* pull in Windows compatibility stuff */
96#include "compat/mingw.h"
97#endif /* __MINGW32__ */
98 82
99#ifndef NO_ICONV 83#ifndef NO_ICONV
100#include <iconv.h> 84#include <iconv.h>
@@ -323,6 +307,7 @@ static inline int has_extension(const char *filename, const char *ext)
323#undef isspace 307#undef isspace
324#undef isdigit 308#undef isdigit
325#undef isalpha 309#undef isalpha
310#undef isprint
326#undef isalnum 311#undef isalnum
327#undef tolower 312#undef tolower
328#undef toupper 313#undef toupper
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
new file mode 100644
index 000000000000..1c15e39f99e3
--- /dev/null
+++ b/tools/perf/util/values.c
@@ -0,0 +1,230 @@
1#include <stdlib.h>
2
3#include "util.h"
4#include "values.h"
5
6void perf_read_values_init(struct perf_read_values *values)
7{
8 values->threads_max = 16;
9 values->pid = malloc(values->threads_max * sizeof(*values->pid));
10 values->tid = malloc(values->threads_max * sizeof(*values->tid));
11 values->value = malloc(values->threads_max * sizeof(*values->value));
12 if (!values->pid || !values->tid || !values->value)
13 die("failed to allocate read_values threads arrays");
14 values->threads = 0;
15
16 values->counters_max = 16;
17 values->counterrawid = malloc(values->counters_max
18 * sizeof(*values->counterrawid));
19 values->countername = malloc(values->counters_max
20 * sizeof(*values->countername));
21 if (!values->counterrawid || !values->countername)
22 die("failed to allocate read_values counters arrays");
23 values->counters = 0;
24}
25
26void perf_read_values_destroy(struct perf_read_values *values)
27{
28 int i;
29
30 if (!values->threads_max || !values->counters_max)
31 return;
32
33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]);
35 free(values->pid);
36 free(values->tid);
37 free(values->counterrawid);
38 for (i = 0; i < values->counters; i++)
39 free(values->countername[i]);
40 free(values->countername);
41}
42
43static void perf_read_values__enlarge_threads(struct perf_read_values *values)
44{
45 values->threads_max *= 2;
46 values->pid = realloc(values->pid,
47 values->threads_max * sizeof(*values->pid));
48 values->tid = realloc(values->tid,
49 values->threads_max * sizeof(*values->tid));
50 values->value = realloc(values->value,
51 values->threads_max * sizeof(*values->value));
52 if (!values->pid || !values->tid || !values->value)
53 die("failed to enlarge read_values threads arrays");
54}
55
56static int perf_read_values__findnew_thread(struct perf_read_values *values,
57 u32 pid, u32 tid)
58{
59 int i;
60
61 for (i = 0; i < values->threads; i++)
62 if (values->pid[i] == pid && values->tid[i] == tid)
63 return i;
64
65 if (values->threads == values->threads_max)
66 perf_read_values__enlarge_threads(values);
67
68 i = values->threads++;
69 values->pid[i] = pid;
70 values->tid[i] = tid;
71 values->value[i] = malloc(values->counters_max * sizeof(**values->value));
72 if (!values->value[i])
73 die("failed to allocate read_values counters array");
74
75 return i;
76}
77
78static void perf_read_values__enlarge_counters(struct perf_read_values *values)
79{
80 int i;
81
82 values->counters_max *= 2;
83 values->counterrawid = realloc(values->counterrawid,
84 values->counters_max * sizeof(*values->counterrawid));
85 values->countername = realloc(values->countername,
86 values->counters_max * sizeof(*values->countername));
87 if (!values->counterrawid || !values->countername)
88 die("failed to enlarge read_values counters arrays");
89
90 for (i = 0; i < values->threads; i++) {
91 values->value[i] = realloc(values->value[i],
92 values->counters_max * sizeof(**values->value));
93 if (!values->value[i])
94 die("failed to enlarge read_values counters arrays");
95 }
96}
97
98static int perf_read_values__findnew_counter(struct perf_read_values *values,
99 u64 rawid, const char *name)
100{
101 int i;
102
103 for (i = 0; i < values->counters; i++)
104 if (values->counterrawid[i] == rawid)
105 return i;
106
107 if (values->counters == values->counters_max)
108 perf_read_values__enlarge_counters(values);
109
110 i = values->counters++;
111 values->counterrawid[i] = rawid;
112 values->countername[i] = strdup(name);
113
114 return i;
115}
116
117void perf_read_values_add_value(struct perf_read_values *values,
118 u32 pid, u32 tid,
119 u64 rawid, const char *name, u64 value)
120{
121 int tindex, cindex;
122
123 tindex = perf_read_values__findnew_thread(values, pid, tid);
124 cindex = perf_read_values__findnew_counter(values, rawid, name);
125
126 values->value[tindex][cindex] = value;
127}
128
129static void perf_read_values__display_pretty(FILE *fp,
130 struct perf_read_values *values)
131{
132 int i, j;
133 int pidwidth, tidwidth;
134 int *counterwidth;
135
136 counterwidth = malloc(values->counters * sizeof(*counterwidth));
137 if (!counterwidth)
138 die("failed to allocate counterwidth array");
139 tidwidth = 3;
140 pidwidth = 3;
141 for (j = 0; j < values->counters; j++)
142 counterwidth[j] = strlen(values->countername[j]);
143 for (i = 0; i < values->threads; i++) {
144 int width;
145
146 width = snprintf(NULL, 0, "%d", values->pid[i]);
147 if (width > pidwidth)
148 pidwidth = width;
149 width = snprintf(NULL, 0, "%d", values->tid[i]);
150 if (width > tidwidth)
151 tidwidth = width;
152 for (j = 0; j < values->counters; j++) {
153 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
154 if (width > counterwidth[j])
155 counterwidth[j] = width;
156 }
157 }
158
159 fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
160 for (j = 0; j < values->counters; j++)
161 fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
162 fprintf(fp, "\n");
163
164 for (i = 0; i < values->threads; i++) {
165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
166 tidwidth, values->tid[i]);
167 for (j = 0; j < values->counters; j++)
168 fprintf(fp, " %*Lu",
169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n");
171 }
172}
173
174static void perf_read_values__display_raw(FILE *fp,
175 struct perf_read_values *values)
176{
177 int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
178 int i, j;
179
180 tidwidth = 3; /* TID */
181 pidwidth = 3; /* PID */
182 namewidth = 4; /* "Name" */
183 rawwidth = 3; /* "Raw" */
184 countwidth = 5; /* "Count" */
185
186 for (i = 0; i < values->threads; i++) {
187 width = snprintf(NULL, 0, "%d", values->pid[i]);
188 if (width > pidwidth)
189 pidwidth = width;
190 width = snprintf(NULL, 0, "%d", values->tid[i]);
191 if (width > tidwidth)
192 tidwidth = width;
193 }
194 for (j = 0; j < values->counters; j++) {
195 width = strlen(values->countername[j]);
196 if (width > namewidth)
197 namewidth = width;
198 width = snprintf(NULL, 0, "%llx", values->counterrawid[j]);
199 if (width > rawwidth)
200 rawwidth = width;
201 }
202 for (i = 0; i < values->threads; i++) {
203 for (j = 0; j < values->counters; j++) {
204 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
205 if (width > countwidth)
206 countwidth = width;
207 }
208 }
209
210 fprintf(fp, "# %*s %*s %*s %*s %*s\n",
211 pidwidth, "PID", tidwidth, "TID",
212 namewidth, "Name", rawwidth, "Raw",
213 countwidth, "Count");
214 for (i = 0; i < values->threads; i++)
215 for (j = 0; j < values->counters; j++)
216 fprintf(fp, " %*d %*d %*s %*llx %*Lu\n",
217 pidwidth, values->pid[i],
218 tidwidth, values->tid[i],
219 namewidth, values->countername[j],
220 rawwidth, values->counterrawid[j],
221 countwidth, values->value[i][j]);
222}
223
224void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw)
225{
226 if (raw)
227 perf_read_values__display_raw(fp, values);
228 else
229 perf_read_values__display_pretty(fp, values);
230}
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
new file mode 100644
index 000000000000..cadf8cf2a590
--- /dev/null
+++ b/tools/perf/util/values.h
@@ -0,0 +1,27 @@
1#ifndef _PERF_VALUES_H
2#define _PERF_VALUES_H
3
4#include "types.h"
5
6struct perf_read_values {
7 int threads;
8 int threads_max;
9 u32 *pid, *tid;
10 int counters;
11 int counters_max;
12 u64 *counterrawid;
13 char **countername;
14 u64 **value;
15};
16
17void perf_read_values_init(struct perf_read_values *values);
18void perf_read_values_destroy(struct perf_read_values *values);
19
20void perf_read_values_add_value(struct perf_read_values *values,
21 u32 pid, u32 tid,
22 u64 rawid, const char *name, u64 value);
23
24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw);
26
27#endif /* _PERF_VALUES_H */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 6350d65f6d9e..4574ac28396f 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -7,7 +7,7 @@
7 * There's no pack memory to release - but stay close to the Git 7 * There's no pack memory to release - but stay close to the Git
8 * version so wrap this away: 8 * version so wrap this away:
9 */ 9 */
10static inline void release_pack_memory(size_t size, int flag) 10static inline void release_pack_memory(size_t size __used, int flag __used)
11{ 11{
12} 12}
13 13
@@ -59,7 +59,8 @@ void *xmemdupz(const void *data, size_t len)
59char *xstrndup(const char *str, size_t len) 59char *xstrndup(const char *str, size_t len)
60{ 60{
61 char *p = memchr(str, '\0', len); 61 char *p = memchr(str, '\0', len);
62 return xmemdupz(str, p ? p - str : len); 62
63 return xmemdupz(str, p ? (size_t)(p - str) : len);
63} 64}
64 65
65void *xrealloc(void *ptr, size_t size) 66void *xrealloc(void *ptr, size_t size)