aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/alias.c2
-rw-r--r--tools/perf/util/cache.h2
-rw-r--r--tools/perf/util/callchain.c255
-rw-r--r--tools/perf/util/callchain.h41
-rw-r--r--tools/perf/util/color.c37
-rw-r--r--tools/perf/util/color.h5
-rw-r--r--tools/perf/util/config.c18
-rw-r--r--tools/perf/util/exec_cmd.c5
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/help.c26
-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/module.c509
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.c431
-rw-r--r--tools/perf/util/parse-events.h5
-rw-r--r--tools/perf/util/parse-options.c5
-rw-r--r--tools/perf/util/parse-options.h27
-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/strbuf.c13
-rw-r--r--tools/perf/util/strbuf.h10
-rw-r--r--tools/perf/util/string.h3
-rw-r--r--tools/perf/util/strlist.c20
-rw-r--r--tools/perf/util/strlist.h13
-rw-r--r--tools/perf/util/symbol.c405
-rw-r--r--tools/perf/util/symbol.h12
-rw-r--r--tools/perf/util/util.h2
-rw-r--r--tools/perf/util/wrapper.c5
38 files changed, 1728 insertions, 1453 deletions
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..4b50c412b9c5 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 *);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index ad3c28578961..9d3c8141b8c1 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -4,6 +4,9 @@
4 * Handle the callchains from the stream in an ad-hoc radix tree and then 4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree. 5 * sort them in an rbtree.
6 * 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 *
7 */ 10 */
8 11
9#include <stdlib.h> 12#include <stdlib.h>
@@ -13,8 +16,12 @@
13 16
14#include "callchain.h" 17#include "callchain.h"
15 18
19#define chain_for_each_child(child, parent) \
20 list_for_each_entry(child, &parent->children, brothers)
16 21
17static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain) 22static void
23rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
24 enum chain_mode mode)
18{ 25{
19 struct rb_node **p = &root->rb_node; 26 struct rb_node **p = &root->rb_node;
20 struct rb_node *parent = NULL; 27 struct rb_node *parent = NULL;
@@ -24,32 +31,125 @@ static void rb_insert_callchain(struct rb_root *root, struct callchain_node *cha
24 parent = *p; 31 parent = *p;
25 rnode = rb_entry(parent, struct callchain_node, rb_node); 32 rnode = rb_entry(parent, struct callchain_node, rb_node);
26 33
27 if (rnode->hit < chain->hit) 34 switch (mode) {
28 p = &(*p)->rb_left; 35 case CHAIN_FLAT:
29 else 36 if (rnode->hit < chain->hit)
30 p = &(*p)->rb_right; 37 p = &(*p)->rb_left;
38 else
39 p = &(*p)->rb_right;
40 break;
41 case CHAIN_GRAPH_ABS: /* Falldown */
42 case CHAIN_GRAPH_REL:
43 if (rnode->cumul_hit < chain->cumul_hit)
44 p = &(*p)->rb_left;
45 else
46 p = &(*p)->rb_right;
47 break;
48 default:
49 break;
50 }
31 } 51 }
32 52
33 rb_link_node(&chain->rb_node, parent, p); 53 rb_link_node(&chain->rb_node, parent, p);
34 rb_insert_color(&chain->rb_node, root); 54 rb_insert_color(&chain->rb_node, root);
35} 55}
36 56
57static void
58__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
59 u64 min_hit)
60{
61 struct callchain_node *child;
62
63 chain_for_each_child(child, node)
64 __sort_chain_flat(rb_root, child, min_hit);
65
66 if (node->hit && node->hit >= min_hit)
67 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
68}
69
37/* 70/*
38 * Once we get every callchains from the stream, we can now 71 * Once we get every callchains from the stream, we can now
39 * sort them by hit 72 * sort them by hit
40 */ 73 */
41void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node) 74static void
75sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
76 u64 min_hit, struct callchain_param *param __used)
77{
78 __sort_chain_flat(rb_root, node, min_hit);
79}
80
81static void __sort_chain_graph_abs(struct callchain_node *node,
82 u64 min_hit)
83{
84 struct callchain_node *child;
85
86 node->rb_root = RB_ROOT;
87
88 chain_for_each_child(child, node) {
89 __sort_chain_graph_abs(child, min_hit);
90 if (child->cumul_hit >= min_hit)
91 rb_insert_callchain(&node->rb_root, child,
92 CHAIN_GRAPH_ABS);
93 }
94}
95
96static void
97sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
98 u64 min_hit, struct callchain_param *param __used)
99{
100 __sort_chain_graph_abs(chain_root, min_hit);
101 rb_root->rb_node = chain_root->rb_root.rb_node;
102}
103
104static void __sort_chain_graph_rel(struct callchain_node *node,
105 double min_percent)
42{ 106{
43 struct callchain_node *child; 107 struct callchain_node *child;
108 u64 min_hit;
44 109
45 list_for_each_entry(child, &node->children, brothers) 110 node->rb_root = RB_ROOT;
46 sort_chain_to_rbtree(rb_root, child); 111 min_hit = node->cumul_hit * min_percent / 100.0;
47 112
48 if (node->hit) 113 chain_for_each_child(child, node) {
49 rb_insert_callchain(rb_root, node); 114 __sort_chain_graph_rel(child, min_percent);
115 if (child->cumul_hit >= min_hit)
116 rb_insert_callchain(&node->rb_root, child,
117 CHAIN_GRAPH_REL);
118 }
50} 119}
51 120
52static struct callchain_node *create_child(struct callchain_node *parent) 121static void
122sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
123 u64 min_hit __used, struct callchain_param *param)
124{
125 __sort_chain_graph_rel(chain_root, param->min_percent);
126 rb_root->rb_node = chain_root->rb_root.rb_node;
127}
128
129int register_callchain_param(struct callchain_param *param)
130{
131 switch (param->mode) {
132 case CHAIN_GRAPH_ABS:
133 param->sort = sort_chain_graph_abs;
134 break;
135 case CHAIN_GRAPH_REL:
136 param->sort = sort_chain_graph_rel;
137 break;
138 case CHAIN_FLAT:
139 param->sort = sort_chain_flat;
140 break;
141 default:
142 return -1;
143 }
144 return 0;
145}
146
147/*
148 * Create a child for a parent. If inherit_children, then the new child
149 * will become the new parent of it's parent children
150 */
151static struct callchain_node *
152create_child(struct callchain_node *parent, bool inherit_children)
53{ 153{
54 struct callchain_node *new; 154 struct callchain_node *new;
55 155
@@ -61,91 +161,147 @@ static struct callchain_node *create_child(struct callchain_node *parent)
61 new->parent = parent; 161 new->parent = parent;
62 INIT_LIST_HEAD(&new->children); 162 INIT_LIST_HEAD(&new->children);
63 INIT_LIST_HEAD(&new->val); 163 INIT_LIST_HEAD(&new->val);
164
165 if (inherit_children) {
166 struct callchain_node *next;
167
168 list_splice(&parent->children, &new->children);
169 INIT_LIST_HEAD(&parent->children);
170
171 chain_for_each_child(next, new)
172 next->parent = new;
173 }
64 list_add_tail(&new->brothers, &parent->children); 174 list_add_tail(&new->brothers, &parent->children);
65 175
66 return new; 176 return new;
67} 177}
68 178
179/*
180 * Fill the node with callchain values
181 */
69static void 182static void
70fill_node(struct callchain_node *node, struct ip_callchain *chain, int start) 183fill_node(struct callchain_node *node, struct ip_callchain *chain,
184 int start, struct symbol **syms)
71{ 185{
72 int i; 186 unsigned int i;
73 187
74 for (i = start; i < chain->nr; i++) { 188 for (i = start; i < chain->nr; i++) {
75 struct callchain_list *call; 189 struct callchain_list *call;
76 190
77 call = malloc(sizeof(*chain)); 191 call = malloc(sizeof(*call));
78 if (!call) { 192 if (!call) {
79 perror("not enough memory for the code path tree"); 193 perror("not enough memory for the code path tree");
80 return; 194 return;
81 } 195 }
82 call->ip = chain->ips[i]; 196 call->ip = chain->ips[i];
197 call->sym = syms[i];
83 list_add_tail(&call->list, &node->val); 198 list_add_tail(&call->list, &node->val);
84 } 199 }
85 node->val_nr = i - start; 200 node->val_nr = chain->nr - start;
201 if (!node->val_nr)
202 printf("Warning: empty node in callchain tree\n");
86} 203}
87 204
88static void add_child(struct callchain_node *parent, struct ip_callchain *chain) 205static void
206add_child(struct callchain_node *parent, struct ip_callchain *chain,
207 int start, struct symbol **syms)
89{ 208{
90 struct callchain_node *new; 209 struct callchain_node *new;
91 210
92 new = create_child(parent); 211 new = create_child(parent, false);
93 fill_node(new, chain, parent->val_nr); 212 fill_node(new, chain, start, syms);
94 213
95 new->hit = 1; 214 new->cumul_hit = new->hit = 1;
96} 215}
97 216
217/*
218 * Split the parent in two parts (a new child is created) and
219 * give a part of its callchain to the created child.
220 * Then create another child to host the given callchain of new branch
221 */
98static void 222static void
99split_add_child(struct callchain_node *parent, struct ip_callchain *chain, 223split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
100 struct callchain_list *to_split, int idx) 224 struct callchain_list *to_split, int idx_parents, int idx_local,
225 struct symbol **syms)
101{ 226{
102 struct callchain_node *new; 227 struct callchain_node *new;
228 struct list_head *old_tail;
229 unsigned int idx_total = idx_parents + idx_local;
103 230
104 /* split */ 231 /* split */
105 new = create_child(parent); 232 new = create_child(parent, true);
106 list_move_tail(&to_split->list, &new->val);
107 new->hit = parent->hit;
108 parent->hit = 0;
109 parent->val_nr = idx;
110 233
111 /* create the new one */ 234 /* split the callchain and move a part to the new child */
112 add_child(parent, chain); 235 old_tail = parent->val.prev;
236 list_del_range(&to_split->list, old_tail);
237 new->val.next = &to_split->list;
238 new->val.prev = old_tail;
239 to_split->list.prev = &new->val;
240 old_tail->next = &new->val;
241
242 /* split the hits */
243 new->hit = parent->hit;
244 new->cumul_hit = parent->cumul_hit;
245 new->val_nr = parent->val_nr - idx_local;
246 parent->val_nr = idx_local;
247
248 /* create a new child for the new branch if any */
249 if (idx_total < chain->nr) {
250 parent->hit = 0;
251 add_child(parent, chain, idx_total, syms);
252 } else {
253 parent->hit = 1;
254 }
113} 255}
114 256
115static int 257static int
116__append_chain(struct callchain_node *root, struct ip_callchain *chain, 258__append_chain(struct callchain_node *root, struct ip_callchain *chain,
117 int start); 259 unsigned int start, struct symbol **syms);
118 260
119static int 261static void
120__append_chain_children(struct callchain_node *root, struct ip_callchain *chain) 262__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
263 struct symbol **syms, unsigned int start)
121{ 264{
122 struct callchain_node *rnode; 265 struct callchain_node *rnode;
123 266
124 /* lookup in childrens */ 267 /* lookup in childrens */
125 list_for_each_entry(rnode, &root->children, brothers) { 268 chain_for_each_child(rnode, root) {
126 int ret = __append_chain(rnode, chain, root->val_nr); 269 unsigned int ret = __append_chain(rnode, chain, start, syms);
270
127 if (!ret) 271 if (!ret)
128 return 0; 272 goto cumul;
129 } 273 }
130 return -1; 274 /* nothing in children, add to the current node */
275 add_child(root, chain, start, syms);
276
277cumul:
278 root->cumul_hit++;
131} 279}
132 280
133static int 281static int
134__append_chain(struct callchain_node *root, struct ip_callchain *chain, 282__append_chain(struct callchain_node *root, struct ip_callchain *chain,
135 int start) 283 unsigned int start, struct symbol **syms)
136{ 284{
137 struct callchain_list *cnode; 285 struct callchain_list *cnode;
138 int i = start; 286 unsigned int i = start;
139 bool found = false; 287 bool found = false;
140 288
141 /* lookup in the current node */ 289 /*
290 * Lookup in the current node
291 * If we have a symbol, then compare the start to match
292 * anywhere inside a function.
293 */
142 list_for_each_entry(cnode, &root->val, list) { 294 list_for_each_entry(cnode, &root->val, list) {
143 if (cnode->ip != chain->ips[i++]) 295 if (i == chain->nr)
296 break;
297 if (cnode->sym && syms[i]) {
298 if (cnode->sym->start != syms[i]->start)
299 break;
300 } else if (cnode->ip != chain->ips[i])
144 break; 301 break;
145 if (!found) 302 if (!found)
146 found = true; 303 found = true;
147 if (i == chain->nr) 304 i++;
148 break;
149 } 305 }
150 306
151 /* matches not, relay on the parent */ 307 /* matches not, relay on the parent */
@@ -153,22 +309,27 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
153 return -1; 309 return -1;
154 310
155 /* we match only a part of the node. Split it and add the new chain */ 311 /* we match only a part of the node. Split it and add the new chain */
156 if (i < root->val_nr) { 312 if (i - start < root->val_nr) {
157 split_add_child(root, chain, cnode, i); 313 split_add_child(root, chain, cnode, start, i - start, syms);
158 return 0; 314 return 0;
159 } 315 }
160 316
161 /* we match 100% of the path, increment the hit */ 317 /* we match 100% of the path, increment the hit */
162 if (i == root->val_nr) { 318 if (i - start == root->val_nr && i == chain->nr) {
163 root->hit++; 319 root->hit++;
320 root->cumul_hit++;
321
164 return 0; 322 return 0;
165 } 323 }
166 324
167 return __append_chain_children(root, chain); 325 /* We match the node and still have a part remaining */
326 __append_chain_children(root, chain, syms, i);
327
328 return 0;
168} 329}
169 330
170void append_chain(struct callchain_node *root, struct ip_callchain *chain) 331void append_chain(struct callchain_node *root, struct ip_callchain *chain,
332 struct symbol **syms)
171{ 333{
172 if (__append_chain_children(root, chain) == -1) 334 __append_chain_children(root, chain, syms, 0);
173 add_child(root, chain);
174} 335}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index fa1cd2f71fd3..7812122bea1d 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -2,22 +2,42 @@
2#define __PERF_CALLCHAIN_H 2#define __PERF_CALLCHAIN_H
3 3
4#include "../perf.h" 4#include "../perf.h"
5#include "list.h" 5#include <linux/list.h>
6#include "rbtree.h" 6#include <linux/rbtree.h>
7#include "symbol.h"
7 8
9enum chain_mode {
10 CHAIN_FLAT,
11 CHAIN_GRAPH_ABS,
12 CHAIN_GRAPH_REL
13};
8 14
9struct callchain_node { 15struct callchain_node {
10 struct callchain_node *parent; 16 struct callchain_node *parent;
11 struct list_head brothers; 17 struct list_head brothers;
12 struct list_head children; 18 struct list_head children;
13 struct list_head val; 19 struct list_head val;
14 struct rb_node rb_node; 20 struct rb_node rb_node; /* to sort nodes in an rbtree */
15 int val_nr; 21 struct rb_root rb_root; /* sorted tree of children */
16 int hit; 22 unsigned int val_nr;
23 u64 hit;
24 u64 cumul_hit; /* hit + hits of children */
25};
26
27struct callchain_param;
28
29typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
30 u64, struct callchain_param *);
31
32struct callchain_param {
33 enum chain_mode mode;
34 double min_percent;
35 sort_chain_func_t sort;
17}; 36};
18 37
19struct callchain_list { 38struct callchain_list {
20 unsigned long ip; 39 u64 ip;
40 struct symbol *sym;
21 struct list_head list; 41 struct list_head list;
22}; 42};
23 43
@@ -28,6 +48,7 @@ static inline void callchain_init(struct callchain_node *node)
28 INIT_LIST_HEAD(&node->val); 48 INIT_LIST_HEAD(&node->val);
29} 49}
30 50
31void append_chain(struct callchain_node *root, struct ip_callchain *chain); 51int register_callchain_param(struct callchain_param *param);
32void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node); 52void append_chain(struct callchain_node *root, struct ip_callchain *chain,
53 struct symbol **syms);
33#endif 54#endif
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 9a8c20ccc53e..90a044d1fe7d 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])
@@ -222,10 +224,12 @@ int color_fwrite_lines(FILE *fp, const char *color,
222{ 224{
223 if (!*color) 225 if (!*color)
224 return fwrite(buf, count, 1, fp) != 1; 226 return fwrite(buf, count, 1, fp) != 1;
227
225 while (count) { 228 while (count) {
226 char *p = memchr(buf, '\n', count); 229 char *p = memchr(buf, '\n', count);
230
227 if (p != buf && (fputs(color, fp) < 0 || 231 if (p != buf && (fputs(color, fp) < 0 ||
228 fwrite(buf, p ? p - buf : count, 1, fp) != 1 || 232 fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
229 fputs(PERF_COLOR_RESET, fp) < 0)) 233 fputs(PERF_COLOR_RESET, fp) < 0))
230 return -1; 234 return -1;
231 if (!p) 235 if (!p)
@@ -238,4 +242,31 @@ int color_fwrite_lines(FILE *fp, const char *color,
238 return 0; 242 return 0;
239} 243}
240 244
245char *get_percent_color(double percent)
246{
247 char *color = PERF_COLOR_NORMAL;
241 248
249 /*
250 * We color high-overhead entries in red, mid-overhead
251 * entries in green - and keep the low overhead places
252 * normal:
253 */
254 if (percent >= MIN_RED)
255 color = PERF_COLOR_RED;
256 else {
257 if (percent > MIN_GREEN)
258 color = PERF_COLOR_GREEN;
259 }
260 return color;
261}
262
263int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
264{
265 int r;
266 char *color;
267
268 color = get_percent_color(percent);
269 r = color_fprintf(fp, color, fmt, percent);
270
271 return r;
272}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 5abfd379582b..706cec50bd25 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 */
@@ -32,5 +35,7 @@ void color_parse_mem(const char *value, int len, const char *var, char *dst);
32int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 35int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
33int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 36int 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); 37int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
38int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
39char *get_percent_color(double percent);
35 40
36#endif /* COLOR_H */ 41#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3dd13faa6a27..780df541006d 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') {
@@ -353,13 +355,13 @@ int perf_config_string(const char **dest, const char *var, const char *value)
353 return 0; 355 return 0;
354} 356}
355 357
356static int perf_default_core_config(const char *var, const char *value) 358static int perf_default_core_config(const char *var __used, const char *value __used)
357{ 359{
358 /* Add other config variables here and to Documentation/config.txt. */ 360 /* Add other config variables here and to Documentation/config.txt. */
359 return 0; 361 return 0;
360} 362}
361 363
362int perf_default_config(const char *var, const char *value, void *dummy) 364int perf_default_config(const char *var, const char *value, void *dummy __used)
363{ 365{
364 if (!prefixcmp(var, "core.")) 366 if (!prefixcmp(var, "core."))
365 return perf_default_core_config(var, value); 367 return perf_default_core_config(var, value);
@@ -471,10 +473,10 @@ static int matches(const char* key, const char* value)
471 !regexec(store.value_regex, value, 0, NULL, 0))); 473 !regexec(store.value_regex, value, 0, NULL, 0)));
472} 474}
473 475
474static int store_aux(const char* key, const char* value, void *cb) 476static int store_aux(const char* key, const char* value, void *cb __used)
475{ 477{
478 int section_len;
476 const char *ep; 479 const char *ep;
477 size_t section_len;
478 480
479 switch (store.state) { 481 switch (store.state) {
480 case KEY_SEEN: 482 case KEY_SEEN:
@@ -551,7 +553,7 @@ static int store_write_section(int fd, const char* key)
551 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); 553 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
552 } 554 }
553 555
554 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 556 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
555 strbuf_release(&sb); 557 strbuf_release(&sb);
556 558
557 return success; 559 return success;
@@ -599,7 +601,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
599 } 601 }
600 strbuf_addf(&sb, "%s\n", quote); 602 strbuf_addf(&sb, "%s\n", quote);
601 603
602 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 604 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
603 strbuf_release(&sb); 605 strbuf_release(&sb);
604 606
605 return success; 607 return success;
@@ -741,7 +743,7 @@ int perf_config_set_multivar(const char* key, const char* value,
741 } else { 743 } else {
742 struct stat st; 744 struct stat st;
743 char* contents; 745 char* contents;
744 size_t contents_sz, copy_begin, copy_end; 746 ssize_t contents_sz, copy_begin, copy_end;
745 int i, new_line = 0; 747 int i, new_line = 0;
746 748
747 if (value_regex == NULL) 749 if (value_regex == NULL)
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index d39292263153..34a352867382 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -1,6 +1,9 @@
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; 9extern char **environ;
@@ -51,7 +54,7 @@ const char *perf_extract_argv0_path(const char *argv0)
51 slash--; 54 slash--;
52 55
53 if (slash >= argv0) { 56 if (slash >= argv0) {
54 argv0_path = strndup(argv0, slash - argv0); 57 argv0_path = xstrndup(argv0, slash - argv0);
55 return slash + 1; 58 return slash + 1;
56 } 59 }
57 60
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index b5ef53ad4c7a..bf280449fcfd 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -16,7 +16,7 @@ struct perf_header {
16 int frozen; 16 int frozen;
17 int attrs, size; 17 int attrs, size;
18 struct perf_header_attr **attr; 18 struct perf_header_attr **attr;
19 off_t attr_offset; 19 s64 attr_offset;
20 u64 data_offset; 20 u64 data_offset;
21 u64 data_size; 21 u64 data_size;
22}; 22};
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index 17a00e0df2c4..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)
@@ -208,7 +210,7 @@ void load_command_list(const char *prefix,
208void list_commands(const char *title, struct cmdnames *main_cmds, 210void list_commands(const char *title, struct cmdnames *main_cmds,
209 struct cmdnames *other_cmds) 211 struct cmdnames *other_cmds)
210{ 212{
211 int i, longest = 0; 213 unsigned int i, longest = 0;
212 214
213 for (i = 0; i < main_cmds->cnt; i++) 215 for (i = 0; i < main_cmds->cnt; i++)
214 if (longest < main_cmds->names[i]->len) 216 if (longest < main_cmds->names[i]->len)
@@ -239,7 +241,8 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
239 241
240int is_in_cmdlist(struct cmdnames *c, const char *s) 242int is_in_cmdlist(struct cmdnames *c, const char *s)
241{ 243{
242 int i; 244 unsigned int i;
245
243 for (i = 0; i < c->cnt; i++) 246 for (i = 0; i < c->cnt; i++)
244 if (!strcmp(s, c->names[i]->name)) 247 if (!strcmp(s, c->names[i]->name))
245 return 1; 248 return 1;
@@ -271,7 +274,8 @@ static int levenshtein_compare(const void *p1, const void *p2)
271 274
272static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) 275static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
273{ 276{
274 int i; 277 unsigned int i;
278
275 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc); 279 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
276 280
277 for (i = 0; i < old->cnt; i++) 281 for (i = 0; i < old->cnt; i++)
@@ -283,7 +287,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
283 287
284const char *help_unknown_cmd(const char *cmd) 288const char *help_unknown_cmd(const char *cmd)
285{ 289{
286 int i, n = 0, best_similarity = 0; 290 unsigned int i, n = 0, best_similarity = 0;
287 struct cmdnames main_cmds, other_cmds; 291 struct cmdnames main_cmds, other_cmds;
288 292
289 memset(&main_cmds, 0, sizeof(main_cmds)); 293 memset(&main_cmds, 0, sizeof(main_cmds));
@@ -345,7 +349,7 @@ const char *help_unknown_cmd(const char *cmd)
345 exit(1); 349 exit(1);
346} 350}
347 351
348int cmd_version(int argc, const char **argv, const char *prefix) 352int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
349{ 353{
350 printf("perf version %s\n", perf_version_string); 354 printf("perf version %s\n", perf_version_string);
351 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/module.c b/tools/perf/util/module.c
new file mode 100644
index 000000000000..ddabe925d65d
--- /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 *path, *name, *tmp;
440 struct module *module;
441 int line_len, 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/parse-events.c b/tools/perf/util/parse-events.c
index 4d042f104cdc..7bdad8df22a6 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -5,6 +5,7 @@
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#include "cache.h"
8 9
9extern char *strcasestr(const char *haystack, const char *needle); 10extern char *strcasestr(const char *haystack, const char *needle);
10 11
@@ -19,6 +20,8 @@ struct event_symbol {
19 char *alias; 20 char *alias;
20}; 21};
21 22
23char debugfs_path[MAXPATHLEN];
24
22#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 25#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
23#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 26#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
24 27
@@ -71,8 +74,8 @@ static char *sw_event_names[] = {
71#define MAX_ALIASES 8 74#define MAX_ALIASES 8
72 75
73static char *hw_cache[][MAX_ALIASES] = { 76static char *hw_cache[][MAX_ALIASES] = {
74 { "L1-d$", "l1-d", "l1d", "L1-data", }, 77 { "L1-dcache", "l1-d", "l1d", "L1-data", },
75 { "L1-i$", "l1-i", "l1i", "L1-instruction", }, 78 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
76 { "LLC", "L2" }, 79 { "LLC", "L2" },
77 { "dTLB", "d-tlb", "Data-TLB", }, 80 { "dTLB", "d-tlb", "Data-TLB", },
78 { "iTLB", "i-tlb", "Instruction-TLB", }, 81 { "iTLB", "i-tlb", "Instruction-TLB", },
@@ -110,6 +113,88 @@ static unsigned long hw_cache_stat[C(MAX)] = {
110 [C(BPU)] = (CACHE_READ), 113 [C(BPU)] = (CACHE_READ),
111}; 114};
112 115
116#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \
117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
118 if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \
119 sys_dirent.d_name) && \
120 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
121 (strcmp(sys_dirent.d_name, ".")) && \
122 (strcmp(sys_dirent.d_name, "..")))
123
124#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
125 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
126 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
127 sys_dirent.d_name, evt_dirent.d_name) && \
128 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
129 (strcmp(evt_dirent.d_name, ".")) && \
130 (strcmp(evt_dirent.d_name, "..")))
131
132#define MAX_EVENT_LENGTH 30
133
134int valid_debugfs_mount(const char *debugfs)
135{
136 struct statfs st_fs;
137
138 if (statfs(debugfs, &st_fs) < 0)
139 return -ENOENT;
140 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
141 return -ENOENT;
142 return 0;
143}
144
145static char *tracepoint_id_to_name(u64 config)
146{
147 static char tracepoint_name[2 * MAX_EVENT_LENGTH];
148 DIR *sys_dir, *evt_dir;
149 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
150 struct stat st;
151 char id_buf[4];
152 int fd;
153 u64 id;
154 char evt_path[MAXPATHLEN];
155
156 if (valid_debugfs_mount(debugfs_path))
157 return "unkown";
158
159 sys_dir = opendir(debugfs_path);
160 if (!sys_dir)
161 goto cleanup;
162
163 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
164 evt_dir = opendir(evt_path);
165 if (!evt_dir)
166 goto cleanup;
167 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
168 evt_path, st) {
169 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
170 debugfs_path, sys_dirent.d_name,
171 evt_dirent.d_name);
172 fd = open(evt_path, O_RDONLY);
173 if (fd < 0)
174 continue;
175 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
176 close(fd);
177 continue;
178 }
179 close(fd);
180 id = atoll(id_buf);
181 if (id == config) {
182 closedir(evt_dir);
183 closedir(sys_dir);
184 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
185 "%s:%s", sys_dirent.d_name,
186 evt_dirent.d_name);
187 return tracepoint_name;
188 }
189 }
190 closedir(evt_dir);
191 }
192
193cleanup:
194 closedir(sys_dir);
195 return "unkown";
196}
197
113static int is_cache_op_valid(u8 cache_type, u8 cache_op) 198static int is_cache_op_valid(u8 cache_type, u8 cache_op)
114{ 199{
115 if (hw_cache_stat[cache_type] & COP(cache_op)) 200 if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -177,6 +262,9 @@ char *event_name(int counter)
177 return sw_event_names[config]; 262 return sw_event_names[config];
178 return "unknown-software"; 263 return "unknown-software";
179 264
265 case PERF_TYPE_TRACEPOINT:
266 return tracepoint_id_to_name(config);
267
180 default: 268 default:
181 break; 269 break;
182 } 270 }
@@ -184,16 +272,20 @@ char *event_name(int counter)
184 return "unknown"; 272 return "unknown";
185} 273}
186 274
187static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) 275static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
188{ 276{
189 int i, j; 277 int i, j;
278 int n, longest = -1;
190 279
191 for (i = 0; i < size; i++) { 280 for (i = 0; i < size; i++) {
192 for (j = 0; j < MAX_ALIASES; j++) { 281 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
193 if (!names[i][j]) 282 n = strlen(names[i][j]);
194 break; 283 if (n > longest && !strncasecmp(*str, names[i][j], n))
195 if (strcasestr(str, names[i][j])) 284 longest = n;
196 return i; 285 }
286 if (longest > 0) {
287 *str += longest;
288 return i;
197 } 289 }
198 } 290 }
199 291
@@ -201,30 +293,53 @@ static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
201} 293}
202 294
203static int 295static int
204parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) 296parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
205{ 297{
206 int cache_type = -1, cache_op = 0, cache_result = 0; 298 const char *s = *str;
299 int cache_type = -1, cache_op = -1, cache_result = -1;
207 300
208 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); 301 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
209 /* 302 /*
210 * No fallback - if we cannot get a clear cache type 303 * No fallback - if we cannot get a clear cache type
211 * then bail out: 304 * then bail out:
212 */ 305 */
213 if (cache_type == -1) 306 if (cache_type == -1)
214 return -EINVAL; 307 return 0;
308
309 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
310 ++s;
311
312 if (cache_op == -1) {
313 cache_op = parse_aliases(&s, hw_cache_op,
314 PERF_COUNT_HW_CACHE_OP_MAX);
315 if (cache_op >= 0) {
316 if (!is_cache_op_valid(cache_type, cache_op))
317 return 0;
318 continue;
319 }
320 }
321
322 if (cache_result == -1) {
323 cache_result = parse_aliases(&s, hw_cache_result,
324 PERF_COUNT_HW_CACHE_RESULT_MAX);
325 if (cache_result >= 0)
326 continue;
327 }
328
329 /*
330 * Can't parse this as a cache op or result, so back up
331 * to the '-'.
332 */
333 --s;
334 break;
335 }
215 336
216 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
217 /* 337 /*
218 * Fall back to reads: 338 * Fall back to reads:
219 */ 339 */
220 if (cache_op == -1) 340 if (cache_op == -1)
221 cache_op = PERF_COUNT_HW_CACHE_OP_READ; 341 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
222 342
223 if (!is_cache_op_valid(cache_type, cache_op))
224 return -EINVAL;
225
226 cache_result = parse_aliases(str, hw_cache_result,
227 PERF_COUNT_HW_CACHE_RESULT_MAX);
228 /* 343 /*
229 * Fall back to accesses: 344 * Fall back to accesses:
230 */ 345 */
@@ -234,93 +349,202 @@ parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
234 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 349 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
235 attr->type = PERF_TYPE_HW_CACHE; 350 attr->type = PERF_TYPE_HW_CACHE;
236 351
237 return 0; 352 *str = s;
353 return 1;
354}
355
356static int parse_tracepoint_event(const char **strp,
357 struct perf_counter_attr *attr)
358{
359 const char *evt_name;
360 char sys_name[MAX_EVENT_LENGTH];
361 char id_buf[4];
362 int fd;
363 unsigned int sys_length, evt_length;
364 u64 id;
365 char evt_path[MAXPATHLEN];
366
367 if (valid_debugfs_mount(debugfs_path))
368 return 0;
369
370 evt_name = strchr(*strp, ':');
371 if (!evt_name)
372 return 0;
373
374 sys_length = evt_name - *strp;
375 if (sys_length >= MAX_EVENT_LENGTH)
376 return 0;
377
378 strncpy(sys_name, *strp, sys_length);
379 sys_name[sys_length] = '\0';
380 evt_name = evt_name + 1;
381 evt_length = strlen(evt_name);
382 if (evt_length >= MAX_EVENT_LENGTH)
383 return 0;
384
385 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
386 sys_name, evt_name);
387 fd = open(evt_path, O_RDONLY);
388 if (fd < 0)
389 return 0;
390
391 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
392 close(fd);
393 return 0;
394 }
395 close(fd);
396 id = atoll(id_buf);
397 attr->config = id;
398 attr->type = PERF_TYPE_TRACEPOINT;
399 *strp = evt_name + evt_length;
400 return 1;
238} 401}
239 402
240static int check_events(const char *str, unsigned int i) 403static int check_events(const char *str, unsigned int i)
241{ 404{
242 if (!strncmp(str, event_symbols[i].symbol, 405 int n;
243 strlen(event_symbols[i].symbol)))
244 return 1;
245 406
246 if (strlen(event_symbols[i].alias)) 407 n = strlen(event_symbols[i].symbol);
247 if (!strncmp(str, event_symbols[i].alias, 408 if (!strncmp(str, event_symbols[i].symbol, n))
248 strlen(event_symbols[i].alias))) 409 return n;
249 return 1; 410
411 n = strlen(event_symbols[i].alias);
412 if (n)
413 if (!strncmp(str, event_symbols[i].alias, n))
414 return n;
250 return 0; 415 return 0;
251} 416}
252 417
253/* 418static int
254 * Each event can have multiple symbolic names. 419parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
255 * Symbolic names are (almost) exactly matched.
256 */
257static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
258{ 420{
259 u64 config, id; 421 const char *str = *strp;
260 int type;
261 unsigned int i; 422 unsigned int i;
262 const char *sep, *pstr; 423 int n;
263 424
264 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { 425 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
265 attr->type = PERF_TYPE_RAW; 426 n = check_events(str, i);
266 attr->config = config; 427 if (n > 0) {
428 attr->type = event_symbols[i].type;
429 attr->config = event_symbols[i].config;
430 *strp = str + n;
431 return 1;
432 }
433 }
434 return 0;
435}
436
437static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
438{
439 const char *str = *strp;
440 u64 config;
441 int n;
267 442
443 if (*str != 'r')
268 return 0; 444 return 0;
445 n = hex2u64(str + 1, &config);
446 if (n > 0) {
447 *strp = str + n + 1;
448 attr->type = PERF_TYPE_RAW;
449 attr->config = config;
450 return 1;
269 } 451 }
452 return 0;
453}
270 454
271 pstr = str; 455static int
272 sep = strchr(pstr, ':'); 456parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
273 if (sep) { 457{
274 type = atoi(pstr); 458 const char *str = *strp;
275 pstr = sep + 1; 459 char *endp;
276 id = atoi(pstr); 460 unsigned long type;
277 sep = strchr(pstr, ':'); 461 u64 config;
278 if (sep) { 462
279 pstr = sep + 1; 463 type = strtoul(str, &endp, 0);
280 if (strchr(pstr, 'k')) 464 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
281 attr->exclude_user = 1; 465 str = endp + 1;
282 if (strchr(pstr, 'u')) 466 config = strtoul(str, &endp, 0);
283 attr->exclude_kernel = 1; 467 if (endp > str) {
468 attr->type = type;
469 attr->config = config;
470 *strp = endp;
471 return 1;
284 } 472 }
285 attr->type = type; 473 }
286 attr->config = id; 474 return 0;
475}
287 476
477static int
478parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
479{
480 const char *str = *strp;
481 int eu = 1, ek = 1, eh = 1;
482
483 if (*str++ != ':')
288 return 0; 484 return 0;
485 while (*str) {
486 if (*str == 'u')
487 eu = 0;
488 else if (*str == 'k')
489 ek = 0;
490 else if (*str == 'h')
491 eh = 0;
492 else
493 break;
494 ++str;
495 }
496 if (str >= *strp + 2) {
497 *strp = str;
498 attr->exclude_user = eu;
499 attr->exclude_kernel = ek;
500 attr->exclude_hv = eh;
501 return 1;
289 } 502 }
503 return 0;
504}
290 505
291 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 506/*
292 if (check_events(str, i)) { 507 * Each event can have multiple symbolic names.
293 attr->type = event_symbols[i].type; 508 * Symbolic names are (almost) exactly matched.
294 attr->config = event_symbols[i].config; 509 */
510static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
511{
512 if (!(parse_tracepoint_event(str, attr) ||
513 parse_raw_event(str, attr) ||
514 parse_numeric_event(str, attr) ||
515 parse_symbolic_event(str, attr) ||
516 parse_generic_hw_event(str, attr)))
517 return 0;
295 518
296 return 0; 519 parse_event_modifier(str, attr);
297 }
298 }
299 520
300 return parse_generic_hw_symbols(str, attr); 521 return 1;
301} 522}
302 523
303int parse_events(const struct option *opt, const char *str, int unset) 524int parse_events(const struct option *opt __used, const char *str, int unset __used)
304{ 525{
305 struct perf_counter_attr attr; 526 struct perf_counter_attr attr;
306 int ret;
307 527
308 memset(&attr, 0, sizeof(attr)); 528 for (;;) {
309again: 529 if (nr_counters == MAX_COUNTERS)
310 if (nr_counters == MAX_COUNTERS) 530 return -1;
311 return -1; 531
532 memset(&attr, 0, sizeof(attr));
533 if (!parse_event_symbols(&str, &attr))
534 return -1;
312 535
313 ret = parse_event_symbols(str, &attr); 536 if (!(*str == 0 || *str == ',' || isspace(*str)))
314 if (ret < 0) 537 return -1;
315 return ret;
316 538
317 attrs[nr_counters] = attr; 539 attrs[nr_counters] = attr;
318 nr_counters++; 540 nr_counters++;
319 541
320 str = strstr(str, ","); 542 if (*str == 0)
321 if (str) { 543 break;
322 str++; 544 if (*str == ',')
323 goto again; 545 ++str;
546 while (isspace(*str))
547 ++str;
324 } 548 }
325 549
326 return 0; 550 return 0;
@@ -335,12 +559,48 @@ static const char * const event_type_descriptors[] = {
335}; 559};
336 560
337/* 561/*
562 * Print the events from <debugfs_mount_point>/tracing/events
563 */
564
565static void print_tracepoint_events(void)
566{
567 DIR *sys_dir, *evt_dir;
568 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
569 struct stat st;
570 char evt_path[MAXPATHLEN];
571
572 if (valid_debugfs_mount(debugfs_path))
573 return;
574
575 sys_dir = opendir(debugfs_path);
576 if (!sys_dir)
577 goto cleanup;
578
579 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
580 evt_dir = opendir(evt_path);
581 if (!evt_dir)
582 goto cleanup;
583 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
584 evt_path, st) {
585 snprintf(evt_path, MAXPATHLEN, "%s:%s",
586 sys_dirent.d_name, evt_dirent.d_name);
587 fprintf(stderr, " %-40s [%s]\n", evt_path,
588 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
589 }
590 closedir(evt_dir);
591 }
592
593cleanup:
594 closedir(sys_dir);
595}
596
597/*
338 * Print the help text for the event symbols: 598 * Print the help text for the event symbols:
339 */ 599 */
340void print_events(void) 600void print_events(void)
341{ 601{
342 struct event_symbol *syms = event_symbols; 602 struct event_symbol *syms = event_symbols;
343 unsigned int i, type, prev_type = -1; 603 unsigned int i, type, op, prev_type = -1;
344 char name[40]; 604 char name[40];
345 605
346 fprintf(stderr, "\n"); 606 fprintf(stderr, "\n");
@@ -348,7 +608,7 @@ void print_events(void)
348 608
349 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 609 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
350 type = syms->type + 1; 610 type = syms->type + 1;
351 if (type > ARRAY_SIZE(event_type_descriptors)) 611 if (type >= ARRAY_SIZE(event_type_descriptors))
352 type = 0; 612 type = 0;
353 613
354 if (type != prev_type) 614 if (type != prev_type)
@@ -365,9 +625,26 @@ void print_events(void)
365 } 625 }
366 626
367 fprintf(stderr, "\n"); 627 fprintf(stderr, "\n");
628 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
629 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
630 /* skip invalid cache type */
631 if (!is_cache_op_valid(type, op))
632 continue;
633
634 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
635 fprintf(stderr, " %-40s [%s]\n",
636 event_cache_name(type, op, i),
637 event_type_descriptors[4]);
638 }
639 }
640 }
641
642 fprintf(stderr, "\n");
368 fprintf(stderr, " %-40s [raw hardware event descriptor]\n", 643 fprintf(stderr, " %-40s [raw hardware event descriptor]\n",
369 "rNNN"); 644 "rNNN");
370 fprintf(stderr, "\n"); 645 fprintf(stderr, "\n");
371 646
647 print_tracepoint_events();
648
372 exit(129); 649 exit(129);
373} 650}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e3d552908e60..1ea5d09b6eb1 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -3,6 +3,8 @@
3 * Parse symbolic events/counts passed in as options: 3 * Parse symbolic events/counts passed in as options:
4 */ 4 */
5 5
6struct option;
7
6extern int nr_counters; 8extern int nr_counters;
7 9
8extern struct perf_counter_attr attrs[MAX_COUNTERS]; 10extern struct perf_counter_attr attrs[MAX_COUNTERS];
@@ -15,3 +17,6 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
15 17
16extern void print_events(void); 18extern void print_events(void);
17 19
20extern char debugfs_path[];
21extern int valid_debugfs_mount(const char *debugfs);
22
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index b3affb1658d2..1bf67190c820 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--;
@@ -485,7 +486,7 @@ int parse_options_usage(const char * const *usagestr,
485} 486}
486 487
487 488
488int parse_opt_verbosity_cb(const struct option *opt, const char *arg, 489int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
489 int unset) 490 int unset)
490{ 491{
491 int *target = opt->value; 492 int *target = opt->value;
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index a1039a6ce0eb..8aa3464c7090 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -90,21 +90,22 @@ 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_DEFAULT(s, l, v, a, h, f, d) \
108 { .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 109
109/* parse_options() will filter out the processed options and leave the 110/* parse_options() will filter out the processed options and leave the
110 * non-option argments in argv[]. 111 * non-option argments in argv[].
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/strbuf.c b/tools/perf/util/strbuf.c
index 464e7ca898cf..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}
@@ -264,7 +265,7 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
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 3dca2f654cd0..bf39dfadfd24 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -5,4 +5,7 @@
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
index 025a78edfffe..7ad38171dc2b 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -64,6 +64,7 @@ int strlist__add(struct strlist *self, const char *new_entry)
64 64
65 rb_link_node(&sn->rb_node, parent, p); 65 rb_link_node(&sn->rb_node, parent, p);
66 rb_insert_color(&sn->rb_node, &self->entries); 66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
67 68
68 return 0; 69 return 0;
69} 70}
@@ -155,8 +156,9 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
155 struct strlist *self = malloc(sizeof(*self)); 156 struct strlist *self = malloc(sizeof(*self));
156 157
157 if (self != NULL) { 158 if (self != NULL) {
158 self->entries = RB_ROOT; 159 self->entries = RB_ROOT;
159 self->dupstr = dupstr; 160 self->dupstr = dupstr;
161 self->nr_entries = 0;
160 if (slist && strlist__parse_list(self, slist) != 0) 162 if (slist && strlist__parse_list(self, slist) != 0)
161 goto out_error; 163 goto out_error;
162 } 164 }
@@ -182,3 +184,17 @@ void strlist__delete(struct strlist *self)
182 free(self); 184 free(self);
183 } 185 }
184} 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
index 2fb117fb4b67..921818e44a54 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,7 +1,7 @@
1#ifndef STRLIST_H_ 1#ifndef STRLIST_H_
2#define STRLIST_H_ 2#define STRLIST_H_
3 3
4#include "rbtree.h" 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7struct str_node { 7struct str_node {
@@ -11,7 +11,8 @@ struct str_node {
11 11
12struct strlist { 12struct strlist {
13 struct rb_root entries; 13 struct rb_root entries;
14 bool dupstr; 14 unsigned int nr_entries;
15 bool dupstr;
15}; 16};
16 17
17struct strlist *strlist__new(bool dupstr, const char *slist); 18struct strlist *strlist__new(bool dupstr, const char *slist);
@@ -21,11 +22,17 @@ void strlist__remove(struct strlist *self, struct str_node *sn);
21int strlist__load(struct strlist *self, const char *filename); 22int strlist__load(struct strlist *self, const char *filename);
22int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
23 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
24bool strlist__has_entry(struct strlist *self, const char *entry); 26bool strlist__has_entry(struct strlist *self, const char *entry);
25 27
26static inline bool strlist__empty(const struct strlist *self) 28static inline bool strlist__empty(const struct strlist *self)
27{ 29{
28 return rb_first(&self->entries) == NULL; 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;
29} 36}
30 37
31int strlist__parse_list(struct strlist *self, const char *s); 38int strlist__parse_list(struct strlist *self, const char *s);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 78c2efde01b7..16ddca202948 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -7,8 +7,23 @@
7#include <gelf.h> 7#include <gelf.h>
8#include <elf.h> 8#include <elf.h>
9 9
10#ifndef NO_DEMANGLE
11#include <bfd.h>
12#else
13static inline
14char *bfd_demangle(void __used *v, const char __used *c, int __used i)
15{
16 return NULL;
17}
18#endif
19
10const char *sym_hist_filter; 20const char *sym_hist_filter;
11 21
22#ifndef DMGL_PARAMS
23#define DMGL_PARAMS (1 << 0) /* Include function args */
24#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
25#endif
26
12static struct symbol *symbol__new(u64 start, u64 len, 27static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 28 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 29 u64 obj_start, int verbose)
@@ -35,7 +50,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
35 self = ((void *)self) + priv_size; 50 self = ((void *)self) + priv_size;
36 } 51 }
37 self->start = start; 52 self->start = start;
38 self->end = start + len - 1; 53 self->end = len ? start + len - 1 : start;
39 memcpy(self->name, name, namelen); 54 memcpy(self->name, name, namelen);
40 55
41 return self; 56 return self;
@@ -48,8 +63,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
48 63
49static size_t symbol__fprintf(struct symbol *self, FILE *fp) 64static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50{ 65{
51 return fprintf(fp, " %llx-%llx %s\n", 66 if (!self->module)
67 return fprintf(fp, " %llx-%llx %s\n",
52 self->start, self->end, self->name); 68 self->start, self->end, self->name);
69 else
70 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
71 self->start, self->end, self->name, self->module->name);
53} 72}
54 73
55struct dso *dso__new(const char *name, unsigned int sym_priv_size) 74struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -61,6 +80,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
61 self->syms = RB_ROOT; 80 self->syms = RB_ROOT;
62 self->sym_priv_size = sym_priv_size; 81 self->sym_priv_size = sym_priv_size;
63 self->find_symbol = dso__find_symbol; 82 self->find_symbol = dso__find_symbol;
83 self->slen_calculated = 0;
64 } 84 }
65 85
66 return self; 86 return self;
@@ -146,6 +166,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
146 char *line = NULL; 166 char *line = NULL;
147 size_t n; 167 size_t n;
148 FILE *file = fopen("/proc/kallsyms", "r"); 168 FILE *file = fopen("/proc/kallsyms", "r");
169 int count = 0;
149 170
150 if (file == NULL) 171 if (file == NULL)
151 goto out_failure; 172 goto out_failure;
@@ -188,8 +209,10 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
188 209
189 if (filter && filter(self, sym)) 210 if (filter && filter(self, sym))
190 symbol__delete(sym, self->sym_priv_size); 211 symbol__delete(sym, self->sym_priv_size);
191 else 212 else {
192 dso__insert_symbol(self, sym); 213 dso__insert_symbol(self, sym);
214 count++;
215 }
193 } 216 }
194 217
195 /* 218 /*
@@ -212,7 +235,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
212 free(line); 235 free(line);
213 fclose(file); 236 fclose(file);
214 237
215 return 0; 238 return count;
216 239
217out_delete_line: 240out_delete_line:
218 free(line); 241 free(line);
@@ -307,6 +330,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
307 sym->st_size != 0; 330 sym->st_size != 0;
308} 331}
309 332
333static inline int elf_sym__is_label(const GElf_Sym *sym)
334{
335 return elf_sym__type(sym) == STT_NOTYPE &&
336 sym->st_name != 0 &&
337 sym->st_shndx != SHN_UNDEF &&
338 sym->st_shndx != SHN_ABS;
339}
340
341static inline const char *elf_sec__name(const GElf_Shdr *shdr,
342 const Elf_Data *secstrs)
343{
344 return secstrs->d_buf + shdr->sh_name;
345}
346
347static inline int elf_sec__is_text(const GElf_Shdr *shdr,
348 const Elf_Data *secstrs)
349{
350 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
351}
352
310static inline const char *elf_sym__name(const GElf_Sym *sym, 353static inline const char *elf_sym__name(const GElf_Sym *sym,
311 const Elf_Data *symstrs) 354 const Elf_Data *symstrs)
312{ 355{
@@ -346,36 +389,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
346 idx < nr_entries; \ 389 idx < nr_entries; \
347 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 390 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
348 391
349static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 392/*
350 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 393 * We need to check if we have a .dynsym, so that we can handle the
351 GElf_Shdr *shdr_dynsym, 394 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
352 size_t dynsym_idx, int verbose) 395 * .dynsym or .symtab).
396 * And always look at the original dso, not at debuginfo packages, that
397 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
398 */
399static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
353{ 400{
354 uint32_t nr_rel_entries, idx; 401 uint32_t nr_rel_entries, idx;
355 GElf_Sym sym; 402 GElf_Sym sym;
356 u64 plt_offset; 403 u64 plt_offset;
357 GElf_Shdr shdr_plt; 404 GElf_Shdr shdr_plt;
358 struct symbol *f; 405 struct symbol *f;
359 GElf_Shdr shdr_rel_plt; 406 GElf_Shdr shdr_rel_plt, shdr_dynsym;
360 Elf_Data *reldata, *syms, *symstrs; 407 Elf_Data *reldata, *syms, *symstrs;
361 Elf_Scn *scn_plt_rel, *scn_symstrs; 408 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
409 size_t dynsym_idx;
410 GElf_Ehdr ehdr;
362 char sympltname[1024]; 411 char sympltname[1024];
363 int nr = 0, symidx; 412 Elf *elf;
413 int nr = 0, symidx, fd, err = 0;
414
415 fd = open(self->name, O_RDONLY);
416 if (fd < 0)
417 goto out;
418
419 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
420 if (elf == NULL)
421 goto out_close;
364 422
365 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 423 if (gelf_getehdr(elf, &ehdr) == NULL)
424 goto out_elf_end;
425
426 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
427 ".dynsym", &dynsym_idx);
428 if (scn_dynsym == NULL)
429 goto out_elf_end;
430
431 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
366 ".rela.plt", NULL); 432 ".rela.plt", NULL);
367 if (scn_plt_rel == NULL) { 433 if (scn_plt_rel == NULL) {
368 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 434 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
369 ".rel.plt", NULL); 435 ".rel.plt", NULL);
370 if (scn_plt_rel == NULL) 436 if (scn_plt_rel == NULL)
371 return 0; 437 goto out_elf_end;
372 } 438 }
373 439
440 err = -1;
441
374 if (shdr_rel_plt.sh_link != dynsym_idx) 442 if (shdr_rel_plt.sh_link != dynsym_idx)
375 return 0; 443 goto out_elf_end;
376 444
377 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 445 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
378 return 0; 446 goto out_elf_end;
379 447
380 /* 448 /*
381 * Fetch the relocation section to find the indexes to the GOT 449 * Fetch the relocation section to find the indexes to the GOT
@@ -383,19 +451,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
383 */ 451 */
384 reldata = elf_getdata(scn_plt_rel, NULL); 452 reldata = elf_getdata(scn_plt_rel, NULL);
385 if (reldata == NULL) 453 if (reldata == NULL)
386 return -1; 454 goto out_elf_end;
387 455
388 syms = elf_getdata(scn_dynsym, NULL); 456 syms = elf_getdata(scn_dynsym, NULL);
389 if (syms == NULL) 457 if (syms == NULL)
390 return -1; 458 goto out_elf_end;
391 459
392 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 460 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
393 if (scn_symstrs == NULL) 461 if (scn_symstrs == NULL)
394 return -1; 462 goto out_elf_end;
395 463
396 symstrs = elf_getdata(scn_symstrs, NULL); 464 symstrs = elf_getdata(scn_symstrs, NULL);
397 if (symstrs == NULL) 465 if (symstrs == NULL)
398 return -1; 466 goto out_elf_end;
399 467
400 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 468 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
401 plt_offset = shdr_plt.sh_offset; 469 plt_offset = shdr_plt.sh_offset;
@@ -414,7 +482,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
414 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 482 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
415 sympltname, self->sym_priv_size, 0, verbose); 483 sympltname, self->sym_priv_size, 0, verbose);
416 if (!f) 484 if (!f)
417 return -1; 485 goto out_elf_end;
418 486
419 dso__insert_symbol(self, f); 487 dso__insert_symbol(self, f);
420 ++nr; 488 ++nr;
@@ -432,25 +500,31 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
432 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 500 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
433 sympltname, self->sym_priv_size, 0, verbose); 501 sympltname, self->sym_priv_size, 0, verbose);
434 if (!f) 502 if (!f)
435 return -1; 503 goto out_elf_end;
436 504
437 dso__insert_symbol(self, f); 505 dso__insert_symbol(self, f);
438 ++nr; 506 ++nr;
439 } 507 }
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 } 508 }
446 509
447 return nr; 510 err = 0;
511out_elf_end:
512 elf_end(elf);
513out_close:
514 close(fd);
515
516 if (err == 0)
517 return nr;
518out:
519 fprintf(stderr, "%s: problems reading %s PLT info.\n",
520 __func__, self->name);
521 return 0;
448} 522}
449 523
450static int dso__load_sym(struct dso *self, int fd, const char *name, 524static int dso__load_sym(struct dso *self, int fd, const char *name,
451 symbol_filter_t filter, int verbose) 525 symbol_filter_t filter, int verbose, struct module *mod)
452{ 526{
453 Elf_Data *symstrs; 527 Elf_Data *symstrs, *secstrs;
454 uint32_t nr_syms; 528 uint32_t nr_syms;
455 int err = -1; 529 int err = -1;
456 uint32_t index; 530 uint32_t index;
@@ -458,10 +532,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
458 GElf_Shdr shdr; 532 GElf_Shdr shdr;
459 Elf_Data *syms; 533 Elf_Data *syms;
460 GElf_Sym sym; 534 GElf_Sym sym;
461 Elf_Scn *sec, *sec_dynsym; 535 Elf_Scn *sec, *sec_strndx;
462 Elf *elf; 536 Elf *elf;
463 size_t dynsym_idx; 537 int nr = 0, kernel = !strcmp("[kernel]", self->name);
464 int nr = 0;
465 538
466 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 539 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467 if (elf == NULL) { 540 if (elf == NULL) {
@@ -477,32 +550,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
477 goto out_elf_end; 550 goto out_elf_end;
478 } 551 }
479 552
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); 553 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
500 if (sec == NULL) { 554 if (sec == NULL) {
501 if (sec_dynsym == NULL) 555 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
556 if (sec == NULL)
502 goto out_elf_end; 557 goto out_elf_end;
503
504 sec = sec_dynsym;
505 gelf_getshdr(sec, &shdr);
506 } 558 }
507 559
508 syms = elf_getdata(sec, NULL); 560 syms = elf_getdata(sec, NULL);
@@ -517,17 +569,34 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
517 if (symstrs == NULL) 569 if (symstrs == NULL)
518 goto out_elf_end; 570 goto out_elf_end;
519 571
572 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
573 if (sec_strndx == NULL)
574 goto out_elf_end;
575
576 secstrs = elf_getdata(sec_strndx, NULL);
577 if (secstrs == NULL)
578 goto out_elf_end;
579
520 nr_syms = shdr.sh_size / shdr.sh_entsize; 580 nr_syms = shdr.sh_size / shdr.sh_entsize;
521 581
522 memset(&sym, 0, sizeof(sym)); 582 memset(&sym, 0, sizeof(sym));
523 self->prelinked = elf_section_by_name(elf, &ehdr, &shdr, 583 if (!kernel) {
524 ".gnu.prelink_undo", 584 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
525 NULL) != NULL; 585 elf_section_by_name(elf, &ehdr, &shdr,
586 ".gnu.prelink_undo",
587 NULL) != NULL);
588 } else self->adjust_symbols = 0;
589
526 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 590 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
527 struct symbol *f; 591 struct symbol *f;
592 const char *name;
593 char *demangled;
528 u64 obj_start; 594 u64 obj_start;
595 struct section *section = NULL;
596 int is_label = elf_sym__is_label(&sym);
597 const char *section_name;
529 598
530 if (!elf_sym__is_function(&sym)) 599 if (!is_label && !elf_sym__is_function(&sym))
531 continue; 600 continue;
532 601
533 sec = elf_getscn(elf, sym.st_shndx); 602 sec = elf_getscn(elf, sym.st_shndx);
@@ -535,9 +604,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
535 goto out_elf_end; 604 goto out_elf_end;
536 605
537 gelf_getshdr(sec, &shdr); 606 gelf_getshdr(sec, &shdr);
607
608 if (is_label && !elf_sec__is_text(&shdr, secstrs))
609 continue;
610
611 section_name = elf_sec__name(&shdr, secstrs);
538 obj_start = sym.st_value; 612 obj_start = sym.st_value;
539 613
540 if (self->prelinked) { 614 if (self->adjust_symbols) {
541 if (verbose >= 2) 615 if (verbose >= 2)
542 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 616 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
543 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 617 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
@@ -545,15 +619,36 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
545 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 619 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
546 } 620 }
547 621
548 f = symbol__new(sym.st_value, sym.st_size, 622 if (mod) {
549 elf_sym__name(&sym, symstrs), 623 section = mod->sections->find_section(mod->sections, section_name);
624 if (section)
625 sym.st_value += section->vma;
626 else {
627 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
628 mod->name, section_name);
629 goto out_elf_end;
630 }
631 }
632 /*
633 * We need to figure out if the object was created from C++ sources
634 * DWARF DW_compile_unit has this, but we don't always have access
635 * to it...
636 */
637 name = elf_sym__name(&sym, symstrs);
638 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
639 if (demangled != NULL)
640 name = demangled;
641
642 f = symbol__new(sym.st_value, sym.st_size, name,
550 self->sym_priv_size, obj_start, verbose); 643 self->sym_priv_size, obj_start, verbose);
644 free(demangled);
551 if (!f) 645 if (!f)
552 goto out_elf_end; 646 goto out_elf_end;
553 647
554 if (filter && filter(self, f)) 648 if (filter && filter(self, f))
555 symbol__delete(f, self->sym_priv_size); 649 symbol__delete(f, self->sym_priv_size);
556 else { 650 else {
651 f->module = mod;
557 dso__insert_symbol(self, f); 652 dso__insert_symbol(self, f);
558 nr++; 653 nr++;
559 } 654 }
@@ -566,10 +661,69 @@ out_close:
566 return err; 661 return err;
567} 662}
568 663
664#define BUILD_ID_SIZE 128
665
666static char *dso__read_build_id(struct dso *self, int verbose)
667{
668 int i;
669 GElf_Ehdr ehdr;
670 GElf_Shdr shdr;
671 Elf_Data *build_id_data;
672 Elf_Scn *sec;
673 char *build_id = NULL, *bid;
674 unsigned char *raw;
675 Elf *elf;
676 int fd = open(self->name, O_RDONLY);
677
678 if (fd < 0)
679 goto out;
680
681 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
682 if (elf == NULL) {
683 if (verbose)
684 fprintf(stderr, "%s: cannot read %s ELF file.\n",
685 __func__, self->name);
686 goto out_close;
687 }
688
689 if (gelf_getehdr(elf, &ehdr) == NULL) {
690 if (verbose)
691 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
692 goto out_elf_end;
693 }
694
695 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
696 if (sec == NULL)
697 goto out_elf_end;
698
699 build_id_data = elf_getdata(sec, NULL);
700 if (build_id_data == NULL)
701 goto out_elf_end;
702 build_id = malloc(BUILD_ID_SIZE);
703 if (build_id == NULL)
704 goto out_elf_end;
705 raw = build_id_data->d_buf + 16;
706 bid = build_id;
707
708 for (i = 0; i < 20; ++i) {
709 sprintf(bid, "%02x", *raw);
710 ++raw;
711 bid += 2;
712 }
713 if (verbose)
714 printf("%s(%s): %s\n", __func__, self->name, build_id);
715out_elf_end:
716 elf_end(elf);
717out_close:
718 close(fd);
719out:
720 return build_id;
721}
722
569int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 723int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
570{ 724{
571 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 725 int size = PATH_MAX;
572 char *name = malloc(size); 726 char *name = malloc(size), *build_id = NULL;
573 int variant = 0; 727 int variant = 0;
574 int ret = -1; 728 int ret = -1;
575 int fd; 729 int fd;
@@ -577,7 +731,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
577 if (!name) 731 if (!name)
578 return -1; 732 return -1;
579 733
580 self->prelinked = 0; 734 self->adjust_symbols = 0;
581 735
582 if (strncmp(self->name, "/tmp/perf-", 10) == 0) 736 if (strncmp(self->name, "/tmp/perf-", 10) == 0)
583 return dso__load_perf_map(self, filter, verbose); 737 return dso__load_perf_map(self, filter, verbose);
@@ -591,7 +745,18 @@ more:
591 case 1: /* Ubuntu */ 745 case 1: /* Ubuntu */
592 snprintf(name, size, "/usr/lib/debug%s", self->name); 746 snprintf(name, size, "/usr/lib/debug%s", self->name);
593 break; 747 break;
594 case 2: /* Sane people */ 748 case 2:
749 build_id = dso__read_build_id(self, verbose);
750 if (build_id != NULL) {
751 snprintf(name, size,
752 "/usr/lib/debug/.build-id/%.2s/%s.debug",
753 build_id, build_id + 2);
754 free(build_id);
755 break;
756 }
757 variant++;
758 /* Fall thru */
759 case 3: /* Sane people */
595 snprintf(name, size, "%s", self->name); 760 snprintf(name, size, "%s", self->name);
596 break; 761 break;
597 762
@@ -603,7 +768,7 @@ more:
603 fd = open(name, O_RDONLY); 768 fd = open(name, O_RDONLY);
604 } while (fd < 0); 769 } while (fd < 0);
605 770
606 ret = dso__load_sym(self, fd, name, filter, verbose); 771 ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
607 close(fd); 772 close(fd);
608 773
609 /* 774 /*
@@ -612,11 +777,96 @@ more:
612 if (!ret) 777 if (!ret)
613 goto more; 778 goto more;
614 779
780 if (ret > 0) {
781 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
782 if (nr_plt > 0)
783 ret += nr_plt;
784 }
615out: 785out:
616 free(name); 786 free(name);
617 return ret; 787 return ret;
618} 788}
619 789
790static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
791 symbol_filter_t filter, int verbose)
792{
793 struct module *mod = mod_dso__find_module(mods, name);
794 int err = 0, fd;
795
796 if (mod == NULL || !mod->active)
797 return err;
798
799 fd = open(mod->path, O_RDONLY);
800
801 if (fd < 0)
802 return err;
803
804 err = dso__load_sym(self, fd, name, filter, verbose, mod);
805 close(fd);
806
807 return err;
808}
809
810int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
811{
812 struct mod_dso *mods = mod_dso__new_dso("modules");
813 struct module *pos;
814 struct rb_node *next;
815 int err;
816
817 err = mod_dso__load_modules(mods);
818
819 if (err <= 0)
820 return err;
821
822 /*
823 * Iterate over modules, and load active symbols.
824 */
825 next = rb_first(&mods->mods);
826 while (next) {
827 pos = rb_entry(next, struct module, rb_node);
828 err = dso__load_module(self, mods, pos->name, filter, verbose);
829
830 if (err < 0)
831 break;
832
833 next = rb_next(&pos->rb_node);
834 }
835
836 if (err < 0) {
837 mod_dso__delete_modules(mods);
838 mod_dso__delete_self(mods);
839 }
840
841 return err;
842}
843
844static inline void dso__fill_symbol_holes(struct dso *self)
845{
846 struct symbol *prev = NULL;
847 struct rb_node *nd;
848
849 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
850 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
851
852 if (prev) {
853 u64 hole = 0;
854 int alias = pos->start == prev->start;
855
856 if (!alias)
857 hole = prev->start - pos->end - 1;
858
859 if (hole || alias) {
860 if (alias)
861 pos->end = prev->end;
862 else if (hole)
863 pos->end = prev->start - 1;
864 }
865 }
866 prev = pos;
867 }
868}
869
620static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 870static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
621 symbol_filter_t filter, int verbose) 871 symbol_filter_t filter, int verbose)
622{ 872{
@@ -625,21 +875,28 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
625 if (fd < 0) 875 if (fd < 0)
626 return -1; 876 return -1;
627 877
628 err = dso__load_sym(self, fd, vmlinux, filter, verbose); 878 err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
879
880 if (err > 0)
881 dso__fill_symbol_holes(self);
882
629 close(fd); 883 close(fd);
630 884
631 return err; 885 return err;
632} 886}
633 887
634int dso__load_kernel(struct dso *self, const char *vmlinux, 888int dso__load_kernel(struct dso *self, const char *vmlinux,
635 symbol_filter_t filter, int verbose) 889 symbol_filter_t filter, int verbose, int modules)
636{ 890{
637 int err = -1; 891 int err = -1;
638 892
639 if (vmlinux) 893 if (vmlinux) {
640 err = dso__load_vmlinux(self, vmlinux, filter, verbose); 894 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
895 if (err > 0 && modules)
896 err = dso__load_modules(self, filter, verbose);
897 }
641 898
642 if (err < 0) 899 if (err <= 0)
643 err = dso__load_kallsyms(self, filter, verbose); 900 err = dso__load_kallsyms(self, filter, verbose);
644 901
645 return err; 902 return err;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 2c48ace8203b..2f92b21c712d 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -3,8 +3,9 @@
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"
8 9
9struct symbol { 10struct symbol {
10 struct rb_node rb_node; 11 struct rb_node rb_node;
@@ -13,6 +14,7 @@ struct symbol {
13 u64 obj_start; 14 u64 obj_start;
14 u64 hist_sum; 15 u64 hist_sum;
15 u64 *hist; 16 u64 *hist;
17 struct module *module;
16 void *priv; 18 void *priv;
17 char name[0]; 19 char name[0];
18}; 20};
@@ -22,7 +24,8 @@ struct dso {
22 struct rb_root syms; 24 struct rb_root syms;
23 struct symbol *(*find_symbol)(struct dso *, u64 ip); 25 struct symbol *(*find_symbol)(struct dso *, u64 ip);
24 unsigned int sym_priv_size; 26 unsigned int sym_priv_size;
25 unsigned char prelinked; 27 unsigned char adjust_symbols;
28 unsigned char slen_calculated;
26 char name[0]; 29 char name[0];
27}; 30};
28 31
@@ -41,7 +44,8 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
41struct symbol *dso__find_symbol(struct dso *self, u64 ip); 44struct symbol *dso__find_symbol(struct dso *self, u64 ip);
42 45
43int dso__load_kernel(struct dso *self, const char *vmlinux, 46int dso__load_kernel(struct dso *self, const char *vmlinux,
44 symbol_filter_t filter, int verbose); 47 symbol_filter_t filter, int verbose, int modules);
48int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
45int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 49int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
46 50
47size_t dso__fprintf(struct dso *self, FILE *fp); 51size_t dso__fprintf(struct dso *self, FILE *fp);
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b4be6071c105..68fe157d72fb 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -50,6 +50,7 @@
50#include <unistd.h> 50#include <unistd.h>
51#include <stdio.h> 51#include <stdio.h>
52#include <sys/stat.h> 52#include <sys/stat.h>
53#include <sys/statfs.h>
53#include <fcntl.h> 54#include <fcntl.h>
54#include <stddef.h> 55#include <stddef.h>
55#include <stdlib.h> 56#include <stdlib.h>
@@ -80,6 +81,7 @@
80#include <netdb.h> 81#include <netdb.h>
81#include <pwd.h> 82#include <pwd.h>
82#include <inttypes.h> 83#include <inttypes.h>
84#include "../../../include/linux/magic.h"
83 85
84#ifndef NO_ICONV 86#ifndef NO_ICONV
85#include <iconv.h> 87#include <iconv.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)