aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/cache.h14
-rw-r--r--tools/perf/util/callchain.c110
-rw-r--r--tools/perf/util/callchain.h6
-rw-r--r--tools/perf/util/color.c5
-rw-r--r--tools/perf/util/debug.c6
-rw-r--r--tools/perf/util/debug.h11
-rw-r--r--tools/perf/util/event.c41
-rw-r--r--tools/perf/util/hist.c77
-rw-r--r--tools/perf/util/hist.h5
-rw-r--r--tools/perf/util/include/linux/compiler.h2
-rw-r--r--tools/perf/util/include/linux/kernel.h9
-rw-r--r--tools/perf/util/map.c95
-rw-r--r--tools/perf/util/map.h52
-rw-r--r--tools/perf/util/newt.c526
-rw-r--r--tools/perf/util/parse-events.c5
-rw-r--r--tools/perf/util/parse-options.c1
-rw-r--r--tools/perf/util/probe-event.c1003
-rw-r--r--tools/perf/util/probe-event.h123
-rw-r--r--tools/perf/util/probe-finder.c467
-rw-r--r--tools/perf/util/probe-finder.h62
-rw-r--r--tools/perf/util/session.c42
-rw-r--r--tools/perf/util/session.h17
-rw-r--r--tools/perf/util/sort.c22
-rw-r--r--tools/perf/util/sort.h3
-rw-r--r--tools/perf/util/string.c43
-rw-r--r--tools/perf/util/string.h2
-rw-r--r--tools/perf/util/symbol.c114
-rw-r--r--tools/perf/util/symbol.h31
-rw-r--r--tools/perf/util/thread.c83
-rw-r--r--tools/perf/util/thread.h49
-rw-r--r--tools/perf/util/util.h9
31 files changed, 2225 insertions, 810 deletions
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 918eb376abe3..4b9aab7f0405 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_CACHE_H 1#ifndef __PERF_CACHE_H
2#define __PERF_CACHE_H 2#define __PERF_CACHE_H
3 3
4#include <stdbool.h>
4#include "util.h" 5#include "util.h"
5#include "strbuf.h" 6#include "strbuf.h"
6#include "../perf.h" 7#include "../perf.h"
@@ -69,6 +70,19 @@ extern const char *pager_program;
69extern int pager_in_use(void); 70extern int pager_in_use(void);
70extern int pager_use_color; 71extern int pager_use_color;
71 72
73extern bool use_browser;
74
75#ifdef NO_NEWT_SUPPORT
76static inline void setup_browser(void)
77{
78 setup_pager();
79}
80static inline void exit_browser(bool wait_for_ok __used) {}
81#else
82void setup_browser(void);
83void exit_browser(bool wait_for_ok);
84#endif
85
72extern const char *editor_program; 86extern const char *editor_program;
73extern const char *excludes_file; 87extern const char *excludes_file;
74 88
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index b3b71258272a..db628af6d20d 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com> 2 * Copyright (C) 2009-2010, Frederic Weisbecker <fweisbec@gmail.com>
3 * 3 *
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.
@@ -183,12 +183,23 @@ create_child(struct callchain_node *parent, bool inherit_children)
183 return new; 183 return new;
184} 184}
185 185
186
187struct resolved_ip {
188 u64 ip;
189 struct map_symbol ms;
190};
191
192struct resolved_chain {
193 u64 nr;
194 struct resolved_ip ips[0];
195};
196
197
186/* 198/*
187 * Fill the node with callchain values 199 * Fill the node with callchain values
188 */ 200 */
189static void 201static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain, 202fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
191 int start, struct symbol **syms)
192{ 203{
193 unsigned int i; 204 unsigned int i;
194 205
@@ -200,8 +211,8 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
200 perror("not enough memory for the code path tree"); 211 perror("not enough memory for the code path tree");
201 return; 212 return;
202 } 213 }
203 call->ip = chain->ips[i]; 214 call->ip = chain->ips[i].ip;
204 call->sym = syms[i]; 215 call->ms = chain->ips[i].ms;
205 list_add_tail(&call->list, &node->val); 216 list_add_tail(&call->list, &node->val);
206 } 217 }
207 node->val_nr = chain->nr - start; 218 node->val_nr = chain->nr - start;
@@ -210,13 +221,13 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
210} 221}
211 222
212static void 223static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain, 224add_child(struct callchain_node *parent, struct resolved_chain *chain,
214 int start, struct symbol **syms) 225 int start)
215{ 226{
216 struct callchain_node *new; 227 struct callchain_node *new;
217 228
218 new = create_child(parent, false); 229 new = create_child(parent, false);
219 fill_node(new, chain, start, syms); 230 fill_node(new, chain, start);
220 231
221 new->children_hit = 0; 232 new->children_hit = 0;
222 new->hit = 1; 233 new->hit = 1;
@@ -228,9 +239,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
228 * Then create another child to host the given callchain of new branch 239 * Then create another child to host the given callchain of new branch
229 */ 240 */
230static void 241static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain, 242split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local, 243 struct callchain_list *to_split, int idx_parents, int idx_local)
233 struct symbol **syms)
234{ 244{
235 struct callchain_node *new; 245 struct callchain_node *new;
236 struct list_head *old_tail; 246 struct list_head *old_tail;
@@ -257,7 +267,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
257 /* create a new child for the new branch if any */ 267 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) { 268 if (idx_total < chain->nr) {
259 parent->hit = 0; 269 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms); 270 add_child(parent, chain, idx_total);
261 parent->children_hit++; 271 parent->children_hit++;
262 } else { 272 } else {
263 parent->hit = 1; 273 parent->hit = 1;
@@ -265,32 +275,33 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
265} 275}
266 276
267static int 277static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain, 278__append_chain(struct callchain_node *root, struct resolved_chain *chain,
269 unsigned int start, struct symbol **syms); 279 unsigned int start);
270 280
271static void 281static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain, 282__append_chain_children(struct callchain_node *root,
273 struct symbol **syms, unsigned int start) 283 struct resolved_chain *chain,
284 unsigned int start)
274{ 285{
275 struct callchain_node *rnode; 286 struct callchain_node *rnode;
276 287
277 /* lookup in childrens */ 288 /* lookup in childrens */
278 chain_for_each_child(rnode, root) { 289 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms); 290 unsigned int ret = __append_chain(rnode, chain, start);
280 291
281 if (!ret) 292 if (!ret)
282 goto inc_children_hit; 293 goto inc_children_hit;
283 } 294 }
284 /* nothing in children, add to the current node */ 295 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms); 296 add_child(root, chain, start);
286 297
287inc_children_hit: 298inc_children_hit:
288 root->children_hit++; 299 root->children_hit++;
289} 300}
290 301
291static int 302static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain, 303__append_chain(struct callchain_node *root, struct resolved_chain *chain,
293 unsigned int start, struct symbol **syms) 304 unsigned int start)
294{ 305{
295 struct callchain_list *cnode; 306 struct callchain_list *cnode;
296 unsigned int i = start; 307 unsigned int i = start;
@@ -302,13 +313,19 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
302 * anywhere inside a function. 313 * anywhere inside a function.
303 */ 314 */
304 list_for_each_entry(cnode, &root->val, list) { 315 list_for_each_entry(cnode, &root->val, list) {
316 struct symbol *sym;
317
305 if (i == chain->nr) 318 if (i == chain->nr)
306 break; 319 break;
307 if (cnode->sym && syms[i]) { 320
308 if (cnode->sym->start != syms[i]->start) 321 sym = chain->ips[i].ms.sym;
322
323 if (cnode->ms.sym && sym) {
324 if (cnode->ms.sym->start != sym->start)
309 break; 325 break;
310 } else if (cnode->ip != chain->ips[i]) 326 } else if (cnode->ip != chain->ips[i].ip)
311 break; 327 break;
328
312 if (!found) 329 if (!found)
313 found = true; 330 found = true;
314 i++; 331 i++;
@@ -320,7 +337,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
320 337
321 /* we match only a part of the node. Split it and add the new chain */ 338 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) { 339 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms); 340 split_add_child(root, chain, cnode, start, i - start);
324 return 0; 341 return 0;
325 } 342 }
326 343
@@ -331,15 +348,50 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
331 } 348 }
332 349
333 /* We match the node and still have a part remaining */ 350 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i); 351 __append_chain_children(root, chain, i);
335 352
336 return 0; 353 return 0;
337} 354}
338 355
339void append_chain(struct callchain_node *root, struct ip_callchain *chain, 356static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
340 struct symbol **syms) 357 struct map_symbol *syms)
358{
359 int i, j = 0;
360
361 for (i = 0; i < (int)old->nr; i++) {
362 if (old->ips[i] >= PERF_CONTEXT_MAX)
363 continue;
364
365 new->ips[j].ip = old->ips[i];
366 new->ips[j].ms = syms[i];
367 j++;
368 }
369
370 new->nr = j;
371}
372
373
374int append_chain(struct callchain_node *root, struct ip_callchain *chain,
375 struct map_symbol *syms)
341{ 376{
377 struct resolved_chain *filtered;
378
342 if (!chain->nr) 379 if (!chain->nr)
343 return; 380 return 0;
344 __append_chain_children(root, chain, syms, 0); 381
382 filtered = malloc(sizeof(*filtered) +
383 chain->nr * sizeof(struct resolved_ip));
384 if (!filtered)
385 return -ENOMEM;
386
387 filter_context(chain, filtered, syms);
388
389 if (!filtered->nr)
390 goto end;
391
392 __append_chain_children(root, filtered, 0);
393end:
394 free(filtered);
395
396 return 0;
345} 397}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index ad4626de4c2b..8a7e8bbd0fda 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -39,7 +39,7 @@ struct callchain_param {
39 39
40struct callchain_list { 40struct callchain_list {
41 u64 ip; 41 u64 ip;
42 struct symbol *sym; 42 struct map_symbol ms;
43 struct list_head list; 43 struct list_head list;
44}; 44};
45 45
@@ -56,6 +56,6 @@ static inline u64 cumul_hits(struct callchain_node *node)
56} 56}
57 57
58int register_callchain_param(struct callchain_param *param); 58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 59int append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 60 struct map_symbol *syms);
61#endif /* __PERF_CALLCHAIN_H */ 61#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e88bca55a599..9da01914e0af 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -203,7 +203,10 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
203 int r; 203 int r;
204 204
205 va_start(args, fmt); 205 va_start(args, fmt);
206 r = color_vfprintf(fp, color, fmt, args); 206 if (use_browser)
207 r = vfprintf(fp, fmt, args);
208 else
209 r = color_vfprintf(fp, color, fmt, args);
207 va_end(args); 210 va_end(args);
208 return r; 211 return r;
209} 212}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 0905600c3851..033d66db863a 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -6,6 +6,7 @@
6#include <stdarg.h> 6#include <stdarg.h>
7#include <stdio.h> 7#include <stdio.h>
8 8
9#include "cache.h"
9#include "color.h" 10#include "color.h"
10#include "event.h" 11#include "event.h"
11#include "debug.h" 12#include "debug.h"
@@ -21,7 +22,10 @@ int eprintf(int level, const char *fmt, ...)
21 22
22 if (verbose >= level) { 23 if (verbose >= level) {
23 va_start(args, fmt); 24 va_start(args, fmt);
24 ret = vfprintf(stderr, fmt, args); 25 if (use_browser)
26 ret = browser__show_help(fmt, args);
27 else
28 ret = vfprintf(stderr, fmt, args);
25 va_end(args); 29 va_end(args);
26 } 30 }
27 31
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index c6c24c522dea..0172edf3f153 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -7,9 +7,16 @@
7extern int verbose; 7extern int verbose;
8extern int dump_trace; 8extern int dump_trace;
9 9
10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(event_t *event); 11void trace_event(event_t *event);
14 12
13#ifdef NO_NEWT_SUPPORT
14static inline int browser__show_help(const char *format __used, va_list ap __used)
15{
16 return 0;
17}
18#else
19int browser__show_help(const char *format, va_list ap);
20#endif
21
15#endif /* __PERF_DEBUG_H */ 22#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 705ec63548b4..052eaeccc202 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -393,7 +393,8 @@ int event__process_mmap(event_t *self, struct perf_session *session)
393 } 393 }
394 394
395 thread = perf_session__findnew(session, self->mmap.pid); 395 thread = perf_session__findnew(session, self->mmap.pid);
396 map = map__new(&self->mmap, MAP__FUNCTION, 396 map = map__new(self->mmap.start, self->mmap.len, self->mmap.pgoff,
397 self->mmap.pid, self->mmap.filename, MAP__FUNCTION,
397 session->cwd, session->cwdlen); 398 session->cwd, session->cwdlen);
398 399
399 if (thread == NULL || map == NULL) 400 if (thread == NULL || map == NULL)
@@ -513,24 +514,32 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
513 514
514 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 515 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
515 516
516 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, 517 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
517 self->ip.ip, al, filter); 518 self->ip.ip, al);
518 dump_printf(" ...... dso: %s\n", 519 dump_printf(" ...... dso: %s\n",
519 al->map ? al->map->dso->long_name : 520 al->map ? al->map->dso->long_name :
520 al->level == 'H' ? "[hypervisor]" : "<not found>"); 521 al->level == 'H' ? "[hypervisor]" : "<not found>");
521 /* 522 al->sym = NULL;
522 * We have to do this here as we may have a dso with no symbol hit that 523
523 * has a name longer than the ones with symbols sampled. 524 if (al->map) {
524 */ 525 if (symbol_conf.dso_list &&
525 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated) 526 (!al->map || !al->map->dso ||
526 dso__calc_col_width(al->map->dso); 527 !(strlist__has_entry(symbol_conf.dso_list,
527 528 al->map->dso->short_name) ||
528 if (symbol_conf.dso_list && 529 (al->map->dso->short_name != al->map->dso->long_name &&
529 (!al->map || !al->map->dso || 530 strlist__has_entry(symbol_conf.dso_list,
530 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) || 531 al->map->dso->long_name)))))
531 (al->map->dso->short_name != al->map->dso->long_name && 532 goto out_filtered;
532 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name))))) 533 /*
533 goto out_filtered; 534 * We have to do this here as we may have a dso with no symbol
535 * hit that has a name longer than the ones with symbols
536 * sampled.
537 */
538 if (!sort_dso.elide && !al->map->dso->slen_calculated)
539 dso__calc_col_width(al->map->dso);
540
541 al->sym = map__find_symbol(al->map, al->addr, filter);
542 }
534 543
535 if (symbol_conf.sym_list && al->sym && 544 if (symbol_conf.sym_list && al->sym &&
536 !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) 545 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 2be33c7dbf03..09e09e78cb62 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -22,8 +22,10 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
22 struct hist_entry *he; 22 struct hist_entry *he;
23 struct hist_entry entry = { 23 struct hist_entry entry = {
24 .thread = al->thread, 24 .thread = al->thread,
25 .map = al->map, 25 .ms = {
26 .sym = al->sym, 26 .map = al->map,
27 .sym = al->sym,
28 },
27 .ip = al->addr, 29 .ip = al->addr,
28 .level = al->level, 30 .level = al->level,
29 .count = count, 31 .count = count,
@@ -258,8 +260,8 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
258 } else 260 } else
259 ret += fprintf(fp, "%s", " "); 261 ret += fprintf(fp, "%s", " ");
260 } 262 }
261 if (chain->sym) 263 if (chain->ms.sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name); 264 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
263 else 265 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 266 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265 267
@@ -278,7 +280,7 @@ static void init_rem_hits(void)
278 } 280 }
279 281
280 strcpy(rem_sq_bracket->name, "[...]"); 282 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket; 283 rem_hits.ms.sym = rem_sq_bracket;
282} 284}
283 285
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 286static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
@@ -328,8 +330,6 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
328 left_margin); 330 left_margin);
329 i = 0; 331 i = 0;
330 list_for_each_entry(chain, &child->val, list) { 332 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth, 333 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++, 334 new_depth_mask, i++,
335 new_total, 335 new_total,
@@ -368,9 +368,6 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
368 int ret = 0; 368 int ret = 0;
369 369
370 list_for_each_entry(chain, &self->val, list) { 370 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM) 371 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue; 372 continue;
376 373
@@ -385,8 +382,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
385 } else 382 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin); 383 ret += callchain__fprintf_left_margin(fp, left_margin);
387 384
388 if (chain->sym) 385 if (chain->ms.sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name); 386 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
390 else 387 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 388 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
392 } 389 }
@@ -411,8 +408,8 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
411 list_for_each_entry(chain, &self->val, list) { 408 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX) 409 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue; 410 continue;
414 if (chain->sym) 411 if (chain->ms.sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name); 412 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
416 else 413 else
417 ret += fprintf(fp, " %p\n", 414 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip); 415 (void *)(long)chain->ip);
@@ -455,11 +452,11 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
455 return ret; 452 return ret;
456} 453}
457 454
458static size_t hist_entry__fprintf(struct hist_entry *self, 455size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *pair_session, 456 struct perf_session *pair_session,
460 bool show_displacement, 457 bool show_displacement,
461 long displacement, FILE *fp, 458 long displacement, FILE *fp,
462 u64 session_total) 459 u64 session_total)
463{ 460{
464 struct sort_entry *se; 461 struct sort_entry *se;
465 u64 count, total; 462 u64 count, total;
@@ -485,9 +482,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
485 482
486 if (symbol_conf.show_nr_samples) { 483 if (symbol_conf.show_nr_samples) {
487 if (sep) 484 if (sep)
488 fprintf(fp, "%c%lld", *sep, count); 485 ret += fprintf(fp, "%c%lld", *sep, count);
489 else 486 else
490 fprintf(fp, "%11lld", count); 487 ret += fprintf(fp, "%11lld", count);
491 } 488 }
492 489
493 if (pair_session) { 490 if (pair_session) {
@@ -518,9 +515,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
518 snprintf(bf, sizeof(bf), " "); 515 snprintf(bf, sizeof(bf), " ");
519 516
520 if (sep) 517 if (sep)
521 fprintf(fp, "%c%s", *sep, bf); 518 ret += fprintf(fp, "%c%s", *sep, bf);
522 else 519 else
523 fprintf(fp, "%6.6s", bf); 520 ret += fprintf(fp, "%6.6s", bf);
524 } 521 }
525 } 522 }
526 523
@@ -528,27 +525,27 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
528 if (se->elide) 525 if (se->elide)
529 continue; 526 continue;
530 527
531 fprintf(fp, "%s", sep ?: " "); 528 ret += fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0); 529 ret += se->print(fp, self, se->width ? *se->width : 0);
533 } 530 }
534 531
535 ret += fprintf(fp, "\n"); 532 return ret + fprintf(fp, "\n");
536 533}
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539 534
540 if (sort__first_dimension == SORT_COMM) { 535static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se), 536 u64 session_total)
542 list); 537{
543 left_margin = se->width ? *se->width : 0; 538 int left_margin = 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546 539
547 hist_entry_callchain__fprintf(fp, self, session_total, 540 if (sort__first_dimension == SORT_COMM) {
548 left_margin); 541 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
542 typeof(*se), list);
543 left_margin = se->width ? *se->width : 0;
544 left_margin -= thread__comm_len(self->thread);
549 } 545 }
550 546
551 return ret; 547 return hist_entry_callchain__fprintf(fp, self, session_total,
548 left_margin);
552} 549}
553 550
554size_t perf_session__fprintf_hists(struct rb_root *hists, 551size_t perf_session__fprintf_hists(struct rb_root *hists,
@@ -655,7 +652,11 @@ print_entries:
655 } 652 }
656 ret += hist_entry__fprintf(h, pair, show_displacement, 653 ret += hist_entry__fprintf(h, pair, show_displacement,
657 displacement, fp, session_total); 654 displacement, fp, session_total);
658 if (h->map == NULL && verbose > 1) { 655
656 if (symbol_conf.use_callchain)
657 ret += hist_entry__fprintf_callchain(h, fp, session_total);
658
659 if (h->ms.map == NULL && verbose > 1) {
659 __map_groups__fprintf_maps(&h->thread->mg, 660 __map_groups__fprintf_maps(&h->thread->mg,
660 MAP__FUNCTION, fp); 661 MAP__FUNCTION, fp);
661 fprintf(fp, "%.10s end\n", graph_dotted_line); 662 fprintf(fp, "%.10s end\n", graph_dotted_line);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 16f360cce5bf..fe366ce5db45 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -18,6 +18,11 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
18 u64 count, bool *hit); 18 u64 count, bool *hit);
19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
21size_t hist_entry__fprintf(struct hist_entry *self,
22 struct perf_session *pair_session,
23 bool show_displacement,
24 long displacement, FILE *fp,
25 u64 session_total);
21void hist_entry__free(struct hist_entry *); 26void hist_entry__free(struct hist_entry *);
22 27
23void perf_session__output_resort(struct rb_root *hists, u64 total_samples); 28void perf_session__output_resort(struct rb_root *hists, u64 total_samples);
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index dfb0713ed47f..791f9dd27ebf 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -7,4 +7,6 @@
7#define __user 7#define __user
8#define __attribute_const__ 8#define __attribute_const__
9 9
10#define __used __attribute__((__unused__))
11
10#endif 12#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index f2611655ab51..388ab1bfd114 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -85,16 +85,19 @@ simple_strtoul(const char *nptr, char **endptr, int base)
85 return strtoul(nptr, endptr, base); 85 return strtoul(nptr, endptr, base);
86} 86}
87 87
88int eprintf(int level,
89 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
90
88#ifndef pr_fmt 91#ifndef pr_fmt
89#define pr_fmt(fmt) fmt 92#define pr_fmt(fmt) fmt
90#endif 93#endif
91 94
92#define pr_err(fmt, ...) \ 95#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 96 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
94#define pr_warning(fmt, ...) \ 97#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 98 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
96#define pr_info(fmt, ...) \ 99#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 100 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
98#define pr_debug(fmt, ...) \ 101#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) 102 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \ 103#define pr_debugN(n, fmt, ...) \
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index e509cd59c67d..9f2963f9ee9a 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -1,9 +1,9 @@
1#include "event.h"
2#include "symbol.h" 1#include "symbol.h"
2#include <limits.h>
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h" 6#include "map.h"
7 7
8const char *map_type__name[MAP__NR_TYPES] = { 8const char *map_type__name[MAP__NR_TYPES] = {
9 [MAP__FUNCTION] = "Functions", 9 [MAP__FUNCTION] = "Functions",
@@ -38,13 +38,12 @@ void map__init(struct map *self, enum map_type type,
38 RB_CLEAR_NODE(&self->rb_node); 38 RB_CLEAR_NODE(&self->rb_node);
39} 39}
40 40
41struct map *map__new(struct mmap_event *event, enum map_type type, 41struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename,
42 char *cwd, int cwdlen) 42 enum map_type type, char *cwd, int cwdlen)
43{ 43{
44 struct map *self = malloc(sizeof(*self)); 44 struct map *self = malloc(sizeof(*self));
45 45
46 if (self != NULL) { 46 if (self != NULL) {
47 const char *filename = event->filename;
48 char newfilename[PATH_MAX]; 47 char newfilename[PATH_MAX];
49 struct dso *dso; 48 struct dso *dso;
50 int anon; 49 int anon;
@@ -62,7 +61,7 @@ struct map *map__new(struct mmap_event *event, enum map_type type,
62 anon = is_anon_memory(filename); 61 anon = is_anon_memory(filename);
63 62
64 if (anon) { 63 if (anon) {
65 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); 64 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
66 filename = newfilename; 65 filename = newfilename;
67 } 66 }
68 67
@@ -70,8 +69,7 @@ struct map *map__new(struct mmap_event *event, enum map_type type,
70 if (dso == NULL) 69 if (dso == NULL)
71 goto out_delete; 70 goto out_delete;
72 71
73 map__init(self, type, event->start, event->start + event->len, 72 map__init(self, type, start, start + len, pgoff, dso);
74 event->pgoff, dso);
75 73
76 if (anon) { 74 if (anon) {
77set_identity: 75set_identity:
@@ -235,3 +233,84 @@ u64 map__objdump_2ip(struct map *map, u64 addr)
235 map->unmap_ip(map, addr); /* RIP -> IP */ 233 map->unmap_ip(map, addr); /* RIP -> IP */
236 return ip; 234 return ip;
237} 235}
236
237struct symbol *map_groups__find_symbol(struct map_groups *self,
238 enum map_type type, u64 addr,
239 symbol_filter_t filter)
240{
241 struct map *map = map_groups__find(self, type, addr);
242
243 if (map != NULL)
244 return map__find_symbol(map, map->map_ip(map, addr), filter);
245
246 return NULL;
247}
248
249static u64 map__reloc_map_ip(struct map *map, u64 ip)
250{
251 return ip + (s64)map->pgoff;
252}
253
254static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
255{
256 return ip - (s64)map->pgoff;
257}
258
259void map__reloc_vmlinux(struct map *self)
260{
261 struct kmap *kmap = map__kmap(self);
262 s64 reloc;
263
264 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
265 return;
266
267 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
268 kmap->ref_reloc_sym->addr);
269
270 if (!reloc)
271 return;
272
273 self->map_ip = map__reloc_map_ip;
274 self->unmap_ip = map__reloc_unmap_ip;
275 self->pgoff = reloc;
276}
277
278void maps__insert(struct rb_root *maps, struct map *map)
279{
280 struct rb_node **p = &maps->rb_node;
281 struct rb_node *parent = NULL;
282 const u64 ip = map->start;
283 struct map *m;
284
285 while (*p != NULL) {
286 parent = *p;
287 m = rb_entry(parent, struct map, rb_node);
288 if (ip < m->start)
289 p = &(*p)->rb_left;
290 else
291 p = &(*p)->rb_right;
292 }
293
294 rb_link_node(&map->rb_node, parent, p);
295 rb_insert_color(&map->rb_node, maps);
296}
297
298struct map *maps__find(struct rb_root *maps, u64 ip)
299{
300 struct rb_node **p = &maps->rb_node;
301 struct rb_node *parent = NULL;
302 struct map *m;
303
304 while (*p != NULL) {
305 parent = *p;
306 m = rb_entry(parent, struct map, rb_node);
307 if (ip < m->start)
308 p = &(*p)->rb_left;
309 else if (ip > m->end)
310 p = &(*p)->rb_right;
311 else
312 return m;
313 }
314
315 return NULL;
316}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index b756368076c6..6a703fa74707 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -4,7 +4,8 @@
4#include <linux/compiler.h> 4#include <linux/compiler.h>
5#include <linux/list.h> 5#include <linux/list.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include <linux/types.h> 7#include <stdio.h>
8#include "types.h"
8 9
9enum map_type { 10enum map_type {
10 MAP__FUNCTION = 0, 11 MAP__FUNCTION = 0,
@@ -68,14 +69,13 @@ u64 map__rip_2objdump(struct map *map, u64 rip);
68u64 map__objdump_2ip(struct map *map, u64 addr); 69u64 map__objdump_2ip(struct map *map, u64 addr);
69 70
70struct symbol; 71struct symbol;
71struct mmap_event;
72 72
73typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 73typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
74 74
75void map__init(struct map *self, enum map_type type, 75void map__init(struct map *self, enum map_type type,
76 u64 start, u64 end, u64 pgoff, struct dso *dso); 76 u64 start, u64 end, u64 pgoff, struct dso *dso);
77struct map *map__new(struct mmap_event *event, enum map_type, 77struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename,
78 char *cwd, int cwdlen); 78 enum map_type type, char *cwd, int cwdlen);
79void map__delete(struct map *self); 79void map__delete(struct map *self);
80struct map *map__clone(struct map *self); 80struct map *map__clone(struct map *self);
81int map__overlap(struct map *l, struct map *r); 81int map__overlap(struct map *l, struct map *r);
@@ -91,4 +91,48 @@ void map__fixup_end(struct map *self);
91 91
92void map__reloc_vmlinux(struct map *self); 92void map__reloc_vmlinux(struct map *self);
93 93
94struct map_groups {
95 struct rb_root maps[MAP__NR_TYPES];
96 struct list_head removed_maps[MAP__NR_TYPES];
97};
98
99size_t __map_groups__fprintf_maps(struct map_groups *self,
100 enum map_type type, FILE *fp);
101void maps__insert(struct rb_root *maps, struct map *map);
102struct map *maps__find(struct rb_root *maps, u64 addr);
103void map_groups__init(struct map_groups *self);
104size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
105
106static inline void map_groups__insert(struct map_groups *self, struct map *map)
107{
108 maps__insert(&self->maps[map->type], map);
109}
110
111static inline struct map *map_groups__find(struct map_groups *self,
112 enum map_type type, u64 addr)
113{
114 return maps__find(&self->maps[type], addr);
115}
116
117struct symbol *map_groups__find_symbol(struct map_groups *self,
118 enum map_type type, u64 addr,
119 symbol_filter_t filter);
120
121static inline struct symbol *map_groups__find_function(struct map_groups *self,
122 u64 addr,
123 symbol_filter_t filter)
124{
125 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
126}
127
128struct map *map_groups__find_by_name(struct map_groups *self,
129 enum map_type type, const char *name);
130int __map_groups__create_kernel_maps(struct map_groups *self,
131 struct map *vmlinux_maps[MAP__NR_TYPES],
132 struct dso *kernel);
133int map_groups__create_kernel_maps(struct map_groups *self,
134 struct map *vmlinux_maps[MAP__NR_TYPES]);
135struct map *map_groups__new_module(struct map_groups *self, u64 start,
136 const char *filename);
137
94#endif /* __PERF_MAP_H */ 138#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
new file mode 100644
index 000000000000..e99bcc8d1939
--- /dev/null
+++ b/tools/perf/util/newt.c
@@ -0,0 +1,526 @@
1#define _GNU_SOURCE
2#include <stdio.h>
3#undef _GNU_SOURCE
4
5#include <stdlib.h>
6#include <newt.h>
7#include <sys/ttydefaults.h>
8
9#include "cache.h"
10#include "hist.h"
11#include "session.h"
12#include "sort.h"
13#include "symbol.h"
14
15static void newt_form__set_exit_keys(newtComponent self)
16{
17 newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
18 newtFormAddHotKey(self, 'Q');
19 newtFormAddHotKey(self, 'q');
20 newtFormAddHotKey(self, CTRL('c'));
21}
22
23static newtComponent newt_form__new(void)
24{
25 newtComponent self = newtForm(NULL, NULL, 0);
26 if (self)
27 newt_form__set_exit_keys(self);
28 return self;
29}
30
31static int popup_menu(int argc, const char *argv[])
32{
33 struct newtExitStruct es;
34 int i, rc = -1, max_len = 5;
35 newtComponent listbox, form = newt_form__new();
36
37 if (form == NULL)
38 return -1;
39
40 listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT);
41 if (listbox == NULL)
42 goto out_destroy_form;
43
44 newtFormAddComponents(form, listbox, NULL);
45
46 for (i = 0; i < argc; ++i) {
47 int len = strlen(argv[i]);
48 if (len > max_len)
49 max_len = len;
50 if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i))
51 goto out_destroy_form;
52 }
53
54 newtCenteredWindow(max_len, argc, NULL);
55 newtFormRun(form, &es);
56 rc = newtListboxGetCurrent(listbox) - NULL;
57 if (es.reason == NEWT_EXIT_HOTKEY)
58 rc = -1;
59 newtPopWindow();
60out_destroy_form:
61 newtFormDestroy(form);
62 return rc;
63}
64
65static bool dialog_yesno(const char *msg)
66{
67 /* newtWinChoice should really be accepting const char pointers... */
68 char yes[] = "Yes", no[] = "No";
69 return newtWinChoice(NULL, no, yes, (char *)msg) == 2;
70}
71
72/*
73 * When debugging newt problems it was useful to be able to "unroll"
74 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
75 * a source file with the sequence of calls to these methods, to then
76 * tweak the arrays to get the intended results, so I'm keeping this code
77 * here, may be useful again in the future.
78 */
79#undef NEWT_DEBUG
80
81static void newt_checkbox_tree__add(newtComponent tree, const char *str,
82 void *priv, int *indexes)
83{
84#ifdef NEWT_DEBUG
85 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
86 int i = 0, len = 40 - strlen(str);
87
88 fprintf(stderr,
89 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
90 len, len, " ", str, priv);
91 while (indexes[i] != NEWT_ARG_LAST) {
92 if (indexes[i] != NEWT_ARG_APPEND)
93 fprintf(stderr, " %d,", indexes[i]);
94 else
95 fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
96 ++i;
97 }
98 fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
99 fflush(stderr);
100#endif
101 newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
102}
103
104static char *callchain_list__sym_name(struct callchain_list *self,
105 char *bf, size_t bfsize)
106{
107 if (self->ms.sym)
108 return self->ms.sym->name;
109
110 snprintf(bf, bfsize, "%#Lx", self->ip);
111 return bf;
112}
113
114static void __callchain__append_graph_browser(struct callchain_node *self,
115 newtComponent tree, u64 total,
116 int *indexes, int depth)
117{
118 struct rb_node *node;
119 u64 new_total, remaining;
120 int idx = 0;
121
122 if (callchain_param.mode == CHAIN_GRAPH_REL)
123 new_total = self->children_hit;
124 else
125 new_total = total;
126
127 remaining = new_total;
128 node = rb_first(&self->rb_root);
129 while (node) {
130 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
131 struct rb_node *next = rb_next(node);
132 u64 cumul = cumul_hits(child);
133 struct callchain_list *chain;
134 int first = true, printed = 0;
135 int chain_idx = -1;
136 remaining -= cumul;
137
138 indexes[depth] = NEWT_ARG_APPEND;
139 indexes[depth + 1] = NEWT_ARG_LAST;
140
141 list_for_each_entry(chain, &child->val, list) {
142 char ipstr[BITS_PER_LONG / 4 + 1],
143 *alloc_str = NULL;
144 const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
145
146 if (first) {
147 double percent = cumul * 100.0 / new_total;
148
149 first = false;
150 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
151 str = "Not enough memory!";
152 else
153 str = alloc_str;
154 } else {
155 indexes[depth] = idx;
156 indexes[depth + 1] = NEWT_ARG_APPEND;
157 indexes[depth + 2] = NEWT_ARG_LAST;
158 ++chain_idx;
159 }
160 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
161 free(alloc_str);
162 ++printed;
163 }
164
165 indexes[depth] = idx;
166 if (chain_idx != -1)
167 indexes[depth + 1] = chain_idx;
168 if (printed != 0)
169 ++idx;
170 __callchain__append_graph_browser(child, tree, new_total, indexes,
171 depth + (chain_idx != -1 ? 2 : 1));
172 node = next;
173 }
174}
175
176static void callchain__append_graph_browser(struct callchain_node *self,
177 newtComponent tree, u64 total,
178 int *indexes, int parent_idx)
179{
180 struct callchain_list *chain;
181 int i = 0;
182
183 indexes[1] = NEWT_ARG_APPEND;
184 indexes[2] = NEWT_ARG_LAST;
185
186 list_for_each_entry(chain, &self->val, list) {
187 char ipstr[BITS_PER_LONG / 4 + 1], *str;
188
189 if (chain->ip >= PERF_CONTEXT_MAX)
190 continue;
191
192 if (!i++ && sort__first_dimension == SORT_SYM)
193 continue;
194
195 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
196 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
197 }
198
199 indexes[1] = parent_idx;
200 indexes[2] = NEWT_ARG_APPEND;
201 indexes[3] = NEWT_ARG_LAST;
202 __callchain__append_graph_browser(self, tree, total, indexes, 2);
203}
204
205static void hist_entry__append_callchain_browser(struct hist_entry *self,
206 newtComponent tree, u64 total, int parent_idx)
207{
208 struct rb_node *rb_node;
209 int indexes[1024] = { [0] = parent_idx, };
210 int idx = 0;
211 struct callchain_node *chain;
212
213 rb_node = rb_first(&self->sorted_chain);
214 while (rb_node) {
215 chain = rb_entry(rb_node, struct callchain_node, rb_node);
216 switch (callchain_param.mode) {
217 case CHAIN_FLAT:
218 break;
219 case CHAIN_GRAPH_ABS: /* falldown */
220 case CHAIN_GRAPH_REL:
221 callchain__append_graph_browser(chain, tree, total, indexes, idx++);
222 break;
223 case CHAIN_NONE:
224 default:
225 break;
226 }
227 rb_node = rb_next(rb_node);
228 }
229}
230
231/*
232 * FIXME: get lib/string.c linked with perf somehow
233 */
234static char *skip_spaces(const char *str)
235{
236 while (isspace(*str))
237 ++str;
238 return (char *)str;
239}
240
241static char *strim(char *s)
242{
243 size_t size;
244 char *end;
245
246 s = skip_spaces(s);
247 size = strlen(s);
248 if (!size)
249 return s;
250
251 end = s + size - 1;
252 while (end >= s && isspace(*end))
253 end--;
254 *(end + 1) = '\0';
255
256 return s;
257}
258
259static size_t hist_entry__append_browser(struct hist_entry *self,
260 newtComponent tree, u64 total)
261{
262 char bf[1024], *s;
263 FILE *fp;
264
265 if (symbol_conf.exclude_other && !self->parent)
266 return 0;
267
268 fp = fmemopen(bf, sizeof(bf), "w");
269 if (fp == NULL)
270 return 0;
271
272 hist_entry__fprintf(self, NULL, false, 0, fp, total);
273 fclose(fp);
274
275 /*
276 * FIXME: We shouldn't need to trim, as the printing routines shouldn't
277 * add spaces it in the first place, the stdio output routines should
278 * call a __snprintf method instead of the current __print (that
279 * actually is a __fprintf) one, but get the raw string and _then_ add
280 * the newline, as this is a detail of stdio printing, not needed in
281 * other UIs, e.g. newt.
282 */
283 s = strim(bf);
284
285 if (symbol_conf.use_callchain) {
286 int indexes[2];
287
288 indexes[0] = NEWT_ARG_APPEND;
289 indexes[1] = NEWT_ARG_LAST;
290 newt_checkbox_tree__add(tree, s, &self->ms, indexes);
291 } else
292 newtListboxAppendEntry(tree, s, &self->ms);
293
294 return strlen(s);
295}
296
297static void map_symbol__annotate_browser(const struct map_symbol *self)
298{
299 FILE *fp;
300 int cols, rows;
301 newtComponent form, tree;
302 struct newtExitStruct es;
303 char *str;
304 size_t line_len, max_line_len = 0;
305 size_t max_usable_width;
306 char *line = NULL;
307
308 if (self->sym == NULL)
309 return;
310
311 if (asprintf(&str, "perf annotate -d \"%s\" %s 2>&1 | expand",
312 self->map->dso->name, self->sym->name) < 0)
313 return;
314
315 fp = popen(str, "r");
316 if (fp == NULL)
317 goto out_free_str;
318
319 newtPushHelpLine("Press ESC to exit");
320 newtGetScreenSize(&cols, &rows);
321 tree = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);
322
323 while (!feof(fp)) {
324 if (getline(&line, &line_len, fp) < 0 || !line_len)
325 break;
326 while (line_len != 0 && isspace(line[line_len - 1]))
327 line[--line_len] = '\0';
328
329 if (line_len > max_line_len)
330 max_line_len = line_len;
331 newtListboxAppendEntry(tree, line, NULL);
332 }
333 fclose(fp);
334 free(line);
335
336 max_usable_width = cols - 22;
337 if (max_line_len > max_usable_width)
338 max_line_len = max_usable_width;
339
340 newtListboxSetWidth(tree, max_line_len);
341
342 newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name);
343 form = newt_form__new();
344 newtFormAddComponents(form, tree, NULL);
345
346 newtFormRun(form, &es);
347 newtFormDestroy(form);
348 newtPopWindow();
349 newtPopHelpLine();
350out_free_str:
351 free(str);
352}
353
354static const void *newt__symbol_tree_get_current(newtComponent self)
355{
356 if (symbol_conf.use_callchain)
357 return newtCheckboxTreeGetCurrent(self);
358 return newtListboxGetCurrent(self);
359}
360
361static void perf_session__selection(newtComponent self, void *data)
362{
363 const struct map_symbol **symbol_ptr = data;
364 *symbol_ptr = newt__symbol_tree_get_current(self);
365}
366
367void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
368 const char *helpline)
369{
370 struct sort_entry *se;
371 struct rb_node *nd;
372 char seq[] = ".";
373 unsigned int width;
374 char *col_width = symbol_conf.col_width_list_str;
375 int rows, cols, idx;
376 int max_len = 0;
377 char str[1024];
378 newtComponent form, tree;
379 struct newtExitStruct es;
380 const struct map_symbol *selection;
381
382 snprintf(str, sizeof(str), "Samples: %Ld", session_total);
383 newtDrawRootText(0, 0, str);
384 newtPushHelpLine(helpline);
385
386 newtGetScreenSize(&cols, &rows);
387
388 if (symbol_conf.use_callchain)
389 tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
390 NEWT_FLAG_SCROLL);
391 else
392 tree = newtListbox(0, 0, rows - 5, (NEWT_FLAG_SCROLL |
393 NEWT_FLAG_RETURNEXIT));
394
395 newtComponentAddCallback(tree, perf_session__selection, &selection);
396
397 list_for_each_entry(se, &hist_entry__sort_list, list) {
398 if (se->elide)
399 continue;
400 width = strlen(se->header);
401 if (se->width) {
402 if (symbol_conf.col_width_list_str) {
403 if (col_width) {
404 *se->width = atoi(col_width);
405 col_width = strchr(col_width, ',');
406 if (col_width)
407 ++col_width;
408 }
409 }
410 *se->width = max(*se->width, width);
411 }
412 }
413
414 idx = 0;
415 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
416 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
417 int len = hist_entry__append_browser(h, tree, session_total);
418 if (len > max_len)
419 max_len = len;
420 if (symbol_conf.use_callchain)
421 hist_entry__append_callchain_browser(h, tree, session_total, idx++);
422 }
423
424 if (max_len > cols)
425 max_len = cols - 3;
426
427 if (!symbol_conf.use_callchain)
428 newtListboxSetWidth(tree, max_len);
429
430 newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
431 rows - 5, "Report");
432 form = newt_form__new();
433 newtFormAddHotKey(form, 'A');
434 newtFormAddHotKey(form, 'a');
435 newtFormAddHotKey(form, NEWT_KEY_RIGHT);
436 newtFormAddComponents(form, tree, NULL);
437 selection = newt__symbol_tree_get_current(tree);
438
439 while (1) {
440 char annotate[512];
441 const char *options[2];
442 int nr_options = 0, choice = 0;
443
444 newtFormRun(form, &es);
445 if (es.reason == NEWT_EXIT_HOTKEY) {
446 if (toupper(es.u.key) == 'A')
447 goto do_annotate;
448 if (es.u.key == NEWT_KEY_ESCAPE ||
449 toupper(es.u.key) == 'Q' ||
450 es.u.key == CTRL('c')) {
451 if (dialog_yesno("Do you really want to exit?"))
452 break;
453 else
454 continue;
455 }
456 }
457
458 if (selection->sym != NULL) {
459 snprintf(annotate, sizeof(annotate),
460 "Annotate %s", selection->sym->name);
461 options[nr_options++] = annotate;
462 }
463
464 options[nr_options++] = "Exit";
465 choice = popup_menu(nr_options, options);
466 if (choice == nr_options - 1)
467 break;
468do_annotate:
469 if (selection->sym != NULL && choice >= 0) {
470 if (selection->map->dso->origin == DSO__ORIG_KERNEL) {
471 newtPopHelpLine();
472 newtPushHelpLine("No vmlinux file found, can't "
473 "annotate with just a "
474 "kallsyms file");
475 continue;
476 }
477 map_symbol__annotate_browser(selection);
478 }
479 }
480
481 newtFormDestroy(form);
482 newtPopWindow();
483}
484
485static char browser__last_msg[1024];
486
487int browser__show_help(const char *format, va_list ap)
488{
489 int ret;
490 static int backlog;
491
492 ret = vsnprintf(browser__last_msg + backlog,
493 sizeof(browser__last_msg) - backlog, format, ap);
494 backlog += ret;
495
496 if (browser__last_msg[backlog - 1] == '\n') {
497 newtPopHelpLine();
498 newtPushHelpLine(browser__last_msg);
499 newtRefresh();
500 backlog = 0;
501 }
502
503 return ret;
504}
505
506void setup_browser(void)
507{
508 if (!isatty(1))
509 return;
510
511 use_browser = true;
512 newtInit();
513 newtCls();
514 newtPushHelpLine(" ");
515}
516
517void exit_browser(bool wait_for_ok)
518{
519 if (use_browser) {
520 if (wait_for_ok) {
521 char title[] = "Fatal Error", ok[] = "Ok";
522 newtWinMessage(title, ok, browser__last_msg);
523 }
524 newtFinished();
525 }
526}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 05d0c5c2030c..435781e0c205 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 "symbol.h"
8#include "cache.h" 9#include "cache.h"
9#include "header.h" 10#include "header.h"
10#include "debugfs.h" 11#include "debugfs.h"
@@ -656,6 +657,10 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr)
656 return EVT_FAILED; 657 return EVT_FAILED;
657 n = hex2u64(str + 1, &config); 658 n = hex2u64(str + 1, &config);
658 if (n > 0) { 659 if (n > 0) {
660 if (str[n+1] == 'p') {
661 attr->precise = 1;
662 n++;
663 }
659 *strp = str + n + 1; 664 *strp = str + n + 1;
660 attr->type = PERF_TYPE_RAW; 665 attr->type = PERF_TYPE_RAW;
661 attr->config = config; 666 attr->config = config;
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index efebd5b476b3..79dfa0c34b3c 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -500,6 +500,7 @@ int usage_with_options_internal(const char * const *usagestr,
500void usage_with_options(const char * const *usagestr, 500void usage_with_options(const char * const *usagestr,
501 const struct option *opts) 501 const struct option *opts)
502{ 502{
503 exit_browser(false);
503 usage_with_options_internal(usagestr, opts, 0); 504 usage_with_options_internal(usagestr, opts, 0);
504 exit(129); 505 exit(129);
505} 506}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 7c004b6ef24f..3fc0be741b8e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -33,19 +33,26 @@
33#include <limits.h> 33#include <limits.h>
34 34
35#undef _GNU_SOURCE 35#undef _GNU_SOURCE
36#include "util.h"
36#include "event.h" 37#include "event.h"
37#include "string.h" 38#include "string.h"
38#include "strlist.h" 39#include "strlist.h"
39#include "debug.h" 40#include "debug.h"
40#include "cache.h" 41#include "cache.h"
41#include "color.h" 42#include "color.h"
42#include "parse-events.h" /* For debugfs_path */ 43#include "symbol.h"
44#include "thread.h"
45#include "trace-event.h" /* For __unused */
46#include "parse-events.h" /* For debugfs_path */
43#include "probe-event.h" 47#include "probe-event.h"
48#include "probe-finder.h"
44 49
45#define MAX_CMDLEN 256 50#define MAX_CMDLEN 256
46#define MAX_PROBE_ARGS 128 51#define MAX_PROBE_ARGS 128
47#define PERFPROBE_GROUP "probe" 52#define PERFPROBE_GROUP "probe"
48 53
54bool probe_event_dry_run; /* Dry run flag */
55
49#define semantic_error(msg ...) die("Semantic error :" msg) 56#define semantic_error(msg ...) die("Semantic error :" msg)
50 57
51/* If there is no space to write, returns -E2BIG. */ 58/* If there is no space to write, returns -E2BIG. */
@@ -64,6 +71,208 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
64 return ret; 71 return ret;
65} 72}
66 73
74static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75static struct map_groups kmap_groups;
76static struct map *kmaps[MAP__NR_TYPES];
77
78/* Initialize symbol maps and path of vmlinux */
79static void init_vmlinux(void)
80{
81 symbol_conf.sort_by_name = true;
82 if (symbol_conf.vmlinux_name == NULL)
83 symbol_conf.try_vmlinux_path = true;
84 else
85 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
86 if (symbol__init() < 0)
87 die("Failed to init symbol map.");
88
89 map_groups__init(&kmap_groups);
90 if (map_groups__create_kernel_maps(&kmap_groups, kmaps) < 0)
91 die("Failed to create kernel maps.");
92}
93
94#ifdef DWARF_SUPPORT
95static int open_vmlinux(void)
96{
97 if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
98 pr_debug("Failed to load kernel map.\n");
99 return -EINVAL;
100 }
101 pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
102 return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
103}
104
105static void convert_to_perf_probe_point(struct kprobe_trace_point *tp,
106 struct perf_probe_point *pp)
107{
108 struct symbol *sym;
109 int fd, ret = 0;
110
111 sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
112 tp->symbol, NULL);
113 if (sym) {
114 fd = open_vmlinux();
115 ret = find_perf_probe_point(fd, sym->start + tp->offset, pp);
116 close(fd);
117 }
118 if (ret <= 0) {
119 pp->function = xstrdup(tp->symbol);
120 pp->offset = tp->offset;
121 }
122 pp->retprobe = tp->retprobe;
123}
124
125/* Try to find perf_probe_event with debuginfo */
126static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
127 struct kprobe_trace_event **tevs)
128{
129 bool need_dwarf = perf_probe_event_need_dwarf(pev);
130 int fd, ntevs;
131
132 fd = open_vmlinux();
133 if (fd < 0) {
134 if (need_dwarf)
135 die("Could not open debuginfo file.");
136
137 pr_debug("Could not open vmlinux. Try to use symbols.\n");
138 return 0;
139 }
140
141 /* Searching trace events corresponding to probe event */
142 ntevs = find_kprobe_trace_events(fd, pev, tevs);
143 close(fd);
144
145 if (ntevs > 0) /* Succeeded to find trace events */
146 return ntevs;
147
148 if (ntevs == 0) /* No error but failed to find probe point. */
149 die("Probe point '%s' not found. - probe not added.",
150 synthesize_perf_probe_point(&pev->point));
151
152 /* Error path */
153 if (need_dwarf) {
154 if (ntevs == -ENOENT)
155 pr_warning("No dwarf info found in the vmlinux - "
156 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
157 die("Could not analyze debuginfo.");
158 }
159 pr_debug("An error occurred in debuginfo analysis."
160 " Try to use symbols.\n");
161 return 0;
162
163}
164
165#define LINEBUF_SIZE 256
166#define NR_ADDITIONAL_LINES 2
167
168static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
169{
170 char buf[LINEBUF_SIZE];
171 const char *color = PERF_COLOR_BLUE;
172
173 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
174 goto error;
175 if (!skip) {
176 if (show_num)
177 fprintf(stdout, "%7u %s", l, buf);
178 else
179 color_fprintf(stdout, color, " %s", buf);
180 }
181
182 while (strlen(buf) == LINEBUF_SIZE - 1 &&
183 buf[LINEBUF_SIZE - 2] != '\n') {
184 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
185 goto error;
186 if (!skip) {
187 if (show_num)
188 fprintf(stdout, "%s", buf);
189 else
190 color_fprintf(stdout, color, "%s", buf);
191 }
192 }
193 return;
194error:
195 if (feof(fp))
196 die("Source file is shorter than expected.");
197 else
198 die("File read error: %s", strerror(errno));
199}
200
201/*
202 * Show line-range always requires debuginfo to find source file and
203 * line number.
204 */
205void show_line_range(struct line_range *lr)
206{
207 unsigned int l = 1;
208 struct line_node *ln;
209 FILE *fp;
210 int fd, ret;
211
212 /* Search a line range */
213 init_vmlinux();
214 fd = open_vmlinux();
215 if (fd < 0)
216 die("Could not open debuginfo file.");
217 ret = find_line_range(fd, lr);
218 if (ret <= 0)
219 die("Source line is not found.\n");
220 close(fd);
221
222 setup_pager();
223
224 if (lr->function)
225 fprintf(stdout, "<%s:%d>\n", lr->function,
226 lr->start - lr->offset);
227 else
228 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
229
230 fp = fopen(lr->path, "r");
231 if (fp == NULL)
232 die("Failed to open %s: %s", lr->path, strerror(errno));
233 /* Skip to starting line number */
234 while (l < lr->start)
235 show_one_line(fp, l++, true, false);
236
237 list_for_each_entry(ln, &lr->line_list, list) {
238 while (ln->line > l)
239 show_one_line(fp, (l++) - lr->offset, false, false);
240 show_one_line(fp, (l++) - lr->offset, false, true);
241 }
242
243 if (lr->end == INT_MAX)
244 lr->end = l + NR_ADDITIONAL_LINES;
245 while (l < lr->end && !feof(fp))
246 show_one_line(fp, (l++) - lr->offset, false, false);
247
248 fclose(fp);
249}
250
251#else /* !DWARF_SUPPORT */
252
253static void convert_to_perf_probe_point(struct kprobe_trace_point *tp,
254 struct perf_probe_point *pp)
255{
256 pp->function = xstrdup(tp->symbol);
257 pp->offset = tp->offset;
258 pp->retprobe = tp->retprobe;
259}
260
261static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
262 struct kprobe_trace_event **tevs __unused)
263{
264 if (perf_probe_event_need_dwarf(pev))
265 die("Debuginfo-analysis is not supported");
266 return 0;
267}
268
269void show_line_range(struct line_range *lr __unused)
270{
271 die("Debuginfo-analysis is not supported");
272}
273
274#endif
275
67void parse_line_range_desc(const char *arg, struct line_range *lr) 276void parse_line_range_desc(const char *arg, struct line_range *lr)
68{ 277{
69 const char *ptr; 278 const char *ptr;
@@ -90,9 +299,9 @@ void parse_line_range_desc(const char *arg, struct line_range *lr)
90 if (*tmp != '\0') 299 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.", 300 semantic_error("Tailing with invalid character '%d'.",
92 *tmp); 301 *tmp);
93 tmp = strndup(arg, (ptr - arg)); 302 tmp = xstrndup(arg, (ptr - arg));
94 } else 303 } else
95 tmp = strdup(arg); 304 tmp = xstrdup(arg);
96 305
97 if (strchr(tmp, '.')) 306 if (strchr(tmp, '.'))
98 lr->file = tmp; 307 lr->file = tmp;
@@ -113,8 +322,9 @@ static bool check_event_name(const char *name)
113} 322}
114 323
115/* Parse probepoint definition. */ 324/* Parse probepoint definition. */
116static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 325static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
117{ 326{
327 struct perf_probe_point *pp = &pev->point;
118 char *ptr, *tmp; 328 char *ptr, *tmp;
119 char c, nc = 0; 329 char c, nc = 0;
120 /* 330 /*
@@ -135,7 +345,8 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
135 if (!check_event_name(arg)) 345 if (!check_event_name(arg))
136 semantic_error("%s is bad for event name -it must " 346 semantic_error("%s is bad for event name -it must "
137 "follow C symbol-naming rule.", arg); 347 "follow C symbol-naming rule.", arg);
138 pp->event = strdup(arg); 348 pev->event = xstrdup(arg);
349 pev->group = NULL;
139 arg = tmp; 350 arg = tmp;
140 } 351 }
141 352
@@ -147,17 +358,16 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
147 358
148 /* Check arg is function or file and copy it */ 359 /* Check arg is function or file and copy it */
149 if (strchr(arg, '.')) /* File */ 360 if (strchr(arg, '.')) /* File */
150 pp->file = strdup(arg); 361 pp->file = xstrdup(arg);
151 else /* Function */ 362 else /* Function */
152 pp->function = strdup(arg); 363 pp->function = xstrdup(arg);
153 DIE_IF(pp->file == NULL && pp->function == NULL);
154 364
155 /* Parse other options */ 365 /* Parse other options */
156 while (ptr) { 366 while (ptr) {
157 arg = ptr; 367 arg = ptr;
158 c = nc; 368 c = nc;
159 if (c == ';') { /* Lazy pattern must be the last part */ 369 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg); 370 pp->lazy_line = xstrdup(arg);
161 break; 371 break;
162 } 372 }
163 ptr = strpbrk(arg, ";:+@%"); 373 ptr = strpbrk(arg, ";:+@%");
@@ -181,8 +391,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
181 case '@': /* File name */ 391 case '@': /* File name */
182 if (pp->file) 392 if (pp->file)
183 semantic_error("SRC@SRC is not allowed."); 393 semantic_error("SRC@SRC is not allowed.");
184 pp->file = strdup(arg); 394 pp->file = xstrdup(arg);
185 DIE_IF(pp->file == NULL);
186 break; 395 break;
187 case '%': /* Probe places */ 396 case '%': /* Probe places */
188 if (strcmp(arg, "return") == 0) { 397 if (strcmp(arg, "return") == 0) {
@@ -220,59 +429,108 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
220 semantic_error("Offset/Line/Lazy pattern can't be used with " 429 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe."); 430 "return probe.");
222 431
223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n", 432 pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 433 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line); 434 pp->lazy_line);
226} 435}
227 436
228/* Parse perf-probe event definition */ 437/* Parse perf-probe event argument */
229void parse_perf_probe_event(const char *str, struct probe_point *pp, 438static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg)
230 bool *need_dwarf) 439{
440 const char *tmp;
441 struct perf_probe_arg_field **fieldp;
442
443 pr_debug("parsing arg: %s into ", str);
444
445 tmp = strpbrk(str, "-.");
446 if (!is_c_varname(str) || !tmp) {
447 /* A variable, register, symbol or special value */
448 arg->name = xstrdup(str);
449 pr_debug("%s\n", arg->name);
450 return;
451 }
452
453 /* Structure fields */
454 arg->name = xstrndup(str, tmp - str);
455 pr_debug("%s, ", arg->name);
456 fieldp = &arg->field;
457
458 do {
459 *fieldp = xzalloc(sizeof(struct perf_probe_arg_field));
460 if (*tmp == '.') {
461 str = tmp + 1;
462 (*fieldp)->ref = false;
463 } else if (tmp[1] == '>') {
464 str = tmp + 2;
465 (*fieldp)->ref = true;
466 } else
467 semantic_error("Argument parse error: %s", str);
468
469 tmp = strpbrk(str, "-.");
470 if (tmp) {
471 (*fieldp)->name = xstrndup(str, tmp - str);
472 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
473 fieldp = &(*fieldp)->next;
474 }
475 } while (tmp);
476 (*fieldp)->name = xstrdup(str);
477 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
478}
479
480/* Parse perf-probe event command */
481void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
231{ 482{
232 char **argv; 483 char **argv;
233 int argc, i; 484 int argc, i;
234 485
235 *need_dwarf = false; 486 argv = argv_split(cmd, &argc);
236
237 argv = argv_split(str, &argc);
238 if (!argv) 487 if (!argv)
239 die("argv_split failed."); 488 die("argv_split failed.");
240 if (argc > MAX_PROBE_ARGS + 1) 489 if (argc > MAX_PROBE_ARGS + 1)
241 semantic_error("Too many arguments"); 490 semantic_error("Too many arguments");
242 491
243 /* Parse probe point */ 492 /* Parse probe point */
244 parse_perf_probe_probepoint(argv[0], pp); 493 parse_perf_probe_point(argv[0], pev);
245 if (pp->file || pp->line || pp->lazy_line)
246 *need_dwarf = true;
247 494
248 /* Copy arguments and ensure return probe has no C argument */ 495 /* Copy arguments and ensure return probe has no C argument */
249 pp->nr_args = argc - 1; 496 pev->nargs = argc - 1;
250 pp->args = zalloc(sizeof(char *) * pp->nr_args); 497 pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
251 for (i = 0; i < pp->nr_args; i++) { 498 for (i = 0; i < pev->nargs; i++) {
252 pp->args[i] = strdup(argv[i + 1]); 499 parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
253 if (!pp->args[i]) 500 if (is_c_varname(pev->args[i].name) && pev->point.retprobe)
254 die("Failed to copy argument."); 501 semantic_error("You can't specify local variable for"
255 if (is_c_varname(pp->args[i])) { 502 " kretprobe");
256 if (pp->retprobe)
257 semantic_error("You can't specify local"
258 " variable for kretprobe");
259 *need_dwarf = true;
260 }
261 } 503 }
262 504
263 argv_free(argv); 505 argv_free(argv);
264} 506}
265 507
508/* Return true if this perf_probe_event requires debuginfo */
509bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
510{
511 int i;
512
513 if (pev->point.file || pev->point.line || pev->point.lazy_line)
514 return true;
515
516 for (i = 0; i < pev->nargs; i++)
517 if (is_c_varname(pev->args[i].name))
518 return true;
519
520 return false;
521}
522
266/* Parse kprobe_events event into struct probe_point */ 523/* Parse kprobe_events event into struct probe_point */
267void parse_trace_kprobe_event(const char *str, struct probe_point *pp) 524void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
268{ 525{
526 struct kprobe_trace_point *tp = &tev->point;
269 char pr; 527 char pr;
270 char *p; 528 char *p;
271 int ret, i, argc; 529 int ret, i, argc;
272 char **argv; 530 char **argv;
273 531
274 pr_debug("Parsing kprobe_events: %s\n", str); 532 pr_debug("Parsing kprobe_events: %s\n", cmd);
275 argv = argv_split(str, &argc); 533 argv = argv_split(cmd, &argc);
276 if (!argv) 534 if (!argv)
277 die("argv_split failed."); 535 die("argv_split failed.");
278 if (argc < 2) 536 if (argc < 2)
@@ -280,132 +538,314 @@ void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
280 538
281 /* Scan event and group name. */ 539 /* Scan event and group name. */
282 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 540 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
283 &pr, (float *)(void *)&pp->group, 541 &pr, (float *)(void *)&tev->group,
284 (float *)(void *)&pp->event); 542 (float *)(void *)&tev->event);
285 if (ret != 3) 543 if (ret != 3)
286 semantic_error("Failed to parse event name: %s", argv[0]); 544 semantic_error("Failed to parse event name: %s", argv[0]);
287 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); 545 pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
288 546
289 pp->retprobe = (pr == 'r'); 547 tp->retprobe = (pr == 'r');
290 548
291 /* Scan function name and offset */ 549 /* Scan function name and offset */
292 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, 550 ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
293 &pp->offset); 551 &tp->offset);
294 if (ret == 1) 552 if (ret == 1)
295 pp->offset = 0; 553 tp->offset = 0;
296
297 /* kprobe_events doesn't have this information */
298 pp->line = 0;
299 pp->file = NULL;
300 554
301 pp->nr_args = argc - 2; 555 tev->nargs = argc - 2;
302 pp->args = zalloc(sizeof(char *) * pp->nr_args); 556 tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
303 for (i = 0; i < pp->nr_args; i++) { 557 for (i = 0; i < tev->nargs; i++) {
304 p = strchr(argv[i + 2], '='); 558 p = strchr(argv[i + 2], '=');
305 if (p) /* We don't need which register is assigned. */ 559 if (p) /* We don't need which register is assigned. */
306 *p = '\0'; 560 *p++ = '\0';
307 pp->args[i] = strdup(argv[i + 2]); 561 else
308 if (!pp->args[i]) 562 p = argv[i + 2];
309 die("Failed to copy argument."); 563 tev->args[i].name = xstrdup(argv[i + 2]);
564 /* TODO: parse regs and offset */
565 tev->args[i].value = xstrdup(p);
310 } 566 }
311 567
312 argv_free(argv); 568 argv_free(argv);
313} 569}
314 570
315/* Synthesize only probe point (not argument) */ 571/* Compose only probe arg */
316int synthesize_perf_probe_point(struct probe_point *pp) 572int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
317{ 573{
318 char *buf; 574 struct perf_probe_arg_field *field = pa->field;
319 char offs[64] = "", line[64] = "";
320 int ret; 575 int ret;
576 char *tmp = buf;
321 577
322 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 578 ret = e_snprintf(tmp, len, "%s", pa->name);
323 pp->found = 1; 579 if (ret <= 0)
324 if (!buf) 580 goto error;
325 die("Failed to allocate memory by zalloc."); 581 tmp += ret;
582 len -= ret;
583
584 while (field) {
585 ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
586 field->name);
587 if (ret <= 0)
588 goto error;
589 tmp += ret;
590 len -= ret;
591 field = field->next;
592 }
593 return tmp - buf;
594error:
595 die("Failed to synthesize perf probe argument: %s", strerror(-ret));
596}
597
598/* Compose only probe point (not argument) */
599static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
600{
601 char *buf, *tmp;
602 char offs[32] = "", line[32] = "", file[32] = "";
603 int ret, len;
604
605 buf = xzalloc(MAX_CMDLEN);
326 if (pp->offset) { 606 if (pp->offset) {
327 ret = e_snprintf(offs, 64, "+%d", pp->offset); 607 ret = e_snprintf(offs, 32, "+%lu", pp->offset);
328 if (ret <= 0) 608 if (ret <= 0)
329 goto error; 609 goto error;
330 } 610 }
331 if (pp->line) { 611 if (pp->line) {
332 ret = e_snprintf(line, 64, ":%d", pp->line); 612 ret = e_snprintf(line, 32, ":%d", pp->line);
613 if (ret <= 0)
614 goto error;
615 }
616 if (pp->file) {
617 len = strlen(pp->file) - 32;
618 if (len < 0)
619 len = 0;
620 tmp = strchr(pp->file + len, '/');
621 if (!tmp)
622 tmp = pp->file + len - 1;
623 ret = e_snprintf(file, 32, "@%s", tmp + 1);
333 if (ret <= 0) 624 if (ret <= 0)
334 goto error; 625 goto error;
335 } 626 }
336 627
337 if (pp->function) 628 if (pp->function)
338 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 629 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
339 offs, pp->retprobe ? "%return" : "", line); 630 offs, pp->retprobe ? "%return" : "", line,
631 file);
340 else 632 else
341 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 633 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
342 if (ret <= 0) { 634 if (ret <= 0)
635 goto error;
636
637 return buf;
343error: 638error:
344 free(pp->probes[0]); 639 die("Failed to synthesize perf probe point: %s", strerror(-ret));
345 pp->probes[0] = NULL;
346 pp->found = 0;
347 }
348 return ret;
349} 640}
350 641
351int synthesize_perf_probe_event(struct probe_point *pp) 642#if 0
643char *synthesize_perf_probe_command(struct perf_probe_event *pev)
352{ 644{
353 char *buf; 645 char *buf;
354 int i, len, ret; 646 int i, len, ret;
355 647
356 len = synthesize_perf_probe_point(pp); 648 buf = synthesize_perf_probe_point(&pev->point);
357 if (len < 0) 649 if (!buf)
358 return 0; 650 return NULL;
359 651
360 buf = pp->probes[0]; 652 len = strlen(buf);
361 for (i = 0; i < pp->nr_args; i++) { 653 for (i = 0; i < pev->nargs; i++) {
362 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 654 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
363 pp->args[i]); 655 pev->args[i].name);
364 if (ret <= 0) 656 if (ret <= 0) {
365 goto error; 657 free(buf);
658 return NULL;
659 }
366 len += ret; 660 len += ret;
367 } 661 }
368 pp->found = 1;
369 662
370 return pp->found; 663 return buf;
371error: 664}
372 free(pp->probes[0]); 665#endif
373 pp->probes[0] = NULL;
374 666
375 return ret; 667static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
668 char **buf, size_t *buflen,
669 int depth)
670{
671 int ret;
672 if (ref->next) {
673 depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf,
674 buflen, depth + 1);
675 if (depth < 0)
676 goto out;
677 }
678
679 ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
680 if (ret < 0)
681 depth = ret;
682 else {
683 *buf += ret;
684 *buflen -= ret;
685 }
686out:
687 return depth;
688
689}
690
691static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
692 char *buf, size_t buflen)
693{
694 int ret, depth = 0;
695 char *tmp = buf;
696
697 /* Argument name or separator */
698 if (arg->name)
699 ret = e_snprintf(buf, buflen, " %s=", arg->name);
700 else
701 ret = e_snprintf(buf, buflen, " ");
702 if (ret < 0)
703 return ret;
704 buf += ret;
705 buflen -= ret;
706
707 /* Dereferencing arguments */
708 if (arg->ref) {
709 depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
710 &buflen, 1);
711 if (depth < 0)
712 return depth;
713 }
714
715 /* Print argument value */
716 ret = e_snprintf(buf, buflen, "%s", arg->value);
717 if (ret < 0)
718 return ret;
719 buf += ret;
720 buflen -= ret;
721
722 /* Closing */
723 while (depth--) {
724 ret = e_snprintf(buf, buflen, ")");
725 if (ret < 0)
726 return ret;
727 buf += ret;
728 buflen -= ret;
729 }
730
731 return buf - tmp;
376} 732}
377 733
378int synthesize_trace_kprobe_event(struct probe_point *pp) 734char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
379{ 735{
736 struct kprobe_trace_point *tp = &tev->point;
380 char *buf; 737 char *buf;
381 int i, len, ret; 738 int i, len, ret;
382 739
383 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 740 buf = xzalloc(MAX_CMDLEN);
384 if (!buf) 741 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
385 die("Failed to allocate memory by zalloc."); 742 tp->retprobe ? 'r' : 'p',
386 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 743 tev->group, tev->event,
387 if (ret <= 0) 744 tp->symbol, tp->offset);
745 if (len <= 0)
388 goto error; 746 goto error;
389 len = ret;
390 747
391 for (i = 0; i < pp->nr_args; i++) { 748 for (i = 0; i < tev->nargs; i++) {
392 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 749 ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len,
393 pp->args[i]); 750 MAX_CMDLEN - len);
394 if (ret <= 0) 751 if (ret <= 0)
395 goto error; 752 goto error;
396 len += ret; 753 len += ret;
397 } 754 }
398 pp->found = 1;
399 755
400 return pp->found; 756 return buf;
401error: 757error:
402 free(pp->probes[0]); 758 free(buf);
403 pp->probes[0] = NULL; 759 return NULL;
760}
404 761
405 return ret; 762void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
763 struct perf_probe_event *pev)
764{
765 char buf[64];
766 int i;
767
768 /* Convert event/group name */
769 pev->event = xstrdup(tev->event);
770 pev->group = xstrdup(tev->group);
771
772 /* Convert trace_point to probe_point */
773 convert_to_perf_probe_point(&tev->point, &pev->point);
774
775 /* Convert trace_arg to probe_arg */
776 pev->nargs = tev->nargs;
777 pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
778 for (i = 0; i < tev->nargs; i++)
779 if (tev->args[i].name)
780 pev->args[i].name = xstrdup(tev->args[i].name);
781 else {
782 synthesize_kprobe_trace_arg(&tev->args[i], buf, 64);
783 pev->args[i].name = xstrdup(buf);
784 }
785}
786
787void clear_perf_probe_event(struct perf_probe_event *pev)
788{
789 struct perf_probe_point *pp = &pev->point;
790 struct perf_probe_arg_field *field, *next;
791 int i;
792
793 if (pev->event)
794 free(pev->event);
795 if (pev->group)
796 free(pev->group);
797 if (pp->file)
798 free(pp->file);
799 if (pp->function)
800 free(pp->function);
801 if (pp->lazy_line)
802 free(pp->lazy_line);
803 for (i = 0; i < pev->nargs; i++) {
804 if (pev->args[i].name)
805 free(pev->args[i].name);
806 field = pev->args[i].field;
807 while (field) {
808 next = field->next;
809 if (field->name)
810 free(field->name);
811 free(field);
812 field = next;
813 }
814 }
815 if (pev->args)
816 free(pev->args);
817 memset(pev, 0, sizeof(*pev));
406} 818}
407 819
408static int open_kprobe_events(int flags, int mode) 820void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
821{
822 struct kprobe_trace_arg_ref *ref, *next;
823 int i;
824
825 if (tev->event)
826 free(tev->event);
827 if (tev->group)
828 free(tev->group);
829 if (tev->point.symbol)
830 free(tev->point.symbol);
831 for (i = 0; i < tev->nargs; i++) {
832 if (tev->args[i].name)
833 free(tev->args[i].name);
834 if (tev->args[i].value)
835 free(tev->args[i].value);
836 ref = tev->args[i].ref;
837 while (ref) {
838 next = ref->next;
839 free(ref);
840 ref = next;
841 }
842 }
843 if (tev->args)
844 free(tev->args);
845 memset(tev, 0, sizeof(*tev));
846}
847
848static int open_kprobe_events(bool readwrite)
409{ 849{
410 char buf[PATH_MAX]; 850 char buf[PATH_MAX];
411 int ret; 851 int ret;
@@ -414,7 +854,11 @@ static int open_kprobe_events(int flags, int mode)
414 if (ret < 0) 854 if (ret < 0)
415 die("Failed to make kprobe_events path."); 855 die("Failed to make kprobe_events path.");
416 856
417 ret = open(buf, flags, mode); 857 if (readwrite && !probe_event_dry_run)
858 ret = open(buf, O_RDWR, O_APPEND);
859 else
860 ret = open(buf, O_RDONLY, 0);
861
418 if (ret < 0) { 862 if (ret < 0) {
419 if (errno == ENOENT) 863 if (errno == ENOENT)
420 die("kprobe_events file does not exist -" 864 die("kprobe_events file does not exist -"
@@ -427,7 +871,7 @@ static int open_kprobe_events(int flags, int mode)
427} 871}
428 872
429/* Get raw string list of current kprobe_events */ 873/* Get raw string list of current kprobe_events */
430static struct strlist *get_trace_kprobe_event_rawlist(int fd) 874static struct strlist *get_kprobe_trace_command_rawlist(int fd)
431{ 875{
432 int ret, idx; 876 int ret, idx;
433 FILE *fp; 877 FILE *fp;
@@ -455,99 +899,85 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd)
455 return sl; 899 return sl;
456} 900}
457 901
458/* Free and zero clear probe_point */
459static void clear_probe_point(struct probe_point *pp)
460{
461 int i;
462
463 if (pp->event)
464 free(pp->event);
465 if (pp->group)
466 free(pp->group);
467 if (pp->function)
468 free(pp->function);
469 if (pp->file)
470 free(pp->file);
471 if (pp->lazy_line)
472 free(pp->lazy_line);
473 for (i = 0; i < pp->nr_args; i++)
474 free(pp->args[i]);
475 if (pp->args)
476 free(pp->args);
477 for (i = 0; i < pp->found; i++)
478 free(pp->probes[i]);
479 memset(pp, 0, sizeof(*pp));
480}
481
482/* Show an event */ 902/* Show an event */
483static void show_perf_probe_event(const char *event, const char *place, 903static void show_perf_probe_event(struct perf_probe_event *pev)
484 struct probe_point *pp)
485{ 904{
486 int i, ret; 905 int i, ret;
487 char buf[128]; 906 char buf[128];
907 char *place;
488 908
489 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); 909 /* Synthesize only event probe point */
910 place = synthesize_perf_probe_point(&pev->point);
911
912 ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
490 if (ret < 0) 913 if (ret < 0)
491 die("Failed to copy event: %s", strerror(-ret)); 914 die("Failed to copy event: %s", strerror(-ret));
492 printf(" %-40s (on %s", buf, place); 915 printf(" %-20s (on %s", buf, place);
493 916
494 if (pp->nr_args > 0) { 917 if (pev->nargs > 0) {
495 printf(" with"); 918 printf(" with");
496 for (i = 0; i < pp->nr_args; i++) 919 for (i = 0; i < pev->nargs; i++) {
497 printf(" %s", pp->args[i]); 920 synthesize_perf_probe_arg(&pev->args[i], buf, 128);
921 printf(" %s", buf);
922 }
498 } 923 }
499 printf(")\n"); 924 printf(")\n");
925 free(place);
500} 926}
501 927
502/* List up current perf-probe events */ 928/* List up current perf-probe events */
503void show_perf_probe_events(void) 929void show_perf_probe_events(void)
504{ 930{
505 int fd; 931 int fd;
506 struct probe_point pp; 932 struct kprobe_trace_event tev;
933 struct perf_probe_event pev;
507 struct strlist *rawlist; 934 struct strlist *rawlist;
508 struct str_node *ent; 935 struct str_node *ent;
509 936
510 setup_pager(); 937 setup_pager();
511 memset(&pp, 0, sizeof(pp)); 938 init_vmlinux();
939
940 memset(&tev, 0, sizeof(tev));
941 memset(&pev, 0, sizeof(pev));
512 942
513 fd = open_kprobe_events(O_RDONLY, 0); 943 fd = open_kprobe_events(false);
514 rawlist = get_trace_kprobe_event_rawlist(fd); 944 rawlist = get_kprobe_trace_command_rawlist(fd);
515 close(fd); 945 close(fd);
516 946
517 strlist__for_each(ent, rawlist) { 947 strlist__for_each(ent, rawlist) {
518 parse_trace_kprobe_event(ent->s, &pp); 948 parse_kprobe_trace_command(ent->s, &tev);
519 /* Synthesize only event probe point */ 949 convert_to_perf_probe_event(&tev, &pev);
520 synthesize_perf_probe_point(&pp);
521 /* Show an event */ 950 /* Show an event */
522 show_perf_probe_event(pp.event, pp.probes[0], &pp); 951 show_perf_probe_event(&pev);
523 clear_probe_point(&pp); 952 clear_perf_probe_event(&pev);
953 clear_kprobe_trace_event(&tev);
524 } 954 }
525 955
526 strlist__delete(rawlist); 956 strlist__delete(rawlist);
527} 957}
528 958
529/* Get current perf-probe event names */ 959/* Get current perf-probe event names */
530static struct strlist *get_perf_event_names(int fd, bool include_group) 960static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
531{ 961{
532 char buf[128]; 962 char buf[128];
533 struct strlist *sl, *rawlist; 963 struct strlist *sl, *rawlist;
534 struct str_node *ent; 964 struct str_node *ent;
535 struct probe_point pp; 965 struct kprobe_trace_event tev;
536 966
537 memset(&pp, 0, sizeof(pp)); 967 memset(&tev, 0, sizeof(tev));
538 rawlist = get_trace_kprobe_event_rawlist(fd);
539 968
969 rawlist = get_kprobe_trace_command_rawlist(fd);
540 sl = strlist__new(true, NULL); 970 sl = strlist__new(true, NULL);
541 strlist__for_each(ent, rawlist) { 971 strlist__for_each(ent, rawlist) {
542 parse_trace_kprobe_event(ent->s, &pp); 972 parse_kprobe_trace_command(ent->s, &tev);
543 if (include_group) { 973 if (include_group) {
544 if (e_snprintf(buf, 128, "%s:%s", pp.group, 974 if (e_snprintf(buf, 128, "%s:%s", tev.group,
545 pp.event) < 0) 975 tev.event) < 0)
546 die("Failed to copy group:event name."); 976 die("Failed to copy group:event name.");
547 strlist__add(sl, buf); 977 strlist__add(sl, buf);
548 } else 978 } else
549 strlist__add(sl, pp.event); 979 strlist__add(sl, tev.event);
550 clear_probe_point(&pp); 980 clear_kprobe_trace_event(&tev);
551 } 981 }
552 982
553 strlist__delete(rawlist); 983 strlist__delete(rawlist);
@@ -555,14 +985,18 @@ static struct strlist *get_perf_event_names(int fd, bool include_group)
555 return sl; 985 return sl;
556} 986}
557 987
558static void write_trace_kprobe_event(int fd, const char *buf) 988static void write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev)
559{ 989{
560 int ret; 990 int ret;
991 char *buf = synthesize_kprobe_trace_command(tev);
561 992
562 pr_debug("Writing event: %s\n", buf); 993 pr_debug("Writing event: %s\n", buf);
563 ret = write(fd, buf, strlen(buf)); 994 if (!probe_event_dry_run) {
564 if (ret <= 0) 995 ret = write(fd, buf, strlen(buf));
565 die("Failed to write event: %s", strerror(errno)); 996 if (ret <= 0)
997 die("Failed to write event: %s", strerror(errno));
998 }
999 free(buf);
566} 1000}
567 1001
568static void get_new_event_name(char *buf, size_t len, const char *base, 1002static void get_new_event_name(char *buf, size_t len, const char *base,
@@ -595,65 +1029,145 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
595 die("Too many events are on the same function."); 1029 die("Too many events are on the same function.");
596} 1030}
597 1031
598void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 1032static void __add_kprobe_trace_events(struct perf_probe_event *pev,
599 bool force_add) 1033 struct kprobe_trace_event *tevs,
1034 int ntevs, bool allow_suffix)
600{ 1035{
601 int i, j, fd; 1036 int i, fd;
602 struct probe_point *pp; 1037 struct kprobe_trace_event *tev = NULL;
603 char buf[MAX_CMDLEN]; 1038 char buf[64];
604 char event[64]; 1039 const char *event, *group;
605 struct strlist *namelist; 1040 struct strlist *namelist;
606 bool allow_suffix;
607 1041
608 fd = open_kprobe_events(O_RDWR, O_APPEND); 1042 fd = open_kprobe_events(true);
609 /* Get current event names */ 1043 /* Get current event names */
610 namelist = get_perf_event_names(fd, false); 1044 namelist = get_kprobe_trace_event_names(fd, false);
611 1045
612 for (j = 0; j < nr_probes; j++) { 1046 printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
613 pp = probes + j; 1047 for (i = 0; i < ntevs; i++) {
614 if (!pp->event) 1048 tev = &tevs[i];
615 pp->event = strdup(pp->function); 1049 if (pev->event)
616 if (!pp->group) 1050 event = pev->event;
617 pp->group = strdup(PERFPROBE_GROUP); 1051 else
618 DIE_IF(!pp->event || !pp->group); 1052 if (pev->point.function)
619 /* If force_add is true, suffix search is allowed */ 1053 event = pev->point.function;
620 allow_suffix = force_add; 1054 else
621 for (i = 0; i < pp->found; i++) { 1055 event = tev->point.symbol;
622 /* Get an unused new event name */ 1056 if (pev->group)
623 get_new_event_name(event, 64, pp->event, namelist, 1057 group = pev->group;
624 allow_suffix); 1058 else
625 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 1059 group = PERFPROBE_GROUP;
626 pp->retprobe ? 'r' : 'p', 1060
627 pp->group, event, 1061 /* Get an unused new event name */
628 pp->probes[i]); 1062 get_new_event_name(buf, 64, event, namelist, allow_suffix);
629 write_trace_kprobe_event(fd, buf); 1063 event = buf;
630 printf("Added new event:\n"); 1064
631 /* Get the first parameter (probe-point) */ 1065 tev->event = xstrdup(event);
632 sscanf(pp->probes[i], "%s", buf); 1066 tev->group = xstrdup(group);
633 show_perf_probe_event(event, buf, pp); 1067 write_kprobe_trace_event(fd, tev);
634 /* Add added event name to namelist */ 1068 /* Add added event name to namelist */
635 strlist__add(namelist, event); 1069 strlist__add(namelist, event);
636 /* 1070
637 * Probes after the first probe which comes from same 1071 /* Trick here - save current event/group */
638 * user input are always allowed to add suffix, because 1072 event = pev->event;
639 * there might be several addresses corresponding to 1073 group = pev->group;
640 * one code line. 1074 pev->event = tev->event;
641 */ 1075 pev->group = tev->group;
642 allow_suffix = true; 1076 show_perf_probe_event(pev);
643 } 1077 /* Trick here - restore current event/group */
1078 pev->event = (char *)event;
1079 pev->group = (char *)group;
1080
1081 /*
1082 * Probes after the first probe which comes from same
1083 * user input are always allowed to add suffix, because
1084 * there might be several addresses corresponding to
1085 * one code line.
1086 */
1087 allow_suffix = true;
644 } 1088 }
645 /* Show how to use the event. */ 1089 /* Show how to use the event. */
646 printf("\nYou can now use it on all perf tools, such as:\n\n"); 1090 printf("\nYou can now use it on all perf tools, such as:\n\n");
647 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); 1091 printf("\tperf record -e %s:%s -a sleep 1\n\n", tev->group, tev->event);
648 1092
649 strlist__delete(namelist); 1093 strlist__delete(namelist);
650 close(fd); 1094 close(fd);
651} 1095}
652 1096
1097static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
1098 struct kprobe_trace_event **tevs)
1099{
1100 struct symbol *sym;
1101 int ntevs = 0, i;
1102 struct kprobe_trace_event *tev;
1103
1104 /* Convert perf_probe_event with debuginfo */
1105 ntevs = try_to_find_kprobe_trace_events(pev, tevs);
1106 if (ntevs > 0)
1107 return ntevs;
1108
1109 /* Allocate trace event buffer */
1110 ntevs = 1;
1111 tev = *tevs = xzalloc(sizeof(struct kprobe_trace_event));
1112
1113 /* Copy parameters */
1114 tev->point.symbol = xstrdup(pev->point.function);
1115 tev->point.offset = pev->point.offset;
1116 tev->nargs = pev->nargs;
1117 if (tev->nargs) {
1118 tev->args = xzalloc(sizeof(struct kprobe_trace_arg)
1119 * tev->nargs);
1120 for (i = 0; i < tev->nargs; i++)
1121 tev->args[i].value = xstrdup(pev->args[i].name);
1122 }
1123
1124 /* Currently just checking function name from symbol map */
1125 sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
1126 tev->point.symbol, NULL);
1127 if (!sym)
1128 die("Kernel symbol \'%s\' not found - probe not added.",
1129 tev->point.symbol);
1130
1131 return ntevs;
1132}
1133
1134struct __event_package {
1135 struct perf_probe_event *pev;
1136 struct kprobe_trace_event *tevs;
1137 int ntevs;
1138};
1139
1140void add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1141 bool force_add)
1142{
1143 int i;
1144 struct __event_package *pkgs;
1145
1146 pkgs = xzalloc(sizeof(struct __event_package) * npevs);
1147
1148 /* Init vmlinux path */
1149 init_vmlinux();
1150
1151 /* Loop 1: convert all events */
1152 for (i = 0; i < npevs; i++) {
1153 pkgs[i].pev = &pevs[i];
1154 /* Convert with or without debuginfo */
1155 pkgs[i].ntevs = convert_to_kprobe_trace_events(pkgs[i].pev,
1156 &pkgs[i].tevs);
1157 }
1158
1159 /* Loop 2: add all events */
1160 for (i = 0; i < npevs; i++)
1161 __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1162 pkgs[i].ntevs, force_add);
1163 /* TODO: cleanup all trace events? */
1164}
1165
653static void __del_trace_kprobe_event(int fd, struct str_node *ent) 1166static void __del_trace_kprobe_event(int fd, struct str_node *ent)
654{ 1167{
655 char *p; 1168 char *p;
656 char buf[128]; 1169 char buf[128];
1170 int ret;
657 1171
658 /* Convert from perf-probe event to trace-kprobe event */ 1172 /* Convert from perf-probe event to trace-kprobe event */
659 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) 1173 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
@@ -663,7 +1177,10 @@ static void __del_trace_kprobe_event(int fd, struct str_node *ent)
663 die("Internal error: %s should have ':' but not.", ent->s); 1177 die("Internal error: %s should have ':' but not.", ent->s);
664 *p = '/'; 1178 *p = '/';
665 1179
666 write_trace_kprobe_event(fd, buf); 1180 pr_debug("Writing event: %s\n", buf);
1181 ret = write(fd, buf, strlen(buf));
1182 if (ret <= 0)
1183 die("Failed to write event: %s", strerror(errno));
667 printf("Remove event: %s\n", ent->s); 1184 printf("Remove event: %s\n", ent->s);
668} 1185}
669 1186
@@ -696,7 +1213,7 @@ static void del_trace_kprobe_event(int fd, const char *group,
696 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); 1213 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
697} 1214}
698 1215
699void del_trace_kprobe_events(struct strlist *dellist) 1216void del_perf_probe_events(struct strlist *dellist)
700{ 1217{
701 int fd; 1218 int fd;
702 const char *group, *event; 1219 const char *group, *event;
@@ -704,14 +1221,12 @@ void del_trace_kprobe_events(struct strlist *dellist)
704 struct str_node *ent; 1221 struct str_node *ent;
705 struct strlist *namelist; 1222 struct strlist *namelist;
706 1223
707 fd = open_kprobe_events(O_RDWR, O_APPEND); 1224 fd = open_kprobe_events(true);
708 /* Get current event names */ 1225 /* Get current event names */
709 namelist = get_perf_event_names(fd, true); 1226 namelist = get_kprobe_trace_event_names(fd, true);
710 1227
711 strlist__for_each(ent, dellist) { 1228 strlist__for_each(ent, dellist) {
712 str = strdup(ent->s); 1229 str = xstrdup(ent->s);
713 if (!str)
714 die("Failed to copy event.");
715 pr_debug("Parsing: %s\n", str); 1230 pr_debug("Parsing: %s\n", str);
716 p = strchr(str, ':'); 1231 p = strchr(str, ':');
717 if (p) { 1232 if (p) {
@@ -730,73 +1245,3 @@ void del_trace_kprobe_events(struct strlist *dellist)
730 close(fd); 1245 close(fd);
731} 1246}
732 1247
733#define LINEBUF_SIZE 256
734#define NR_ADDITIONAL_LINES 2
735
736static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
737{
738 char buf[LINEBUF_SIZE];
739 const char *color = PERF_COLOR_BLUE;
740
741 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
742 goto error;
743 if (!skip) {
744 if (show_num)
745 fprintf(stdout, "%7u %s", l, buf);
746 else
747 color_fprintf(stdout, color, " %s", buf);
748 }
749
750 while (strlen(buf) == LINEBUF_SIZE - 1 &&
751 buf[LINEBUF_SIZE - 2] != '\n') {
752 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
753 goto error;
754 if (!skip) {
755 if (show_num)
756 fprintf(stdout, "%s", buf);
757 else
758 color_fprintf(stdout, color, "%s", buf);
759 }
760 }
761 return;
762error:
763 if (feof(fp))
764 die("Source file is shorter than expected.");
765 else
766 die("File read error: %s", strerror(errno));
767}
768
769void show_line_range(struct line_range *lr)
770{
771 unsigned int l = 1;
772 struct line_node *ln;
773 FILE *fp;
774
775 setup_pager();
776
777 if (lr->function)
778 fprintf(stdout, "<%s:%d>\n", lr->function,
779 lr->start - lr->offset);
780 else
781 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
782
783 fp = fopen(lr->path, "r");
784 if (fp == NULL)
785 die("Failed to open %s: %s", lr->path, strerror(errno));
786 /* Skip to starting line number */
787 while (l < lr->start)
788 show_one_line(fp, l++, true, false);
789
790 list_for_each_entry(ln, &lr->line_list, list) {
791 while (ln->line > l)
792 show_one_line(fp, (l++) - lr->offset, false, false);
793 show_one_line(fp, (l++) - lr->offset, false, true);
794 }
795
796 if (lr->end == INT_MAX)
797 lr->end = l + NR_ADDITIONAL_LINES;
798 while (l < lr->end && !feof(fp))
799 show_one_line(fp, (l++) - lr->offset, false, false);
800
801 fclose(fp);
802}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 711287d4baea..cd308b0a4d96 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,22 +2,123 @@
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "probe-finder.h"
6#include "strlist.h" 5#include "strlist.h"
7 6
8extern void parse_line_range_desc(const char *arg, struct line_range *lr); 7extern bool probe_event_dry_run;
9extern void parse_perf_probe_event(const char *str, struct probe_point *pp, 8
10 bool *need_dwarf); 9/* kprobe-tracer tracing point */
11extern int synthesize_perf_probe_point(struct probe_point *pp); 10struct kprobe_trace_point {
12extern int synthesize_perf_probe_event(struct probe_point *pp); 11 char *symbol; /* Base symbol */
13extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp); 12 unsigned long offset; /* Offset from symbol */
14extern int synthesize_trace_kprobe_event(struct probe_point *pp); 13 bool retprobe; /* Return probe flag */
15extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 14};
16 bool force_add); 15
17extern void del_trace_kprobe_events(struct strlist *dellist); 16/* kprobe-tracer tracing argument referencing offset */
17struct kprobe_trace_arg_ref {
18 struct kprobe_trace_arg_ref *next; /* Next reference */
19 long offset; /* Offset value */
20};
21
22/* kprobe-tracer tracing argument */
23struct kprobe_trace_arg {
24 char *name; /* Argument name */
25 char *value; /* Base value */
26 struct kprobe_trace_arg_ref *ref; /* Referencing offset */
27};
28
29/* kprobe-tracer tracing event (point + arg) */
30struct kprobe_trace_event {
31 char *event; /* Event name */
32 char *group; /* Group name */
33 struct kprobe_trace_point point; /* Trace point */
34 int nargs; /* Number of args */
35 struct kprobe_trace_arg *args; /* Arguments */
36};
37
38/* Perf probe probing point */
39struct perf_probe_point {
40 char *file; /* File path */
41 char *function; /* Function name */
42 int line; /* Line number */
43 char *lazy_line; /* Lazy matching pattern */
44 unsigned long offset; /* Offset from function entry */
45 bool retprobe; /* Return probe flag */
46};
47
48/* Perf probe probing argument field chain */
49struct perf_probe_arg_field {
50 struct perf_probe_arg_field *next; /* Next field */
51 char *name; /* Name of the field */
52 bool ref; /* Referencing flag */
53};
54
55/* Perf probe probing argument */
56struct perf_probe_arg {
57 char *name; /* Argument name */
58 struct perf_probe_arg_field *field; /* Structure fields */
59};
60
61/* Perf probe probing event (point + arg) */
62struct perf_probe_event {
63 char *event; /* Event name */
64 char *group; /* Group name */
65 struct perf_probe_point point; /* Probe point */
66 int nargs; /* Number of arguments */
67 struct perf_probe_arg *args; /* Arguments */
68};
69
70
71/* Line number container */
72struct line_node {
73 struct list_head list;
74 unsigned int line;
75};
76
77/* Line range */
78struct line_range {
79 char *file; /* File name */
80 char *function; /* Function name */
81 unsigned int start; /* Start line number */
82 unsigned int end; /* End line number */
83 int offset; /* Start line offset */
84 char *path; /* Real path name */
85 struct list_head line_list; /* Visible lines */
86};
87
88/* Command string to events */
89extern void parse_perf_probe_command(const char *cmd,
90 struct perf_probe_event *pev);
91extern void parse_kprobe_trace_command(const char *cmd,
92 struct kprobe_trace_event *tev);
93
94/* Events to command string */
95extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
96extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev);
97extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
98 size_t len);
99
100/* Check the perf_probe_event needs debuginfo */
101extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
102
103/* Convert from kprobe_trace_event to perf_probe_event */
104extern void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
105 struct perf_probe_event *pev);
106
107/* Release event contents */
108extern void clear_perf_probe_event(struct perf_probe_event *pev);
109extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev);
110
111/* Command string to line-range */
112extern void parse_line_range_desc(const char *cmd, struct line_range *lr);
113
114
115extern void add_perf_probe_events(struct perf_probe_event *pevs, int ntevs,
116 bool force_add);
117extern void del_perf_probe_events(struct strlist *dellist);
18extern void show_perf_probe_events(void); 118extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr); 119extern void show_line_range(struct line_range *lr);
20 120
121
21/* Maximum index number of event-name postfix */ 122/* Maximum index number of event-name postfix */
22#define MAX_EVENT_INDEX 1024 123#define MAX_EVENT_INDEX 1024
23 124
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c171a243d05b..a8513772df08 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -125,8 +125,7 @@ static void line_list__add_line(struct list_head *head, unsigned int line)
125 p = head; 125 p = head;
126found: 126found:
127 pr_debug("line list: add a line %u\n", line); 127 pr_debug("line list: add a line %u\n", line);
128 ln = zalloc(sizeof(struct line_node)); 128 ln = xzalloc(sizeof(struct line_node));
129 DIE_IF(ln == NULL);
130 ln->line = line; 129 ln->line = line;
131 INIT_LIST_HEAD(&ln->list); 130 INIT_LIST_HEAD(&ln->list);
132 list_add(&ln->list, p); 131 list_add(&ln->list, p);
@@ -184,9 +183,89 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
184 if (strtailcmp(src, fname) == 0) 183 if (strtailcmp(src, fname) == 0)
185 break; 184 break;
186 } 185 }
186 if (i == nfiles)
187 return NULL;
187 return src; 188 return src;
188} 189}
189 190
191/* Compare diename and tname */
192static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
193{
194 const char *name;
195 name = dwarf_diename(dw_die);
196 DIE_IF(name == NULL);
197 return strcmp(tname, name);
198}
199
200/* Get entry pc(or low pc, 1st entry of ranges) of the die */
201static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
202{
203 Dwarf_Addr epc;
204 int ret;
205
206 ret = dwarf_entrypc(dw_die, &epc);
207 DIE_IF(ret == -1);
208 return epc;
209}
210
211/* Get type die, but skip qualifiers and typedef */
212static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
213{
214 Dwarf_Attribute attr;
215 int tag;
216
217 do {
218 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
219 dwarf_formref_die(&attr, die_mem) == NULL)
220 return NULL;
221
222 tag = dwarf_tag(die_mem);
223 vr_die = die_mem;
224 } while (tag == DW_TAG_const_type ||
225 tag == DW_TAG_restrict_type ||
226 tag == DW_TAG_volatile_type ||
227 tag == DW_TAG_shared_type ||
228 tag == DW_TAG_typedef);
229
230 return die_mem;
231}
232
233/* Return values for die_find callbacks */
234enum {
235 DIE_FIND_CB_FOUND = 0, /* End of Search */
236 DIE_FIND_CB_CHILD = 1, /* Search only children */
237 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
238 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
239};
240
241/* Search a child die */
242static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
243 int (*callback)(Dwarf_Die *, void *),
244 void *data, Dwarf_Die *die_mem)
245{
246 Dwarf_Die child_die;
247 int ret;
248
249 ret = dwarf_child(rt_die, die_mem);
250 if (ret != 0)
251 return NULL;
252
253 do {
254 ret = callback(die_mem, data);
255 if (ret == DIE_FIND_CB_FOUND)
256 return die_mem;
257
258 if ((ret & DIE_FIND_CB_CHILD) &&
259 die_find_child(die_mem, callback, data, &child_die)) {
260 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
261 return die_mem;
262 }
263 } while ((ret & DIE_FIND_CB_SIBLING) &&
264 dwarf_siblingof(die_mem, die_mem) == 0);
265
266 return NULL;
267}
268
190struct __addr_die_search_param { 269struct __addr_die_search_param {
191 Dwarf_Addr addr; 270 Dwarf_Addr addr;
192 Dwarf_Die *die_mem; 271 Dwarf_Die *die_mem;
@@ -205,8 +284,8 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
205} 284}
206 285
207/* Search a real subprogram including this line, */ 286/* Search a real subprogram including this line, */
208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, 287static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
209 Dwarf_Die *die_mem) 288 Dwarf_Die *die_mem)
210{ 289{
211 struct __addr_die_search_param ad; 290 struct __addr_die_search_param ad;
212 ad.addr = addr; 291 ad.addr = addr;
@@ -218,77 +297,64 @@ static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
218 return die_mem; 297 return die_mem;
219} 298}
220 299
221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ 300/* die_find callback for inline function search */
222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 301static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
223 Dwarf_Die *die_mem)
224{ 302{
225 Dwarf_Die child_die; 303 Dwarf_Addr *addr = data;
226 int ret;
227
228 ret = dwarf_child(sp_die, die_mem);
229 if (ret != 0)
230 return NULL;
231 304
232 do { 305 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && 306 dwarf_haspc(die_mem, *addr))
234 dwarf_haspc(die_mem, addr)) 307 return DIE_FIND_CB_FOUND;
235 return die_mem;
236 308
237 if (die_get_inlinefunc(die_mem, addr, &child_die)) { 309 return DIE_FIND_CB_CONTINUE;
238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
239 return die_mem;
240 }
241 } while (dwarf_siblingof(die_mem, die_mem) == 0);
242
243 return NULL;
244} 310}
245 311
246/* Compare diename and tname */ 312/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 313static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
314 Dwarf_Die *die_mem)
248{ 315{
249 const char *name; 316 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
250 name = dwarf_diename(dw_die);
251 DIE_IF(name == NULL);
252 return strcmp(tname, name);
253} 317}
254 318
255/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 319static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
257{ 320{
258 Dwarf_Addr epc; 321 const char *name = data;
259 int ret; 322 int tag;
260 323
261 ret = dwarf_entrypc(dw_die, &epc); 324 tag = dwarf_tag(die_mem);
262 DIE_IF(ret == -1); 325 if ((tag == DW_TAG_formal_parameter ||
263 return epc; 326 tag == DW_TAG_variable) &&
327 (die_compare_name(die_mem, name) == 0))
328 return DIE_FIND_CB_FOUND;
329
330 return DIE_FIND_CB_CONTINUE;
264} 331}
265 332
266/* Get a variable die */ 333/* Find a variable called 'name' */
267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, 334static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
268 Dwarf_Die *die_mem) 335 Dwarf_Die *die_mem)
269{ 336{
270 Dwarf_Die child_die; 337 return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
271 int tag; 338 die_mem);
272 int ret; 339}
273 340
274 ret = dwarf_child(sp_die, die_mem); 341static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
275 if (ret != 0) 342{
276 return NULL; 343 const char *name = data;
277 344
278 do { 345 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
279 tag = dwarf_tag(die_mem); 346 (die_compare_name(die_mem, name) == 0))
280 if ((tag == DW_TAG_formal_parameter || 347 return DIE_FIND_CB_FOUND;
281 tag == DW_TAG_variable) &&
282 (die_compare_name(die_mem, name) == 0))
283 return die_mem;
284 348
285 if (die_find_variable(die_mem, name, &child_die)) { 349 return DIE_FIND_CB_SIBLING;
286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 350}
287 return die_mem;
288 }
289 } while (dwarf_siblingof(die_mem, die_mem) == 0);
290 351
291 return NULL; 352/* Find a member called 'name' */
353static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
354 Dwarf_Die *die_mem)
355{
356 return die_find_child(st_die, __die_find_member_cb, (void *)name,
357 die_mem);
292} 358}
293 359
294/* 360/*
@@ -296,19 +362,20 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
296 */ 362 */
297 363
298/* Show a location */ 364/* Show a location */
299static void show_location(Dwarf_Op *op, struct probe_finder *pf) 365static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
300{ 366{
301 unsigned int regn; 367 unsigned int regn;
302 Dwarf_Word offs = 0; 368 Dwarf_Word offs = 0;
303 int deref = 0, ret; 369 bool ref = false;
304 const char *regs; 370 const char *regs;
371 struct kprobe_trace_arg *tvar = pf->tvar;
305 372
306 /* TODO: support CFA */ 373 /* TODO: support CFA */
307 /* If this is based on frame buffer, set the offset */ 374 /* If this is based on frame buffer, set the offset */
308 if (op->atom == DW_OP_fbreg) { 375 if (op->atom == DW_OP_fbreg) {
309 if (pf->fb_ops == NULL) 376 if (pf->fb_ops == NULL)
310 die("The attribute of frame base is not supported.\n"); 377 die("The attribute of frame base is not supported.\n");
311 deref = 1; 378 ref = true;
312 offs = op->number; 379 offs = op->number;
313 op = &pf->fb_ops[0]; 380 op = &pf->fb_ops[0];
314 } 381 }
@@ -316,13 +383,13 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 383 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
317 regn = op->atom - DW_OP_breg0; 384 regn = op->atom - DW_OP_breg0;
318 offs += op->number; 385 offs += op->number;
319 deref = 1; 386 ref = true;
320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 387 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
321 regn = op->atom - DW_OP_reg0; 388 regn = op->atom - DW_OP_reg0;
322 } else if (op->atom == DW_OP_bregx) { 389 } else if (op->atom == DW_OP_bregx) {
323 regn = op->number; 390 regn = op->number;
324 offs += op->number2; 391 offs += op->number2;
325 deref = 1; 392 ref = true;
326 } else if (op->atom == DW_OP_regx) { 393 } else if (op->atom == DW_OP_regx) {
327 regn = op->number; 394 regn = op->number;
328 } else 395 } else
@@ -332,17 +399,75 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
332 if (!regs) 399 if (!regs)
333 die("%u exceeds max register number.", regn); 400 die("%u exceeds max register number.", regn);
334 401
335 if (deref) 402 tvar->value = xstrdup(regs);
336 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", 403 if (ref) {
337 pf->var, (intmax_t)offs, regs); 404 tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
338 else 405 tvar->ref->offset = (long)offs;
339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 406 }
340 DIE_IF(ret < 0); 407}
341 DIE_IF(ret >= pf->len); 408
409static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
410 struct perf_probe_arg_field *field,
411 struct kprobe_trace_arg_ref **ref_ptr)
412{
413 struct kprobe_trace_arg_ref *ref = *ref_ptr;
414 Dwarf_Attribute attr;
415 Dwarf_Die member;
416 Dwarf_Die type;
417 Dwarf_Word offs;
418
419 pr_debug("converting %s in %s\n", field->name, varname);
420 if (die_get_real_type(vr_die, &type) == NULL)
421 die("Failed to get a type information of %s.", varname);
422
423 /* Check the pointer and dereference */
424 if (dwarf_tag(&type) == DW_TAG_pointer_type) {
425 if (!field->ref)
426 die("Semantic error: %s must be referred by '->'",
427 field->name);
428 /* Get the type pointed by this pointer */
429 if (die_get_real_type(&type, &type) == NULL)
430 die("Failed to get a type information of %s.", varname);
431
432 /* Verify it is a data structure */
433 if (dwarf_tag(&type) != DW_TAG_structure_type)
434 die("%s is not a data structure.", varname);
435
436 ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
437 if (*ref_ptr)
438 (*ref_ptr)->next = ref;
439 else
440 *ref_ptr = ref;
441 } else {
442 /* Verify it is a data structure */
443 if (dwarf_tag(&type) != DW_TAG_structure_type)
444 die("%s is not a data structure.", varname);
445
446 if (field->ref)
447 die("Semantic error: %s must be referred by '.'",
448 field->name);
449 if (!ref)
450 die("Structure on a register is not supported yet.");
451 }
452
453 if (die_find_member(&type, field->name, &member) == NULL)
454 die("%s(tyep:%s) has no member %s.", varname,
455 dwarf_diename(&type), field->name);
456
457 /* Get the offset of the field */
458 if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL ||
459 dwarf_formudata(&attr, &offs) != 0)
460 die("Failed to get the offset of %s.", field->name);
461 ref->offset += (long)offs;
462
463 /* Converting next field */
464 if (field->next)
465 convert_variable_fields(&member, field->name, field->next,
466 &ref);
342} 467}
343 468
344/* Show a variables in kprobe event format */ 469/* Show a variables in kprobe event format */
345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 470static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
346{ 471{
347 Dwarf_Attribute attr; 472 Dwarf_Attribute attr;
348 Dwarf_Op *expr; 473 Dwarf_Op *expr;
@@ -356,83 +481,77 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
356 if (ret <= 0 || nexpr == 0) 481 if (ret <= 0 || nexpr == 0)
357 goto error; 482 goto error;
358 483
359 show_location(expr, pf); 484 convert_location(expr, pf);
485
486 if (pf->pvar->field)
487 convert_variable_fields(vr_die, pf->pvar->name,
488 pf->pvar->field, &pf->tvar->ref);
360 /* *expr will be cached in libdw. Don't free it. */ 489 /* *expr will be cached in libdw. Don't free it. */
361 return ; 490 return ;
362error: 491error:
363 /* TODO: Support const_value */ 492 /* TODO: Support const_value */
364 die("Failed to find the location of %s at this address.\n" 493 die("Failed to find the location of %s at this address.\n"
365 " Perhaps, it has been optimized out.", pf->var); 494 " Perhaps, it has been optimized out.", pf->pvar->name);
366} 495}
367 496
368/* Find a variable in a subprogram die */ 497/* Find a variable in a subprogram die */
369static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 498static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
370{ 499{
371 int ret;
372 Dwarf_Die vr_die; 500 Dwarf_Die vr_die;
501 char buf[128];
373 502
374 /* TODO: Support struct members and arrays */ 503 /* TODO: Support struct members and arrays */
375 if (!is_c_varname(pf->var)) { 504 if (!is_c_varname(pf->pvar->name)) {
376 /* Output raw parameters */ 505 /* Copy raw parameters */
377 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 506 pf->tvar->value = xstrdup(pf->pvar->name);
378 DIE_IF(ret < 0); 507 } else {
379 DIE_IF(ret >= pf->len); 508 synthesize_perf_probe_arg(pf->pvar, buf, 128);
380 return ; 509 pf->tvar->name = xstrdup(buf);
510 pr_debug("Searching '%s' variable in context.\n",
511 pf->pvar->name);
512 /* Search child die for local variables and parameters. */
513 if (!die_find_variable(sp_die, pf->pvar->name, &vr_die))
514 die("Failed to find '%s' in this function.",
515 pf->pvar->name);
516 convert_variable(&vr_die, pf);
381 } 517 }
382
383 pr_debug("Searching '%s' variable in context.\n", pf->var);
384 /* Search child die for local variables and parameters. */
385 if (!die_find_variable(sp_die, pf->var, &vr_die))
386 die("Failed to find '%s' in this function.", pf->var);
387
388 show_variable(&vr_die, pf);
389} 518}
390 519
391/* Show a probe point to output buffer */ 520/* Show a probe point to output buffer */
392static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 521static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
393{ 522{
394 struct probe_point *pp = pf->pp; 523 struct kprobe_trace_event *tev;
395 Dwarf_Addr eaddr; 524 Dwarf_Addr eaddr;
396 Dwarf_Die die_mem; 525 Dwarf_Die die_mem;
397 const char *name; 526 const char *name;
398 char tmp[MAX_PROBE_BUFFER]; 527 int ret, i;
399 int ret, i, len;
400 Dwarf_Attribute fb_attr; 528 Dwarf_Attribute fb_attr;
401 size_t nops; 529 size_t nops;
402 530
531 if (pf->ntevs == MAX_PROBES)
532 die("Too many( > %d) probe point found.\n", MAX_PROBES);
533 tev = &pf->tevs[pf->ntevs++];
534
403 /* If no real subprogram, find a real one */ 535 /* If no real subprogram, find a real one */
404 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 536 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
405 sp_die = die_get_real_subprogram(&pf->cu_die, 537 sp_die = die_find_real_subprogram(&pf->cu_die,
406 pf->addr, &die_mem); 538 pf->addr, &die_mem);
407 if (!sp_die) 539 if (!sp_die)
408 die("Probe point is not found in subprograms."); 540 die("Probe point is not found in subprograms.");
409 } 541 }
410 542
411 /* Output name of probe point */ 543 /* Copy the name of probe point */
412 name = dwarf_diename(sp_die); 544 name = dwarf_diename(sp_die);
413 if (name) { 545 if (name) {
414 dwarf_entrypc(sp_die, &eaddr); 546 dwarf_entrypc(sp_die, &eaddr);
415 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name, 547 tev->point.symbol = xstrdup(name);
416 (unsigned long)(pf->addr - eaddr)); 548 tev->point.offset = (unsigned long)(pf->addr - eaddr);
417 /* Copy the function name if possible */ 549 } else
418 if (!pp->function) {
419 pp->function = strdup(name);
420 pp->offset = (size_t)(pf->addr - eaddr);
421 }
422 } else {
423 /* This function has no name. */ 550 /* This function has no name. */
424 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx", 551 tev->point.offset = (unsigned long)pf->addr;
425 (uintmax_t)pf->addr); 552
426 if (!pp->function) { 553 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
427 /* TODO: Use _stext */ 554 tev->point.offset);
428 pp->function = strdup("");
429 pp->offset = (size_t)pf->addr;
430 }
431 }
432 DIE_IF(ret < 0);
433 DIE_IF(ret >= MAX_PROBE_BUFFER);
434 len = ret;
435 pr_debug("Probe point found: %s\n", tmp);
436 555
437 /* Get the frame base attribute/ops */ 556 /* Get the frame base attribute/ops */
438 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 557 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -442,22 +561,16 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
442 561
443 /* Find each argument */ 562 /* Find each argument */
444 /* TODO: use dwarf_cfi_addrframe */ 563 /* TODO: use dwarf_cfi_addrframe */
445 for (i = 0; i < pp->nr_args; i++) { 564 tev->nargs = pf->pev->nargs;
446 pf->var = pp->args[i]; 565 tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
447 pf->buf = &tmp[len]; 566 for (i = 0; i < pf->pev->nargs; i++) {
448 pf->len = MAX_PROBE_BUFFER - len; 567 pf->pvar = &pf->pev->args[i];
568 pf->tvar = &tev->args[i];
449 find_variable(sp_die, pf); 569 find_variable(sp_die, pf);
450 len += strlen(pf->buf);
451 } 570 }
452 571
453 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 572 /* *pf->fb_ops will be cached in libdw. Don't free it. */
454 pf->fb_ops = NULL; 573 pf->fb_ops = NULL;
455
456 if (pp->found == MAX_PROBES)
457 die("Too many( > %d) probe point found.\n", MAX_PROBES);
458
459 pp->probes[pp->found] = strdup(tmp);
460 pp->found++;
461} 574}
462 575
463/* Find probe point from its line number */ 576/* Find probe point from its line number */
@@ -489,7 +602,7 @@ static void find_probe_point_by_line(struct probe_finder *pf)
489 (int)i, lineno, (uintmax_t)addr); 602 (int)i, lineno, (uintmax_t)addr);
490 pf->addr = addr; 603 pf->addr = addr;
491 604
492 show_probe_point(NULL, pf); 605 convert_probe_point(NULL, pf);
493 /* Continuing, because target line might be inlined. */ 606 /* Continuing, because target line might be inlined. */
494 } 607 }
495} 608}
@@ -506,8 +619,7 @@ static int find_lazy_match_lines(struct list_head *head,
506 if (fd < 0) 619 if (fd < 0)
507 die("failed to open %s", fname); 620 die("failed to open %s", fname);
508 DIE_IF(fstat(fd, &st) < 0); 621 DIE_IF(fstat(fd, &st) < 0);
509 fbuf = malloc(st.st_size + 2); 622 fbuf = xmalloc(st.st_size + 2);
510 DIE_IF(fbuf == NULL);
511 DIE_IF(read(fd, fbuf, st.st_size) < 0); 623 DIE_IF(read(fd, fbuf, st.st_size) < 0);
512 close(fd); 624 close(fd);
513 fbuf[st.st_size] = '\n'; /* Dummy line */ 625 fbuf[st.st_size] = '\n'; /* Dummy line */
@@ -541,7 +653,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
541 if (list_empty(&pf->lcache)) { 653 if (list_empty(&pf->lcache)) {
542 /* Matching lazy line pattern */ 654 /* Matching lazy line pattern */
543 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 655 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
544 pf->pp->lazy_line); 656 pf->pev->point.lazy_line);
545 if (ret <= 0) 657 if (ret <= 0)
546 die("No matched lines found in %s.", pf->fname); 658 die("No matched lines found in %s.", pf->fname);
547 } 659 }
@@ -566,7 +678,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
566 if (!dwarf_haspc(sp_die, addr)) 678 if (!dwarf_haspc(sp_die, addr))
567 continue; 679 continue;
568 /* Address filtering 2: No child include addr? */ 680 /* Address filtering 2: No child include addr? */
569 if (die_get_inlinefunc(sp_die, addr, &die_mem)) 681 if (die_find_inlinefunc(sp_die, addr, &die_mem))
570 continue; 682 continue;
571 } 683 }
572 684
@@ -574,7 +686,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
574 (int)i, lineno, (unsigned long long)addr); 686 (int)i, lineno, (unsigned long long)addr);
575 pf->addr = addr; 687 pf->addr = addr;
576 688
577 show_probe_point(sp_die, pf); 689 convert_probe_point(sp_die, pf);
578 /* Continuing, because target line might be inlined. */ 690 /* Continuing, because target line might be inlined. */
579 } 691 }
580 /* TODO: deallocate lines, but how? */ 692 /* TODO: deallocate lines, but how? */
@@ -583,7 +695,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
583static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 695static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
584{ 696{
585 struct probe_finder *pf = (struct probe_finder *)data; 697 struct probe_finder *pf = (struct probe_finder *)data;
586 struct probe_point *pp = pf->pp; 698 struct perf_probe_point *pp = &pf->pev->point;
587 699
588 if (pp->lazy_line) 700 if (pp->lazy_line)
589 find_probe_point_lazy(in_die, pf); 701 find_probe_point_lazy(in_die, pf);
@@ -594,7 +706,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
594 pr_debug("found inline addr: 0x%jx\n", 706 pr_debug("found inline addr: 0x%jx\n",
595 (uintmax_t)pf->addr); 707 (uintmax_t)pf->addr);
596 708
597 show_probe_point(in_die, pf); 709 convert_probe_point(in_die, pf);
598 } 710 }
599 711
600 return DWARF_CB_OK; 712 return DWARF_CB_OK;
@@ -604,7 +716,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
604static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 716static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
605{ 717{
606 struct probe_finder *pf = (struct probe_finder *)data; 718 struct probe_finder *pf = (struct probe_finder *)data;
607 struct probe_point *pp = pf->pp; 719 struct perf_probe_point *pp = &pf->pev->point;
608 720
609 /* Check tag and diename */ 721 /* Check tag and diename */
610 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 722 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
@@ -624,7 +736,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
624 pf->addr = die_get_entrypc(sp_die); 736 pf->addr = die_get_entrypc(sp_die);
625 pf->addr += pp->offset; 737 pf->addr += pp->offset;
626 /* TODO: Check the address in this function */ 738 /* TODO: Check the address in this function */
627 show_probe_point(sp_die, pf); 739 convert_probe_point(sp_die, pf);
628 } 740 }
629 } else 741 } else
630 /* Inlined function: search instances */ 742 /* Inlined function: search instances */
@@ -638,20 +750,25 @@ static void find_probe_point_by_func(struct probe_finder *pf)
638 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); 750 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
639} 751}
640 752
641/* Find a probe point */ 753/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
642int find_probe_point(int fd, struct probe_point *pp) 754int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
755 struct kprobe_trace_event **tevs)
643{ 756{
644 struct probe_finder pf = {.pp = pp}; 757 struct probe_finder pf = {.pev = pev};
758 struct perf_probe_point *pp = &pev->point;
645 Dwarf_Off off, noff; 759 Dwarf_Off off, noff;
646 size_t cuhl; 760 size_t cuhl;
647 Dwarf_Die *diep; 761 Dwarf_Die *diep;
648 Dwarf *dbg; 762 Dwarf *dbg;
649 763
764 pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES);
765 *tevs = pf.tevs;
766 pf.ntevs = 0;
767
650 dbg = dwarf_begin(fd, DWARF_C_READ); 768 dbg = dwarf_begin(fd, DWARF_C_READ);
651 if (!dbg) 769 if (!dbg)
652 return -ENOENT; 770 return -ENOENT;
653 771
654 pp->found = 0;
655 off = 0; 772 off = 0;
656 line_list__init(&pf.lcache); 773 line_list__init(&pf.lcache);
657 /* Loop on CUs (Compilation Unit) */ 774 /* Loop on CUs (Compilation Unit) */
@@ -682,9 +799,81 @@ int find_probe_point(int fd, struct probe_point *pp)
682 line_list__free(&pf.lcache); 799 line_list__free(&pf.lcache);
683 dwarf_end(dbg); 800 dwarf_end(dbg);
684 801
685 return pp->found; 802 return pf.ntevs;
803}
804
805/* Reverse search */
806int find_perf_probe_point(int fd, unsigned long addr,
807 struct perf_probe_point *ppt)
808{
809 Dwarf_Die cudie, spdie, indie;
810 Dwarf *dbg;
811 Dwarf_Line *line;
812 Dwarf_Addr laddr, eaddr;
813 const char *tmp;
814 int lineno, ret = 0;
815
816 dbg = dwarf_begin(fd, DWARF_C_READ);
817 if (!dbg)
818 return -ENOENT;
819
820 /* Find cu die */
821 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
822 ret = -EINVAL;
823 goto end;
824 }
825
826 /* Find a corresponding line */
827 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
828 if (line) {
829 dwarf_lineaddr(line, &laddr);
830 if ((Dwarf_Addr)addr == laddr) {
831 dwarf_lineno(line, &lineno);
832 ppt->line = lineno;
833
834 tmp = dwarf_linesrc(line, NULL, NULL);
835 DIE_IF(!tmp);
836 ppt->file = xstrdup(tmp);
837 ret = 1;
838 }
839 }
840
841 /* Find a corresponding function */
842 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
843 tmp = dwarf_diename(&spdie);
844 if (!tmp)
845 goto end;
846
847 dwarf_entrypc(&spdie, &eaddr);
848 if (!lineno) {
849 /* We don't have a line number, let's use offset */
850 ppt->function = xstrdup(tmp);
851 ppt->offset = addr - (unsigned long)eaddr;
852 ret = 1;
853 goto end;
854 }
855 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) {
856 /* addr in an inline function */
857 tmp = dwarf_diename(&indie);
858 if (!tmp)
859 goto end;
860 dwarf_decl_line(&indie, &lineno);
861 } else {
862 if (eaddr == addr) /* No offset: function entry */
863 lineno = ppt->line;
864 else
865 dwarf_decl_line(&spdie, &lineno);
866 }
867 ppt->function = xstrdup(tmp);
868 ppt->line -= lineno; /* Make a relative line number */
869 }
870
871end:
872 dwarf_end(dbg);
873 return ret;
686} 874}
687 875
876
688/* Find line range from its line number */ 877/* Find line range from its line number */
689static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 878static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
690{ 879{
@@ -716,7 +905,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
716 continue; 905 continue;
717 906
718 /* Address filtering 2: No child include addr? */ 907 /* Address filtering 2: No child include addr? */
719 if (die_get_inlinefunc(sp_die, addr, &die_mem)) 908 if (die_find_inlinefunc(sp_die, addr, &die_mem))
720 continue; 909 continue;
721 } 910 }
722 911
@@ -727,7 +916,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
727 916
728 /* Copy real path */ 917 /* Copy real path */
729 if (!lf->lr->path) 918 if (!lf->lr->path)
730 lf->lr->path = strdup(src); 919 lf->lr->path = xstrdup(src);
731 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno); 920 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
732 } 921 }
733 /* Update status */ 922 /* Update status */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 21f7354397b4..3564f22954f1 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -3,6 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "util.h" 5#include "util.h"
6#include "probe-event.h"
6 7
7#define MAX_PATH_LEN 256 8#define MAX_PATH_LEN 256
8#define MAX_PROBE_BUFFER 1024 9#define MAX_PROBE_BUFFER 1024
@@ -14,67 +15,36 @@ static inline int is_c_varname(const char *name)
14 return isalpha(name[0]) || name[0] == '_'; 15 return isalpha(name[0]) || name[0] == '_';
15} 16}
16 17
17struct probe_point { 18#ifdef DWARF_SUPPORT
18 char *event; /* Event name */ 19/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
19 char *group; /* Event group */ 20extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
21 struct kprobe_trace_event **tevs);
20 22
21 /* Inputs */ 23/* Find a perf_probe_point from debuginfo */
22 char *file; /* File name */ 24extern int find_perf_probe_point(int fd, unsigned long addr,
23 int line; /* Line number */ 25 struct perf_probe_point *ppt);
24 char *lazy_line; /* Lazy line pattern */
25 26
26 char *function; /* Function name */
27 int offset; /* Offset bytes */
28
29 int nr_args; /* Number of arguments */
30 char **args; /* Arguments */
31
32 int retprobe; /* Return probe */
33
34 /* Output */
35 int found; /* Number of found probe points */
36 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
37};
38
39/* Line number container */
40struct line_node {
41 struct list_head list;
42 unsigned int line;
43};
44
45/* Line range */
46struct line_range {
47 char *file; /* File name */
48 char *function; /* Function name */
49 unsigned int start; /* Start line number */
50 unsigned int end; /* End line number */
51 int offset; /* Start line offset */
52 char *path; /* Real path name */
53 struct list_head line_list; /* Visible lines */
54};
55
56#ifndef NO_DWARF_SUPPORT
57extern int find_probe_point(int fd, struct probe_point *pp);
58extern int find_line_range(int fd, struct line_range *lr); 27extern int find_line_range(int fd, struct line_range *lr);
59 28
60#include <dwarf.h> 29#include <dwarf.h>
61#include <libdw.h> 30#include <libdw.h>
62 31
63struct probe_finder { 32struct probe_finder {
64 struct probe_point *pp; /* Target probe point */ 33 struct perf_probe_event *pev; /* Target probe event */
34 int ntevs; /* number of trace events */
35 struct kprobe_trace_event *tevs; /* Result trace events */
65 36
66 /* For function searching */ 37 /* For function searching */
67 Dwarf_Addr addr; /* Address */ 38 Dwarf_Addr addr; /* Address */
68 const char *fname; /* File name */ 39 const char *fname; /* Real file name */
69 int lno; /* Line number */ 40 int lno; /* Line number */
70 Dwarf_Die cu_die; /* Current CU */ 41 Dwarf_Die cu_die; /* Current CU */
42 struct list_head lcache; /* Line cache for lazy match */
71 43
72 /* For variable searching */ 44 /* For variable searching */
73 Dwarf_Op *fb_ops; /* Frame base attribute */ 45 Dwarf_Op *fb_ops; /* Frame base attribute */
74 const char *var; /* Current variable name */ 46 struct perf_probe_arg *pvar; /* Current target variable */
75 char *buf; /* Current output buffer */ 47 struct kprobe_trace_arg *tvar; /* Current result variable */
76 int len; /* Length of output buffer */
77 struct list_head lcache; /* Line cache for lazy match */
78}; 48};
79 49
80struct line_finder { 50struct line_finder {
@@ -87,6 +57,6 @@ struct line_finder {
87 int found; 57 int found;
88}; 58};
89 59
90#endif /* NO_DWARF_SUPPORT */ 60#endif /* DWARF_SUPPORT */
91 61
92#endif /*_PROBE_FINDER_H */ 62#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index eed1cb889008..76b4ac689df9 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -117,13 +117,13 @@ static bool symbol__match_parent_regex(struct symbol *sym)
117 return 0; 117 return 0;
118} 118}
119 119
120struct symbol **perf_session__resolve_callchain(struct perf_session *self, 120struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
121 struct thread *thread, 121 struct thread *thread,
122 struct ip_callchain *chain, 122 struct ip_callchain *chain,
123 struct symbol **parent) 123 struct symbol **parent)
124{ 124{
125 u8 cpumode = PERF_RECORD_MISC_USER; 125 u8 cpumode = PERF_RECORD_MISC_USER;
126 struct symbol **syms = NULL; 126 struct map_symbol *syms = NULL;
127 unsigned int i; 127 unsigned int i;
128 128
129 if (symbol_conf.use_callchain) { 129 if (symbol_conf.use_callchain) {
@@ -160,7 +160,8 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
160 *parent = al.sym; 160 *parent = al.sym;
161 if (!symbol_conf.use_callchain) 161 if (!symbol_conf.use_callchain)
162 break; 162 break;
163 syms[i] = al.sym; 163 syms[i].map = al.map;
164 syms[i].sym = al.sym;
164 } 165 }
165 } 166 }
166 167
@@ -543,32 +544,3 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
543 544
544 return 0; 545 return 0;
545} 546}
546
547static u64 map__reloc_map_ip(struct map *map, u64 ip)
548{
549 return ip + (s64)map->pgoff;
550}
551
552static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
553{
554 return ip - (s64)map->pgoff;
555}
556
557void map__reloc_vmlinux(struct map *self)
558{
559 struct kmap *kmap = map__kmap(self);
560 s64 reloc;
561
562 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
563 return;
564
565 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
566 kmap->ref_reloc_sym->addr);
567
568 if (!reloc)
569 return;
570
571 self->map_ip = map__reloc_map_ip;
572 self->unmap_ip = map__reloc_unmap_ip;
573 self->pgoff = reloc;
574}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 5c33417eebb3..631f8157fc17 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -57,10 +57,10 @@ int __perf_session__process_events(struct perf_session *self,
57int perf_session__process_events(struct perf_session *self, 57int perf_session__process_events(struct perf_session *self,
58 struct perf_event_ops *event_ops); 58 struct perf_event_ops *event_ops);
59 59
60struct symbol **perf_session__resolve_callchain(struct perf_session *self, 60struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
61 struct thread *thread, 61 struct thread *thread,
62 struct ip_callchain *chain, 62 struct ip_callchain *chain,
63 struct symbol **parent); 63 struct symbol **parent);
64 64
65bool perf_session__has_traces(struct perf_session *self, const char *msg); 65bool perf_session__has_traces(struct perf_session *self, const char *msg);
66 66
@@ -86,4 +86,13 @@ static inline struct map *
86{ 86{
87 return map_groups__new_module(&self->kmaps, start, filename); 87 return map_groups__new_module(&self->kmaps, start, filename);
88} 88}
89
90#ifdef NO_NEWT_SUPPORT
91static inline void perf_session__browse_hists(struct rb_root *hists __used,
92 u64 session_total __used,
93 const char *helpline __used) {}
94#else
95void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
96 const char *helpline);
97#endif
89#endif /* __PERF_SESSION_H */ 98#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cb0f327de9e8..9b80c13cae46 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -131,8 +131,8 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
131int64_t 131int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{ 133{
134 struct dso *dso_l = left->map ? left->map->dso : NULL; 134 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL; 135 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
136 const char *dso_name_l, *dso_name_r; 136 const char *dso_name_l, *dso_name_r;
137 137
138 if (!dso_l || !dso_r) 138 if (!dso_l || !dso_r)
@@ -152,9 +152,9 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
152size_t 152size_t
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) 153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
154{ 154{
155 if (self->map && self->map->dso) { 155 if (self->ms.map && self->ms.map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name : 156 const char *dso_name = !verbose ? self->ms.map->dso->short_name :
157 self->map->dso->long_name; 157 self->ms.map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name); 158 return repsep_fprintf(fp, "%-*s", width, dso_name);
159 } 159 }
160 160
@@ -168,11 +168,11 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{ 168{
169 u64 ip_l, ip_r; 169 u64 ip_l, ip_r;
170 170
171 if (left->sym == right->sym) 171 if (left->ms.sym == right->ms.sym)
172 return 0; 172 return 0;
173 173
174 ip_l = left->sym ? left->sym->start : left->ip; 174 ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip; 175 ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
176 176
177 return (int64_t)(ip_r - ip_l); 177 return (int64_t)(ip_r - ip_l);
178} 178}
@@ -184,13 +184,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
184 size_t ret = 0; 184 size_t ret = 0;
185 185
186 if (verbose) { 186 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!'; 187 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o); 188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
189 } 189 }
190 190
191 ret += repsep_fprintf(fp, "[%c] ", self->level); 191 ret += repsep_fprintf(fp, "[%c] ", self->level);
192 if (self->sym) 192 if (self->ms.sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name); 193 ret += repsep_fprintf(fp, "%s", self->ms.sym->name);
194 else 194 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); 195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
196 196
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 753f9ea99fb0..598568696f97 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -45,8 +45,7 @@ struct hist_entry {
45 struct rb_node rb_node; 45 struct rb_node rb_node;
46 u64 count; 46 u64 count;
47 struct thread *thread; 47 struct thread *thread;
48 struct map *map; 48 struct map_symbol ms;
49 struct symbol *sym;
50 u64 ip; 49 u64 ip;
51 char level; 50 char level;
52 struct symbol *parent; 51 struct symbol *parent;
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index a175949ed216..d4389242cfd7 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,49 +1,6 @@
1#include "string.h" 1#include "string.h"
2#include "util.h" 2#include "util.h"
3 3
4static int hex(char ch)
5{
6 if ((ch >= '0') && (ch <= '9'))
7 return ch - '0';
8 if ((ch >= 'a') && (ch <= 'f'))
9 return ch - 'a' + 10;
10 if ((ch >= 'A') && (ch <= 'F'))
11 return ch - 'A' + 10;
12 return -1;
13}
14
15/*
16 * While we find nice hex chars, build a long_val.
17 * Return number of chars processed.
18 */
19int hex2u64(const char *ptr, u64 *long_val)
20{
21 const char *p = ptr;
22 *long_val = 0;
23
24 while (*p) {
25 const int hex_val = hex(*p);
26
27 if (hex_val < 0)
28 break;
29
30 *long_val = (*long_val << 4) | hex_val;
31 p++;
32 }
33
34 return p - ptr;
35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
46
47#define K 1024LL 4#define K 1024LL
48/* 5/*
49 * perf_atoll() 6 * perf_atoll()
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 542e44de3719..700582416664 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -4,8 +4,6 @@
4#include <stdbool.h> 4#include <stdbool.h>
5#include "types.h" 5#include "types.h"
6 6
7int hex2u64(const char *ptr, u64 *val);
8char *strxfrchar(char *s, char from, char to);
9s64 perf_atoll(const char *str); 7s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp); 8char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv); 9void argv_free(char **argv);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c458c4a371d1..f3d4151e46a1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,13 +1,19 @@
1#include "util.h" 1#define _GNU_SOURCE
2#include "../perf.h" 2#include <ctype.h>
3#include "sort.h" 3#include <dirent.h>
4#include "string.h" 4#include <errno.h>
5#include <libgen.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <string.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <sys/param.h>
12#include <fcntl.h>
13#include <unistd.h>
5#include "symbol.h" 14#include "symbol.h"
6#include "thread.h" 15#include "strlist.h"
7 16
8#include "debug.h"
9
10#include <asm/bug.h>
11#include <libelf.h> 17#include <libelf.h>
12#include <gelf.h> 18#include <gelf.h>
13#include <elf.h> 19#include <elf.h>
@@ -18,18 +24,6 @@
18#define NT_GNU_BUILD_ID 3 24#define NT_GNU_BUILD_ID 3
19#endif 25#endif
20 26
21enum dso_origin {
22 DSO__ORIG_KERNEL = 0,
23 DSO__ORIG_JAVA_JIT,
24 DSO__ORIG_BUILD_ID_CACHE,
25 DSO__ORIG_FEDORA,
26 DSO__ORIG_UBUNTU,
27 DSO__ORIG_BUILDID,
28 DSO__ORIG_DSO,
29 DSO__ORIG_KMODULE,
30 DSO__ORIG_NOT_FOUND,
31};
32
33static void dsos__add(struct list_head *head, struct dso *dso); 27static void dsos__add(struct list_head *head, struct dso *dso);
34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 28static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 29static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -126,8 +120,8 @@ static void map_groups__fixup_end(struct map_groups *self)
126static struct symbol *symbol__new(u64 start, u64 len, const char *name) 120static struct symbol *symbol__new(u64 start, u64 len, const char *name)
127{ 121{
128 size_t namelen = strlen(name) + 1; 122 size_t namelen = strlen(name) + 1;
129 struct symbol *self = zalloc(symbol_conf.priv_size + 123 struct symbol *self = calloc(1, (symbol_conf.priv_size +
130 sizeof(*self) + namelen); 124 sizeof(*self) + namelen));
131 if (self == NULL) 125 if (self == NULL)
132 return NULL; 126 return NULL;
133 127
@@ -178,7 +172,7 @@ static void dso__set_basename(struct dso *self)
178 172
179struct dso *dso__new(const char *name) 173struct dso *dso__new(const char *name)
180{ 174{
181 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1); 175 struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
182 176
183 if (self != NULL) { 177 if (self != NULL) {
184 int i; 178 int i;
@@ -870,8 +864,8 @@ out_close:
870 if (err == 0) 864 if (err == 0)
871 return nr; 865 return nr;
872out: 866out:
873 pr_warning("%s: problems reading %s PLT info.\n", 867 pr_debug("%s: problems reading %s PLT info.\n",
874 __func__, self->long_name); 868 __func__, self->long_name);
875 return 0; 869 return 0;
876} 870}
877 871
@@ -1025,7 +1019,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1025 } 1019 }
1026 curr_map->map_ip = identity__map_ip; 1020 curr_map->map_ip = identity__map_ip;
1027 curr_map->unmap_ip = identity__map_ip; 1021 curr_map->unmap_ip = identity__map_ip;
1028 curr_dso->origin = DSO__ORIG_KERNEL; 1022 curr_dso->origin = self->origin;
1029 map_groups__insert(kmap->kmaps, curr_map); 1023 map_groups__insert(kmap->kmaps, curr_map);
1030 dsos__add(&dsos__kernel, curr_dso); 1024 dsos__add(&dsos__kernel, curr_dso);
1031 dso__set_loaded(curr_dso, map->type); 1025 dso__set_loaded(curr_dso, map->type);
@@ -1394,13 +1388,13 @@ static int dso__kernel_module_get_build_id(struct dso *self)
1394 return 0; 1388 return 0;
1395} 1389}
1396 1390
1397static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname) 1391static int map_groups__set_modules_path_dir(struct map_groups *self, char *dir_name)
1398{ 1392{
1399 struct dirent *dent; 1393 struct dirent *dent;
1400 DIR *dir = opendir(dirname); 1394 DIR *dir = opendir(dir_name);
1401 1395
1402 if (!dir) { 1396 if (!dir) {
1403 pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1397 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1404 return -1; 1398 return -1;
1405 } 1399 }
1406 1400
@@ -1413,7 +1407,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirna
1413 continue; 1407 continue;
1414 1408
1415 snprintf(path, sizeof(path), "%s/%s", 1409 snprintf(path, sizeof(path), "%s/%s",
1416 dirname, dent->d_name); 1410 dir_name, dent->d_name);
1417 if (map_groups__set_modules_path_dir(self, path) < 0) 1411 if (map_groups__set_modules_path_dir(self, path) < 0)
1418 goto failure; 1412 goto failure;
1419 } else { 1413 } else {
@@ -1433,7 +1427,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirna
1433 continue; 1427 continue;
1434 1428
1435 snprintf(path, sizeof(path), "%s/%s", 1429 snprintf(path, sizeof(path), "%s/%s",
1436 dirname, dent->d_name); 1430 dir_name, dent->d_name);
1437 1431
1438 long_name = strdup(path); 1432 long_name = strdup(path);
1439 if (long_name == NULL) 1433 if (long_name == NULL)
@@ -1470,8 +1464,8 @@ static int map_groups__set_modules_path(struct map_groups *self)
1470 */ 1464 */
1471static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1465static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1472{ 1466{
1473 struct map *self = zalloc(sizeof(*self) + 1467 struct map *self = calloc(1, (sizeof(*self) +
1474 (dso->kernel ? sizeof(struct kmap) : 0)); 1468 (dso->kernel ? sizeof(struct kmap) : 0)));
1475 if (self != NULL) { 1469 if (self != NULL) {
1476 /* 1470 /*
1477 * ->end will be filled after we load all the symbols 1471 * ->end will be filled after we load all the symbols
@@ -1895,6 +1889,17 @@ out_fail:
1895 return -1; 1889 return -1;
1896} 1890}
1897 1891
1892size_t vmlinux_path__fprintf(FILE *fp)
1893{
1894 int i;
1895 size_t printed = 0;
1896
1897 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1898 printed += fprintf(fp, "[%d] %s\n", i, vmlinux_path[i]);
1899
1900 return printed;
1901}
1902
1898static int setup_list(struct strlist **list, const char *list_str, 1903static int setup_list(struct strlist **list, const char *list_str,
1899 const char *list_name) 1904 const char *list_name)
1900{ 1905{
@@ -1964,3 +1969,46 @@ int map_groups__create_kernel_maps(struct map_groups *self,
1964 map_groups__fixup_end(self); 1969 map_groups__fixup_end(self);
1965 return 0; 1970 return 0;
1966} 1971}
1972
1973static int hex(char ch)
1974{
1975 if ((ch >= '0') && (ch <= '9'))
1976 return ch - '0';
1977 if ((ch >= 'a') && (ch <= 'f'))
1978 return ch - 'a' + 10;
1979 if ((ch >= 'A') && (ch <= 'F'))
1980 return ch - 'A' + 10;
1981 return -1;
1982}
1983
1984/*
1985 * While we find nice hex chars, build a long_val.
1986 * Return number of chars processed.
1987 */
1988int hex2u64(const char *ptr, u64 *long_val)
1989{
1990 const char *p = ptr;
1991 *long_val = 0;
1992
1993 while (*p) {
1994 const int hex_val = hex(*p);
1995
1996 if (hex_val < 0)
1997 break;
1998
1999 *long_val = (*long_val << 4) | hex_val;
2000 p++;
2001 }
2002
2003 return p - ptr;
2004}
2005
2006char *strxfrchar(char *s, char from, char to)
2007{
2008 char *p = s;
2009
2010 while ((p = strchr(p, from)) != NULL)
2011 *p++ = to;
2012
2013 return s;
2014}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index f30a37428919..757fae3f5ee0 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -3,10 +3,11 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include "types.h" 6#include <stdint.h>
7#include "map.h"
7#include <linux/list.h> 8#include <linux/list.h>
8#include <linux/rbtree.h> 9#include <linux/rbtree.h>
9#include "event.h" 10#include <stdio.h>
10 11
11#define DEBUG_CACHE_DIR ".debug" 12#define DEBUG_CACHE_DIR ".debug"
12 13
@@ -29,6 +30,9 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
29#endif 30#endif
30#endif 31#endif
31 32
33int hex2u64(const char *ptr, u64 *val);
34char *strxfrchar(char *s, char from, char to);
35
32/* 36/*
33 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; 37 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
34 * for newer versions we can use mmap to reduce memory usage: 38 * for newer versions we can use mmap to reduce memory usage:
@@ -44,6 +48,8 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
44#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 48#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
45#endif 49#endif
46 50
51#define BUILD_ID_SIZE 20
52
47struct symbol { 53struct symbol {
48 struct rb_node rb_node; 54 struct rb_node rb_node;
49 u64 start; 55 u64 start;
@@ -88,6 +94,11 @@ struct ref_reloc_sym {
88 u64 unrelocated_addr; 94 u64 unrelocated_addr;
89}; 95};
90 96
97struct map_symbol {
98 struct map *map;
99 struct symbol *sym;
100};
101
91struct addr_location { 102struct addr_location {
92 struct thread *thread; 103 struct thread *thread;
93 struct map *map; 104 struct map *map;
@@ -106,6 +117,7 @@ struct dso {
106 u8 has_build_id:1; 117 u8 has_build_id:1;
107 u8 kernel:1; 118 u8 kernel:1;
108 u8 hit:1; 119 u8 hit:1;
120 u8 annotate_warned:1;
109 unsigned char origin; 121 unsigned char origin;
110 u8 sorted_by_name; 122 u8 sorted_by_name;
111 u8 loaded; 123 u8 loaded;
@@ -150,6 +162,19 @@ size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
150 162
151size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 163size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
152size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 164size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
165
166enum dso_origin {
167 DSO__ORIG_KERNEL = 0,
168 DSO__ORIG_JAVA_JIT,
169 DSO__ORIG_BUILD_ID_CACHE,
170 DSO__ORIG_FEDORA,
171 DSO__ORIG_UBUNTU,
172 DSO__ORIG_BUILDID,
173 DSO__ORIG_DSO,
174 DSO__ORIG_KMODULE,
175 DSO__ORIG_NOT_FOUND,
176};
177
153char dso__symtab_origin(const struct dso *self); 178char dso__symtab_origin(const struct dso *self);
154void dso__set_long_name(struct dso *self, char *name); 179void dso__set_long_name(struct dso *self, char *name);
155void dso__set_build_id(struct dso *self, void *build_id); 180void dso__set_build_id(struct dso *self, void *build_id);
@@ -169,4 +194,6 @@ int kallsyms__parse(const char *filename, void *arg,
169int symbol__init(void); 194int symbol__init(void);
170bool symbol_type__is_a(char symbol_type, enum map_type map_type); 195bool symbol_type__is_a(char symbol_type, enum map_type map_type);
171 196
197size_t vmlinux_path__fprintf(FILE *fp);
198
172#endif /* __PERF_SYMBOL */ 199#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index fa968312ee7d..9bbe27d75306 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,6 +7,37 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10int find_all_tid(int pid, pid_t ** all_tid)
11{
12 char name[256];
13 int items;
14 struct dirent **namelist = NULL;
15 int ret = 0;
16 int i;
17
18 sprintf(name, "/proc/%d/task", pid);
19 items = scandir(name, &namelist, NULL, NULL);
20 if (items <= 0)
21 return -ENOENT;
22 *all_tid = malloc(sizeof(pid_t) * items);
23 if (!*all_tid) {
24 ret = -ENOMEM;
25 goto failure;
26 }
27
28 for (i = 0; i < items; i++)
29 (*all_tid)[i] = atoi(namelist[i]->d_name);
30
31 ret = items;
32
33failure:
34 for (i=0; i<items; i++)
35 free(namelist[i]);
36 free(namelist);
37
38 return ret;
39}
40
10void map_groups__init(struct map_groups *self) 41void map_groups__init(struct map_groups *self)
11{ 42{
12 int i; 43 int i;
@@ -241,46 +272,6 @@ static int map_groups__fixup_overlappings(struct map_groups *self,
241 return 0; 272 return 0;
242} 273}
243 274
244void maps__insert(struct rb_root *maps, struct map *map)
245{
246 struct rb_node **p = &maps->rb_node;
247 struct rb_node *parent = NULL;
248 const u64 ip = map->start;
249 struct map *m;
250
251 while (*p != NULL) {
252 parent = *p;
253 m = rb_entry(parent, struct map, rb_node);
254 if (ip < m->start)
255 p = &(*p)->rb_left;
256 else
257 p = &(*p)->rb_right;
258 }
259
260 rb_link_node(&map->rb_node, parent, p);
261 rb_insert_color(&map->rb_node, maps);
262}
263
264struct map *maps__find(struct rb_root *maps, u64 ip)
265{
266 struct rb_node **p = &maps->rb_node;
267 struct rb_node *parent = NULL;
268 struct map *m;
269
270 while (*p != NULL) {
271 parent = *p;
272 m = rb_entry(parent, struct map, rb_node);
273 if (ip < m->start)
274 p = &(*p)->rb_left;
275 else if (ip > m->end)
276 p = &(*p)->rb_right;
277 else
278 return m;
279 }
280
281 return NULL;
282}
283
284void thread__insert_map(struct thread *self, struct map *map) 275void thread__insert_map(struct thread *self, struct map *map)
285{ 276{
286 map_groups__fixup_overlappings(&self->mg, map); 277 map_groups__fixup_overlappings(&self->mg, map);
@@ -336,15 +327,3 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
336 327
337 return ret; 328 return ret;
338} 329}
339
340struct symbol *map_groups__find_symbol(struct map_groups *self,
341 enum map_type type, u64 addr,
342 symbol_filter_t filter)
343{
344 struct map *map = map_groups__find(self, type, addr);
345
346 if (map != NULL)
347 return map__find_symbol(map, map->map_ip(map, addr), filter);
348
349 return NULL;
350}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index dcf70303e58e..9c488fcadec9 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,14 +5,6 @@
5#include <unistd.h> 5#include <unistd.h>
6#include "symbol.h" 6#include "symbol.h"
7 7
8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES];
11};
12
13size_t __map_groups__fprintf_maps(struct map_groups *self,
14 enum map_type type, FILE *fp);
15
16struct thread { 8struct thread {
17 struct rb_node rb_node; 9 struct rb_node rb_node;
18 struct map_groups mg; 10 struct map_groups mg;
@@ -23,29 +15,16 @@ struct thread {
23 int comm_len; 15 int comm_len;
24}; 16};
25 17
26void map_groups__init(struct map_groups *self); 18struct perf_session;
19
20int find_all_tid(int pid, pid_t ** all_tid);
27int thread__set_comm(struct thread *self, const char *comm); 21int thread__set_comm(struct thread *self, const char *comm);
28int thread__comm_len(struct thread *self); 22int thread__comm_len(struct thread *self);
29struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 23struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
30void thread__insert_map(struct thread *self, struct map *map); 24void thread__insert_map(struct thread *self, struct map *map);
31int thread__fork(struct thread *self, struct thread *parent); 25int thread__fork(struct thread *self, struct thread *parent);
32size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
33size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 26size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
34 27
35void maps__insert(struct rb_root *maps, struct map *map);
36struct map *maps__find(struct rb_root *maps, u64 addr);
37
38static inline void map_groups__insert(struct map_groups *self, struct map *map)
39{
40 maps__insert(&self->maps[map->type], map);
41}
42
43static inline struct map *map_groups__find(struct map_groups *self,
44 enum map_type type, u64 addr)
45{
46 return maps__find(&self->maps[type], addr);
47}
48
49static inline struct map *thread__find_map(struct thread *self, 28static inline struct map *thread__find_map(struct thread *self,
50 enum map_type type, u64 addr) 29 enum map_type type, u64 addr)
51{ 30{
@@ -62,26 +41,4 @@ void thread__find_addr_location(struct thread *self,
62 enum map_type type, u64 addr, 41 enum map_type type, u64 addr,
63 struct addr_location *al, 42 struct addr_location *al,
64 symbol_filter_t filter); 43 symbol_filter_t filter);
65struct symbol *map_groups__find_symbol(struct map_groups *self,
66 enum map_type type, u64 addr,
67 symbol_filter_t filter);
68
69static inline struct symbol *map_groups__find_function(struct map_groups *self,
70 u64 addr,
71 symbol_filter_t filter)
72{
73 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
74}
75
76struct map *map_groups__find_by_name(struct map_groups *self,
77 enum map_type type, const char *name);
78
79int __map_groups__create_kernel_maps(struct map_groups *self,
80 struct map *vmlinux_maps[MAP__NR_TYPES],
81 struct dso *kernel);
82int map_groups__create_kernel_maps(struct map_groups *self,
83 struct map *vmlinux_maps[MAP__NR_TYPES]);
84
85struct map *map_groups__new_module(struct map_groups *self, u64 start,
86 const char *filename);
87#endif /* __PERF_THREAD_H */ 44#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f5b2a6f1080..52701087ce04 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -295,6 +295,13 @@ extern void *xmemdupz(const void *data, size_t len);
295extern char *xstrndup(const char *str, size_t len); 295extern char *xstrndup(const char *str, size_t len);
296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak)); 296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
297 297
298static inline void *xzalloc(size_t size)
299{
300 void *buf = xmalloc(size);
301
302 return memset(buf, 0, size);
303}
304
298static inline void *zalloc(size_t size) 305static inline void *zalloc(size_t size)
299{ 306{
300 return calloc(1, size); 307 return calloc(1, size);
@@ -309,6 +316,7 @@ static inline int has_extension(const char *filename, const char *ext)
309{ 316{
310 size_t len = strlen(filename); 317 size_t len = strlen(filename);
311 size_t extlen = strlen(ext); 318 size_t extlen = strlen(ext);
319
312 return len > extlen && !memcmp(filename + len - extlen, ext, extlen); 320 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
313} 321}
314 322
@@ -322,6 +330,7 @@ static inline int has_extension(const char *filename, const char *ext)
322#undef isalnum 330#undef isalnum
323#undef tolower 331#undef tolower
324#undef toupper 332#undef toupper
333
325extern unsigned char sane_ctype[256]; 334extern unsigned char sane_ctype[256];
326#define GIT_SPACE 0x01 335#define GIT_SPACE 0x01
327#define GIT_DIGIT 0x02 336#define GIT_DIGIT 0x02