aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorMichal Marek <mmarek@suse.cz>2010-08-04 07:59:13 -0400
committerMichal Marek <mmarek@suse.cz>2010-08-04 07:59:13 -0400
commit772320e84588dcbe1600ffb83e5f328f2209ac2a (patch)
treea7de21b79340aeaa17c58126f6b801b82c77b53a /tools/perf/util
parent1ce53adf13a54375d2a5c7cdbe341b2558389615 (diff)
parent9fe6206f400646a2322096b56c59891d530e8d51 (diff)
Merge commit 'v2.6.35' into kbuild/kbuild
Conflicts: arch/powerpc/Makefile
Diffstat (limited to 'tools/perf/util')
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN23
-rw-r--r--tools/perf/util/abspath.c81
-rw-r--r--tools/perf/util/bitmap.c21
-rw-r--r--tools/perf/util/build-id.c61
-rw-r--r--tools/perf/util/build-id.h10
-rw-r--r--tools/perf/util/cache.h67
-rw-r--r--tools/perf/util/callchain.c131
-rw-r--r--tools/perf/util/callchain.h14
-rw-r--r--tools/perf/util/color.c48
-rw-r--r--tools/perf/util/color.h4
-rw-r--r--tools/perf/util/config.c461
-rw-r--r--tools/perf/util/cpumap.c59
-rw-r--r--tools/perf/util/cpumap.h7
-rw-r--r--tools/perf/util/data_map.c252
-rw-r--r--tools/perf/util/debug.c9
-rw-r--r--tools/perf/util/debug.h30
-rw-r--r--tools/perf/util/debugfs.c17
-rw-r--r--tools/perf/util/debugfs.h2
-rw-r--r--tools/perf/util/event.c475
-rw-r--r--tools/perf/util/event.h130
-rw-r--r--tools/perf/util/exec_cmd.c6
-rw-r--r--tools/perf/util/exec_cmd.h1
-rw-r--r--tools/perf/util/header.c745
-rw-r--r--tools/perf/util/header.h46
-rw-r--r--tools/perf/util/help.c30
-rw-r--r--tools/perf/util/hist.c660
-rw-r--r--tools/perf/util/hist.h122
-rw-r--r--tools/perf/util/hweight.c31
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/hweight.h8
-rw-r--r--tools/perf/util/include/dwarf-regs.h8
-rw-r--r--tools/perf/util/include/linux/bitmap.h38
-rw-r--r--tools/perf/util/include/linux/bitops.h20
-rw-r--r--tools/perf/util/include/linux/compiler.h2
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h12
-rw-r--r--tools/perf/util/map.c461
-rw-r--r--tools/perf/util/map.h217
-rw-r--r--tools/perf/util/newt.c1178
-rw-r--r--tools/perf/util/parse-events.c90
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/parse-options.c55
-rw-r--r--tools/perf/util/parse-options.h29
-rw-r--r--tools/perf/util/path.c204
-rw-r--r--tools/perf/util/probe-event.c1553
-rw-r--r--tools/perf/util/probe-event.h128
-rw-r--r--tools/perf/util/probe-finder.c1616
-rw-r--r--tools/perf/util/probe-finder.h81
-rw-r--r--tools/perf/util/pstack.c75
-rw-r--r--tools/perf/util/pstack.h12
-rw-r--r--tools/perf/util/quote.c433
-rw-r--r--tools/perf/util/quote.h39
-rw-r--r--tools/perf/util/run-command.c90
-rw-r--r--tools/perf/util/run-command.h30
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c (renamed from tools/perf/util/trace-event-perl.c)118
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c594
-rw-r--r--tools/perf/util/session.c807
-rw-r--r--tools/perf/util/session.h130
-rw-r--r--tools/perf/util/sigchain.c2
-rw-r--r--tools/perf/util/sigchain.h1
-rw-r--r--tools/perf/util/sort.c153
-rw-r--r--tools/perf/util/sort.h35
-rw-r--r--tools/perf/util/strbuf.c229
-rw-r--r--tools/perf/util/strbuf.h45
-rw-r--r--tools/perf/util/string.c141
-rw-r--r--tools/perf/util/string.h17
-rw-r--r--tools/perf/util/symbol.c1030
-rw-r--r--tools/perf/util/symbol.h114
-rw-r--r--tools/perf/util/thread.c228
-rw-r--r--tools/perf/util/thread.h51
-rw-r--r--tools/perf/util/trace-event-info.c99
-rw-r--r--tools/perf/util/trace-event-parse.c142
-rw-r--r--tools/perf/util/trace-event-perl.h55
-rw-r--r--tools/perf/util/trace-event-read.c139
-rw-r--r--tools/perf/util/trace-event-scripting.c167
-rw-r--r--tools/perf/util/trace-event.h25
-rw-r--r--tools/perf/util/util.c116
-rw-r--r--tools/perf/util/util.h190
-rw-r--r--tools/perf/util/values.c1
-rw-r--r--tools/perf/util/wrapper.c110
80 files changed, 10078 insertions, 4607 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 54552a00a117..97d76562a1a0 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -1,17 +1,17 @@
1#!/bin/sh 1#!/bin/sh
2 2
3GVF=PERF-VERSION-FILE 3if [ $# -eq 1 ] ; then
4DEF_VER=v0.0.2.PERF 4 OUTPUT=$1
5fi
6
7GVF=${OUTPUT}PERF-VERSION-FILE
5 8
6LF=' 9LF='
7' 10'
8 11
9# First see if there is a version file (included in release tarballs), 12# First check if there is a .git to get the version from git describe
10# then try git-describe, then default. 13# otherwise try to get the version from the kernel makefile
11if test -f version 14if test -d ../../.git -o -f ../../.git &&
12then
13 VN=$(cat version) || VN="$DEF_VER"
14elif test -d .git -o -f .git &&
15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && 15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
16 case "$VN" in 16 case "$VN" in
17 *$LF*) (exit 1) ;; 17 *$LF*) (exit 1) ;;
@@ -23,7 +23,12 @@ elif test -d .git -o -f .git &&
23then 23then
24 VN=$(echo "$VN" | sed -e 's/-/./g'); 24 VN=$(echo "$VN" | sed -e 's/-/./g');
25else 25else
26 VN="$DEF_VER" 26 eval `grep '^VERSION\s*=' ../../Makefile|tr -d ' '`
27 eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '`
28 eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '`
29 eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '`
30
31 VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
27fi 32fi
28 33
29VN=$(expr "$VN" : v*'\(.*\)') 34VN=$(expr "$VN" : v*'\(.*\)')
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
index a791dd467261..0e76affe9c36 100644
--- a/tools/perf/util/abspath.c
+++ b/tools/perf/util/abspath.c
@@ -1,86 +1,5 @@
1#include "cache.h" 1#include "cache.h"
2 2
3/*
4 * Do not use this for inspecting *tracked* content. When path is a
5 * symlink to a directory, we do not want to say it is a directory when
6 * dealing with tracked content in the working tree.
7 */
8static int is_directory(const char *path)
9{
10 struct stat st;
11 return (!stat(path, &st) && S_ISDIR(st.st_mode));
12}
13
14/* We allow "recursive" symbolic links. Only within reason, though. */
15#define MAXDEPTH 5
16
17const char *make_absolute_path(const char *path)
18{
19 static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
20 char cwd[1024] = "";
21 int buf_index = 1, len;
22
23 int depth = MAXDEPTH;
24 char *last_elem = NULL;
25 struct stat st;
26
27 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
28 die ("Too long path: %.*s", 60, path);
29
30 while (depth--) {
31 if (!is_directory(buf)) {
32 char *last_slash = strrchr(buf, '/');
33 if (last_slash) {
34 *last_slash = '\0';
35 last_elem = xstrdup(last_slash + 1);
36 } else {
37 last_elem = xstrdup(buf);
38 *buf = '\0';
39 }
40 }
41
42 if (*buf) {
43 if (!*cwd && !getcwd(cwd, sizeof(cwd)))
44 die ("Could not get current working directory");
45
46 if (chdir(buf))
47 die ("Could not switch to '%s'", buf);
48 }
49 if (!getcwd(buf, PATH_MAX))
50 die ("Could not get current working directory");
51
52 if (last_elem) {
53 len = strlen(buf);
54
55 if (len + strlen(last_elem) + 2 > PATH_MAX)
56 die ("Too long path name: '%s/%s'",
57 buf, last_elem);
58 buf[len] = '/';
59 strcpy(buf + len + 1, last_elem);
60 free(last_elem);
61 last_elem = NULL;
62 }
63
64 if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
65 len = readlink(buf, next_buf, PATH_MAX);
66 if (len < 0)
67 die ("Invalid symlink: %s", buf);
68 if (PATH_MAX <= len)
69 die("symbolic link too long: %s", buf);
70 next_buf[len] = '\0';
71 buf = next_buf;
72 buf_index = 1 - buf_index;
73 next_buf = bufs[buf_index];
74 } else
75 break;
76 }
77
78 if (*cwd && chdir(cwd))
79 die ("Could not change back to '%s'", cwd);
80
81 return buf;
82}
83
84static const char *get_pwd_cwd(void) 3static const char *get_pwd_cwd(void)
85{ 4{
86 static char cwd[PATH_MAX + 1]; 5 static char cwd[PATH_MAX + 1];
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
new file mode 100644
index 000000000000..5e230acae1e9
--- /dev/null
+++ b/tools/perf/util/bitmap.c
@@ -0,0 +1,21 @@
1/*
2 * From lib/bitmap.c
3 * Helper functions for bitmap.h.
4 *
5 * This source code is licensed under the GNU General Public License,
6 * Version 2. See the file COPYING for more details.
7 */
8#include <linux/bitmap.h>
9
10int __bitmap_weight(const unsigned long *bitmap, int bits)
11{
12 int k, w = 0, lim = bits/BITS_PER_LONG;
13
14 for (k = 0; k < lim; k++)
15 w += hweight_long(bitmap[k]);
16
17 if (bits % BITS_PER_LONG)
18 w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
19
20 return w;
21}
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
new file mode 100644
index 000000000000..70c5cf87d020
--- /dev/null
+++ b/tools/perf/util/build-id.c
@@ -0,0 +1,61 @@
1/*
2 * build-id.c
3 *
4 * build-id support
5 *
6 * Copyright (C) 2009, 2010 Red Hat Inc.
7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "util.h"
10#include <stdio.h>
11#include "build-id.h"
12#include "event.h"
13#include "symbol.h"
14#include <linux/kernel.h>
15
16static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
17{
18 struct addr_location al;
19 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
20 struct thread *thread = perf_session__findnew(session, event->ip.pid);
21
22 if (thread == NULL) {
23 pr_err("problem processing %d event, skipping it.\n",
24 event->header.type);
25 return -1;
26 }
27
28 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
29 event->ip.pid, event->ip.ip, &al);
30
31 if (al.map != NULL)
32 al.map->dso->hit = 1;
33
34 return 0;
35}
36
37struct perf_event_ops build_id__mark_dso_hit_ops = {
38 .sample = build_id__mark_dso_hit,
39 .mmap = event__process_mmap,
40 .fork = event__process_task,
41};
42
43char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
44{
45 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
46 const char *home;
47
48 if (!self->has_build_id)
49 return NULL;
50
51 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
52 home = getenv("HOME");
53 if (bf == NULL) {
54 if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home,
55 DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0)
56 return NULL;
57 } else
58 snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home,
59 DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2);
60 return bf;
61}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
new file mode 100644
index 000000000000..5dafb00eaa06
--- /dev/null
+++ b/tools/perf/util/build-id.h
@@ -0,0 +1,10 @@
1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1
3
4#include "session.h"
5
6extern struct perf_event_ops build_id__mark_dso_hit_ops;
7
8char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
9
10#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 918eb376abe3..65fe664fddf6 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"
@@ -12,56 +13,16 @@
12 13
13#define PERF_DIR_ENVIRONMENT "PERF_DIR" 14#define PERF_DIR_ENVIRONMENT "PERF_DIR"
14#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 15#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
15#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
16#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY"
17#define INDEX_ENVIRONMENT "PERF_INDEX_FILE"
18#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE"
19#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR"
20#define CONFIG_ENVIRONMENT "PERF_CONFIG"
21#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" 16#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
22#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES" 17#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
23#define PERFATTRIBUTES_FILE ".perfattributes"
24#define INFOATTRIBUTES_FILE "info/attributes"
25#define ATTRIBUTE_MACRO_PREFIX "[attr]"
26#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" 18#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
27 19
28typedef int (*config_fn_t)(const char *, const char *, void *); 20typedef int (*config_fn_t)(const char *, const char *, void *);
29extern int perf_default_config(const char *, const char *, void *); 21extern int perf_default_config(const char *, const char *, void *);
30extern int perf_config_from_file(config_fn_t fn, const char *, void *);
31extern int perf_config(config_fn_t fn, void *); 22extern int perf_config(config_fn_t fn, void *);
32extern int perf_parse_ulong(const char *, unsigned long *);
33extern int perf_config_int(const char *, const char *); 23extern int perf_config_int(const char *, const char *);
34extern unsigned long perf_config_ulong(const char *, const char *);
35extern int perf_config_bool_or_int(const char *, const char *, int *);
36extern int perf_config_bool(const char *, const char *); 24extern int perf_config_bool(const char *, const char *);
37extern int perf_config_string(const char **, const char *, const char *);
38extern int perf_config_set(const char *, const char *);
39extern int perf_config_set_multivar(const char *, const char *, const char *, int);
40extern int perf_config_rename_section(const char *, const char *);
41extern const char *perf_etc_perfconfig(void);
42extern int check_repository_format_version(const char *var, const char *value, void *cb);
43extern int perf_config_system(void);
44extern int perf_config_global(void);
45extern int config_error_nonbool(const char *); 25extern int config_error_nonbool(const char *);
46extern const char *config_exclusive_filename;
47
48#define MAX_PERFNAME (1000)
49extern char perf_default_email[MAX_PERFNAME];
50extern char perf_default_name[MAX_PERFNAME];
51extern int user_ident_explicitly_given;
52
53extern const char *perf_log_output_encoding;
54extern const char *perf_mailmap_file;
55
56/* IO helper functions */
57extern void maybe_flush_or_die(FILE *, const char *);
58extern int copy_fd(int ifd, int ofd);
59extern int copy_file(const char *dst, const char *src, int mode);
60extern ssize_t write_in_full(int fd, const void *buf, size_t count);
61extern void write_or_die(int fd, const void *buf, size_t count);
62extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
63extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
64extern void fsync_or_die(int fd, const char *);
65 26
66/* pager.c */ 27/* pager.c */
67extern void setup_pager(void); 28extern void setup_pager(void);
@@ -69,8 +30,18 @@ extern const char *pager_program;
69extern int pager_in_use(void); 30extern int pager_in_use(void);
70extern int pager_use_color; 31extern int pager_use_color;
71 32
72extern const char *editor_program; 33extern int use_browser;
73extern const char *excludes_file; 34
35#ifdef NO_NEWT_SUPPORT
36static inline void setup_browser(void)
37{
38 setup_pager();
39}
40static inline void exit_browser(bool wait_for_ok __used) {}
41#else
42void setup_browser(void);
43void exit_browser(bool wait_for_ok);
44#endif
74 45
75char *alias_lookup(const char *alias); 46char *alias_lookup(const char *alias);
76int split_cmdline(char *cmdline, const char ***argv); 47int split_cmdline(char *cmdline, const char ***argv);
@@ -101,22 +72,12 @@ static inline int is_absolute_path(const char *path)
101 return path[0] == '/'; 72 return path[0] == '/';
102} 73}
103 74
104const char *make_absolute_path(const char *path);
105const char *make_nonrelative_path(const char *path); 75const char *make_nonrelative_path(const char *path);
106const char *make_relative_path(const char *abs, const char *base);
107int normalize_path_copy(char *dst, const char *src);
108int longest_ancestor_length(const char *path, const char *prefix_list);
109char *strip_path_suffix(const char *path, const char *suffix); 76char *strip_path_suffix(const char *path, const char *suffix);
110 77
111extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 78extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
112extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 79extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
113/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
114extern int perf_mkstemp(char *path, size_t len, const char *template);
115 80
116extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
117 __attribute__((format (printf, 3, 4)));
118extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
119 __attribute__((format (printf, 3, 4)));
120extern char *perf_pathdup(const char *fmt, ...) 81extern char *perf_pathdup(const char *fmt, ...)
121 __attribute__((format (printf, 1, 2))); 82 __attribute__((format (printf, 1, 2)));
122 83
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index b3b71258272a..52c777e451ed 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.
@@ -15,8 +15,16 @@
15#include <errno.h> 15#include <errno.h>
16#include <math.h> 16#include <math.h>
17 17
18#include "util.h"
18#include "callchain.h" 19#include "callchain.h"
19 20
21bool ip_callchain__valid(struct ip_callchain *chain, event_t *event)
22{
23 unsigned int chain_size = event->header.size;
24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
25 return chain->nr * sizeof(u64) <= chain_size;
26}
27
20#define chain_for_each_child(child, parent) \ 28#define chain_for_each_child(child, parent) \
21 list_for_each_entry(child, &parent->children, brothers) 29 list_for_each_entry(child, &parent->children, brothers)
22 30
@@ -160,7 +168,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
160{ 168{
161 struct callchain_node *new; 169 struct callchain_node *new;
162 170
163 new = malloc(sizeof(*new)); 171 new = zalloc(sizeof(*new));
164 if (!new) { 172 if (!new) {
165 perror("not enough memory to create child for code path tree"); 173 perror("not enough memory to create child for code path tree");
166 return NULL; 174 return NULL;
@@ -183,25 +191,36 @@ create_child(struct callchain_node *parent, bool inherit_children)
183 return new; 191 return new;
184} 192}
185 193
194
195struct resolved_ip {
196 u64 ip;
197 struct map_symbol ms;
198};
199
200struct resolved_chain {
201 u64 nr;
202 struct resolved_ip ips[0];
203};
204
205
186/* 206/*
187 * Fill the node with callchain values 207 * Fill the node with callchain values
188 */ 208 */
189static void 209static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain, 210fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
191 int start, struct symbol **syms)
192{ 211{
193 unsigned int i; 212 unsigned int i;
194 213
195 for (i = start; i < chain->nr; i++) { 214 for (i = start; i < chain->nr; i++) {
196 struct callchain_list *call; 215 struct callchain_list *call;
197 216
198 call = malloc(sizeof(*call)); 217 call = zalloc(sizeof(*call));
199 if (!call) { 218 if (!call) {
200 perror("not enough memory for the code path tree"); 219 perror("not enough memory for the code path tree");
201 return; 220 return;
202 } 221 }
203 call->ip = chain->ips[i]; 222 call->ip = chain->ips[i].ip;
204 call->sym = syms[i]; 223 call->ms = chain->ips[i].ms;
205 list_add_tail(&call->list, &node->val); 224 list_add_tail(&call->list, &node->val);
206 } 225 }
207 node->val_nr = chain->nr - start; 226 node->val_nr = chain->nr - start;
@@ -210,16 +229,16 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
210} 229}
211 230
212static void 231static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain, 232add_child(struct callchain_node *parent, struct resolved_chain *chain,
214 int start, struct symbol **syms) 233 int start, u64 period)
215{ 234{
216 struct callchain_node *new; 235 struct callchain_node *new;
217 236
218 new = create_child(parent, false); 237 new = create_child(parent, false);
219 fill_node(new, chain, start, syms); 238 fill_node(new, chain, start);
220 239
221 new->children_hit = 0; 240 new->children_hit = 0;
222 new->hit = 1; 241 new->hit = period;
223} 242}
224 243
225/* 244/*
@@ -228,9 +247,9 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
228 * Then create another child to host the given callchain of new branch 247 * Then create another child to host the given callchain of new branch
229 */ 248 */
230static void 249static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain, 250split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local, 251 struct callchain_list *to_split, int idx_parents, int idx_local,
233 struct symbol **syms) 252 u64 period)
234{ 253{
235 struct callchain_node *new; 254 struct callchain_node *new;
236 struct list_head *old_tail; 255 struct list_head *old_tail;
@@ -257,40 +276,41 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
257 /* create a new child for the new branch if any */ 276 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) { 277 if (idx_total < chain->nr) {
259 parent->hit = 0; 278 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms); 279 add_child(parent, chain, idx_total, period);
261 parent->children_hit++; 280 parent->children_hit += period;
262 } else { 281 } else {
263 parent->hit = 1; 282 parent->hit = period;
264 } 283 }
265} 284}
266 285
267static int 286static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain, 287__append_chain(struct callchain_node *root, struct resolved_chain *chain,
269 unsigned int start, struct symbol **syms); 288 unsigned int start, u64 period);
270 289
271static void 290static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain, 291__append_chain_children(struct callchain_node *root,
273 struct symbol **syms, unsigned int start) 292 struct resolved_chain *chain,
293 unsigned int start, u64 period)
274{ 294{
275 struct callchain_node *rnode; 295 struct callchain_node *rnode;
276 296
277 /* lookup in childrens */ 297 /* lookup in childrens */
278 chain_for_each_child(rnode, root) { 298 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms); 299 unsigned int ret = __append_chain(rnode, chain, start, period);
280 300
281 if (!ret) 301 if (!ret)
282 goto inc_children_hit; 302 goto inc_children_hit;
283 } 303 }
284 /* nothing in children, add to the current node */ 304 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms); 305 add_child(root, chain, start, period);
286 306
287inc_children_hit: 307inc_children_hit:
288 root->children_hit++; 308 root->children_hit += period;
289} 309}
290 310
291static int 311static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain, 312__append_chain(struct callchain_node *root, struct resolved_chain *chain,
293 unsigned int start, struct symbol **syms) 313 unsigned int start, u64 period)
294{ 314{
295 struct callchain_list *cnode; 315 struct callchain_list *cnode;
296 unsigned int i = start; 316 unsigned int i = start;
@@ -302,13 +322,19 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
302 * anywhere inside a function. 322 * anywhere inside a function.
303 */ 323 */
304 list_for_each_entry(cnode, &root->val, list) { 324 list_for_each_entry(cnode, &root->val, list) {
325 struct symbol *sym;
326
305 if (i == chain->nr) 327 if (i == chain->nr)
306 break; 328 break;
307 if (cnode->sym && syms[i]) { 329
308 if (cnode->sym->start != syms[i]->start) 330 sym = chain->ips[i].ms.sym;
331
332 if (cnode->ms.sym && sym) {
333 if (cnode->ms.sym->start != sym->start)
309 break; 334 break;
310 } else if (cnode->ip != chain->ips[i]) 335 } else if (cnode->ip != chain->ips[i].ip)
311 break; 336 break;
337
312 if (!found) 338 if (!found)
313 found = true; 339 found = true;
314 i++; 340 i++;
@@ -320,26 +346,61 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
320 346
321 /* we match only a part of the node. Split it and add the new chain */ 347 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) { 348 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms); 349 split_add_child(root, chain, cnode, start, i - start, period);
324 return 0; 350 return 0;
325 } 351 }
326 352
327 /* we match 100% of the path, increment the hit */ 353 /* we match 100% of the path, increment the hit */
328 if (i - start == root->val_nr && i == chain->nr) { 354 if (i - start == root->val_nr && i == chain->nr) {
329 root->hit++; 355 root->hit += period;
330 return 0; 356 return 0;
331 } 357 }
332 358
333 /* We match the node and still have a part remaining */ 359 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i); 360 __append_chain_children(root, chain, i, period);
335 361
336 return 0; 362 return 0;
337} 363}
338 364
339void append_chain(struct callchain_node *root, struct ip_callchain *chain, 365static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
340 struct symbol **syms) 366 struct map_symbol *syms)
341{ 367{
368 int i, j = 0;
369
370 for (i = 0; i < (int)old->nr; i++) {
371 if (old->ips[i] >= PERF_CONTEXT_MAX)
372 continue;
373
374 new->ips[j].ip = old->ips[i];
375 new->ips[j].ms = syms[i];
376 j++;
377 }
378
379 new->nr = j;
380}
381
382
383int append_chain(struct callchain_node *root, struct ip_callchain *chain,
384 struct map_symbol *syms, u64 period)
385{
386 struct resolved_chain *filtered;
387
342 if (!chain->nr) 388 if (!chain->nr)
343 return; 389 return 0;
344 __append_chain_children(root, chain, syms, 0); 390
391 filtered = zalloc(sizeof(*filtered) +
392 chain->nr * sizeof(struct resolved_ip));
393 if (!filtered)
394 return -ENOMEM;
395
396 filter_context(chain, filtered, syms);
397
398 if (!filtered->nr)
399 goto end;
400
401 __append_chain_children(root, filtered, 0, period);
402end:
403 free(filtered);
404
405 return 0;
345} 406}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index ad4626de4c2b..f2e9ee164bd8 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -4,7 +4,7 @@
4#include "../perf.h" 4#include "../perf.h"
5#include <linux/list.h> 5#include <linux/list.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include "util.h" 7#include "event.h"
8#include "symbol.h" 8#include "symbol.h"
9 9
10enum chain_mode { 10enum chain_mode {
@@ -33,13 +33,14 @@ typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
33 33
34struct callchain_param { 34struct callchain_param {
35 enum chain_mode mode; 35 enum chain_mode mode;
36 u32 print_limit;
36 double min_percent; 37 double min_percent;
37 sort_chain_func_t sort; 38 sort_chain_func_t sort;
38}; 39};
39 40
40struct callchain_list { 41struct callchain_list {
41 u64 ip; 42 u64 ip;
42 struct symbol *sym; 43 struct map_symbol ms;
43 struct list_head list; 44 struct list_head list;
44}; 45};
45 46
@@ -48,6 +49,9 @@ static inline void callchain_init(struct callchain_node *node)
48 INIT_LIST_HEAD(&node->brothers); 49 INIT_LIST_HEAD(&node->brothers);
49 INIT_LIST_HEAD(&node->children); 50 INIT_LIST_HEAD(&node->children);
50 INIT_LIST_HEAD(&node->val); 51 INIT_LIST_HEAD(&node->val);
52
53 node->parent = NULL;
54 node->hit = 0;
51} 55}
52 56
53static inline u64 cumul_hits(struct callchain_node *node) 57static inline u64 cumul_hits(struct callchain_node *node)
@@ -56,6 +60,8 @@ static inline u64 cumul_hits(struct callchain_node *node)
56} 60}
57 61
58int register_callchain_param(struct callchain_param *param); 62int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 63int append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 64 struct map_symbol *syms, u64 period);
65
66bool ip_callchain__valid(struct ip_callchain *chain, event_t *event);
61#endif /* __PERF_CALLCHAIN_H */ 67#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e88bca55a599..e191eb9a667f 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -166,6 +166,31 @@ int perf_color_default_config(const char *var, const char *value, void *cb)
166 return perf_default_config(var, value, cb); 166 return perf_default_config(var, value, cb);
167} 167}
168 168
169static int __color_vsnprintf(char *bf, size_t size, const char *color,
170 const char *fmt, va_list args, const char *trail)
171{
172 int r = 0;
173
174 /*
175 * Auto-detect:
176 */
177 if (perf_use_color_default < 0) {
178 if (isatty(1) || pager_in_use())
179 perf_use_color_default = 1;
180 else
181 perf_use_color_default = 0;
182 }
183
184 if (perf_use_color_default && *color)
185 r += snprintf(bf, size, "%s", color);
186 r += vsnprintf(bf + r, size - r, fmt, args);
187 if (perf_use_color_default && *color)
188 r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
189 if (trail)
190 r += snprintf(bf + r, size - r, "%s", trail);
191 return r;
192}
193
169static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, 194static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
170 va_list args, const char *trail) 195 va_list args, const char *trail)
171{ 196{
@@ -191,11 +216,28 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
191 return r; 216 return r;
192} 217}
193 218
219int color_vsnprintf(char *bf, size_t size, const char *color,
220 const char *fmt, va_list args)
221{
222 return __color_vsnprintf(bf, size, color, fmt, args, NULL);
223}
224
194int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) 225int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
195{ 226{
196 return __color_vfprintf(fp, color, fmt, args, NULL); 227 return __color_vfprintf(fp, color, fmt, args, NULL);
197} 228}
198 229
230int color_snprintf(char *bf, size_t size, const char *color,
231 const char *fmt, ...)
232{
233 va_list args;
234 int r;
235
236 va_start(args, fmt);
237 r = color_vsnprintf(bf, size, color, fmt, args);
238 va_end(args);
239 return r;
240}
199 241
200int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) 242int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
201{ 243{
@@ -274,3 +316,9 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
274 316
275 return r; 317 return r;
276} 318}
319
320int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent)
321{
322 const char *color = get_percent_color(percent);
323 return color_snprintf(bf, size, color, fmt, percent);
324}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 24e8809210bb..dea082b79602 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -32,10 +32,14 @@ int perf_color_default_config(const char *var, const char *value, void *cb);
32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); 32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
33void color_parse(const char *value, const char *var, char *dst); 33void color_parse(const char *value, const char *var, char *dst);
34void color_parse_mem(const char *value, int len, const char *var, char *dst); 34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_vsnprintf(char *bf, size_t size, const char *color,
36 const char *fmt, va_list args);
35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); 37int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 38int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
37int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
38int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent);
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 43int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 44const char *get_percent_color(double percent);
41 45
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 8784649109ce..dabe892d0e53 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -16,7 +16,7 @@ static const char *config_file_name;
16static int config_linenr; 16static int config_linenr;
17static int config_file_eof; 17static int config_file_eof;
18 18
19const char *config_exclusive_filename = NULL; 19static const char *config_exclusive_filename;
20 20
21static int get_next_char(void) 21static int get_next_char(void)
22{ 22{
@@ -291,19 +291,6 @@ static int perf_parse_long(const char *value, long *ret)
291 return 0; 291 return 0;
292} 292}
293 293
294int perf_parse_ulong(const char *value, unsigned long *ret)
295{
296 if (value && *value) {
297 char *end;
298 unsigned long val = strtoul(value, &end, 0);
299 if (!parse_unit_factor(end, &val))
300 return 0;
301 *ret = val;
302 return 1;
303 }
304 return 0;
305}
306
307static void die_bad_config(const char *name) 294static void die_bad_config(const char *name)
308{ 295{
309 if (config_file_name) 296 if (config_file_name)
@@ -319,15 +306,7 @@ int perf_config_int(const char *name, const char *value)
319 return ret; 306 return ret;
320} 307}
321 308
322unsigned long perf_config_ulong(const char *name, const char *value) 309static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
323{
324 unsigned long ret;
325 if (!perf_parse_ulong(value, &ret))
326 die_bad_config(name);
327 return ret;
328}
329
330int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
331{ 310{
332 *is_bool = 1; 311 *is_bool = 1;
333 if (!value) 312 if (!value)
@@ -348,14 +327,6 @@ int perf_config_bool(const char *name, const char *value)
348 return !!perf_config_bool_or_int(name, value, &discard); 327 return !!perf_config_bool_or_int(name, value, &discard);
349} 328}
350 329
351int perf_config_string(const char **dest, const char *var, const char *value)
352{
353 if (!value)
354 return config_error_nonbool(var);
355 *dest = strdup(value);
356 return 0;
357}
358
359static int perf_default_core_config(const char *var __used, const char *value __used) 330static int perf_default_core_config(const char *var __used, const char *value __used)
360{ 331{
361 /* Add other config variables here and to Documentation/config.txt. */ 332 /* Add other config variables here and to Documentation/config.txt. */
@@ -371,7 +342,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)
371 return 0; 342 return 0;
372} 343}
373 344
374int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 345static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
375{ 346{
376 int ret; 347 int ret;
377 FILE *f = fopen(filename, "r"); 348 FILE *f = fopen(filename, "r");
@@ -389,7 +360,7 @@ int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
389 return ret; 360 return ret;
390} 361}
391 362
392const char *perf_etc_perfconfig(void) 363static const char *perf_etc_perfconfig(void)
393{ 364{
394 static const char *system_wide; 365 static const char *system_wide;
395 if (!system_wide) 366 if (!system_wide)
@@ -403,12 +374,12 @@ static int perf_env_bool(const char *k, int def)
403 return v ? perf_config_bool(k, v) : def; 374 return v ? perf_config_bool(k, v) : def;
404} 375}
405 376
406int perf_config_system(void) 377static int perf_config_system(void)
407{ 378{
408 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 379 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
409} 380}
410 381
411int perf_config_global(void) 382static int perf_config_global(void)
412{ 383{
413 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 384 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
414} 385}
@@ -450,426 +421,6 @@ int perf_config(config_fn_t fn, void *data)
450} 421}
451 422
452/* 423/*
453 * Find all the stuff for perf_config_set() below.
454 */
455
456#define MAX_MATCHES 512
457
458static struct {
459 int baselen;
460 char* key;
461 int do_not_match;
462 regex_t* value_regex;
463 int multi_replace;
464 size_t offset[MAX_MATCHES];
465 enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
466 int seen;
467} store;
468
469static int matches(const char* key, const char* value)
470{
471 return !strcmp(key, store.key) &&
472 (store.value_regex == NULL ||
473 (store.do_not_match ^
474 !regexec(store.value_regex, value, 0, NULL, 0)));
475}
476
477static int store_aux(const char* key, const char* value, void *cb __used)
478{
479 int section_len;
480 const char *ep;
481
482 switch (store.state) {
483 case KEY_SEEN:
484 if (matches(key, value)) {
485 if (store.seen == 1 && store.multi_replace == 0) {
486 warning("%s has multiple values", key);
487 } else if (store.seen >= MAX_MATCHES) {
488 error("too many matches for %s", key);
489 return 1;
490 }
491
492 store.offset[store.seen] = ftell(config_file);
493 store.seen++;
494 }
495 break;
496 case SECTION_SEEN:
497 /*
498 * What we are looking for is in store.key (both
499 * section and var), and its section part is baselen
500 * long. We found key (again, both section and var).
501 * We would want to know if this key is in the same
502 * section as what we are looking for. We already
503 * know we are in the same section as what should
504 * hold store.key.
505 */
506 ep = strrchr(key, '.');
507 section_len = ep - key;
508
509 if ((section_len != store.baselen) ||
510 memcmp(key, store.key, section_len+1)) {
511 store.state = SECTION_END_SEEN;
512 break;
513 }
514
515 /*
516 * Do not increment matches: this is no match, but we
517 * just made sure we are in the desired section.
518 */
519 store.offset[store.seen] = ftell(config_file);
520 /* fallthru */
521 case SECTION_END_SEEN:
522 case START:
523 if (matches(key, value)) {
524 store.offset[store.seen] = ftell(config_file);
525 store.state = KEY_SEEN;
526 store.seen++;
527 } else {
528 if (strrchr(key, '.') - key == store.baselen &&
529 !strncmp(key, store.key, store.baselen)) {
530 store.state = SECTION_SEEN;
531 store.offset[store.seen] = ftell(config_file);
532 }
533 }
534 default:
535 break;
536 }
537 return 0;
538}
539
540static int store_write_section(int fd, const char* key)
541{
542 const char *dot;
543 int i, success;
544 struct strbuf sb = STRBUF_INIT;
545
546 dot = memchr(key, '.', store.baselen);
547 if (dot) {
548 strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
549 for (i = dot - key + 1; i < store.baselen; i++) {
550 if (key[i] == '"' || key[i] == '\\')
551 strbuf_addch(&sb, '\\');
552 strbuf_addch(&sb, key[i]);
553 }
554 strbuf_addstr(&sb, "\"]\n");
555 } else {
556 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
557 }
558
559 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
560 strbuf_release(&sb);
561
562 return success;
563}
564
565static int store_write_pair(int fd, const char* key, const char* value)
566{
567 int i, success;
568 int length = strlen(key + store.baselen + 1);
569 const char *quote = "";
570 struct strbuf sb = STRBUF_INIT;
571
572 /*
573 * Check to see if the value needs to be surrounded with a dq pair.
574 * Note that problematic characters are always backslash-quoted; this
575 * check is about not losing leading or trailing SP and strings that
576 * follow beginning-of-comment characters (i.e. ';' and '#') by the
577 * configuration parser.
578 */
579 if (value[0] == ' ')
580 quote = "\"";
581 for (i = 0; value[i]; i++)
582 if (value[i] == ';' || value[i] == '#')
583 quote = "\"";
584 if (i && value[i - 1] == ' ')
585 quote = "\"";
586
587 strbuf_addf(&sb, "\t%.*s = %s",
588 length, key + store.baselen + 1, quote);
589
590 for (i = 0; value[i]; i++)
591 switch (value[i]) {
592 case '\n':
593 strbuf_addstr(&sb, "\\n");
594 break;
595 case '\t':
596 strbuf_addstr(&sb, "\\t");
597 break;
598 case '"':
599 case '\\':
600 strbuf_addch(&sb, '\\');
601 default:
602 strbuf_addch(&sb, value[i]);
603 break;
604 }
605 strbuf_addf(&sb, "%s\n", quote);
606
607 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
608 strbuf_release(&sb);
609
610 return success;
611}
612
613static ssize_t find_beginning_of_line(const char* contents, size_t size,
614 size_t offset_, int* found_bracket)
615{
616 size_t equal_offset = size, bracket_offset = size;
617 ssize_t offset;
618
619contline:
620 for (offset = offset_-2; offset > 0
621 && contents[offset] != '\n'; offset--)
622 switch (contents[offset]) {
623 case '=': equal_offset = offset; break;
624 case ']': bracket_offset = offset; break;
625 default: break;
626 }
627 if (offset > 0 && contents[offset-1] == '\\') {
628 offset_ = offset;
629 goto contline;
630 }
631 if (bracket_offset < equal_offset) {
632 *found_bracket = 1;
633 offset = bracket_offset+1;
634 } else
635 offset++;
636
637 return offset;
638}
639
640int perf_config_set(const char* key, const char* value)
641{
642 return perf_config_set_multivar(key, value, NULL, 0);
643}
644
645/*
646 * If value==NULL, unset in (remove from) config,
647 * if value_regex!=NULL, disregard key/value pairs where value does not match.
648 * if multi_replace==0, nothing, or only one matching key/value is replaced,
649 * else all matching key/values (regardless how many) are removed,
650 * before the new pair is written.
651 *
652 * Returns 0 on success.
653 *
654 * This function does this:
655 *
656 * - it locks the config file by creating ".perf/config.lock"
657 *
658 * - it then parses the config using store_aux() as validator to find
659 * the position on the key/value pair to replace. If it is to be unset,
660 * it must be found exactly once.
661 *
662 * - the config file is mmap()ed and the part before the match (if any) is
663 * written to the lock file, then the changed part and the rest.
664 *
665 * - the config file is removed and the lock file rename()d to it.
666 *
667 */
668int perf_config_set_multivar(const char* key, const char* value,
669 const char* value_regex, int multi_replace)
670{
671 int i, dot;
672 int fd = -1, in_fd;
673 int ret = 0;
674 char* config_filename;
675 const char* last_dot = strrchr(key, '.');
676
677 if (config_exclusive_filename)
678 config_filename = strdup(config_exclusive_filename);
679 else
680 config_filename = perf_pathdup("config");
681
682 /*
683 * Since "key" actually contains the section name and the real
684 * key name separated by a dot, we have to know where the dot is.
685 */
686
687 if (last_dot == NULL) {
688 error("key does not contain a section: %s", key);
689 ret = 2;
690 goto out_free;
691 }
692 store.baselen = last_dot - key;
693
694 store.multi_replace = multi_replace;
695
696 /*
697 * Validate the key and while at it, lower case it for matching.
698 */
699 store.key = malloc(strlen(key) + 1);
700 dot = 0;
701 for (i = 0; key[i]; i++) {
702 unsigned char c = key[i];
703 if (c == '.')
704 dot = 1;
705 /* Leave the extended basename untouched.. */
706 if (!dot || i > store.baselen) {
707 if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
708 error("invalid key: %s", key);
709 free(store.key);
710 ret = 1;
711 goto out_free;
712 }
713 c = tolower(c);
714 } else if (c == '\n') {
715 error("invalid key (newline): %s", key);
716 free(store.key);
717 ret = 1;
718 goto out_free;
719 }
720 store.key[i] = c;
721 }
722 store.key[i] = 0;
723
724 /*
725 * If .perf/config does not exist yet, write a minimal version.
726 */
727 in_fd = open(config_filename, O_RDONLY);
728 if ( in_fd < 0 ) {
729 free(store.key);
730
731 if ( ENOENT != errno ) {
732 error("opening %s: %s", config_filename,
733 strerror(errno));
734 ret = 3; /* same as "invalid config file" */
735 goto out_free;
736 }
737 /* if nothing to unset, error out */
738 if (value == NULL) {
739 ret = 5;
740 goto out_free;
741 }
742
743 store.key = (char*)key;
744 if (!store_write_section(fd, key) ||
745 !store_write_pair(fd, key, value))
746 goto write_err_out;
747 } else {
748 struct stat st;
749 char *contents;
750 ssize_t contents_sz, copy_begin, copy_end;
751 int new_line = 0;
752
753 if (value_regex == NULL)
754 store.value_regex = NULL;
755 else {
756 if (value_regex[0] == '!') {
757 store.do_not_match = 1;
758 value_regex++;
759 } else
760 store.do_not_match = 0;
761
762 store.value_regex = (regex_t*)malloc(sizeof(regex_t));
763 if (regcomp(store.value_regex, value_regex,
764 REG_EXTENDED)) {
765 error("invalid pattern: %s", value_regex);
766 free(store.value_regex);
767 ret = 6;
768 goto out_free;
769 }
770 }
771
772 store.offset[0] = 0;
773 store.state = START;
774 store.seen = 0;
775
776 /*
777 * After this, store.offset will contain the *end* offset
778 * of the last match, or remain at 0 if no match was found.
779 * As a side effect, we make sure to transform only a valid
780 * existing config file.
781 */
782 if (perf_config_from_file(store_aux, config_filename, NULL)) {
783 error("invalid config file %s", config_filename);
784 free(store.key);
785 if (store.value_regex != NULL) {
786 regfree(store.value_regex);
787 free(store.value_regex);
788 }
789 ret = 3;
790 goto out_free;
791 }
792
793 free(store.key);
794 if (store.value_regex != NULL) {
795 regfree(store.value_regex);
796 free(store.value_regex);
797 }
798
799 /* if nothing to unset, or too many matches, error out */
800 if ((store.seen == 0 && value == NULL) ||
801 (store.seen > 1 && multi_replace == 0)) {
802 ret = 5;
803 goto out_free;
804 }
805
806 fstat(in_fd, &st);
807 contents_sz = xsize_t(st.st_size);
808 contents = mmap(NULL, contents_sz, PROT_READ,
809 MAP_PRIVATE, in_fd, 0);
810 close(in_fd);
811
812 if (store.seen == 0)
813 store.seen = 1;
814
815 for (i = 0, copy_begin = 0; i < store.seen; i++) {
816 if (store.offset[i] == 0) {
817 store.offset[i] = copy_end = contents_sz;
818 } else if (store.state != KEY_SEEN) {
819 copy_end = store.offset[i];
820 } else
821 copy_end = find_beginning_of_line(
822 contents, contents_sz,
823 store.offset[i]-2, &new_line);
824
825 if (copy_end > 0 && contents[copy_end-1] != '\n')
826 new_line = 1;
827
828 /* write the first part of the config */
829 if (copy_end > copy_begin) {
830 if (write_in_full(fd, contents + copy_begin,
831 copy_end - copy_begin) <
832 copy_end - copy_begin)
833 goto write_err_out;
834 if (new_line &&
835 write_in_full(fd, "\n", 1) != 1)
836 goto write_err_out;
837 }
838 copy_begin = store.offset[i];
839 }
840
841 /* write the pair (value == NULL means unset) */
842 if (value != NULL) {
843 if (store.state == START) {
844 if (!store_write_section(fd, key))
845 goto write_err_out;
846 }
847 if (!store_write_pair(fd, key, value))
848 goto write_err_out;
849 }
850
851 /* write the rest of the config */
852 if (copy_begin < contents_sz)
853 if (write_in_full(fd, contents + copy_begin,
854 contents_sz - copy_begin) <
855 contents_sz - copy_begin)
856 goto write_err_out;
857
858 munmap(contents, contents_sz);
859 }
860
861 ret = 0;
862
863out_free:
864 free(config_filename);
865 return ret;
866
867write_err_out:
868 goto out_free;
869
870}
871
872/*
873 * Call this to report error for your variable that should not 424 * Call this to report error for your variable that should not
874 * get a boolean value (i.e. "[my] var" means "true"). 425 * get a boolean value (i.e. "[my] var" means "true").
875 */ 426 */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
new file mode 100644
index 000000000000..4e01490e51e5
--- /dev/null
+++ b/tools/perf/util/cpumap.c
@@ -0,0 +1,59 @@
1#include "util.h"
2#include "../perf.h"
3#include "cpumap.h"
4#include <assert.h>
5#include <stdio.h>
6
7int cpumap[MAX_NR_CPUS];
8
9static int default_cpu_map(void)
10{
11 int nr_cpus, i;
12
13 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14 assert(nr_cpus <= MAX_NR_CPUS);
15 assert((int)nr_cpus >= 0);
16
17 for (i = 0; i < nr_cpus; ++i)
18 cpumap[i] = i;
19
20 return nr_cpus;
21}
22
23int read_cpu_map(void)
24{
25 FILE *onlnf;
26 int nr_cpus = 0;
27 int n, cpu, prev;
28 char sep;
29
30 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 if (!onlnf)
32 return default_cpu_map();
33
34 sep = 0;
35 prev = -1;
36 for (;;) {
37 n = fscanf(onlnf, "%u%c", &cpu, &sep);
38 if (n <= 0)
39 break;
40 if (prev >= 0) {
41 assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS);
42 while (++prev < cpu)
43 cpumap[nr_cpus++] = prev;
44 }
45 assert (nr_cpus < MAX_NR_CPUS);
46 cpumap[nr_cpus++] = cpu;
47 if (n == 2 && sep == '-')
48 prev = cpu;
49 else
50 prev = -1;
51 if (n == 1 || sep == '\n')
52 break;
53 }
54 fclose(onlnf);
55 if (nr_cpus > 0)
56 return nr_cpus;
57
58 return default_cpu_map();
59}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
new file mode 100644
index 000000000000..86c78bb33098
--- /dev/null
+++ b/tools/perf/util/cpumap.h
@@ -0,0 +1,7 @@
1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H
3
4extern int read_cpu_map(void);
5extern int cpumap[];
6
7#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
deleted file mode 100644
index b557b836de3d..000000000000
--- a/tools/perf/util/data_map.c
+++ /dev/null
@@ -1,252 +0,0 @@
1#include "symbol.h"
2#include "util.h"
3#include "debug.h"
4#include "thread.h"
5#include "session.h"
6
7static int process_event_stub(event_t *event __used,
8 struct perf_session *session __used)
9{
10 dump_printf(": unhandled!\n");
11 return 0;
12}
13
14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15{
16 if (!handler->process_sample_event)
17 handler->process_sample_event = process_event_stub;
18 if (!handler->process_mmap_event)
19 handler->process_mmap_event = process_event_stub;
20 if (!handler->process_comm_event)
21 handler->process_comm_event = process_event_stub;
22 if (!handler->process_fork_event)
23 handler->process_fork_event = process_event_stub;
24 if (!handler->process_exit_event)
25 handler->process_exit_event = process_event_stub;
26 if (!handler->process_lost_event)
27 handler->process_lost_event = process_event_stub;
28 if (!handler->process_read_event)
29 handler->process_read_event = process_event_stub;
30 if (!handler->process_throttle_event)
31 handler->process_throttle_event = process_event_stub;
32 if (!handler->process_unthrottle_event)
33 handler->process_unthrottle_event = process_event_stub;
34}
35
36static const char *event__name[] = {
37 [0] = "TOTAL",
38 [PERF_RECORD_MMAP] = "MMAP",
39 [PERF_RECORD_LOST] = "LOST",
40 [PERF_RECORD_COMM] = "COMM",
41 [PERF_RECORD_EXIT] = "EXIT",
42 [PERF_RECORD_THROTTLE] = "THROTTLE",
43 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44 [PERF_RECORD_FORK] = "FORK",
45 [PERF_RECORD_READ] = "READ",
46 [PERF_RECORD_SAMPLE] = "SAMPLE",
47};
48
49unsigned long event__total[PERF_RECORD_MAX];
50
51void event__print_totals(void)
52{
53 int i;
54 for (i = 0; i < PERF_RECORD_MAX; ++i)
55 pr_info("%10s events: %10ld\n",
56 event__name[i], event__total[i]);
57}
58
59static int process_event(event_t *event, struct perf_session *session,
60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
62{
63 trace_event(event);
64
65 if (event->header.type < PERF_RECORD_MAX) {
66 dump_printf("%p [%p]: PERF_RECORD_%s",
67 (void *)(offset + head),
68 (void *)(long)(event->header.size),
69 event__name[event->header.type]);
70 ++event__total[0];
71 ++event__total[event->header.type];
72 }
73
74 switch (event->header.type) {
75 case PERF_RECORD_SAMPLE:
76 return ops->process_sample_event(event, session);
77 case PERF_RECORD_MMAP:
78 return ops->process_mmap_event(event, session);
79 case PERF_RECORD_COMM:
80 return ops->process_comm_event(event, session);
81 case PERF_RECORD_FORK:
82 return ops->process_fork_event(event, session);
83 case PERF_RECORD_EXIT:
84 return ops->process_exit_event(event, session);
85 case PERF_RECORD_LOST:
86 return ops->process_lost_event(event, session);
87 case PERF_RECORD_READ:
88 return ops->process_read_event(event, session);
89 case PERF_RECORD_THROTTLE:
90 return ops->process_throttle_event(event, session);
91 case PERF_RECORD_UNTHROTTLE:
92 return ops->process_unthrottle_event(event, session);
93 default:
94 ops->total_unknown++;
95 return -1;
96 }
97}
98
99int perf_header__read_build_ids(int input, u64 offset, u64 size)
100{
101 struct build_id_event bev;
102 char filename[PATH_MAX];
103 u64 limit = offset + size;
104 int err = -1;
105
106 while (offset < limit) {
107 struct dso *dso;
108 ssize_t len;
109
110 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111 goto out;
112
113 len = bev.header.size - sizeof(bev);
114 if (read(input, filename, len) != len)
115 goto out;
116
117 dso = dsos__findnew(filename);
118 if (dso != NULL)
119 dso__set_build_id(dso, &bev.build_id);
120
121 offset += bev.header.size;
122 }
123 err = 0;
124out:
125 return err;
126}
127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
142{
143 int err;
144 unsigned long head, shift;
145 unsigned long offset = 0;
146 size_t page_size;
147 event_t *event;
148 uint32_t size;
149 char *buf;
150
151 if (perf_session__register_idle_thread(self) == NULL)
152 return -ENOMEM;
153
154 perf_event_ops__fill_defaults(ops);
155
156 page_size = getpagesize();
157
158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
160
161 err = -EINVAL;
162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
163 goto out_err;
164
165 if (!ops->full_paths) {
166 char bf[PATH_MAX];
167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
178 }
179 self->cwdlen = strlen(self->cwd);
180 }
181
182 shift = page_size * (head / page_size);
183 offset += shift;
184 head -= shift;
185
186remap:
187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
188 MAP_SHARED, self->fd, offset);
189 if (buf == MAP_FAILED) {
190 pr_err("failed to mmap file\n");
191 err = -errno;
192 goto out_err;
193 }
194
195more:
196 event = (event_t *)(buf + head);
197
198 size = event->header.size;
199 if (!size)
200 size = 8;
201
202 if (head + event->header.size >= page_size * self->mmap_window) {
203 int munmap_ret;
204
205 shift = page_size * (head / page_size);
206
207 munmap_ret = munmap(buf, page_size * self->mmap_window);
208 assert(munmap_ret == 0);
209
210 offset += shift;
211 head -= shift;
212 goto remap;
213 }
214
215 size = event->header.size;
216
217 dump_printf("\n%p [%p]: event: %d\n",
218 (void *)(offset + head),
219 (void *)(long)event->header.size,
220 event->header.type);
221
222 if (!size || process_event(event, self, ops, offset, head) < 0) {
223
224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
225 (void *)(offset + head),
226 (void *)(long)(event->header.size),
227 event->header.type);
228
229 /*
230 * assume we lost track of the stream, check alignment, and
231 * increment a single u64 in the hope to catch on again 'soon'.
232 */
233
234 if (unlikely(head & 7))
235 head &= ~7ULL;
236
237 size = 8;
238 }
239
240 head += size;
241
242 if (offset + head >= self->header.data_offset + self->header.data_size)
243 goto done;
244
245 if (offset + head < self->size)
246 goto more;
247
248done:
249 err = 0;
250out_err:
251 return err;
252}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 28d520d5a1fb..6cddff2bc970 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -6,12 +6,14 @@
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"
13#include "util.h"
12 14
13int verbose = 0; 15int verbose = 0;
14int dump_trace = 0; 16bool dump_trace = false;
15 17
16int eprintf(int level, const char *fmt, ...) 18int eprintf(int level, const char *fmt, ...)
17{ 19{
@@ -20,7 +22,10 @@ int eprintf(int level, const char *fmt, ...)
20 22
21 if (verbose >= level) { 23 if (verbose >= level) {
22 va_start(args, fmt); 24 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args); 25 if (use_browser > 0)
26 ret = browser__show_help(fmt, args);
27 else
28 ret = vfprintf(stderr, fmt, args);
24 va_end(args); 29 va_end(args);
25 } 30 }
26 31
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index c6c24c522dea..047ac3324ebe 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -2,14 +2,38 @@
2#ifndef __PERF_DEBUG_H 2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H 3#define __PERF_DEBUG_H
4 4
5#include <stdbool.h>
5#include "event.h" 6#include "event.h"
6 7
7extern int verbose; 8extern int verbose;
8extern int dump_trace; 9extern bool dump_trace;
9 10
10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(event_t *event); 12void trace_event(event_t *event);
14 13
14struct ui_progress;
15
16#ifdef NO_NEWT_SUPPORT
17static inline int browser__show_help(const char *format __used, va_list ap __used)
18{
19 return 0;
20}
21
22static inline struct ui_progress *ui_progress__new(const char *title __used,
23 u64 total __used)
24{
25 return (struct ui_progress *)1;
26}
27
28static inline void ui_progress__update(struct ui_progress *self __used,
29 u64 curr __used) {}
30
31static inline void ui_progress__delete(struct ui_progress *self __used) {}
32#else
33int browser__show_help(const char *format, va_list ap);
34struct ui_progress *ui_progress__new(const char *title, u64 total);
35void ui_progress__update(struct ui_progress *self, u64 curr);
36void ui_progress__delete(struct ui_progress *self);
37#endif
38
15#endif /* __PERF_DEBUG_H */ 39#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index 06b73ee02c49..a88fefc0cc0a 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -106,16 +106,14 @@ int debugfs_valid_entry(const char *path)
106 return 0; 106 return 0;
107} 107}
108 108
109/* mount the debugfs somewhere */ 109/* mount the debugfs somewhere if it's not mounted */
110 110
111int debugfs_mount(const char *mountpoint) 111char *debugfs_mount(const char *mountpoint)
112{ 112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */ 113 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) { 114 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1; 115 debugfs_premounted = 1;
118 return 0; 116 return debugfs_mountpoint;
119 } 117 }
120 118
121 /* if not mounted and no argument */ 119 /* if not mounted and no argument */
@@ -127,13 +125,14 @@ int debugfs_mount(const char *mountpoint)
127 mountpoint = "/sys/kernel/debug"; 125 mountpoint = "/sys/kernel/debug";
128 } 126 }
129 127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
130 /* save the mountpoint */ 131 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
132 134
133 /* mount it */ 135 return debugfs_mountpoint;
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137} 136}
138 137
139/* umount the debugfs */ 138/* umount the debugfs */
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 3cd14f9ae784..83a02879745f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -15,7 +15,7 @@
15extern const char *debugfs_find_mountpoint(void); 15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs); 16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path); 17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint); 18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void); 19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value); 20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size); 21extern int debugfs_read(const char *entry, char *buffer, size_t size);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bb0fd6da2d56..2fbf6a463c81 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -7,9 +7,25 @@
7#include "strlist.h" 7#include "strlist.h"
8#include "thread.h" 8#include "thread.h"
9 9
10const char *event__name[] = {
11 [0] = "TOTAL",
12 [PERF_RECORD_MMAP] = "MMAP",
13 [PERF_RECORD_LOST] = "LOST",
14 [PERF_RECORD_COMM] = "COMM",
15 [PERF_RECORD_EXIT] = "EXIT",
16 [PERF_RECORD_THROTTLE] = "THROTTLE",
17 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
18 [PERF_RECORD_FORK] = "FORK",
19 [PERF_RECORD_READ] = "READ",
20 [PERF_RECORD_SAMPLE] = "SAMPLE",
21 [PERF_RECORD_HEADER_ATTR] = "ATTR",
22 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
23 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
24 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
25};
26
10static pid_t event__synthesize_comm(pid_t pid, int full, 27static pid_t event__synthesize_comm(pid_t pid, int full,
11 int (*process)(event_t *event, 28 event__handler_t process,
12 struct perf_session *session),
13 struct perf_session *session) 29 struct perf_session *session)
14{ 30{
15 event_t ev; 31 event_t ev;
@@ -91,8 +107,7 @@ out_failure:
91} 107}
92 108
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 109static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
94 int (*process)(event_t *event, 110 event__handler_t process,
95 struct perf_session *session),
96 struct perf_session *session) 111 struct perf_session *session)
97{ 112{
98 char filename[PATH_MAX]; 113 char filename[PATH_MAX];
@@ -112,7 +127,14 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
112 while (1) { 127 while (1) {
113 char bf[BUFSIZ], *pbf = bf; 128 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = { 129 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP }, 130 .header = {
131 .type = PERF_RECORD_MMAP,
132 /*
133 * Just like the kernel, see __perf_event_mmap
134 * in kernel/perf_event.c
135 */
136 .misc = PERF_RECORD_MISC_USER,
137 },
116 }; 138 };
117 int n; 139 int n;
118 size_t size; 140 size_t size;
@@ -129,6 +151,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
129 continue; 151 continue;
130 pbf += n + 3; 152 pbf += n + 3;
131 if (*pbf == 'x') { /* vm_exec */ 153 if (*pbf == 'x') { /* vm_exec */
154 u64 vm_pgoff;
132 char *execname = strchr(bf, '/'); 155 char *execname = strchr(bf, '/');
133 156
134 /* Catch VDSO */ 157 /* Catch VDSO */
@@ -138,6 +161,14 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
138 if (execname == NULL) 161 if (execname == NULL)
139 continue; 162 continue;
140 163
164 pbf += 3;
165 n = hex2u64(pbf, &vm_pgoff);
166 /* pgoff is in bytes, not pages */
167 if (n >= 0)
168 ev.mmap.pgoff = vm_pgoff << getpagesize();
169 else
170 ev.mmap.pgoff = 0;
171
141 size = strlen(execname); 172 size = strlen(execname);
142 execname[size - 1] = '\0'; /* Remove \n */ 173 execname[size - 1] = '\0'; /* Remove \n */
143 memcpy(ev.mmap.filename, execname, size); 174 memcpy(ev.mmap.filename, execname, size);
@@ -156,9 +187,51 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
156 return 0; 187 return 0;
157} 188}
158 189
159int event__synthesize_thread(pid_t pid, 190int event__synthesize_modules(event__handler_t process,
160 int (*process)(event_t *event, 191 struct perf_session *session,
161 struct perf_session *session), 192 struct machine *machine)
193{
194 struct rb_node *nd;
195 struct map_groups *kmaps = &machine->kmaps;
196 u16 misc;
197
198 /*
199 * kernel uses 0 for user space maps, see kernel/perf_event.c
200 * __perf_event_mmap
201 */
202 if (machine__is_host(machine))
203 misc = PERF_RECORD_MISC_KERNEL;
204 else
205 misc = PERF_RECORD_MISC_GUEST_KERNEL;
206
207 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
208 nd; nd = rb_next(nd)) {
209 event_t ev;
210 size_t size;
211 struct map *pos = rb_entry(nd, struct map, rb_node);
212
213 if (pos->dso->kernel)
214 continue;
215
216 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
217 memset(&ev, 0, sizeof(ev));
218 ev.mmap.header.misc = misc;
219 ev.mmap.header.type = PERF_RECORD_MMAP;
220 ev.mmap.header.size = (sizeof(ev.mmap) -
221 (sizeof(ev.mmap.filename) - size));
222 ev.mmap.start = pos->start;
223 ev.mmap.len = pos->end - pos->start;
224 ev.mmap.pid = machine->pid;
225
226 memcpy(ev.mmap.filename, pos->dso->long_name,
227 pos->dso->long_name_len + 1);
228 process(&ev, session);
229 }
230
231 return 0;
232}
233
234int event__synthesize_thread(pid_t pid, event__handler_t process,
162 struct perf_session *session) 235 struct perf_session *session)
163{ 236{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 237 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
@@ -167,8 +240,7 @@ int event__synthesize_thread(pid_t pid,
167 return event__synthesize_mmap_events(pid, tgid, process, session); 240 return event__synthesize_mmap_events(pid, tgid, process, session);
168} 241}
169 242
170void event__synthesize_threads(int (*process)(event_t *event, 243void event__synthesize_threads(event__handler_t process,
171 struct perf_session *session),
172 struct perf_session *session) 244 struct perf_session *session)
173{ 245{
174 DIR *proc; 246 DIR *proc;
@@ -189,6 +261,85 @@ void event__synthesize_threads(int (*process)(event_t *event,
189 closedir(proc); 261 closedir(proc);
190} 262}
191 263
264struct process_symbol_args {
265 const char *name;
266 u64 start;
267};
268
269static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
270{
271 struct process_symbol_args *args = arg;
272
273 /*
274 * Must be a function or at least an alias, as in PARISC64, where "_text" is
275 * an 'A' to the same address as "_stext".
276 */
277 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
278 type == 'A') || strcmp(name, args->name))
279 return 0;
280
281 args->start = start;
282 return 1;
283}
284
285int event__synthesize_kernel_mmap(event__handler_t process,
286 struct perf_session *session,
287 struct machine *machine,
288 const char *symbol_name)
289{
290 size_t size;
291 const char *filename, *mmap_name;
292 char path[PATH_MAX];
293 char name_buff[PATH_MAX];
294 struct map *map;
295
296 event_t ev = {
297 .header = {
298 .type = PERF_RECORD_MMAP,
299 },
300 };
301 /*
302 * We should get this from /sys/kernel/sections/.text, but till that is
303 * available use this, and after it is use this as a fallback for older
304 * kernels.
305 */
306 struct process_symbol_args args = { .name = symbol_name, };
307
308 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
309 if (machine__is_host(machine)) {
310 /*
311 * kernel uses PERF_RECORD_MISC_USER for user space maps,
312 * see kernel/perf_event.c __perf_event_mmap
313 */
314 ev.header.misc = PERF_RECORD_MISC_KERNEL;
315 filename = "/proc/kallsyms";
316 } else {
317 ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
318 if (machine__is_default_guest(machine))
319 filename = (char *) symbol_conf.default_guest_kallsyms;
320 else {
321 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
322 filename = path;
323 }
324 }
325
326 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
327 return -ENOENT;
328
329 map = machine->vmlinux_maps[MAP__FUNCTION];
330 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
331 "%s%s", mmap_name, symbol_name) + 1;
332 size = ALIGN(size, sizeof(u64));
333 ev.mmap.header.size = (sizeof(ev.mmap) -
334 (sizeof(ev.mmap.filename) - size));
335 ev.mmap.pgoff = args.start;
336 ev.mmap.start = map->start;
337 ev.mmap.len = map->end - ev.mmap.start;
338 ev.mmap.pid = machine->pid;
339
340 return process(&ev, session);
341}
342
192static void thread__comm_adjust(struct thread *self) 343static void thread__comm_adjust(struct thread *self)
193{ 344{
194 char *comm = self->comm; 345 char *comm = self->comm;
@@ -219,9 +370,9 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
219 370
220int event__process_comm(event_t *self, struct perf_session *session) 371int event__process_comm(event_t *self, struct perf_session *session)
221{ 372{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid); 373 struct thread *thread = perf_session__findnew(session, self->comm.tid);
223 374
224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 375 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
225 376
226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { 377 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 378 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
@@ -234,46 +385,163 @@ int event__process_comm(event_t *self, struct perf_session *session)
234int event__process_lost(event_t *self, struct perf_session *session) 385int event__process_lost(event_t *self, struct perf_session *session)
235{ 386{
236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 387 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
237 session->events_stats.lost += self->lost.lost; 388 session->hists.stats.total_lost += self->lost.lost;
238 return 0; 389 return 0;
239} 390}
240 391
392static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
393{
394 maps[MAP__FUNCTION]->start = self->mmap.start;
395 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
396 /*
397 * Be a bit paranoid here, some perf.data file came with
398 * a zero sized synthesized MMAP event for the kernel.
399 */
400 if (maps[MAP__FUNCTION]->end == 0)
401 maps[MAP__FUNCTION]->end = ~0UL;
402}
403
404static int event__process_kernel_mmap(event_t *self,
405 struct perf_session *session)
406{
407 struct map *map;
408 char kmmap_prefix[PATH_MAX];
409 struct machine *machine;
410 enum dso_kernel_type kernel_type;
411 bool is_kernel_mmap;
412
413 machine = perf_session__findnew_machine(session, self->mmap.pid);
414 if (!machine) {
415 pr_err("Can't find id %d's machine\n", self->mmap.pid);
416 goto out_problem;
417 }
418
419 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
420 if (machine__is_host(machine))
421 kernel_type = DSO_TYPE_KERNEL;
422 else
423 kernel_type = DSO_TYPE_GUEST_KERNEL;
424
425 is_kernel_mmap = memcmp(self->mmap.filename,
426 kmmap_prefix,
427 strlen(kmmap_prefix)) == 0;
428 if (self->mmap.filename[0] == '/' ||
429 (!is_kernel_mmap && self->mmap.filename[0] == '[')) {
430
431 char short_module_name[1024];
432 char *name, *dot;
433
434 if (self->mmap.filename[0] == '/') {
435 name = strrchr(self->mmap.filename, '/');
436 if (name == NULL)
437 goto out_problem;
438
439 ++name; /* skip / */
440 dot = strrchr(name, '.');
441 if (dot == NULL)
442 goto out_problem;
443 snprintf(short_module_name, sizeof(short_module_name),
444 "[%.*s]", (int)(dot - name), name);
445 strxfrchar(short_module_name, '-', '_');
446 } else
447 strcpy(short_module_name, self->mmap.filename);
448
449 map = machine__new_module(machine, self->mmap.start,
450 self->mmap.filename);
451 if (map == NULL)
452 goto out_problem;
453
454 name = strdup(short_module_name);
455 if (name == NULL)
456 goto out_problem;
457
458 map->dso->short_name = name;
459 map->end = map->start + self->mmap.len;
460 } else if (is_kernel_mmap) {
461 const char *symbol_name = (self->mmap.filename +
462 strlen(kmmap_prefix));
463 /*
464 * Should be there already, from the build-id table in
465 * the header.
466 */
467 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
468 kmmap_prefix);
469 if (kernel == NULL)
470 goto out_problem;
471
472 kernel->kernel = kernel_type;
473 if (__machine__create_kernel_maps(machine, kernel) < 0)
474 goto out_problem;
475
476 event_set_kernel_mmap_len(machine->vmlinux_maps, self);
477 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
478 symbol_name,
479 self->mmap.pgoff);
480 if (machine__is_default_guest(machine)) {
481 /*
482 * preload dso of guest kernel and modules
483 */
484 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
485 NULL);
486 }
487 }
488 return 0;
489out_problem:
490 return -1;
491}
492
241int event__process_mmap(event_t *self, struct perf_session *session) 493int event__process_mmap(event_t *self, struct perf_session *session)
242{ 494{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid); 495 struct machine *machine;
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 496 struct thread *thread;
245 session->cwd, session->cwdlen); 497 struct map *map;
498 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
499 int ret = 0;
500
501 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
502 self->mmap.pid, self->mmap.tid, self->mmap.start,
503 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
504
505 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
506 cpumode == PERF_RECORD_MISC_KERNEL) {
507 ret = event__process_kernel_mmap(self, session);
508 if (ret < 0)
509 goto out_problem;
510 return 0;
511 }
246 512
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 513 machine = perf_session__find_host_machine(session);
248 self->mmap.pid, self->mmap.tid, 514 if (machine == NULL)
249 (void *)(long)self->mmap.start, 515 goto out_problem;
250 (void *)(long)self->mmap.len, 516 thread = perf_session__findnew(session, self->mmap.pid);
251 (void *)(long)self->mmap.pgoff, 517 map = map__new(&machine->user_dsos, self->mmap.start,
252 self->mmap.filename); 518 self->mmap.len, self->mmap.pgoff,
519 self->mmap.pid, self->mmap.filename,
520 MAP__FUNCTION, session->cwd, session->cwdlen);
253 521
254 if (thread == NULL || map == NULL) 522 if (thread == NULL || map == NULL)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 523 goto out_problem;
256 else
257 thread__insert_map(thread, map);
258 524
525 thread__insert_map(thread, map);
526 return 0;
527
528out_problem:
529 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
259 return 0; 530 return 0;
260} 531}
261 532
262int event__process_task(event_t *self, struct perf_session *session) 533int event__process_task(event_t *self, struct perf_session *session)
263{ 534{
264 struct thread *thread = perf_session__findnew(session, self->fork.pid); 535 struct thread *thread = perf_session__findnew(session, self->fork.tid);
265 struct thread *parent = perf_session__findnew(session, self->fork.ppid); 536 struct thread *parent = perf_session__findnew(session, self->fork.ptid);
266 537
267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 538 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
268 self->fork.ppid, self->fork.ptid); 539 self->fork.ppid, self->fork.ptid);
269 /*
270 * A thread clone will have the same PID for both parent and child.
271 */
272 if (thread == parent)
273 return 0;
274 540
275 if (self->header.type == PERF_RECORD_EXIT) 541 if (self->header.type == PERF_RECORD_EXIT) {
542 perf_session__remove_thread(session, thread);
276 return 0; 543 return 0;
544 }
277 545
278 if (thread == NULL || parent == NULL || 546 if (thread == NULL || parent == NULL ||
279 thread__fork(thread, parent) < 0) { 547 thread__fork(thread, parent) < 0) {
@@ -284,26 +552,58 @@ int event__process_task(event_t *self, struct perf_session *session)
284 return 0; 552 return 0;
285} 553}
286 554
287void thread__find_addr_location(struct thread *self, 555void thread__find_addr_map(struct thread *self,
288 struct perf_session *session, u8 cpumode, 556 struct perf_session *session, u8 cpumode,
289 enum map_type type, u64 addr, 557 enum map_type type, pid_t pid, u64 addr,
290 struct addr_location *al, 558 struct addr_location *al)
291 symbol_filter_t filter)
292{ 559{
293 struct map_groups *mg = &self->mg; 560 struct map_groups *mg = &self->mg;
561 struct machine *machine = NULL;
294 562
295 al->thread = self; 563 al->thread = self;
296 al->addr = addr; 564 al->addr = addr;
565 al->cpumode = cpumode;
566 al->filtered = false;
297 567
298 if (cpumode & PERF_RECORD_MISC_KERNEL) { 568 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
299 al->level = 'k'; 569 al->level = 'k';
300 mg = &session->kmaps; 570 machine = perf_session__find_host_machine(session);
301 } else if (cpumode & PERF_RECORD_MISC_USER) 571 if (machine == NULL) {
572 al->map = NULL;
573 return;
574 }
575 mg = &machine->kmaps;
576 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
302 al->level = '.'; 577 al->level = '.';
303 else { 578 machine = perf_session__find_host_machine(session);
304 al->level = 'H'; 579 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
580 al->level = 'g';
581 machine = perf_session__find_machine(session, pid);
582 if (machine == NULL) {
583 al->map = NULL;
584 return;
585 }
586 mg = &machine->kmaps;
587 } else {
588 /*
589 * 'u' means guest os user space.
590 * TODO: We don't support guest user space. Might support late.
591 */
592 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
593 al->level = 'u';
594 else
595 al->level = 'H';
305 al->map = NULL; 596 al->map = NULL;
306 al->sym = NULL; 597
598 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
599 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
600 !perf_guest)
601 al->filtered = true;
602 if ((cpumode == PERF_RECORD_MISC_USER ||
603 cpumode == PERF_RECORD_MISC_KERNEL) &&
604 !perf_host)
605 al->filtered = true;
606
307 return; 607 return;
308 } 608 }
309try_again: 609try_again:
@@ -318,15 +618,27 @@ try_again:
318 * "[vdso]" dso, but for now lets use the old trick of looking 618 * "[vdso]" dso, but for now lets use the old trick of looking
319 * in the whole kernel symbol list. 619 * in the whole kernel symbol list.
320 */ 620 */
321 if ((long long)al->addr < 0 && mg != &session->kmaps) { 621 if ((long long)al->addr < 0 &&
322 mg = &session->kmaps; 622 cpumode == PERF_RECORD_MISC_KERNEL &&
623 machine && mg != &machine->kmaps) {
624 mg = &machine->kmaps;
323 goto try_again; 625 goto try_again;
324 } 626 }
325 al->sym = NULL; 627 } else
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr); 628 al->addr = al->map->map_ip(al->map, al->addr);
328 al->sym = map__find_symbol(al->map, session, al->addr, filter); 629}
329 } 630
631void thread__find_addr_location(struct thread *self,
632 struct perf_session *session, u8 cpumode,
633 enum map_type type, pid_t pid, u64 addr,
634 struct addr_location *al,
635 symbol_filter_t filter)
636{
637 thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
638 if (al->map != NULL)
639 al->sym = map__find_symbol(al->map, al->addr, filter);
640 else
641 al->sym = NULL;
330} 642}
331 643
332static void dso__calc_col_width(struct dso *self) 644static void dso__calc_col_width(struct dso *self)
@@ -334,8 +646,10 @@ static void dso__calc_col_width(struct dso *self)
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 646 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list || 647 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) { 648 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name); 649 u16 slen = self->short_name_len;
338 if (slen > dsos__col_width) 650 if (verbose)
651 slen = self->long_name_len;
652 if (dsos__col_width < slen)
339 dsos__col_width = slen; 653 dsos__col_width = slen;
340 } 654 }
341 655
@@ -356,31 +670,55 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
356 goto out_filtered; 670 goto out_filtered;
357 671
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 672 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
673 /*
674 * Have we already created the kernel maps for the host machine?
675 *
676 * This should have happened earlier, when we processed the kernel MMAP
677 * events, but for older perf.data files there was no such thing, so do
678 * it now.
679 */
680 if (cpumode == PERF_RECORD_MISC_KERNEL &&
681 session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL)
682 machine__create_kernel_maps(&session->host_machine);
359 683
360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, 684 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
361 self->ip.ip, al, filter); 685 self->ip.pid, self->ip.ip, al);
362 dump_printf(" ...... dso: %s\n", 686 dump_printf(" ...... dso: %s\n",
363 al->map ? al->map->dso->long_name : 687 al->map ? al->map->dso->long_name :
364 al->level == 'H' ? "[hypervisor]" : "<not found>"); 688 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /* 689 al->sym = NULL;
366 * We have to do this here as we may have a dso with no symbol hit that 690
367 * has a name longer than the ones with symbols sampled. 691 if (al->map) {
368 */ 692 if (symbol_conf.dso_list &&
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated) 693 (!al->map || !al->map->dso ||
370 dso__calc_col_width(al->map->dso); 694 !(strlist__has_entry(symbol_conf.dso_list,
371 695 al->map->dso->short_name) ||
372 if (symbol_conf.dso_list && 696 (al->map->dso->short_name != al->map->dso->long_name &&
373 (!al->map || !al->map->dso || 697 strlist__has_entry(symbol_conf.dso_list,
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) || 698 al->map->dso->long_name)))))
375 (al->map->dso->short_name != al->map->dso->long_name && 699 goto out_filtered;
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name))))) 700 /*
377 goto out_filtered; 701 * We have to do this here as we may have a dso with no symbol
702 * hit that has a name longer than the ones with symbols
703 * sampled.
704 */
705 if (!sort_dso.elide && !al->map->dso->slen_calculated)
706 dso__calc_col_width(al->map->dso);
707
708 al->sym = map__find_symbol(al->map, al->addr, filter);
709 } else {
710 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
711
712 if (dsos__col_width < unresolved_col_width &&
713 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
714 !symbol_conf.dso_list)
715 dsos__col_width = unresolved_col_width;
716 }
378 717
379 if (symbol_conf.sym_list && al->sym && 718 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) 719 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered; 720 goto out_filtered;
382 721
383 al->filtered = false;
384 return 0; 722 return 0;
385 723
386out_filtered: 724out_filtered:
@@ -414,6 +752,7 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
414 array++; 752 array++;
415 } 753 }
416 754
755 data->id = -1ULL;
417 if (type & PERF_SAMPLE_ID) { 756 if (type & PERF_SAMPLE_ID) {
418 data->id = *array; 757 data->id = *array;
419 array++; 758 array++;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 690a96d0467c..8577085db067 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,10 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h>
5
4#include "../perf.h" 6#include "../perf.h"
5#include "util.h" 7#include "map.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8 8
9/* 9/*
10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -68,21 +68,54 @@ struct sample_data {
68 u64 addr; 68 u64 addr;
69 u64 id; 69 u64 id;
70 u64 stream_id; 70 u64 stream_id;
71 u32 cpu;
72 u64 period; 71 u64 period;
73 struct ip_callchain *callchain; 72 u32 cpu;
74 u32 raw_size; 73 u32 raw_size;
75 void *raw_data; 74 void *raw_data;
75 struct ip_callchain *callchain;
76}; 76};
77 77
78#define BUILD_ID_SIZE 20 78#define BUILD_ID_SIZE 20
79 79
80struct build_id_event { 80struct build_id_event {
81 struct perf_event_header header; 81 struct perf_event_header header;
82 pid_t pid;
82 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; 83 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
83 char filename[]; 84 char filename[];
84}; 85};
85 86
87enum perf_user_event_type { /* above any possible kernel type */
88 PERF_RECORD_HEADER_ATTR = 64,
89 PERF_RECORD_HEADER_EVENT_TYPE = 65,
90 PERF_RECORD_HEADER_TRACING_DATA = 66,
91 PERF_RECORD_HEADER_BUILD_ID = 67,
92 PERF_RECORD_FINISHED_ROUND = 68,
93 PERF_RECORD_HEADER_MAX
94};
95
96struct attr_event {
97 struct perf_event_header header;
98 struct perf_event_attr attr;
99 u64 id[];
100};
101
102#define MAX_EVENT_NAME 64
103
104struct perf_trace_event_type {
105 u64 event_id;
106 char name[MAX_EVENT_NAME];
107};
108
109struct event_type_event {
110 struct perf_event_header header;
111 struct perf_trace_event_type event_type;
112};
113
114struct tracing_data_event {
115 struct perf_event_header header;
116 u32 size;
117};
118
86typedef union event_union { 119typedef union event_union {
87 struct perf_event_header header; 120 struct perf_event_header header;
88 struct ip_event ip; 121 struct ip_event ip;
@@ -92,83 +125,30 @@ typedef union event_union {
92 struct lost_event lost; 125 struct lost_event lost;
93 struct read_event read; 126 struct read_event read;
94 struct sample_event sample; 127 struct sample_event sample;
128 struct attr_event attr;
129 struct event_type_event event_type;
130 struct tracing_data_event tracing_data;
131 struct build_id_event build_id;
95} event_t; 132} event_t;
96 133
97struct events_stats {
98 u64 total;
99 u64 lost;
100};
101
102void event__print_totals(void); 134void event__print_totals(void);
103 135
104enum map_type {
105 MAP__FUNCTION = 0,
106 MAP__VARIABLE,
107};
108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
111struct map {
112 union {
113 struct rb_node rb_node;
114 struct list_head node;
115 };
116 u64 start;
117 u64 end;
118 enum map_type type;
119 u64 pgoff;
120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
122 struct dso *dso;
123};
124
125static inline u64 map__map_ip(struct map *map, u64 ip)
126{
127 return ip - map->start + map->pgoff;
128}
129
130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
136{
137 return ip;
138}
139
140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp);
152
153struct perf_session; 136struct perf_session;
154 137
155int map__load(struct map *self, struct perf_session *session, 138typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
156 symbol_filter_t filter); 139
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 140int event__synthesize_thread(pid_t pid, event__handler_t process,
158 u64 addr, symbol_filter_t filter);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
162void map__fixup_start(struct map *self);
163void map__fixup_end(struct map *self);
164
165int event__synthesize_thread(pid_t pid,
166 int (*process)(event_t *event,
167 struct perf_session *session),
168 struct perf_session *session); 141 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event, 142void event__synthesize_threads(event__handler_t process,
170 struct perf_session *session),
171 struct perf_session *session); 143 struct perf_session *session);
144int event__synthesize_kernel_mmap(event__handler_t process,
145 struct perf_session *session,
146 struct machine *machine,
147 const char *symbol_name);
148
149int event__synthesize_modules(event__handler_t process,
150 struct perf_session *session,
151 struct machine *machine);
172 152
173int event__process_comm(event_t *self, struct perf_session *session); 153int event__process_comm(event_t *self, struct perf_session *session);
174int event__process_lost(event_t *self, struct perf_session *session); 154int event__process_lost(event_t *self, struct perf_session *session);
@@ -180,4 +160,6 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
180 struct addr_location *al, symbol_filter_t filter); 160 struct addr_location *al, symbol_filter_t filter);
181int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 161int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
182 162
163extern const char *event__name[];
164
183#endif /* __PERF_RECORD_H */ 165#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index 2745605dba11..67eeff571568 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -53,8 +53,8 @@ const char *perf_extract_argv0_path(const char *argv0)
53 slash--; 53 slash--;
54 54
55 if (slash >= argv0) { 55 if (slash >= argv0) {
56 argv0_path = xstrndup(argv0, slash - argv0); 56 argv0_path = strndup(argv0, slash - argv0);
57 return slash + 1; 57 return argv0_path ? slash + 1 : NULL;
58 } 58 }
59 59
60 return argv0; 60 return argv0;
@@ -116,7 +116,7 @@ void setup_path(void)
116 strbuf_release(&new_path); 116 strbuf_release(&new_path);
117} 117}
118 118
119const char **prepare_perf_cmd(const char **argv) 119static const char **prepare_perf_cmd(const char **argv)
120{ 120{
121 int argc; 121 int argc;
122 const char **nargv; 122 const char **nargv;
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index 31647ac92ed1..bc4b915963f5 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -5,7 +5,6 @@ extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path); 5extern const char *perf_extract_argv0_path(const char *path);
6extern const char *perf_exec_path(void); 6extern const char *perf_exec_path(void);
7extern void setup_path(void); 7extern void setup_path(void);
8extern const char **prepare_perf_cmd(const char **argv);
9extern int execv_perf_cmd(const char **argv); /* NULL terminated */ 8extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...); 9extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path); 10extern const char *system_path(const char *path);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 8a0bca55106f..1f62435f96c2 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,8 +1,12 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <sys/types.h> 3#include <sys/types.h>
4#include <byteswap.h>
2#include <unistd.h> 5#include <unistd.h>
3#include <stdio.h> 6#include <stdio.h>
4#include <stdlib.h> 7#include <stdlib.h>
5#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h>
6 10
7#include "util.h" 11#include "util.h"
8#include "header.h" 12#include "header.h"
@@ -95,34 +99,31 @@ int perf_header__add_attr(struct perf_header *self,
95 return 0; 99 return 0;
96} 100}
97 101
98#define MAX_EVENT_NAME 64
99
100struct perf_trace_event_type {
101 u64 event_id;
102 char name[MAX_EVENT_NAME];
103};
104
105static int event_count; 102static int event_count;
106static struct perf_trace_event_type *events; 103static struct perf_trace_event_type *events;
107 104
108void perf_header__push_event(u64 id, const char *name) 105int perf_header__push_event(u64 id, const char *name)
109{ 106{
110 if (strlen(name) > MAX_EVENT_NAME) 107 if (strlen(name) > MAX_EVENT_NAME)
111 pr_warning("Event %s will be truncated\n", name); 108 pr_warning("Event %s will be truncated\n", name);
112 109
113 if (!events) { 110 if (!events) {
114 events = malloc(sizeof(struct perf_trace_event_type)); 111 events = malloc(sizeof(struct perf_trace_event_type));
115 if (!events) 112 if (events == NULL)
116 die("nomem"); 113 return -ENOMEM;
117 } else { 114 } else {
118 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 115 struct perf_trace_event_type *nevents;
119 if (!events) 116
120 die("nomem"); 117 nevents = realloc(events, (event_count + 1) * sizeof(*events));
118 if (nevents == NULL)
119 return -ENOMEM;
120 events = nevents;
121 } 121 }
122 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 122 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
123 events[event_count].event_id = id; 123 events[event_count].event_id = id;
124 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 124 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
125 event_count++; 125 event_count++;
126 return 0;
126} 127}
127 128
128char *perf_header__find_event(u64 id) 129char *perf_header__find_event(u64 id)
@@ -169,31 +170,50 @@ static int do_write(int fd, const void *buf, size_t size)
169 return 0; 170 return 0;
170} 171}
171 172
172static int __dsos__write_buildid_table(struct list_head *head, int fd) 173#define NAME_ALIGN 64
174
175static int write_padded(int fd, const void *bf, size_t count,
176 size_t count_aligned)
173{ 177{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN]; 178 static const char zero_buf[NAME_ALIGN];
179 int err = do_write(fd, bf, count);
180
181 if (!err)
182 err = do_write(fd, zero_buf, count_aligned - count);
177 183
178 list_for_each_entry(pos, head, node) { 184 return err;
185}
186
187#define dsos__for_each_with_build_id(pos, head) \
188 list_for_each_entry(pos, head, node) \
189 if (!pos->has_build_id) \
190 continue; \
191 else
192
193static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
194 u16 misc, int fd)
195{
196 struct dso *pos;
197
198 dsos__for_each_with_build_id(pos, head) {
179 int err; 199 int err;
180 struct build_id_event b; 200 struct build_id_event b;
181 size_t len; 201 size_t len;
182 202
183 if (!pos->has_build_id) 203 if (!pos->hit)
184 continue; 204 continue;
185 len = pos->long_name_len + 1; 205 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN); 206 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b)); 207 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 208 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
209 b.pid = pid;
210 b.header.misc = misc;
189 b.header.size = sizeof(b) + len; 211 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b)); 212 err = do_write(fd, &b, sizeof(b));
191 if (err < 0) 213 if (err < 0)
192 return err; 214 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1); 215 err = write_padded(fd, pos->long_name,
194 if (err < 0) 216 pos->long_name_len + 1, len);
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0) 217 if (err < 0)
198 return err; 218 return err;
199 } 219 }
@@ -201,23 +221,216 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
201 return 0; 221 return 0;
202} 222}
203 223
204static int dsos__write_buildid_table(int fd) 224static int machine__write_buildid_table(struct machine *self, int fd)
205{ 225{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 226 int err;
227 u16 kmisc = PERF_RECORD_MISC_KERNEL,
228 umisc = PERF_RECORD_MISC_USER;
229
230 if (!machine__is_host(self)) {
231 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
232 umisc = PERF_RECORD_MISC_GUEST_USER;
233 }
234
235 err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid,
236 kmisc, fd);
207 if (err == 0) 237 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd); 238 err = __dsos__write_buildid_table(&self->user_dsos,
239 self->pid, umisc, fd);
240 return err;
241}
242
243static int dsos__write_buildid_table(struct perf_header *header, int fd)
244{
245 struct perf_session *session = container_of(header,
246 struct perf_session, header);
247 struct rb_node *nd;
248 int err = machine__write_buildid_table(&session->host_machine, fd);
249
250 if (err)
251 return err;
252
253 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
254 struct machine *pos = rb_entry(nd, struct machine, rb_node);
255 err = machine__write_buildid_table(pos, fd);
256 if (err)
257 break;
258 }
259 return err;
260}
261
262int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
263 const char *name, bool is_kallsyms)
264{
265 const size_t size = PATH_MAX;
266 char *filename = malloc(size),
267 *linkname = malloc(size), *targetname;
268 int len, err = -1;
269
270 if (filename == NULL || linkname == NULL)
271 goto out_free;
272
273 len = snprintf(filename, size, "%s%s%s",
274 debugdir, is_kallsyms ? "/" : "", name);
275 if (mkdir_p(filename, 0755))
276 goto out_free;
277
278 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
279
280 if (access(filename, F_OK)) {
281 if (is_kallsyms) {
282 if (copyfile("/proc/kallsyms", filename))
283 goto out_free;
284 } else if (link(name, filename) && copyfile(name, filename))
285 goto out_free;
286 }
287
288 len = snprintf(linkname, size, "%s/.build-id/%.2s",
289 debugdir, sbuild_id);
290
291 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
292 goto out_free;
293
294 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
295 targetname = filename + strlen(debugdir) - 5;
296 memcpy(targetname, "../..", 5);
297
298 if (symlink(targetname, linkname) == 0)
299 err = 0;
300out_free:
301 free(filename);
302 free(linkname);
303 return err;
304}
305
306static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
307 const char *name, const char *debugdir,
308 bool is_kallsyms)
309{
310 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
311
312 build_id__sprintf(build_id, build_id_size, sbuild_id);
313
314 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
315}
316
317int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
318{
319 const size_t size = PATH_MAX;
320 char *filename = malloc(size),
321 *linkname = malloc(size);
322 int err = -1;
323
324 if (filename == NULL || linkname == NULL)
325 goto out_free;
326
327 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
328 debugdir, sbuild_id, sbuild_id + 2);
329
330 if (access(linkname, F_OK))
331 goto out_free;
332
333 if (readlink(linkname, filename, size) < 0)
334 goto out_free;
335
336 if (unlink(linkname))
337 goto out_free;
338
339 /*
340 * Since the link is relative, we must make it absolute:
341 */
342 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
343 debugdir, sbuild_id, filename);
344
345 if (unlink(linkname))
346 goto out_free;
347
348 err = 0;
349out_free:
350 free(filename);
351 free(linkname);
352 return err;
353}
354
355static int dso__cache_build_id(struct dso *self, const char *debugdir)
356{
357 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
358
359 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
360 self->long_name, debugdir, is_kallsyms);
361}
362
363static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
364{
365 struct dso *pos;
366 int err = 0;
367
368 dsos__for_each_with_build_id(pos, head)
369 if (dso__cache_build_id(pos, debugdir))
370 err = -1;
371
209 return err; 372 return err;
210} 373}
211 374
375static int machine__cache_build_ids(struct machine *self, const char *debugdir)
376{
377 int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir);
378 ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir);
379 return ret;
380}
381
382static int perf_session__cache_build_ids(struct perf_session *self)
383{
384 struct rb_node *nd;
385 int ret;
386 char debugdir[PATH_MAX];
387
388 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
389 DEBUG_CACHE_DIR);
390
391 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
392 return -1;
393
394 ret = machine__cache_build_ids(&self->host_machine, debugdir);
395
396 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
397 struct machine *pos = rb_entry(nd, struct machine, rb_node);
398 ret |= machine__cache_build_ids(pos, debugdir);
399 }
400 return ret ? -1 : 0;
401}
402
403static bool machine__read_build_ids(struct machine *self, bool with_hits)
404{
405 bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits);
406 ret |= __dsos__read_build_ids(&self->user_dsos, with_hits);
407 return ret;
408}
409
410static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits)
411{
412 struct rb_node *nd;
413 bool ret = machine__read_build_ids(&self->host_machine, with_hits);
414
415 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
416 struct machine *pos = rb_entry(nd, struct machine, rb_node);
417 ret |= machine__read_build_ids(pos, with_hits);
418 }
419
420 return ret;
421}
422
212static int perf_header__adds_write(struct perf_header *self, int fd) 423static int perf_header__adds_write(struct perf_header *self, int fd)
213{ 424{
214 int nr_sections; 425 int nr_sections;
426 struct perf_session *session;
215 struct perf_file_section *feat_sec; 427 struct perf_file_section *feat_sec;
216 int sec_size; 428 int sec_size;
217 u64 sec_start; 429 u64 sec_start;
218 int idx = 0, err; 430 int idx = 0, err;
219 431
220 if (dsos__read_build_ids()) 432 session = container_of(self, struct perf_session, header);
433 if (perf_session__read_build_ids(session, true))
221 perf_header__set_feat(self, HEADER_BUILD_ID); 434 perf_header__set_feat(self, HEADER_BUILD_ID);
222 435
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 436 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -244,7 +457,6 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
244 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 457 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
245 } 458 }
246 459
247
248 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 460 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
249 struct perf_file_section *buildid_sec; 461 struct perf_file_section *buildid_sec;
250 462
@@ -252,12 +464,14 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
252 464
253 /* Write build-ids */ 465 /* Write build-ids */
254 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 466 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
255 err = dsos__write_buildid_table(fd); 467 err = dsos__write_buildid_table(self, fd);
256 if (err < 0) { 468 if (err < 0) {
257 pr_debug("failed to write buildid table\n"); 469 pr_debug("failed to write buildid table\n");
258 goto out_free; 470 goto out_free;
259 } 471 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 472 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
473 buildid_sec->offset;
474 perf_session__cache_build_ids(session);
261 } 475 }
262 476
263 lseek(fd, sec_start, SEEK_SET); 477 lseek(fd, sec_start, SEEK_SET);
@@ -269,6 +483,25 @@ out_free:
269 return err; 483 return err;
270} 484}
271 485
486int perf_header__write_pipe(int fd)
487{
488 struct perf_pipe_file_header f_header;
489 int err;
490
491 f_header = (struct perf_pipe_file_header){
492 .magic = PERF_MAGIC,
493 .size = sizeof(f_header),
494 };
495
496 err = do_write(fd, &f_header, sizeof(f_header));
497 if (err < 0) {
498 pr_debug("failed to write perf pipe header\n");
499 return err;
500 }
501
502 return 0;
503}
504
272int perf_header__write(struct perf_header *self, int fd, bool at_exit) 505int perf_header__write(struct perf_header *self, int fd, bool at_exit)
273{ 506{
274 struct perf_file_header f_header; 507 struct perf_file_header f_header;
@@ -278,7 +511,6 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
278 511
279 lseek(fd, sizeof(f_header), SEEK_SET); 512 lseek(fd, sizeof(f_header), SEEK_SET);
280 513
281
282 for (i = 0; i < self->attrs; i++) { 514 for (i = 0; i < self->attrs; i++) {
283 attr = self->attr[i]; 515 attr = self->attr[i];
284 516
@@ -360,30 +592,28 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
360 return 0; 592 return 0;
361} 593}
362 594
363static void do_read(int fd, void *buf, size_t size) 595static int perf_header__getbuffer64(struct perf_header *self,
596 int fd, void *buf, size_t size)
364{ 597{
365 while (size) { 598 if (do_read(fd, buf, size) <= 0)
366 int ret = read(fd, buf, size); 599 return -1;
367 600
368 if (ret < 0) 601 if (self->needs_swap)
369 die("failed to read"); 602 mem_bswap_64(buf, size);
370 if (ret == 0)
371 die("failed to read: missing data");
372 603
373 size -= ret; 604 return 0;
374 buf += ret;
375 }
376} 605}
377 606
378int perf_header__process_sections(struct perf_header *self, int fd, 607int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self, 608 int (*process)(struct perf_file_section *self,
609 struct perf_header *ph,
380 int feat, int fd)) 610 int feat, int fd))
381{ 611{
382 struct perf_file_section *feat_sec; 612 struct perf_file_section *feat_sec;
383 int nr_sections; 613 int nr_sections;
384 int sec_size; 614 int sec_size;
385 int idx = 0; 615 int idx = 0;
386 int err = 0, feat = 1; 616 int err = -1, feat = 1;
387 617
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 618 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections) 619 if (!nr_sections)
@@ -397,33 +627,45 @@ int perf_header__process_sections(struct perf_header *self, int fd,
397 627
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 628 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399 629
400 do_read(fd, feat_sec, sec_size); 630 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
631 goto out_free;
401 632
633 err = 0;
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 634 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) { 635 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++]; 636 struct perf_file_section *sec = &feat_sec[idx++];
405 637
406 err = process(sec, feat, fd); 638 err = process(sec, self, feat, fd);
407 if (err < 0) 639 if (err < 0)
408 break; 640 break;
409 } 641 }
410 ++feat; 642 ++feat;
411 } 643 }
412 644out_free:
413 free(feat_sec); 645 free(feat_sec);
414 return err; 646 return err;
415}; 647}
416 648
417int perf_file_header__read(struct perf_file_header *self, 649int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd) 650 struct perf_header *ph, int fd)
419{ 651{
420 lseek(fd, 0, SEEK_SET); 652 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422 653
423 if (self->magic != PERF_MAGIC || 654 if (do_read(fd, self, sizeof(*self)) <= 0 ||
424 self->attr_size != sizeof(struct perf_file_attr)) 655 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
425 return -1; 656 return -1;
426 657
658 if (self->attr_size != sizeof(struct perf_file_attr)) {
659 u64 attr_size = bswap_64(self->attr_size);
660
661 if (attr_size != sizeof(struct perf_file_attr))
662 return -1;
663
664 mem_bswap_64(self, offsetof(struct perf_file_header,
665 adds_features));
666 ph->needs_swap = true;
667 }
668
427 if (self->size != sizeof(*self)) { 669 if (self->size != sizeof(*self)) {
428 /* Support the previous format */ 670 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features)) 671 if (self->size == offsetof(typeof(*self), adds_features))
@@ -433,19 +675,118 @@ int perf_file_header__read(struct perf_file_header *self,
433 } 675 }
434 676
435 memcpy(&ph->adds_features, &self->adds_features, 677 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features)); 678 sizeof(ph->adds_features));
679 /*
680 * FIXME: hack that assumes that if we need swap the perf.data file
681 * may be coming from an arch with a different word-size, ergo different
682 * DEFINE_BITMAP format, investigate more later, but for now its mostly
683 * safe to assume that we have a build-id section. Trace files probably
684 * have several other issues in this realm anyway...
685 */
686 if (ph->needs_swap) {
687 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
688 perf_header__set_feat(ph, HEADER_BUILD_ID);
689 }
437 690
438 ph->event_offset = self->event_types.offset; 691 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size; 692 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset; 693 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size; 694 ph->data_size = self->data.size;
442 return 0; 695 return 0;
443} 696}
444 697
698static int __event_process_build_id(struct build_id_event *bev,
699 char *filename,
700 struct perf_session *session)
701{
702 int err = -1;
703 struct list_head *head;
704 struct machine *machine;
705 u16 misc;
706 struct dso *dso;
707 enum dso_kernel_type dso_type;
708
709 machine = perf_session__findnew_machine(session, bev->pid);
710 if (!machine)
711 goto out;
712
713 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
714
715 switch (misc) {
716 case PERF_RECORD_MISC_KERNEL:
717 dso_type = DSO_TYPE_KERNEL;
718 head = &machine->kernel_dsos;
719 break;
720 case PERF_RECORD_MISC_GUEST_KERNEL:
721 dso_type = DSO_TYPE_GUEST_KERNEL;
722 head = &machine->kernel_dsos;
723 break;
724 case PERF_RECORD_MISC_USER:
725 case PERF_RECORD_MISC_GUEST_USER:
726 dso_type = DSO_TYPE_USER;
727 head = &machine->user_dsos;
728 break;
729 default:
730 goto out;
731 }
732
733 dso = __dsos__findnew(head, filename);
734 if (dso != NULL) {
735 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
736
737 dso__set_build_id(dso, &bev->build_id);
738
739 if (filename[0] == '[')
740 dso->kernel = dso_type;
741
742 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
743 sbuild_id);
744 pr_debug("build id event received for %s: %s\n",
745 dso->long_name, sbuild_id);
746 }
747
748 err = 0;
749out:
750 return err;
751}
752
753static int perf_header__read_build_ids(struct perf_header *self,
754 int input, u64 offset, u64 size)
755{
756 struct perf_session *session = container_of(self,
757 struct perf_session, header);
758 struct build_id_event bev;
759 char filename[PATH_MAX];
760 u64 limit = offset + size;
761 int err = -1;
762
763 while (offset < limit) {
764 ssize_t len;
765
766 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
767 goto out;
768
769 if (self->needs_swap)
770 perf_event_header__bswap(&bev.header);
771
772 len = bev.header.size - sizeof(bev);
773 if (read(input, filename, len) != len)
774 goto out;
775
776 __event_process_build_id(&bev, filename, session);
777
778 offset += bev.header.size;
779 }
780 err = 0;
781out:
782 return err;
783}
784
445static int perf_file_section__process(struct perf_file_section *self, 785static int perf_file_section__process(struct perf_file_section *self,
786 struct perf_header *ph,
446 int feat, int fd) 787 int feat, int fd)
447{ 788{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) { 789 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, " 790 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat); 791 "continuing...\n", self->offset, feat);
451 return 0; 792 return 0;
@@ -453,11 +794,11 @@ static int perf_file_section__process(struct perf_file_section *self,
453 794
454 switch (feat) { 795 switch (feat) {
455 case HEADER_TRACE_INFO: 796 case HEADER_TRACE_INFO:
456 trace_report(fd); 797 trace_report(fd, false);
457 break; 798 break;
458 799
459 case HEADER_BUILD_ID: 800 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size)) 801 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n"); 802 pr_debug("Failed to read buildids, continuing...\n");
462 break; 803 break;
463 default: 804 default:
@@ -467,13 +808,56 @@ static int perf_file_section__process(struct perf_file_section *self,
467 return 0; 808 return 0;
468} 809}
469 810
470int perf_header__read(struct perf_header *self, int fd) 811static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
812 struct perf_header *ph, int fd,
813 bool repipe)
471{ 814{
472 struct perf_file_header f_header; 815 if (do_read(fd, self, sizeof(*self)) <= 0 ||
816 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
817 return -1;
818
819 if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0)
820 return -1;
821
822 if (self->size != sizeof(*self)) {
823 u64 size = bswap_64(self->size);
824
825 if (size != sizeof(*self))
826 return -1;
827
828 ph->needs_swap = true;
829 }
830
831 return 0;
832}
833
834static int perf_header__read_pipe(struct perf_session *session, int fd)
835{
836 struct perf_header *self = &session->header;
837 struct perf_pipe_file_header f_header;
838
839 if (perf_file_header__read_pipe(&f_header, self, fd,
840 session->repipe) < 0) {
841 pr_debug("incompatible file format\n");
842 return -EINVAL;
843 }
844
845 session->fd = fd;
846
847 return 0;
848}
849
850int perf_header__read(struct perf_session *session, int fd)
851{
852 struct perf_header *self = &session->header;
853 struct perf_file_header f_header;
473 struct perf_file_attr f_attr; 854 struct perf_file_attr f_attr;
474 u64 f_id; 855 u64 f_id;
475 int nr_attrs, nr_ids, i, j; 856 int nr_attrs, nr_ids, i, j;
476 857
858 if (session->fd_pipe)
859 return perf_header__read_pipe(session, fd);
860
477 if (perf_file_header__read(&f_header, self, fd) < 0) { 861 if (perf_file_header__read(&f_header, self, fd) < 0) {
478 pr_debug("incompatible file format\n"); 862 pr_debug("incompatible file format\n");
479 return -EINVAL; 863 return -EINVAL;
@@ -486,7 +870,9 @@ int perf_header__read(struct perf_header *self, int fd)
486 struct perf_header_attr *attr; 870 struct perf_header_attr *attr;
487 off_t tmp; 871 off_t tmp;
488 872
489 do_read(fd, &f_attr, sizeof(f_attr)); 873 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
874 goto out_errno;
875
490 tmp = lseek(fd, 0, SEEK_CUR); 876 tmp = lseek(fd, 0, SEEK_CUR);
491 877
492 attr = perf_header_attr__new(&f_attr.attr); 878 attr = perf_header_attr__new(&f_attr.attr);
@@ -497,7 +883,8 @@ int perf_header__read(struct perf_header *self, int fd)
497 lseek(fd, f_attr.ids.offset, SEEK_SET); 883 lseek(fd, f_attr.ids.offset, SEEK_SET);
498 884
499 for (j = 0; j < nr_ids; j++) { 885 for (j = 0; j < nr_ids; j++) {
500 do_read(fd, &f_id, sizeof(f_id)); 886 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
887 goto out_errno;
501 888
502 if (perf_header_attr__add_id(attr, f_id) < 0) { 889 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr); 890 perf_header_attr__delete(attr);
@@ -517,7 +904,9 @@ int perf_header__read(struct perf_header *self, int fd)
517 events = malloc(f_header.event_types.size); 904 events = malloc(f_header.event_types.size);
518 if (events == NULL) 905 if (events == NULL)
519 return -ENOMEM; 906 return -ENOMEM;
520 do_read(fd, events, f_header.event_types.size); 907 if (perf_header__getbuffer64(self, fd, events,
908 f_header.event_types.size))
909 goto out_errno;
521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 910 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
522 } 911 }
523 912
@@ -527,6 +916,8 @@ int perf_header__read(struct perf_header *self, int fd)
527 916
528 self->frozen = 1; 917 self->frozen = 1;
529 return 0; 918 return 0;
919out_errno:
920 return -errno;
530} 921}
531 922
532u64 perf_header__sample_type(struct perf_header *header) 923u64 perf_header__sample_type(struct perf_header *header)
@@ -551,6 +942,14 @@ perf_header__find_attr(u64 id, struct perf_header *header)
551{ 942{
552 int i; 943 int i;
553 944
945 /*
946 * We set id to -1 if the data file doesn't contain sample
947 * ids. Check for this and avoid walking through the entire
948 * list of ids which may be large.
949 */
950 if (id == -1ULL)
951 return NULL;
952
554 for (i = 0; i < header->attrs; i++) { 953 for (i = 0; i < header->attrs; i++) {
555 struct perf_header_attr *attr = header->attr[i]; 954 struct perf_header_attr *attr = header->attr[i];
556 int j; 955 int j;
@@ -563,3 +962,231 @@ perf_header__find_attr(u64 id, struct perf_header *header)
563 962
564 return NULL; 963 return NULL;
565} 964}
965
966int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
967 event__handler_t process,
968 struct perf_session *session)
969{
970 event_t *ev;
971 size_t size;
972 int err;
973
974 size = sizeof(struct perf_event_attr);
975 size = ALIGN(size, sizeof(u64));
976 size += sizeof(struct perf_event_header);
977 size += ids * sizeof(u64);
978
979 ev = malloc(size);
980
981 ev->attr.attr = *attr;
982 memcpy(ev->attr.id, id, ids * sizeof(u64));
983
984 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
985 ev->attr.header.size = size;
986
987 err = process(ev, session);
988
989 free(ev);
990
991 return err;
992}
993
994int event__synthesize_attrs(struct perf_header *self,
995 event__handler_t process,
996 struct perf_session *session)
997{
998 struct perf_header_attr *attr;
999 int i, err = 0;
1000
1001 for (i = 0; i < self->attrs; i++) {
1002 attr = self->attr[i];
1003
1004 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id,
1005 process, session);
1006 if (err) {
1007 pr_debug("failed to create perf header attribute\n");
1008 return err;
1009 }
1010 }
1011
1012 return err;
1013}
1014
1015int event__process_attr(event_t *self, struct perf_session *session)
1016{
1017 struct perf_header_attr *attr;
1018 unsigned int i, ids, n_ids;
1019
1020 attr = perf_header_attr__new(&self->attr.attr);
1021 if (attr == NULL)
1022 return -ENOMEM;
1023
1024 ids = self->header.size;
1025 ids -= (void *)&self->attr.id - (void *)self;
1026 n_ids = ids / sizeof(u64);
1027
1028 for (i = 0; i < n_ids; i++) {
1029 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) {
1030 perf_header_attr__delete(attr);
1031 return -ENOMEM;
1032 }
1033 }
1034
1035 if (perf_header__add_attr(&session->header, attr) < 0) {
1036 perf_header_attr__delete(attr);
1037 return -ENOMEM;
1038 }
1039
1040 perf_session__update_sample_type(session);
1041
1042 return 0;
1043}
1044
1045int event__synthesize_event_type(u64 event_id, char *name,
1046 event__handler_t process,
1047 struct perf_session *session)
1048{
1049 event_t ev;
1050 size_t size = 0;
1051 int err = 0;
1052
1053 memset(&ev, 0, sizeof(ev));
1054
1055 ev.event_type.event_type.event_id = event_id;
1056 memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
1057 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
1058
1059 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
1060 size = strlen(name);
1061 size = ALIGN(size, sizeof(u64));
1062 ev.event_type.header.size = sizeof(ev.event_type) -
1063 (sizeof(ev.event_type.event_type.name) - size);
1064
1065 err = process(&ev, session);
1066
1067 return err;
1068}
1069
1070int event__synthesize_event_types(event__handler_t process,
1071 struct perf_session *session)
1072{
1073 struct perf_trace_event_type *type;
1074 int i, err = 0;
1075
1076 for (i = 0; i < event_count; i++) {
1077 type = &events[i];
1078
1079 err = event__synthesize_event_type(type->event_id, type->name,
1080 process, session);
1081 if (err) {
1082 pr_debug("failed to create perf header event type\n");
1083 return err;
1084 }
1085 }
1086
1087 return err;
1088}
1089
1090int event__process_event_type(event_t *self,
1091 struct perf_session *session __unused)
1092{
1093 if (perf_header__push_event(self->event_type.event_type.event_id,
1094 self->event_type.event_type.name) < 0)
1095 return -ENOMEM;
1096
1097 return 0;
1098}
1099
1100int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
1101 int nb_events,
1102 event__handler_t process,
1103 struct perf_session *session __unused)
1104{
1105 event_t ev;
1106 ssize_t size = 0, aligned_size = 0, padding;
1107 int err = 0;
1108
1109 memset(&ev, 0, sizeof(ev));
1110
1111 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1112 size = read_tracing_data_size(fd, pattrs, nb_events);
1113 if (size <= 0)
1114 return size;
1115 aligned_size = ALIGN(size, sizeof(u64));
1116 padding = aligned_size - size;
1117 ev.tracing_data.header.size = sizeof(ev.tracing_data);
1118 ev.tracing_data.size = aligned_size;
1119
1120 process(&ev, session);
1121
1122 err = read_tracing_data(fd, pattrs, nb_events);
1123 write_padded(fd, NULL, 0, padding);
1124
1125 return aligned_size;
1126}
1127
1128int event__process_tracing_data(event_t *self,
1129 struct perf_session *session)
1130{
1131 ssize_t size_read, padding, size = self->tracing_data.size;
1132 off_t offset = lseek(session->fd, 0, SEEK_CUR);
1133 char buf[BUFSIZ];
1134
1135 /* setup for reading amidst mmap */
1136 lseek(session->fd, offset + sizeof(struct tracing_data_event),
1137 SEEK_SET);
1138
1139 size_read = trace_report(session->fd, session->repipe);
1140
1141 padding = ALIGN(size_read, sizeof(u64)) - size_read;
1142
1143 if (read(session->fd, buf, padding) < 0)
1144 die("reading input file");
1145 if (session->repipe) {
1146 int retw = write(STDOUT_FILENO, buf, padding);
1147 if (retw <= 0 || retw != padding)
1148 die("repiping tracing data padding");
1149 }
1150
1151 if (size_read + padding != size)
1152 die("tracing data size mismatch");
1153
1154 return size_read + padding;
1155}
1156
1157int event__synthesize_build_id(struct dso *pos, u16 misc,
1158 event__handler_t process,
1159 struct machine *machine,
1160 struct perf_session *session)
1161{
1162 event_t ev;
1163 size_t len;
1164 int err = 0;
1165
1166 if (!pos->hit)
1167 return err;
1168
1169 memset(&ev, 0, sizeof(ev));
1170
1171 len = pos->long_name_len + 1;
1172 len = ALIGN(len, NAME_ALIGN);
1173 memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
1174 ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
1175 ev.build_id.header.misc = misc;
1176 ev.build_id.pid = machine->pid;
1177 ev.build_id.header.size = sizeof(ev.build_id) + len;
1178 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
1179
1180 err = process(&ev, session);
1181
1182 return err;
1183}
1184
1185int event__process_build_id(event_t *self,
1186 struct perf_session *session)
1187{
1188 __event_process_build_id(&self->build_id,
1189 self->build_id.filename,
1190 session);
1191 return 0;
1192}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d118d05d3abe..402ac2454cf8 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -5,6 +5,7 @@
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
8#include "event.h"
8 9
9#include <linux/bitmap.h> 10#include <linux/bitmap.h>
10 11
@@ -38,6 +39,11 @@ struct perf_file_header {
38 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 39 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
39}; 40};
40 41
42struct perf_pipe_file_header {
43 u64 magic;
44 u64 size;
45};
46
41struct perf_header; 47struct perf_header;
42 48
43int perf_file_header__read(struct perf_file_header *self, 49int perf_file_header__read(struct perf_file_header *self,
@@ -46,6 +52,7 @@ int perf_file_header__read(struct perf_file_header *self,
46struct perf_header { 52struct perf_header {
47 int frozen; 53 int frozen;
48 int attrs, size; 54 int attrs, size;
55 bool needs_swap;
49 struct perf_header_attr **attr; 56 struct perf_header_attr **attr;
50 s64 attr_offset; 57 s64 attr_offset;
51 u64 data_offset; 58 u64 data_offset;
@@ -58,13 +65,14 @@ struct perf_header {
58int perf_header__init(struct perf_header *self); 65int perf_header__init(struct perf_header *self);
59void perf_header__exit(struct perf_header *self); 66void perf_header__exit(struct perf_header *self);
60 67
61int perf_header__read(struct perf_header *self, int fd); 68int perf_header__read(struct perf_session *session, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit); 69int perf_header__write(struct perf_header *self, int fd, bool at_exit);
70int perf_header__write_pipe(int fd);
63 71
64int perf_header__add_attr(struct perf_header *self, 72int perf_header__add_attr(struct perf_header *self,
65 struct perf_header_attr *attr); 73 struct perf_header_attr *attr);
66 74
67void perf_header__push_event(u64 id, const char *name); 75int perf_header__push_event(u64 id, const char *name);
68char *perf_header__find_event(u64 id); 76char *perf_header__find_event(u64 id);
69 77
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 78struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
@@ -80,6 +88,40 @@ bool perf_header__has_feat(const struct perf_header *self, int feat);
80 88
81int perf_header__process_sections(struct perf_header *self, int fd, 89int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self, 90 int (*process)(struct perf_file_section *self,
91 struct perf_header *ph,
83 int feat, int fd)); 92 int feat, int fd));
84 93
94int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
95 const char *name, bool is_kallsyms);
96int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
97
98int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
99 event__handler_t process,
100 struct perf_session *session);
101int event__synthesize_attrs(struct perf_header *self,
102 event__handler_t process,
103 struct perf_session *session);
104int event__process_attr(event_t *self, struct perf_session *session);
105
106int event__synthesize_event_type(u64 event_id, char *name,
107 event__handler_t process,
108 struct perf_session *session);
109int event__synthesize_event_types(event__handler_t process,
110 struct perf_session *session);
111int event__process_event_type(event_t *self,
112 struct perf_session *session);
113
114int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
115 int nb_events,
116 event__handler_t process,
117 struct perf_session *session);
118int event__process_tracing_data(event_t *self,
119 struct perf_session *session);
120
121int event__synthesize_build_id(struct dso *pos, u16 misc,
122 event__handler_t process,
123 struct machine *machine,
124 struct perf_session *session);
125int event__process_build_id(event_t *self, struct perf_session *session);
126
85#endif /* __PERF_HEADER_H */ 127#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index fbb00978b2e2..6f2975a00358 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -4,28 +4,6 @@
4#include "levenshtein.h" 4#include "levenshtein.h"
5#include "help.h" 5#include "help.h"
6 6
7/* most GUI terminals set COLUMNS (although some don't export it) */
8static int term_columns(void)
9{
10 char *col_string = getenv("COLUMNS");
11 int n_cols;
12
13 if (col_string && (n_cols = atoi(col_string)) > 0)
14 return n_cols;
15
16#ifdef TIOCGWINSZ
17 {
18 struct winsize ws;
19 if (!ioctl(1, TIOCGWINSZ, &ws)) {
20 if (ws.ws_col)
21 return ws.ws_col;
22 }
23 }
24#endif
25
26 return 80;
27}
28
29void add_cmdname(struct cmdnames *cmds, const char *name, size_t len) 7void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
30{ 8{
31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1); 9 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
@@ -96,9 +74,13 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
96{ 74{
97 int cols = 1, rows; 75 int cols = 1, rows;
98 int space = longest + 1; /* min 1 SP between words */ 76 int space = longest + 1; /* min 1 SP between words */
99 int max_cols = term_columns() - 1; /* don't print *on* the edge */ 77 struct winsize win;
78 int max_cols;
100 int i, j; 79 int i, j;
101 80
81 get_term_dimensions(&win);
82 max_cols = win.ws_col - 1; /* don't print *on* the edge */
83
102 if (space < max_cols) 84 if (space < max_cols)
103 cols = max_cols / space; 85 cols = max_cols / space;
104 rows = (cmds->cnt + cols - 1) / cols; 86 rows = (cmds->cnt + cols - 1) / cols;
@@ -324,7 +306,7 @@ const char *help_unknown_cmd(const char *cmd)
324 306
325 main_cmds.names[0] = NULL; 307 main_cmds.names[0] = NULL;
326 clean_cmdnames(&main_cmds); 308 clean_cmdnames(&main_cmds);
327 fprintf(stderr, "WARNING: You called a Git program named '%s', " 309 fprintf(stderr, "WARNING: You called a perf program named '%s', "
328 "which does not exist.\n" 310 "which does not exist.\n"
329 "Continuing under the assumption that you meant '%s'\n", 311 "Continuing under the assumption that you meant '%s'\n",
330 cmd, assumed); 312 cmd, assumed);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e8daf5ca6fd2..784ee0bdda77 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,3 +1,5 @@
1#include "util.h"
2#include "build-id.h"
1#include "hist.h" 3#include "hist.h"
2#include "session.h" 4#include "session.h"
3#include "sort.h" 5#include "sort.h"
@@ -8,25 +10,69 @@ struct callchain_param callchain_param = {
8 .min_percent = 0.5 10 .min_percent = 0.5
9}; 11};
10 12
13static void hist_entry__add_cpumode_period(struct hist_entry *self,
14 unsigned int cpumode, u64 period)
15{
16 switch (cpumode) {
17 case PERF_RECORD_MISC_KERNEL:
18 self->period_sys += period;
19 break;
20 case PERF_RECORD_MISC_USER:
21 self->period_us += period;
22 break;
23 case PERF_RECORD_MISC_GUEST_KERNEL:
24 self->period_guest_sys += period;
25 break;
26 case PERF_RECORD_MISC_GUEST_USER:
27 self->period_guest_us += period;
28 break;
29 default:
30 break;
31 }
32}
33
11/* 34/*
12 * histogram, sorted on item, collects counts 35 * histogram, sorted on item, collects periods
13 */ 36 */
14 37
15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 38static struct hist_entry *hist_entry__new(struct hist_entry *template)
16 struct addr_location *al,
17 struct symbol *sym_parent,
18 u64 count, bool *hit)
19{ 39{
20 struct rb_node **p = &self->hists.rb_node; 40 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0;
41 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
42
43 if (self != NULL) {
44 *self = *template;
45 self->nr_events = 1;
46 if (symbol_conf.use_callchain)
47 callchain_init(self->callchain);
48 }
49
50 return self;
51}
52
53static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry)
54{
55 if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen)
56 self->max_sym_namelen = entry->ms.sym->namelen;
57 ++self->nr_entries;
58}
59
60struct hist_entry *__hists__add_entry(struct hists *self,
61 struct addr_location *al,
62 struct symbol *sym_parent, u64 period)
63{
64 struct rb_node **p = &self->entries.rb_node;
21 struct rb_node *parent = NULL; 65 struct rb_node *parent = NULL;
22 struct hist_entry *he; 66 struct hist_entry *he;
23 struct hist_entry entry = { 67 struct hist_entry entry = {
24 .thread = al->thread, 68 .thread = al->thread,
25 .map = al->map, 69 .ms = {
26 .sym = al->sym, 70 .map = al->map,
71 .sym = al->sym,
72 },
27 .ip = al->addr, 73 .ip = al->addr,
28 .level = al->level, 74 .level = al->level,
29 .count = count, 75 .period = period,
30 .parent = sym_parent, 76 .parent = sym_parent,
31 }; 77 };
32 int cmp; 78 int cmp;
@@ -38,8 +84,9 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
38 cmp = hist_entry__cmp(&entry, he); 84 cmp = hist_entry__cmp(&entry, he);
39 85
40 if (!cmp) { 86 if (!cmp) {
41 *hit = true; 87 he->period += period;
42 return he; 88 ++he->nr_events;
89 goto out;
43 } 90 }
44 91
45 if (cmp < 0) 92 if (cmp < 0)
@@ -48,13 +95,14 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
48 p = &(*p)->rb_right; 95 p = &(*p)->rb_right;
49 } 96 }
50 97
51 he = malloc(sizeof(*he)); 98 he = hist_entry__new(&entry);
52 if (!he) 99 if (!he)
53 return NULL; 100 return NULL;
54 *he = entry;
55 rb_link_node(&he->rb_node, parent, p); 101 rb_link_node(&he->rb_node, parent, p);
56 rb_insert_color(&he->rb_node, &self->hists); 102 rb_insert_color(&he->rb_node, &self->entries);
57 *hit = false; 103 hists__inc_nr_entries(self, he);
104out:
105 hist_entry__add_cpumode_period(he, al->cpumode, period);
58 return he; 106 return he;
59} 107}
60 108
@@ -65,7 +113,7 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
65 int64_t cmp = 0; 113 int64_t cmp = 0;
66 114
67 list_for_each_entry(se, &hist_entry__sort_list, list) { 115 list_for_each_entry(se, &hist_entry__sort_list, list) {
68 cmp = se->cmp(left, right); 116 cmp = se->se_cmp(left, right);
69 if (cmp) 117 if (cmp)
70 break; 118 break;
71 } 119 }
@@ -82,7 +130,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
82 list_for_each_entry(se, &hist_entry__sort_list, list) { 130 list_for_each_entry(se, &hist_entry__sort_list, list) {
83 int64_t (*f)(struct hist_entry *, struct hist_entry *); 131 int64_t (*f)(struct hist_entry *, struct hist_entry *);
84 132
85 f = se->collapse ?: se->cmp; 133 f = se->se_collapse ?: se->se_cmp;
86 134
87 cmp = f(left, right); 135 cmp = f(left, right);
88 if (cmp) 136 if (cmp)
@@ -101,7 +149,7 @@ void hist_entry__free(struct hist_entry *he)
101 * collapse the histogram 149 * collapse the histogram
102 */ 150 */
103 151
104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he) 152static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
105{ 153{
106 struct rb_node **p = &root->rb_node; 154 struct rb_node **p = &root->rb_node;
107 struct rb_node *parent = NULL; 155 struct rb_node *parent = NULL;
@@ -115,9 +163,9 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
115 cmp = hist_entry__collapse(iter, he); 163 cmp = hist_entry__collapse(iter, he);
116 164
117 if (!cmp) { 165 if (!cmp) {
118 iter->count += he->count; 166 iter->period += he->period;
119 hist_entry__free(he); 167 hist_entry__free(he);
120 return; 168 return false;
121 } 169 }
122 170
123 if (cmp < 0) 171 if (cmp < 0)
@@ -128,9 +176,10 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
128 176
129 rb_link_node(&he->rb_node, parent, p); 177 rb_link_node(&he->rb_node, parent, p);
130 rb_insert_color(&he->rb_node, root); 178 rb_insert_color(&he->rb_node, root);
179 return true;
131} 180}
132 181
133void perf_session__collapse_resort(struct perf_session *self) 182void hists__collapse_resort(struct hists *self)
134{ 183{
135 struct rb_root tmp; 184 struct rb_root tmp;
136 struct rb_node *next; 185 struct rb_node *next;
@@ -140,72 +189,77 @@ void perf_session__collapse_resort(struct perf_session *self)
140 return; 189 return;
141 190
142 tmp = RB_ROOT; 191 tmp = RB_ROOT;
143 next = rb_first(&self->hists); 192 next = rb_first(&self->entries);
193 self->nr_entries = 0;
194 self->max_sym_namelen = 0;
144 195
145 while (next) { 196 while (next) {
146 n = rb_entry(next, struct hist_entry, rb_node); 197 n = rb_entry(next, struct hist_entry, rb_node);
147 next = rb_next(&n->rb_node); 198 next = rb_next(&n->rb_node);
148 199
149 rb_erase(&n->rb_node, &self->hists); 200 rb_erase(&n->rb_node, &self->entries);
150 collapse__insert_entry(&tmp, n); 201 if (collapse__insert_entry(&tmp, n))
202 hists__inc_nr_entries(self, n);
151 } 203 }
152 204
153 self->hists = tmp; 205 self->entries = tmp;
154} 206}
155 207
156/* 208/*
157 * reverse the map, sort on count. 209 * reverse the map, sort on period.
158 */ 210 */
159 211
160static void perf_session__insert_output_hist_entry(struct rb_root *root, 212static void __hists__insert_output_entry(struct rb_root *entries,
161 struct hist_entry *he, 213 struct hist_entry *he,
162 u64 min_callchain_hits) 214 u64 min_callchain_hits)
163{ 215{
164 struct rb_node **p = &root->rb_node; 216 struct rb_node **p = &entries->rb_node;
165 struct rb_node *parent = NULL; 217 struct rb_node *parent = NULL;
166 struct hist_entry *iter; 218 struct hist_entry *iter;
167 219
168 if (symbol_conf.use_callchain) 220 if (symbol_conf.use_callchain)
169 callchain_param.sort(&he->sorted_chain, &he->callchain, 221 callchain_param.sort(&he->sorted_chain, he->callchain,
170 min_callchain_hits, &callchain_param); 222 min_callchain_hits, &callchain_param);
171 223
172 while (*p != NULL) { 224 while (*p != NULL) {
173 parent = *p; 225 parent = *p;
174 iter = rb_entry(parent, struct hist_entry, rb_node); 226 iter = rb_entry(parent, struct hist_entry, rb_node);
175 227
176 if (he->count > iter->count) 228 if (he->period > iter->period)
177 p = &(*p)->rb_left; 229 p = &(*p)->rb_left;
178 else 230 else
179 p = &(*p)->rb_right; 231 p = &(*p)->rb_right;
180 } 232 }
181 233
182 rb_link_node(&he->rb_node, parent, p); 234 rb_link_node(&he->rb_node, parent, p);
183 rb_insert_color(&he->rb_node, root); 235 rb_insert_color(&he->rb_node, entries);
184} 236}
185 237
186void perf_session__output_resort(struct perf_session *self, u64 total_samples) 238void hists__output_resort(struct hists *self)
187{ 239{
188 struct rb_root tmp; 240 struct rb_root tmp;
189 struct rb_node *next; 241 struct rb_node *next;
190 struct hist_entry *n; 242 struct hist_entry *n;
191 u64 min_callchain_hits; 243 u64 min_callchain_hits;
192 244
193 min_callchain_hits = 245 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100);
194 total_samples * (callchain_param.min_percent / 100);
195 246
196 tmp = RB_ROOT; 247 tmp = RB_ROOT;
197 next = rb_first(&self->hists); 248 next = rb_first(&self->entries);
249
250 self->nr_entries = 0;
251 self->max_sym_namelen = 0;
198 252
199 while (next) { 253 while (next) {
200 n = rb_entry(next, struct hist_entry, rb_node); 254 n = rb_entry(next, struct hist_entry, rb_node);
201 next = rb_next(&n->rb_node); 255 next = rb_next(&n->rb_node);
202 256
203 rb_erase(&n->rb_node, &self->hists); 257 rb_erase(&n->rb_node, &self->entries);
204 perf_session__insert_output_hist_entry(&tmp, n, 258 __hists__insert_output_entry(&tmp, n, min_callchain_hits);
205 min_callchain_hits); 259 hists__inc_nr_entries(self, n);
206 } 260 }
207 261
208 self->hists = tmp; 262 self->entries = tmp;
209} 263}
210 264
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 265static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -237,7 +291,7 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
237} 291}
238 292
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 293static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count, 294 int depth, int depth_mask, int period,
241 u64 total_samples, int hits, 295 u64 total_samples, int hits,
242 int left_margin) 296 int left_margin)
243{ 297{
@@ -250,7 +304,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
250 ret += fprintf(fp, "|"); 304 ret += fprintf(fp, "|");
251 else 305 else
252 ret += fprintf(fp, " "); 306 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) { 307 if (!period && i == depth - 1) {
254 double percent; 308 double percent;
255 309
256 percent = hits * 100.0 / total_samples; 310 percent = hits * 100.0 / total_samples;
@@ -258,8 +312,8 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
258 } else 312 } else
259 ret += fprintf(fp, "%s", " "); 313 ret += fprintf(fp, "%s", " ");
260 } 314 }
261 if (chain->sym) 315 if (chain->ms.sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name); 316 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
263 else 317 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 318 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265 319
@@ -278,7 +332,7 @@ static void init_rem_hits(void)
278 } 332 }
279 333
280 strcpy(rem_sq_bracket->name, "[...]"); 334 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket; 335 rem_hits.ms.sym = rem_sq_bracket;
282} 336}
283 337
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 338static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
@@ -293,6 +347,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
293 u64 remaining; 347 u64 remaining;
294 size_t ret = 0; 348 size_t ret = 0;
295 int i; 349 int i;
350 uint entries_printed = 0;
296 351
297 if (callchain_param.mode == CHAIN_GRAPH_REL) 352 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit; 353 new_total = self->children_hit;
@@ -321,15 +376,13 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
321 new_depth_mask &= ~(1 << (depth - 1)); 376 new_depth_mask &= ~(1 << (depth - 1));
322 377
323 /* 378 /*
324 * But we keep the older depth mask for the line seperator 379 * But we keep the older depth mask for the line separator
325 * to keep the level link until we reach the last child 380 * to keep the level link until we reach the last child
326 */ 381 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 382 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin); 383 left_margin);
329 i = 0; 384 i = 0;
330 list_for_each_entry(chain, &child->val, list) { 385 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, 386 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++, 387 new_depth_mask, i++,
335 new_total, 388 new_total,
@@ -341,6 +394,8 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
341 new_depth_mask | (1 << depth), 394 new_depth_mask | (1 << depth),
342 left_margin); 395 left_margin);
343 node = next; 396 node = next;
397 if (++entries_printed == callchain_param.print_limit)
398 break;
344 } 399 }
345 400
346 if (callchain_param.mode == CHAIN_GRAPH_REL && 401 if (callchain_param.mode == CHAIN_GRAPH_REL &&
@@ -366,11 +421,9 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
366 bool printed = false; 421 bool printed = false;
367 int i = 0; 422 int i = 0;
368 int ret = 0; 423 int ret = 0;
424 u32 entries_printed = 0;
369 425
370 list_for_each_entry(chain, &self->val, list) { 426 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) 427 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue; 428 continue;
376 429
@@ -385,10 +438,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
385 } else 438 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin); 439 ret += callchain__fprintf_left_margin(fp, left_margin);
387 440
388 if (chain->sym) 441 if (chain->ms.sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name); 442 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
390 else 443 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 444 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
445
446 if (++entries_printed == callchain_param.print_limit)
447 break;
392 } 448 }
393 449
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 450 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
@@ -411,8 +467,8 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
411 list_for_each_entry(chain, &self->val, list) { 467 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX) 468 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue; 469 continue;
414 if (chain->sym) 470 if (chain->ms.sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name); 471 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
416 else 472 else
417 ret += fprintf(fp, " %p\n", 473 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip); 474 (void *)(long)chain->ip);
@@ -427,6 +483,7 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
427 struct rb_node *rb_node; 483 struct rb_node *rb_node;
428 struct callchain_node *chain; 484 struct callchain_node *chain;
429 size_t ret = 0; 485 size_t ret = 0;
486 u32 entries_printed = 0;
430 487
431 rb_node = rb_first(&self->sorted_chain); 488 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) { 489 while (rb_node) {
@@ -449,55 +506,88 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
449 break; 506 break;
450 } 507 }
451 ret += fprintf(fp, "\n"); 508 ret += fprintf(fp, "\n");
509 if (++entries_printed == callchain_param.print_limit)
510 break;
452 rb_node = rb_next(rb_node); 511 rb_node = rb_next(rb_node);
453 } 512 }
454 513
455 return ret; 514 return ret;
456} 515}
457 516
458static size_t hist_entry__fprintf(struct hist_entry *self, 517int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
459 struct perf_session *session, 518 struct hists *pair_hists, bool show_displacement,
460 struct perf_session *pair_session, 519 long displacement, bool color, u64 session_total)
461 bool show_displacement,
462 long displacement, FILE *fp)
463{ 520{
464 struct sort_entry *se; 521 struct sort_entry *se;
465 u64 count, total; 522 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
466 const char *sep = symbol_conf.field_sep; 523 const char *sep = symbol_conf.field_sep;
467 size_t ret; 524 int ret;
468 525
469 if (symbol_conf.exclude_other && !self->parent) 526 if (symbol_conf.exclude_other && !self->parent)
470 return 0; 527 return 0;
471 528
472 if (pair_session) { 529 if (pair_hists) {
473 count = self->pair ? self->pair->count : 0; 530 period = self->pair ? self->pair->period : 0;
474 total = pair_session->events_stats.total; 531 total = pair_hists->stats.total_period;
532 period_sys = self->pair ? self->pair->period_sys : 0;
533 period_us = self->pair ? self->pair->period_us : 0;
534 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
535 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
475 } else { 536 } else {
476 count = self->count; 537 period = self->period;
477 total = session->events_stats.total; 538 total = session_total;
539 period_sys = self->period_sys;
540 period_us = self->period_us;
541 period_guest_sys = self->period_guest_sys;
542 period_guest_us = self->period_guest_us;
478 } 543 }
479 544
480 if (total) 545 if (total) {
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%", 546 if (color)
482 (count * 100.0) / total); 547 ret = percent_color_snprintf(s, size,
483 else 548 sep ? "%.2f" : " %6.2f%%",
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count); 549 (period * 100.0) / total);
550 else
551 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
552 (period * 100.0) / total);
553 if (symbol_conf.show_cpu_utilization) {
554 ret += percent_color_snprintf(s + ret, size - ret,
555 sep ? "%.2f" : " %6.2f%%",
556 (period_sys * 100.0) / total);
557 ret += percent_color_snprintf(s + ret, size - ret,
558 sep ? "%.2f" : " %6.2f%%",
559 (period_us * 100.0) / total);
560 if (perf_guest) {
561 ret += percent_color_snprintf(s + ret,
562 size - ret,
563 sep ? "%.2f" : " %6.2f%%",
564 (period_guest_sys * 100.0) /
565 total);
566 ret += percent_color_snprintf(s + ret,
567 size - ret,
568 sep ? "%.2f" : " %6.2f%%",
569 (period_guest_us * 100.0) /
570 total);
571 }
572 }
573 } else
574 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period);
485 575
486 if (symbol_conf.show_nr_samples) { 576 if (symbol_conf.show_nr_samples) {
487 if (sep) 577 if (sep)
488 fprintf(fp, "%c%lld", *sep, count); 578 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period);
489 else 579 else
490 fprintf(fp, "%11lld", count); 580 ret += snprintf(s + ret, size - ret, "%11lld", period);
491 } 581 }
492 582
493 if (pair_session) { 583 if (pair_hists) {
494 char bf[32]; 584 char bf[32];
495 double old_percent = 0, new_percent = 0, diff; 585 double old_percent = 0, new_percent = 0, diff;
496 586
497 if (total > 0) 587 if (total > 0)
498 old_percent = (count * 100.0) / total; 588 old_percent = (period * 100.0) / total;
499 if (session->events_stats.total > 0) 589 if (session_total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total; 590 new_percent = (self->period * 100.0) / session_total;
501 591
502 diff = new_percent - old_percent; 592 diff = new_percent - old_percent;
503 593
@@ -507,9 +597,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
507 snprintf(bf, sizeof(bf), " "); 597 snprintf(bf, sizeof(bf), " ");
508 598
509 if (sep) 599 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf); 600 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
511 else 601 else
512 ret += fprintf(fp, "%11.11s", bf); 602 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
513 603
514 if (show_displacement) { 604 if (show_displacement) {
515 if (displacement) 605 if (displacement)
@@ -518,9 +608,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
518 snprintf(bf, sizeof(bf), " "); 608 snprintf(bf, sizeof(bf), " ");
519 609
520 if (sep) 610 if (sep)
521 fprintf(fp, "%c%s", *sep, bf); 611 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
522 else 612 else
523 fprintf(fp, "%6.6s", bf); 613 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
524 } 614 }
525 } 615 }
526 616
@@ -528,32 +618,48 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
528 if (se->elide) 618 if (se->elide)
529 continue; 619 continue;
530 620
531 fprintf(fp, "%s", sep ?: " "); 621 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0); 622 ret += se->se_snprintf(self, s + ret, size - ret,
623 se->se_width ? *se->se_width : 0);
533 } 624 }
534 625
535 ret += fprintf(fp, "\n"); 626 return ret;
627}
536 628
537 if (symbol_conf.use_callchain) { 629int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
538 int left_margin = 0; 630 bool show_displacement, long displacement, FILE *fp,
631 u64 session_total)
632{
633 char bf[512];
634 int ret;
539 635
540 if (sort__first_dimension == SORT_COMM) { 636 ret = hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se), 637 show_displacement, displacement,
542 list); 638 true, session_total);
543 left_margin = se->width ? *se->width : 0; 639 if (!ret)
544 left_margin -= thread__comm_len(self->thread); 640 return 0;
545 } 641
642 return fprintf(fp, "%s\n", bf);
643}
644
645static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
646 u64 session_total)
647{
648 int left_margin = 0;
546 649
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total, 650 if (sort__first_dimension == SORT_COMM) {
548 left_margin); 651 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
652 typeof(*se), list);
653 left_margin = se->se_width ? *se->se_width : 0;
654 left_margin -= thread__comm_len(self->thread);
549 } 655 }
550 656
551 return ret; 657 return hist_entry_callchain__fprintf(fp, self, session_total,
658 left_margin);
552} 659}
553 660
554size_t perf_session__fprintf_hists(struct perf_session *self, 661size_t hists__fprintf(struct hists *self, struct hists *pair,
555 struct perf_session *pair, 662 bool show_displacement, FILE *fp)
556 bool show_displacement, FILE *fp)
557{ 663{
558 struct sort_entry *se; 664 struct sort_entry *se;
559 struct rb_node *nd; 665 struct rb_node *nd;
@@ -562,7 +668,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
562 long displacement = 0; 668 long displacement = 0;
563 unsigned int width; 669 unsigned int width;
564 const char *sep = symbol_conf.field_sep; 670 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str; 671 const char *col_width = symbol_conf.col_width_list_str;
566 672
567 init_rem_hits(); 673 init_rem_hits();
568 674
@@ -575,6 +681,24 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
575 fputs(" Samples ", fp); 681 fputs(" Samples ", fp);
576 } 682 }
577 683
684 if (symbol_conf.show_cpu_utilization) {
685 if (sep) {
686 ret += fprintf(fp, "%csys", *sep);
687 ret += fprintf(fp, "%cus", *sep);
688 if (perf_guest) {
689 ret += fprintf(fp, "%cguest sys", *sep);
690 ret += fprintf(fp, "%cguest us", *sep);
691 }
692 } else {
693 ret += fprintf(fp, " sys ");
694 ret += fprintf(fp, " us ");
695 if (perf_guest) {
696 ret += fprintf(fp, " guest sys ");
697 ret += fprintf(fp, " guest us ");
698 }
699 }
700 }
701
578 if (pair) { 702 if (pair) {
579 if (sep) 703 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep); 704 ret += fprintf(fp, "%cDelta", *sep);
@@ -593,22 +717,22 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
593 if (se->elide) 717 if (se->elide)
594 continue; 718 continue;
595 if (sep) { 719 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header); 720 fprintf(fp, "%c%s", *sep, se->se_header);
597 continue; 721 continue;
598 } 722 }
599 width = strlen(se->header); 723 width = strlen(se->se_header);
600 if (se->width) { 724 if (se->se_width) {
601 if (symbol_conf.col_width_list_str) { 725 if (symbol_conf.col_width_list_str) {
602 if (col_width) { 726 if (col_width) {
603 *se->width = atoi(col_width); 727 *se->se_width = atoi(col_width);
604 col_width = strchr(col_width, ','); 728 col_width = strchr(col_width, ',');
605 if (col_width) 729 if (col_width)
606 ++col_width; 730 ++col_width;
607 } 731 }
608 } 732 }
609 width = *se->width = max(*se->width, width); 733 width = *se->se_width = max(*se->se_width, width);
610 } 734 }
611 fprintf(fp, " %*s", width, se->header); 735 fprintf(fp, " %*s", width, se->se_header);
612 } 736 }
613 fprintf(fp, "\n"); 737 fprintf(fp, "\n");
614 738
@@ -630,10 +754,10 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
630 continue; 754 continue;
631 755
632 fprintf(fp, " "); 756 fprintf(fp, " ");
633 if (se->width) 757 if (se->se_width)
634 width = *se->width; 758 width = *se->se_width;
635 else 759 else
636 width = strlen(se->header); 760 width = strlen(se->se_header);
637 for (i = 0; i < width; i++) 761 for (i = 0; i < width; i++)
638 fprintf(fp, "."); 762 fprintf(fp, ".");
639 } 763 }
@@ -641,8 +765,9 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
641 fprintf(fp, "\n#\n"); 765 fprintf(fp, "\n#\n");
642 766
643print_entries: 767print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { 768 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 769 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
770 int cnt;
646 771
647 if (show_displacement) { 772 if (show_displacement) {
648 if (h->pair != NULL) 773 if (h->pair != NULL)
@@ -652,11 +777,320 @@ print_entries:
652 displacement = 0; 777 displacement = 0;
653 ++position; 778 ++position;
654 } 779 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement, 780 cnt = hist_entry__fprintf(h, pair, show_displacement,
656 displacement, fp); 781 displacement, fp, self->stats.total_period);
782 /* Ignore those that didn't match the parent filter */
783 if (!cnt)
784 continue;
785
786 ret += cnt;
787
788 if (symbol_conf.use_callchain)
789 ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period);
790
791 if (h->ms.map == NULL && verbose > 1) {
792 __map_groups__fprintf_maps(&h->thread->mg,
793 MAP__FUNCTION, verbose, fp);
794 fprintf(fp, "%.10s end\n", graph_dotted_line);
795 }
657 } 796 }
658 797
659 free(rem_sq_bracket); 798 free(rem_sq_bracket);
660 799
661 return ret; 800 return ret;
662} 801}
802
803enum hist_filter {
804 HIST_FILTER__DSO,
805 HIST_FILTER__THREAD,
806};
807
808void hists__filter_by_dso(struct hists *self, const struct dso *dso)
809{
810 struct rb_node *nd;
811
812 self->nr_entries = self->stats.total_period = 0;
813 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
814 self->max_sym_namelen = 0;
815
816 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
817 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
818
819 if (symbol_conf.exclude_other && !h->parent)
820 continue;
821
822 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
823 h->filtered |= (1 << HIST_FILTER__DSO);
824 continue;
825 }
826
827 h->filtered &= ~(1 << HIST_FILTER__DSO);
828 if (!h->filtered) {
829 ++self->nr_entries;
830 self->stats.total_period += h->period;
831 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
832 if (h->ms.sym &&
833 self->max_sym_namelen < h->ms.sym->namelen)
834 self->max_sym_namelen = h->ms.sym->namelen;
835 }
836 }
837}
838
839void hists__filter_by_thread(struct hists *self, const struct thread *thread)
840{
841 struct rb_node *nd;
842
843 self->nr_entries = self->stats.total_period = 0;
844 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
845 self->max_sym_namelen = 0;
846
847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
849
850 if (thread != NULL && h->thread != thread) {
851 h->filtered |= (1 << HIST_FILTER__THREAD);
852 continue;
853 }
854 h->filtered &= ~(1 << HIST_FILTER__THREAD);
855 if (!h->filtered) {
856 ++self->nr_entries;
857 self->stats.total_period += h->period;
858 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
859 if (h->ms.sym &&
860 self->max_sym_namelen < h->ms.sym->namelen)
861 self->max_sym_namelen = h->ms.sym->namelen;
862 }
863 }
864}
865
866static int symbol__alloc_hist(struct symbol *self)
867{
868 struct sym_priv *priv = symbol__priv(self);
869 const int size = (sizeof(*priv->hist) +
870 (self->end - self->start) * sizeof(u64));
871
872 priv->hist = zalloc(size);
873 return priv->hist == NULL ? -1 : 0;
874}
875
876int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
877{
878 unsigned int sym_size, offset;
879 struct symbol *sym = self->ms.sym;
880 struct sym_priv *priv;
881 struct sym_hist *h;
882
883 if (!sym || !self->ms.map)
884 return 0;
885
886 priv = symbol__priv(sym);
887 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
888 return -ENOMEM;
889
890 sym_size = sym->end - sym->start;
891 offset = ip - sym->start;
892
893 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
894
895 if (offset >= sym_size)
896 return 0;
897
898 h = priv->hist;
899 h->sum++;
900 h->ip[offset]++;
901
902 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
903 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
904 return 0;
905}
906
907static struct objdump_line *objdump_line__new(s64 offset, char *line)
908{
909 struct objdump_line *self = malloc(sizeof(*self));
910
911 if (self != NULL) {
912 self->offset = offset;
913 self->line = line;
914 }
915
916 return self;
917}
918
919void objdump_line__free(struct objdump_line *self)
920{
921 free(self->line);
922 free(self);
923}
924
925static void objdump__add_line(struct list_head *head, struct objdump_line *line)
926{
927 list_add_tail(&line->node, head);
928}
929
930struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
931 struct objdump_line *pos)
932{
933 list_for_each_entry_continue(pos, head, node)
934 if (pos->offset >= 0)
935 return pos;
936
937 return NULL;
938}
939
940static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
941 struct list_head *head)
942{
943 struct symbol *sym = self->ms.sym;
944 struct objdump_line *objdump_line;
945 char *line = NULL, *tmp, *tmp2, *c;
946 size_t line_len;
947 s64 line_ip, offset = -1;
948
949 if (getline(&line, &line_len, file) < 0)
950 return -1;
951
952 if (!line)
953 return -1;
954
955 while (line_len != 0 && isspace(line[line_len - 1]))
956 line[--line_len] = '\0';
957
958 c = strchr(line, '\n');
959 if (c)
960 *c = 0;
961
962 line_ip = -1;
963
964 /*
965 * Strip leading spaces:
966 */
967 tmp = line;
968 while (*tmp) {
969 if (*tmp != ' ')
970 break;
971 tmp++;
972 }
973
974 if (*tmp) {
975 /*
976 * Parse hexa addresses followed by ':'
977 */
978 line_ip = strtoull(tmp, &tmp2, 16);
979 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
980 line_ip = -1;
981 }
982
983 if (line_ip != -1) {
984 u64 start = map__rip_2objdump(self->ms.map, sym->start),
985 end = map__rip_2objdump(self->ms.map, sym->end);
986
987 offset = line_ip - start;
988 if (offset < 0 || (u64)line_ip > end)
989 offset = -1;
990 }
991
992 objdump_line = objdump_line__new(offset, line);
993 if (objdump_line == NULL) {
994 free(line);
995 return -1;
996 }
997 objdump__add_line(head, objdump_line);
998
999 return 0;
1000}
1001
1002int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
1003{
1004 struct symbol *sym = self->ms.sym;
1005 struct map *map = self->ms.map;
1006 struct dso *dso = map->dso;
1007 char *filename = dso__build_id_filename(dso, NULL, 0);
1008 bool free_filename = true;
1009 char command[PATH_MAX * 2];
1010 FILE *file;
1011 int err = 0;
1012 u64 len;
1013
1014 if (filename == NULL) {
1015 if (dso->has_build_id) {
1016 pr_err("Can't annotate %s: not enough memory\n",
1017 sym->name);
1018 return -ENOMEM;
1019 }
1020 goto fallback;
1021 } else if (readlink(filename, command, sizeof(command)) < 0 ||
1022 strstr(command, "[kernel.kallsyms]") ||
1023 access(filename, R_OK)) {
1024 free(filename);
1025fallback:
1026 /*
1027 * If we don't have build-ids or the build-id file isn't in the
1028 * cache, or is just a kallsyms file, well, lets hope that this
1029 * DSO is the same as when 'perf record' ran.
1030 */
1031 filename = dso->long_name;
1032 free_filename = false;
1033 }
1034
1035 if (dso->origin == DSO__ORIG_KERNEL) {
1036 if (dso->annotate_warned)
1037 goto out_free_filename;
1038 err = -ENOENT;
1039 dso->annotate_warned = 1;
1040 pr_err("Can't annotate %s: No vmlinux file was found in the "
1041 "path\n", sym->name);
1042 goto out_free_filename;
1043 }
1044
1045 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1046 filename, sym->name, map->unmap_ip(map, sym->start),
1047 map->unmap_ip(map, sym->end));
1048
1049 len = sym->end - sym->start;
1050
1051 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1052 dso, dso->long_name, sym, sym->name);
1053
1054 snprintf(command, sizeof(command),
1055 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand",
1056 map__rip_2objdump(map, sym->start),
1057 map__rip_2objdump(map, sym->end),
1058 filename, filename);
1059
1060 pr_debug("Executing: %s\n", command);
1061
1062 file = popen(command, "r");
1063 if (!file)
1064 goto out_free_filename;
1065
1066 while (!feof(file))
1067 if (hist_entry__parse_objdump_line(self, file, head) < 0)
1068 break;
1069
1070 pclose(file);
1071out_free_filename:
1072 if (free_filename)
1073 free(filename);
1074 return err;
1075}
1076
1077void hists__inc_nr_events(struct hists *self, u32 type)
1078{
1079 ++self->stats.nr_events[0];
1080 ++self->stats.nr_events[type];
1081}
1082
1083size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1084{
1085 int i;
1086 size_t ret = 0;
1087
1088 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1089 if (!event__name[i])
1090 continue;
1091 ret += fprintf(fp, "%10s events: %10d\n",
1092 event__name[i], self->stats.nr_events[i]);
1093 }
1094
1095 return ret;
1096}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index e5f99b24048b..83fa33a7b38b 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -6,22 +6,124 @@
6 6
7extern struct callchain_param callchain_param; 7extern struct callchain_param callchain_param;
8 8
9struct perf_session;
10struct hist_entry; 9struct hist_entry;
11struct addr_location; 10struct addr_location;
12struct symbol; 11struct symbol;
12struct rb_root;
13 13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 14struct objdump_line {
15 struct addr_location *al, 15 struct list_head node;
16 struct symbol *parent, 16 s64 offset;
17 u64 count, bool *hit); 17 char *line;
18};
19
20void objdump_line__free(struct objdump_line *self);
21struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
22 struct objdump_line *pos);
23
24struct sym_hist {
25 u64 sum;
26 u64 ip[0];
27};
28
29struct sym_ext {
30 struct rb_node node;
31 double percent;
32 char *path;
33};
34
35struct sym_priv {
36 struct sym_hist *hist;
37 struct sym_ext *ext;
38};
39
40/*
41 * The kernel collects the number of events it couldn't send in a stretch and
42 * when possible sends this number in a PERF_RECORD_LOST event. The number of
43 * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while
44 * total_lost tells exactly how many events the kernel in fact lost, i.e. it is
45 * the sum of all struct lost_event.lost fields reported.
46 *
47 * The total_period is needed because by default auto-freq is used, so
48 * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get
49 * the total number of low level events, it is necessary to to sum all struct
50 * sample_event.period and stash the result in total_period.
51 */
52struct events_stats {
53 u64 total_period;
54 u64 total_lost;
55 u32 nr_events[PERF_RECORD_HEADER_MAX];
56 u32 nr_unknown_events;
57};
58
59struct hists {
60 struct rb_node rb_node;
61 struct rb_root entries;
62 u64 nr_entries;
63 struct events_stats stats;
64 u64 config;
65 u64 event_stream;
66 u32 type;
67 u32 max_sym_namelen;
68};
69
70struct hist_entry *__hists__add_entry(struct hists *self,
71 struct addr_location *al,
72 struct symbol *parent, u64 period);
18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 73extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 74extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
75int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
76 bool show_displacement, long displacement, FILE *fp,
77 u64 total);
78int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
79 struct hists *pair_hists, bool show_displacement,
80 long displacement, bool color, u64 total);
20void hist_entry__free(struct hist_entry *); 81void hist_entry__free(struct hist_entry *);
21 82
22void perf_session__output_resort(struct perf_session *self, u64 total_samples); 83void hists__output_resort(struct hists *self);
23void perf_session__collapse_resort(struct perf_session *self); 84void hists__collapse_resort(struct hists *self);
24size_t perf_session__fprintf_hists(struct perf_session *self, 85
25 struct perf_session *pair, 86void hists__inc_nr_events(struct hists *self, u32 type);
26 bool show_displacement, FILE *fp); 87size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
88
89size_t hists__fprintf(struct hists *self, struct hists *pair,
90 bool show_displacement, FILE *fp);
91
92int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip);
93int hist_entry__annotate(struct hist_entry *self, struct list_head *head);
94
95void hists__filter_by_dso(struct hists *self, const struct dso *dso);
96void hists__filter_by_thread(struct hists *self, const struct thread *thread);
97
98#ifdef NO_NEWT_SUPPORT
99static inline int hists__browse(struct hists *self __used,
100 const char *helpline __used,
101 const char *ev_name __used)
102{
103 return 0;
104}
105
106static inline int hists__tui_browse_tree(struct rb_root *self __used,
107 const char *help __used)
108{
109 return 0;
110}
111
112static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
113{
114 return 0;
115}
116#define KEY_LEFT -1
117#define KEY_RIGHT -2
118#else
119#include <newt.h>
120int hists__browse(struct hists *self, const char *helpline,
121 const char *ev_name);
122int hist_entry__tui_annotate(struct hist_entry *self);
123
124#define KEY_LEFT NEWT_KEY_LEFT
125#define KEY_RIGHT NEWT_KEY_RIGHT
126
127int hists__tui_browse_tree(struct rb_root *self, const char *help);
128#endif
27#endif /* __PERF_HIST_H */ 129#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/hweight.c b/tools/perf/util/hweight.c
new file mode 100644
index 000000000000..5c1d0d099f0d
--- /dev/null
+++ b/tools/perf/util/hweight.c
@@ -0,0 +1,31 @@
1#include <linux/bitops.h>
2
3/**
4 * hweightN - returns the hamming weight of a N-bit word
5 * @x: the word to weigh
6 *
7 * The Hamming Weight of a number is the total number of bits set in it.
8 */
9
10unsigned int hweight32(unsigned int w)
11{
12 unsigned int res = w - ((w >> 1) & 0x55555555);
13 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
14 res = (res + (res >> 4)) & 0x0F0F0F0F;
15 res = res + (res >> 8);
16 return (res + (res >> 16)) & 0x000000FF;
17}
18
19unsigned long hweight64(__u64 w)
20{
21#if BITS_PER_LONG == 32
22 return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
23#elif BITS_PER_LONG == 64
24 __u64 res = w - ((w >> 1) & 0x5555555555555555ul);
25 res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
26 res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
27 res = res + (res >> 8);
28 res = res + (res >> 16);
29 return (res + (res >> 32)) & 0x00000000000000FFul;
30#endif
31}
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
deleted file mode 100644
index 58e9817ffae0..000000000000
--- a/tools/perf/util/include/asm/bitops.h
+++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/hweight.h b/tools/perf/util/include/asm/hweight.h
new file mode 100644
index 000000000000..36cf26d434a5
--- /dev/null
+++ b/tools/perf/util/include/asm/hweight.h
@@ -0,0 +1,8 @@
1#ifndef PERF_HWEIGHT_H
2#define PERF_HWEIGHT_H
3
4#include <linux/types.h>
5unsigned int hweight32(unsigned int w);
6unsigned long hweight64(__u64 w);
7
8#endif /* PERF_HWEIGHT_H */
diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h
new file mode 100644
index 000000000000..cf6727e99c44
--- /dev/null
+++ b/tools/perf/util/include/dwarf-regs.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_DWARF_REGS_H_
2#define _PERF_DWARF_REGS_H_
3
4#ifdef DWARF_SUPPORT
5const char *get_arch_regstr(unsigned int n);
6#endif
7
8#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index 94507639a8c4..eda4416efa0a 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -1,3 +1,35 @@
1#include "../../../../include/linux/bitmap.h" 1#ifndef _PERF_BITOPS_H
2#include "../../../../include/asm-generic/bitops/find.h" 2#define _PERF_BITOPS_H
3#include <linux/errno.h> 3
4#include <string.h>
5#include <linux/bitops.h>
6
7int __bitmap_weight(const unsigned long *bitmap, int bits);
8
9#define BITMAP_LAST_WORD_MASK(nbits) \
10( \
11 ((nbits) % BITS_PER_LONG) ? \
12 (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \
13)
14
15#define small_const_nbits(nbits) \
16 (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
17
18static inline void bitmap_zero(unsigned long *dst, int nbits)
19{
20 if (small_const_nbits(nbits))
21 *dst = 0UL;
22 else {
23 int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
24 memset(dst, 0, len);
25 }
26}
27
28static inline int bitmap_weight(const unsigned long *src, int nbits)
29{
30 if (small_const_nbits(nbits))
31 return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
32 return __bitmap_weight(src, nbits);
33}
34
35#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 8d63116e9435..bb4ac2e05385 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -1,13 +1,12 @@
1#ifndef _PERF_LINUX_BITOPS_H_ 1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_ 2#define _PERF_LINUX_BITOPS_H_
3 3
4#define __KERNEL__ 4#include <linux/kernel.h>
5#include <asm/hweight.h>
5 6
6#define CONFIG_GENERIC_FIND_NEXT_BIT 7#define BITS_PER_LONG __WORDSIZE
7#define CONFIG_GENERIC_FIND_FIRST_BIT 8#define BITS_PER_BYTE 8
8#include "../../../../include/linux/bitops.h" 9#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
9
10#undef __KERNEL__
11 10
12static inline void set_bit(int nr, unsigned long *addr) 11static inline void set_bit(int nr, unsigned long *addr)
13{ 12{
@@ -20,10 +19,9 @@ static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0; 19 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21} 20}
22 21
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned 22static inline unsigned long hweight_long(unsigned long w)
24 long size, unsigned long offset); 23{
25 24 return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned 25}
27 long size, unsigned long offset);
28 26
29#endif 27#endif
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/hash.h b/tools/perf/util/include/linux/hash.h
new file mode 100644
index 000000000000..201f57397997
--- /dev/null
+++ b/tools/perf/util/include/linux/hash.h
@@ -0,0 +1,5 @@
1#include "../../../../include/linux/hash.h"
2
3#ifndef PERF_HASH_H
4#define PERF_HASH_H
5#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 21c0274c02fa..1eb804fd3fbf 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -28,6 +28,8 @@
28 (type *)((char *)__mptr - offsetof(type, member)); }) 28 (type *)((char *)__mptr - offsetof(type, member)); })
29#endif 29#endif
30 30
31#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
32
31#ifndef max 33#ifndef max
32#define max(x, y) ({ \ 34#define max(x, y) ({ \
33 typeof(x) _max1 = (x); \ 35 typeof(x) _max1 = (x); \
@@ -85,21 +87,25 @@ simple_strtoul(const char *nptr, char **endptr, int base)
85 return strtoul(nptr, endptr, base); 87 return strtoul(nptr, endptr, base);
86} 88}
87 89
90int eprintf(int level,
91 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
92
88#ifndef pr_fmt 93#ifndef pr_fmt
89#define pr_fmt(fmt) fmt 94#define pr_fmt(fmt) fmt
90#endif 95#endif
91 96
92#define pr_err(fmt, ...) \ 97#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 98 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
94#define pr_warning(fmt, ...) \ 99#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 100 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
96#define pr_info(fmt, ...) \ 101#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 102 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
98#define pr_debug(fmt, ...) \ 103#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) 104 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \ 105#define pr_debugN(n, fmt, ...) \
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) 106 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 107#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 108#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
109#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
104 110
105#endif 111#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index c4d55a0da2ea..e672f2fef65b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -1,9 +1,16 @@
1#include "event.h"
2#include "symbol.h" 1#include "symbol.h"
2#include <errno.h>
3#include <limits.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <string.h> 5#include <string.h>
5#include <stdio.h> 6#include <stdio.h>
6#include "debug.h" 7#include <unistd.h>
8#include "map.h"
9
10const char *map_type__name[MAP__NR_TYPES] = {
11 [MAP__FUNCTION] = "Functions",
12 [MAP__VARIABLE] = "Variables",
13};
7 14
8static inline int is_anon_memory(const char *filename) 15static inline int is_anon_memory(const char *filename)
9{ 16{
@@ -31,15 +38,16 @@ void map__init(struct map *self, enum map_type type,
31 self->map_ip = map__map_ip; 38 self->map_ip = map__map_ip;
32 self->unmap_ip = map__unmap_ip; 39 self->unmap_ip = map__unmap_ip;
33 RB_CLEAR_NODE(&self->rb_node); 40 RB_CLEAR_NODE(&self->rb_node);
41 self->groups = NULL;
34} 42}
35 43
36struct map *map__new(struct mmap_event *event, enum map_type type, 44struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
37 char *cwd, int cwdlen) 45 u64 pgoff, u32 pid, char *filename,
46 enum map_type type, char *cwd, int cwdlen)
38{ 47{
39 struct map *self = malloc(sizeof(*self)); 48 struct map *self = malloc(sizeof(*self));
40 49
41 if (self != NULL) { 50 if (self != NULL) {
42 const char *filename = event->filename;
43 char newfilename[PATH_MAX]; 51 char newfilename[PATH_MAX];
44 struct dso *dso; 52 struct dso *dso;
45 int anon; 53 int anon;
@@ -57,19 +65,23 @@ struct map *map__new(struct mmap_event *event, enum map_type type,
57 anon = is_anon_memory(filename); 65 anon = is_anon_memory(filename);
58 66
59 if (anon) { 67 if (anon) {
60 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); 68 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
61 filename = newfilename; 69 filename = newfilename;
62 } 70 }
63 71
64 dso = dsos__findnew(filename); 72 dso = __dsos__findnew(dsos__list, filename);
65 if (dso == NULL) 73 if (dso == NULL)
66 goto out_delete; 74 goto out_delete;
67 75
68 map__init(self, type, event->start, event->start + event->len, 76 map__init(self, type, start, start + len, pgoff, dso);
69 event->pgoff, dso);
70 77
71 if (self->dso == vdso || anon) 78 if (anon) {
79set_identity:
72 self->map_ip = self->unmap_ip = identity__map_ip; 80 self->map_ip = self->unmap_ip = identity__map_ip;
81 } else if (strcmp(filename, "[vdso]") == 0) {
82 dso__set_loaded(dso, self->type);
83 goto set_identity;
84 }
73 } 85 }
74 return self; 86 return self;
75out_delete: 87out_delete:
@@ -104,8 +116,7 @@ void map__fixup_end(struct map *self)
104 116
105#define DSO__DELETED "(deleted)" 117#define DSO__DELETED "(deleted)"
106 118
107int map__load(struct map *self, struct perf_session *session, 119int map__load(struct map *self, symbol_filter_t filter)
108 symbol_filter_t filter)
109{ 120{
110 const char *name = self->dso->long_name; 121 const char *name = self->dso->long_name;
111 int nr; 122 int nr;
@@ -113,7 +124,7 @@ int map__load(struct map *self, struct perf_session *session,
113 if (dso__loaded(self->dso, self->type)) 124 if (dso__loaded(self->dso, self->type))
114 return 0; 125 return 0;
115 126
116 nr = dso__load(self->dso, self, session, filter); 127 nr = dso__load(self->dso, self, filter);
117 if (nr < 0) { 128 if (nr < 0) {
118 if (self->dso->has_build_id) { 129 if (self->dso->has_build_id) {
119 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 130 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -144,24 +155,29 @@ int map__load(struct map *self, struct perf_session *session,
144 155
145 return -1; 156 return -1;
146 } 157 }
158 /*
159 * Only applies to the kernel, as its symtabs aren't relative like the
160 * module ones.
161 */
162 if (self->dso->kernel)
163 map__reloc_vmlinux(self);
147 164
148 return 0; 165 return 0;
149} 166}
150 167
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 168struct symbol *map__find_symbol(struct map *self, u64 addr,
152 u64 addr, symbol_filter_t filter) 169 symbol_filter_t filter)
153{ 170{
154 if (map__load(self, session, filter) < 0) 171 if (map__load(self, filter) < 0)
155 return NULL; 172 return NULL;
156 173
157 return dso__find_symbol(self->dso, self->type, addr); 174 return dso__find_symbol(self->dso, self->type, addr);
158} 175}
159 176
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 177struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter) 178 symbol_filter_t filter)
163{ 179{
164 if (map__load(self, session, filter) < 0) 180 if (map__load(self, filter) < 0)
165 return NULL; 181 return NULL;
166 182
167 if (!dso__sorted_by_name(self->dso, self->type)) 183 if (!dso__sorted_by_name(self->dso, self->type))
@@ -201,3 +217,412 @@ size_t map__fprintf(struct map *self, FILE *fp)
201 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 217 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
202 self->start, self->end, self->pgoff, self->dso->name); 218 self->start, self->end, self->pgoff, self->dso->name);
203} 219}
220
221/*
222 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
223 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
224 */
225u64 map__rip_2objdump(struct map *map, u64 rip)
226{
227 u64 addr = map->dso->adjust_symbols ?
228 map->unmap_ip(map, rip) : /* RIP -> IP */
229 rip;
230 return addr;
231}
232
233u64 map__objdump_2ip(struct map *map, u64 addr)
234{
235 u64 ip = map->dso->adjust_symbols ?
236 addr :
237 map->unmap_ip(map, addr); /* RIP -> IP */
238 return ip;
239}
240
241void map_groups__init(struct map_groups *self)
242{
243 int i;
244 for (i = 0; i < MAP__NR_TYPES; ++i) {
245 self->maps[i] = RB_ROOT;
246 INIT_LIST_HEAD(&self->removed_maps[i]);
247 }
248 self->machine = NULL;
249}
250
251void map_groups__flush(struct map_groups *self)
252{
253 int type;
254
255 for (type = 0; type < MAP__NR_TYPES; type++) {
256 struct rb_root *root = &self->maps[type];
257 struct rb_node *next = rb_first(root);
258
259 while (next) {
260 struct map *pos = rb_entry(next, struct map, rb_node);
261 next = rb_next(&pos->rb_node);
262 rb_erase(&pos->rb_node, root);
263 /*
264 * We may have references to this map, for
265 * instance in some hist_entry instances, so
266 * just move them to a separate list.
267 */
268 list_add_tail(&pos->node, &self->removed_maps[pos->type]);
269 }
270 }
271}
272
273struct symbol *map_groups__find_symbol(struct map_groups *self,
274 enum map_type type, u64 addr,
275 struct map **mapp,
276 symbol_filter_t filter)
277{
278 struct map *map = map_groups__find(self, type, addr);
279
280 if (map != NULL) {
281 if (mapp != NULL)
282 *mapp = map;
283 return map__find_symbol(map, map->map_ip(map, addr), filter);
284 }
285
286 return NULL;
287}
288
289struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
290 enum map_type type,
291 const char *name,
292 struct map **mapp,
293 symbol_filter_t filter)
294{
295 struct rb_node *nd;
296
297 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
298 struct map *pos = rb_entry(nd, struct map, rb_node);
299 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
300
301 if (sym == NULL)
302 continue;
303 if (mapp != NULL)
304 *mapp = pos;
305 return sym;
306 }
307
308 return NULL;
309}
310
311size_t __map_groups__fprintf_maps(struct map_groups *self,
312 enum map_type type, int verbose, FILE *fp)
313{
314 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
315 struct rb_node *nd;
316
317 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
318 struct map *pos = rb_entry(nd, struct map, rb_node);
319 printed += fprintf(fp, "Map:");
320 printed += map__fprintf(pos, fp);
321 if (verbose > 2) {
322 printed += dso__fprintf(pos->dso, type, fp);
323 printed += fprintf(fp, "--\n");
324 }
325 }
326
327 return printed;
328}
329
330size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp)
331{
332 size_t printed = 0, i;
333 for (i = 0; i < MAP__NR_TYPES; ++i)
334 printed += __map_groups__fprintf_maps(self, i, verbose, fp);
335 return printed;
336}
337
338static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
339 enum map_type type,
340 int verbose, FILE *fp)
341{
342 struct map *pos;
343 size_t printed = 0;
344
345 list_for_each_entry(pos, &self->removed_maps[type], node) {
346 printed += fprintf(fp, "Map:");
347 printed += map__fprintf(pos, fp);
348 if (verbose > 1) {
349 printed += dso__fprintf(pos->dso, type, fp);
350 printed += fprintf(fp, "--\n");
351 }
352 }
353 return printed;
354}
355
356static size_t map_groups__fprintf_removed_maps(struct map_groups *self,
357 int verbose, FILE *fp)
358{
359 size_t printed = 0, i;
360 for (i = 0; i < MAP__NR_TYPES; ++i)
361 printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp);
362 return printed;
363}
364
365size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp)
366{
367 size_t printed = map_groups__fprintf_maps(self, verbose, fp);
368 printed += fprintf(fp, "Removed maps:\n");
369 return printed + map_groups__fprintf_removed_maps(self, verbose, fp);
370}
371
372int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
373 int verbose, FILE *fp)
374{
375 struct rb_root *root = &self->maps[map->type];
376 struct rb_node *next = rb_first(root);
377
378 while (next) {
379 struct map *pos = rb_entry(next, struct map, rb_node);
380 next = rb_next(&pos->rb_node);
381
382 if (!map__overlap(pos, map))
383 continue;
384
385 if (verbose >= 2) {
386 fputs("overlapping maps:\n", fp);
387 map__fprintf(map, fp);
388 map__fprintf(pos, fp);
389 }
390
391 rb_erase(&pos->rb_node, root);
392 /*
393 * We may have references to this map, for instance in some
394 * hist_entry instances, so just move them to a separate
395 * list.
396 */
397 list_add_tail(&pos->node, &self->removed_maps[map->type]);
398 /*
399 * Now check if we need to create new maps for areas not
400 * overlapped by the new map:
401 */
402 if (map->start > pos->start) {
403 struct map *before = map__clone(pos);
404
405 if (before == NULL)
406 return -ENOMEM;
407
408 before->end = map->start - 1;
409 map_groups__insert(self, before);
410 if (verbose >= 2)
411 map__fprintf(before, fp);
412 }
413
414 if (map->end < pos->end) {
415 struct map *after = map__clone(pos);
416
417 if (after == NULL)
418 return -ENOMEM;
419
420 after->start = map->end + 1;
421 map_groups__insert(self, after);
422 if (verbose >= 2)
423 map__fprintf(after, fp);
424 }
425 }
426
427 return 0;
428}
429
430/*
431 * XXX This should not really _copy_ te maps, but refcount them.
432 */
433int map_groups__clone(struct map_groups *self,
434 struct map_groups *parent, enum map_type type)
435{
436 struct rb_node *nd;
437 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
438 struct map *map = rb_entry(nd, struct map, rb_node);
439 struct map *new = map__clone(map);
440 if (new == NULL)
441 return -ENOMEM;
442 map_groups__insert(self, new);
443 }
444 return 0;
445}
446
447static u64 map__reloc_map_ip(struct map *map, u64 ip)
448{
449 return ip + (s64)map->pgoff;
450}
451
452static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
453{
454 return ip - (s64)map->pgoff;
455}
456
457void map__reloc_vmlinux(struct map *self)
458{
459 struct kmap *kmap = map__kmap(self);
460 s64 reloc;
461
462 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
463 return;
464
465 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
466 kmap->ref_reloc_sym->addr);
467
468 if (!reloc)
469 return;
470
471 self->map_ip = map__reloc_map_ip;
472 self->unmap_ip = map__reloc_unmap_ip;
473 self->pgoff = reloc;
474}
475
476void maps__insert(struct rb_root *maps, struct map *map)
477{
478 struct rb_node **p = &maps->rb_node;
479 struct rb_node *parent = NULL;
480 const u64 ip = map->start;
481 struct map *m;
482
483 while (*p != NULL) {
484 parent = *p;
485 m = rb_entry(parent, struct map, rb_node);
486 if (ip < m->start)
487 p = &(*p)->rb_left;
488 else
489 p = &(*p)->rb_right;
490 }
491
492 rb_link_node(&map->rb_node, parent, p);
493 rb_insert_color(&map->rb_node, maps);
494}
495
496struct map *maps__find(struct rb_root *maps, u64 ip)
497{
498 struct rb_node **p = &maps->rb_node;
499 struct rb_node *parent = NULL;
500 struct map *m;
501
502 while (*p != NULL) {
503 parent = *p;
504 m = rb_entry(parent, struct map, rb_node);
505 if (ip < m->start)
506 p = &(*p)->rb_left;
507 else if (ip > m->end)
508 p = &(*p)->rb_right;
509 else
510 return m;
511 }
512
513 return NULL;
514}
515
516int machine__init(struct machine *self, const char *root_dir, pid_t pid)
517{
518 map_groups__init(&self->kmaps);
519 RB_CLEAR_NODE(&self->rb_node);
520 INIT_LIST_HEAD(&self->user_dsos);
521 INIT_LIST_HEAD(&self->kernel_dsos);
522
523 self->kmaps.machine = self;
524 self->pid = pid;
525 self->root_dir = strdup(root_dir);
526 return self->root_dir == NULL ? -ENOMEM : 0;
527}
528
529struct machine *machines__add(struct rb_root *self, pid_t pid,
530 const char *root_dir)
531{
532 struct rb_node **p = &self->rb_node;
533 struct rb_node *parent = NULL;
534 struct machine *pos, *machine = malloc(sizeof(*machine));
535
536 if (!machine)
537 return NULL;
538
539 if (machine__init(machine, root_dir, pid) != 0) {
540 free(machine);
541 return NULL;
542 }
543
544 while (*p != NULL) {
545 parent = *p;
546 pos = rb_entry(parent, struct machine, rb_node);
547 if (pid < pos->pid)
548 p = &(*p)->rb_left;
549 else
550 p = &(*p)->rb_right;
551 }
552
553 rb_link_node(&machine->rb_node, parent, p);
554 rb_insert_color(&machine->rb_node, self);
555
556 return machine;
557}
558
559struct machine *machines__find(struct rb_root *self, pid_t pid)
560{
561 struct rb_node **p = &self->rb_node;
562 struct rb_node *parent = NULL;
563 struct machine *machine;
564 struct machine *default_machine = NULL;
565
566 while (*p != NULL) {
567 parent = *p;
568 machine = rb_entry(parent, struct machine, rb_node);
569 if (pid < machine->pid)
570 p = &(*p)->rb_left;
571 else if (pid > machine->pid)
572 p = &(*p)->rb_right;
573 else
574 return machine;
575 if (!machine->pid)
576 default_machine = machine;
577 }
578
579 return default_machine;
580}
581
582struct machine *machines__findnew(struct rb_root *self, pid_t pid)
583{
584 char path[PATH_MAX];
585 const char *root_dir;
586 struct machine *machine = machines__find(self, pid);
587
588 if (!machine || machine->pid != pid) {
589 if (pid == HOST_KERNEL_ID || pid == DEFAULT_GUEST_KERNEL_ID)
590 root_dir = "";
591 else {
592 if (!symbol_conf.guestmount)
593 goto out;
594 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
595 if (access(path, R_OK)) {
596 pr_err("Can't access file %s\n", path);
597 goto out;
598 }
599 root_dir = path;
600 }
601 machine = machines__add(self, pid, root_dir);
602 }
603
604out:
605 return machine;
606}
607
608void machines__process(struct rb_root *self, machine__process_t process, void *data)
609{
610 struct rb_node *nd;
611
612 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
613 struct machine *pos = rb_entry(nd, struct machine, rb_node);
614 process(pos, data);
615 }
616}
617
618char *machine__mmap_name(struct machine *self, char *bf, size_t size)
619{
620 if (machine__is_host(self))
621 snprintf(bf, size, "[%s]", "kernel.kallsyms");
622 else if (machine__is_default_guest(self))
623 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
624 else
625 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
626
627 return bf;
628}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 000000000000..f39134512829
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,217 @@
1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H
3
4#include <linux/compiler.h>
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include <stdio.h>
8#include <stdbool.h>
9#include "types.h"
10
11enum map_type {
12 MAP__FUNCTION = 0,
13 MAP__VARIABLE,
14};
15
16#define MAP__NR_TYPES (MAP__VARIABLE + 1)
17
18extern const char *map_type__name[MAP__NR_TYPES];
19
20struct dso;
21struct ref_reloc_sym;
22struct map_groups;
23struct machine;
24
25struct map {
26 union {
27 struct rb_node rb_node;
28 struct list_head node;
29 };
30 u64 start;
31 u64 end;
32 enum map_type type;
33 u32 priv;
34 u64 pgoff;
35
36 /* ip -> dso rip */
37 u64 (*map_ip)(struct map *, u64);
38 /* dso rip -> ip */
39 u64 (*unmap_ip)(struct map *, u64);
40
41 struct dso *dso;
42 struct map_groups *groups;
43};
44
45struct kmap {
46 struct ref_reloc_sym *ref_reloc_sym;
47 struct map_groups *kmaps;
48};
49
50struct map_groups {
51 struct rb_root maps[MAP__NR_TYPES];
52 struct list_head removed_maps[MAP__NR_TYPES];
53 struct machine *machine;
54};
55
56/* Native host kernel uses -1 as pid index in machine */
57#define HOST_KERNEL_ID (-1)
58#define DEFAULT_GUEST_KERNEL_ID (0)
59
60struct machine {
61 struct rb_node rb_node;
62 pid_t pid;
63 char *root_dir;
64 struct list_head user_dsos;
65 struct list_head kernel_dsos;
66 struct map_groups kmaps;
67 struct map *vmlinux_maps[MAP__NR_TYPES];
68};
69
70static inline
71struct map *machine__kernel_map(struct machine *self, enum map_type type)
72{
73 return self->vmlinux_maps[type];
74}
75
76static inline struct kmap *map__kmap(struct map *self)
77{
78 return (struct kmap *)(self + 1);
79}
80
81static inline u64 map__map_ip(struct map *map, u64 ip)
82{
83 return ip - map->start + map->pgoff;
84}
85
86static inline u64 map__unmap_ip(struct map *map, u64 ip)
87{
88 return ip + map->start - map->pgoff;
89}
90
91static inline u64 identity__map_ip(struct map *map __used, u64 ip)
92{
93 return ip;
94}
95
96
97/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
98u64 map__rip_2objdump(struct map *map, u64 rip);
99u64 map__objdump_2ip(struct map *map, u64 addr);
100
101struct symbol;
102
103typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
104
105void map__init(struct map *self, enum map_type type,
106 u64 start, u64 end, u64 pgoff, struct dso *dso);
107struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
108 u64 pgoff, u32 pid, char *filename,
109 enum map_type type, char *cwd, int cwdlen);
110void map__delete(struct map *self);
111struct map *map__clone(struct map *self);
112int map__overlap(struct map *l, struct map *r);
113size_t map__fprintf(struct map *self, FILE *fp);
114
115int map__load(struct map *self, symbol_filter_t filter);
116struct symbol *map__find_symbol(struct map *self,
117 u64 addr, symbol_filter_t filter);
118struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
119 symbol_filter_t filter);
120void map__fixup_start(struct map *self);
121void map__fixup_end(struct map *self);
122
123void map__reloc_vmlinux(struct map *self);
124
125size_t __map_groups__fprintf_maps(struct map_groups *self,
126 enum map_type type, int verbose, FILE *fp);
127void maps__insert(struct rb_root *maps, struct map *map);
128struct map *maps__find(struct rb_root *maps, u64 addr);
129void map_groups__init(struct map_groups *self);
130int map_groups__clone(struct map_groups *self,
131 struct map_groups *parent, enum map_type type);
132size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
133size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
134
135typedef void (*machine__process_t)(struct machine *self, void *data);
136
137void machines__process(struct rb_root *self, machine__process_t process, void *data);
138struct machine *machines__add(struct rb_root *self, pid_t pid,
139 const char *root_dir);
140struct machine *machines__find_host(struct rb_root *self);
141struct machine *machines__find(struct rb_root *self, pid_t pid);
142struct machine *machines__findnew(struct rb_root *self, pid_t pid);
143char *machine__mmap_name(struct machine *self, char *bf, size_t size);
144int machine__init(struct machine *self, const char *root_dir, pid_t pid);
145
146/*
147 * Default guest kernel is defined by parameter --guestkallsyms
148 * and --guestmodules
149 */
150static inline bool machine__is_default_guest(struct machine *self)
151{
152 return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false;
153}
154
155static inline bool machine__is_host(struct machine *self)
156{
157 return self ? self->pid == HOST_KERNEL_ID : false;
158}
159
160static inline void map_groups__insert(struct map_groups *self, struct map *map)
161{
162 maps__insert(&self->maps[map->type], map);
163 map->groups = self;
164}
165
166static inline struct map *map_groups__find(struct map_groups *self,
167 enum map_type type, u64 addr)
168{
169 return maps__find(&self->maps[type], addr);
170}
171
172struct symbol *map_groups__find_symbol(struct map_groups *self,
173 enum map_type type, u64 addr,
174 struct map **mapp,
175 symbol_filter_t filter);
176
177struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
178 enum map_type type,
179 const char *name,
180 struct map **mapp,
181 symbol_filter_t filter);
182
183static inline
184struct symbol *machine__find_kernel_symbol(struct machine *self,
185 enum map_type type, u64 addr,
186 struct map **mapp,
187 symbol_filter_t filter)
188{
189 return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter);
190}
191
192static inline
193struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
194 struct map **mapp,
195 symbol_filter_t filter)
196{
197 return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter);
198}
199
200static inline
201struct symbol *map_groups__find_function_by_name(struct map_groups *self,
202 const char *name, struct map **mapp,
203 symbol_filter_t filter)
204{
205 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
206}
207
208int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
209 int verbose, FILE *fp);
210
211struct map *map_groups__find_by_name(struct map_groups *self,
212 enum map_type type, const char *name);
213struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
214
215void map_groups__flush(struct map_groups *self);
216
217#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
new file mode 100644
index 000000000000..7537ca15900b
--- /dev/null
+++ b/tools/perf/util/newt.c
@@ -0,0 +1,1178 @@
1#define _GNU_SOURCE
2#include <stdio.h>
3#undef _GNU_SOURCE
4/*
5 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
6 * the build if it isn't defined. Use the equivalent one that glibc
7 * has on features.h.
8 */
9#include <features.h>
10#ifndef HAVE_LONG_LONG
11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
12#endif
13#include <slang.h>
14#include <stdlib.h>
15#include <newt.h>
16#include <sys/ttydefaults.h>
17
18#include "cache.h"
19#include "hist.h"
20#include "pstack.h"
21#include "session.h"
22#include "sort.h"
23#include "symbol.h"
24
25#if SLANG_VERSION < 20104
26#define slsmg_printf(msg, args...) SLsmg_printf((char *)msg, ##args)
27#define slsmg_write_nstring(msg, len) SLsmg_write_nstring((char *)msg, len)
28#define sltt_set_color(obj, name, fg, bg) SLtt_set_color(obj,(char *)name,\
29 (char *)fg, (char *)bg)
30#else
31#define slsmg_printf SLsmg_printf
32#define slsmg_write_nstring SLsmg_write_nstring
33#define sltt_set_color SLtt_set_color
34#endif
35
36struct ui_progress {
37 newtComponent form, scale;
38};
39
40struct ui_progress *ui_progress__new(const char *title, u64 total)
41{
42 struct ui_progress *self = malloc(sizeof(*self));
43
44 if (self != NULL) {
45 int cols;
46
47 if (use_browser <= 0)
48 return self;
49 newtGetScreenSize(&cols, NULL);
50 cols -= 4;
51 newtCenteredWindow(cols, 1, title);
52 self->form = newtForm(NULL, NULL, 0);
53 if (self->form == NULL)
54 goto out_free_self;
55 self->scale = newtScale(0, 0, cols, total);
56 if (self->scale == NULL)
57 goto out_free_form;
58 newtFormAddComponent(self->form, self->scale);
59 newtRefresh();
60 }
61
62 return self;
63
64out_free_form:
65 newtFormDestroy(self->form);
66out_free_self:
67 free(self);
68 return NULL;
69}
70
71void ui_progress__update(struct ui_progress *self, u64 curr)
72{
73 /*
74 * FIXME: We should have a per UI backend way of showing progress,
75 * stdio will just show a percentage as NN%, etc.
76 */
77 if (use_browser <= 0)
78 return;
79 newtScaleSet(self->scale, curr);
80 newtRefresh();
81}
82
83void ui_progress__delete(struct ui_progress *self)
84{
85 if (use_browser > 0) {
86 newtFormDestroy(self->form);
87 newtPopWindow();
88 }
89 free(self);
90}
91
92static void ui_helpline__pop(void)
93{
94 newtPopHelpLine();
95}
96
97static void ui_helpline__push(const char *msg)
98{
99 newtPushHelpLine(msg);
100}
101
102static void ui_helpline__vpush(const char *fmt, va_list ap)
103{
104 char *s;
105
106 if (vasprintf(&s, fmt, ap) < 0)
107 vfprintf(stderr, fmt, ap);
108 else {
109 ui_helpline__push(s);
110 free(s);
111 }
112}
113
114static void ui_helpline__fpush(const char *fmt, ...)
115{
116 va_list ap;
117
118 va_start(ap, fmt);
119 ui_helpline__vpush(fmt, ap);
120 va_end(ap);
121}
122
123static void ui_helpline__puts(const char *msg)
124{
125 ui_helpline__pop();
126 ui_helpline__push(msg);
127}
128
129static char browser__last_msg[1024];
130
131int browser__show_help(const char *format, va_list ap)
132{
133 int ret;
134 static int backlog;
135
136 ret = vsnprintf(browser__last_msg + backlog,
137 sizeof(browser__last_msg) - backlog, format, ap);
138 backlog += ret;
139
140 if (browser__last_msg[backlog - 1] == '\n') {
141 ui_helpline__puts(browser__last_msg);
142 newtRefresh();
143 backlog = 0;
144 }
145
146 return ret;
147}
148
149static void newt_form__set_exit_keys(newtComponent self)
150{
151 newtFormAddHotKey(self, NEWT_KEY_LEFT);
152 newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
153 newtFormAddHotKey(self, 'Q');
154 newtFormAddHotKey(self, 'q');
155 newtFormAddHotKey(self, CTRL('c'));
156}
157
158static newtComponent newt_form__new(void)
159{
160 newtComponent self = newtForm(NULL, NULL, 0);
161 if (self)
162 newt_form__set_exit_keys(self);
163 return self;
164}
165
166static int popup_menu(int argc, char * const argv[])
167{
168 struct newtExitStruct es;
169 int i, rc = -1, max_len = 5;
170 newtComponent listbox, form = newt_form__new();
171
172 if (form == NULL)
173 return -1;
174
175 listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT);
176 if (listbox == NULL)
177 goto out_destroy_form;
178
179 newtFormAddComponent(form, listbox);
180
181 for (i = 0; i < argc; ++i) {
182 int len = strlen(argv[i]);
183 if (len > max_len)
184 max_len = len;
185 if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i))
186 goto out_destroy_form;
187 }
188
189 newtCenteredWindow(max_len, argc, NULL);
190 newtFormRun(form, &es);
191 rc = newtListboxGetCurrent(listbox) - NULL;
192 if (es.reason == NEWT_EXIT_HOTKEY)
193 rc = -1;
194 newtPopWindow();
195out_destroy_form:
196 newtFormDestroy(form);
197 return rc;
198}
199
200static int ui__help_window(const char *text)
201{
202 struct newtExitStruct es;
203 newtComponent tb, form = newt_form__new();
204 int rc = -1;
205 int max_len = 0, nr_lines = 0;
206 const char *t;
207
208 if (form == NULL)
209 return -1;
210
211 t = text;
212 while (1) {
213 const char *sep = strchr(t, '\n');
214 int len;
215
216 if (sep == NULL)
217 sep = strchr(t, '\0');
218 len = sep - t;
219 if (max_len < len)
220 max_len = len;
221 ++nr_lines;
222 if (*sep == '\0')
223 break;
224 t = sep + 1;
225 }
226
227 tb = newtTextbox(0, 0, max_len, nr_lines, 0);
228 if (tb == NULL)
229 goto out_destroy_form;
230
231 newtTextboxSetText(tb, text);
232 newtFormAddComponent(form, tb);
233 newtCenteredWindow(max_len, nr_lines, NULL);
234 newtFormRun(form, &es);
235 newtPopWindow();
236 rc = 0;
237out_destroy_form:
238 newtFormDestroy(form);
239 return rc;
240}
241
242static bool dialog_yesno(const char *msg)
243{
244 /* newtWinChoice should really be accepting const char pointers... */
245 char yes[] = "Yes", no[] = "No";
246 return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
247}
248
249static void ui__error_window(const char *fmt, ...)
250{
251 va_list ap;
252
253 va_start(ap, fmt);
254 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
255 va_end(ap);
256}
257
258#define HE_COLORSET_TOP 50
259#define HE_COLORSET_MEDIUM 51
260#define HE_COLORSET_NORMAL 52
261#define HE_COLORSET_SELECTED 53
262#define HE_COLORSET_CODE 54
263
264static int ui_browser__percent_color(double percent, bool current)
265{
266 if (current)
267 return HE_COLORSET_SELECTED;
268 if (percent >= MIN_RED)
269 return HE_COLORSET_TOP;
270 if (percent >= MIN_GREEN)
271 return HE_COLORSET_MEDIUM;
272 return HE_COLORSET_NORMAL;
273}
274
275struct ui_browser {
276 newtComponent form, sb;
277 u64 index, first_visible_entry_idx;
278 void *first_visible_entry, *entries;
279 u16 top, left, width, height;
280 void *priv;
281 u32 nr_entries;
282};
283
284static void ui_browser__refresh_dimensions(struct ui_browser *self)
285{
286 int cols, rows;
287 newtGetScreenSize(&cols, &rows);
288
289 if (self->width > cols - 4)
290 self->width = cols - 4;
291 self->height = rows - 5;
292 if (self->height > self->nr_entries)
293 self->height = self->nr_entries;
294 self->top = (rows - self->height) / 2;
295 self->left = (cols - self->width) / 2;
296}
297
298static void ui_browser__reset_index(struct ui_browser *self)
299{
300 self->index = self->first_visible_entry_idx = 0;
301 self->first_visible_entry = NULL;
302}
303
304static int objdump_line__show(struct objdump_line *self, struct list_head *head,
305 int width, struct hist_entry *he, int len,
306 bool current_entry)
307{
308 if (self->offset != -1) {
309 struct symbol *sym = he->ms.sym;
310 unsigned int hits = 0;
311 double percent = 0.0;
312 int color;
313 struct sym_priv *priv = symbol__priv(sym);
314 struct sym_ext *sym_ext = priv->ext;
315 struct sym_hist *h = priv->hist;
316 s64 offset = self->offset;
317 struct objdump_line *next = objdump__get_next_ip_line(head, self);
318
319 while (offset < (s64)len &&
320 (next == NULL || offset < next->offset)) {
321 if (sym_ext) {
322 percent += sym_ext[offset].percent;
323 } else
324 hits += h->ip[offset];
325
326 ++offset;
327 }
328
329 if (sym_ext == NULL && h->sum)
330 percent = 100.0 * hits / h->sum;
331
332 color = ui_browser__percent_color(percent, current_entry);
333 SLsmg_set_color(color);
334 slsmg_printf(" %7.2f ", percent);
335 if (!current_entry)
336 SLsmg_set_color(HE_COLORSET_CODE);
337 } else {
338 int color = ui_browser__percent_color(0, current_entry);
339 SLsmg_set_color(color);
340 slsmg_write_nstring(" ", 9);
341 }
342
343 SLsmg_write_char(':');
344 slsmg_write_nstring(" ", 8);
345 if (!*self->line)
346 slsmg_write_nstring(" ", width - 18);
347 else
348 slsmg_write_nstring(self->line, width - 18);
349
350 return 0;
351}
352
353static int ui_browser__refresh_entries(struct ui_browser *self)
354{
355 struct objdump_line *pos;
356 struct list_head *head = self->entries;
357 struct hist_entry *he = self->priv;
358 int row = 0;
359 int len = he->ms.sym->end - he->ms.sym->start;
360
361 if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
362 self->first_visible_entry = head->next;
363
364 pos = list_entry(self->first_visible_entry, struct objdump_line, node);
365
366 list_for_each_entry_from(pos, head, node) {
367 bool current_entry = (self->first_visible_entry_idx + row) == self->index;
368 SLsmg_gotorc(self->top + row, self->left);
369 objdump_line__show(pos, head, self->width,
370 he, len, current_entry);
371 if (++row == self->height)
372 break;
373 }
374
375 SLsmg_set_color(HE_COLORSET_NORMAL);
376 SLsmg_fill_region(self->top + row, self->left,
377 self->height - row, self->width, ' ');
378
379 return 0;
380}
381
382static int ui_browser__run(struct ui_browser *self, const char *title,
383 struct newtExitStruct *es)
384{
385 if (self->form) {
386 newtFormDestroy(self->form);
387 newtPopWindow();
388 }
389
390 ui_browser__refresh_dimensions(self);
391 newtCenteredWindow(self->width + 2, self->height, title);
392 self->form = newt_form__new();
393 if (self->form == NULL)
394 return -1;
395
396 self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height,
397 HE_COLORSET_NORMAL,
398 HE_COLORSET_SELECTED);
399 if (self->sb == NULL)
400 return -1;
401
402 newtFormAddHotKey(self->form, NEWT_KEY_UP);
403 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
404 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
405 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
406 newtFormAddHotKey(self->form, ' ');
407 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
408 newtFormAddHotKey(self->form, NEWT_KEY_END);
409 newtFormAddHotKey(self->form, NEWT_KEY_TAB);
410 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
411
412 if (ui_browser__refresh_entries(self) < 0)
413 return -1;
414 newtFormAddComponent(self->form, self->sb);
415
416 while (1) {
417 unsigned int offset;
418
419 newtFormRun(self->form, es);
420
421 if (es->reason != NEWT_EXIT_HOTKEY)
422 break;
423 if (is_exit_key(es->u.key))
424 return es->u.key;
425 switch (es->u.key) {
426 case NEWT_KEY_DOWN:
427 if (self->index == self->nr_entries - 1)
428 break;
429 ++self->index;
430 if (self->index == self->first_visible_entry_idx + self->height) {
431 struct list_head *pos = self->first_visible_entry;
432 ++self->first_visible_entry_idx;
433 self->first_visible_entry = pos->next;
434 }
435 break;
436 case NEWT_KEY_UP:
437 if (self->index == 0)
438 break;
439 --self->index;
440 if (self->index < self->first_visible_entry_idx) {
441 struct list_head *pos = self->first_visible_entry;
442 --self->first_visible_entry_idx;
443 self->first_visible_entry = pos->prev;
444 }
445 break;
446 case NEWT_KEY_PGDN:
447 case ' ':
448 if (self->first_visible_entry_idx + self->height > self->nr_entries - 1)
449 break;
450
451 offset = self->height;
452 if (self->index + offset > self->nr_entries - 1)
453 offset = self->nr_entries - 1 - self->index;
454 self->index += offset;
455 self->first_visible_entry_idx += offset;
456
457 while (offset--) {
458 struct list_head *pos = self->first_visible_entry;
459 self->first_visible_entry = pos->next;
460 }
461
462 break;
463 case NEWT_KEY_PGUP:
464 if (self->first_visible_entry_idx == 0)
465 break;
466
467 if (self->first_visible_entry_idx < self->height)
468 offset = self->first_visible_entry_idx;
469 else
470 offset = self->height;
471
472 self->index -= offset;
473 self->first_visible_entry_idx -= offset;
474
475 while (offset--) {
476 struct list_head *pos = self->first_visible_entry;
477 self->first_visible_entry = pos->prev;
478 }
479 break;
480 case NEWT_KEY_HOME:
481 ui_browser__reset_index(self);
482 break;
483 case NEWT_KEY_END: {
484 struct list_head *head = self->entries;
485 offset = self->height - 1;
486
487 if (offset > self->nr_entries)
488 offset = self->nr_entries;
489
490 self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset;
491 self->first_visible_entry = head->prev;
492 while (offset-- != 0) {
493 struct list_head *pos = self->first_visible_entry;
494 self->first_visible_entry = pos->prev;
495 }
496 }
497 break;
498 case NEWT_KEY_RIGHT:
499 case NEWT_KEY_LEFT:
500 case NEWT_KEY_TAB:
501 return es->u.key;
502 default:
503 continue;
504 }
505 if (ui_browser__refresh_entries(self) < 0)
506 return -1;
507 }
508 return 0;
509}
510
511/*
512 * When debugging newt problems it was useful to be able to "unroll"
513 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
514 * a source file with the sequence of calls to these methods, to then
515 * tweak the arrays to get the intended results, so I'm keeping this code
516 * here, may be useful again in the future.
517 */
518#undef NEWT_DEBUG
519
520static void newt_checkbox_tree__add(newtComponent tree, const char *str,
521 void *priv, int *indexes)
522{
523#ifdef NEWT_DEBUG
524 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
525 int i = 0, len = 40 - strlen(str);
526
527 fprintf(stderr,
528 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
529 len, len, " ", str, priv);
530 while (indexes[i] != NEWT_ARG_LAST) {
531 if (indexes[i] != NEWT_ARG_APPEND)
532 fprintf(stderr, " %d,", indexes[i]);
533 else
534 fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
535 ++i;
536 }
537 fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
538 fflush(stderr);
539#endif
540 newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
541}
542
543static char *callchain_list__sym_name(struct callchain_list *self,
544 char *bf, size_t bfsize)
545{
546 if (self->ms.sym)
547 return self->ms.sym->name;
548
549 snprintf(bf, bfsize, "%#Lx", self->ip);
550 return bf;
551}
552
553static void __callchain__append_graph_browser(struct callchain_node *self,
554 newtComponent tree, u64 total,
555 int *indexes, int depth)
556{
557 struct rb_node *node;
558 u64 new_total, remaining;
559 int idx = 0;
560
561 if (callchain_param.mode == CHAIN_GRAPH_REL)
562 new_total = self->children_hit;
563 else
564 new_total = total;
565
566 remaining = new_total;
567 node = rb_first(&self->rb_root);
568 while (node) {
569 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
570 struct rb_node *next = rb_next(node);
571 u64 cumul = cumul_hits(child);
572 struct callchain_list *chain;
573 int first = true, printed = 0;
574 int chain_idx = -1;
575 remaining -= cumul;
576
577 indexes[depth] = NEWT_ARG_APPEND;
578 indexes[depth + 1] = NEWT_ARG_LAST;
579
580 list_for_each_entry(chain, &child->val, list) {
581 char ipstr[BITS_PER_LONG / 4 + 1],
582 *alloc_str = NULL;
583 const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
584
585 if (first) {
586 double percent = cumul * 100.0 / new_total;
587
588 first = false;
589 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
590 str = "Not enough memory!";
591 else
592 str = alloc_str;
593 } else {
594 indexes[depth] = idx;
595 indexes[depth + 1] = NEWT_ARG_APPEND;
596 indexes[depth + 2] = NEWT_ARG_LAST;
597 ++chain_idx;
598 }
599 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
600 free(alloc_str);
601 ++printed;
602 }
603
604 indexes[depth] = idx;
605 if (chain_idx != -1)
606 indexes[depth + 1] = chain_idx;
607 if (printed != 0)
608 ++idx;
609 __callchain__append_graph_browser(child, tree, new_total, indexes,
610 depth + (chain_idx != -1 ? 2 : 1));
611 node = next;
612 }
613}
614
615static void callchain__append_graph_browser(struct callchain_node *self,
616 newtComponent tree, u64 total,
617 int *indexes, int parent_idx)
618{
619 struct callchain_list *chain;
620 int i = 0;
621
622 indexes[1] = NEWT_ARG_APPEND;
623 indexes[2] = NEWT_ARG_LAST;
624
625 list_for_each_entry(chain, &self->val, list) {
626 char ipstr[BITS_PER_LONG / 4 + 1], *str;
627
628 if (chain->ip >= PERF_CONTEXT_MAX)
629 continue;
630
631 if (!i++ && sort__first_dimension == SORT_SYM)
632 continue;
633
634 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
635 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
636 }
637
638 indexes[1] = parent_idx;
639 indexes[2] = NEWT_ARG_APPEND;
640 indexes[3] = NEWT_ARG_LAST;
641 __callchain__append_graph_browser(self, tree, total, indexes, 2);
642}
643
644static void hist_entry__append_callchain_browser(struct hist_entry *self,
645 newtComponent tree, u64 total, int parent_idx)
646{
647 struct rb_node *rb_node;
648 int indexes[1024] = { [0] = parent_idx, };
649 int idx = 0;
650 struct callchain_node *chain;
651
652 rb_node = rb_first(&self->sorted_chain);
653 while (rb_node) {
654 chain = rb_entry(rb_node, struct callchain_node, rb_node);
655 switch (callchain_param.mode) {
656 case CHAIN_FLAT:
657 break;
658 case CHAIN_GRAPH_ABS: /* falldown */
659 case CHAIN_GRAPH_REL:
660 callchain__append_graph_browser(chain, tree, total, indexes, idx++);
661 break;
662 case CHAIN_NONE:
663 default:
664 break;
665 }
666 rb_node = rb_next(rb_node);
667 }
668}
669
670static size_t hist_entry__append_browser(struct hist_entry *self,
671 newtComponent tree, u64 total)
672{
673 char s[256];
674 size_t ret;
675
676 if (symbol_conf.exclude_other && !self->parent)
677 return 0;
678
679 ret = hist_entry__snprintf(self, s, sizeof(s), NULL,
680 false, 0, false, total);
681 if (symbol_conf.use_callchain) {
682 int indexes[2];
683
684 indexes[0] = NEWT_ARG_APPEND;
685 indexes[1] = NEWT_ARG_LAST;
686 newt_checkbox_tree__add(tree, s, &self->ms, indexes);
687 } else
688 newtListboxAppendEntry(tree, s, &self->ms);
689
690 return ret;
691}
692
693int hist_entry__tui_annotate(struct hist_entry *self)
694{
695 struct ui_browser browser;
696 struct newtExitStruct es;
697 struct objdump_line *pos, *n;
698 LIST_HEAD(head);
699 int ret;
700
701 if (self->ms.sym == NULL)
702 return -1;
703
704 if (self->ms.map->dso->annotate_warned)
705 return -1;
706
707 if (hist_entry__annotate(self, &head) < 0) {
708 ui__error_window(browser__last_msg);
709 return -1;
710 }
711
712 ui_helpline__push("Press <- or ESC to exit");
713
714 memset(&browser, 0, sizeof(browser));
715 browser.entries = &head;
716 browser.priv = self;
717 list_for_each_entry(pos, &head, node) {
718 size_t line_len = strlen(pos->line);
719 if (browser.width < line_len)
720 browser.width = line_len;
721 ++browser.nr_entries;
722 }
723
724 browser.width += 18; /* Percentage */
725 ret = ui_browser__run(&browser, self->ms.sym->name, &es);
726 newtFormDestroy(browser.form);
727 newtPopWindow();
728 list_for_each_entry_safe(pos, n, &head, node) {
729 list_del(&pos->node);
730 objdump_line__free(pos);
731 }
732 ui_helpline__pop();
733 return ret;
734}
735
736static const void *newt__symbol_tree_get_current(newtComponent self)
737{
738 if (symbol_conf.use_callchain)
739 return newtCheckboxTreeGetCurrent(self);
740 return newtListboxGetCurrent(self);
741}
742
743static void hist_browser__selection(newtComponent self, void *data)
744{
745 const struct map_symbol **symbol_ptr = data;
746 *symbol_ptr = newt__symbol_tree_get_current(self);
747}
748
749struct hist_browser {
750 newtComponent form, tree;
751 const struct map_symbol *selection;
752};
753
754static struct hist_browser *hist_browser__new(void)
755{
756 struct hist_browser *self = malloc(sizeof(*self));
757
758 if (self != NULL)
759 self->form = NULL;
760
761 return self;
762}
763
764static void hist_browser__delete(struct hist_browser *self)
765{
766 newtFormDestroy(self->form);
767 newtPopWindow();
768 free(self);
769}
770
771static int hist_browser__populate(struct hist_browser *self, struct hists *hists,
772 const char *title)
773{
774 int max_len = 0, idx, cols, rows;
775 struct ui_progress *progress;
776 struct rb_node *nd;
777 u64 curr_hist = 0;
778 char seq[] = ".", unit;
779 char str[256];
780 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
781
782 if (self->form) {
783 newtFormDestroy(self->form);
784 newtPopWindow();
785 }
786
787 nr_events = convert_unit(nr_events, &unit);
788 snprintf(str, sizeof(str), "Events: %lu%c ",
789 nr_events, unit);
790 newtDrawRootText(0, 0, str);
791
792 newtGetScreenSize(NULL, &rows);
793
794 if (symbol_conf.use_callchain)
795 self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
796 NEWT_FLAG_SCROLL);
797 else
798 self->tree = newtListbox(0, 0, rows - 5,
799 (NEWT_FLAG_SCROLL |
800 NEWT_FLAG_RETURNEXIT));
801
802 newtComponentAddCallback(self->tree, hist_browser__selection,
803 &self->selection);
804
805 progress = ui_progress__new("Adding entries to the browser...",
806 hists->nr_entries);
807 if (progress == NULL)
808 return -1;
809
810 idx = 0;
811 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
812 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
813 int len;
814
815 if (h->filtered)
816 continue;
817
818 len = hist_entry__append_browser(h, self->tree, hists->stats.total_period);
819 if (len > max_len)
820 max_len = len;
821 if (symbol_conf.use_callchain)
822 hist_entry__append_callchain_browser(h, self->tree,
823 hists->stats.total_period, idx++);
824 ++curr_hist;
825 if (curr_hist % 5)
826 ui_progress__update(progress, curr_hist);
827 }
828
829 ui_progress__delete(progress);
830
831 newtGetScreenSize(&cols, &rows);
832
833 if (max_len > cols)
834 max_len = cols - 3;
835
836 if (!symbol_conf.use_callchain)
837 newtListboxSetWidth(self->tree, max_len);
838
839 newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
840 rows - 5, title);
841 self->form = newt_form__new();
842 if (self->form == NULL)
843 return -1;
844
845 newtFormAddHotKey(self->form, 'A');
846 newtFormAddHotKey(self->form, 'a');
847 newtFormAddHotKey(self->form, 'D');
848 newtFormAddHotKey(self->form, 'd');
849 newtFormAddHotKey(self->form, 'T');
850 newtFormAddHotKey(self->form, 't');
851 newtFormAddHotKey(self->form, '?');
852 newtFormAddHotKey(self->form, 'H');
853 newtFormAddHotKey(self->form, 'h');
854 newtFormAddHotKey(self->form, NEWT_KEY_F1);
855 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
856 newtFormAddHotKey(self->form, NEWT_KEY_TAB);
857 newtFormAddHotKey(self->form, NEWT_KEY_UNTAB);
858 newtFormAddComponents(self->form, self->tree, NULL);
859 self->selection = newt__symbol_tree_get_current(self->tree);
860
861 return 0;
862}
863
864static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
865{
866 int *indexes;
867
868 if (!symbol_conf.use_callchain)
869 goto out;
870
871 indexes = newtCheckboxTreeFindItem(self->tree, (void *)self->selection);
872 if (indexes) {
873 bool is_hist_entry = indexes[1] == NEWT_ARG_LAST;
874 free(indexes);
875 if (is_hist_entry)
876 goto out;
877 }
878 return NULL;
879out:
880 return container_of(self->selection, struct hist_entry, ms);
881}
882
883static struct thread *hist_browser__selected_thread(struct hist_browser *self)
884{
885 struct hist_entry *he = hist_browser__selected_entry(self);
886 return he ? he->thread : NULL;
887}
888
889static int hist_browser__title(char *bf, size_t size, const char *ev_name,
890 const struct dso *dso, const struct thread *thread)
891{
892 int printed = 0;
893
894 if (thread)
895 printed += snprintf(bf + printed, size - printed,
896 "Thread: %s(%d)",
897 (thread->comm_set ? thread->comm : ""),
898 thread->pid);
899 if (dso)
900 printed += snprintf(bf + printed, size - printed,
901 "%sDSO: %s", thread ? " " : "",
902 dso->short_name);
903 return printed ?: snprintf(bf, size, "Event: %s", ev_name);
904}
905
906int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
907{
908 struct hist_browser *browser = hist_browser__new();
909 struct pstack *fstack;
910 const struct thread *thread_filter = NULL;
911 const struct dso *dso_filter = NULL;
912 struct newtExitStruct es;
913 char msg[160];
914 int key = -1;
915
916 if (browser == NULL)
917 return -1;
918
919 fstack = pstack__new(2);
920 if (fstack == NULL)
921 goto out;
922
923 ui_helpline__push(helpline);
924
925 hist_browser__title(msg, sizeof(msg), ev_name,
926 dso_filter, thread_filter);
927 if (hist_browser__populate(browser, self, msg) < 0)
928 goto out_free_stack;
929
930 while (1) {
931 const struct thread *thread;
932 const struct dso *dso;
933 char *options[16];
934 int nr_options = 0, choice = 0, i,
935 annotate = -2, zoom_dso = -2, zoom_thread = -2;
936
937 newtFormRun(browser->form, &es);
938
939 thread = hist_browser__selected_thread(browser);
940 dso = browser->selection->map ? browser->selection->map->dso : NULL;
941
942 if (es.reason == NEWT_EXIT_HOTKEY) {
943 key = es.u.key;
944
945 switch (key) {
946 case NEWT_KEY_F1:
947 goto do_help;
948 case NEWT_KEY_TAB:
949 case NEWT_KEY_UNTAB:
950 /*
951 * Exit the browser, let hists__browser_tree
952 * go to the next or previous
953 */
954 goto out_free_stack;
955 default:;
956 }
957
958 key = toupper(key);
959 switch (key) {
960 case 'A':
961 if (browser->selection->map == NULL &&
962 browser->selection->map->dso->annotate_warned)
963 continue;
964 goto do_annotate;
965 case 'D':
966 goto zoom_dso;
967 case 'T':
968 goto zoom_thread;
969 case 'H':
970 case '?':
971do_help:
972 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
973 "<- Zoom out\n"
974 "a Annotate current symbol\n"
975 "h/?/F1 Show this window\n"
976 "d Zoom into current DSO\n"
977 "t Zoom into current Thread\n"
978 "q/CTRL+C Exit browser");
979 continue;
980 default:;
981 }
982 if (is_exit_key(key)) {
983 if (key == NEWT_KEY_ESCAPE) {
984 if (dialog_yesno("Do you really want to exit?"))
985 break;
986 else
987 continue;
988 } else
989 break;
990 }
991
992 if (es.u.key == NEWT_KEY_LEFT) {
993 const void *top;
994
995 if (pstack__empty(fstack))
996 continue;
997 top = pstack__pop(fstack);
998 if (top == &dso_filter)
999 goto zoom_out_dso;
1000 if (top == &thread_filter)
1001 goto zoom_out_thread;
1002 continue;
1003 }
1004 }
1005
1006 if (browser->selection->sym != NULL &&
1007 !browser->selection->map->dso->annotate_warned &&
1008 asprintf(&options[nr_options], "Annotate %s",
1009 browser->selection->sym->name) > 0)
1010 annotate = nr_options++;
1011
1012 if (thread != NULL &&
1013 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
1014 (thread_filter ? "out of" : "into"),
1015 (thread->comm_set ? thread->comm : ""),
1016 thread->pid) > 0)
1017 zoom_thread = nr_options++;
1018
1019 if (dso != NULL &&
1020 asprintf(&options[nr_options], "Zoom %s %s DSO",
1021 (dso_filter ? "out of" : "into"),
1022 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1023 zoom_dso = nr_options++;
1024
1025 options[nr_options++] = (char *)"Exit";
1026
1027 choice = popup_menu(nr_options, options);
1028
1029 for (i = 0; i < nr_options - 1; ++i)
1030 free(options[i]);
1031
1032 if (choice == nr_options - 1)
1033 break;
1034
1035 if (choice == -1)
1036 continue;
1037
1038 if (choice == annotate) {
1039 struct hist_entry *he;
1040do_annotate:
1041 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
1042 browser->selection->map->dso->annotate_warned = 1;
1043 ui_helpline__puts("No vmlinux file found, can't "
1044 "annotate with just a "
1045 "kallsyms file");
1046 continue;
1047 }
1048
1049 he = hist_browser__selected_entry(browser);
1050 if (he == NULL)
1051 continue;
1052
1053 hist_entry__tui_annotate(he);
1054 } else if (choice == zoom_dso) {
1055zoom_dso:
1056 if (dso_filter) {
1057 pstack__remove(fstack, &dso_filter);
1058zoom_out_dso:
1059 ui_helpline__pop();
1060 dso_filter = NULL;
1061 } else {
1062 if (dso == NULL)
1063 continue;
1064 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1065 dso->kernel ? "the Kernel" : dso->short_name);
1066 dso_filter = dso;
1067 pstack__push(fstack, &dso_filter);
1068 }
1069 hists__filter_by_dso(self, dso_filter);
1070 hist_browser__title(msg, sizeof(msg), ev_name,
1071 dso_filter, thread_filter);
1072 if (hist_browser__populate(browser, self, msg) < 0)
1073 goto out;
1074 } else if (choice == zoom_thread) {
1075zoom_thread:
1076 if (thread_filter) {
1077 pstack__remove(fstack, &thread_filter);
1078zoom_out_thread:
1079 ui_helpline__pop();
1080 thread_filter = NULL;
1081 } else {
1082 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1083 thread->comm_set ? thread->comm : "",
1084 thread->pid);
1085 thread_filter = thread;
1086 pstack__push(fstack, &thread_filter);
1087 }
1088 hists__filter_by_thread(self, thread_filter);
1089 hist_browser__title(msg, sizeof(msg), ev_name,
1090 dso_filter, thread_filter);
1091 if (hist_browser__populate(browser, self, msg) < 0)
1092 goto out;
1093 }
1094 }
1095out_free_stack:
1096 pstack__delete(fstack);
1097out:
1098 hist_browser__delete(browser);
1099 return key;
1100}
1101
1102int hists__tui_browse_tree(struct rb_root *self, const char *help)
1103{
1104 struct rb_node *first = rb_first(self), *nd = first, *next;
1105 int key = 0;
1106
1107 while (nd) {
1108 struct hists *hists = rb_entry(nd, struct hists, rb_node);
1109 const char *ev_name = __event_name(hists->type, hists->config);
1110
1111 key = hists__browse(hists, help, ev_name);
1112
1113 if (is_exit_key(key))
1114 break;
1115
1116 switch (key) {
1117 case NEWT_KEY_TAB:
1118 next = rb_next(nd);
1119 if (next)
1120 nd = next;
1121 break;
1122 case NEWT_KEY_UNTAB:
1123 if (nd == first)
1124 continue;
1125 nd = rb_prev(nd);
1126 default:
1127 break;
1128 }
1129 }
1130
1131 return key;
1132}
1133
1134static struct newtPercentTreeColors {
1135 const char *topColorFg, *topColorBg;
1136 const char *mediumColorFg, *mediumColorBg;
1137 const char *normalColorFg, *normalColorBg;
1138 const char *selColorFg, *selColorBg;
1139 const char *codeColorFg, *codeColorBg;
1140} defaultPercentTreeColors = {
1141 "red", "lightgray",
1142 "green", "lightgray",
1143 "black", "lightgray",
1144 "lightgray", "magenta",
1145 "blue", "lightgray",
1146};
1147
1148void setup_browser(void)
1149{
1150 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
1151
1152 if (!isatty(1) || !use_browser || dump_trace) {
1153 use_browser = 0;
1154 setup_pager();
1155 return;
1156 }
1157
1158 use_browser = 1;
1159 newtInit();
1160 newtCls();
1161 ui_helpline__puts(" ");
1162 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
1163 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
1164 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
1165 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
1166 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
1167}
1168
1169void exit_browser(bool wait_for_ok)
1170{
1171 if (use_browser > 0) {
1172 if (wait_for_ok) {
1173 char title[] = "Fatal Error", ok[] = "Ok";
1174 newtWinMessage(title, ok, browser__last_msg);
1175 }
1176 newtFinished();
1177 }
1178}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb016b2..9bf0f402ca73 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"
@@ -409,7 +410,6 @@ static enum event_result
409parse_single_tracepoint_event(char *sys_name, 410parse_single_tracepoint_event(char *sys_name,
410 const char *evt_name, 411 const char *evt_name,
411 unsigned int evt_length, 412 unsigned int evt_length,
412 char *flags,
413 struct perf_event_attr *attr, 413 struct perf_event_attr *attr,
414 const char **strp) 414 const char **strp)
415{ 415{
@@ -418,14 +418,6 @@ parse_single_tracepoint_event(char *sys_name,
418 u64 id; 418 u64 id;
419 int fd; 419 int fd;
420 420
421 if (flags) {
422 if (!strncmp(flags, "record", strlen(flags))) {
423 attr->sample_type |= PERF_SAMPLE_RAW;
424 attr->sample_type |= PERF_SAMPLE_TIME;
425 attr->sample_type |= PERF_SAMPLE_CPU;
426 }
427 }
428
429 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 421 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
430 sys_name, evt_name); 422 sys_name, evt_name);
431 423
@@ -444,13 +436,21 @@ parse_single_tracepoint_event(char *sys_name,
444 attr->type = PERF_TYPE_TRACEPOINT; 436 attr->type = PERF_TYPE_TRACEPOINT;
445 *strp = evt_name + evt_length; 437 *strp = evt_name + evt_length;
446 438
439 attr->sample_type |= PERF_SAMPLE_RAW;
440 attr->sample_type |= PERF_SAMPLE_TIME;
441 attr->sample_type |= PERF_SAMPLE_CPU;
442
443 attr->sample_period = 1;
444
445
447 return EVT_HANDLED; 446 return EVT_HANDLED;
448} 447}
449 448
450/* sys + ':' + event + ':' + flags*/ 449/* sys + ':' + event + ':' + flags*/
451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 450#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
452static enum event_result 451static enum event_result
453parse_subsystem_tracepoint_event(char *sys_name, char *flags) 452parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
453 char *flags)
454{ 454{
455 char evt_path[MAXPATHLEN]; 455 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 456 struct dirent *evt_ent;
@@ -474,6 +474,9 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
474 || !strcmp(evt_ent->d_name, "filter")) 474 || !strcmp(evt_ent->d_name, "filter"))
475 continue; 475 continue;
476 476
477 if (!strglobmatch(evt_ent->d_name, evt_exp))
478 continue;
479
477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 480 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
478 evt_ent->d_name, flags ? ":" : "", 481 evt_ent->d_name, flags ? ":" : "",
479 flags ?: ""); 482 flags ?: "");
@@ -522,13 +525,13 @@ static enum event_result parse_tracepoint_event(const char **strp,
522 if (evt_length >= MAX_EVENT_LENGTH) 525 if (evt_length >= MAX_EVENT_LENGTH)
523 return EVT_FAILED; 526 return EVT_FAILED;
524 527
525 if (!strcmp(evt_name, "*")) { 528 if (strpbrk(evt_name, "*?")) {
526 *strp = evt_name + evt_length; 529 *strp = evt_name + evt_length;
527 return parse_subsystem_tracepoint_event(sys_name, flags); 530 return parse_multiple_tracepoint_event(sys_name, evt_name,
531 flags);
528 } else 532 } else
529 return parse_single_tracepoint_event(sys_name, evt_name, 533 return parse_single_tracepoint_event(sys_name, evt_name,
530 evt_length, flags, 534 evt_length, attr, strp);
531 attr, strp);
532} 535}
533 536
534static enum event_result 537static enum event_result
@@ -685,19 +688,29 @@ static enum event_result
685parse_event_modifier(const char **strp, struct perf_event_attr *attr) 688parse_event_modifier(const char **strp, struct perf_event_attr *attr)
686{ 689{
687 const char *str = *strp; 690 const char *str = *strp;
688 int eu = 1, ek = 1, eh = 1; 691 int exclude = 0;
692 int eu = 0, ek = 0, eh = 0, precise = 0;
689 693
690 if (*str++ != ':') 694 if (*str++ != ':')
691 return 0; 695 return 0;
692 while (*str) { 696 while (*str) {
693 if (*str == 'u') 697 if (*str == 'u') {
698 if (!exclude)
699 exclude = eu = ek = eh = 1;
694 eu = 0; 700 eu = 0;
695 else if (*str == 'k') 701 } else if (*str == 'k') {
702 if (!exclude)
703 exclude = eu = ek = eh = 1;
696 ek = 0; 704 ek = 0;
697 else if (*str == 'h') 705 } else if (*str == 'h') {
706 if (!exclude)
707 exclude = eu = ek = eh = 1;
698 eh = 0; 708 eh = 0;
699 else 709 } else if (*str == 'p') {
710 precise++;
711 } else
700 break; 712 break;
713
701 ++str; 714 ++str;
702 } 715 }
703 if (str >= *strp + 2) { 716 if (str >= *strp + 2) {
@@ -705,6 +718,7 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
705 attr->exclude_user = eu; 718 attr->exclude_user = eu;
706 attr->exclude_kernel = ek; 719 attr->exclude_kernel = ek;
707 attr->exclude_hv = eh; 720 attr->exclude_hv = eh;
721 attr->precise_ip = precise;
708 return 1; 722 return 1;
709 } 723 }
710 return 0; 724 return 0;
@@ -753,11 +767,11 @@ modifier:
753 return ret; 767 return ret;
754} 768}
755 769
756static void store_event_type(const char *orgname) 770static int store_event_type(const char *orgname)
757{ 771{
758 char filename[PATH_MAX], *c; 772 char filename[PATH_MAX], *c;
759 FILE *file; 773 FILE *file;
760 int id; 774 int id, n;
761 775
762 sprintf(filename, "%s/", debugfs_path); 776 sprintf(filename, "%s/", debugfs_path);
763 strncat(filename, orgname, strlen(orgname)); 777 strncat(filename, orgname, strlen(orgname));
@@ -769,11 +783,14 @@ static void store_event_type(const char *orgname)
769 783
770 file = fopen(filename, "r"); 784 file = fopen(filename, "r");
771 if (!file) 785 if (!file)
772 return; 786 return 0;
773 if (fscanf(file, "%i", &id) < 1) 787 n = fscanf(file, "%i", &id);
774 die("cannot store event ID");
775 fclose(file); 788 fclose(file);
776 perf_header__push_event(id, orgname); 789 if (n < 1) {
790 pr_err("cannot store event ID\n");
791 return -EINVAL;
792 }
793 return perf_header__push_event(id, orgname);
777} 794}
778 795
779int parse_events(const struct option *opt __used, const char *str, int unset __used) 796int parse_events(const struct option *opt __used, const char *str, int unset __used)
@@ -782,7 +799,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
782 enum event_result ret; 799 enum event_result ret;
783 800
784 if (strchr(str, ':')) 801 if (strchr(str, ':'))
785 store_event_type(str); 802 if (store_event_type(str) < 0)
803 return -1;
786 804
787 for (;;) { 805 for (;;) {
788 if (nr_counters == MAX_COUNTERS) 806 if (nr_counters == MAX_COUNTERS)
@@ -835,11 +853,12 @@ int parse_filter(const struct option *opt __used, const char *str,
835} 853}
836 854
837static const char * const event_type_descriptors[] = { 855static const char * const event_type_descriptors[] = {
838 "",
839 "Hardware event", 856 "Hardware event",
840 "Software event", 857 "Software event",
841 "Tracepoint event", 858 "Tracepoint event",
842 "Hardware cache event", 859 "Hardware cache event",
860 "Raw hardware event descriptor",
861 "Hardware breakpoint",
843}; 862};
844 863
845/* 864/*
@@ -872,7 +891,7 @@ static void print_tracepoint_events(void)
872 snprintf(evt_path, MAXPATHLEN, "%s:%s", 891 snprintf(evt_path, MAXPATHLEN, "%s:%s",
873 sys_dirent.d_name, evt_dirent.d_name); 892 sys_dirent.d_name, evt_dirent.d_name);
874 printf(" %-42s [%s]\n", evt_path, 893 printf(" %-42s [%s]\n", evt_path,
875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 894 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
876 } 895 }
877 closedir(evt_dir); 896 closedir(evt_dir);
878 } 897 }
@@ -892,9 +911,7 @@ void print_events(void)
892 printf("List of pre-defined events (to be used in -e):\n"); 911 printf("List of pre-defined events (to be used in -e):\n");
893 912
894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 913 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
895 type = syms->type + 1; 914 type = syms->type;
896 if (type >= ARRAY_SIZE(event_type_descriptors))
897 type = 0;
898 915
899 if (type != prev_type) 916 if (type != prev_type)
900 printf("\n"); 917 printf("\n");
@@ -919,17 +936,20 @@ void print_events(void)
919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 936 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
920 printf(" %-42s [%s]\n", 937 printf(" %-42s [%s]\n",
921 event_cache_name(type, op, i), 938 event_cache_name(type, op, i),
922 event_type_descriptors[4]); 939 event_type_descriptors[PERF_TYPE_HW_CACHE]);
923 } 940 }
924 } 941 }
925 } 942 }
926 943
927 printf("\n"); 944 printf("\n");
928 printf(" %-42s [raw hardware event descriptor]\n", 945 printf(" %-42s [%s]\n",
929 "rNNN"); 946 "rNNN (see 'perf list --help' on how to encode it)",
947 event_type_descriptors[PERF_TYPE_RAW]);
930 printf("\n"); 948 printf("\n");
931 949
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); 950 printf(" %-42s [%s]\n",
951 "mem:<addr>[:access]",
952 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
933 printf("\n"); 953 printf("\n");
934 954
935 print_tracepoint_events(); 955 print_tracepoint_events();
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b8c1f64bc935..fc4ab3fe877a 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -13,6 +13,7 @@ struct tracepoint_path {
13}; 13};
14 14
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 15extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16extern bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events);
16 17
17extern int nr_counters; 18extern int nr_counters;
18 19
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index efebd5b476b3..99d02aa57dbf 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -49,8 +49,9 @@ static int get_value(struct parse_opt_ctx_t *p,
49 break; 49 break;
50 /* FALLTHROUGH */ 50 /* FALLTHROUGH */
51 case OPTION_BOOLEAN: 51 case OPTION_BOOLEAN:
52 case OPTION_INCR:
52 case OPTION_BIT: 53 case OPTION_BIT:
53 case OPTION_SET_INT: 54 case OPTION_SET_UINT:
54 case OPTION_SET_PTR: 55 case OPTION_SET_PTR:
55 return opterror(opt, "takes no value", flags); 56 return opterror(opt, "takes no value", flags);
56 case OPTION_END: 57 case OPTION_END:
@@ -58,7 +59,9 @@ static int get_value(struct parse_opt_ctx_t *p,
58 case OPTION_GROUP: 59 case OPTION_GROUP:
59 case OPTION_STRING: 60 case OPTION_STRING:
60 case OPTION_INTEGER: 61 case OPTION_INTEGER:
62 case OPTION_UINTEGER:
61 case OPTION_LONG: 63 case OPTION_LONG:
64 case OPTION_U64:
62 default: 65 default:
63 break; 66 break;
64 } 67 }
@@ -73,11 +76,15 @@ static int get_value(struct parse_opt_ctx_t *p,
73 return 0; 76 return 0;
74 77
75 case OPTION_BOOLEAN: 78 case OPTION_BOOLEAN:
79 *(bool *)opt->value = unset ? false : true;
80 return 0;
81
82 case OPTION_INCR:
76 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; 83 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
77 return 0; 84 return 0;
78 85
79 case OPTION_SET_INT: 86 case OPTION_SET_UINT:
80 *(int *)opt->value = unset ? 0 : opt->defval; 87 *(unsigned int *)opt->value = unset ? 0 : opt->defval;
81 return 0; 88 return 0;
82 89
83 case OPTION_SET_PTR: 90 case OPTION_SET_PTR:
@@ -120,6 +127,22 @@ static int get_value(struct parse_opt_ctx_t *p,
120 return opterror(opt, "expects a numerical value", flags); 127 return opterror(opt, "expects a numerical value", flags);
121 return 0; 128 return 0;
122 129
130 case OPTION_UINTEGER:
131 if (unset) {
132 *(unsigned int *)opt->value = 0;
133 return 0;
134 }
135 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
136 *(unsigned int *)opt->value = opt->defval;
137 return 0;
138 }
139 if (get_arg(p, opt, flags, &arg))
140 return -1;
141 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
142 if (*s)
143 return opterror(opt, "expects a numerical value", flags);
144 return 0;
145
123 case OPTION_LONG: 146 case OPTION_LONG:
124 if (unset) { 147 if (unset) {
125 *(long *)opt->value = 0; 148 *(long *)opt->value = 0;
@@ -136,6 +159,22 @@ static int get_value(struct parse_opt_ctx_t *p,
136 return opterror(opt, "expects a numerical value", flags); 159 return opterror(opt, "expects a numerical value", flags);
137 return 0; 160 return 0;
138 161
162 case OPTION_U64:
163 if (unset) {
164 *(u64 *)opt->value = 0;
165 return 0;
166 }
167 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
168 *(u64 *)opt->value = opt->defval;
169 return 0;
170 }
171 if (get_arg(p, opt, flags, &arg))
172 return -1;
173 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
174 if (*s)
175 return opterror(opt, "expects a numerical value", flags);
176 return 0;
177
139 case OPTION_END: 178 case OPTION_END:
140 case OPTION_ARGUMENT: 179 case OPTION_ARGUMENT:
141 case OPTION_GROUP: 180 case OPTION_GROUP:
@@ -441,7 +480,10 @@ int usage_with_options_internal(const char * const *usagestr,
441 switch (opts->type) { 480 switch (opts->type) {
442 case OPTION_ARGUMENT: 481 case OPTION_ARGUMENT:
443 break; 482 break;
483 case OPTION_LONG:
484 case OPTION_U64:
444 case OPTION_INTEGER: 485 case OPTION_INTEGER:
486 case OPTION_UINTEGER:
445 if (opts->flags & PARSE_OPT_OPTARG) 487 if (opts->flags & PARSE_OPT_OPTARG)
446 if (opts->long_name) 488 if (opts->long_name)
447 pos += fprintf(stderr, "[=<n>]"); 489 pos += fprintf(stderr, "[=<n>]");
@@ -473,14 +515,14 @@ int usage_with_options_internal(const char * const *usagestr,
473 pos += fprintf(stderr, " ..."); 515 pos += fprintf(stderr, " ...");
474 } 516 }
475 break; 517 break;
476 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ 518 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
477 case OPTION_END: 519 case OPTION_END:
478 case OPTION_GROUP: 520 case OPTION_GROUP:
479 case OPTION_BIT: 521 case OPTION_BIT:
480 case OPTION_BOOLEAN: 522 case OPTION_BOOLEAN:
481 case OPTION_SET_INT: 523 case OPTION_INCR:
524 case OPTION_SET_UINT:
482 case OPTION_SET_PTR: 525 case OPTION_SET_PTR:
483 case OPTION_LONG:
484 break; 526 break;
485 } 527 }
486 528
@@ -500,6 +542,7 @@ int usage_with_options_internal(const char * const *usagestr,
500void usage_with_options(const char * const *usagestr, 542void usage_with_options(const char * const *usagestr,
501 const struct option *opts) 543 const struct option *opts)
502{ 544{
545 exit_browser(false);
503 usage_with_options_internal(usagestr, opts, 0); 546 usage_with_options_internal(usagestr, opts, 0);
504 exit(129); 547 exit(129);
505} 548}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 948805af43c2..c7d72dce54b2 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,6 +1,9 @@
1#ifndef __PERF_PARSE_OPTIONS_H 1#ifndef __PERF_PARSE_OPTIONS_H
2#define __PERF_PARSE_OPTIONS_H 2#define __PERF_PARSE_OPTIONS_H
3 3
4#include <linux/kernel.h>
5#include <stdbool.h>
6
4enum parse_opt_type { 7enum parse_opt_type {
5 /* special types */ 8 /* special types */
6 OPTION_END, 9 OPTION_END,
@@ -8,14 +11,17 @@ enum parse_opt_type {
8 OPTION_GROUP, 11 OPTION_GROUP,
9 /* options with no arguments */ 12 /* options with no arguments */
10 OPTION_BIT, 13 OPTION_BIT,
11 OPTION_BOOLEAN, /* _INCR would have been a better name */ 14 OPTION_BOOLEAN,
12 OPTION_SET_INT, 15 OPTION_INCR,
16 OPTION_SET_UINT,
13 OPTION_SET_PTR, 17 OPTION_SET_PTR,
14 /* options with arguments (usually) */ 18 /* options with arguments (usually) */
15 OPTION_STRING, 19 OPTION_STRING,
16 OPTION_INTEGER, 20 OPTION_INTEGER,
17 OPTION_LONG, 21 OPTION_LONG,
18 OPTION_CALLBACK, 22 OPTION_CALLBACK,
23 OPTION_U64,
24 OPTION_UINTEGER,
19}; 25};
20 26
21enum parse_opt_flags { 27enum parse_opt_flags {
@@ -73,7 +79,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
73 * 79 *
74 * `defval`:: 80 * `defval`::
75 * default value to fill (*->value) with for PARSE_OPT_OPTARG. 81 * default value to fill (*->value) with for PARSE_OPT_OPTARG.
76 * OPTION_{BIT,SET_INT,SET_PTR} store the {mask,integer,pointer} to put in 82 * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
77 * the value when met. 83 * the value when met.
78 * CALLBACKS can use it like they want. 84 * CALLBACKS can use it like they want.
79 */ 85 */
@@ -90,16 +96,21 @@ struct option {
90 intptr_t defval; 96 intptr_t defval;
91}; 97};
92 98
99#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
100
93#define OPT_END() { .type = OPTION_END } 101#define OPT_END() { .type = OPTION_END }
94#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) } 102#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
95#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } 103#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
96#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (b) } 104#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
97#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) } 105#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
98#define OPT_SET_INT(s, l, v, h, i) { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) } 106#define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
107#define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } 108#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
100#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = (v), .help = (h) } 109#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
101#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) } 110#define OPT_UINTEGER(s, l, v, h) { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) }
102#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) } 111#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
112#define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
113#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
103#define OPT_DATE(s, l, v, h) \ 114#define OPT_DATE(s, l, v, h) \
104 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb } 115 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
105#define OPT_CALLBACK(s, l, v, a, h, f) \ 116#define OPT_CALLBACK(s, l, v, a, h, f) \
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index fd1f2faaade4..58a470d036dd 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -54,21 +54,6 @@ static char *cleanup_path(char *path)
54 return path; 54 return path;
55} 55}
56 56
57char *mksnpath(char *buf, size_t n, const char *fmt, ...)
58{
59 va_list args;
60 unsigned len;
61
62 va_start(args, fmt);
63 len = vsnprintf(buf, n, fmt, args);
64 va_end(args);
65 if (len >= n) {
66 strlcpy(buf, bad_path, n);
67 return buf;
68 }
69 return cleanup_path(buf);
70}
71
72static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args) 57static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
73{ 58{
74 const char *perf_dir = get_perf_dir(); 59 const char *perf_dir = get_perf_dir();
@@ -89,15 +74,6 @@ bad:
89 return buf; 74 return buf;
90} 75}
91 76
92char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
93{
94 va_list args;
95 va_start(args, fmt);
96 (void)perf_vsnpath(buf, n, fmt, args);
97 va_end(args);
98 return buf;
99}
100
101char *perf_pathdup(const char *fmt, ...) 77char *perf_pathdup(const char *fmt, ...)
102{ 78{
103 char path[PATH_MAX]; 79 char path[PATH_MAX];
@@ -143,184 +119,6 @@ char *perf_path(const char *fmt, ...)
143 return cleanup_path(pathname); 119 return cleanup_path(pathname);
144} 120}
145 121
146
147/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
148int perf_mkstemp(char *path, size_t len, const char *template)
149{
150 const char *tmp;
151 size_t n;
152
153 tmp = getenv("TMPDIR");
154 if (!tmp)
155 tmp = "/tmp";
156 n = snprintf(path, len, "%s/%s", tmp, template);
157 if (len <= n) {
158 errno = ENAMETOOLONG;
159 return -1;
160 }
161 return mkstemp(path);
162}
163
164
165const char *make_relative_path(const char *abs_path, const char *base)
166{
167 static char buf[PATH_MAX + 1];
168 int baselen;
169
170 if (!base)
171 return abs_path;
172
173 baselen = strlen(base);
174 if (prefixcmp(abs_path, base))
175 return abs_path;
176 if (abs_path[baselen] == '/')
177 baselen++;
178 else if (base[baselen - 1] != '/')
179 return abs_path;
180
181 strcpy(buf, abs_path + baselen);
182
183 return buf;
184}
185
186/*
187 * It is okay if dst == src, but they should not overlap otherwise.
188 *
189 * Performs the following normalizations on src, storing the result in dst:
190 * - Ensures that components are separated by '/' (Windows only)
191 * - Squashes sequences of '/'.
192 * - Removes "." components.
193 * - Removes ".." components, and the components the precede them.
194 * Returns failure (non-zero) if a ".." component appears as first path
195 * component anytime during the normalization. Otherwise, returns success (0).
196 *
197 * Note that this function is purely textual. It does not follow symlinks,
198 * verify the existence of the path, or make any system calls.
199 */
200int normalize_path_copy(char *dst, const char *src)
201{
202 char *dst0;
203
204 if (has_dos_drive_prefix(src)) {
205 *dst++ = *src++;
206 *dst++ = *src++;
207 }
208 dst0 = dst;
209
210 if (is_dir_sep(*src)) {
211 *dst++ = '/';
212 while (is_dir_sep(*src))
213 src++;
214 }
215
216 for (;;) {
217 char c = *src;
218
219 /*
220 * A path component that begins with . could be
221 * special:
222 * (1) "." and ends -- ignore and terminate.
223 * (2) "./" -- ignore them, eat slash and continue.
224 * (3) ".." and ends -- strip one and terminate.
225 * (4) "../" -- strip one, eat slash and continue.
226 */
227 if (c == '.') {
228 if (!src[1]) {
229 /* (1) */
230 src++;
231 } else if (is_dir_sep(src[1])) {
232 /* (2) */
233 src += 2;
234 while (is_dir_sep(*src))
235 src++;
236 continue;
237 } else if (src[1] == '.') {
238 if (!src[2]) {
239 /* (3) */
240 src += 2;
241 goto up_one;
242 } else if (is_dir_sep(src[2])) {
243 /* (4) */
244 src += 3;
245 while (is_dir_sep(*src))
246 src++;
247 goto up_one;
248 }
249 }
250 }
251
252 /* copy up to the next '/', and eat all '/' */
253 while ((c = *src++) != '\0' && !is_dir_sep(c))
254 *dst++ = c;
255 if (is_dir_sep(c)) {
256 *dst++ = '/';
257 while (is_dir_sep(c))
258 c = *src++;
259 src--;
260 } else if (!c)
261 break;
262 continue;
263
264 up_one:
265 /*
266 * dst0..dst is prefix portion, and dst[-1] is '/';
267 * go up one level.
268 */
269 dst--; /* go to trailing '/' */
270 if (dst <= dst0)
271 return -1;
272 /* Windows: dst[-1] cannot be backslash anymore */
273 while (dst0 < dst && dst[-1] != '/')
274 dst--;
275 }
276 *dst = '\0';
277 return 0;
278}
279
280/*
281 * path = Canonical absolute path
282 * prefix_list = Colon-separated list of absolute paths
283 *
284 * Determines, for each path in prefix_list, whether the "prefix" really
285 * is an ancestor directory of path. Returns the length of the longest
286 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
287 * is an ancestor. (Note that this means 0 is returned if prefix_list is
288 * "/".) "/foo" is not considered an ancestor of "/foobar". Directories
289 * are not considered to be their own ancestors. path must be in a
290 * canonical form: empty components, or "." or ".." components are not
291 * allowed. prefix_list may be null, which is like "".
292 */
293int longest_ancestor_length(const char *path, const char *prefix_list)
294{
295 char buf[PATH_MAX+1];
296 const char *ceil, *colon;
297 int len, max_len = -1;
298
299 if (prefix_list == NULL || !strcmp(path, "/"))
300 return -1;
301
302 for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
303 for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
304 len = colon - ceil;
305 if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
306 continue;
307 strlcpy(buf, ceil, len+1);
308 if (normalize_path_copy(buf, buf) < 0)
309 continue;
310 len = strlen(buf);
311 if (len > 0 && buf[len-1] == '/')
312 buf[--len] = '\0';
313
314 if (!strncmp(path, buf, len) &&
315 path[len] == '/' &&
316 len > max_len) {
317 max_len = len;
318 }
319 }
320
321 return max_len;
322}
323
324/* strip arbitrary amount of directory separators at end of path */ 122/* strip arbitrary amount of directory separators at end of path */
325static inline int chomp_trailing_dir_sep(const char *path, int len) 123static inline int chomp_trailing_dir_sep(const char *path, int len)
326{ 124{
@@ -354,5 +152,5 @@ char *strip_path_suffix(const char *path, const char *suffix)
354 152
355 if (path_len && !is_dir_sep(path[path_len - 1])) 153 if (path_len && !is_dir_sep(path[path_len - 1]))
356 return NULL; 154 return NULL;
357 return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); 155 return strndup(path, chomp_trailing_dir_sep(path, path_len));
358} 156}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 29465d440043..914c67095d96 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -33,18 +33,27 @@
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 "parse-events.h" /* For debugfs_path */ 41#include "cache.h"
42#include "color.h"
43#include "symbol.h"
44#include "thread.h"
45#include "debugfs.h"
46#include "trace-event.h" /* For __unused */
41#include "probe-event.h" 47#include "probe-event.h"
48#include "probe-finder.h"
42 49
43#define MAX_CMDLEN 256 50#define MAX_CMDLEN 256
44#define MAX_PROBE_ARGS 128 51#define MAX_PROBE_ARGS 128
45#define PERFPROBE_GROUP "probe" 52#define PERFPROBE_GROUP "probe"
46 53
47#define semantic_error(msg ...) die("Semantic error :" msg) 54bool probe_event_dry_run; /* Dry run flag */
55
56#define semantic_error(msg ...) pr_err("Semantic error :" msg)
48 57
49/* If there is no space to write, returns -E2BIG. */ 58/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...) 59static int e_snprintf(char *str, size_t size, const char *format, ...)
@@ -62,6 +71,326 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 71 return ret;
63} 72}
64 73
74static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75static struct machine machine;
76
77/* Initialize symbol maps and path of vmlinux */
78static int init_vmlinux(void)
79{
80 struct dso *kernel;
81 int ret;
82
83 symbol_conf.sort_by_name = true;
84 if (symbol_conf.vmlinux_name == NULL)
85 symbol_conf.try_vmlinux_path = true;
86 else
87 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
88 ret = symbol__init();
89 if (ret < 0) {
90 pr_debug("Failed to init symbol map.\n");
91 goto out;
92 }
93
94 ret = machine__init(&machine, "/", 0);
95 if (ret < 0)
96 goto out;
97
98 kernel = dso__new_kernel(symbol_conf.vmlinux_name);
99 if (kernel == NULL)
100 die("Failed to create kernel dso.");
101
102 ret = __machine__create_kernel_maps(&machine, kernel);
103 if (ret < 0)
104 pr_debug("Failed to create kernel maps.\n");
105
106out:
107 if (ret < 0)
108 pr_warning("Failed to init vmlinux path.\n");
109 return ret;
110}
111
112#ifdef DWARF_SUPPORT
113static int open_vmlinux(void)
114{
115 if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
116 pr_debug("Failed to load kernel map.\n");
117 return -EINVAL;
118 }
119 pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
121}
122
123/* Convert trace point to probe point with debuginfo */
124static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
125 struct perf_probe_point *pp)
126{
127 struct symbol *sym;
128 int fd, ret = -ENOENT;
129
130 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
131 tp->symbol, NULL);
132 if (sym) {
133 fd = open_vmlinux();
134 if (fd >= 0) {
135 ret = find_perf_probe_point(fd,
136 sym->start + tp->offset, pp);
137 close(fd);
138 }
139 }
140 if (ret <= 0) {
141 pr_debug("Failed to find corresponding probes from "
142 "debuginfo. Use kprobe event information.\n");
143 pp->function = strdup(tp->symbol);
144 if (pp->function == NULL)
145 return -ENOMEM;
146 pp->offset = tp->offset;
147 }
148 pp->retprobe = tp->retprobe;
149
150 return 0;
151}
152
153/* Try to find perf_probe_event with debuginfo */
154static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
155 struct kprobe_trace_event **tevs,
156 int max_tevs)
157{
158 bool need_dwarf = perf_probe_event_need_dwarf(pev);
159 int fd, ntevs;
160
161 fd = open_vmlinux();
162 if (fd < 0) {
163 if (need_dwarf) {
164 pr_warning("Failed to open debuginfo file.\n");
165 return fd;
166 }
167 pr_debug("Could not open vmlinux. Try to use symbols.\n");
168 return 0;
169 }
170
171 /* Searching trace events corresponding to probe event */
172 ntevs = find_kprobe_trace_events(fd, pev, tevs, max_tevs);
173 close(fd);
174
175 if (ntevs > 0) { /* Succeeded to find trace events */
176 pr_debug("find %d kprobe_trace_events.\n", ntevs);
177 return ntevs;
178 }
179
180 if (ntevs == 0) { /* No error but failed to find probe point. */
181 pr_warning("Probe point '%s' not found.\n",
182 synthesize_perf_probe_point(&pev->point));
183 return -ENOENT;
184 }
185 /* Error path : ntevs < 0 */
186 pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
187 if (ntevs == -EBADF) {
188 pr_warning("Warning: No dwarf info found in the vmlinux - "
189 "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
190 if (!need_dwarf) {
191 pr_debug("Trying to use symbols.\nn");
192 return 0;
193 }
194 }
195 return ntevs;
196}
197
198#define LINEBUF_SIZE 256
199#define NR_ADDITIONAL_LINES 2
200
201static int show_one_line(FILE *fp, int l, bool skip, bool show_num)
202{
203 char buf[LINEBUF_SIZE];
204 const char *color = PERF_COLOR_BLUE;
205
206 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
207 goto error;
208 if (!skip) {
209 if (show_num)
210 fprintf(stdout, "%7d %s", l, buf);
211 else
212 color_fprintf(stdout, color, " %s", buf);
213 }
214
215 while (strlen(buf) == LINEBUF_SIZE - 1 &&
216 buf[LINEBUF_SIZE - 2] != '\n') {
217 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
218 goto error;
219 if (!skip) {
220 if (show_num)
221 fprintf(stdout, "%s", buf);
222 else
223 color_fprintf(stdout, color, "%s", buf);
224 }
225 }
226
227 return 0;
228error:
229 if (feof(fp))
230 pr_warning("Source file is shorter than expected.\n");
231 else
232 pr_warning("File read error: %s\n", strerror(errno));
233
234 return -1;
235}
236
237/*
238 * Show line-range always requires debuginfo to find source file and
239 * line number.
240 */
241int show_line_range(struct line_range *lr)
242{
243 int l = 1;
244 struct line_node *ln;
245 FILE *fp;
246 int fd, ret;
247
248 /* Search a line range */
249 ret = init_vmlinux();
250 if (ret < 0)
251 return ret;
252
253 fd = open_vmlinux();
254 if (fd < 0) {
255 pr_warning("Failed to open debuginfo file.\n");
256 return fd;
257 }
258
259 ret = find_line_range(fd, lr);
260 close(fd);
261 if (ret == 0) {
262 pr_warning("Specified source line is not found.\n");
263 return -ENOENT;
264 } else if (ret < 0) {
265 pr_warning("Debuginfo analysis failed. (%d)\n", ret);
266 return ret;
267 }
268
269 setup_pager();
270
271 if (lr->function)
272 fprintf(stdout, "<%s:%d>\n", lr->function,
273 lr->start - lr->offset);
274 else
275 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
276
277 fp = fopen(lr->path, "r");
278 if (fp == NULL) {
279 pr_warning("Failed to open %s: %s\n", lr->path,
280 strerror(errno));
281 return -errno;
282 }
283 /* Skip to starting line number */
284 while (l < lr->start && ret >= 0)
285 ret = show_one_line(fp, l++, true, false);
286 if (ret < 0)
287 goto end;
288
289 list_for_each_entry(ln, &lr->line_list, list) {
290 while (ln->line > l && ret >= 0)
291 ret = show_one_line(fp, (l++) - lr->offset,
292 false, false);
293 if (ret >= 0)
294 ret = show_one_line(fp, (l++) - lr->offset,
295 false, true);
296 if (ret < 0)
297 goto end;
298 }
299
300 if (lr->end == INT_MAX)
301 lr->end = l + NR_ADDITIONAL_LINES;
302 while (l <= lr->end && !feof(fp) && ret >= 0)
303 ret = show_one_line(fp, (l++) - lr->offset, false, false);
304end:
305 fclose(fp);
306 return ret;
307}
308
309#else /* !DWARF_SUPPORT */
310
311static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
312 struct perf_probe_point *pp)
313{
314 pp->function = strdup(tp->symbol);
315 if (pp->function == NULL)
316 return -ENOMEM;
317 pp->offset = tp->offset;
318 pp->retprobe = tp->retprobe;
319
320 return 0;
321}
322
323static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
324 struct kprobe_trace_event **tevs __unused,
325 int max_tevs __unused)
326{
327 if (perf_probe_event_need_dwarf(pev)) {
328 pr_warning("Debuginfo-analysis is not supported.\n");
329 return -ENOSYS;
330 }
331 return 0;
332}
333
334int show_line_range(struct line_range *lr __unused)
335{
336 pr_warning("Debuginfo-analysis is not supported.\n");
337 return -ENOSYS;
338}
339
340#endif
341
342int parse_line_range_desc(const char *arg, struct line_range *lr)
343{
344 const char *ptr;
345 char *tmp;
346 /*
347 * <Syntax>
348 * SRC:SLN[+NUM|-ELN]
349 * FUNC[:SLN[+NUM|-ELN]]
350 */
351 ptr = strchr(arg, ':');
352 if (ptr) {
353 lr->start = (int)strtoul(ptr + 1, &tmp, 0);
354 if (*tmp == '+') {
355 lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
356 lr->end--; /*
357 * Adjust the number of lines here.
358 * If the number of lines == 1, the
359 * the end of line should be equal to
360 * the start of line.
361 */
362 } else if (*tmp == '-')
363 lr->end = (int)strtoul(tmp + 1, &tmp, 0);
364 else
365 lr->end = INT_MAX;
366 pr_debug("Line range is %d to %d\n", lr->start, lr->end);
367 if (lr->start > lr->end) {
368 semantic_error("Start line must be smaller"
369 " than end line.\n");
370 return -EINVAL;
371 }
372 if (*tmp != '\0') {
373 semantic_error("Tailing with invalid character '%d'.\n",
374 *tmp);
375 return -EINVAL;
376 }
377 tmp = strndup(arg, (ptr - arg));
378 } else {
379 tmp = strdup(arg);
380 lr->end = INT_MAX;
381 }
382
383 if (tmp == NULL)
384 return -ENOMEM;
385
386 if (strchr(tmp, '.'))
387 lr->file = tmp;
388 else
389 lr->function = tmp;
390
391 return 0;
392}
393
65/* Check the name is good for event/group */ 394/* Check the name is good for event/group */
66static bool check_event_name(const char *name) 395static bool check_event_name(const char *name)
67{ 396{
@@ -75,50 +404,66 @@ static bool check_event_name(const char *name)
75} 404}
76 405
77/* Parse probepoint definition. */ 406/* Parse probepoint definition. */
78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 407static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
79{ 408{
409 struct perf_probe_point *pp = &pev->point;
80 char *ptr, *tmp; 410 char *ptr, *tmp;
81 char c, nc = 0; 411 char c, nc = 0;
82 /* 412 /*
83 * <Syntax> 413 * <Syntax>
84 * perf probe [EVENT=]SRC:LN 414 * perf probe [EVENT=]SRC[:LN|;PTN]
85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC] 415 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
86 * 416 *
87 * TODO:Group name support 417 * TODO:Group name support
88 */ 418 */
89 419
90 ptr = strchr(arg, '='); 420 ptr = strpbrk(arg, ";=@+%");
91 if (ptr) { /* Event name */ 421 if (ptr && *ptr == '=') { /* Event name */
92 *ptr = '\0'; 422 *ptr = '\0';
93 tmp = ptr + 1; 423 tmp = ptr + 1;
94 ptr = strchr(arg, ':'); 424 if (strchr(arg, ':')) {
95 if (ptr) /* Group name is not supported yet. */ 425 semantic_error("Group name is not supported yet.\n");
96 semantic_error("Group name is not supported yet."); 426 return -ENOTSUP;
97 if (!check_event_name(arg)) 427 }
428 if (!check_event_name(arg)) {
98 semantic_error("%s is bad for event name -it must " 429 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg); 430 "follow C symbol-naming rule.\n", arg);
100 pp->event = strdup(arg); 431 return -EINVAL;
432 }
433 pev->event = strdup(arg);
434 if (pev->event == NULL)
435 return -ENOMEM;
436 pev->group = NULL;
101 arg = tmp; 437 arg = tmp;
102 } 438 }
103 439
104 ptr = strpbrk(arg, ":+@%"); 440 ptr = strpbrk(arg, ";:+@%");
105 if (ptr) { 441 if (ptr) {
106 nc = *ptr; 442 nc = *ptr;
107 *ptr++ = '\0'; 443 *ptr++ = '\0';
108 } 444 }
109 445
446 tmp = strdup(arg);
447 if (tmp == NULL)
448 return -ENOMEM;
449
110 /* Check arg is function or file and copy it */ 450 /* Check arg is function or file and copy it */
111 if (strchr(arg, '.')) /* File */ 451 if (strchr(tmp, '.')) /* File */
112 pp->file = strdup(arg); 452 pp->file = tmp;
113 else /* Function */ 453 else /* Function */
114 pp->function = strdup(arg); 454 pp->function = tmp;
115 DIE_IF(pp->file == NULL && pp->function == NULL);
116 455
117 /* Parse other options */ 456 /* Parse other options */
118 while (ptr) { 457 while (ptr) {
119 arg = ptr; 458 arg = ptr;
120 c = nc; 459 c = nc;
121 ptr = strpbrk(arg, ":+@%"); 460 if (c == ';') { /* Lazy pattern must be the last part */
461 pp->lazy_line = strdup(arg);
462 if (pp->lazy_line == NULL)
463 return -ENOMEM;
464 break;
465 }
466 ptr = strpbrk(arg, ";:+@%");
122 if (ptr) { 467 if (ptr) {
123 nc = *ptr; 468 nc = *ptr;
124 *ptr++ = '\0'; 469 *ptr++ = '\0';
@@ -126,258 +471,658 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
126 switch (c) { 471 switch (c) {
127 case ':': /* Line number */ 472 case ':': /* Line number */
128 pp->line = strtoul(arg, &tmp, 0); 473 pp->line = strtoul(arg, &tmp, 0);
129 if (*tmp != '\0') 474 if (*tmp != '\0') {
130 semantic_error("There is non-digit charactor" 475 semantic_error("There is non-digit char"
131 " in line number."); 476 " in line number.\n");
477 return -EINVAL;
478 }
132 break; 479 break;
133 case '+': /* Byte offset from a symbol */ 480 case '+': /* Byte offset from a symbol */
134 pp->offset = strtoul(arg, &tmp, 0); 481 pp->offset = strtoul(arg, &tmp, 0);
135 if (*tmp != '\0') 482 if (*tmp != '\0') {
136 semantic_error("There is non-digit charactor" 483 semantic_error("There is non-digit character"
137 " in offset."); 484 " in offset.\n");
485 return -EINVAL;
486 }
138 break; 487 break;
139 case '@': /* File name */ 488 case '@': /* File name */
140 if (pp->file) 489 if (pp->file) {
141 semantic_error("SRC@SRC is not allowed."); 490 semantic_error("SRC@SRC is not allowed.\n");
491 return -EINVAL;
492 }
142 pp->file = strdup(arg); 493 pp->file = strdup(arg);
143 DIE_IF(pp->file == NULL); 494 if (pp->file == NULL)
144 if (ptr) 495 return -ENOMEM;
145 semantic_error("@SRC must be the last "
146 "option.");
147 break; 496 break;
148 case '%': /* Probe places */ 497 case '%': /* Probe places */
149 if (strcmp(arg, "return") == 0) { 498 if (strcmp(arg, "return") == 0) {
150 pp->retprobe = 1; 499 pp->retprobe = 1;
151 } else /* Others not supported yet */ 500 } else { /* Others not supported yet */
152 semantic_error("%%%s is not supported.", arg); 501 semantic_error("%%%s is not supported.\n", arg);
502 return -ENOTSUP;
503 }
153 break; 504 break;
154 default: 505 default: /* Buggy case */
155 DIE_IF("Program has a bug."); 506 pr_err("This program has a bug at %s:%d.\n",
507 __FILE__, __LINE__);
508 return -ENOTSUP;
156 break; 509 break;
157 } 510 }
158 } 511 }
159 512
160 /* Exclusion check */ 513 /* Exclusion check */
161 if (pp->line && pp->offset) 514 if (pp->lazy_line && pp->line) {
515 semantic_error("Lazy pattern can't be used with line number.");
516 return -EINVAL;
517 }
518
519 if (pp->lazy_line && pp->offset) {
520 semantic_error("Lazy pattern can't be used with offset.");
521 return -EINVAL;
522 }
523
524 if (pp->line && pp->offset) {
162 semantic_error("Offset can't be used with line number."); 525 semantic_error("Offset can't be used with line number.");
526 return -EINVAL;
527 }
163 528
164 if (!pp->line && pp->file && !pp->function) 529 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
165 semantic_error("File always requires line number."); 530 semantic_error("File always requires line number or "
531 "lazy pattern.");
532 return -EINVAL;
533 }
166 534
167 if (pp->offset && !pp->function) 535 if (pp->offset && !pp->function) {
168 semantic_error("Offset requires an entry function."); 536 semantic_error("Offset requires an entry function.");
537 return -EINVAL;
538 }
169 539
170 if (pp->retprobe && !pp->function) 540 if (pp->retprobe && !pp->function) {
171 semantic_error("Return probe requires an entry function."); 541 semantic_error("Return probe requires an entry function.");
542 return -EINVAL;
543 }
172 544
173 if ((pp->offset || pp->line) && pp->retprobe) 545 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
174 semantic_error("Offset/Line can't be used with return probe."); 546 semantic_error("Offset/Line/Lazy pattern can't be used with "
547 "return probe.");
548 return -EINVAL;
549 }
175 550
176 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 551 pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
177 pp->function, pp->file, pp->line, pp->offset, pp->retprobe); 552 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
553 pp->lazy_line);
554 return 0;
178} 555}
179 556
180/* Parse perf-probe event definition */ 557/* Parse perf-probe event argument */
181void parse_perf_probe_event(const char *str, struct probe_point *pp, 558static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
182 bool *need_dwarf)
183{ 559{
184 char **argv; 560 char *tmp;
185 int argc, i; 561 struct perf_probe_arg_field **fieldp;
562
563 pr_debug("parsing arg: %s into ", str);
564
565 tmp = strchr(str, '=');
566 if (tmp) {
567 arg->name = strndup(str, tmp - str);
568 if (arg->name == NULL)
569 return -ENOMEM;
570 pr_debug("name:%s ", arg->name);
571 str = tmp + 1;
572 }
573
574 tmp = strchr(str, ':');
575 if (tmp) { /* Type setting */
576 *tmp = '\0';
577 arg->type = strdup(tmp + 1);
578 if (arg->type == NULL)
579 return -ENOMEM;
580 pr_debug("type:%s ", arg->type);
581 }
582
583 tmp = strpbrk(str, "-.");
584 if (!is_c_varname(str) || !tmp) {
585 /* A variable, register, symbol or special value */
586 arg->var = strdup(str);
587 if (arg->var == NULL)
588 return -ENOMEM;
589 pr_debug("%s\n", arg->var);
590 return 0;
591 }
592
593 /* Structure fields */
594 arg->var = strndup(str, tmp - str);
595 if (arg->var == NULL)
596 return -ENOMEM;
597 pr_debug("%s, ", arg->var);
598 fieldp = &arg->field;
599
600 do {
601 *fieldp = zalloc(sizeof(struct perf_probe_arg_field));
602 if (*fieldp == NULL)
603 return -ENOMEM;
604 if (*tmp == '.') {
605 str = tmp + 1;
606 (*fieldp)->ref = false;
607 } else if (tmp[1] == '>') {
608 str = tmp + 2;
609 (*fieldp)->ref = true;
610 } else {
611 semantic_error("Argument parse error: %s\n", str);
612 return -EINVAL;
613 }
186 614
187 *need_dwarf = false; 615 tmp = strpbrk(str, "-.");
616 if (tmp) {
617 (*fieldp)->name = strndup(str, tmp - str);
618 if ((*fieldp)->name == NULL)
619 return -ENOMEM;
620 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
621 fieldp = &(*fieldp)->next;
622 }
623 } while (tmp);
624 (*fieldp)->name = strdup(str);
625 if ((*fieldp)->name == NULL)
626 return -ENOMEM;
627 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
628
629 /* If no name is specified, set the last field name */
630 if (!arg->name) {
631 arg->name = strdup((*fieldp)->name);
632 if (arg->name == NULL)
633 return -ENOMEM;
634 }
635 return 0;
636}
188 637
189 argv = argv_split(str, &argc); 638/* Parse perf-probe event command */
190 if (!argv) 639int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
191 die("argv_split failed."); 640{
192 if (argc > MAX_PROBE_ARGS + 1) 641 char **argv;
193 semantic_error("Too many arguments"); 642 int argc, i, ret = 0;
194 643
644 argv = argv_split(cmd, &argc);
645 if (!argv) {
646 pr_debug("Failed to split arguments.\n");
647 return -ENOMEM;
648 }
649 if (argc - 1 > MAX_PROBE_ARGS) {
650 semantic_error("Too many probe arguments (%d).\n", argc - 1);
651 ret = -ERANGE;
652 goto out;
653 }
195 /* Parse probe point */ 654 /* Parse probe point */
196 parse_perf_probe_probepoint(argv[0], pp); 655 ret = parse_perf_probe_point(argv[0], pev);
197 if (pp->file || pp->line) 656 if (ret < 0)
198 *need_dwarf = true; 657 goto out;
199 658
200 /* Copy arguments and ensure return probe has no C argument */ 659 /* Copy arguments and ensure return probe has no C argument */
201 pp->nr_args = argc - 1; 660 pev->nargs = argc - 1;
202 pp->args = zalloc(sizeof(char *) * pp->nr_args); 661 pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
203 for (i = 0; i < pp->nr_args; i++) { 662 if (pev->args == NULL) {
204 pp->args[i] = strdup(argv[i + 1]); 663 ret = -ENOMEM;
205 if (!pp->args[i]) 664 goto out;
206 die("Failed to copy argument."); 665 }
207 if (is_c_varname(pp->args[i])) { 666 for (i = 0; i < pev->nargs && ret >= 0; i++) {
208 if (pp->retprobe) 667 ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
209 semantic_error("You can't specify local" 668 if (ret >= 0 &&
210 " variable for kretprobe"); 669 is_c_varname(pev->args[i].var) && pev->point.retprobe) {
211 *need_dwarf = true; 670 semantic_error("You can't specify local variable for"
671 " kretprobe.\n");
672 ret = -EINVAL;
212 } 673 }
213 } 674 }
214 675out:
215 argv_free(argv); 676 argv_free(argv);
677
678 return ret;
679}
680
681/* Return true if this perf_probe_event requires debuginfo */
682bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
683{
684 int i;
685
686 if (pev->point.file || pev->point.line || pev->point.lazy_line)
687 return true;
688
689 for (i = 0; i < pev->nargs; i++)
690 if (is_c_varname(pev->args[i].var))
691 return true;
692
693 return false;
216} 694}
217 695
218/* Parse kprobe_events event into struct probe_point */ 696/* Parse kprobe_events event into struct probe_point */
219void parse_trace_kprobe_event(const char *str, struct probe_point *pp) 697int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
220{ 698{
699 struct kprobe_trace_point *tp = &tev->point;
221 char pr; 700 char pr;
222 char *p; 701 char *p;
223 int ret, i, argc; 702 int ret, i, argc;
224 char **argv; 703 char **argv;
225 704
226 pr_debug("Parsing kprobe_events: %s\n", str); 705 pr_debug("Parsing kprobe_events: %s\n", cmd);
227 argv = argv_split(str, &argc); 706 argv = argv_split(cmd, &argc);
228 if (!argv) 707 if (!argv) {
229 die("argv_split failed."); 708 pr_debug("Failed to split arguments.\n");
230 if (argc < 2) 709 return -ENOMEM;
231 semantic_error("Too less arguments."); 710 }
711 if (argc < 2) {
712 semantic_error("Too few probe arguments.\n");
713 ret = -ERANGE;
714 goto out;
715 }
232 716
233 /* Scan event and group name. */ 717 /* Scan event and group name. */
234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 718 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
235 &pr, (float *)(void *)&pp->group, 719 &pr, (float *)(void *)&tev->group,
236 (float *)(void *)&pp->event); 720 (float *)(void *)&tev->event);
237 if (ret != 3) 721 if (ret != 3) {
238 semantic_error("Failed to parse event name: %s", argv[0]); 722 semantic_error("Failed to parse event name: %s\n", argv[0]);
239 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); 723 ret = -EINVAL;
724 goto out;
725 }
726 pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
240 727
241 pp->retprobe = (pr == 'r'); 728 tp->retprobe = (pr == 'r');
242 729
243 /* Scan function name and offset */ 730 /* Scan function name and offset */
244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, 731 ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
245 &pp->offset); 732 &tp->offset);
246 if (ret == 1) 733 if (ret == 1)
247 pp->offset = 0; 734 tp->offset = 0;
248
249 /* kprobe_events doesn't have this information */
250 pp->line = 0;
251 pp->file = NULL;
252 735
253 pp->nr_args = argc - 2; 736 tev->nargs = argc - 2;
254 pp->args = zalloc(sizeof(char *) * pp->nr_args); 737 tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
255 for (i = 0; i < pp->nr_args; i++) { 738 if (tev->args == NULL) {
739 ret = -ENOMEM;
740 goto out;
741 }
742 for (i = 0; i < tev->nargs; i++) {
256 p = strchr(argv[i + 2], '='); 743 p = strchr(argv[i + 2], '=');
257 if (p) /* We don't need which register is assigned. */ 744 if (p) /* We don't need which register is assigned. */
258 *p = '\0'; 745 *p++ = '\0';
259 pp->args[i] = strdup(argv[i + 2]); 746 else
260 if (!pp->args[i]) 747 p = argv[i + 2];
261 die("Failed to copy argument."); 748 tev->args[i].name = strdup(argv[i + 2]);
749 /* TODO: parse regs and offset */
750 tev->args[i].value = strdup(p);
751 if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
752 ret = -ENOMEM;
753 goto out;
754 }
262 } 755 }
263 756 ret = 0;
757out:
264 argv_free(argv); 758 argv_free(argv);
759 return ret;
265} 760}
266 761
267/* Synthesize only probe point (not argument) */ 762/* Compose only probe arg */
268int synthesize_perf_probe_point(struct probe_point *pp) 763int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
269{ 764{
270 char *buf; 765 struct perf_probe_arg_field *field = pa->field;
271 char offs[64] = "", line[64] = "";
272 int ret; 766 int ret;
767 char *tmp = buf;
273 768
274 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 769 if (pa->name && pa->var)
275 if (!buf) 770 ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
276 die("Failed to allocate memory by zalloc."); 771 else
772 ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
773 if (ret <= 0)
774 goto error;
775 tmp += ret;
776 len -= ret;
777
778 while (field) {
779 ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
780 field->name);
781 if (ret <= 0)
782 goto error;
783 tmp += ret;
784 len -= ret;
785 field = field->next;
786 }
787
788 if (pa->type) {
789 ret = e_snprintf(tmp, len, ":%s", pa->type);
790 if (ret <= 0)
791 goto error;
792 tmp += ret;
793 len -= ret;
794 }
795
796 return tmp - buf;
797error:
798 pr_debug("Failed to synthesize perf probe argument: %s",
799 strerror(-ret));
800 return ret;
801}
802
803/* Compose only probe point (not argument) */
804static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
805{
806 char *buf, *tmp;
807 char offs[32] = "", line[32] = "", file[32] = "";
808 int ret, len;
809
810 buf = zalloc(MAX_CMDLEN);
811 if (buf == NULL) {
812 ret = -ENOMEM;
813 goto error;
814 }
277 if (pp->offset) { 815 if (pp->offset) {
278 ret = e_snprintf(offs, 64, "+%d", pp->offset); 816 ret = e_snprintf(offs, 32, "+%lu", pp->offset);
279 if (ret <= 0) 817 if (ret <= 0)
280 goto error; 818 goto error;
281 } 819 }
282 if (pp->line) { 820 if (pp->line) {
283 ret = e_snprintf(line, 64, ":%d", pp->line); 821 ret = e_snprintf(line, 32, ":%d", pp->line);
822 if (ret <= 0)
823 goto error;
824 }
825 if (pp->file) {
826 len = strlen(pp->file) - 31;
827 if (len < 0)
828 len = 0;
829 tmp = strchr(pp->file + len, '/');
830 if (!tmp)
831 tmp = pp->file + len;
832 ret = e_snprintf(file, 32, "@%s", tmp + 1);
284 if (ret <= 0) 833 if (ret <= 0)
285 goto error; 834 goto error;
286 } 835 }
287 836
288 if (pp->function) 837 if (pp->function)
289 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 838 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
290 offs, pp->retprobe ? "%return" : "", line); 839 offs, pp->retprobe ? "%return" : "", line,
840 file);
291 else 841 else
292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 842 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
293 if (ret <= 0) { 843 if (ret <= 0)
844 goto error;
845
846 return buf;
294error: 847error:
295 free(pp->probes[0]); 848 pr_debug("Failed to synthesize perf probe point: %s",
296 pp->probes[0] = NULL; 849 strerror(-ret));
297 } 850 if (buf)
298 return ret; 851 free(buf);
852 return NULL;
299} 853}
300 854
301int synthesize_perf_probe_event(struct probe_point *pp) 855#if 0
856char *synthesize_perf_probe_command(struct perf_probe_event *pev)
302{ 857{
303 char *buf; 858 char *buf;
304 int i, len, ret; 859 int i, len, ret;
305 860
306 len = synthesize_perf_probe_point(pp); 861 buf = synthesize_perf_probe_point(&pev->point);
307 if (len < 0) 862 if (!buf)
308 return 0; 863 return NULL;
309 864
310 buf = pp->probes[0]; 865 len = strlen(buf);
311 for (i = 0; i < pp->nr_args; i++) { 866 for (i = 0; i < pev->nargs; i++) {
312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 867 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
313 pp->args[i]); 868 pev->args[i].name);
314 if (ret <= 0) 869 if (ret <= 0) {
315 goto error; 870 free(buf);
871 return NULL;
872 }
316 len += ret; 873 len += ret;
317 } 874 }
318 pp->found = 1;
319 875
320 return pp->found; 876 return buf;
321error: 877}
322 free(pp->probes[0]); 878#endif
323 pp->probes[0] = NULL; 879
880static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
881 char **buf, size_t *buflen,
882 int depth)
883{
884 int ret;
885 if (ref->next) {
886 depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf,
887 buflen, depth + 1);
888 if (depth < 0)
889 goto out;
890 }
891
892 ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
893 if (ret < 0)
894 depth = ret;
895 else {
896 *buf += ret;
897 *buflen -= ret;
898 }
899out:
900 return depth;
324 901
325 return ret;
326} 902}
327 903
328int synthesize_trace_kprobe_event(struct probe_point *pp) 904static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
905 char *buf, size_t buflen)
329{ 906{
907 int ret, depth = 0;
908 char *tmp = buf;
909
910 /* Argument name or separator */
911 if (arg->name)
912 ret = e_snprintf(buf, buflen, " %s=", arg->name);
913 else
914 ret = e_snprintf(buf, buflen, " ");
915 if (ret < 0)
916 return ret;
917 buf += ret;
918 buflen -= ret;
919
920 /* Dereferencing arguments */
921 if (arg->ref) {
922 depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
923 &buflen, 1);
924 if (depth < 0)
925 return depth;
926 }
927
928 /* Print argument value */
929 ret = e_snprintf(buf, buflen, "%s", arg->value);
930 if (ret < 0)
931 return ret;
932 buf += ret;
933 buflen -= ret;
934
935 /* Closing */
936 while (depth--) {
937 ret = e_snprintf(buf, buflen, ")");
938 if (ret < 0)
939 return ret;
940 buf += ret;
941 buflen -= ret;
942 }
943 /* Print argument type */
944 if (arg->type) {
945 ret = e_snprintf(buf, buflen, ":%s", arg->type);
946 if (ret <= 0)
947 return ret;
948 buf += ret;
949 }
950
951 return buf - tmp;
952}
953
954char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
955{
956 struct kprobe_trace_point *tp = &tev->point;
330 char *buf; 957 char *buf;
331 int i, len, ret; 958 int i, len, ret;
332 959
333 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 960 buf = zalloc(MAX_CMDLEN);
334 if (!buf) 961 if (buf == NULL)
335 die("Failed to allocate memory by zalloc."); 962 return NULL;
336 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 963
337 if (ret <= 0) 964 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
965 tp->retprobe ? 'r' : 'p',
966 tev->group, tev->event,
967 tp->symbol, tp->offset);
968 if (len <= 0)
338 goto error; 969 goto error;
339 len = ret;
340 970
341 for (i = 0; i < pp->nr_args; i++) { 971 for (i = 0; i < tev->nargs; i++) {
342 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 972 ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len,
343 pp->args[i]); 973 MAX_CMDLEN - len);
344 if (ret <= 0) 974 if (ret <= 0)
345 goto error; 975 goto error;
346 len += ret; 976 len += ret;
347 } 977 }
348 pp->found = 1;
349 978
350 return pp->found; 979 return buf;
351error: 980error:
352 free(pp->probes[0]); 981 free(buf);
353 pp->probes[0] = NULL; 982 return NULL;
983}
984
985int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
986 struct perf_probe_event *pev)
987{
988 char buf[64] = "";
989 int i, ret;
990
991 /* Convert event/group name */
992 pev->event = strdup(tev->event);
993 pev->group = strdup(tev->group);
994 if (pev->event == NULL || pev->group == NULL)
995 return -ENOMEM;
996
997 /* Convert trace_point to probe_point */
998 ret = convert_to_perf_probe_point(&tev->point, &pev->point);
999 if (ret < 0)
1000 return ret;
1001
1002 /* Convert trace_arg to probe_arg */
1003 pev->nargs = tev->nargs;
1004 pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1005 if (pev->args == NULL)
1006 return -ENOMEM;
1007 for (i = 0; i < tev->nargs && ret >= 0; i++) {
1008 if (tev->args[i].name)
1009 pev->args[i].name = strdup(tev->args[i].name);
1010 else {
1011 ret = synthesize_kprobe_trace_arg(&tev->args[i],
1012 buf, 64);
1013 pev->args[i].name = strdup(buf);
1014 }
1015 if (pev->args[i].name == NULL && ret >= 0)
1016 ret = -ENOMEM;
1017 }
1018
1019 if (ret < 0)
1020 clear_perf_probe_event(pev);
354 1021
355 return ret; 1022 return ret;
356} 1023}
357 1024
358static int open_kprobe_events(int flags, int mode) 1025void clear_perf_probe_event(struct perf_probe_event *pev)
1026{
1027 struct perf_probe_point *pp = &pev->point;
1028 struct perf_probe_arg_field *field, *next;
1029 int i;
1030
1031 if (pev->event)
1032 free(pev->event);
1033 if (pev->group)
1034 free(pev->group);
1035 if (pp->file)
1036 free(pp->file);
1037 if (pp->function)
1038 free(pp->function);
1039 if (pp->lazy_line)
1040 free(pp->lazy_line);
1041 for (i = 0; i < pev->nargs; i++) {
1042 if (pev->args[i].name)
1043 free(pev->args[i].name);
1044 if (pev->args[i].var)
1045 free(pev->args[i].var);
1046 if (pev->args[i].type)
1047 free(pev->args[i].type);
1048 field = pev->args[i].field;
1049 while (field) {
1050 next = field->next;
1051 if (field->name)
1052 free(field->name);
1053 free(field);
1054 field = next;
1055 }
1056 }
1057 if (pev->args)
1058 free(pev->args);
1059 memset(pev, 0, sizeof(*pev));
1060}
1061
1062void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
1063{
1064 struct kprobe_trace_arg_ref *ref, *next;
1065 int i;
1066
1067 if (tev->event)
1068 free(tev->event);
1069 if (tev->group)
1070 free(tev->group);
1071 if (tev->point.symbol)
1072 free(tev->point.symbol);
1073 for (i = 0; i < tev->nargs; i++) {
1074 if (tev->args[i].name)
1075 free(tev->args[i].name);
1076 if (tev->args[i].value)
1077 free(tev->args[i].value);
1078 if (tev->args[i].type)
1079 free(tev->args[i].type);
1080 ref = tev->args[i].ref;
1081 while (ref) {
1082 next = ref->next;
1083 free(ref);
1084 ref = next;
1085 }
1086 }
1087 if (tev->args)
1088 free(tev->args);
1089 memset(tev, 0, sizeof(*tev));
1090}
1091
1092static int open_kprobe_events(bool readwrite)
359{ 1093{
360 char buf[PATH_MAX]; 1094 char buf[PATH_MAX];
1095 const char *__debugfs;
361 int ret; 1096 int ret;
362 1097
363 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); 1098 __debugfs = debugfs_find_mountpoint();
364 if (ret < 0) 1099 if (__debugfs == NULL) {
365 die("Failed to make kprobe_events path."); 1100 pr_warning("Debugfs is not mounted.\n");
1101 return -ENOENT;
1102 }
1103
1104 ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
1105 if (ret >= 0) {
1106 pr_debug("Opening %s write=%d\n", buf, readwrite);
1107 if (readwrite && !probe_event_dry_run)
1108 ret = open(buf, O_RDWR, O_APPEND);
1109 else
1110 ret = open(buf, O_RDONLY, 0);
1111 }
366 1112
367 ret = open(buf, flags, mode);
368 if (ret < 0) { 1113 if (ret < 0) {
369 if (errno == ENOENT) 1114 if (errno == ENOENT)
370 die("kprobe_events file does not exist -" 1115 pr_warning("kprobe_events file does not exist - please"
371 " please rebuild with CONFIG_KPROBE_TRACER."); 1116 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
372 else 1117 else
373 die("Could not open kprobe_events file: %s", 1118 pr_warning("Failed to open kprobe_events file: %s\n",
374 strerror(errno)); 1119 strerror(errno));
375 } 1120 }
376 return ret; 1121 return ret;
377} 1122}
378 1123
379/* Get raw string list of current kprobe_events */ 1124/* Get raw string list of current kprobe_events */
380static struct strlist *get_trace_kprobe_event_rawlist(int fd) 1125static struct strlist *get_kprobe_trace_command_rawlist(int fd)
381{ 1126{
382 int ret, idx; 1127 int ret, idx;
383 FILE *fp; 1128 FILE *fp;
@@ -397,266 +1142,486 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd)
397 if (p[idx] == '\n') 1142 if (p[idx] == '\n')
398 p[idx] = '\0'; 1143 p[idx] = '\0';
399 ret = strlist__add(sl, buf); 1144 ret = strlist__add(sl, buf);
400 if (ret < 0) 1145 if (ret < 0) {
401 die("strlist__add failed: %s", strerror(-ret)); 1146 pr_debug("strlist__add failed: %s\n", strerror(-ret));
1147 strlist__delete(sl);
1148 return NULL;
1149 }
402 } 1150 }
403 fclose(fp); 1151 fclose(fp);
404 1152
405 return sl; 1153 return sl;
406} 1154}
407 1155
408/* Free and zero clear probe_point */
409static void clear_probe_point(struct probe_point *pp)
410{
411 int i;
412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
417 if (pp->function)
418 free(pp->function);
419 if (pp->file)
420 free(pp->file);
421 for (i = 0; i < pp->nr_args; i++)
422 free(pp->args[i]);
423 if (pp->args)
424 free(pp->args);
425 for (i = 0; i < pp->found; i++)
426 free(pp->probes[i]);
427 memset(pp, 0, sizeof(*pp));
428}
429
430/* Show an event */ 1156/* Show an event */
431static void show_perf_probe_event(const char *event, const char *place, 1157static int show_perf_probe_event(struct perf_probe_event *pev)
432 struct probe_point *pp)
433{ 1158{
434 int i, ret; 1159 int i, ret;
435 char buf[128]; 1160 char buf[128];
1161 char *place;
1162
1163 /* Synthesize only event probe point */
1164 place = synthesize_perf_probe_point(&pev->point);
1165 if (!place)
1166 return -EINVAL;
436 1167
437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); 1168 ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
438 if (ret < 0) 1169 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret)); 1170 return ret;
440 printf(" %-40s (on %s", buf, place); 1171
1172 printf(" %-20s (on %s", buf, place);
441 1173
442 if (pp->nr_args > 0) { 1174 if (pev->nargs > 0) {
443 printf(" with"); 1175 printf(" with");
444 for (i = 0; i < pp->nr_args; i++) 1176 for (i = 0; i < pev->nargs; i++) {
445 printf(" %s", pp->args[i]); 1177 ret = synthesize_perf_probe_arg(&pev->args[i],
1178 buf, 128);
1179 if (ret < 0)
1180 break;
1181 printf(" %s", buf);
1182 }
446 } 1183 }
447 printf(")\n"); 1184 printf(")\n");
1185 free(place);
1186 return ret;
448} 1187}
449 1188
450/* List up current perf-probe events */ 1189/* List up current perf-probe events */
451void show_perf_probe_events(void) 1190int show_perf_probe_events(void)
452{ 1191{
453 int fd; 1192 int fd, ret;
454 struct probe_point pp; 1193 struct kprobe_trace_event tev;
1194 struct perf_probe_event pev;
455 struct strlist *rawlist; 1195 struct strlist *rawlist;
456 struct str_node *ent; 1196 struct str_node *ent;
457 1197
458 fd = open_kprobe_events(O_RDONLY, 0); 1198 setup_pager();
459 rawlist = get_trace_kprobe_event_rawlist(fd); 1199 ret = init_vmlinux();
1200 if (ret < 0)
1201 return ret;
1202
1203 memset(&tev, 0, sizeof(tev));
1204 memset(&pev, 0, sizeof(pev));
1205
1206 fd = open_kprobe_events(false);
1207 if (fd < 0)
1208 return fd;
1209
1210 rawlist = get_kprobe_trace_command_rawlist(fd);
460 close(fd); 1211 close(fd);
1212 if (!rawlist)
1213 return -ENOENT;
461 1214
462 strlist__for_each(ent, rawlist) { 1215 strlist__for_each(ent, rawlist) {
463 parse_trace_kprobe_event(ent->s, &pp); 1216 ret = parse_kprobe_trace_command(ent->s, &tev);
464 /* Synthesize only event probe point */ 1217 if (ret >= 0) {
465 synthesize_perf_probe_point(&pp); 1218 ret = convert_to_perf_probe_event(&tev, &pev);
466 /* Show an event */ 1219 if (ret >= 0)
467 show_perf_probe_event(pp.event, pp.probes[0], &pp); 1220 ret = show_perf_probe_event(&pev);
468 clear_probe_point(&pp); 1221 }
1222 clear_perf_probe_event(&pev);
1223 clear_kprobe_trace_event(&tev);
1224 if (ret < 0)
1225 break;
469 } 1226 }
470
471 strlist__delete(rawlist); 1227 strlist__delete(rawlist);
1228
1229 return ret;
472} 1230}
473 1231
474/* Get current perf-probe event names */ 1232/* Get current perf-probe event names */
475static struct strlist *get_perf_event_names(int fd, bool include_group) 1233static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
476{ 1234{
477 char buf[128]; 1235 char buf[128];
478 struct strlist *sl, *rawlist; 1236 struct strlist *sl, *rawlist;
479 struct str_node *ent; 1237 struct str_node *ent;
480 struct probe_point pp; 1238 struct kprobe_trace_event tev;
1239 int ret = 0;
481 1240
482 memset(&pp, 0, sizeof(pp)); 1241 memset(&tev, 0, sizeof(tev));
483 rawlist = get_trace_kprobe_event_rawlist(fd);
484 1242
1243 rawlist = get_kprobe_trace_command_rawlist(fd);
485 sl = strlist__new(true, NULL); 1244 sl = strlist__new(true, NULL);
486 strlist__for_each(ent, rawlist) { 1245 strlist__for_each(ent, rawlist) {
487 parse_trace_kprobe_event(ent->s, &pp); 1246 ret = parse_kprobe_trace_command(ent->s, &tev);
1247 if (ret < 0)
1248 break;
488 if (include_group) { 1249 if (include_group) {
489 if (e_snprintf(buf, 128, "%s:%s", pp.group, 1250 ret = e_snprintf(buf, 128, "%s:%s", tev.group,
490 pp.event) < 0) 1251 tev.event);
491 die("Failed to copy group:event name."); 1252 if (ret >= 0)
492 strlist__add(sl, buf); 1253 ret = strlist__add(sl, buf);
493 } else 1254 } else
494 strlist__add(sl, pp.event); 1255 ret = strlist__add(sl, tev.event);
495 clear_probe_point(&pp); 1256 clear_kprobe_trace_event(&tev);
1257 if (ret < 0)
1258 break;
496 } 1259 }
497
498 strlist__delete(rawlist); 1260 strlist__delete(rawlist);
499 1261
1262 if (ret < 0) {
1263 strlist__delete(sl);
1264 return NULL;
1265 }
500 return sl; 1266 return sl;
501} 1267}
502 1268
503static void write_trace_kprobe_event(int fd, const char *buf) 1269static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev)
504{ 1270{
505 int ret; 1271 int ret = 0;
1272 char *buf = synthesize_kprobe_trace_command(tev);
1273
1274 if (!buf) {
1275 pr_debug("Failed to synthesize kprobe trace event.\n");
1276 return -EINVAL;
1277 }
506 1278
507 pr_debug("Writing event: %s\n", buf); 1279 pr_debug("Writing event: %s\n", buf);
508 ret = write(fd, buf, strlen(buf)); 1280 if (!probe_event_dry_run) {
509 if (ret <= 0) 1281 ret = write(fd, buf, strlen(buf));
510 die("Failed to write event: %s", strerror(errno)); 1282 if (ret <= 0)
1283 pr_warning("Failed to write event: %s\n",
1284 strerror(errno));
1285 }
1286 free(buf);
1287 return ret;
511} 1288}
512 1289
513static void get_new_event_name(char *buf, size_t len, const char *base, 1290static int get_new_event_name(char *buf, size_t len, const char *base,
514 struct strlist *namelist, bool allow_suffix) 1291 struct strlist *namelist, bool allow_suffix)
515{ 1292{
516 int i, ret; 1293 int i, ret;
517 1294
518 /* Try no suffix */ 1295 /* Try no suffix */
519 ret = e_snprintf(buf, len, "%s", base); 1296 ret = e_snprintf(buf, len, "%s", base);
520 if (ret < 0) 1297 if (ret < 0) {
521 die("snprintf() failed: %s", strerror(-ret)); 1298 pr_debug("snprintf() failed: %s\n", strerror(-ret));
1299 return ret;
1300 }
522 if (!strlist__has_entry(namelist, buf)) 1301 if (!strlist__has_entry(namelist, buf))
523 return; 1302 return 0;
524 1303
525 if (!allow_suffix) { 1304 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. " 1305 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base); 1306 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event."); 1307 return -EEXIST;
529 } 1308 }
530 1309
531 /* Try to add suffix */ 1310 /* Try to add suffix */
532 for (i = 1; i < MAX_EVENT_INDEX; i++) { 1311 for (i = 1; i < MAX_EVENT_INDEX; i++) {
533 ret = e_snprintf(buf, len, "%s_%d", base, i); 1312 ret = e_snprintf(buf, len, "%s_%d", base, i);
534 if (ret < 0) 1313 if (ret < 0) {
535 die("snprintf() failed: %s", strerror(-ret)); 1314 pr_debug("snprintf() failed: %s\n", strerror(-ret));
1315 return ret;
1316 }
536 if (!strlist__has_entry(namelist, buf)) 1317 if (!strlist__has_entry(namelist, buf))
537 break; 1318 break;
538 } 1319 }
539 if (i == MAX_EVENT_INDEX) 1320 if (i == MAX_EVENT_INDEX) {
540 die("Too many events are on the same function."); 1321 pr_warning("Too many events are on the same function.\n");
1322 ret = -ERANGE;
1323 }
1324
1325 return ret;
541} 1326}
542 1327
543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 1328static int __add_kprobe_trace_events(struct perf_probe_event *pev,
544 bool force_add) 1329 struct kprobe_trace_event *tevs,
1330 int ntevs, bool allow_suffix)
545{ 1331{
546 int i, j, fd; 1332 int i, fd, ret;
547 struct probe_point *pp; 1333 struct kprobe_trace_event *tev = NULL;
548 char buf[MAX_CMDLEN]; 1334 char buf[64];
549 char event[64]; 1335 const char *event, *group;
550 struct strlist *namelist; 1336 struct strlist *namelist;
551 bool allow_suffix;
552 1337
553 fd = open_kprobe_events(O_RDWR, O_APPEND); 1338 fd = open_kprobe_events(true);
1339 if (fd < 0)
1340 return fd;
554 /* Get current event names */ 1341 /* Get current event names */
555 namelist = get_perf_event_names(fd, false); 1342 namelist = get_kprobe_trace_event_names(fd, false);
556 1343 if (!namelist) {
557 for (j = 0; j < nr_probes; j++) { 1344 pr_debug("Failed to get current event list.\n");
558 pp = probes + j; 1345 return -EIO;
559 if (!pp->event) 1346 }
560 pp->event = strdup(pp->function); 1347
561 if (!pp->group) 1348 ret = 0;
562 pp->group = strdup(PERFPROBE_GROUP); 1349 printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
563 DIE_IF(!pp->event || !pp->group); 1350 for (i = 0; i < ntevs; i++) {
564 /* If force_add is true, suffix search is allowed */ 1351 tev = &tevs[i];
565 allow_suffix = force_add; 1352 if (pev->event)
566 for (i = 0; i < pp->found; i++) { 1353 event = pev->event;
567 /* Get an unused new event name */ 1354 else
568 get_new_event_name(event, 64, pp->event, namelist, 1355 if (pev->point.function)
569 allow_suffix); 1356 event = pev->point.function;
570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 1357 else
571 pp->retprobe ? 'r' : 'p', 1358 event = tev->point.symbol;
572 pp->group, event, 1359 if (pev->group)
573 pp->probes[i]); 1360 group = pev->group;
574 write_trace_kprobe_event(fd, buf); 1361 else
575 printf("Added new event:\n"); 1362 group = PERFPROBE_GROUP;
576 /* Get the first parameter (probe-point) */ 1363
577 sscanf(pp->probes[i], "%s", buf); 1364 /* Get an unused new event name */
578 show_perf_probe_event(event, buf, pp); 1365 ret = get_new_event_name(buf, 64, event,
579 /* Add added event name to namelist */ 1366 namelist, allow_suffix);
580 strlist__add(namelist, event); 1367 if (ret < 0)
581 /* 1368 break;
582 * Probes after the first probe which comes from same 1369 event = buf;
583 * user input are always allowed to add suffix, because 1370
584 * there might be several addresses corresponding to 1371 tev->event = strdup(event);
585 * one code line. 1372 tev->group = strdup(group);
586 */ 1373 if (tev->event == NULL || tev->group == NULL) {
587 allow_suffix = true; 1374 ret = -ENOMEM;
1375 break;
588 } 1376 }
1377 ret = write_kprobe_trace_event(fd, tev);
1378 if (ret < 0)
1379 break;
1380 /* Add added event name to namelist */
1381 strlist__add(namelist, event);
1382
1383 /* Trick here - save current event/group */
1384 event = pev->event;
1385 group = pev->group;
1386 pev->event = tev->event;
1387 pev->group = tev->group;
1388 show_perf_probe_event(pev);
1389 /* Trick here - restore current event/group */
1390 pev->event = (char *)event;
1391 pev->group = (char *)group;
1392
1393 /*
1394 * Probes after the first probe which comes from same
1395 * user input are always allowed to add suffix, because
1396 * there might be several addresses corresponding to
1397 * one code line.
1398 */
1399 allow_suffix = true;
1400 }
1401
1402 if (ret >= 0) {
1403 /* Show how to use the event. */
1404 printf("\nYou can now use it on all perf tools, such as:\n\n");
1405 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1406 tev->event);
589 } 1407 }
590 /* Show how to use the event. */
591 printf("\nYou can now use it on all perf tools, such as:\n\n");
592 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
593 1408
594 strlist__delete(namelist); 1409 strlist__delete(namelist);
595 close(fd); 1410 close(fd);
1411 return ret;
596} 1412}
597 1413
598static void __del_trace_kprobe_event(int fd, struct str_node *ent) 1414static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
1415 struct kprobe_trace_event **tevs,
1416 int max_tevs)
1417{
1418 struct symbol *sym;
1419 int ret = 0, i;
1420 struct kprobe_trace_event *tev;
1421
1422 /* Convert perf_probe_event with debuginfo */
1423 ret = try_to_find_kprobe_trace_events(pev, tevs, max_tevs);
1424 if (ret != 0)
1425 return ret;
1426
1427 /* Allocate trace event buffer */
1428 tev = *tevs = zalloc(sizeof(struct kprobe_trace_event));
1429 if (tev == NULL)
1430 return -ENOMEM;
1431
1432 /* Copy parameters */
1433 tev->point.symbol = strdup(pev->point.function);
1434 if (tev->point.symbol == NULL) {
1435 ret = -ENOMEM;
1436 goto error;
1437 }
1438 tev->point.offset = pev->point.offset;
1439 tev->nargs = pev->nargs;
1440 if (tev->nargs) {
1441 tev->args = zalloc(sizeof(struct kprobe_trace_arg)
1442 * tev->nargs);
1443 if (tev->args == NULL) {
1444 ret = -ENOMEM;
1445 goto error;
1446 }
1447 for (i = 0; i < tev->nargs; i++) {
1448 if (pev->args[i].name) {
1449 tev->args[i].name = strdup(pev->args[i].name);
1450 if (tev->args[i].name == NULL) {
1451 ret = -ENOMEM;
1452 goto error;
1453 }
1454 }
1455 tev->args[i].value = strdup(pev->args[i].var);
1456 if (tev->args[i].value == NULL) {
1457 ret = -ENOMEM;
1458 goto error;
1459 }
1460 if (pev->args[i].type) {
1461 tev->args[i].type = strdup(pev->args[i].type);
1462 if (tev->args[i].type == NULL) {
1463 ret = -ENOMEM;
1464 goto error;
1465 }
1466 }
1467 }
1468 }
1469
1470 /* Currently just checking function name from symbol map */
1471 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
1472 tev->point.symbol, NULL);
1473 if (!sym) {
1474 pr_warning("Kernel symbol \'%s\' not found.\n",
1475 tev->point.symbol);
1476 ret = -ENOENT;
1477 goto error;
1478 }
1479
1480 return 1;
1481error:
1482 clear_kprobe_trace_event(tev);
1483 free(tev);
1484 *tevs = NULL;
1485 return ret;
1486}
1487
1488struct __event_package {
1489 struct perf_probe_event *pev;
1490 struct kprobe_trace_event *tevs;
1491 int ntevs;
1492};
1493
1494int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1495 bool force_add, int max_tevs)
1496{
1497 int i, j, ret;
1498 struct __event_package *pkgs;
1499
1500 pkgs = zalloc(sizeof(struct __event_package) * npevs);
1501 if (pkgs == NULL)
1502 return -ENOMEM;
1503
1504 /* Init vmlinux path */
1505 ret = init_vmlinux();
1506 if (ret < 0)
1507 return ret;
1508
1509 /* Loop 1: convert all events */
1510 for (i = 0; i < npevs; i++) {
1511 pkgs[i].pev = &pevs[i];
1512 /* Convert with or without debuginfo */
1513 ret = convert_to_kprobe_trace_events(pkgs[i].pev,
1514 &pkgs[i].tevs, max_tevs);
1515 if (ret < 0)
1516 goto end;
1517 pkgs[i].ntevs = ret;
1518 }
1519
1520 /* Loop 2: add all events */
1521 for (i = 0; i < npevs && ret >= 0; i++)
1522 ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1523 pkgs[i].ntevs, force_add);
1524end:
1525 /* Loop 3: cleanup trace events */
1526 for (i = 0; i < npevs; i++)
1527 for (j = 0; j < pkgs[i].ntevs; j++)
1528 clear_kprobe_trace_event(&pkgs[i].tevs[j]);
1529
1530 return ret;
1531}
1532
1533static int __del_trace_kprobe_event(int fd, struct str_node *ent)
599{ 1534{
600 char *p; 1535 char *p;
601 char buf[128]; 1536 char buf[128];
1537 int ret;
602 1538
603 /* Convert from perf-probe event to trace-kprobe event */ 1539 /* Convert from perf-probe event to trace-kprobe event */
604 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) 1540 ret = e_snprintf(buf, 128, "-:%s", ent->s);
605 die("Failed to copy event."); 1541 if (ret < 0)
1542 goto error;
1543
606 p = strchr(buf + 2, ':'); 1544 p = strchr(buf + 2, ':');
607 if (!p) 1545 if (!p) {
608 die("Internal error: %s should have ':' but not.", ent->s); 1546 pr_debug("Internal error: %s should have ':' but not.\n",
1547 ent->s);
1548 ret = -ENOTSUP;
1549 goto error;
1550 }
609 *p = '/'; 1551 *p = '/';
610 1552
611 write_trace_kprobe_event(fd, buf); 1553 pr_debug("Writing event: %s\n", buf);
1554 ret = write(fd, buf, strlen(buf));
1555 if (ret < 0)
1556 goto error;
1557
612 printf("Remove event: %s\n", ent->s); 1558 printf("Remove event: %s\n", ent->s);
1559 return 0;
1560error:
1561 pr_warning("Failed to delete event: %s\n", strerror(-ret));
1562 return ret;
613} 1563}
614 1564
615static void del_trace_kprobe_event(int fd, const char *group, 1565static int del_trace_kprobe_event(int fd, const char *group,
616 const char *event, struct strlist *namelist) 1566 const char *event, struct strlist *namelist)
617{ 1567{
618 char buf[128]; 1568 char buf[128];
619 struct str_node *ent, *n; 1569 struct str_node *ent, *n;
620 int found = 0; 1570 int found = 0, ret = 0;
621 1571
622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 1572 ret = e_snprintf(buf, 128, "%s:%s", group, event);
623 die("Failed to copy event."); 1573 if (ret < 0) {
1574 pr_err("Failed to copy event.");
1575 return ret;
1576 }
624 1577
625 if (strpbrk(buf, "*?")) { /* Glob-exp */ 1578 if (strpbrk(buf, "*?")) { /* Glob-exp */
626 strlist__for_each_safe(ent, n, namelist) 1579 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) { 1580 if (strglobmatch(ent->s, buf)) {
628 found++; 1581 found++;
629 __del_trace_kprobe_event(fd, ent); 1582 ret = __del_trace_kprobe_event(fd, ent);
1583 if (ret < 0)
1584 break;
630 strlist__remove(namelist, ent); 1585 strlist__remove(namelist, ent);
631 } 1586 }
632 } else { 1587 } else {
633 ent = strlist__find(namelist, buf); 1588 ent = strlist__find(namelist, buf);
634 if (ent) { 1589 if (ent) {
635 found++; 1590 found++;
636 __del_trace_kprobe_event(fd, ent); 1591 ret = __del_trace_kprobe_event(fd, ent);
637 strlist__remove(namelist, ent); 1592 if (ret >= 0)
1593 strlist__remove(namelist, ent);
638 } 1594 }
639 } 1595 }
640 if (found == 0) 1596 if (found == 0 && ret >= 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); 1597 pr_info("Info: Event \"%s\" does not exist.\n", buf);
1598
1599 return ret;
642} 1600}
643 1601
644void del_trace_kprobe_events(struct strlist *dellist) 1602int del_perf_probe_events(struct strlist *dellist)
645{ 1603{
646 int fd; 1604 int fd, ret = 0;
647 const char *group, *event; 1605 const char *group, *event;
648 char *p, *str; 1606 char *p, *str;
649 struct str_node *ent; 1607 struct str_node *ent;
650 struct strlist *namelist; 1608 struct strlist *namelist;
651 1609
652 fd = open_kprobe_events(O_RDWR, O_APPEND); 1610 fd = open_kprobe_events(true);
1611 if (fd < 0)
1612 return fd;
1613
653 /* Get current event names */ 1614 /* Get current event names */
654 namelist = get_perf_event_names(fd, true); 1615 namelist = get_kprobe_trace_event_names(fd, true);
1616 if (namelist == NULL)
1617 return -EINVAL;
655 1618
656 strlist__for_each(ent, dellist) { 1619 strlist__for_each(ent, dellist) {
657 str = strdup(ent->s); 1620 str = strdup(ent->s);
658 if (!str) 1621 if (str == NULL) {
659 die("Failed to copy event."); 1622 ret = -ENOMEM;
1623 break;
1624 }
660 pr_debug("Parsing: %s\n", str); 1625 pr_debug("Parsing: %s\n", str);
661 p = strchr(str, ':'); 1626 p = strchr(str, ':');
662 if (p) { 1627 if (p) {
@@ -668,10 +1633,14 @@ void del_trace_kprobe_events(struct strlist *dellist)
668 event = str; 1633 event = str;
669 } 1634 }
670 pr_debug("Group: %s, Event: %s\n", group, event); 1635 pr_debug("Group: %s, Event: %s\n", group, event);
671 del_trace_kprobe_event(fd, group, event, namelist); 1636 ret = del_trace_kprobe_event(fd, group, event, namelist);
672 free(str); 1637 free(str);
1638 if (ret < 0)
1639 break;
673 } 1640 }
674 strlist__delete(namelist); 1641 strlist__delete(namelist);
675 close(fd); 1642 close(fd);
1643
1644 return ret;
676} 1645}
677 1646
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 7f1d499118c0..e9db1a214ca4 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,19 +2,125 @@
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_perf_probe_event(const char *str, struct probe_point *pp, 7extern bool probe_event_dry_run;
9 bool *need_dwarf); 8
10extern int synthesize_perf_probe_point(struct probe_point *pp); 9/* kprobe-tracer tracing point */
11extern int synthesize_perf_probe_event(struct probe_point *pp); 10struct kprobe_trace_point {
12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp); 11 char *symbol; /* Base symbol */
13extern int synthesize_trace_kprobe_event(struct probe_point *pp); 12 unsigned long offset; /* Offset from symbol */
14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 13 bool retprobe; /* Return probe flag */
15 bool force_add); 14};
16extern void del_trace_kprobe_events(struct strlist *dellist); 15
17extern void show_perf_probe_events(void); 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 char *type; /* Type name */
27 struct kprobe_trace_arg_ref *ref; /* Referencing offset */
28};
29
30/* kprobe-tracer tracing event (point + arg) */
31struct kprobe_trace_event {
32 char *event; /* Event name */
33 char *group; /* Group name */
34 struct kprobe_trace_point point; /* Trace point */
35 int nargs; /* Number of args */
36 struct kprobe_trace_arg *args; /* Arguments */
37};
38
39/* Perf probe probing point */
40struct perf_probe_point {
41 char *file; /* File path */
42 char *function; /* Function name */
43 int line; /* Line number */
44 bool retprobe; /* Return probe flag */
45 char *lazy_line; /* Lazy matching pattern */
46 unsigned long offset; /* Offset from function entry */
47};
48
49/* Perf probe probing argument field chain */
50struct perf_probe_arg_field {
51 struct perf_probe_arg_field *next; /* Next field */
52 char *name; /* Name of the field */
53 bool ref; /* Referencing flag */
54};
55
56/* Perf probe probing argument */
57struct perf_probe_arg {
58 char *name; /* Argument name */
59 char *var; /* Variable name */
60 char *type; /* Type name */
61 struct perf_probe_arg_field *field; /* Structure fields */
62};
63
64/* Perf probe probing event (point + arg) */
65struct perf_probe_event {
66 char *event; /* Event name */
67 char *group; /* Group name */
68 struct perf_probe_point point; /* Probe point */
69 int nargs; /* Number of arguments */
70 struct perf_probe_arg *args; /* Arguments */
71};
72
73
74/* Line number container */
75struct line_node {
76 struct list_head list;
77 int line;
78};
79
80/* Line range */
81struct line_range {
82 char *file; /* File name */
83 char *function; /* Function name */
84 int start; /* Start line number */
85 int end; /* End line number */
86 int offset; /* Start line offset */
87 char *path; /* Real path name */
88 struct list_head line_list; /* Visible lines */
89};
90
91/* Command string to events */
92extern int parse_perf_probe_command(const char *cmd,
93 struct perf_probe_event *pev);
94extern int parse_kprobe_trace_command(const char *cmd,
95 struct kprobe_trace_event *tev);
96
97/* Events to command string */
98extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
99extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev);
100extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
101 size_t len);
102
103/* Check the perf_probe_event needs debuginfo */
104extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
105
106/* Convert from kprobe_trace_event to perf_probe_event */
107extern int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
108 struct perf_probe_event *pev);
109
110/* Release event contents */
111extern void clear_perf_probe_event(struct perf_probe_event *pev);
112extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev);
113
114/* Command string to line-range */
115extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
116
117
118extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
119 bool force_add, int max_probe_points);
120extern int del_perf_probe_events(struct strlist *dellist);
121extern int show_perf_probe_events(void);
122extern int show_line_range(struct line_range *lr);
123
18 124
19/* Maximum index number of event-name postfix */ 125/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024 126#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4b852c0d16a5..d964cb199c67 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -31,72 +31,16 @@
31#include <string.h> 31#include <string.h>
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h> 33#include <ctype.h>
34#include <dwarf-regs.h>
34 35
36#include "string.h"
35#include "event.h" 37#include "event.h"
36#include "debug.h" 38#include "debug.h"
37#include "util.h" 39#include "util.h"
38#include "probe-finder.h" 40#include "probe-finder.h"
39 41
40 42/* Kprobe tracer basic type is up to u64 */
41/* Dwarf_Die Linkage to parent Die */ 43#define MAX_BASIC_TYPE_BITS 64
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
50/*
51 * Generic dwarf analysis helpers
52 */
53
54#define X86_32_MAX_REGS 8
55const char *x86_32_regs_table[X86_32_MAX_REGS] = {
56 "%ax",
57 "%cx",
58 "%dx",
59 "%bx",
60 "$stack", /* Stack address instead of %sp */
61 "%bp",
62 "%si",
63 "%di",
64};
65
66#define X86_64_MAX_REGS 16
67const char *x86_64_regs_table[X86_64_MAX_REGS] = {
68 "%ax",
69 "%dx",
70 "%cx",
71 "%bx",
72 "%si",
73 "%di",
74 "%bp",
75 "%sp",
76 "%r8",
77 "%r9",
78 "%r10",
79 "%r11",
80 "%r12",
81 "%r13",
82 "%r14",
83 "%r15",
84};
85
86/* TODO: switching by dwarf address size */
87#ifdef __x86_64__
88#define ARCH_MAX_REGS X86_64_MAX_REGS
89#define arch_regs_table x86_64_regs_table
90#else
91#define ARCH_MAX_REGS X86_32_MAX_REGS
92#define arch_regs_table x86_32_regs_table
93#endif
94
95/* Return architecture dependent register string (for kprobe-tracer) */
96static const char *get_arch_regstr(unsigned int n)
97{
98 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
99}
100 44
101/* 45/*
102 * Compare the tail of two strings. 46 * Compare the tail of two strings.
@@ -113,256 +57,299 @@ static int strtailcmp(const char *s1, const char *s2)
113 return 0; 57 return 0;
114} 58}
115 59
116/* Find the fileno of the target file. */ 60/* Line number list operations */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname) 61
62/* Add a line to line number list */
63static int line_list__add_line(struct list_head *head, int line)
64{
65 struct line_node *ln;
66 struct list_head *p;
67
68 /* Reverse search, because new line will be the last one */
69 list_for_each_entry_reverse(ln, head, list) {
70 if (ln->line < line) {
71 p = &ln->list;
72 goto found;
73 } else if (ln->line == line) /* Already exist */
74 return 1;
75 }
76 /* List is empty, or the smallest entry */
77 p = head;
78found:
79 pr_debug("line list: add a line %u\n", line);
80 ln = zalloc(sizeof(struct line_node));
81 if (ln == NULL)
82 return -ENOMEM;
83 ln->line = line;
84 INIT_LIST_HEAD(&ln->list);
85 list_add(&ln->list, p);
86 return 0;
87}
88
89/* Check if the line in line number list */
90static int line_list__has_line(struct list_head *head, int line)
91{
92 struct line_node *ln;
93
94 /* Reverse search, because new line will be the last one */
95 list_for_each_entry(ln, head, list)
96 if (ln->line == line)
97 return 1;
98
99 return 0;
100}
101
102/* Init line number list */
103static void line_list__init(struct list_head *head)
104{
105 INIT_LIST_HEAD(head);
106}
107
108/* Free line number list */
109static void line_list__free(struct list_head *head)
110{
111 struct line_node *ln;
112 while (!list_empty(head)) {
113 ln = list_first_entry(head, struct line_node, list);
114 list_del(&ln->list);
115 free(ln);
116 }
117}
118
119/* Dwarf wrappers */
120
121/* Find the realpath of the target file. */
122static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
118{ 123{
119 Dwarf_Signed cnt, i; 124 Dwarf_Files *files;
120 Dwarf_Unsigned found = 0; 125 size_t nfiles, i;
121 char **srcs; 126 const char *src = NULL;
122 int ret; 127 int ret;
123 128
124 if (!fname) 129 if (!fname)
125 return 0; 130 return NULL;
126 131
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 132 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
128 if (ret == DW_DLV_OK) { 133 if (ret != 0)
129 for (i = 0; i < cnt && !found; i++) { 134 return NULL;
130 if (strtailcmp(srcs[i], fname) == 0) 135
131 found = i + 1; 136 for (i = 0; i < nfiles; i++) {
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 137 src = dwarf_filesrc(files, i, NULL, NULL);
133 } 138 if (strtailcmp(src, fname) == 0)
134 for (; i < cnt; i++) 139 break;
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 } 140 }
138 if (found) 141 if (i == nfiles)
139 pr_debug("found fno: %d\n", (int)found); 142 return NULL;
140 return found; 143 return src;
141} 144}
142 145
143/* Compare diename and tname */ 146/* Compare diename and tname */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 147static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
145{ 148{
146 char *name; 149 const char *name;
147 int ret; 150 name = dwarf_diename(dw_die);
148 ret = dwarf_diename(dw_die, &name, &__dw_error); 151 return name ? strcmp(tname, name) : -1;
149 DIE_IF(ret == DW_DLV_ERROR);
150 if (ret == DW_DLV_OK) {
151 ret = strcmp(tname, name);
152 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
153 } else
154 ret = -1;
155 return ret;
156} 152}
157 153
158/* Check the address is in the subprogram(function). */ 154/* Get type die, but skip qualifiers and typedef */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 155static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
160 Dwarf_Signed *offs)
161{ 156{
162 Dwarf_Addr lopc, hipc; 157 Dwarf_Attribute attr;
163 int ret; 158 int tag;
164 159
165 /* TODO: check ranges */ 160 do {
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error); 161 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
167 DIE_IF(ret == DW_DLV_ERROR); 162 dwarf_formref_die(&attr, die_mem) == NULL)
168 if (ret == DW_DLV_NO_ENTRY) 163 return NULL;
169 return 0; 164
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error); 165 tag = dwarf_tag(die_mem);
171 DIE_IF(ret != DW_DLV_OK); 166 vr_die = die_mem;
172 if (lopc <= addr && addr < hipc) { 167 } while (tag == DW_TAG_const_type ||
173 *offs = addr - lopc; 168 tag == DW_TAG_restrict_type ||
174 return 1; 169 tag == DW_TAG_volatile_type ||
175 } else 170 tag == DW_TAG_shared_type ||
176 return 0; 171 tag == DW_TAG_typedef);
172
173 return die_mem;
177} 174}
178 175
179/* Check the die is inlined function */ 176static bool die_is_signed_type(Dwarf_Die *tp_die)
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
181{ 177{
182 /* TODO: check strictly */ 178 Dwarf_Attribute attr;
183 Dwarf_Bool inl; 179 Dwarf_Word ret;
184 int ret; 180
181 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
182 dwarf_formudata(&attr, &ret) != 0)
183 return false;
185 184
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 185 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
187 DIE_IF(ret == DW_DLV_ERROR); 186 ret == DW_ATE_signed_fixed);
188 return inl;
189} 187}
190 188
191/* Get the offset of abstruct_origin */ 189static int die_get_byte_size(Dwarf_Die *tp_die)
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
193{ 190{
194 Dwarf_Attribute attr; 191 Dwarf_Attribute attr;
195 Dwarf_Off cu_offs; 192 Dwarf_Word ret;
196 int ret; 193
194 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
195 dwarf_formudata(&attr, &ret) != 0)
196 return 0;
197 197
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 198 return (int)ret;
199 DIE_IF(ret != DW_DLV_OK);
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error);
201 DIE_IF(ret != DW_DLV_OK);
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
203 return cu_offs;
204} 199}
205 200
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 201/* Get data_member_location offset */
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 202static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
208{ 203{
209 Dwarf_Attribute attr; 204 Dwarf_Attribute attr;
210 Dwarf_Addr addr; 205 Dwarf_Op *expr;
211 Dwarf_Off offs; 206 size_t nexpr;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret; 207 int ret;
215 208
216 /* Try to get entry pc */ 209 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 210 return -ENOENT;
218 DIE_IF(ret == DW_DLV_ERROR); 211
219 if (ret == DW_DLV_OK) { 212 if (dwarf_formudata(&attr, offs) != 0) {
220 ret = dwarf_formaddr(attr, &addr, &__dw_error); 213 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
221 DIE_IF(ret != DW_DLV_OK); 214 ret = dwarf_getlocation(&attr, &expr, &nexpr);
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 215 if (ret < 0 || nexpr == 0)
223 return addr; 216 return -ENOENT;
224 } 217
225 218 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
226 /* Try to get low pc */ 219 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error); 220 expr[0].atom, nexpr);
228 DIE_IF(ret == DW_DLV_ERROR); 221 return -ENOTSUP;
229 if (ret == DW_DLV_OK) 222 }
230 return addr; 223 *offs = (Dwarf_Word)expr[0].number;
231 224 }
232 /* Try to get ranges */ 225 return 0;
233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
234 DIE_IF(ret != DW_DLV_OK);
235 ret = dwarf_formref(attr, &offs, &__dw_error);
236 DIE_IF(ret != DW_DLV_OK);
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
238 &__dw_error);
239 DIE_IF(ret != DW_DLV_OK);
240 addr = ranges[0].dwr_addr1;
241 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
242 return addr;
243} 226}
244 227
245/* 228/* Return values for die_find callbacks */
246 * Search a Die from Die tree. 229enum {
247 * Note: cur_link->die should be deallocated in this function. 230 DIE_FIND_CB_FOUND = 0, /* End of Search */
248 */ 231 DIE_FIND_CB_CHILD = 1, /* Search only children */
249static int __search_die_tree(struct die_link *cur_link, 232 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
250 int (*die_cb)(struct die_link *, void *), 233 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
251 void *data) 234};
235
236/* Search a child die */
237static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
238 int (*callback)(Dwarf_Die *, void *),
239 void *data, Dwarf_Die *die_mem)
252{ 240{
253 Dwarf_Die new_die; 241 Dwarf_Die child_die;
254 struct die_link new_link;
255 int ret; 242 int ret;
256 243
257 if (!die_cb) 244 ret = dwarf_child(rt_die, die_mem);
258 return 0; 245 if (ret != 0)
246 return NULL;
247
248 do {
249 ret = callback(die_mem, data);
250 if (ret == DIE_FIND_CB_FOUND)
251 return die_mem;
259 252
260 /* Check current die */ 253 if ((ret & DIE_FIND_CB_CHILD) &&
261 while (!(ret = die_cb(cur_link, data))) { 254 die_find_child(die_mem, callback, data, &child_die)) {
262 /* Check child die */ 255 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error); 256 return die_mem;
264 DIE_IF(ret == DW_DLV_ERROR);
265 if (ret == DW_DLV_OK) {
266 new_link.parent = cur_link;
267 new_link.die = new_die;
268 ret = __search_die_tree(&new_link, die_cb, data);
269 if (ret)
270 break;
271 } 257 }
258 } while ((ret & DIE_FIND_CB_SIBLING) &&
259 dwarf_siblingof(die_mem, die_mem) == 0);
272 260
273 /* Move to next sibling */ 261 return NULL;
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
275 &__dw_error);
276 DIE_IF(ret == DW_DLV_ERROR);
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
278 cur_link->die = new_die;
279 if (ret == DW_DLV_NO_ENTRY)
280 return 0;
281 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
283 return ret;
284} 262}
285 263
286/* Search a die in its children's die tree */ 264struct __addr_die_search_param {
287static int search_die_from_children(Dwarf_Die parent_die, 265 Dwarf_Addr addr;
288 int (*die_cb)(struct die_link *, void *), 266 Dwarf_Die *die_mem;
289 void *data) 267};
268
269static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
290{ 270{
291 struct die_link new_link; 271 struct __addr_die_search_param *ad = data;
292 int ret;
293 272
294 new_link.parent = NULL; 273 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error); 274 dwarf_haspc(fn_die, ad->addr)) {
296 DIE_IF(ret == DW_DLV_ERROR); 275 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
297 if (ret == DW_DLV_OK) 276 return DWARF_CB_ABORT;
298 return __search_die_tree(&new_link, die_cb, data); 277 }
278 return DWARF_CB_OK;
279}
280
281/* Search a real subprogram including this line, */
282static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
283 Dwarf_Die *die_mem)
284{
285 struct __addr_die_search_param ad;
286 ad.addr = addr;
287 ad.die_mem = die_mem;
288 /* dwarf_getscopes can't find subprogram. */
289 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
290 return NULL;
299 else 291 else
300 return 0; 292 return die_mem;
301} 293}
302 294
303/* Find a locdesc corresponding to the address */ 295/* die_find callback for inline function search */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 296static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
305 Dwarf_Addr addr)
306{ 297{
307 Dwarf_Signed lcnt; 298 Dwarf_Addr *addr = data;
308 Dwarf_Locdesc **llbuf;
309 int ret, i;
310 299
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error); 300 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
312 DIE_IF(ret != DW_DLV_OK); 301 dwarf_haspc(die_mem, *addr))
313 ret = DW_DLV_NO_ENTRY; 302 return DIE_FIND_CB_FOUND;
314 for (i = 0; i < lcnt; ++i) { 303
315 if (llbuf[i]->ld_lopc <= addr && 304 return DIE_FIND_CB_CONTINUE;
316 llbuf[i]->ld_hipc > addr) {
317 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
318 desc->ld_s =
319 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
320 DIE_IF(desc->ld_s == NULL);
321 memcpy(desc->ld_s, llbuf[i]->ld_s,
322 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
323 ret = DW_DLV_OK;
324 break;
325 }
326 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
327 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
328 }
329 /* Releasing loop */
330 for (; i < lcnt; ++i) {
331 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
332 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
333 }
334 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
335 return ret;
336} 305}
337 306
338/* Get decl_file attribute value (file number) */ 307/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 308static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
309 Dwarf_Die *die_mem)
340{ 310{
341 Dwarf_Attribute attr; 311 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
342 Dwarf_Unsigned fno; 312}
343 int ret;
344 313
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 314static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
346 DIE_IF(ret != DW_DLV_OK); 315{
347 dwarf_formudata(attr, &fno, &__dw_error); 316 const char *name = data;
348 DIE_IF(ret != DW_DLV_OK); 317 int tag;
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 318
350 return fno; 319 tag = dwarf_tag(die_mem);
320 if ((tag == DW_TAG_formal_parameter ||
321 tag == DW_TAG_variable) &&
322 (die_compare_name(die_mem, name) == 0))
323 return DIE_FIND_CB_FOUND;
324
325 return DIE_FIND_CB_CONTINUE;
351} 326}
352 327
353/* Get decl_line attribute value (line number) */ 328/* Find a variable called 'name' */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 329static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
330 Dwarf_Die *die_mem)
355{ 331{
356 Dwarf_Attribute attr; 332 return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
357 Dwarf_Unsigned lno; 333 die_mem);
358 int ret; 334}
335
336static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
337{
338 const char *name = data;
359 339
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 340 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
361 DIE_IF(ret != DW_DLV_OK); 341 (die_compare_name(die_mem, name) == 0))
362 dwarf_formudata(attr, &lno, &__dw_error); 342 return DIE_FIND_CB_FOUND;
363 DIE_IF(ret != DW_DLV_OK); 343
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 344 return DIE_FIND_CB_SIBLING;
365 return lno; 345}
346
347/* Find a member called 'name' */
348static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
349 Dwarf_Die *die_mem)
350{
351 return die_find_child(st_die, __die_find_member_cb, (void *)name,
352 die_mem);
366} 353}
367 354
368/* 355/*
@@ -370,361 +357,950 @@ static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
370 */ 357 */
371 358
372/* Show a location */ 359/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 360static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
374{ 361{
375 Dwarf_Small op; 362 unsigned int regn;
376 Dwarf_Unsigned regn; 363 Dwarf_Word offs = 0;
377 Dwarf_Signed offs; 364 bool ref = false;
378 int deref = 0, ret;
379 const char *regs; 365 const char *regs;
380 366 struct kprobe_trace_arg *tvar = pf->tvar;
381 op = loc->lr_atom;
382 367
383 /* If this is based on frame buffer, set the offset */ 368 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) { 369 if (op->atom == DW_OP_fbreg) {
385 deref = 1; 370 if (pf->fb_ops == NULL) {
386 offs = (Dwarf_Signed)loc->lr_number; 371 pr_warning("The attribute of frame base is not "
387 op = pf->fbloc.ld_s[0].lr_atom; 372 "supported.\n");
388 loc = &pf->fbloc.ld_s[0]; 373 return -ENOTSUP;
389 } else 374 }
390 offs = 0; 375 ref = true;
391 376 offs = op->number;
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 377 op = &pf->fb_ops[0];
393 regn = op - DW_OP_breg0; 378 }
394 offs += (Dwarf_Signed)loc->lr_number; 379
395 deref = 1; 380 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 381 regn = op->atom - DW_OP_breg0;
397 regn = op - DW_OP_reg0; 382 offs += op->number;
398 } else if (op == DW_OP_bregx) { 383 ref = true;
399 regn = loc->lr_number; 384 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
400 offs += (Dwarf_Signed)loc->lr_number2; 385 regn = op->atom - DW_OP_reg0;
401 deref = 1; 386 } else if (op->atom == DW_OP_bregx) {
402 } else if (op == DW_OP_regx) { 387 regn = op->number;
403 regn = loc->lr_number; 388 offs += op->number2;
404 } else 389 ref = true;
405 die("Dwarf_OP %d is not supported.\n", op); 390 } else if (op->atom == DW_OP_regx) {
391 regn = op->number;
392 } else {
393 pr_warning("DW_OP %x is not supported.\n", op->atom);
394 return -ENOTSUP;
395 }
406 396
407 regs = get_arch_regstr(regn); 397 regs = get_arch_regstr(regn);
408 if (!regs) 398 if (!regs) {
409 die("%lld exceeds max register number.\n", regn); 399 pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
400 return -ERANGE;
401 }
410 402
411 if (deref) 403 tvar->value = strdup(regs);
412 ret = snprintf(pf->buf, pf->len, 404 if (tvar->value == NULL)
413 " %s=%+lld(%s)", pf->var, offs, regs); 405 return -ENOMEM;
414 else 406
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 407 if (ref) {
416 DIE_IF(ret < 0); 408 tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
417 DIE_IF(ret >= pf->len); 409 if (tvar->ref == NULL)
410 return -ENOMEM;
411 tvar->ref->offset = (long)offs;
412 }
413 return 0;
418} 414}
419 415
420/* Show a variables in kprobe event format */ 416static int convert_variable_type(Dwarf_Die *vr_die,
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 417 struct kprobe_trace_arg *targ)
422{ 418{
423 Dwarf_Attribute attr; 419 Dwarf_Die type;
424 Dwarf_Locdesc ld; 420 char buf[16];
425 int ret; 421 int ret;
426 422
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 423 if (die_get_real_type(vr_die, &type) == NULL) {
428 if (ret != DW_DLV_OK) 424 pr_warning("Failed to get a type information of %s.\n",
429 goto error; 425 dwarf_diename(vr_die));
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 426 return -ENOENT;
431 if (ret != DW_DLV_OK) 427 }
432 goto error;
433 /* TODO? */
434 DIE_IF(ld.ld_cents != 1);
435 show_location(&ld.ld_s[0], pf);
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ;
439error:
440 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var);
442}
443 428
444static int variable_callback(struct die_link *dlink, void *data) 429 ret = die_get_byte_size(&type) * 8;
445{ 430 if (ret) {
446 struct probe_finder *pf = (struct probe_finder *)data; 431 /* Check the bitwidth */
447 Dwarf_Half tag; 432 if (ret > MAX_BASIC_TYPE_BITS) {
448 int ret; 433 pr_info("%s exceeds max-bitwidth."
434 " Cut down to %d bits.\n",
435 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
436 ret = MAX_BASIC_TYPE_BITS;
437 }
449 438
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 439 ret = snprintf(buf, 16, "%c%d",
451 DIE_IF(ret == DW_DLV_ERROR); 440 die_is_signed_type(&type) ? 's' : 'u', ret);
452 if ((tag == DW_TAG_formal_parameter || 441 if (ret < 0 || ret >= 16) {
453 tag == DW_TAG_variable) && 442 if (ret >= 16)
454 (die_compare_name(dlink->die, pf->var) == 0)) { 443 ret = -E2BIG;
455 show_variable(dlink->die, pf); 444 pr_warning("Failed to convert variable type: %s\n",
456 return 1; 445 strerror(-ret));
446 return ret;
447 }
448 targ->type = strdup(buf);
449 if (targ->type == NULL)
450 return -ENOMEM;
457 } 451 }
458 /* TODO: Support struct members and arrays */
459 return 0; 452 return 0;
460} 453}
461 454
462/* Find a variable in a subprogram die */ 455static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 456 struct perf_probe_arg_field *field,
457 struct kprobe_trace_arg_ref **ref_ptr,
458 Dwarf_Die *die_mem)
464{ 459{
460 struct kprobe_trace_arg_ref *ref = *ref_ptr;
461 Dwarf_Die type;
462 Dwarf_Word offs;
465 int ret; 463 int ret;
466 464
467 if (!is_c_varname(pf->var)) { 465 pr_debug("converting %s in %s\n", field->name, varname);
468 /* Output raw parameters */ 466 if (die_get_real_type(vr_die, &type) == NULL) {
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 467 pr_warning("Failed to get the type of %s.\n", varname);
470 DIE_IF(ret < 0); 468 return -ENOENT;
471 DIE_IF(ret >= pf->len);
472 return ;
473 } 469 }
474 470
475 pr_debug("Searching '%s' variable in context.\n", pf->var); 471 /* Check the pointer and dereference */
476 /* Search child die for local variables and parameters. */ 472 if (dwarf_tag(&type) == DW_TAG_pointer_type) {
477 ret = search_die_from_children(sp_die, variable_callback, pf); 473 if (!field->ref) {
478 if (!ret) 474 pr_err("Semantic error: %s must be referred by '->'\n",
479 die("Failed to find '%s' in this function.\n", pf->var); 475 field->name);
476 return -EINVAL;
477 }
478 /* Get the type pointed by this pointer */
479 if (die_get_real_type(&type, &type) == NULL) {
480 pr_warning("Failed to get the type of %s.\n", varname);
481 return -ENOENT;
482 }
483 /* Verify it is a data structure */
484 if (dwarf_tag(&type) != DW_TAG_structure_type) {
485 pr_warning("%s is not a data structure.\n", varname);
486 return -EINVAL;
487 }
488
489 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
490 if (ref == NULL)
491 return -ENOMEM;
492 if (*ref_ptr)
493 (*ref_ptr)->next = ref;
494 else
495 *ref_ptr = ref;
496 } else {
497 /* Verify it is a data structure */
498 if (dwarf_tag(&type) != DW_TAG_structure_type) {
499 pr_warning("%s is not a data structure.\n", varname);
500 return -EINVAL;
501 }
502 if (field->ref) {
503 pr_err("Semantic error: %s must be referred by '.'\n",
504 field->name);
505 return -EINVAL;
506 }
507 if (!ref) {
508 pr_warning("Structure on a register is not "
509 "supported yet.\n");
510 return -ENOTSUP;
511 }
512 }
513
514 if (die_find_member(&type, field->name, die_mem) == NULL) {
515 pr_warning("%s(tyep:%s) has no member %s.\n", varname,
516 dwarf_diename(&type), field->name);
517 return -EINVAL;
518 }
519
520 /* Get the offset of the field */
521 ret = die_get_data_member_location(die_mem, &offs);
522 if (ret < 0) {
523 pr_warning("Failed to get the offset of %s.\n", field->name);
524 return ret;
525 }
526 ref->offset += (long)offs;
527
528 /* Converting next field */
529 if (field->next)
530 return convert_variable_fields(die_mem, field->name,
531 field->next, &ref, die_mem);
532 else
533 return 0;
480} 534}
481 535
482/* Get a frame base on the address */ 536/* Show a variables in kprobe event format */
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf) 537static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
484{ 538{
485 Dwarf_Attribute attr; 539 Dwarf_Attribute attr;
540 Dwarf_Die die_mem;
541 Dwarf_Op *expr;
542 size_t nexpr;
486 int ret; 543 int ret;
487 544
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error); 545 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
489 DIE_IF(ret != DW_DLV_OK); 546 goto error;
490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base)); 547 /* TODO: handle more than 1 exprs */
491 DIE_IF(ret != DW_DLV_OK); 548 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 549 if (ret <= 0 || nexpr == 0)
550 goto error;
551
552 ret = convert_location(expr, pf);
553 if (ret == 0 && pf->pvar->field) {
554 ret = convert_variable_fields(vr_die, pf->pvar->var,
555 pf->pvar->field, &pf->tvar->ref,
556 &die_mem);
557 vr_die = &die_mem;
558 }
559 if (ret == 0) {
560 if (pf->pvar->type) {
561 pf->tvar->type = strdup(pf->pvar->type);
562 if (pf->tvar->type == NULL)
563 ret = -ENOMEM;
564 } else
565 ret = convert_variable_type(vr_die, pf->tvar);
566 }
567 /* *expr will be cached in libdw. Don't free it. */
568 return ret;
569error:
570 /* TODO: Support const_value */
571 pr_err("Failed to find the location of %s at this address.\n"
572 " Perhaps, it has been optimized out.\n", pf->pvar->var);
573 return -ENOENT;
493} 574}
494 575
495static void free_current_frame_base(struct probe_finder *pf) 576/* Find a variable in a subprogram die */
577static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
496{ 578{
497 free(pf->fbloc.ld_s); 579 Dwarf_Die vr_die;
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc)); 580 char buf[32], *ptr;
581 int ret;
582
583 /* TODO: Support arrays */
584 if (pf->pvar->name)
585 pf->tvar->name = strdup(pf->pvar->name);
586 else {
587 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
588 if (ret < 0)
589 return ret;
590 ptr = strchr(buf, ':'); /* Change type separator to _ */
591 if (ptr)
592 *ptr = '_';
593 pf->tvar->name = strdup(buf);
594 }
595 if (pf->tvar->name == NULL)
596 return -ENOMEM;
597
598 if (!is_c_varname(pf->pvar->var)) {
599 /* Copy raw parameters */
600 pf->tvar->value = strdup(pf->pvar->var);
601 if (pf->tvar->value == NULL)
602 return -ENOMEM;
603 else
604 return 0;
605 }
606
607 pr_debug("Searching '%s' variable in context.\n",
608 pf->pvar->var);
609 /* Search child die for local variables and parameters. */
610 if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) {
611 pr_warning("Failed to find '%s' in this function.\n",
612 pf->pvar->var);
613 return -ENOENT;
614 }
615 return convert_variable(&vr_die, pf);
499} 616}
500 617
501/* Show a probe point to output buffer */ 618/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 619static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
503 struct probe_finder *pf) 620{
504{ 621 struct kprobe_trace_event *tev;
505 struct probe_point *pp = pf->pp; 622 Dwarf_Addr eaddr;
506 char *name; 623 Dwarf_Die die_mem;
507 char tmp[MAX_PROBE_BUFFER]; 624 const char *name;
508 int ret, i, len; 625 int ret, i;
509 626 Dwarf_Attribute fb_attr;
510 /* Output name of probe point */ 627 size_t nops;
511 ret = dwarf_diename(sp_die, &name, &__dw_error); 628
512 DIE_IF(ret == DW_DLV_ERROR); 629 if (pf->ntevs == pf->max_tevs) {
513 if (ret == DW_DLV_OK) { 630 pr_warning("Too many( > %d) probe point found.\n",
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 631 pf->max_tevs);
515 (unsigned int)offs); 632 return -ERANGE;
516 /* Copy the function name if possible */ 633 }
517 if (!pp->function) { 634 tev = &pf->tevs[pf->ntevs++];
518 pp->function = strdup(name); 635
519 pp->offset = offs; 636 /* If no real subprogram, find a real one */
637 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
638 sp_die = die_find_real_subprogram(&pf->cu_die,
639 pf->addr, &die_mem);
640 if (!sp_die) {
641 pr_warning("Failed to find probe point in any "
642 "functions.\n");
643 return -ENOENT;
520 } 644 }
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING); 645 }
522 } else { 646
647 /* Copy the name of probe point */
648 name = dwarf_diename(sp_die);
649 if (name) {
650 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
651 pr_warning("Failed to get entry pc of %s\n",
652 dwarf_diename(sp_die));
653 return -ENOENT;
654 }
655 tev->point.symbol = strdup(name);
656 if (tev->point.symbol == NULL)
657 return -ENOMEM;
658 tev->point.offset = (unsigned long)(pf->addr - eaddr);
659 } else
523 /* This function has no name. */ 660 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 661 tev->point.offset = (unsigned long)pf->addr;
525 if (!pp->function) { 662
526 /* TODO: Use _stext */ 663 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
527 pp->function = strdup(""); 664 tev->point.offset);
528 pp->offset = (int)pf->addr; 665
666 /* Get the frame base attribute/ops */
667 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
668 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
669 if (ret <= 0 || nops == 0) {
670 pf->fb_ops = NULL;
671#if _ELFUTILS_PREREQ(0, 142)
672 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
673 pf->cfi != NULL) {
674 Dwarf_Frame *frame;
675 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
676 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
677 pr_warning("Failed to get CFA on 0x%jx\n",
678 (uintmax_t)pf->addr);
679 return -ENOENT;
529 } 680 }
681#endif
530 } 682 }
531 DIE_IF(ret < 0);
532 DIE_IF(ret >= MAX_PROBE_BUFFER);
533 len = ret;
534 pr_debug("Probe point found: %s\n", tmp);
535 683
536 /* Find each argument */ 684 /* Find each argument */
537 get_current_frame_base(sp_die, pf); 685 tev->nargs = pf->pev->nargs;
538 for (i = 0; i < pp->nr_args; i++) { 686 tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
539 pf->var = pp->args[i]; 687 if (tev->args == NULL)
540 pf->buf = &tmp[len]; 688 return -ENOMEM;
541 pf->len = MAX_PROBE_BUFFER - len; 689 for (i = 0; i < pf->pev->nargs; i++) {
542 find_variable(sp_die, pf); 690 pf->pvar = &pf->pev->args[i];
543 len += strlen(pf->buf); 691 pf->tvar = &tev->args[i];
692 ret = find_variable(sp_die, pf);
693 if (ret != 0)
694 return ret;
544 } 695 }
545 free_current_frame_base(pf);
546 696
547 pp->probes[pp->found] = strdup(tmp); 697 /* *pf->fb_ops will be cached in libdw. Don't free it. */
548 pp->found++; 698 pf->fb_ops = NULL;
699 return 0;
549} 700}
550 701
551static int probeaddr_callback(struct die_link *dlink, void *data) 702/* Find probe point from its line number */
703static int find_probe_point_by_line(struct probe_finder *pf)
552{ 704{
553 struct probe_finder *pf = (struct probe_finder *)data; 705 Dwarf_Lines *lines;
554 Dwarf_Half tag; 706 Dwarf_Line *line;
555 Dwarf_Signed offs; 707 size_t nlines, i;
556 int ret; 708 Dwarf_Addr addr;
709 int lineno;
710 int ret = 0;
557 711
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 712 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
559 DIE_IF(ret == DW_DLV_ERROR); 713 pr_warning("No source lines found in this CU.\n");
560 /* Check the address is in this subprogram */ 714 return -ENOENT;
561 if (tag == DW_TAG_subprogram &&
562 die_within_subprogram(dlink->die, pf->addr, &offs)) {
563 show_probepoint(dlink->die, offs, pf);
564 return 1;
565 } 715 }
566 return 0; 716
717 for (i = 0; i < nlines && ret == 0; i++) {
718 line = dwarf_onesrcline(lines, i);
719 if (dwarf_lineno(line, &lineno) != 0 ||
720 lineno != pf->lno)
721 continue;
722
723 /* TODO: Get fileno from line, but how? */
724 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
725 continue;
726
727 if (dwarf_lineaddr(line, &addr) != 0) {
728 pr_warning("Failed to get the address of the line.\n");
729 return -ENOENT;
730 }
731 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
732 (int)i, lineno, (uintmax_t)addr);
733 pf->addr = addr;
734
735 ret = convert_probe_point(NULL, pf);
736 /* Continuing, because target line might be inlined. */
737 }
738 return ret;
567} 739}
568 740
569/* Find probe point from its line number */ 741/* Find lines which match lazy pattern */
570static void find_by_line(struct probe_finder *pf) 742static int find_lazy_match_lines(struct list_head *head,
743 const char *fname, const char *pat)
571{ 744{
572 Dwarf_Signed cnt, i, clm; 745 char *fbuf, *p1, *p2;
573 Dwarf_Line *lines; 746 int fd, line, nlines = -1;
574 Dwarf_Unsigned lineno = 0; 747 struct stat st;
748
749 fd = open(fname, O_RDONLY);
750 if (fd < 0) {
751 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd));
752 return -errno;
753 }
754
755 if (fstat(fd, &st) < 0) {
756 pr_warning("Failed to get the size of %s: %s\n",
757 fname, strerror(errno));
758 nlines = -errno;
759 goto out_close;
760 }
761
762 nlines = -ENOMEM;
763 fbuf = malloc(st.st_size + 2);
764 if (fbuf == NULL)
765 goto out_close;
766 if (read(fd, fbuf, st.st_size) < 0) {
767 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
768 nlines = -errno;
769 goto out_free_fbuf;
770 }
771 fbuf[st.st_size] = '\n'; /* Dummy line */
772 fbuf[st.st_size + 1] = '\0';
773 p1 = fbuf;
774 line = 1;
775 nlines = 0;
776 while ((p2 = strchr(p1, '\n')) != NULL) {
777 *p2 = '\0';
778 if (strlazymatch(p1, pat)) {
779 line_list__add_line(head, line);
780 nlines++;
781 }
782 line++;
783 p1 = p2 + 1;
784 }
785out_free_fbuf:
786 free(fbuf);
787out_close:
788 close(fd);
789 return nlines;
790}
791
792/* Find probe points from lazy pattern */
793static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
794{
795 Dwarf_Lines *lines;
796 Dwarf_Line *line;
797 size_t nlines, i;
575 Dwarf_Addr addr; 798 Dwarf_Addr addr;
576 Dwarf_Unsigned fno; 799 Dwarf_Die die_mem;
577 int ret; 800 int lineno;
801 int ret = 0;
802
803 if (list_empty(&pf->lcache)) {
804 /* Matching lazy line pattern */
805 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
806 pf->pev->point.lazy_line);
807 if (ret == 0) {
808 pr_debug("No matched lines found in %s.\n", pf->fname);
809 return 0;
810 } else if (ret < 0)
811 return ret;
812 }
578 813
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 814 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
580 DIE_IF(ret != DW_DLV_OK); 815 pr_warning("No source lines found in this CU.\n");
816 return -ENOENT;
817 }
581 818
582 for (i = 0; i < cnt; i++) { 819 for (i = 0; i < nlines && ret >= 0; i++) {
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 820 line = dwarf_onesrcline(lines, i);
584 DIE_IF(ret != DW_DLV_OK); 821
585 if (fno != pf->fno) 822 if (dwarf_lineno(line, &lineno) != 0 ||
823 !line_list__has_line(&pf->lcache, lineno))
586 continue; 824 continue;
587 825
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 826 /* TODO: Get fileno from line, but how? */
589 DIE_IF(ret != DW_DLV_OK); 827 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
590 if (lineno != pf->lno)
591 continue; 828 continue;
592 829
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 830 if (dwarf_lineaddr(line, &addr) != 0) {
594 DIE_IF(ret != DW_DLV_OK); 831 pr_debug("Failed to get the address of line %d.\n",
832 lineno);
833 continue;
834 }
835 if (sp_die) {
836 /* Address filtering 1: does sp_die include addr? */
837 if (!dwarf_haspc(sp_die, addr))
838 continue;
839 /* Address filtering 2: No child include addr? */
840 if (die_find_inlinefunc(sp_die, addr, &die_mem))
841 continue;
842 }
595 843
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 844 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
597 DIE_IF(ret != DW_DLV_OK); 845 (int)i, lineno, (unsigned long long)addr);
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i, (unsigned)lineno, (int)clm, addr);
600 pf->addr = addr; 846 pf->addr = addr;
601 /* Search a real subprogram including this line, */ 847
602 ret = search_die_from_children(pf->cu_die, 848 ret = convert_probe_point(sp_die, pf);
603 probeaddr_callback, pf);
604 if (ret == 0)
605 die("Probe point is not found in subprograms.\n");
606 /* Continuing, because target line might be inlined. */ 849 /* Continuing, because target line might be inlined. */
607 } 850 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 851 /* TODO: deallocate lines, but how? */
852 return ret;
609} 853}
610 854
611/* Search function from function name */ 855/* Callback parameter with return value */
612static int probefunc_callback(struct die_link *dlink, void *data) 856struct dwarf_callback_param {
857 void *data;
858 int retval;
859};
860
861static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
613{ 862{
614 struct probe_finder *pf = (struct probe_finder *)data; 863 struct dwarf_callback_param *param = data;
615 struct probe_point *pp = pf->pp; 864 struct probe_finder *pf = param->data;
616 struct die_link *lk; 865 struct perf_probe_point *pp = &pf->pev->point;
617 Dwarf_Signed offs; 866 Dwarf_Addr addr;
618 Dwarf_Half tag;
619 int ret;
620 867
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 868 if (pp->lazy_line)
622 DIE_IF(ret == DW_DLV_ERROR); 869 param->retval = find_probe_point_lazy(in_die, pf);
623 if (tag == DW_TAG_subprogram) { 870 else {
624 if (die_compare_name(dlink->die, pp->function) == 0) { 871 /* Get probe address */
625 if (pp->line) { /* Function relative line */ 872 if (dwarf_entrypc(in_die, &addr) != 0) {
626 pf->fno = die_get_decl_file(dlink->die); 873 pr_warning("Failed to get entry pc of %s.\n",
627 pf->lno = die_get_decl_line(dlink->die) 874 dwarf_diename(in_die));
628 + pp->line; 875 param->retval = -ENOENT;
629 find_by_line(pf); 876 return DWARF_CB_ABORT;
630 return 1; 877 }
631 } 878 pf->addr = addr;
632 if (die_inlined_subprogram(dlink->die)) { 879 pf->addr += pp->offset;
633 /* Inlined function, save it. */ 880 pr_debug("found inline addr: 0x%jx\n",
634 ret = dwarf_die_CU_offset(dlink->die, 881 (uintmax_t)pf->addr);
635 &pf->inl_offs, 882
636 &__dw_error); 883 param->retval = convert_probe_point(in_die, pf);
637 DIE_IF(ret != DW_DLV_OK); 884 if (param->retval < 0)
638 pr_debug("inline definition offset %lld\n", 885 return DWARF_CB_ABORT;
639 pf->inl_offs); 886 }
640 return 0; /* Continue to search */ 887
888 return DWARF_CB_OK;
889}
890
891/* Search function from function name */
892static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
893{
894 struct dwarf_callback_param *param = data;
895 struct probe_finder *pf = param->data;
896 struct perf_probe_point *pp = &pf->pev->point;
897
898 /* Check tag and diename */
899 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
900 die_compare_name(sp_die, pp->function) != 0)
901 return DWARF_CB_OK;
902
903 pf->fname = dwarf_decl_file(sp_die);
904 if (pp->line) { /* Function relative line */
905 dwarf_decl_line(sp_die, &pf->lno);
906 pf->lno += pp->line;
907 param->retval = find_probe_point_by_line(pf);
908 } else if (!dwarf_func_inline(sp_die)) {
909 /* Real function */
910 if (pp->lazy_line)
911 param->retval = find_probe_point_lazy(sp_die, pf);
912 else {
913 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
914 pr_warning("Failed to get entry pc of %s.\n",
915 dwarf_diename(sp_die));
916 param->retval = -ENOENT;
917 return DWARF_CB_ABORT;
641 } 918 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset; 919 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */ 920 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf); 921 param->retval = convert_probe_point(sp_die, pf);
647 return 1; /* Exit; no same symbol in this CU. */
648 } 922 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) { 923 } else {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) { 924 struct dwarf_callback_param _param = {.data = (void *)pf,
651 /* Get probe address */ 925 .retval = 0};
652 pf->addr = die_get_entrypc(dlink->die); 926 /* Inlined function: search instances */
653 pf->addr += pp->offset; 927 dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
654 pr_debug("found inline addr: 0x%llx\n", pf->addr); 928 &_param);
655 /* Inlined function. Get a real subprogram */ 929 param->retval = _param.retval;
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) { 930 }
657 tag = 0; 931
658 dwarf_tag(lk->die, &tag, &__dw_error); 932 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
659 DIE_IF(ret == DW_DLV_ERROR); 933}
660 if (tag == DW_TAG_subprogram && 934
661 !die_inlined_subprogram(lk->die)) 935static int find_probe_point_by_func(struct probe_finder *pf)
662 goto found; 936{
937 struct dwarf_callback_param _param = {.data = (void *)pf,
938 .retval = 0};
939 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
940 return _param.retval;
941}
942
943/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
944int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
945 struct kprobe_trace_event **tevs, int max_tevs)
946{
947 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
948 struct perf_probe_point *pp = &pev->point;
949 Dwarf_Off off, noff;
950 size_t cuhl;
951 Dwarf_Die *diep;
952 Dwarf *dbg;
953 int ret = 0;
954
955 pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs);
956 if (pf.tevs == NULL)
957 return -ENOMEM;
958 *tevs = pf.tevs;
959 pf.ntevs = 0;
960
961 dbg = dwarf_begin(fd, DWARF_C_READ);
962 if (!dbg) {
963 pr_warning("No dwarf info found in the vmlinux - "
964 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
965 free(pf.tevs);
966 *tevs = NULL;
967 return -EBADF;
968 }
969
970#if _ELFUTILS_PREREQ(0, 142)
971 /* Get the call frame information from this dwarf */
972 pf.cfi = dwarf_getcfi(dbg);
973#endif
974
975 off = 0;
976 line_list__init(&pf.lcache);
977 /* Loop on CUs (Compilation Unit) */
978 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
979 ret >= 0) {
980 /* Get the DIE(Debugging Information Entry) of this CU */
981 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
982 if (!diep)
983 continue;
984
985 /* Check if target file is included. */
986 if (pp->file)
987 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
988 else
989 pf.fname = NULL;
990
991 if (!pp->file || pf.fname) {
992 if (pp->function)
993 ret = find_probe_point_by_func(&pf);
994 else if (pp->lazy_line)
995 ret = find_probe_point_lazy(NULL, &pf);
996 else {
997 pf.lno = pp->line;
998 ret = find_probe_point_by_line(&pf);
663 } 999 }
664 die("Failed to find real subprogram.\n"); 1000 }
1001 off = noff;
1002 }
1003 line_list__free(&pf.lcache);
1004 dwarf_end(dbg);
1005
1006 return (ret < 0) ? ret : pf.ntevs;
1007}
1008
1009/* Reverse search */
1010int find_perf_probe_point(int fd, unsigned long addr,
1011 struct perf_probe_point *ppt)
1012{
1013 Dwarf_Die cudie, spdie, indie;
1014 Dwarf *dbg;
1015 Dwarf_Line *line;
1016 Dwarf_Addr laddr, eaddr;
1017 const char *tmp;
1018 int lineno, ret = 0;
1019 bool found = false;
1020
1021 dbg = dwarf_begin(fd, DWARF_C_READ);
1022 if (!dbg)
1023 return -EBADF;
1024
1025 /* Find cu die */
1026 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
1027 ret = -EINVAL;
1028 goto end;
1029 }
1030
1031 /* Find a corresponding line */
1032 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
1033 if (line) {
1034 if (dwarf_lineaddr(line, &laddr) == 0 &&
1035 (Dwarf_Addr)addr == laddr &&
1036 dwarf_lineno(line, &lineno) == 0) {
1037 tmp = dwarf_linesrc(line, NULL, NULL);
1038 if (tmp) {
1039 ppt->line = lineno;
1040 ppt->file = strdup(tmp);
1041 if (ppt->file == NULL) {
1042 ret = -ENOMEM;
1043 goto end;
1044 }
1045 found = true;
1046 }
1047 }
1048 }
1049
1050 /* Find a corresponding function */
1051 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
1052 tmp = dwarf_diename(&spdie);
1053 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
1054 goto end;
1055
1056 if (ppt->line) {
1057 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1058 &indie)) {
1059 /* addr in an inline function */
1060 tmp = dwarf_diename(&indie);
1061 if (!tmp)
1062 goto end;
1063 ret = dwarf_decl_line(&indie, &lineno);
1064 } else {
1065 if (eaddr == addr) { /* Function entry */
1066 lineno = ppt->line;
1067 ret = 0;
1068 } else
1069 ret = dwarf_decl_line(&spdie, &lineno);
1070 }
1071 if (ret == 0) {
1072 /* Make a relative line number */
1073 ppt->line -= lineno;
1074 goto found;
1075 }
1076 }
1077 /* We don't have a line number, let's use offset */
1078 ppt->offset = addr - (unsigned long)eaddr;
665found: 1079found:
666 /* Get offset from subprogram */ 1080 ppt->function = strdup(tmp);
667 ret = die_within_subprogram(lk->die, pf->addr, &offs); 1081 if (ppt->function == NULL) {
668 DIE_IF(!ret); 1082 ret = -ENOMEM;
669 show_probepoint(lk->die, offs, pf); 1083 goto end;
670 /* Continue to search */
671 } 1084 }
1085 found = true;
672 } 1086 }
673 return 0; 1087
1088end:
1089 dwarf_end(dbg);
1090 if (ret >= 0)
1091 ret = found ? 1 : 0;
1092 return ret;
1093}
1094
1095/* Add a line and store the src path */
1096static int line_range_add_line(const char *src, unsigned int lineno,
1097 struct line_range *lr)
1098{
1099 /* Copy real path */
1100 if (!lr->path) {
1101 lr->path = strdup(src);
1102 if (lr->path == NULL)
1103 return -ENOMEM;
1104 }
1105 return line_list__add_line(&lr->line_list, lineno);
674} 1106}
675 1107
676static void find_by_func(struct probe_finder *pf) 1108/* Search function declaration lines */
1109static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
677{ 1110{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 1111 struct dwarf_callback_param *param = data;
1112 struct line_finder *lf = param->data;
1113 const char *src;
1114 int lineno;
1115
1116 src = dwarf_decl_file(sp_die);
1117 if (src && strtailcmp(src, lf->fname) != 0)
1118 return DWARF_CB_OK;
1119
1120 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1121 (lf->lno_s > lineno || lf->lno_e < lineno))
1122 return DWARF_CB_OK;
1123
1124 param->retval = line_range_add_line(src, lineno, lf->lr);
1125 if (param->retval < 0)
1126 return DWARF_CB_ABORT;
1127 return DWARF_CB_OK;
679} 1128}
680 1129
681/* Find a probe point */ 1130static int find_line_range_func_decl_lines(struct line_finder *lf)
682int find_probepoint(int fd, struct probe_point *pp)
683{ 1131{
684 Dwarf_Half addr_size = 0; 1132 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
685 Dwarf_Unsigned next_cuh = 0; 1133 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
686 int cu_number = 0, ret; 1134 return param.retval;
687 struct probe_finder pf = {.pp = pp}; 1135}
1136
1137/* Find line range from its line number */
1138static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1139{
1140 Dwarf_Lines *lines;
1141 Dwarf_Line *line;
1142 size_t nlines, i;
1143 Dwarf_Addr addr;
1144 int lineno, ret = 0;
1145 const char *src;
1146 Dwarf_Die die_mem;
688 1147
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 1148 line_list__init(&lf->lr->line_list);
690 if (ret != DW_DLV_OK) 1149 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1150 pr_warning("No source lines found in this CU.\n");
691 return -ENOENT; 1151 return -ENOENT;
1152 }
1153
1154 /* Search probable lines on lines list */
1155 for (i = 0; i < nlines; i++) {
1156 line = dwarf_onesrcline(lines, i);
1157 if (dwarf_lineno(line, &lineno) != 0 ||
1158 (lf->lno_s > lineno || lf->lno_e < lineno))
1159 continue;
1160
1161 if (sp_die) {
1162 /* Address filtering 1: does sp_die include addr? */
1163 if (dwarf_lineaddr(line, &addr) != 0 ||
1164 !dwarf_haspc(sp_die, addr))
1165 continue;
1166
1167 /* Address filtering 2: No child include addr? */
1168 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1169 continue;
1170 }
1171
1172 /* TODO: Get fileno from line, but how? */
1173 src = dwarf_linesrc(line, NULL, NULL);
1174 if (strtailcmp(src, lf->fname) != 0)
1175 continue;
1176
1177 ret = line_range_add_line(src, lineno, lf->lr);
1178 if (ret < 0)
1179 return ret;
1180 }
1181
1182 /*
1183 * Dwarf lines doesn't include function declarations. We have to
1184 * check functions list or given function.
1185 */
1186 if (sp_die) {
1187 src = dwarf_decl_file(sp_die);
1188 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1189 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1190 ret = line_range_add_line(src, lineno, lf->lr);
1191 } else
1192 ret = find_line_range_func_decl_lines(lf);
1193
1194 /* Update status */
1195 if (ret >= 0)
1196 if (!list_empty(&lf->lr->line_list))
1197 ret = lf->found = 1;
1198 else
1199 ret = 0; /* Lines are not found */
1200 else {
1201 free(lf->lr->path);
1202 lf->lr->path = NULL;
1203 }
1204 return ret;
1205}
692 1206
693 pp->found = 0; 1207static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
694 while (++cu_number) { 1208{
695 /* Search CU (Compilation Unit) */ 1209 struct dwarf_callback_param *param = data;
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 1210
697 &addr_size, &next_cuh, &__dw_error); 1211 param->retval = find_line_range_by_line(in_die, param->data);
698 DIE_IF(ret == DW_DLV_ERROR); 1212 return DWARF_CB_ABORT; /* No need to find other instances */
699 if (ret == DW_DLV_NO_ENTRY) 1213}
1214
1215/* Search function from function name */
1216static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1217{
1218 struct dwarf_callback_param *param = data;
1219 struct line_finder *lf = param->data;
1220 struct line_range *lr = lf->lr;
1221
1222 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1223 die_compare_name(sp_die, lr->function) == 0) {
1224 lf->fname = dwarf_decl_file(sp_die);
1225 dwarf_decl_line(sp_die, &lr->offset);
1226 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
1227 lf->lno_s = lr->offset + lr->start;
1228 if (lf->lno_s < 0) /* Overflow */
1229 lf->lno_s = INT_MAX;
1230 lf->lno_e = lr->offset + lr->end;
1231 if (lf->lno_e < 0) /* Overflow */
1232 lf->lno_e = INT_MAX;
1233 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
1234 lr->start = lf->lno_s;
1235 lr->end = lf->lno_e;
1236 if (dwarf_func_inline(sp_die)) {
1237 struct dwarf_callback_param _param;
1238 _param.data = (void *)lf;
1239 _param.retval = 0;
1240 dwarf_func_inline_instances(sp_die,
1241 line_range_inline_cb,
1242 &_param);
1243 param->retval = _param.retval;
1244 } else
1245 param->retval = find_line_range_by_line(sp_die, lf);
1246 return DWARF_CB_ABORT;
1247 }
1248 return DWARF_CB_OK;
1249}
1250
1251static int find_line_range_by_func(struct line_finder *lf)
1252{
1253 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1254 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
1255 return param.retval;
1256}
1257
1258int find_line_range(int fd, struct line_range *lr)
1259{
1260 struct line_finder lf = {.lr = lr, .found = 0};
1261 int ret = 0;
1262 Dwarf_Off off = 0, noff;
1263 size_t cuhl;
1264 Dwarf_Die *diep;
1265 Dwarf *dbg;
1266
1267 dbg = dwarf_begin(fd, DWARF_C_READ);
1268 if (!dbg) {
1269 pr_warning("No dwarf info found in the vmlinux - "
1270 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1271 return -EBADF;
1272 }
1273
1274 /* Loop on CUs (Compilation Unit) */
1275 while (!lf.found && ret >= 0) {
1276 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
700 break; 1277 break;
701 1278
702 /* Get the DIE(Debugging Information Entry) of this CU */ 1279 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 1280 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
704 DIE_IF(ret != DW_DLV_OK); 1281 if (!diep)
1282 continue;
705 1283
706 /* Check if target file is included. */ 1284 /* Check if target file is included. */
707 if (pp->file) 1285 if (lr->file)
708 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 1286 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
709 1287 else
710 if (!pp->file || pf.fno) { 1288 lf.fname = 0;
711 /* Save CU base address (for frame_base) */ 1289
712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 1290 if (!lr->file || lf.fname) {
713 DIE_IF(ret == DW_DLV_ERROR); 1291 if (lr->function)
714 if (ret == DW_DLV_NO_ENTRY) 1292 ret = find_line_range_by_func(&lf);
715 pf.cu_base = 0;
716 if (pp->function)
717 find_by_func(&pf);
718 else { 1293 else {
719 pf.lno = pp->line; 1294 lf.lno_s = lr->start;
720 find_by_line(&pf); 1295 lf.lno_e = lr->end;
1296 ret = find_line_range_by_line(NULL, &lf);
721 } 1297 }
722 } 1298 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 1299 off = noff;
724 } 1300 }
725 ret = dwarf_finish(__dw_debug, &__dw_error); 1301 pr_debug("path: %lx\n", (unsigned long)lr->path);
726 DIE_IF(ret != DW_DLV_OK); 1302 dwarf_end(dbg);
727 1303
728 return pp->found; 1304 return (ret < 0) ? ret : lf.found;
729} 1305}
730 1306
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index a4086aaddb73..e1f61dcd18ff 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,6 +1,10 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#include <stdbool.h>
5#include "util.h"
6#include "probe-event.h"
7
4#define MAX_PATH_LEN 256 8#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 9#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 10#define MAX_PROBES 128
@@ -11,55 +15,54 @@ static inline int is_c_varname(const char *name)
11 return isalpha(name[0]) || name[0] == '_'; 15 return isalpha(name[0]) || name[0] == '_';
12} 16}
13 17
14struct probe_point { 18#ifdef DWARF_SUPPORT
15 char *event; /* Event name */ 19/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
16 char *group; /* Event group */ 20extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
17 21 struct kprobe_trace_event **tevs,
18 /* Inputs */ 22 int max_tevs);
19 char *file; /* File name */
20 int line; /* Line number */
21 23
22 char *function; /* Function name */ 24/* Find a perf_probe_point from debuginfo */
23 int offset; /* Offset bytes */ 25extern int find_perf_probe_point(int fd, unsigned long addr,
26 struct perf_probe_point *ppt);
24 27
25 int nr_args; /* Number of arguments */ 28extern int find_line_range(int fd, struct line_range *lr);
26 char **args; /* Arguments */
27
28 int retprobe; /* Return probe */
29
30 /* Output */
31 int found; /* Number of found probe points */
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33};
34
35#ifndef NO_LIBDWARF
36extern int find_probepoint(int fd, struct probe_point *pp);
37
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
39#ifndef _MIPS_SZLONG
40# define _MIPS_SZLONG 0
41#endif
42 29
43#include <dwarf.h> 30#include <dwarf.h>
44#include <libdwarf.h> 31#include <libdw.h>
32#include <version.h>
45 33
46struct probe_finder { 34struct probe_finder {
47 struct probe_point *pp; /* Target probe point */ 35 struct perf_probe_event *pev; /* Target probe event */
36 struct kprobe_trace_event *tevs; /* Result trace events */
37 int ntevs; /* Number of trace events */
38 int max_tevs; /* Max number of trace events */
48 39
49 /* For function searching */ 40 /* For function searching */
50 Dwarf_Addr addr; /* Address */ 41 int lno; /* Line number */
51 Dwarf_Unsigned fno; /* File number */ 42 Dwarf_Addr addr; /* Address */
52 Dwarf_Unsigned lno; /* Line number */ 43 const char *fname; /* Real file name */
53 Dwarf_Off inl_offs; /* Inline offset */ 44 Dwarf_Die cu_die; /* Current CU */
54 Dwarf_Die cu_die; /* Current CU */ 45 struct list_head lcache; /* Line cache for lazy match */
55 46
56 /* For variable searching */ 47 /* For variable searching */
57 Dwarf_Addr cu_base; /* Current CU base address */ 48#if _ELFUTILS_PREREQ(0, 142)
58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 49 Dwarf_CFI *cfi; /* Call Frame Information */
59 const char *var; /* Current variable name */ 50#endif
60 char *buf; /* Current output buffer */ 51 Dwarf_Op *fb_ops; /* Frame base attribute */
61 int len; /* Length of output buffer */ 52 struct perf_probe_arg *pvar; /* Current target variable */
53 struct kprobe_trace_arg *tvar; /* Current result variable */
54};
55
56struct line_finder {
57 struct line_range *lr; /* Target line range */
58
59 const char *fname; /* File name */
60 int lno_s; /* Start line number */
61 int lno_e; /* End line number */
62 Dwarf_Die cu_die; /* Current CU */
63 int found;
62}; 64};
63#endif /* NO_LIBDWARF */ 65
66#endif /* DWARF_SUPPORT */
64 67
65#endif /*_PROBE_FINDER_H */ 68#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
new file mode 100644
index 000000000000..13d36faf64eb
--- /dev/null
+++ b/tools/perf/util/pstack.c
@@ -0,0 +1,75 @@
1/*
2 * Simple pointer stack
3 *
4 * (c) 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
5 */
6
7#include "util.h"
8#include "pstack.h"
9#include <linux/kernel.h>
10#include <stdlib.h>
11
12struct pstack {
13 unsigned short top;
14 unsigned short max_nr_entries;
15 void *entries[0];
16};
17
18struct pstack *pstack__new(unsigned short max_nr_entries)
19{
20 struct pstack *self = zalloc((sizeof(*self) +
21 max_nr_entries * sizeof(void *)));
22 if (self != NULL)
23 self->max_nr_entries = max_nr_entries;
24 return self;
25}
26
27void pstack__delete(struct pstack *self)
28{
29 free(self);
30}
31
32bool pstack__empty(const struct pstack *self)
33{
34 return self->top == 0;
35}
36
37void pstack__remove(struct pstack *self, void *key)
38{
39 unsigned short i = self->top, last_index = self->top - 1;
40
41 while (i-- != 0) {
42 if (self->entries[i] == key) {
43 if (i < last_index)
44 memmove(self->entries + i,
45 self->entries + i + 1,
46 (last_index - i) * sizeof(void *));
47 --self->top;
48 return;
49 }
50 }
51 pr_err("%s: %p not on the pstack!\n", __func__, key);
52}
53
54void pstack__push(struct pstack *self, void *key)
55{
56 if (self->top == self->max_nr_entries) {
57 pr_err("%s: top=%d, overflow!\n", __func__, self->top);
58 return;
59 }
60 self->entries[self->top++] = key;
61}
62
63void *pstack__pop(struct pstack *self)
64{
65 void *ret;
66
67 if (self->top == 0) {
68 pr_err("%s: underflow!\n", __func__);
69 return NULL;
70 }
71
72 ret = self->entries[--self->top];
73 self->entries[self->top] = NULL;
74 return ret;
75}
diff --git a/tools/perf/util/pstack.h b/tools/perf/util/pstack.h
new file mode 100644
index 000000000000..5ad07023504b
--- /dev/null
+++ b/tools/perf/util/pstack.h
@@ -0,0 +1,12 @@
1#ifndef _PERF_PSTACK_
2#define _PERF_PSTACK_
3
4struct pstack;
5struct pstack *pstack__new(unsigned short max_nr_entries);
6void pstack__delete(struct pstack *self);
7bool pstack__empty(const struct pstack *self);
8void pstack__remove(struct pstack *self, void *key);
9void pstack__push(struct pstack *self, void *key);
10void *pstack__pop(struct pstack *self);
11
12#endif /* _PERF_PSTACK_ */
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index 2726fe40eb5d..01f03242b86a 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -1,8 +1,6 @@
1#include "cache.h" 1#include "cache.h"
2#include "quote.h" 2#include "quote.h"
3 3
4int quote_path_fully = 1;
5
6/* Help to copy the thing properly quoted for the shell safety. 4/* Help to copy the thing properly quoted for the shell safety.
7 * any single quote is replaced with '\'', any exclamation point 5 * any single quote is replaced with '\'', any exclamation point
8 * is replaced with '\!', and the whole thing is enclosed in a 6 * is replaced with '\!', and the whole thing is enclosed in a
@@ -19,7 +17,7 @@ static inline int need_bs_quote(char c)
19 return (c == '\'' || c == '!'); 17 return (c == '\'' || c == '!');
20} 18}
21 19
22void sq_quote_buf(struct strbuf *dst, const char *src) 20static void sq_quote_buf(struct strbuf *dst, const char *src)
23{ 21{
24 char *to_free = NULL; 22 char *to_free = NULL;
25 23
@@ -41,23 +39,6 @@ void sq_quote_buf(struct strbuf *dst, const char *src)
41 free(to_free); 39 free(to_free);
42} 40}
43 41
44void sq_quote_print(FILE *stream, const char *src)
45{
46 char c;
47
48 fputc('\'', stream);
49 while ((c = *src++)) {
50 if (need_bs_quote(c)) {
51 fputs("'\\", stream);
52 fputc(c, stream);
53 fputc('\'', stream);
54 } else {
55 fputc(c, stream);
56 }
57 }
58 fputc('\'', stream);
59}
60
61void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) 42void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
62{ 43{
63 int i; 44 int i;
@@ -71,415 +52,3 @@ void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
71 die("Too many or long arguments"); 52 die("Too many or long arguments");
72 } 53 }
73} 54}
74
75char *sq_dequote_step(char *arg, char **next)
76{
77 char *dst = arg;
78 char *src = arg;
79 char c;
80
81 if (*src != '\'')
82 return NULL;
83 for (;;) {
84 c = *++src;
85 if (!c)
86 return NULL;
87 if (c != '\'') {
88 *dst++ = c;
89 continue;
90 }
91 /* We stepped out of sq */
92 switch (*++src) {
93 case '\0':
94 *dst = 0;
95 if (next)
96 *next = NULL;
97 return arg;
98 case '\\':
99 c = *++src;
100 if (need_bs_quote(c) && *++src == '\'') {
101 *dst++ = c;
102 continue;
103 }
104 /* Fallthrough */
105 default:
106 if (!next || !isspace(*src))
107 return NULL;
108 do {
109 c = *++src;
110 } while (isspace(c));
111 *dst = 0;
112 *next = src;
113 return arg;
114 }
115 }
116}
117
118char *sq_dequote(char *arg)
119{
120 return sq_dequote_step(arg, NULL);
121}
122
123int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc)
124{
125 char *next = arg;
126
127 if (!*arg)
128 return 0;
129 do {
130 char *dequoted = sq_dequote_step(next, &next);
131 if (!dequoted)
132 return -1;
133 ALLOC_GROW(*argv, *nr + 1, *alloc);
134 (*argv)[(*nr)++] = dequoted;
135 } while (next);
136
137 return 0;
138}
139
140/* 1 means: quote as octal
141 * 0 means: quote as octal if (quote_path_fully)
142 * -1 means: never quote
143 * c: quote as "\\c"
144 */
145#define X8(x) x, x, x, x, x, x, x, x
146#define X16(x) X8(x), X8(x)
147static signed char const sq_lookup[256] = {
148 /* 0 1 2 3 4 5 6 7 */
149 /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a',
150 /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1,
151 /* 0x10 */ X16(1),
152 /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1,
153 /* 0x28 */ X16(-1), X16(-1), X16(-1),
154 /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1,
155 /* 0x60 */ X16(-1), X8(-1),
156 /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1,
157 /* 0x80 */ /* set to 0 */
158};
159
160static inline int sq_must_quote(char c)
161{
162 return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
163}
164
165/*
166 * Returns the longest prefix not needing a quote up to maxlen if
167 * positive.
168 * This stops at the first \0 because it's marked as a character
169 * needing an escape.
170 */
171static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
172{
173 ssize_t len;
174
175 if (maxlen < 0) {
176 for (len = 0; !sq_must_quote(s[len]); len++);
177 } else {
178 for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
179 }
180 return len;
181}
182
183/*
184 * C-style name quoting.
185 *
186 * (1) if sb and fp are both NULL, inspect the input name and counts the
187 * number of bytes that are needed to hold c_style quoted version of name,
188 * counting the double quotes around it but not terminating NUL, and
189 * returns it.
190 * However, if name does not need c_style quoting, it returns 0.
191 *
192 * (2) if sb or fp are not NULL, it emits the c_style quoted version
193 * of name, enclosed with double quotes if asked and needed only.
194 * Return value is the same as in (1).
195 */
196static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
197 struct strbuf *sb, FILE *fp, int no_dq)
198{
199#define EMIT(c) \
200 do { \
201 if (sb) strbuf_addch(sb, (c)); \
202 if (fp) fputc((c), fp); \
203 count++; \
204 } while (0)
205
206#define EMITBUF(s, l) \
207 do { \
208 int __ret; \
209 if (sb) strbuf_add(sb, (s), (l)); \
210 if (fp) __ret = fwrite((s), (l), 1, fp); \
211 count += (l); \
212 } while (0)
213
214 ssize_t len, count = 0;
215 const char *p = name;
216
217 for (;;) {
218 int ch;
219
220 len = next_quote_pos(p, maxlen);
221 if (len == maxlen || !p[len])
222 break;
223
224 if (!no_dq && p == name)
225 EMIT('"');
226
227 EMITBUF(p, len);
228 EMIT('\\');
229 p += len;
230 ch = (unsigned char)*p++;
231 if (sq_lookup[ch] >= ' ') {
232 EMIT(sq_lookup[ch]);
233 } else {
234 EMIT(((ch >> 6) & 03) + '0');
235 EMIT(((ch >> 3) & 07) + '0');
236 EMIT(((ch >> 0) & 07) + '0');
237 }
238 }
239
240 EMITBUF(p, len);
241 if (p == name) /* no ending quote needed */
242 return 0;
243
244 if (!no_dq)
245 EMIT('"');
246 return count;
247}
248
249size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
250{
251 return quote_c_style_counted(name, -1, sb, fp, nodq);
252}
253
254void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq)
255{
256 if (quote_c_style(prefix, NULL, NULL, 0) ||
257 quote_c_style(path, NULL, NULL, 0)) {
258 if (!nodq)
259 strbuf_addch(sb, '"');
260 quote_c_style(prefix, sb, NULL, 1);
261 quote_c_style(path, sb, NULL, 1);
262 if (!nodq)
263 strbuf_addch(sb, '"');
264 } else {
265 strbuf_addstr(sb, prefix);
266 strbuf_addstr(sb, path);
267 }
268}
269
270void write_name_quoted(const char *name, FILE *fp, int terminator)
271{
272 if (terminator) {
273 quote_c_style(name, NULL, fp, 0);
274 } else {
275 fputs(name, fp);
276 }
277 fputc(terminator, fp);
278}
279
280void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
281 const char *name, FILE *fp, int terminator)
282{
283 int needquote = 0;
284
285 if (terminator) {
286 needquote = next_quote_pos(pfx, pfxlen) < pfxlen
287 || name[next_quote_pos(name, -1)];
288 }
289 if (needquote) {
290 fputc('"', fp);
291 quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
292 quote_c_style(name, NULL, fp, 1);
293 fputc('"', fp);
294 } else {
295 int ret;
296
297 ret = fwrite(pfx, pfxlen, 1, fp);
298 fputs(name, fp);
299 }
300 fputc(terminator, fp);
301}
302
303/* quote path as relative to the given prefix */
304char *quote_path_relative(const char *in, int len,
305 struct strbuf *out, const char *prefix)
306{
307 int needquote;
308
309 if (len < 0)
310 len = strlen(in);
311
312 /* "../" prefix itself does not need quoting, but "in" might. */
313 needquote = (next_quote_pos(in, len) < len);
314 strbuf_setlen(out, 0);
315 strbuf_grow(out, len);
316
317 if (needquote)
318 strbuf_addch(out, '"');
319 if (prefix) {
320 int off = 0;
321 while (off < len && prefix[off] && prefix[off] == in[off])
322 if (prefix[off] == '/') {
323 prefix += off + 1;
324 in += off + 1;
325 len -= off + 1;
326 off = 0;
327 } else
328 off++;
329
330 for (; *prefix; prefix++)
331 if (*prefix == '/')
332 strbuf_addstr(out, "../");
333 }
334
335 quote_c_style_counted (in, len, out, NULL, 1);
336
337 if (needquote)
338 strbuf_addch(out, '"');
339 if (!out->len)
340 strbuf_addstr(out, "./");
341
342 return out->buf;
343}
344
345/*
346 * C-style name unquoting.
347 *
348 * Quoted should point at the opening double quote.
349 * + Returns 0 if it was able to unquote the string properly, and appends the
350 * result in the strbuf `sb'.
351 * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
352 * that this function will allocate memory in the strbuf, so calling
353 * strbuf_release is mandatory whichever result unquote_c_style returns.
354 *
355 * Updates endp pointer to point at one past the ending double quote if given.
356 */
357int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
358{
359 size_t oldlen = sb->len, len;
360 int ch, ac;
361
362 if (*quoted++ != '"')
363 return -1;
364
365 for (;;) {
366 len = strcspn(quoted, "\"\\");
367 strbuf_add(sb, quoted, len);
368 quoted += len;
369
370 switch (*quoted++) {
371 case '"':
372 if (endp)
373 *endp = quoted;
374 return 0;
375 case '\\':
376 break;
377 default:
378 goto error;
379 }
380
381 switch ((ch = *quoted++)) {
382 case 'a': ch = '\a'; break;
383 case 'b': ch = '\b'; break;
384 case 'f': ch = '\f'; break;
385 case 'n': ch = '\n'; break;
386 case 'r': ch = '\r'; break;
387 case 't': ch = '\t'; break;
388 case 'v': ch = '\v'; break;
389
390 case '\\': case '"':
391 break; /* verbatim */
392
393 /* octal values with first digit over 4 overflow */
394 case '0': case '1': case '2': case '3':
395 ac = ((ch - '0') << 6);
396 if ((ch = *quoted++) < '0' || '7' < ch)
397 goto error;
398 ac |= ((ch - '0') << 3);
399 if ((ch = *quoted++) < '0' || '7' < ch)
400 goto error;
401 ac |= (ch - '0');
402 ch = ac;
403 break;
404 default:
405 goto error;
406 }
407 strbuf_addch(sb, ch);
408 }
409
410 error:
411 strbuf_setlen(sb, oldlen);
412 return -1;
413}
414
415/* quoting as a string literal for other languages */
416
417void perl_quote_print(FILE *stream, const char *src)
418{
419 const char sq = '\'';
420 const char bq = '\\';
421 char c;
422
423 fputc(sq, stream);
424 while ((c = *src++)) {
425 if (c == sq || c == bq)
426 fputc(bq, stream);
427 fputc(c, stream);
428 }
429 fputc(sq, stream);
430}
431
432void python_quote_print(FILE *stream, const char *src)
433{
434 const char sq = '\'';
435 const char bq = '\\';
436 const char nl = '\n';
437 char c;
438
439 fputc(sq, stream);
440 while ((c = *src++)) {
441 if (c == nl) {
442 fputc(bq, stream);
443 fputc('n', stream);
444 continue;
445 }
446 if (c == sq || c == bq)
447 fputc(bq, stream);
448 fputc(c, stream);
449 }
450 fputc(sq, stream);
451}
452
453void tcl_quote_print(FILE *stream, const char *src)
454{
455 char c;
456
457 fputc('"', stream);
458 while ((c = *src++)) {
459 switch (c) {
460 case '[': case ']':
461 case '{': case '}':
462 case '$': case '\\': case '"':
463 fputc('\\', stream);
464 default:
465 fputc(c, stream);
466 break;
467 case '\f':
468 fputs("\\f", stream);
469 break;
470 case '\r':
471 fputs("\\r", stream);
472 break;
473 case '\n':
474 fputs("\\n", stream);
475 break;
476 case '\t':
477 fputs("\\t", stream);
478 break;
479 case '\v':
480 fputs("\\v", stream);
481 break;
482 }
483 }
484 fputc('"', stream);
485}
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index b6a019733919..172889ea234f 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -22,47 +22,8 @@
22 * 22 *
23 * Note that the above examples leak memory! Remember to free result from 23 * Note that the above examples leak memory! Remember to free result from
24 * sq_quote() in a real application. 24 * sq_quote() in a real application.
25 *
26 * sq_quote_buf() writes to an existing buffer of specified size; it
27 * will return the number of characters that would have been written
28 * excluding the final null regardless of the buffer size.
29 */ 25 */
30 26
31extern void sq_quote_print(FILE *stream, const char *src);
32
33extern void sq_quote_buf(struct strbuf *, const char *src);
34extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); 27extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
35 28
36/* This unwraps what sq_quote() produces in place, but returns
37 * NULL if the input does not look like what sq_quote would have
38 * produced.
39 */
40extern char *sq_dequote(char *);
41
42/*
43 * Same as the above, but can be used to unwrap many arguments in the
44 * same string separated by space. "next" is changed to point to the
45 * next argument that should be passed as first parameter. When there
46 * is no more argument to be dequoted, "next" is updated to point to NULL.
47 */
48extern char *sq_dequote_step(char *arg, char **next);
49extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc);
50
51extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp);
52extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq);
53extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
54
55extern void write_name_quoted(const char *name, FILE *, int terminator);
56extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
57 const char *name, FILE *, int terminator);
58
59/* quote path as relative to the given prefix */
60char *quote_path_relative(const char *in, int len,
61 struct strbuf *out, const char *prefix);
62
63/* quoting as a string literal for other languages */
64extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src);
67
68#endif /* __PERF_QUOTE_H */ 29#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
index 2b615acf94d7..da8e9b285f51 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/perf/util/run-command.c
@@ -212,93 +212,3 @@ int run_command_v_opt(const char **argv, int opt)
212 prepare_run_command_v_opt(&cmd, argv, opt); 212 prepare_run_command_v_opt(&cmd, argv, opt);
213 return run_command(&cmd); 213 return run_command(&cmd);
214} 214}
215
216int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
217{
218 struct child_process cmd;
219 prepare_run_command_v_opt(&cmd, argv, opt);
220 cmd.dir = dir;
221 cmd.env = env;
222 return run_command(&cmd);
223}
224
225int start_async(struct async *async)
226{
227 int pipe_out[2];
228
229 if (pipe(pipe_out) < 0)
230 return error("cannot create pipe: %s", strerror(errno));
231 async->out = pipe_out[0];
232
233 /* Flush stdio before fork() to avoid cloning buffers */
234 fflush(NULL);
235
236 async->pid = fork();
237 if (async->pid < 0) {
238 error("fork (async) failed: %s", strerror(errno));
239 close_pair(pipe_out);
240 return -1;
241 }
242 if (!async->pid) {
243 close(pipe_out[0]);
244 exit(!!async->proc(pipe_out[1], async->data));
245 }
246 close(pipe_out[1]);
247
248 return 0;
249}
250
251int finish_async(struct async *async)
252{
253 int ret = 0;
254
255 if (wait_or_whine(async->pid))
256 ret = error("waitpid (async) failed");
257
258 return ret;
259}
260
261int run_hook(const char *index_file, const char *name, ...)
262{
263 struct child_process hook;
264 const char **argv = NULL, *env[2];
265 char idx[PATH_MAX];
266 va_list args;
267 int ret;
268 size_t i = 0, alloc = 0;
269
270 if (access(perf_path("hooks/%s", name), X_OK) < 0)
271 return 0;
272
273 va_start(args, name);
274 ALLOC_GROW(argv, i + 1, alloc);
275 argv[i++] = perf_path("hooks/%s", name);
276 while (argv[i-1]) {
277 ALLOC_GROW(argv, i + 1, alloc);
278 argv[i++] = va_arg(args, const char *);
279 }
280 va_end(args);
281
282 memset(&hook, 0, sizeof(hook));
283 hook.argv = argv;
284 hook.no_stdin = 1;
285 hook.stdout_to_stderr = 1;
286 if (index_file) {
287 snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file);
288 env[0] = idx;
289 env[1] = NULL;
290 hook.env = env;
291 }
292
293 ret = start_command(&hook);
294 free(argv);
295 if (ret) {
296 warning("Could not spawn %s", argv[0]);
297 return ret;
298 }
299 ret = finish_command(&hook);
300 if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
301 warning("%s exited due to uncaught signal", argv[0]);
302
303 return ret;
304}
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index d79028727ce2..1ef264d5069c 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -50,39 +50,9 @@ int start_command(struct child_process *);
50int finish_command(struct child_process *); 50int finish_command(struct child_process *);
51int run_command(struct child_process *); 51int run_command(struct child_process *);
52 52
53extern int run_hook(const char *index_file, const char *name, ...);
54
55#define RUN_COMMAND_NO_STDIN 1 53#define RUN_COMMAND_NO_STDIN 1
56#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */ 54#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */
57#define RUN_COMMAND_STDOUT_TO_STDERR 4 55#define RUN_COMMAND_STDOUT_TO_STDERR 4
58int run_command_v_opt(const char **argv, int opt); 56int run_command_v_opt(const char **argv, int opt);
59 57
60/*
61 * env (the environment) is to be formatted like environ: "VAR=VALUE".
62 * To unset an environment variable use just "VAR".
63 */
64int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
65
66/*
67 * The purpose of the following functions is to feed a pipe by running
68 * a function asynchronously and providing output that the caller reads.
69 *
70 * It is expected that no synchronization and mutual exclusion between
71 * the caller and the feed function is necessary so that the function
72 * can run in a thread without interfering with the caller.
73 */
74struct async {
75 /*
76 * proc writes to fd and closes it;
77 * returns 0 on success, non-zero on failure
78 */
79 int (*proc)(int fd, void *data);
80 void *data;
81 int out; /* caller reads from here and closes it */
82 pid_t pid;
83};
84
85int start_async(struct async *async);
86int finish_async(struct async *async);
87
88#endif /* __PERF_RUN_COMMAND_H */ 58#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 6d6d76b8a21e..b059dc50cc2d 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -25,10 +25,16 @@
25#include <ctype.h> 25#include <ctype.h>
26#include <errno.h> 26#include <errno.h>
27 27
28#include "../perf.h" 28#include "../../perf.h"
29#include "util.h" 29#include "../util.h"
30#include "trace-event.h" 30#include "../trace-event.h"
31#include "trace-event-perl.h" 31
32#include <EXTERN.h>
33#include <perl.h>
34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37typedef PerlInterpreter * INTERP;
32 38
33void xs_init(pTHX); 39void xs_init(pTHX);
34 40
@@ -49,7 +55,7 @@ INTERP my_perl;
49 55
50struct event *events[FTRACE_MAX_EVENT]; 56struct event *events[FTRACE_MAX_EVENT];
51 57
52static struct scripting_context *scripting_context; 58extern struct scripting_context *scripting_context;
53 59
54static char *cur_field_name; 60static char *cur_field_name;
55static int zero_flag_atom; 61static int zero_flag_atom;
@@ -239,33 +245,6 @@ static inline struct event *find_cache_event(int type)
239 return event; 245 return event;
240} 246}
241 247
242int common_pc(struct scripting_context *context)
243{
244 int pc;
245
246 pc = parse_common_pc(context->event_data);
247
248 return pc;
249}
250
251int common_flags(struct scripting_context *context)
252{
253 int flags;
254
255 flags = parse_common_flags(context->event_data);
256
257 return flags;
258}
259
260int common_lock_depth(struct scripting_context *context)
261{
262 int lock_depth;
263
264 lock_depth = parse_common_lock_depth(context->event_data);
265
266 return lock_depth;
267}
268
269static void perl_process_event(int cpu, void *data, 248static void perl_process_event(int cpu, void *data,
270 int size __unused, 249 int size __unused,
271 unsigned long long nsecs, char *comm) 250 unsigned long long nsecs, char *comm)
@@ -392,7 +371,6 @@ static int perl_start_script(const char *script, int argc, const char **argv)
392 run_start_sub(); 371 run_start_sub();
393 372
394 free(command_line); 373 free(command_line);
395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
396 return 0; 374 return 0;
397error: 375error:
398 perl_free(my_perl); 376 perl_free(my_perl);
@@ -415,8 +393,6 @@ static int perl_stop_script(void)
415 perl_destruct(my_perl); 393 perl_destruct(my_perl);
416 perl_free(my_perl); 394 perl_free(my_perl);
417 395
418 fprintf(stderr, "\nperf trace Perl script stopped\n");
419
420 return 0; 396 return 0;
421} 397}
422 398
@@ -587,75 +563,3 @@ struct scripting_ops perl_scripting_ops = {
587 .process_event = perl_process_event, 563 .process_event = perl_process_event,
588 .generate_script = perl_generate_script, 564 .generate_script = perl_generate_script,
589}; 565};
590
591static void print_unsupported_msg(void)
592{
593 fprintf(stderr, "Perl scripting not supported."
594 " Install libperl and rebuild perf to enable it.\n"
595 "For example:\n # apt-get install libperl-dev (ubuntu)"
596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
598}
599
600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609static int perl_stop_script_unsupported(void)
610{
611 return 0;
612}
613
614static void perl_process_event_unsupported(int cpu __unused,
615 void *data __unused,
616 int size __unused,
617 unsigned long long nsecs __unused,
618 char *comm __unused)
619{
620}
621
622static int perl_generate_script_unsupported(const char *outfile __unused)
623{
624 print_unsupported_msg();
625
626 return -1;
627}
628
629struct scripting_ops perl_scripting_unsupported_ops = {
630 .name = "Perl",
631 .start_script = perl_start_script_unsupported,
632 .stop_script = perl_stop_script_unsupported,
633 .process_event = perl_process_event_unsupported,
634 .generate_script = perl_generate_script_unsupported,
635};
636
637static void register_perl_scripting(struct scripting_ops *scripting_ops)
638{
639 int err;
640 err = script_spec_register("Perl", scripting_ops);
641 if (err)
642 die("error registering Perl script extension");
643
644 err = script_spec_register("pl", scripting_ops);
645 if (err)
646 die("error registering pl script extension");
647
648 scripting_context = malloc(sizeof(struct scripting_context));
649}
650
651#ifdef NO_LIBPERL
652void setup_perl_scripting(void)
653{
654 register_perl_scripting(&perl_scripting_unsupported_ops);
655}
656#else
657void setup_perl_scripting(void)
658{
659 register_perl_scripting(&perl_scripting_ops);
660}
661#endif
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
new file mode 100644
index 000000000000..33a632523743
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -0,0 +1,594 @@
1/*
2 * trace-event-python. Feed trace events to an embedded Python interpreter.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <errno.h>
29
30#include "../../perf.h"
31#include "../util.h"
32#include "../trace-event.h"
33
34PyMODINIT_FUNC initperf_trace_context(void);
35
36#define FTRACE_MAX_EVENT \
37 ((1 << (sizeof(unsigned short) * 8)) - 1)
38
39struct event *events[FTRACE_MAX_EVENT];
40
41#define MAX_FIELDS 64
42#define N_COMMON_FIELDS 7
43
44extern struct scripting_context *scripting_context;
45
46static char *cur_field_name;
47static int zero_flag_atom;
48
49static PyObject *main_module, *main_dict;
50
51static void handler_call_die(const char *handler_name)
52{
53 PyErr_Print();
54 Py_FatalError("problem in Python trace event handler");
55}
56
57static void define_value(enum print_arg_type field_type,
58 const char *ev_name,
59 const char *field_name,
60 const char *field_value,
61 const char *field_str)
62{
63 const char *handler_name = "define_flag_value";
64 PyObject *handler, *t, *retval;
65 unsigned long long value;
66 unsigned n = 0;
67
68 if (field_type == PRINT_SYMBOL)
69 handler_name = "define_symbolic_value";
70
71 t = PyTuple_New(4);
72 if (!t)
73 Py_FatalError("couldn't create Python tuple");
74
75 value = eval_flag(field_value);
76
77 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
78 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
79 PyTuple_SetItem(t, n++, PyInt_FromLong(value));
80 PyTuple_SetItem(t, n++, PyString_FromString(field_str));
81
82 handler = PyDict_GetItemString(main_dict, handler_name);
83 if (handler && PyCallable_Check(handler)) {
84 retval = PyObject_CallObject(handler, t);
85 if (retval == NULL)
86 handler_call_die(handler_name);
87 }
88
89 Py_DECREF(t);
90}
91
92static void define_values(enum print_arg_type field_type,
93 struct print_flag_sym *field,
94 const char *ev_name,
95 const char *field_name)
96{
97 define_value(field_type, ev_name, field_name, field->value,
98 field->str);
99
100 if (field->next)
101 define_values(field_type, field->next, ev_name, field_name);
102}
103
104static void define_field(enum print_arg_type field_type,
105 const char *ev_name,
106 const char *field_name,
107 const char *delim)
108{
109 const char *handler_name = "define_flag_field";
110 PyObject *handler, *t, *retval;
111 unsigned n = 0;
112
113 if (field_type == PRINT_SYMBOL)
114 handler_name = "define_symbolic_field";
115
116 if (field_type == PRINT_FLAGS)
117 t = PyTuple_New(3);
118 else
119 t = PyTuple_New(2);
120 if (!t)
121 Py_FatalError("couldn't create Python tuple");
122
123 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
124 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
125 if (field_type == PRINT_FLAGS)
126 PyTuple_SetItem(t, n++, PyString_FromString(delim));
127
128 handler = PyDict_GetItemString(main_dict, handler_name);
129 if (handler && PyCallable_Check(handler)) {
130 retval = PyObject_CallObject(handler, t);
131 if (retval == NULL)
132 handler_call_die(handler_name);
133 }
134
135 Py_DECREF(t);
136}
137
138static void define_event_symbols(struct event *event,
139 const char *ev_name,
140 struct print_arg *args)
141{
142 switch (args->type) {
143 case PRINT_NULL:
144 break;
145 case PRINT_ATOM:
146 define_value(PRINT_FLAGS, ev_name, cur_field_name, "0",
147 args->atom.atom);
148 zero_flag_atom = 0;
149 break;
150 case PRINT_FIELD:
151 if (cur_field_name)
152 free(cur_field_name);
153 cur_field_name = strdup(args->field.name);
154 break;
155 case PRINT_FLAGS:
156 define_event_symbols(event, ev_name, args->flags.field);
157 define_field(PRINT_FLAGS, ev_name, cur_field_name,
158 args->flags.delim);
159 define_values(PRINT_FLAGS, args->flags.flags, ev_name,
160 cur_field_name);
161 break;
162 case PRINT_SYMBOL:
163 define_event_symbols(event, ev_name, args->symbol.field);
164 define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL);
165 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
166 cur_field_name);
167 break;
168 case PRINT_STRING:
169 break;
170 case PRINT_TYPE:
171 define_event_symbols(event, ev_name, args->typecast.item);
172 break;
173 case PRINT_OP:
174 if (strcmp(args->op.op, ":") == 0)
175 zero_flag_atom = 1;
176 define_event_symbols(event, ev_name, args->op.left);
177 define_event_symbols(event, ev_name, args->op.right);
178 break;
179 default:
180 /* we should warn... */
181 return;
182 }
183
184 if (args->next)
185 define_event_symbols(event, ev_name, args->next);
186}
187
188static inline struct event *find_cache_event(int type)
189{
190 static char ev_name[256];
191 struct event *event;
192
193 if (events[type])
194 return events[type];
195
196 events[type] = event = trace_find_event(type);
197 if (!event)
198 return NULL;
199
200 sprintf(ev_name, "%s__%s", event->system, event->name);
201
202 define_event_symbols(event, ev_name, event->print_fmt.args);
203
204 return event;
205}
206
207static void python_process_event(int cpu, void *data,
208 int size __unused,
209 unsigned long long nsecs, char *comm)
210{
211 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
212 static char handler_name[256];
213 struct format_field *field;
214 unsigned long long val;
215 unsigned long s, ns;
216 struct event *event;
217 unsigned n = 0;
218 int type;
219 int pid;
220
221 t = PyTuple_New(MAX_FIELDS);
222 if (!t)
223 Py_FatalError("couldn't create Python tuple");
224
225 type = trace_parse_common_type(data);
226
227 event = find_cache_event(type);
228 if (!event)
229 die("ug! no event found for type %d", type);
230
231 pid = trace_parse_common_pid(data);
232
233 sprintf(handler_name, "%s__%s", event->system, event->name);
234
235 handler = PyDict_GetItemString(main_dict, handler_name);
236 if (handler && !PyCallable_Check(handler))
237 handler = NULL;
238 if (!handler) {
239 dict = PyDict_New();
240 if (!dict)
241 Py_FatalError("couldn't create Python dict");
242 }
243 s = nsecs / NSECS_PER_SEC;
244 ns = nsecs - s * NSECS_PER_SEC;
245
246 scripting_context->event_data = data;
247
248 context = PyCObject_FromVoidPtr(scripting_context, NULL);
249
250 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
251 PyTuple_SetItem(t, n++,
252 PyCObject_FromVoidPtr(scripting_context, NULL));
253
254 if (handler) {
255 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
256 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
257 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
258 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
259 PyTuple_SetItem(t, n++, PyString_FromString(comm));
260 } else {
261 PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu));
262 PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s));
263 PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns));
264 PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid));
265 PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm));
266 }
267 for (field = event->format.fields; field; field = field->next) {
268 if (field->flags & FIELD_IS_STRING) {
269 int offset;
270 if (field->flags & FIELD_IS_DYNAMIC) {
271 offset = *(int *)(data + field->offset);
272 offset &= 0xffff;
273 } else
274 offset = field->offset;
275 obj = PyString_FromString((char *)data + offset);
276 } else { /* FIELD_IS_NUMERIC */
277 val = read_size(data + field->offset, field->size);
278 if (field->flags & FIELD_IS_SIGNED) {
279 if ((long long)val >= LONG_MIN &&
280 (long long)val <= LONG_MAX)
281 obj = PyInt_FromLong(val);
282 else
283 obj = PyLong_FromLongLong(val);
284 } else {
285 if (val <= LONG_MAX)
286 obj = PyInt_FromLong(val);
287 else
288 obj = PyLong_FromUnsignedLongLong(val);
289 }
290 }
291 if (handler)
292 PyTuple_SetItem(t, n++, obj);
293 else
294 PyDict_SetItemString(dict, field->name, obj);
295
296 }
297 if (!handler)
298 PyTuple_SetItem(t, n++, dict);
299
300 if (_PyTuple_Resize(&t, n) == -1)
301 Py_FatalError("error resizing Python tuple");
302
303 if (handler) {
304 retval = PyObject_CallObject(handler, t);
305 if (retval == NULL)
306 handler_call_die(handler_name);
307 } else {
308 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
309 if (handler && PyCallable_Check(handler)) {
310
311 retval = PyObject_CallObject(handler, t);
312 if (retval == NULL)
313 handler_call_die("trace_unhandled");
314 }
315 Py_DECREF(dict);
316 }
317
318 Py_DECREF(t);
319}
320
321static int run_start_sub(void)
322{
323 PyObject *handler, *retval;
324 int err = 0;
325
326 main_module = PyImport_AddModule("__main__");
327 if (main_module == NULL)
328 return -1;
329 Py_INCREF(main_module);
330
331 main_dict = PyModule_GetDict(main_module);
332 if (main_dict == NULL) {
333 err = -1;
334 goto error;
335 }
336 Py_INCREF(main_dict);
337
338 handler = PyDict_GetItemString(main_dict, "trace_begin");
339 if (handler == NULL || !PyCallable_Check(handler))
340 goto out;
341
342 retval = PyObject_CallObject(handler, NULL);
343 if (retval == NULL)
344 handler_call_die("trace_begin");
345
346 Py_DECREF(retval);
347 return err;
348error:
349 Py_XDECREF(main_dict);
350 Py_XDECREF(main_module);
351out:
352 return err;
353}
354
355/*
356 * Start trace script
357 */
358static int python_start_script(const char *script, int argc, const char **argv)
359{
360 const char **command_line;
361 char buf[PATH_MAX];
362 int i, err = 0;
363 FILE *fp;
364
365 command_line = malloc((argc + 1) * sizeof(const char *));
366 command_line[0] = script;
367 for (i = 1; i < argc + 1; i++)
368 command_line[i] = argv[i - 1];
369
370 Py_Initialize();
371
372 initperf_trace_context();
373
374 PySys_SetArgv(argc + 1, (char **)command_line);
375
376 fp = fopen(script, "r");
377 if (!fp) {
378 sprintf(buf, "Can't open python script \"%s\"", script);
379 perror(buf);
380 err = -1;
381 goto error;
382 }
383
384 err = PyRun_SimpleFile(fp, script);
385 if (err) {
386 fprintf(stderr, "Error running python script %s\n", script);
387 goto error;
388 }
389
390 err = run_start_sub();
391 if (err) {
392 fprintf(stderr, "Error starting python script %s\n", script);
393 goto error;
394 }
395
396 free(command_line);
397
398 return err;
399error:
400 Py_Finalize();
401 free(command_line);
402
403 return err;
404}
405
406/*
407 * Stop trace script
408 */
409static int python_stop_script(void)
410{
411 PyObject *handler, *retval;
412 int err = 0;
413
414 handler = PyDict_GetItemString(main_dict, "trace_end");
415 if (handler == NULL || !PyCallable_Check(handler))
416 goto out;
417
418 retval = PyObject_CallObject(handler, NULL);
419 if (retval == NULL)
420 handler_call_die("trace_end");
421 else
422 Py_DECREF(retval);
423out:
424 Py_XDECREF(main_dict);
425 Py_XDECREF(main_module);
426 Py_Finalize();
427
428 return err;
429}
430
431static int python_generate_script(const char *outfile)
432{
433 struct event *event = NULL;
434 struct format_field *f;
435 char fname[PATH_MAX];
436 int not_first, count;
437 FILE *ofp;
438
439 sprintf(fname, "%s.py", outfile);
440 ofp = fopen(fname, "w");
441 if (ofp == NULL) {
442 fprintf(stderr, "couldn't open %s\n", fname);
443 return -1;
444 }
445 fprintf(ofp, "# perf trace event handlers, "
446 "generated by perf trace -g python\n");
447
448 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
449 " License version 2\n\n");
450
451 fprintf(ofp, "# The common_* event handler fields are the most useful "
452 "fields common to\n");
453
454 fprintf(ofp, "# all events. They don't necessarily correspond to "
455 "the 'common_*' fields\n");
456
457 fprintf(ofp, "# in the format files. Those fields not available as "
458 "handler params can\n");
459
460 fprintf(ofp, "# be retrieved using Python functions of the form "
461 "common_*(context).\n");
462
463 fprintf(ofp, "# See the perf-trace-python Documentation for the list "
464 "of available functions.\n\n");
465
466 fprintf(ofp, "import os\n");
467 fprintf(ofp, "import sys\n\n");
468
469 fprintf(ofp, "sys.path.append(os.environ['PERF_EXEC_PATH'] + \\\n");
470 fprintf(ofp, "\t'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')\n");
471 fprintf(ofp, "\nfrom perf_trace_context import *\n");
472 fprintf(ofp, "from Core import *\n\n\n");
473
474 fprintf(ofp, "def trace_begin():\n");
475 fprintf(ofp, "\tprint \"in trace_begin\"\n\n");
476
477 fprintf(ofp, "def trace_end():\n");
478 fprintf(ofp, "\tprint \"in trace_end\"\n\n");
479
480 while ((event = trace_find_next_event(event))) {
481 fprintf(ofp, "def %s__%s(", event->system, event->name);
482 fprintf(ofp, "event_name, ");
483 fprintf(ofp, "context, ");
484 fprintf(ofp, "common_cpu,\n");
485 fprintf(ofp, "\tcommon_secs, ");
486 fprintf(ofp, "common_nsecs, ");
487 fprintf(ofp, "common_pid, ");
488 fprintf(ofp, "common_comm,\n\t");
489
490 not_first = 0;
491 count = 0;
492
493 for (f = event->format.fields; f; f = f->next) {
494 if (not_first++)
495 fprintf(ofp, ", ");
496 if (++count % 5 == 0)
497 fprintf(ofp, "\n\t");
498
499 fprintf(ofp, "%s", f->name);
500 }
501 fprintf(ofp, "):\n");
502
503 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
504 "common_secs, common_nsecs,\n\t\t\t"
505 "common_pid, common_comm)\n\n");
506
507 fprintf(ofp, "\t\tprint \"");
508
509 not_first = 0;
510 count = 0;
511
512 for (f = event->format.fields; f; f = f->next) {
513 if (not_first++)
514 fprintf(ofp, ", ");
515 if (count && count % 3 == 0) {
516 fprintf(ofp, "\" \\\n\t\t\"");
517 }
518 count++;
519
520 fprintf(ofp, "%s=", f->name);
521 if (f->flags & FIELD_IS_STRING ||
522 f->flags & FIELD_IS_FLAG ||
523 f->flags & FIELD_IS_SYMBOLIC)
524 fprintf(ofp, "%%s");
525 else if (f->flags & FIELD_IS_SIGNED)
526 fprintf(ofp, "%%d");
527 else
528 fprintf(ofp, "%%u");
529 }
530
531 fprintf(ofp, "\\n\" %% \\\n\t\t(");
532
533 not_first = 0;
534 count = 0;
535
536 for (f = event->format.fields; f; f = f->next) {
537 if (not_first++)
538 fprintf(ofp, ", ");
539
540 if (++count % 5 == 0)
541 fprintf(ofp, "\n\t\t");
542
543 if (f->flags & FIELD_IS_FLAG) {
544 if ((count - 1) % 5 != 0) {
545 fprintf(ofp, "\n\t\t");
546 count = 4;
547 }
548 fprintf(ofp, "flag_str(\"");
549 fprintf(ofp, "%s__%s\", ", event->system,
550 event->name);
551 fprintf(ofp, "\"%s\", %s)", f->name,
552 f->name);
553 } else if (f->flags & FIELD_IS_SYMBOLIC) {
554 if ((count - 1) % 5 != 0) {
555 fprintf(ofp, "\n\t\t");
556 count = 4;
557 }
558 fprintf(ofp, "symbol_str(\"");
559 fprintf(ofp, "%s__%s\", ", event->system,
560 event->name);
561 fprintf(ofp, "\"%s\", %s)", f->name,
562 f->name);
563 } else
564 fprintf(ofp, "%s", f->name);
565 }
566
567 fprintf(ofp, "),\n\n");
568 }
569
570 fprintf(ofp, "def trace_unhandled(event_name, context, "
571 "event_fields_dict):\n");
572
573 fprintf(ofp, "\t\tprint ' '.join(['%%s=%%s'%%(k,str(v))"
574 "for k,v in sorted(event_fields_dict.items())])\n\n");
575
576 fprintf(ofp, "def print_header("
577 "event_name, cpu, secs, nsecs, pid, comm):\n"
578 "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t"
579 "(event_name, cpu, secs, nsecs, pid, comm),\n");
580
581 fclose(ofp);
582
583 fprintf(stderr, "generated Python script: %s\n", fname);
584
585 return 0;
586}
587
588struct scripting_ops python_scripting_ops = {
589 .name = "Python",
590 .start_script = python_start_script,
591 .stop_script = python_stop_script,
592 .process_event = python_process_event,
593 .generate_script = python_generate_script,
594};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce3a6c8abe76..c422cd676313 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,7 +1,11 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <linux/kernel.h> 3#include <linux/kernel.h>
2 4
5#include <byteswap.h>
3#include <unistd.h> 6#include <unistd.h>
4#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/mman.h>
5 9
6#include "session.h" 10#include "session.h"
7#include "sort.h" 11#include "sort.h"
@@ -11,6 +15,16 @@ static int perf_session__open(struct perf_session *self, bool force)
11{ 15{
12 struct stat input_stat; 16 struct stat input_stat;
13 17
18 if (!strcmp(self->filename, "-")) {
19 self->fd_pipe = true;
20 self->fd = STDIN_FILENO;
21
22 if (perf_header__read(self, self->fd) < 0)
23 pr_err("incompatible file format");
24
25 return 0;
26 }
27
14 self->fd = open(self->filename, O_RDONLY); 28 self->fd = open(self->filename, O_RDONLY);
15 if (self->fd < 0) { 29 if (self->fd < 0) {
16 pr_err("failed to open file: %s", self->filename); 30 pr_err("failed to open file: %s", self->filename);
@@ -35,7 +49,7 @@ static int perf_session__open(struct perf_session *self, bool force)
35 goto out_close; 49 goto out_close;
36 } 50 }
37 51
38 if (perf_header__read(&self->header, self->fd) < 0) { 52 if (perf_header__read(self, self->fd) < 0) {
39 pr_err("incompatible file format"); 53 pr_err("incompatible file format");
40 goto out_close; 54 goto out_close;
41 } 55 }
@@ -49,7 +63,21 @@ out_close:
49 return -1; 63 return -1;
50} 64}
51 65
52struct perf_session *perf_session__new(const char *filename, int mode, bool force) 66void perf_session__update_sample_type(struct perf_session *self)
67{
68 self->sample_type = perf_header__sample_type(&self->header);
69}
70
71int perf_session__create_kernel_maps(struct perf_session *self)
72{
73 int ret = machine__create_kernel_maps(&self->host_machine);
74
75 if (ret >= 0)
76 ret = machines__create_guest_kernel_maps(&self->machines);
77 return ret;
78}
79
80struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe)
53{ 81{
54 size_t len = filename ? strlen(filename) + 1 : 0; 82 size_t len = filename ? strlen(filename) + 1 : 0;
55 struct perf_session *self = zalloc(sizeof(*self) + len); 83 struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -62,17 +90,30 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
62 90
63 memcpy(self->filename, filename, len); 91 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT; 92 self->threads = RB_ROOT;
93 INIT_LIST_HEAD(&self->dead_threads);
94 self->hists_tree = RB_ROOT;
65 self->last_match = NULL; 95 self->last_match = NULL;
66 self->mmap_window = 32; 96 self->mmap_window = 32;
67 self->cwd = NULL; 97 self->cwd = NULL;
68 self->cwdlen = 0; 98 self->cwdlen = 0;
69 map_groups__init(&self->kmaps); 99 self->machines = RB_ROOT;
100 self->repipe = repipe;
101 INIT_LIST_HEAD(&self->ordered_samples.samples_head);
102 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
70 103
71 if (perf_session__create_kernel_maps(self) < 0) 104 if (mode == O_RDONLY) {
72 goto out_delete; 105 if (perf_session__open(self, force) < 0)
106 goto out_delete;
107 } else if (mode == O_WRONLY) {
108 /*
109 * In O_RDONLY mode this will be performed when reading the
110 * kernel MMAP event, in event__process_mmap().
111 */
112 if (perf_session__create_kernel_maps(self) < 0)
113 goto out_delete;
114 }
73 115
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0) 116 perf_session__update_sample_type(self);
75 goto out_delete;
76out: 117out:
77 return self; 118 return self;
78out_free: 119out_free:
@@ -91,6 +132,16 @@ void perf_session__delete(struct perf_session *self)
91 free(self); 132 free(self);
92} 133}
93 134
135void perf_session__remove_thread(struct perf_session *self, struct thread *th)
136{
137 rb_erase(&th->rb_node, &self->threads);
138 /*
139 * We may have references to this thread, for instance in some hist_entry
140 * instances, so just move them to a separate list.
141 */
142 list_add_tail(&th->node, &self->dead_threads);
143}
144
94static bool symbol__match_parent_regex(struct symbol *sym) 145static bool symbol__match_parent_regex(struct symbol *sym)
95{ 146{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 147 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -99,22 +150,17 @@ static bool symbol__match_parent_regex(struct symbol *sym)
99 return 0; 150 return 0;
100} 151}
101 152
102struct symbol **perf_session__resolve_callchain(struct perf_session *self, 153struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread, 154 struct thread *thread,
104 struct ip_callchain *chain, 155 struct ip_callchain *chain,
105 struct symbol **parent) 156 struct symbol **parent)
106{ 157{
107 u8 cpumode = PERF_RECORD_MISC_USER; 158 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i; 159 unsigned int i;
160 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
110 161
111 if (symbol_conf.use_callchain) { 162 if (!syms)
112 syms = calloc(chain->nr, sizeof(*syms)); 163 return NULL;
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118 164
119 for (i = 0; i < chain->nr; i++) { 165 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i]; 166 u64 ip = chain->ips[i];
@@ -134,17 +180,736 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
134 continue; 180 continue;
135 } 181 }
136 182
183 al.filtered = false;
137 thread__find_addr_location(thread, self, cpumode, 184 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL); 185 MAP__FUNCTION, thread->pid, ip, &al, NULL);
139 if (al.sym != NULL) { 186 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent && 187 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym)) 188 symbol__match_parent_regex(al.sym))
142 *parent = al.sym; 189 *parent = al.sym;
143 if (!symbol_conf.use_callchain) 190 if (!symbol_conf.use_callchain)
144 break; 191 break;
145 syms[i] = al.sym; 192 syms[i].map = al.map;
193 syms[i].sym = al.sym;
146 } 194 }
147 } 195 }
148 196
149 return syms; 197 return syms;
150} 198}
199
200static int process_event_stub(event_t *event __used,
201 struct perf_session *session __used)
202{
203 dump_printf(": unhandled!\n");
204 return 0;
205}
206
207static int process_finished_round_stub(event_t *event __used,
208 struct perf_session *session __used,
209 struct perf_event_ops *ops __used)
210{
211 dump_printf(": unhandled!\n");
212 return 0;
213}
214
215static int process_finished_round(event_t *event,
216 struct perf_session *session,
217 struct perf_event_ops *ops);
218
219static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
220{
221 if (handler->sample == NULL)
222 handler->sample = process_event_stub;
223 if (handler->mmap == NULL)
224 handler->mmap = process_event_stub;
225 if (handler->comm == NULL)
226 handler->comm = process_event_stub;
227 if (handler->fork == NULL)
228 handler->fork = process_event_stub;
229 if (handler->exit == NULL)
230 handler->exit = process_event_stub;
231 if (handler->lost == NULL)
232 handler->lost = process_event_stub;
233 if (handler->read == NULL)
234 handler->read = process_event_stub;
235 if (handler->throttle == NULL)
236 handler->throttle = process_event_stub;
237 if (handler->unthrottle == NULL)
238 handler->unthrottle = process_event_stub;
239 if (handler->attr == NULL)
240 handler->attr = process_event_stub;
241 if (handler->event_type == NULL)
242 handler->event_type = process_event_stub;
243 if (handler->tracing_data == NULL)
244 handler->tracing_data = process_event_stub;
245 if (handler->build_id == NULL)
246 handler->build_id = process_event_stub;
247 if (handler->finished_round == NULL) {
248 if (handler->ordered_samples)
249 handler->finished_round = process_finished_round;
250 else
251 handler->finished_round = process_finished_round_stub;
252 }
253}
254
255void mem_bswap_64(void *src, int byte_size)
256{
257 u64 *m = src;
258
259 while (byte_size > 0) {
260 *m = bswap_64(*m);
261 byte_size -= sizeof(u64);
262 ++m;
263 }
264}
265
266static void event__all64_swap(event_t *self)
267{
268 struct perf_event_header *hdr = &self->header;
269 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
270}
271
272static void event__comm_swap(event_t *self)
273{
274 self->comm.pid = bswap_32(self->comm.pid);
275 self->comm.tid = bswap_32(self->comm.tid);
276}
277
278static void event__mmap_swap(event_t *self)
279{
280 self->mmap.pid = bswap_32(self->mmap.pid);
281 self->mmap.tid = bswap_32(self->mmap.tid);
282 self->mmap.start = bswap_64(self->mmap.start);
283 self->mmap.len = bswap_64(self->mmap.len);
284 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
285}
286
287static void event__task_swap(event_t *self)
288{
289 self->fork.pid = bswap_32(self->fork.pid);
290 self->fork.tid = bswap_32(self->fork.tid);
291 self->fork.ppid = bswap_32(self->fork.ppid);
292 self->fork.ptid = bswap_32(self->fork.ptid);
293 self->fork.time = bswap_64(self->fork.time);
294}
295
296static void event__read_swap(event_t *self)
297{
298 self->read.pid = bswap_32(self->read.pid);
299 self->read.tid = bswap_32(self->read.tid);
300 self->read.value = bswap_64(self->read.value);
301 self->read.time_enabled = bswap_64(self->read.time_enabled);
302 self->read.time_running = bswap_64(self->read.time_running);
303 self->read.id = bswap_64(self->read.id);
304}
305
306static void event__attr_swap(event_t *self)
307{
308 size_t size;
309
310 self->attr.attr.type = bswap_32(self->attr.attr.type);
311 self->attr.attr.size = bswap_32(self->attr.attr.size);
312 self->attr.attr.config = bswap_64(self->attr.attr.config);
313 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period);
314 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type);
315 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format);
316 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events);
317 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type);
318 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr);
319 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len);
320
321 size = self->header.size;
322 size -= (void *)&self->attr.id - (void *)self;
323 mem_bswap_64(self->attr.id, size);
324}
325
326static void event__event_type_swap(event_t *self)
327{
328 self->event_type.event_type.event_id =
329 bswap_64(self->event_type.event_type.event_id);
330}
331
332static void event__tracing_data_swap(event_t *self)
333{
334 self->tracing_data.size = bswap_32(self->tracing_data.size);
335}
336
337typedef void (*event__swap_op)(event_t *self);
338
339static event__swap_op event__swap_ops[] = {
340 [PERF_RECORD_MMAP] = event__mmap_swap,
341 [PERF_RECORD_COMM] = event__comm_swap,
342 [PERF_RECORD_FORK] = event__task_swap,
343 [PERF_RECORD_EXIT] = event__task_swap,
344 [PERF_RECORD_LOST] = event__all64_swap,
345 [PERF_RECORD_READ] = event__read_swap,
346 [PERF_RECORD_SAMPLE] = event__all64_swap,
347 [PERF_RECORD_HEADER_ATTR] = event__attr_swap,
348 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
349 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap,
350 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
351 [PERF_RECORD_HEADER_MAX] = NULL,
352};
353
354struct sample_queue {
355 u64 timestamp;
356 struct sample_event *event;
357 struct list_head list;
358};
359
360static void flush_sample_queue(struct perf_session *s,
361 struct perf_event_ops *ops)
362{
363 struct list_head *head = &s->ordered_samples.samples_head;
364 u64 limit = s->ordered_samples.next_flush;
365 struct sample_queue *tmp, *iter;
366
367 if (!ops->ordered_samples || !limit)
368 return;
369
370 list_for_each_entry_safe(iter, tmp, head, list) {
371 if (iter->timestamp > limit)
372 return;
373
374 if (iter == s->ordered_samples.last_inserted)
375 s->ordered_samples.last_inserted = NULL;
376
377 ops->sample((event_t *)iter->event, s);
378
379 s->ordered_samples.last_flush = iter->timestamp;
380 list_del(&iter->list);
381 free(iter->event);
382 free(iter);
383 }
384}
385
386/*
387 * When perf record finishes a pass on every buffers, it records this pseudo
388 * event.
389 * We record the max timestamp t found in the pass n.
390 * Assuming these timestamps are monotonic across cpus, we know that if
391 * a buffer still has events with timestamps below t, they will be all
392 * available and then read in the pass n + 1.
393 * Hence when we start to read the pass n + 2, we can safely flush every
394 * events with timestamps below t.
395 *
396 * ============ PASS n =================
397 * CPU 0 | CPU 1
398 * |
399 * cnt1 timestamps | cnt2 timestamps
400 * 1 | 2
401 * 2 | 3
402 * - | 4 <--- max recorded
403 *
404 * ============ PASS n + 1 ==============
405 * CPU 0 | CPU 1
406 * |
407 * cnt1 timestamps | cnt2 timestamps
408 * 3 | 5
409 * 4 | 6
410 * 5 | 7 <---- max recorded
411 *
412 * Flush every events below timestamp 4
413 *
414 * ============ PASS n + 2 ==============
415 * CPU 0 | CPU 1
416 * |
417 * cnt1 timestamps | cnt2 timestamps
418 * 6 | 8
419 * 7 | 9
420 * - | 10
421 *
422 * Flush every events below timestamp 7
423 * etc...
424 */
425static int process_finished_round(event_t *event __used,
426 struct perf_session *session,
427 struct perf_event_ops *ops)
428{
429 flush_sample_queue(session, ops);
430 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
431
432 return 0;
433}
434
435static void __queue_sample_end(struct sample_queue *new, struct list_head *head)
436{
437 struct sample_queue *iter;
438
439 list_for_each_entry_reverse(iter, head, list) {
440 if (iter->timestamp < new->timestamp) {
441 list_add(&new->list, &iter->list);
442 return;
443 }
444 }
445
446 list_add(&new->list, head);
447}
448
449static void __queue_sample_before(struct sample_queue *new,
450 struct sample_queue *iter,
451 struct list_head *head)
452{
453 list_for_each_entry_continue_reverse(iter, head, list) {
454 if (iter->timestamp < new->timestamp) {
455 list_add(&new->list, &iter->list);
456 return;
457 }
458 }
459
460 list_add(&new->list, head);
461}
462
463static void __queue_sample_after(struct sample_queue *new,
464 struct sample_queue *iter,
465 struct list_head *head)
466{
467 list_for_each_entry_continue(iter, head, list) {
468 if (iter->timestamp > new->timestamp) {
469 list_add_tail(&new->list, &iter->list);
470 return;
471 }
472 }
473 list_add_tail(&new->list, head);
474}
475
476/* The queue is ordered by time */
477static void __queue_sample_event(struct sample_queue *new,
478 struct perf_session *s)
479{
480 struct sample_queue *last_inserted = s->ordered_samples.last_inserted;
481 struct list_head *head = &s->ordered_samples.samples_head;
482
483
484 if (!last_inserted) {
485 __queue_sample_end(new, head);
486 return;
487 }
488
489 /*
490 * Most of the time the current event has a timestamp
491 * very close to the last event inserted, unless we just switched
492 * to another event buffer. Having a sorting based on a list and
493 * on the last inserted event that is close to the current one is
494 * probably more efficient than an rbtree based sorting.
495 */
496 if (last_inserted->timestamp >= new->timestamp)
497 __queue_sample_before(new, last_inserted, head);
498 else
499 __queue_sample_after(new, last_inserted, head);
500}
501
502static int queue_sample_event(event_t *event, struct sample_data *data,
503 struct perf_session *s)
504{
505 u64 timestamp = data->time;
506 struct sample_queue *new;
507
508
509 if (timestamp < s->ordered_samples.last_flush) {
510 printf("Warning: Timestamp below last timeslice flush\n");
511 return -EINVAL;
512 }
513
514 new = malloc(sizeof(*new));
515 if (!new)
516 return -ENOMEM;
517
518 new->timestamp = timestamp;
519
520 new->event = malloc(event->header.size);
521 if (!new->event) {
522 free(new);
523 return -ENOMEM;
524 }
525
526 memcpy(new->event, event, event->header.size);
527
528 __queue_sample_event(new, s);
529 s->ordered_samples.last_inserted = new;
530
531 if (new->timestamp > s->ordered_samples.max_timestamp)
532 s->ordered_samples.max_timestamp = new->timestamp;
533
534 return 0;
535}
536
537static int perf_session__process_sample(event_t *event, struct perf_session *s,
538 struct perf_event_ops *ops)
539{
540 struct sample_data data;
541
542 if (!ops->ordered_samples)
543 return ops->sample(event, s);
544
545 bzero(&data, sizeof(struct sample_data));
546 event__parse_sample(event, s->sample_type, &data);
547
548 queue_sample_event(event, &data, s);
549
550 return 0;
551}
552
553static int perf_session__process_event(struct perf_session *self,
554 event_t *event,
555 struct perf_event_ops *ops,
556 u64 offset, u64 head)
557{
558 trace_event(event);
559
560 if (event->header.type < PERF_RECORD_HEADER_MAX) {
561 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
562 offset + head, event->header.size,
563 event__name[event->header.type]);
564 hists__inc_nr_events(&self->hists, event->header.type);
565 }
566
567 if (self->header.needs_swap && event__swap_ops[event->header.type])
568 event__swap_ops[event->header.type](event);
569
570 switch (event->header.type) {
571 case PERF_RECORD_SAMPLE:
572 return perf_session__process_sample(event, self, ops);
573 case PERF_RECORD_MMAP:
574 return ops->mmap(event, self);
575 case PERF_RECORD_COMM:
576 return ops->comm(event, self);
577 case PERF_RECORD_FORK:
578 return ops->fork(event, self);
579 case PERF_RECORD_EXIT:
580 return ops->exit(event, self);
581 case PERF_RECORD_LOST:
582 return ops->lost(event, self);
583 case PERF_RECORD_READ:
584 return ops->read(event, self);
585 case PERF_RECORD_THROTTLE:
586 return ops->throttle(event, self);
587 case PERF_RECORD_UNTHROTTLE:
588 return ops->unthrottle(event, self);
589 case PERF_RECORD_HEADER_ATTR:
590 return ops->attr(event, self);
591 case PERF_RECORD_HEADER_EVENT_TYPE:
592 return ops->event_type(event, self);
593 case PERF_RECORD_HEADER_TRACING_DATA:
594 /* setup for reading amidst mmap */
595 lseek(self->fd, offset + head, SEEK_SET);
596 return ops->tracing_data(event, self);
597 case PERF_RECORD_HEADER_BUILD_ID:
598 return ops->build_id(event, self);
599 case PERF_RECORD_FINISHED_ROUND:
600 return ops->finished_round(event, self, ops);
601 default:
602 ++self->hists.stats.nr_unknown_events;
603 return -1;
604 }
605}
606
607void perf_event_header__bswap(struct perf_event_header *self)
608{
609 self->type = bswap_32(self->type);
610 self->misc = bswap_16(self->misc);
611 self->size = bswap_16(self->size);
612}
613
614static struct thread *perf_session__register_idle_thread(struct perf_session *self)
615{
616 struct thread *thread = perf_session__findnew(self, 0);
617
618 if (thread == NULL || thread__set_comm(thread, "swapper")) {
619 pr_err("problem inserting idle task.\n");
620 thread = NULL;
621 }
622
623 return thread;
624}
625
626int do_read(int fd, void *buf, size_t size)
627{
628 void *buf_start = buf;
629
630 while (size) {
631 int ret = read(fd, buf, size);
632
633 if (ret <= 0)
634 return ret;
635
636 size -= ret;
637 buf += ret;
638 }
639
640 return buf - buf_start;
641}
642
643#define session_done() (*(volatile int *)(&session_done))
644volatile int session_done;
645
646static int __perf_session__process_pipe_events(struct perf_session *self,
647 struct perf_event_ops *ops)
648{
649 event_t event;
650 uint32_t size;
651 int skip = 0;
652 u64 head;
653 int err;
654 void *p;
655
656 perf_event_ops__fill_defaults(ops);
657
658 head = 0;
659more:
660 err = do_read(self->fd, &event, sizeof(struct perf_event_header));
661 if (err <= 0) {
662 if (err == 0)
663 goto done;
664
665 pr_err("failed to read event header\n");
666 goto out_err;
667 }
668
669 if (self->header.needs_swap)
670 perf_event_header__bswap(&event.header);
671
672 size = event.header.size;
673 if (size == 0)
674 size = 8;
675
676 p = &event;
677 p += sizeof(struct perf_event_header);
678
679 if (size - sizeof(struct perf_event_header)) {
680 err = do_read(self->fd, p,
681 size - sizeof(struct perf_event_header));
682 if (err <= 0) {
683 if (err == 0) {
684 pr_err("unexpected end of event stream\n");
685 goto done;
686 }
687
688 pr_err("failed to read event data\n");
689 goto out_err;
690 }
691 }
692
693 if (size == 0 ||
694 (skip = perf_session__process_event(self, &event, ops,
695 0, head)) < 0) {
696 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
697 head, event.header.size, event.header.type);
698 /*
699 * assume we lost track of the stream, check alignment, and
700 * increment a single u64 in the hope to catch on again 'soon'.
701 */
702 if (unlikely(head & 7))
703 head &= ~7ULL;
704
705 size = 8;
706 }
707
708 head += size;
709
710 dump_printf("\n%#Lx [%#x]: event: %d\n",
711 head, event.header.size, event.header.type);
712
713 if (skip > 0)
714 head += skip;
715
716 if (!session_done())
717 goto more;
718done:
719 err = 0;
720out_err:
721 return err;
722}
723
724int __perf_session__process_events(struct perf_session *self,
725 u64 data_offset, u64 data_size,
726 u64 file_size, struct perf_event_ops *ops)
727{
728 int err, mmap_prot, mmap_flags;
729 u64 head, shift;
730 u64 offset = 0;
731 size_t page_size;
732 event_t *event;
733 uint32_t size;
734 char *buf;
735 struct ui_progress *progress = ui_progress__new("Processing events...",
736 self->size);
737 if (progress == NULL)
738 return -1;
739
740 perf_event_ops__fill_defaults(ops);
741
742 page_size = sysconf(_SC_PAGESIZE);
743
744 head = data_offset;
745 shift = page_size * (head / page_size);
746 offset += shift;
747 head -= shift;
748
749 mmap_prot = PROT_READ;
750 mmap_flags = MAP_SHARED;
751
752 if (self->header.needs_swap) {
753 mmap_prot |= PROT_WRITE;
754 mmap_flags = MAP_PRIVATE;
755 }
756remap:
757 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
758 mmap_flags, self->fd, offset);
759 if (buf == MAP_FAILED) {
760 pr_err("failed to mmap file\n");
761 err = -errno;
762 goto out_err;
763 }
764
765more:
766 event = (event_t *)(buf + head);
767 ui_progress__update(progress, offset);
768
769 if (self->header.needs_swap)
770 perf_event_header__bswap(&event->header);
771 size = event->header.size;
772 if (size == 0)
773 size = 8;
774
775 if (head + event->header.size >= page_size * self->mmap_window) {
776 int munmap_ret;
777
778 shift = page_size * (head / page_size);
779
780 munmap_ret = munmap(buf, page_size * self->mmap_window);
781 assert(munmap_ret == 0);
782
783 offset += shift;
784 head -= shift;
785 goto remap;
786 }
787
788 size = event->header.size;
789
790 dump_printf("\n%#Lx [%#x]: event: %d\n",
791 offset + head, event->header.size, event->header.type);
792
793 if (size == 0 ||
794 perf_session__process_event(self, event, ops, offset, head) < 0) {
795 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
796 offset + head, event->header.size,
797 event->header.type);
798 /*
799 * assume we lost track of the stream, check alignment, and
800 * increment a single u64 in the hope to catch on again 'soon'.
801 */
802 if (unlikely(head & 7))
803 head &= ~7ULL;
804
805 size = 8;
806 }
807
808 head += size;
809
810 if (offset + head >= data_offset + data_size)
811 goto done;
812
813 if (offset + head < file_size)
814 goto more;
815done:
816 err = 0;
817 /* do the final flush for ordered samples */
818 self->ordered_samples.next_flush = ULLONG_MAX;
819 flush_sample_queue(self, ops);
820out_err:
821 ui_progress__delete(progress);
822 return err;
823}
824
825int perf_session__process_events(struct perf_session *self,
826 struct perf_event_ops *ops)
827{
828 int err;
829
830 if (perf_session__register_idle_thread(self) == NULL)
831 return -ENOMEM;
832
833 if (!symbol_conf.full_paths) {
834 char bf[PATH_MAX];
835
836 if (getcwd(bf, sizeof(bf)) == NULL) {
837 err = -errno;
838out_getcwd_err:
839 pr_err("failed to get the current directory\n");
840 goto out_err;
841 }
842 self->cwd = strdup(bf);
843 if (self->cwd == NULL) {
844 err = -ENOMEM;
845 goto out_getcwd_err;
846 }
847 self->cwdlen = strlen(self->cwd);
848 }
849
850 if (!self->fd_pipe)
851 err = __perf_session__process_events(self,
852 self->header.data_offset,
853 self->header.data_size,
854 self->size, ops);
855 else
856 err = __perf_session__process_pipe_events(self, ops);
857out_err:
858 return err;
859}
860
861bool perf_session__has_traces(struct perf_session *self, const char *msg)
862{
863 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
864 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
865 return false;
866 }
867
868 return true;
869}
870
871int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
872 const char *symbol_name,
873 u64 addr)
874{
875 char *bracket;
876 enum map_type i;
877 struct ref_reloc_sym *ref;
878
879 ref = zalloc(sizeof(struct ref_reloc_sym));
880 if (ref == NULL)
881 return -ENOMEM;
882
883 ref->name = strdup(symbol_name);
884 if (ref->name == NULL) {
885 free(ref);
886 return -ENOMEM;
887 }
888
889 bracket = strchr(ref->name, ']');
890 if (bracket)
891 *bracket = '\0';
892
893 ref->addr = addr;
894
895 for (i = 0; i < MAP__NR_TYPES; ++i) {
896 struct kmap *kmap = map__kmap(maps[i]);
897 kmap->ref_reloc_sym = ref;
898 }
899
900 return 0;
901}
902
903size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
904{
905 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) +
906 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
907 machines__fprintf_dsos(&self->machines, fp);
908}
909
910size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
911 bool with_hits)
912{
913 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
914 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
915}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 32eaa1bada06..9fa0fc2a863f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,61 +1,145 @@
1#ifndef __PERF_SESSION_H 1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "hist.h"
4#include "event.h" 5#include "event.h"
5#include "header.h" 6#include "header.h"
7#include "symbol.h"
6#include "thread.h" 8#include "thread.h"
7#include <linux/rbtree.h> 9#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h" 10#include "../../../include/linux/perf_event.h"
9 11
12struct sample_queue;
10struct ip_callchain; 13struct ip_callchain;
11struct thread; 14struct thread;
12struct symbol; 15
16struct ordered_samples {
17 u64 last_flush;
18 u64 next_flush;
19 u64 max_timestamp;
20 struct list_head samples_head;
21 struct sample_queue *last_inserted;
22};
13 23
14struct perf_session { 24struct perf_session {
15 struct perf_header header; 25 struct perf_header header;
16 unsigned long size; 26 unsigned long size;
17 unsigned long mmap_window; 27 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads; 28 struct rb_root threads;
29 struct list_head dead_threads;
20 struct thread *last_match; 30 struct thread *last_match;
21 struct events_stats events_stats; 31 struct machine host_machine;
22 unsigned long event_total[PERF_RECORD_MAX]; 32 struct rb_root machines;
23 struct rb_root hists; 33 struct rb_root hists_tree;
34 /*
35 * FIXME: should point to the first entry in hists_tree and
36 * be a hists instance. Right now its only 'report'
37 * that is using ->hists_tree while all the rest use
38 * ->hists.
39 */
40 struct hists hists;
24 u64 sample_type; 41 u64 sample_type;
25 int fd; 42 int fd;
43 bool fd_pipe;
44 bool repipe;
26 int cwdlen; 45 int cwdlen;
27 char *cwd; 46 char *cwd;
47 struct ordered_samples ordered_samples;
28 char filename[0]; 48 char filename[0];
29}; 49};
30 50
51struct perf_event_ops;
52
31typedef int (*event_op)(event_t *self, struct perf_session *session); 53typedef int (*event_op)(event_t *self, struct perf_session *session);
54typedef int (*event_op2)(event_t *self, struct perf_session *session,
55 struct perf_event_ops *ops);
32 56
33struct perf_event_ops { 57struct perf_event_ops {
34 event_op process_sample_event; 58 event_op sample,
35 event_op process_mmap_event; 59 mmap,
36 event_op process_comm_event; 60 comm,
37 event_op process_fork_event; 61 fork,
38 event_op process_exit_event; 62 exit,
39 event_op process_lost_event; 63 lost,
40 event_op process_read_event; 64 read,
41 event_op process_throttle_event; 65 throttle,
42 event_op process_unthrottle_event; 66 unthrottle,
43 int (*sample_type_check)(struct perf_session *session); 67 attr,
44 unsigned long total_unknown; 68 event_type,
45 bool full_paths; 69 tracing_data,
70 build_id;
71 event_op2 finished_round;
72 bool ordered_samples;
46}; 73};
47 74
48struct perf_session *perf_session__new(const char *filename, int mode, bool force); 75struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe);
49void perf_session__delete(struct perf_session *self); 76void perf_session__delete(struct perf_session *self);
50 77
78void perf_event_header__bswap(struct perf_event_header *self);
79
80int __perf_session__process_events(struct perf_session *self,
81 u64 data_offset, u64 data_size, u64 size,
82 struct perf_event_ops *ops);
51int perf_session__process_events(struct perf_session *self, 83int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops); 84 struct perf_event_ops *event_ops);
53 85
54struct symbol **perf_session__resolve_callchain(struct perf_session *self, 86struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread, 87 struct thread *thread,
56 struct ip_callchain *chain, 88 struct ip_callchain *chain,
57 struct symbol **parent); 89 struct symbol **parent);
90
91bool perf_session__has_traces(struct perf_session *self, const char *msg);
92
93int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
94 const char *symbol_name,
95 u64 addr);
96
97void mem_bswap_64(void *src, int byte_size);
98
99int perf_session__create_kernel_maps(struct perf_session *self);
100
101int do_read(int fd, void *buf, size_t size);
102void perf_session__update_sample_type(struct perf_session *self);
103void perf_session__remove_thread(struct perf_session *self, struct thread *th);
104
105static inline
106struct machine *perf_session__find_host_machine(struct perf_session *self)
107{
108 return &self->host_machine;
109}
110
111static inline
112struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
113{
114 if (pid == HOST_KERNEL_ID)
115 return &self->host_machine;
116 return machines__find(&self->machines, pid);
117}
118
119static inline
120struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
121{
122 if (pid == HOST_KERNEL_ID)
123 return &self->host_machine;
124 return machines__findnew(&self->machines, pid);
125}
126
127static inline
128void perf_session__process_machines(struct perf_session *self,
129 machine__process_t process)
130{
131 process(&self->host_machine, self);
132 return machines__process(&self->machines, process, self);
133}
134
135size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
58 136
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 137size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
138 FILE *fp, bool with_hits);
60 139
140static inline
141size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp)
142{
143 return hists__fprintf_nr_events(&self->hists, fp);
144}
61#endif /* __PERF_SESSION_H */ 145#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sigchain.c b/tools/perf/util/sigchain.c
index 1118b99e57d3..ba785e9b1841 100644
--- a/tools/perf/util/sigchain.c
+++ b/tools/perf/util/sigchain.c
@@ -16,7 +16,7 @@ static void check_signum(int sig)
16 die("BUG: signal out of range: %d", sig); 16 die("BUG: signal out of range: %d", sig);
17} 17}
18 18
19int sigchain_push(int sig, sigchain_fun f) 19static int sigchain_push(int sig, sigchain_fun f)
20{ 20{
21 struct sigchain_signal *s = signals + sig; 21 struct sigchain_signal *s = signals + sig;
22 check_signum(sig); 22 check_signum(sig);
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 1a53c11265fd..959d64eb5557 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -3,7 +3,6 @@
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
6int sigchain_push(int sig, sigchain_fun f);
7int sigchain_pop(int sig); 6int sigchain_pop(int sig);
8 7
9void sigchain_push_common(sigchain_fun f); 8void sigchain_push_common(sigchain_fun f);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cb0f327de9e8..2316cb5a4116 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,10 +1,10 @@
1#include "sort.h" 1#include "sort.h"
2 2
3regex_t parent_regex; 3regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault"; 4const char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern; 5const char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol"; 6const char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order; 7const char *sort_order = default_sort_order;
8int sort__need_collapse = 0; 8int sort__need_collapse = 0;
9int sort__has_parent = 0; 9int sort__has_parent = 0;
10 10
@@ -18,39 +18,50 @@ char * field_sep;
18 18
19LIST_HEAD(hist_entry__sort_list); 19LIST_HEAD(hist_entry__sort_list);
20 20
21static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
22 size_t size, unsigned int width);
23static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
24 size_t size, unsigned int width);
25static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
26 size_t size, unsigned int width);
27static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
28 size_t size, unsigned int width);
29static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
30 size_t size, unsigned int width);
31
21struct sort_entry sort_thread = { 32struct sort_entry sort_thread = {
22 .header = "Command: Pid", 33 .se_header = "Command: Pid",
23 .cmp = sort__thread_cmp, 34 .se_cmp = sort__thread_cmp,
24 .print = sort__thread_print, 35 .se_snprintf = hist_entry__thread_snprintf,
25 .width = &threads__col_width, 36 .se_width = &threads__col_width,
26}; 37};
27 38
28struct sort_entry sort_comm = { 39struct sort_entry sort_comm = {
29 .header = "Command", 40 .se_header = "Command",
30 .cmp = sort__comm_cmp, 41 .se_cmp = sort__comm_cmp,
31 .collapse = sort__comm_collapse, 42 .se_collapse = sort__comm_collapse,
32 .print = sort__comm_print, 43 .se_snprintf = hist_entry__comm_snprintf,
33 .width = &comms__col_width, 44 .se_width = &comms__col_width,
34}; 45};
35 46
36struct sort_entry sort_dso = { 47struct sort_entry sort_dso = {
37 .header = "Shared Object", 48 .se_header = "Shared Object",
38 .cmp = sort__dso_cmp, 49 .se_cmp = sort__dso_cmp,
39 .print = sort__dso_print, 50 .se_snprintf = hist_entry__dso_snprintf,
40 .width = &dsos__col_width, 51 .se_width = &dsos__col_width,
41}; 52};
42 53
43struct sort_entry sort_sym = { 54struct sort_entry sort_sym = {
44 .header = "Symbol", 55 .se_header = "Symbol",
45 .cmp = sort__sym_cmp, 56 .se_cmp = sort__sym_cmp,
46 .print = sort__sym_print, 57 .se_snprintf = hist_entry__sym_snprintf,
47}; 58};
48 59
49struct sort_entry sort_parent = { 60struct sort_entry sort_parent = {
50 .header = "Parent symbol", 61 .se_header = "Parent symbol",
51 .cmp = sort__parent_cmp, 62 .se_cmp = sort__parent_cmp,
52 .print = sort__parent_print, 63 .se_snprintf = hist_entry__parent_snprintf,
53 .width = &parent_symbol__col_width, 64 .se_width = &parent_symbol__col_width,
54}; 65};
55 66
56struct sort_dimension { 67struct sort_dimension {
@@ -85,45 +96,38 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
85 return right->thread->pid - left->thread->pid; 96 return right->thread->pid - left->thread->pid;
86} 97}
87 98
88int repsep_fprintf(FILE *fp, const char *fmt, ...) 99static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
89{ 100{
90 int n; 101 int n;
91 va_list ap; 102 va_list ap;
92 103
93 va_start(ap, fmt); 104 va_start(ap, fmt);
94 if (!field_sep) 105 n = vsnprintf(bf, size, fmt, ap);
95 n = vfprintf(fp, fmt, ap); 106 if (field_sep && n > 0) {
96 else { 107 char *sep = bf;
97 char *bf = NULL; 108
98 n = vasprintf(&bf, fmt, ap); 109 while (1) {
99 if (n > 0) { 110 sep = strchr(sep, *field_sep);
100 char *sep = bf; 111 if (sep == NULL)
101 112 break;
102 while (1) { 113 *sep = '.';
103 sep = strchr(sep, *field_sep);
104 if (sep == NULL)
105 break;
106 *sep = '.';
107 }
108 } 114 }
109 fputs(bf, fp);
110 free(bf);
111 } 115 }
112 va_end(ap); 116 va_end(ap);
113 return n; 117 return n;
114} 118}
115 119
116size_t 120static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
117sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width) 121 size_t size, unsigned int width)
118{ 122{
119 return repsep_fprintf(fp, "%*s:%5d", width - 6, 123 return repsep_snprintf(bf, size, "%*s:%5d", width,
120 self->thread->comm ?: "", self->thread->pid); 124 self->thread->comm ?: "", self->thread->pid);
121} 125}
122 126
123size_t 127static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
124sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width) 128 size_t size, unsigned int width)
125{ 129{
126 return repsep_fprintf(fp, "%*s", width, self->thread->comm); 130 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
127} 131}
128 132
129/* --sort dso */ 133/* --sort dso */
@@ -131,8 +135,8 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
131int64_t 135int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 136sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{ 137{
134 struct dso *dso_l = left->map ? left->map->dso : NULL; 138 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL; 139 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
136 const char *dso_name_l, *dso_name_r; 140 const char *dso_name_l, *dso_name_r;
137 141
138 if (!dso_l || !dso_r) 142 if (!dso_l || !dso_r)
@@ -149,16 +153,16 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
149 return strcmp(dso_name_l, dso_name_r); 153 return strcmp(dso_name_l, dso_name_r);
150} 154}
151 155
152size_t 156static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) 157 size_t size, unsigned int width)
154{ 158{
155 if (self->map && self->map->dso) { 159 if (self->ms.map && self->ms.map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name : 160 const char *dso_name = !verbose ? self->ms.map->dso->short_name :
157 self->map->dso->long_name; 161 self->ms.map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name); 162 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
159 } 163 }
160 164
161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); 165 return repsep_snprintf(bf, size, "%*Lx", width, self->ip);
162} 166}
163 167
164/* --sort symbol */ 168/* --sort symbol */
@@ -168,31 +172,31 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{ 172{
169 u64 ip_l, ip_r; 173 u64 ip_l, ip_r;
170 174
171 if (left->sym == right->sym) 175 if (left->ms.sym == right->ms.sym)
172 return 0; 176 return 0;
173 177
174 ip_l = left->sym ? left->sym->start : left->ip; 178 ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip; 179 ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
176 180
177 return (int64_t)(ip_r - ip_l); 181 return (int64_t)(ip_r - ip_l);
178} 182}
179 183
180 184static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
181size_t 185 size_t size, unsigned int width __used)
182sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
183{ 186{
184 size_t ret = 0; 187 size_t ret = 0;
185 188
186 if (verbose) { 189 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!'; 190 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o); 191 ret += repsep_snprintf(bf, size, "%#018llx %c ", self->ip, o);
189 } 192 }
190 193
191 ret += repsep_fprintf(fp, "[%c] ", self->level); 194 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
192 if (self->sym) 195 if (self->ms.sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name); 196 ret += repsep_snprintf(bf + ret, size - ret, "%s",
197 self->ms.sym->name);
194 else 198 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); 199 ret += repsep_snprintf(bf + ret, size - ret, "%#016llx", self->ip);
196 200
197 return ret; 201 return ret;
198} 202}
@@ -231,10 +235,10 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
231 return strcmp(sym_l->name, sym_r->name); 235 return strcmp(sym_l->name, sym_r->name);
232} 236}
233 237
234size_t 238static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
235sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width) 239 size_t size, unsigned int width)
236{ 240{
237 return repsep_fprintf(fp, "%-*s", width, 241 return repsep_snprintf(bf, size, "%-*s", width,
238 self->parent ? self->parent->name : "[other]"); 242 self->parent ? self->parent->name : "[other]");
239} 243}
240 244
@@ -251,7 +255,7 @@ int sort_dimension__add(const char *tok)
251 if (strncasecmp(tok, sd->name, strlen(tok))) 255 if (strncasecmp(tok, sd->name, strlen(tok)))
252 continue; 256 continue;
253 257
254 if (sd->entry->collapse) 258 if (sd->entry->se_collapse)
255 sort__need_collapse = 1; 259 sort__need_collapse = 1;
256 260
257 if (sd->entry == &sort_parent) { 261 if (sd->entry == &sort_parent) {
@@ -260,9 +264,8 @@ int sort_dimension__add(const char *tok)
260 char err[BUFSIZ]; 264 char err[BUFSIZ];
261 265
262 regerror(ret, &parent_regex, err, sizeof(err)); 266 regerror(ret, &parent_regex, err, sizeof(err));
263 fprintf(stderr, "Invalid regex: %s\n%s", 267 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
264 parent_pattern, err); 268 return -EINVAL;
265 exit(-1);
266 } 269 }
267 sort__has_parent = 1; 270 sort__has_parent = 1;
268 } 271 }
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 753f9ea99fb0..0d61c4082f43 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -25,10 +25,10 @@
25#include "sort.h" 25#include "sort.h"
26 26
27extern regex_t parent_regex; 27extern regex_t parent_regex;
28extern char *sort_order; 28extern const char *sort_order;
29extern char default_parent_pattern[]; 29extern const char default_parent_pattern[];
30extern char *parent_pattern; 30extern const char *parent_pattern;
31extern char default_sort_order[]; 31extern const char default_sort_order[];
32extern int sort__need_collapse; 32extern int sort__need_collapse;
33extern int sort__has_parent; 33extern int sort__has_parent;
34extern char *field_sep; 34extern char *field_sep;
@@ -43,19 +43,24 @@ extern enum sort_type sort__first_dimension;
43 43
44struct hist_entry { 44struct hist_entry {
45 struct rb_node rb_node; 45 struct rb_node rb_node;
46 u64 count; 46 u64 period;
47 u64 period_sys;
48 u64 period_us;
49 u64 period_guest_sys;
50 u64 period_guest_us;
51 struct map_symbol ms;
47 struct thread *thread; 52 struct thread *thread;
48 struct map *map;
49 struct symbol *sym;
50 u64 ip; 53 u64 ip;
54 u32 nr_events;
51 char level; 55 char level;
52 struct symbol *parent; 56 u8 filtered;
53 struct callchain_node callchain; 57 struct symbol *parent;
54 union { 58 union {
55 unsigned long position; 59 unsigned long position;
56 struct hist_entry *pair; 60 struct hist_entry *pair;
57 struct rb_root sorted_chain; 61 struct rb_root sorted_chain;
58 }; 62 };
63 struct callchain_node callchain[0];
59}; 64};
60 65
61enum sort_type { 66enum sort_type {
@@ -73,12 +78,13 @@ enum sort_type {
73struct sort_entry { 78struct sort_entry {
74 struct list_head list; 79 struct list_head list;
75 80
76 const char *header; 81 const char *se_header;
77 82
78 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 83 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
79 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 84 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
80 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width); 85 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size,
81 unsigned int *width; 86 unsigned int width);
87 unsigned int *se_width;
82 bool elide; 88 bool elide;
83}; 89};
84 90
@@ -87,7 +93,6 @@ extern struct list_head hist_entry__sort_list;
87 93
88void setup_sorting(const char * const usagestr[], const struct option *opts); 94void setup_sorting(const char * const usagestr[], const struct option *opts);
89 95
90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 96extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 97extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
93extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int); 98extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 5249d5a1b0c2..92e068517c1a 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -41,16 +41,6 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz)
41 return res; 41 return res;
42} 42}
43 43
44void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
45{
46 strbuf_release(sb);
47 sb->buf = buf;
48 sb->len = len;
49 sb->alloc = alloc;
50 strbuf_grow(sb, 0);
51 sb->buf[sb->len] = '\0';
52}
53
54void strbuf_grow(struct strbuf *sb, size_t extra) 44void strbuf_grow(struct strbuf *sb, size_t extra)
55{ 45{
56 if (sb->len + extra + 1 <= sb->len) 46 if (sb->len + extra + 1 <= sb->len)
@@ -60,94 +50,7 @@ void strbuf_grow(struct strbuf *sb, size_t extra)
60 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); 50 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
61} 51}
62 52
63void strbuf_trim(struct strbuf *sb) 53static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
64{
65 char *b = sb->buf;
66 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
67 sb->len--;
68 while (sb->len > 0 && isspace(*b)) {
69 b++;
70 sb->len--;
71 }
72 memmove(sb->buf, b, sb->len);
73 sb->buf[sb->len] = '\0';
74}
75void strbuf_rtrim(struct strbuf *sb)
76{
77 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
78 sb->len--;
79 sb->buf[sb->len] = '\0';
80}
81
82void strbuf_ltrim(struct strbuf *sb)
83{
84 char *b = sb->buf;
85 while (sb->len > 0 && isspace(*b)) {
86 b++;
87 sb->len--;
88 }
89 memmove(sb->buf, b, sb->len);
90 sb->buf[sb->len] = '\0';
91}
92
93void strbuf_tolower(struct strbuf *sb)
94{
95 unsigned int i;
96
97 for (i = 0; i < sb->len; i++)
98 sb->buf[i] = tolower(sb->buf[i]);
99}
100
101struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
102{
103 int alloc = 2, pos = 0;
104 char *n, *p;
105 struct strbuf **ret;
106 struct strbuf *t;
107
108 ret = calloc(alloc, sizeof(struct strbuf *));
109 p = n = sb->buf;
110 while (n < sb->buf + sb->len) {
111 int len;
112 n = memchr(n, delim, sb->len - (n - sb->buf));
113 if (pos + 1 >= alloc) {
114 alloc = alloc * 2;
115 ret = realloc(ret, sizeof(struct strbuf *) * alloc);
116 }
117 if (!n)
118 n = sb->buf + sb->len - 1;
119 len = n - p + 1;
120 t = malloc(sizeof(struct strbuf));
121 strbuf_init(t, len);
122 strbuf_add(t, p, len);
123 ret[pos] = t;
124 ret[++pos] = NULL;
125 p = ++n;
126 }
127 return ret;
128}
129
130void strbuf_list_free(struct strbuf **sbs)
131{
132 struct strbuf **s = sbs;
133
134 while (*s) {
135 strbuf_release(*s);
136 free(*s++);
137 }
138 free(sbs);
139}
140
141int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
142{
143 int len = a->len < b->len ? a->len: b->len;
144 int cmp = memcmp(a->buf, b->buf, len);
145 if (cmp)
146 return cmp;
147 return a->len < b->len ? -1: a->len != b->len;
148}
149
150void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
151 const void *data, size_t dlen) 54 const void *data, size_t dlen)
152{ 55{
153 if (pos + len < pos) 56 if (pos + len < pos)
@@ -166,11 +69,6 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
166 strbuf_setlen(sb, sb->len + dlen - len); 69 strbuf_setlen(sb, sb->len + dlen - len);
167} 70}
168 71
169void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
170{
171 strbuf_splice(sb, pos, 0, data, len);
172}
173
174void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) 72void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
175{ 73{
176 strbuf_splice(sb, pos, len, NULL, 0); 74 strbuf_splice(sb, pos, len, NULL, 0);
@@ -183,13 +81,6 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
183 strbuf_setlen(sb, sb->len + len); 81 strbuf_setlen(sb, sb->len + len);
184} 82}
185 83
186void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
187{
188 strbuf_grow(sb, len);
189 memcpy(sb->buf + sb->len, sb->buf + pos, len);
190 strbuf_setlen(sb, sb->len + len);
191}
192
193void strbuf_addf(struct strbuf *sb, const char *fmt, ...) 84void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
194{ 85{
195 int len; 86 int len;
@@ -214,57 +105,6 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
214 strbuf_setlen(sb, sb->len + len); 105 strbuf_setlen(sb, sb->len + len);
215} 106}
216 107
217void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
218 void *context)
219{
220 for (;;) {
221 const char *percent;
222 size_t consumed;
223
224 percent = strchrnul(format, '%');
225 strbuf_add(sb, format, percent - format);
226 if (!*percent)
227 break;
228 format = percent + 1;
229
230 consumed = fn(sb, format, context);
231 if (consumed)
232 format += consumed;
233 else
234 strbuf_addch(sb, '%');
235 }
236}
237
238size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
239 void *context)
240{
241 struct strbuf_expand_dict_entry *e = context;
242 size_t len;
243
244 for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
245 if (!strncmp(placeholder, e->placeholder, len)) {
246 if (e->value)
247 strbuf_addstr(sb, e->value);
248 return len;
249 }
250 }
251 return 0;
252}
253
254size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
255{
256 size_t res;
257 size_t oldalloc = sb->alloc;
258
259 strbuf_grow(sb, size);
260 res = fread(sb->buf + sb->len, 1, size, f);
261 if (res > 0)
262 strbuf_setlen(sb, sb->len + res);
263 else if (oldalloc == 0)
264 strbuf_release(sb);
265 return res;
266}
267
268ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) 108ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
269{ 109{
270 size_t oldlen = sb->len; 110 size_t oldlen = sb->len;
@@ -291,70 +131,3 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
291 sb->buf[sb->len] = '\0'; 131 sb->buf[sb->len] = '\0';
292 return sb->len - oldlen; 132 return sb->len - oldlen;
293} 133}
294
295#define STRBUF_MAXLINK (2*PATH_MAX)
296
297int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
298{
299 size_t oldalloc = sb->alloc;
300
301 if (hint < 32)
302 hint = 32;
303
304 while (hint < STRBUF_MAXLINK) {
305 ssize_t len;
306
307 strbuf_grow(sb, hint);
308 len = readlink(path, sb->buf, hint);
309 if (len < 0) {
310 if (errno != ERANGE)
311 break;
312 } else if (len < hint) {
313 strbuf_setlen(sb, len);
314 return 0;
315 }
316
317 /* .. the buffer was too small - try again */
318 hint *= 2;
319 }
320 if (oldalloc == 0)
321 strbuf_release(sb);
322 return -1;
323}
324
325int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
326{
327 int ch;
328
329 strbuf_grow(sb, 0);
330 if (feof(fp))
331 return EOF;
332
333 strbuf_reset(sb);
334 while ((ch = fgetc(fp)) != EOF) {
335 if (ch == term)
336 break;
337 strbuf_grow(sb, 1);
338 sb->buf[sb->len++] = ch;
339 }
340 if (ch == EOF && sb->len == 0)
341 return EOF;
342
343 sb->buf[sb->len] = '\0';
344 return 0;
345}
346
347int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
348{
349 int fd, len;
350
351 fd = open(path, O_RDONLY);
352 if (fd < 0)
353 return -1;
354 len = strbuf_read(sb, fd, hint);
355 close(fd);
356 if (len < 0)
357 return -1;
358
359 return len;
360}
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index a3d121d6c83e..436ac319f6c7 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -53,12 +53,6 @@ struct strbuf {
53extern void strbuf_init(struct strbuf *buf, ssize_t hint); 53extern void strbuf_init(struct strbuf *buf, ssize_t hint);
54extern void strbuf_release(struct strbuf *); 54extern void strbuf_release(struct strbuf *);
55extern char *strbuf_detach(struct strbuf *, size_t *); 55extern char *strbuf_detach(struct strbuf *, size_t *);
56extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
57static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
58 struct strbuf tmp = *a;
59 *a = *b;
60 *b = tmp;
61}
62 56
63/*----- strbuf size related -----*/ 57/*----- strbuf size related -----*/
64static inline ssize_t strbuf_avail(const struct strbuf *sb) { 58static inline ssize_t strbuf_avail(const struct strbuf *sb) {
@@ -74,17 +68,6 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
74 sb->len = len; 68 sb->len = len;
75 sb->buf[len] = '\0'; 69 sb->buf[len] = '\0';
76} 70}
77#define strbuf_reset(sb) strbuf_setlen(sb, 0)
78
79/*----- content related -----*/
80extern void strbuf_trim(struct strbuf *);
81extern void strbuf_rtrim(struct strbuf *);
82extern void strbuf_ltrim(struct strbuf *);
83extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
84extern void strbuf_tolower(struct strbuf *);
85
86extern struct strbuf **strbuf_split(const struct strbuf *, int delim);
87extern void strbuf_list_free(struct strbuf **);
88 71
89/*----- add data in your buffer -----*/ 72/*----- add data in your buffer -----*/
90static inline void strbuf_addch(struct strbuf *sb, int c) { 73static inline void strbuf_addch(struct strbuf *sb, int c) {
@@ -93,45 +76,17 @@ static inline void strbuf_addch(struct strbuf *sb, int c) {
93 sb->buf[sb->len] = '\0'; 76 sb->buf[sb->len] = '\0';
94} 77}
95 78
96extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
97extern void strbuf_remove(struct strbuf *, size_t pos, size_t len); 79extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
98 80
99/* splice pos..pos+len with given data */
100extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
101 const void *, size_t);
102
103extern void strbuf_add(struct strbuf *, const void *, size_t); 81extern void strbuf_add(struct strbuf *, const void *, size_t);
104static inline void strbuf_addstr(struct strbuf *sb, const char *s) { 82static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
105 strbuf_add(sb, s, strlen(s)); 83 strbuf_add(sb, s, strlen(s));
106} 84}
107static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {
108 strbuf_add(sb, sb2->buf, sb2->len);
109}
110extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
111
112typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
113extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
114struct strbuf_expand_dict_entry {
115 const char *placeholder;
116 const char *value;
117};
118extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
119 85
120__attribute__((format(printf,2,3))) 86__attribute__((format(printf,2,3)))
121extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); 87extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
122 88
123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
124/* XXX: if read fails, any partial read is undone */ 89/* XXX: if read fails, any partial read is undone */
125extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); 90extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
126extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
127extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
128
129extern int strbuf_getline(struct strbuf *, FILE *, int);
130
131extern void stripspace(struct strbuf *buf, int skip_comments);
132extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
133
134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 91
137#endif /* __PERF_STRBUF_H */ 92#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 5352d7dccc61..0409fc7c0058 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,48 +1,5 @@
1#include "string.h"
2#include "util.h" 1#include "util.h"
3 2#include "string.h"
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 3
47#define K 1024LL 4#define K 1024LL
48/* 5/*
@@ -227,16 +184,73 @@ fail:
227 return NULL; 184 return NULL;
228} 185}
229 186
230/* Glob expression pattern matching */ 187/* Character class matching */
231bool strglobmatch(const char *str, const char *pat) 188static bool __match_charclass(const char *pat, char c, const char **npat)
189{
190 bool complement = false, ret = true;
191
192 if (*pat == '!') {
193 complement = true;
194 pat++;
195 }
196 if (*pat++ == c) /* First character is special */
197 goto end;
198
199 while (*pat && *pat != ']') { /* Matching */
200 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
201 if (*(pat - 1) <= c && c <= *(pat + 1))
202 goto end;
203 if (*(pat - 1) > *(pat + 1))
204 goto error;
205 pat += 2;
206 } else if (*pat++ == c)
207 goto end;
208 }
209 if (!*pat)
210 goto error;
211 ret = false;
212
213end:
214 while (*pat && *pat != ']') /* Searching closing */
215 pat++;
216 if (!*pat)
217 goto error;
218 *npat = pat + 1;
219 return complement ? !ret : ret;
220
221error:
222 return false;
223}
224
225/* Glob/lazy pattern matching */
226static bool __match_glob(const char *str, const char *pat, bool ignore_space)
232{ 227{
233 while (*str && *pat && *pat != '*') { 228 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') { 229 if (ignore_space) {
230 /* Ignore spaces for lazy matching */
231 if (isspace(*str)) {
232 str++;
233 continue;
234 }
235 if (isspace(*pat)) {
236 pat++;
237 continue;
238 }
239 }
240 if (*pat == '?') { /* Matches any single character */
235 str++; 241 str++;
236 pat++; 242 pat++;
237 } else 243 continue;
238 if (*str++ != *pat++) 244 } else if (*pat == '[') /* Character classes/Ranges */
245 if (__match_charclass(pat + 1, *str, &pat)) {
246 str++;
247 continue;
248 } else
239 return false; 249 return false;
250 else if (*pat == '\\') /* Escaped char match as normal char */
251 pat++;
252 if (*str++ != *pat++)
253 return false;
240 } 254 }
241 /* Check wild card */ 255 /* Check wild card */
242 if (*pat == '*') { 256 if (*pat == '*') {
@@ -251,3 +265,32 @@ bool strglobmatch(const char *str, const char *pat)
251 return !*str && !*pat; 265 return !*str && !*pat;
252} 266}
253 267
268/**
269 * strglobmatch - glob expression pattern matching
270 * @str: the target string to match
271 * @pat: the pattern string to match
272 *
273 * This returns true if the @str matches @pat. @pat can includes wildcards
274 * ('*','?') and character classes ([CHARS], complementation and ranges are
275 * also supported). Also, this supports escape character ('\') to use special
276 * characters as normal character.
277 *
278 * Note: if @pat syntax is broken, this always returns false.
279 */
280bool strglobmatch(const char *str, const char *pat)
281{
282 return __match_glob(str, pat, false);
283}
284
285/**
286 * strlazymatch - matching pattern strings lazily with glob pattern
287 * @str: the target string to match
288 * @pat: the pattern string to match
289 *
290 * This is similar to strglobmatch, except this ignores spaces in
291 * the target string.
292 */
293bool strlazymatch(const char *str, const char *pat)
294{
295 return __match_glob(str, pat, true);
296}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
deleted file mode 100644
index 02ede58c54b4..000000000000
--- a/tools/perf/util/string.h
+++ /dev/null
@@ -1,17 +0,0 @@
1#ifndef __PERF_STRING_H_
2#define __PERF_STRING_H_
3
4#include <stdbool.h>
5#include "types.h"
6
7int hex2u64(const char *ptr, u64 *val);
8char *strxfrchar(char *s, char from, char to);
9s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
13
14#define _STR(x) #x
15#define STR(x) _STR(x)
16
17#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab92763edb03..5b276833e2bf 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,14 +1,20 @@
1#include "util.h" 1#define _GNU_SOURCE
2#include "../perf.h" 2#include <ctype.h>
3#include "session.h" 3#include <dirent.h>
4#include "sort.h" 4#include <errno.h>
5#include "string.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>
14#include "build-id.h"
6#include "symbol.h" 15#include "symbol.h"
7#include "thread.h" 16#include "strlist.h"
8 17
9#include "debug.h"
10
11#include <asm/bug.h>
12#include <libelf.h> 18#include <libelf.h>
13#include <gelf.h> 19#include <gelf.h>
14#include <elf.h> 20#include <elf.h>
@@ -19,21 +25,12 @@
19#define NT_GNU_BUILD_ID 3 25#define NT_GNU_BUILD_ID 3
20#endif 26#endif
21 27
22enum dso_origin {
23 DSO__ORIG_KERNEL = 0,
24 DSO__ORIG_JAVA_JIT,
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); 28static void dsos__add(struct list_head *head, struct dso *dso);
34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 29static 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, 30static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct perf_session *session, symbol_filter_t filter); 31 symbol_filter_t filter);
32static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
33 symbol_filter_t filter);
37static int vmlinux_path__nr_entries; 34static int vmlinux_path__nr_entries;
38static char **vmlinux_path; 35static char **vmlinux_path;
39 36
@@ -53,17 +50,12 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type)
53 return self->sorted_by_name & (1 << type); 50 return self->sorted_by_name & (1 << type);
54} 51}
55 52
56static void dso__set_loaded(struct dso *self, enum map_type type)
57{
58 self->loaded |= (1 << type);
59}
60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 53static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{ 54{
63 self->sorted_by_name |= (1 << type); 55 self->sorted_by_name |= (1 << type);
64} 56}
65 57
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 58bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{ 59{
68 switch (map_type) { 60 switch (map_type) {
69 case MAP__FUNCTION: 61 case MAP__FUNCTION:
@@ -131,25 +123,26 @@ static void map_groups__fixup_end(struct map_groups *self)
131static struct symbol *symbol__new(u64 start, u64 len, const char *name) 123static struct symbol *symbol__new(u64 start, u64 len, const char *name)
132{ 124{
133 size_t namelen = strlen(name) + 1; 125 size_t namelen = strlen(name) + 1;
134 struct symbol *self = zalloc(symbol_conf.priv_size + 126 struct symbol *self = calloc(1, (symbol_conf.priv_size +
135 sizeof(*self) + namelen); 127 sizeof(*self) + namelen));
136 if (self == NULL) 128 if (self == NULL)
137 return NULL; 129 return NULL;
138 130
139 if (symbol_conf.priv_size) 131 if (symbol_conf.priv_size)
140 self = ((void *)self) + symbol_conf.priv_size; 132 self = ((void *)self) + symbol_conf.priv_size;
141 133
142 self->start = start; 134 self->start = start;
143 self->end = len ? start + len - 1 : start; 135 self->end = len ? start + len - 1 : start;
136 self->namelen = namelen - 1;
144 137
145 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 138 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
146 139
147 memcpy(self->name, name, namelen); 140 memcpy(self->name, name, namelen);
148 141
149 return self; 142 return self;
150} 143}
151 144
152static void symbol__delete(struct symbol *self) 145void symbol__delete(struct symbol *self)
153{ 146{
154 free(((void *)self) - symbol_conf.priv_size); 147 free(((void *)self) - symbol_conf.priv_size);
155} 148}
@@ -160,7 +153,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
160 self->start, self->end, self->name); 153 self->start, self->end, self->name);
161} 154}
162 155
163static void dso__set_long_name(struct dso *self, char *name) 156void dso__set_long_name(struct dso *self, char *name)
164{ 157{
165 if (name == NULL) 158 if (name == NULL)
166 return; 159 return;
@@ -168,20 +161,28 @@ static void dso__set_long_name(struct dso *self, char *name)
168 self->long_name_len = strlen(name); 161 self->long_name_len = strlen(name);
169} 162}
170 163
164static void dso__set_short_name(struct dso *self, const char *name)
165{
166 if (name == NULL)
167 return;
168 self->short_name = name;
169 self->short_name_len = strlen(name);
170}
171
171static void dso__set_basename(struct dso *self) 172static void dso__set_basename(struct dso *self)
172{ 173{
173 self->short_name = basename(self->long_name); 174 dso__set_short_name(self, basename(self->long_name));
174} 175}
175 176
176struct dso *dso__new(const char *name) 177struct dso *dso__new(const char *name)
177{ 178{
178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 179 struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
179 180
180 if (self != NULL) { 181 if (self != NULL) {
181 int i; 182 int i;
182 strcpy(self->name, name); 183 strcpy(self->name, name);
183 dso__set_long_name(self, self->name); 184 dso__set_long_name(self, self->name);
184 self->short_name = self->name; 185 dso__set_short_name(self, self->name);
185 for (i = 0; i < MAP__NR_TYPES; ++i) 186 for (i = 0; i < MAP__NR_TYPES; ++i)
186 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 187 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
187 self->slen_calculated = 0; 188 self->slen_calculated = 0;
@@ -189,6 +190,8 @@ struct dso *dso__new(const char *name)
189 self->loaded = 0; 190 self->loaded = 0;
190 self->sorted_by_name = 0; 191 self->sorted_by_name = 0;
191 self->has_build_id = 0; 192 self->has_build_id = 0;
193 self->kernel = DSO_TYPE_USER;
194 INIT_LIST_HEAD(&self->node);
192 } 195 }
193 196
194 return self; 197 return self;
@@ -344,10 +347,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
344 &self->symbols[type]); 347 &self->symbols[type]);
345} 348}
346 349
347int build_id__sprintf(u8 *self, int len, char *bf) 350int build_id__sprintf(const u8 *self, int len, char *bf)
348{ 351{
349 char *bid = bf; 352 char *bid = bf;
350 u8 *raw = self; 353 const u8 *raw = self;
351 int i; 354 int i;
352 355
353 for (i = 0; i < len; ++i) { 356 for (i = 0; i < len; ++i) {
@@ -372,6 +375,10 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
372 struct rb_node *nd; 375 struct rb_node *nd;
373 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 376 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
374 377
378 if (self->short_name != self->long_name)
379 ret += fprintf(fp, "%s, ", self->long_name);
380 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
381 self->loaded ? "" : "NOT ");
375 ret += dso__fprintf_buildid(self, fp); 382 ret += dso__fprintf_buildid(self, fp);
376 ret += fprintf(fp, ")\n"); 383 ret += fprintf(fp, ")\n");
377 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 384 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
@@ -382,35 +389,28 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
382 return ret; 389 return ret;
383} 390}
384 391
385/* 392int kallsyms__parse(const char *filename, void *arg,
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso, 393 int (*process_symbol)(void *arg, const char *name,
387 * so that we can in the next step set the symbol ->end address and then 394 char type, u64 start))
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
391{ 395{
392 char *line = NULL; 396 char *line = NULL;
393 size_t n; 397 size_t n;
394 struct rb_root *root = &self->symbols[map->type]; 398 int err = 0;
395 FILE *file = fopen("/proc/kallsyms", "r"); 399 FILE *file = fopen(filename, "r");
396 400
397 if (file == NULL) 401 if (file == NULL)
398 goto out_failure; 402 goto out_failure;
399 403
400 while (!feof(file)) { 404 while (!feof(file)) {
401 u64 start; 405 u64 start;
402 struct symbol *sym;
403 int line_len, len; 406 int line_len, len;
404 char symbol_type; 407 char symbol_type;
405 char *symbol_name; 408 char *symbol_name;
406 409
407 line_len = getline(&line, &n, file); 410 line_len = getline(&line, &n, file);
408 if (line_len < 0) 411 if (line_len < 0 || !line)
409 break; 412 break;
410 413
411 if (!line)
412 goto out_failure;
413
414 line[--line_len] = '\0'; /* \n */ 414 line[--line_len] = '\0'; /* \n */
415 415
416 len = hex2u64(line, &start); 416 len = hex2u64(line, &start);
@@ -420,43 +420,74 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
420 continue; 420 continue;
421 421
422 symbol_type = toupper(line[len]); 422 symbol_type = toupper(line[len]);
423 if (!symbol_type__is_a(symbol_type, map->type))
424 continue;
425
426 symbol_name = line + len + 2; 423 symbol_name = line + len + 2;
427 /*
428 * Will fix up the end later, when we have all symbols sorted.
429 */
430 sym = symbol__new(start, 0, symbol_name);
431 424
432 if (sym == NULL) 425 err = process_symbol(arg, symbol_name, symbol_type, start);
433 goto out_delete_line; 426 if (err)
434 /* 427 break;
435 * We will pass the symbols to the filter later, in
436 * map__split_kallsyms, when we have split the maps per module
437 */
438 symbols__insert(root, sym);
439 } 428 }
440 429
441 free(line); 430 free(line);
442 fclose(file); 431 fclose(file);
432 return err;
443 433
444 return 0;
445
446out_delete_line:
447 free(line);
448out_failure: 434out_failure:
449 return -1; 435 return -1;
450} 436}
451 437
438struct process_kallsyms_args {
439 struct map *map;
440 struct dso *dso;
441};
442
443static int map__process_kallsym_symbol(void *arg, const char *name,
444 char type, u64 start)
445{
446 struct symbol *sym;
447 struct process_kallsyms_args *a = arg;
448 struct rb_root *root = &a->dso->symbols[a->map->type];
449
450 if (!symbol_type__is_a(type, a->map->type))
451 return 0;
452
453 /*
454 * Will fix up the end later, when we have all symbols sorted.
455 */
456 sym = symbol__new(start, 0, name);
457
458 if (sym == NULL)
459 return -ENOMEM;
460 /*
461 * We will pass the symbols to the filter later, in
462 * map__split_kallsyms, when we have split the maps per module
463 */
464 symbols__insert(root, sym);
465
466 return 0;
467}
468
469/*
470 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
471 * so that we can in the next step set the symbol ->end address and then
472 * call kernel_maps__split_kallsyms.
473 */
474static int dso__load_all_kallsyms(struct dso *self, const char *filename,
475 struct map *map)
476{
477 struct process_kallsyms_args args = { .map = map, .dso = self, };
478 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
479}
480
452/* 481/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the 482 * Split the symbols into maps, making sure there are no overlaps, i.e. the
454 * kernel range is broken in several maps, named [kernel].N, as we don't have 483 * kernel range is broken in several maps, named [kernel].N, as we don't have
455 * the original ELF section names vmlinux have. 484 * the original ELF section names vmlinux have.
456 */ 485 */
457static int dso__split_kallsyms(struct dso *self, struct map *map, 486static int dso__split_kallsyms(struct dso *self, struct map *map,
458 struct perf_session *session, symbol_filter_t filter) 487 symbol_filter_t filter)
459{ 488{
489 struct map_groups *kmaps = map__kmap(map)->kmaps;
490 struct machine *machine = kmaps->machine;
460 struct map *curr_map = map; 491 struct map *curr_map = map;
461 struct symbol *pos; 492 struct symbol *pos;
462 int count = 0; 493 int count = 0;
@@ -477,13 +508,35 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
477 508
478 *module++ = '\0'; 509 *module++ = '\0';
479 510
480 if (strcmp(self->name, module)) { 511 if (strcmp(curr_map->dso->short_name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 512 if (curr_map != map &&
513 self->kernel == DSO_TYPE_GUEST_KERNEL &&
514 machine__is_default_guest(machine)) {
515 /*
516 * We assume all symbols of a module are
517 * continuous in * kallsyms, so curr_map
518 * points to a module and all its
519 * symbols are in its kmap. Mark it as
520 * loaded.
521 */
522 dso__set_loaded(curr_map->dso,
523 curr_map->type);
524 }
525
526 curr_map = map_groups__find_by_name(kmaps,
527 map->type, module);
482 if (curr_map == NULL) { 528 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} " 529 pr_debug("%s/proc/{kallsyms,modules} "
484 "inconsistency!\n"); 530 "inconsistency while looking "
485 return -1; 531 "for \"%s\" module!\n",
532 machine->root_dir, module);
533 curr_map = map;
534 goto discard_symbol;
486 } 535 }
536
537 if (curr_map->dso->loaded &&
538 !machine__is_default_guest(machine))
539 goto discard_symbol;
487 } 540 }
488 /* 541 /*
489 * So that we look just like we get from .ko files, 542 * So that we look just like we get from .ko files,
@@ -495,21 +548,29 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
495 char dso_name[PATH_MAX]; 548 char dso_name[PATH_MAX];
496 struct dso *dso; 549 struct dso *dso;
497 550
498 snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 551 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
499 kernel_range++); 552 snprintf(dso_name, sizeof(dso_name),
553 "[guest.kernel].%d",
554 kernel_range++);
555 else
556 snprintf(dso_name, sizeof(dso_name),
557 "[kernel].%d",
558 kernel_range++);
500 559
501 dso = dso__new(dso_name); 560 dso = dso__new(dso_name);
502 if (dso == NULL) 561 if (dso == NULL)
503 return -1; 562 return -1;
504 563
564 dso->kernel = self->kernel;
565
505 curr_map = map__new2(pos->start, dso, map->type); 566 curr_map = map__new2(pos->start, dso, map->type);
506 if (map == NULL) { 567 if (curr_map == NULL) {
507 dso__delete(dso); 568 dso__delete(dso);
508 return -1; 569 return -1;
509 } 570 }
510 571
511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 572 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
512 map_groups__insert(&session->kmaps, curr_map); 573 map_groups__insert(kmaps, curr_map);
513 ++kernel_range; 574 ++kernel_range;
514 } 575 }
515 576
@@ -525,20 +586,28 @@ discard_symbol: rb_erase(&pos->rb_node, root);
525 } 586 }
526 } 587 }
527 588
589 if (curr_map != map &&
590 self->kernel == DSO_TYPE_GUEST_KERNEL &&
591 machine__is_default_guest(kmaps->machine)) {
592 dso__set_loaded(curr_map->dso, curr_map->type);
593 }
594
528 return count; 595 return count;
529} 596}
530 597
531 598int dso__load_kallsyms(struct dso *self, const char *filename,
532static int dso__load_kallsyms(struct dso *self, struct map *map, 599 struct map *map, symbol_filter_t filter)
533 struct perf_session *session, symbol_filter_t filter)
534{ 600{
535 if (dso__load_all_kallsyms(self, map) < 0) 601 if (dso__load_all_kallsyms(self, filename, map) < 0)
536 return -1; 602 return -1;
537 603
538 symbols__fixup_end(&self->symbols[map->type]); 604 symbols__fixup_end(&self->symbols[map->type]);
539 self->origin = DSO__ORIG_KERNEL; 605 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
606 self->origin = DSO__ORIG_GUEST_KERNEL;
607 else
608 self->origin = DSO__ORIG_KERNEL;
540 609
541 return dso__split_kallsyms(self, map, session, filter); 610 return dso__split_kallsyms(self, map, filter);
542} 611}
543 612
544static int dso__load_perf_map(struct dso *self, struct map *map, 613static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -835,8 +904,8 @@ out_close:
835 if (err == 0) 904 if (err == 0)
836 return nr; 905 return nr;
837out: 906out:
838 pr_warning("%s: problems reading %s PLT info.\n", 907 pr_debug("%s: problems reading %s PLT info.\n",
839 __func__, self->long_name); 908 __func__, self->long_name);
840 return 0; 909 return 0;
841} 910}
842 911
@@ -864,13 +933,12 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
864 } 933 }
865} 934}
866 935
867static int dso__load_sym(struct dso *self, struct map *map, 936static int dso__load_sym(struct dso *self, struct map *map, const char *name,
868 struct perf_session *session, const char *name, int fd, 937 int fd, symbol_filter_t filter, int kmodule)
869 symbol_filter_t filter, int kernel, int kmodule)
870{ 938{
939 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
871 struct map *curr_map = map; 940 struct map *curr_map = map;
872 struct dso *curr_dso = self; 941 struct dso *curr_dso = self;
873 size_t dso_name_len = strlen(self->short_name);
874 Elf_Data *symstrs, *secstrs; 942 Elf_Data *symstrs, *secstrs;
875 uint32_t nr_syms; 943 uint32_t nr_syms;
876 int err = -1; 944 int err = -1;
@@ -924,7 +992,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
924 nr_syms = shdr.sh_size / shdr.sh_entsize; 992 nr_syms = shdr.sh_size / shdr.sh_entsize;
925 993
926 memset(&sym, 0, sizeof(sym)); 994 memset(&sym, 0, sizeof(sym));
927 if (!kernel) { 995 if (self->kernel == DSO_TYPE_USER) {
928 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 996 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
929 elf_section_by_name(elf, &ehdr, &shdr, 997 elf_section_by_name(elf, &ehdr, &shdr,
930 ".gnu.prelink_undo", 998 ".gnu.prelink_undo",
@@ -933,11 +1001,15 @@ static int dso__load_sym(struct dso *self, struct map *map,
933 1001
934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 1002 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
935 struct symbol *f; 1003 struct symbol *f;
936 const char *elf_name; 1004 const char *elf_name = elf_sym__name(&sym, symstrs);
937 char *demangled = NULL; 1005 char *demangled = NULL;
938 int is_label = elf_sym__is_label(&sym); 1006 int is_label = elf_sym__is_label(&sym);
939 const char *section_name; 1007 const char *section_name;
940 1008
1009 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
1010 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
1011 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
1012
941 if (!is_label && !elf_sym__is_a(&sym, map->type)) 1013 if (!is_label && !elf_sym__is_a(&sym, map->type))
942 continue; 1014 continue;
943 1015
@@ -950,14 +1022,14 @@ static int dso__load_sym(struct dso *self, struct map *map,
950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 1022 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
951 continue; 1023 continue;
952 1024
953 elf_name = elf_sym__name(&sym, symstrs);
954 section_name = elf_sec__name(&shdr, secstrs); 1025 section_name = elf_sec__name(&shdr, secstrs);
955 1026
956 if (kernel || kmodule) { 1027 if (self->kernel != DSO_TYPE_USER || kmodule) {
957 char dso_name[PATH_MAX]; 1028 char dso_name[PATH_MAX];
958 1029
959 if (strcmp(section_name, 1030 if (strcmp(section_name,
960 curr_dso->short_name + dso_name_len) == 0) 1031 (curr_dso->short_name +
1032 self->short_name_len)) == 0)
961 goto new_symbol; 1033 goto new_symbol;
962 1034
963 if (strcmp(section_name, ".text") == 0) { 1035 if (strcmp(section_name, ".text") == 0) {
@@ -969,7 +1041,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
969 snprintf(dso_name, sizeof(dso_name), 1041 snprintf(dso_name, sizeof(dso_name),
970 "%s%s", self->short_name, section_name); 1042 "%s%s", self->short_name, section_name);
971 1043
972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 1044 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
973 if (curr_map == NULL) { 1045 if (curr_map == NULL) {
974 u64 start = sym.st_value; 1046 u64 start = sym.st_value;
975 1047
@@ -979,17 +1051,19 @@ static int dso__load_sym(struct dso *self, struct map *map,
979 curr_dso = dso__new(dso_name); 1051 curr_dso = dso__new(dso_name);
980 if (curr_dso == NULL) 1052 if (curr_dso == NULL)
981 goto out_elf_end; 1053 goto out_elf_end;
1054 curr_dso->kernel = self->kernel;
982 curr_map = map__new2(start, curr_dso, 1055 curr_map = map__new2(start, curr_dso,
983 MAP__FUNCTION); 1056 map->type);
984 if (curr_map == NULL) { 1057 if (curr_map == NULL) {
985 dso__delete(curr_dso); 1058 dso__delete(curr_dso);
986 goto out_elf_end; 1059 goto out_elf_end;
987 } 1060 }
988 curr_map->map_ip = identity__map_ip; 1061 curr_map->map_ip = identity__map_ip;
989 curr_map->unmap_ip = identity__map_ip; 1062 curr_map->unmap_ip = identity__map_ip;
990 curr_dso->origin = DSO__ORIG_KERNEL; 1063 curr_dso->origin = self->origin;
991 map_groups__insert(&session->kmaps, curr_map); 1064 map_groups__insert(kmap->kmaps, curr_map);
992 dsos__add(&dsos__kernel, curr_dso); 1065 dsos__add(&self->node, curr_dso);
1066 dso__set_loaded(curr_dso, map->type);
993 } else 1067 } else
994 curr_dso = curr_map->dso; 1068 curr_dso = curr_map->dso;
995 1069
@@ -997,9 +1071,10 @@ static int dso__load_sym(struct dso *self, struct map *map,
997 } 1071 }
998 1072
999 if (curr_dso->adjust_symbols) { 1073 if (curr_dso->adjust_symbols) {
1000 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 1074 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1001 "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 1075 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1002 (u64)shdr.sh_addr, (u64)shdr.sh_offset); 1076 (u64)sym.st_value, (u64)shdr.sh_addr,
1077 (u64)shdr.sh_offset);
1003 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1078 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1004 } 1079 }
1005 /* 1080 /*
@@ -1027,8 +1102,16 @@ new_symbol:
1027 /* 1102 /*
1028 * For misannotated, zeroed, ASM function sizes. 1103 * For misannotated, zeroed, ASM function sizes.
1029 */ 1104 */
1030 if (nr > 0) 1105 if (nr > 0) {
1031 symbols__fixup_end(&self->symbols[map->type]); 1106 symbols__fixup_end(&self->symbols[map->type]);
1107 if (kmap) {
1108 /*
1109 * We need to fixup this here too because we create new
1110 * maps here, for things like vsyscall sections.
1111 */
1112 __map_groups__fixup_end(kmap->kmaps, map->type);
1113 }
1114 }
1032 err = nr; 1115 err = nr;
1033out_elf_end: 1116out_elf_end:
1034 elf_end(elf); 1117 elf_end(elf);
@@ -1041,28 +1124,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1041 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 1124 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1042} 1125}
1043 1126
1044static bool __dsos__read_build_ids(struct list_head *head) 1127bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1045{ 1128{
1046 bool have_build_id = false; 1129 bool have_build_id = false;
1047 struct dso *pos; 1130 struct dso *pos;
1048 1131
1049 list_for_each_entry(pos, head, node) 1132 list_for_each_entry(pos, head, node) {
1133 if (with_hits && !pos->hit)
1134 continue;
1135 if (pos->has_build_id) {
1136 have_build_id = true;
1137 continue;
1138 }
1050 if (filename__read_build_id(pos->long_name, pos->build_id, 1139 if (filename__read_build_id(pos->long_name, pos->build_id,
1051 sizeof(pos->build_id)) > 0) { 1140 sizeof(pos->build_id)) > 0) {
1052 have_build_id = true; 1141 have_build_id = true;
1053 pos->has_build_id = true; 1142 pos->has_build_id = true;
1054 } 1143 }
1144 }
1055 1145
1056 return have_build_id; 1146 return have_build_id;
1057} 1147}
1058 1148
1059bool dsos__read_build_ids(void)
1060{
1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
1062 ubuildids = __dsos__read_build_ids(&dsos__user);
1063 return kbuildids || ubuildids;
1064}
1065
1066/* 1149/*
1067 * Align offset to 4 bytes as needed for note name and descriptor data. 1150 * Align offset to 4 bytes as needed for note name and descriptor data.
1068 */ 1151 */
@@ -1191,11 +1274,14 @@ char dso__symtab_origin(const struct dso *self)
1191 static const char origin[] = { 1274 static const char origin[] = {
1192 [DSO__ORIG_KERNEL] = 'k', 1275 [DSO__ORIG_KERNEL] = 'k',
1193 [DSO__ORIG_JAVA_JIT] = 'j', 1276 [DSO__ORIG_JAVA_JIT] = 'j',
1277 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
1194 [DSO__ORIG_FEDORA] = 'f', 1278 [DSO__ORIG_FEDORA] = 'f',
1195 [DSO__ORIG_UBUNTU] = 'u', 1279 [DSO__ORIG_UBUNTU] = 'u',
1196 [DSO__ORIG_BUILDID] = 'b', 1280 [DSO__ORIG_BUILDID] = 'b',
1197 [DSO__ORIG_DSO] = 'd', 1281 [DSO__ORIG_DSO] = 'd',
1198 [DSO__ORIG_KMODULE] = 'K', 1282 [DSO__ORIG_KMODULE] = 'K',
1283 [DSO__ORIG_GUEST_KERNEL] = 'g',
1284 [DSO__ORIG_GUEST_KMODULE] = 'G',
1199 }; 1285 };
1200 1286
1201 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1287 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -1203,19 +1289,27 @@ char dso__symtab_origin(const struct dso *self)
1203 return origin[self->origin]; 1289 return origin[self->origin];
1204} 1290}
1205 1291
1206int dso__load(struct dso *self, struct map *map, struct perf_session *session, 1292int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1207 symbol_filter_t filter)
1208{ 1293{
1209 int size = PATH_MAX; 1294 int size = PATH_MAX;
1210 char *name; 1295 char *name;
1211 u8 build_id[BUILD_ID_SIZE]; 1296 u8 build_id[BUILD_ID_SIZE];
1212 int ret = -1; 1297 int ret = -1;
1213 int fd; 1298 int fd;
1299 struct machine *machine;
1300 const char *root_dir;
1214 1301
1215 dso__set_loaded(self, map->type); 1302 dso__set_loaded(self, map->type);
1216 1303
1217 if (self->kernel) 1304 if (self->kernel == DSO_TYPE_KERNEL)
1218 return dso__load_kernel_sym(self, map, session, filter); 1305 return dso__load_kernel_sym(self, map, filter);
1306 else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1307 return dso__load_guest_kernel_sym(self, map, filter);
1308
1309 if (map->groups && map->groups->machine)
1310 machine = map->groups->machine;
1311 else
1312 machine = NULL;
1219 1313
1220 name = malloc(size); 1314 name = malloc(size);
1221 if (!name) 1315 if (!name)
@@ -1230,8 +1324,9 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1230 return ret; 1324 return ret;
1231 } 1325 }
1232 1326
1233 self->origin = DSO__ORIG_FEDORA - 1; 1327 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1234 1328 if (dso__build_id_filename(self, name, size) != NULL)
1329 goto open_file;
1235more: 1330more:
1236 do { 1331 do {
1237 self->origin++; 1332 self->origin++;
@@ -1248,7 +1343,6 @@ more:
1248 if (filename__read_build_id(self->long_name, build_id, 1343 if (filename__read_build_id(self->long_name, build_id,
1249 sizeof(build_id))) { 1344 sizeof(build_id))) {
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1345 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1251
1252 build_id__sprintf(build_id, sizeof(build_id), 1346 build_id__sprintf(build_id, sizeof(build_id),
1253 build_id_hex); 1347 build_id_hex);
1254 snprintf(name, size, 1348 snprintf(name, size,
@@ -1263,6 +1357,13 @@ more:
1263 case DSO__ORIG_DSO: 1357 case DSO__ORIG_DSO:
1264 snprintf(name, size, "%s", self->long_name); 1358 snprintf(name, size, "%s", self->long_name);
1265 break; 1359 break;
1360 case DSO__ORIG_GUEST_KMODULE:
1361 if (map->groups && map->groups->machine)
1362 root_dir = map->groups->machine->root_dir;
1363 else
1364 root_dir = "";
1365 snprintf(name, size, "%s%s", root_dir, self->long_name);
1366 break;
1266 1367
1267 default: 1368 default:
1268 goto out; 1369 goto out;
@@ -1276,11 +1377,11 @@ compare_build_id:
1276 if (!dso__build_id_equal(self, build_id)) 1377 if (!dso__build_id_equal(self, build_id))
1277 goto more; 1378 goto more;
1278 } 1379 }
1279 1380open_file:
1280 fd = open(name, O_RDONLY); 1381 fd = open(name, O_RDONLY);
1281 } while (fd < 0); 1382 } while (fd < 0);
1282 1383
1283 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 1384 ret = dso__load_sym(self, map, name, fd, filter, 0);
1284 close(fd); 1385 close(fd);
1285 1386
1286 /* 1387 /*
@@ -1309,35 +1410,65 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1410 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1310 struct map *map = rb_entry(nd, struct map, rb_node); 1411 struct map *map = rb_entry(nd, struct map, rb_node);
1311 1412
1312 if (map->dso && strcmp(map->dso->name, name) == 0) 1413 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1313 return map; 1414 return map;
1314 } 1415 }
1315 1416
1316 return NULL; 1417 return NULL;
1317} 1418}
1318 1419
1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 1420static int dso__kernel_module_get_build_id(struct dso *self,
1421 const char *root_dir)
1422{
1423 char filename[PATH_MAX];
1424 /*
1425 * kernel module short names are of the form "[module]" and
1426 * we need just "module" here.
1427 */
1428 const char *name = self->short_name + 1;
1429
1430 snprintf(filename, sizeof(filename),
1431 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1432 root_dir, (int)strlen(name) - 1, name);
1433
1434 if (sysfs__read_build_id(filename, self->build_id,
1435 sizeof(self->build_id)) == 0)
1436 self->has_build_id = true;
1437
1438 return 0;
1439}
1440
1441static int map_groups__set_modules_path_dir(struct map_groups *self,
1442 const char *dir_name)
1320{ 1443{
1321 struct dirent *dent; 1444 struct dirent *dent;
1322 DIR *dir = opendir(dirname); 1445 DIR *dir = opendir(dir_name);
1446 int ret = 0;
1323 1447
1324 if (!dir) { 1448 if (!dir) {
1325 pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1449 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1326 return -1; 1450 return -1;
1327 } 1451 }
1328 1452
1329 while ((dent = readdir(dir)) != NULL) { 1453 while ((dent = readdir(dir)) != NULL) {
1330 char path[PATH_MAX]; 1454 char path[PATH_MAX];
1455 struct stat st;
1456
1457 /*sshfs might return bad dent->d_type, so we have to stat*/
1458 sprintf(path, "%s/%s", dir_name, dent->d_name);
1459 if (stat(path, &st))
1460 continue;
1331 1461
1332 if (dent->d_type == DT_DIR) { 1462 if (S_ISDIR(st.st_mode)) {
1333 if (!strcmp(dent->d_name, ".") || 1463 if (!strcmp(dent->d_name, ".") ||
1334 !strcmp(dent->d_name, "..")) 1464 !strcmp(dent->d_name, ".."))
1335 continue; 1465 continue;
1336 1466
1337 snprintf(path, sizeof(path), "%s/%s", 1467 snprintf(path, sizeof(path), "%s/%s",
1338 dirname, dent->d_name); 1468 dir_name, dent->d_name);
1339 if (perf_session__set_modules_path_dir(self, path) < 0) 1469 ret = map_groups__set_modules_path_dir(self, path);
1340 goto failure; 1470 if (ret < 0)
1471 goto out;
1341 } else { 1472 } else {
1342 char *dot = strrchr(dent->d_name, '.'), 1473 char *dot = strrchr(dent->d_name, '.'),
1343 dso_name[PATH_MAX]; 1474 dso_name[PATH_MAX];
@@ -1350,38 +1481,69 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1350 (int)(dot - dent->d_name), dent->d_name); 1481 (int)(dot - dent->d_name), dent->d_name);
1351 1482
1352 strxfrchar(dso_name, '-', '_'); 1483 strxfrchar(dso_name, '-', '_');
1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1484 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1354 if (map == NULL) 1485 if (map == NULL)
1355 continue; 1486 continue;
1356 1487
1357 snprintf(path, sizeof(path), "%s/%s", 1488 snprintf(path, sizeof(path), "%s/%s",
1358 dirname, dent->d_name); 1489 dir_name, dent->d_name);
1359 1490
1360 long_name = strdup(path); 1491 long_name = strdup(path);
1361 if (long_name == NULL) 1492 if (long_name == NULL) {
1362 goto failure; 1493 ret = -1;
1494 goto out;
1495 }
1363 dso__set_long_name(map->dso, long_name); 1496 dso__set_long_name(map->dso, long_name);
1497 dso__kernel_module_get_build_id(map->dso, "");
1364 } 1498 }
1365 } 1499 }
1366 1500
1367 return 0; 1501out:
1368failure:
1369 closedir(dir); 1502 closedir(dir);
1370 return -1; 1503 return ret;
1371} 1504}
1372 1505
1373static int perf_session__set_modules_path(struct perf_session *self) 1506static char *get_kernel_version(const char *root_dir)
1374{ 1507{
1375 struct utsname uts; 1508 char version[PATH_MAX];
1509 FILE *file;
1510 char *name, *tmp;
1511 const char *prefix = "Linux version ";
1512
1513 sprintf(version, "%s/proc/version", root_dir);
1514 file = fopen(version, "r");
1515 if (!file)
1516 return NULL;
1517
1518 version[0] = '\0';
1519 tmp = fgets(version, sizeof(version), file);
1520 fclose(file);
1521
1522 name = strstr(version, prefix);
1523 if (!name)
1524 return NULL;
1525 name += strlen(prefix);
1526 tmp = strchr(name, ' ');
1527 if (tmp)
1528 *tmp = '\0';
1529
1530 return strdup(name);
1531}
1532
1533static int machine__set_modules_path(struct machine *self)
1534{
1535 char *version;
1376 char modules_path[PATH_MAX]; 1536 char modules_path[PATH_MAX];
1377 1537
1378 if (uname(&uts) < 0) 1538 version = get_kernel_version(self->root_dir);
1539 if (!version)
1379 return -1; 1540 return -1;
1380 1541
1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1542 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1382 uts.release); 1543 self->root_dir, version);
1544 free(version);
1383 1545
1384 return perf_session__set_modules_path_dir(self, modules_path); 1546 return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
1385} 1547}
1386 1548
1387/* 1549/*
@@ -1391,8 +1553,8 @@ static int perf_session__set_modules_path(struct perf_session *self)
1391 */ 1553 */
1392static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1554static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1393{ 1555{
1394 struct map *self = malloc(sizeof(*self)); 1556 struct map *self = calloc(1, (sizeof(*self) +
1395 1557 (dso->kernel ? sizeof(struct kmap) : 0)));
1396 if (self != NULL) { 1558 if (self != NULL) {
1397 /* 1559 /*
1398 * ->end will be filled after we load all the symbols 1560 * ->end will be filled after we load all the symbols
@@ -1403,20 +1565,50 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1403 return self; 1565 return self;
1404} 1566}
1405 1567
1406static int perf_session__create_module_maps(struct perf_session *self) 1568struct map *machine__new_module(struct machine *self, u64 start,
1569 const char *filename)
1570{
1571 struct map *map;
1572 struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
1573
1574 if (dso == NULL)
1575 return NULL;
1576
1577 map = map__new2(start, dso, MAP__FUNCTION);
1578 if (map == NULL)
1579 return NULL;
1580
1581 if (machine__is_host(self))
1582 dso->origin = DSO__ORIG_KMODULE;
1583 else
1584 dso->origin = DSO__ORIG_GUEST_KMODULE;
1585 map_groups__insert(&self->kmaps, map);
1586 return map;
1587}
1588
1589static int machine__create_modules(struct machine *self)
1407{ 1590{
1408 char *line = NULL; 1591 char *line = NULL;
1409 size_t n; 1592 size_t n;
1410 FILE *file = fopen("/proc/modules", "r"); 1593 FILE *file;
1411 struct map *map; 1594 struct map *map;
1595 const char *modules;
1596 char path[PATH_MAX];
1597
1598 if (machine__is_default_guest(self))
1599 modules = symbol_conf.default_guest_modules;
1600 else {
1601 sprintf(path, "%s/proc/modules", self->root_dir);
1602 modules = path;
1603 }
1412 1604
1605 file = fopen(modules, "r");
1413 if (file == NULL) 1606 if (file == NULL)
1414 return -1; 1607 return -1;
1415 1608
1416 while (!feof(file)) { 1609 while (!feof(file)) {
1417 char name[PATH_MAX]; 1610 char name[PATH_MAX];
1418 u64 start; 1611 u64 start;
1419 struct dso *dso;
1420 char *sep; 1612 char *sep;
1421 int line_len; 1613 int line_len;
1422 1614
@@ -1442,32 +1634,16 @@ static int perf_session__create_module_maps(struct perf_session *self)
1442 *sep = '\0'; 1634 *sep = '\0';
1443 1635
1444 snprintf(name, sizeof(name), "[%s]", line); 1636 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name); 1637 map = machine__new_module(self, start, name);
1446 1638 if (map == NULL)
1447 if (dso == NULL)
1448 goto out_delete_line;
1449
1450 map = map__new2(start, dso, MAP__FUNCTION);
1451 if (map == NULL) {
1452 dso__delete(dso);
1453 goto out_delete_line; 1639 goto out_delete_line;
1454 } 1640 dso__kernel_module_get_build_id(map->dso, self->root_dir);
1455
1456 snprintf(name, sizeof(name),
1457 "/sys/module/%s/notes/.note.gnu.build-id", line);
1458 if (sysfs__read_build_id(name, dso->build_id,
1459 sizeof(dso->build_id)) == 0)
1460 dso->has_build_id = true;
1461
1462 dso->origin = DSO__ORIG_KMODULE;
1463 map_groups__insert(&self->kmaps, map);
1464 dsos__add(&dsos__kernel, dso);
1465 } 1641 }
1466 1642
1467 free(line); 1643 free(line);
1468 fclose(file); 1644 fclose(file);
1469 1645
1470 return perf_session__set_modules_path(self); 1646 return machine__set_modules_path(self);
1471 1647
1472out_delete_line: 1648out_delete_line:
1473 free(line); 1649 free(line);
@@ -1476,7 +1652,6 @@ out_failure:
1476} 1652}
1477 1653
1478static int dso__load_vmlinux(struct dso *self, struct map *map, 1654static int dso__load_vmlinux(struct dso *self, struct map *map,
1479 struct perf_session *session,
1480 const char *vmlinux, symbol_filter_t filter) 1655 const char *vmlinux, symbol_filter_t filter)
1481{ 1656{
1482 int err = -1, fd; 1657 int err = -1, fd;
@@ -1510,51 +1685,139 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1510 return -1; 1685 return -1;
1511 1686
1512 dso__set_loaded(self, map->type); 1687 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 1688 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
1514 close(fd); 1689 close(fd);
1515 1690
1691 if (err > 0)
1692 pr_debug("Using %s for symbols\n", vmlinux);
1693
1694 return err;
1695}
1696
1697int dso__load_vmlinux_path(struct dso *self, struct map *map,
1698 symbol_filter_t filter)
1699{
1700 int i, err = 0;
1701 char *filename;
1702
1703 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1704 vmlinux_path__nr_entries + 1);
1705
1706 filename = dso__build_id_filename(self, NULL, 0);
1707 if (filename != NULL) {
1708 err = dso__load_vmlinux(self, map, filename, filter);
1709 if (err > 0) {
1710 dso__set_long_name(self, filename);
1711 goto out;
1712 }
1713 free(filename);
1714 }
1715
1716 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1717 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1718 if (err > 0) {
1719 dso__set_long_name(self, strdup(vmlinux_path[i]));
1720 break;
1721 }
1722 }
1723out:
1516 return err; 1724 return err;
1517} 1725}
1518 1726
1519static int dso__load_kernel_sym(struct dso *self, struct map *map, 1727static int dso__load_kernel_sym(struct dso *self, struct map *map,
1520 struct perf_session *session, symbol_filter_t filter) 1728 symbol_filter_t filter)
1521{ 1729{
1522 int err; 1730 int err;
1523 bool is_kallsyms; 1731 const char *kallsyms_filename = NULL;
1732 char *kallsyms_allocated_filename = NULL;
1733 /*
1734 * Step 1: if the user specified a vmlinux filename, use it and only
1735 * it, reporting errors to the user if it cannot be used.
1736 *
1737 * For instance, try to analyse an ARM perf.data file _without_ a
1738 * build-id, or if the user specifies the wrong path to the right
1739 * vmlinux file, obviously we can't fallback to another vmlinux (a
1740 * x86_86 one, on the machine where analysis is being performed, say),
1741 * or worse, /proc/kallsyms.
1742 *
1743 * If the specified file _has_ a build-id and there is a build-id
1744 * section in the perf.data file, we will still do the expected
1745 * validation in dso__load_vmlinux and will bail out if they don't
1746 * match.
1747 */
1748 if (symbol_conf.vmlinux_name != NULL) {
1749 err = dso__load_vmlinux(self, map,
1750 symbol_conf.vmlinux_name, filter);
1751 if (err > 0) {
1752 dso__set_long_name(self,
1753 strdup(symbol_conf.vmlinux_name));
1754 goto out_fixup;
1755 }
1756 return err;
1757 }
1524 1758
1525 if (vmlinux_path != NULL) { 1759 if (vmlinux_path != NULL) {
1526 int i; 1760 err = dso__load_vmlinux_path(self, map, filter);
1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1761 if (err > 0)
1528 vmlinux_path__nr_entries); 1762 goto out_fixup;
1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1763 }
1530 err = dso__load_vmlinux(self, map, session, 1764
1531 vmlinux_path[i], filter); 1765 /*
1532 if (err > 0) { 1766 * Say the kernel DSO was created when processing the build-id header table,
1533 pr_debug("Using %s for symbols\n", 1767 * we have a build-id, so check if it is the same as the running kernel,
1534 vmlinux_path[i]); 1768 * using it if it is.
1535 dso__set_long_name(self, 1769 */
1536 strdup(vmlinux_path[i])); 1770 if (self->has_build_id) {
1537 goto out_fixup; 1771 u8 kallsyms_build_id[BUILD_ID_SIZE];
1772 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1773
1774 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1775 sizeof(kallsyms_build_id)) == 0) {
1776 if (dso__build_id_equal(self, kallsyms_build_id)) {
1777 kallsyms_filename = "/proc/kallsyms";
1778 goto do_kallsyms;
1538 } 1779 }
1539 } 1780 }
1540 } 1781 /*
1782 * Now look if we have it on the build-id cache in
1783 * $HOME/.debug/[kernel.kallsyms].
1784 */
1785 build_id__sprintf(self->build_id, sizeof(self->build_id),
1786 sbuild_id);
1541 1787
1542 is_kallsyms = self->long_name[0] == '['; 1788 if (asprintf(&kallsyms_allocated_filename,
1543 if (is_kallsyms) 1789 "%s/.debug/[kernel.kallsyms]/%s",
1544 goto do_kallsyms; 1790 getenv("HOME"), sbuild_id) == -1) {
1791 pr_err("Not enough memory for kallsyms file lookup\n");
1792 return -1;
1793 }
1545 1794
1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1795 kallsyms_filename = kallsyms_allocated_filename;
1547 if (err <= 0) { 1796
1548 pr_info("The file %s cannot be used, " 1797 if (access(kallsyms_filename, F_OK)) {
1549 "trying to use /proc/kallsyms...", self->long_name); 1798 pr_err("No kallsyms or vmlinux with build-id %s "
1550do_kallsyms: 1799 "was found\n", sbuild_id);
1551 err = dso__load_kallsyms(self, map, session, filter); 1800 free(kallsyms_allocated_filename);
1552 if (err > 0 && !is_kallsyms) 1801 return -1;
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1802 }
1803 } else {
1804 /*
1805 * Last resort, if we don't have a build-id and couldn't find
1806 * any vmlinux file, try the running kernel kallsyms table.
1807 */
1808 kallsyms_filename = "/proc/kallsyms";
1554 } 1809 }
1555 1810
1811do_kallsyms:
1812 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1813 if (err > 0)
1814 pr_debug("Using %s for symbols\n", kallsyms_filename);
1815 free(kallsyms_allocated_filename);
1816
1556 if (err > 0) { 1817 if (err > 0) {
1557out_fixup: 1818out_fixup:
1819 if (kallsyms_filename != NULL)
1820 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1558 map__fixup_start(map); 1821 map__fixup_start(map);
1559 map__fixup_end(map); 1822 map__fixup_end(map);
1560 } 1823 }
@@ -1562,9 +1825,56 @@ out_fixup:
1562 return err; 1825 return err;
1563} 1826}
1564 1827
1565LIST_HEAD(dsos__user); 1828static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1566LIST_HEAD(dsos__kernel); 1829 symbol_filter_t filter)
1567struct dso *vdso; 1830{
1831 int err;
1832 const char *kallsyms_filename = NULL;
1833 struct machine *machine;
1834 char path[PATH_MAX];
1835
1836 if (!map->groups) {
1837 pr_debug("Guest kernel map hasn't the point to groups\n");
1838 return -1;
1839 }
1840 machine = map->groups->machine;
1841
1842 if (machine__is_default_guest(machine)) {
1843 /*
1844 * if the user specified a vmlinux filename, use it and only
1845 * it, reporting errors to the user if it cannot be used.
1846 * Or use file guest_kallsyms inputted by user on commandline
1847 */
1848 if (symbol_conf.default_guest_vmlinux_name != NULL) {
1849 err = dso__load_vmlinux(self, map,
1850 symbol_conf.default_guest_vmlinux_name, filter);
1851 goto out_try_fixup;
1852 }
1853
1854 kallsyms_filename = symbol_conf.default_guest_kallsyms;
1855 if (!kallsyms_filename)
1856 return -1;
1857 } else {
1858 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1859 kallsyms_filename = path;
1860 }
1861
1862 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1863 if (err > 0)
1864 pr_debug("Using %s for symbols\n", kallsyms_filename);
1865
1866out_try_fixup:
1867 if (err > 0) {
1868 if (kallsyms_filename != NULL) {
1869 machine__mmap_name(machine, path, sizeof(path));
1870 dso__set_long_name(self, strdup(path));
1871 }
1872 map__fixup_start(map);
1873 map__fixup_end(map);
1874 }
1875
1876 return err;
1877}
1568 1878
1569static void dsos__add(struct list_head *head, struct dso *dso) 1879static void dsos__add(struct list_head *head, struct dso *dso)
1570{ 1880{
@@ -1576,19 +1886,19 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
1576 struct dso *pos; 1886 struct dso *pos;
1577 1887
1578 list_for_each_entry(pos, head, node) 1888 list_for_each_entry(pos, head, node)
1579 if (strcmp(pos->name, name) == 0) 1889 if (strcmp(pos->long_name, name) == 0)
1580 return pos; 1890 return pos;
1581 return NULL; 1891 return NULL;
1582} 1892}
1583 1893
1584struct dso *dsos__findnew(const char *name) 1894struct dso *__dsos__findnew(struct list_head *head, const char *name)
1585{ 1895{
1586 struct dso *dso = dsos__find(&dsos__user, name); 1896 struct dso *dso = dsos__find(head, name);
1587 1897
1588 if (!dso) { 1898 if (!dso) {
1589 dso = dso__new(name); 1899 dso = dso__new(name);
1590 if (dso != NULL) { 1900 if (dso != NULL) {
1591 dsos__add(&dsos__user, dso); 1901 dsos__add(head, dso);
1592 dso__set_basename(dso); 1902 dso__set_basename(dso);
1593 } 1903 }
1594 } 1904 }
@@ -1596,96 +1906,165 @@ struct dso *dsos__findnew(const char *name)
1596 return dso; 1906 return dso;
1597} 1907}
1598 1908
1599static void __dsos__fprintf(struct list_head *head, FILE *fp) 1909size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1600{ 1910{
1601 struct dso *pos; 1911 struct dso *pos;
1912 size_t ret = 0;
1602 1913
1603 list_for_each_entry(pos, head, node) { 1914 list_for_each_entry(pos, head, node) {
1604 int i; 1915 int i;
1605 for (i = 0; i < MAP__NR_TYPES; ++i) 1916 for (i = 0; i < MAP__NR_TYPES; ++i)
1606 dso__fprintf(pos, i, fp); 1917 ret += dso__fprintf(pos, i, fp);
1607 } 1918 }
1919
1920 return ret;
1608} 1921}
1609 1922
1610void dsos__fprintf(FILE *fp) 1923size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
1611{ 1924{
1612 __dsos__fprintf(&dsos__kernel, fp); 1925 struct rb_node *nd;
1613 __dsos__fprintf(&dsos__user, fp); 1926 size_t ret = 0;
1927
1928 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
1929 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1930 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
1931 ret += __dsos__fprintf(&pos->user_dsos, fp);
1932 }
1933
1934 return ret;
1614} 1935}
1615 1936
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 1937static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1938 bool with_hits)
1617{ 1939{
1618 struct dso *pos; 1940 struct dso *pos;
1619 size_t ret = 0; 1941 size_t ret = 0;
1620 1942
1621 list_for_each_entry(pos, head, node) { 1943 list_for_each_entry(pos, head, node) {
1944 if (with_hits && !pos->hit)
1945 continue;
1622 ret += dso__fprintf_buildid(pos, fp); 1946 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name); 1947 ret += fprintf(fp, " %s\n", pos->long_name);
1624 } 1948 }
1625 return ret; 1949 return ret;
1626} 1950}
1627 1951
1628size_t dsos__fprintf_buildid(FILE *fp) 1952size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
1629{ 1953{
1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1954 return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
1631 __dsos__fprintf_buildid(&dsos__user, fp)); 1955 __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
1632} 1956}
1633 1957
1634static struct dso *dsos__create_kernel( const char *vmlinux) 1958size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
1635{ 1959{
1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1960 struct rb_node *nd;
1961 size_t ret = 0;
1637 1962
1638 if (kernel == NULL) 1963 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
1639 return NULL; 1964 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1965 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
1966 }
1967 return ret;
1968}
1640 1969
1641 kernel->short_name = "[kernel]"; 1970struct dso *dso__new_kernel(const char *name)
1642 kernel->kernel = 1; 1971{
1972 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1643 1973
1644 vdso = dso__new("[vdso]"); 1974 if (self != NULL) {
1645 if (vdso == NULL) 1975 dso__set_short_name(self, "[kernel]");
1646 goto out_delete_kernel_dso; 1976 self->kernel = DSO_TYPE_KERNEL;
1647 dso__set_loaded(vdso, MAP__FUNCTION); 1977 }
1648 1978
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1979 return self;
1650 sizeof(kernel->build_id)) == 0) 1980}
1651 kernel->has_build_id = true;
1652 1981
1653 dsos__add(&dsos__kernel, kernel); 1982static struct dso *dso__new_guest_kernel(struct machine *machine,
1654 dsos__add(&dsos__user, vdso); 1983 const char *name)
1984{
1985 char bf[PATH_MAX];
1986 struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
1655 1987
1656 return kernel; 1988 if (self != NULL) {
1989 dso__set_short_name(self, "[guest.kernel]");
1990 self->kernel = DSO_TYPE_GUEST_KERNEL;
1991 }
1657 1992
1658out_delete_kernel_dso: 1993 return self;
1659 dso__delete(kernel);
1660 return NULL;
1661} 1994}
1662 1995
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 1996void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
1664{ 1997{
1665 struct map *functions, *variables; 1998 char path[PATH_MAX];
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667 1999
1668 if (kernel == NULL) 2000 if (machine__is_default_guest(machine))
1669 return -1; 2001 return;
2002 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2003 if (sysfs__read_build_id(path, self->build_id,
2004 sizeof(self->build_id)) == 0)
2005 self->has_build_id = true;
2006}
1670 2007
1671 functions = map__new2(0, kernel, MAP__FUNCTION); 2008static struct dso *machine__create_kernel(struct machine *self)
1672 if (functions == NULL) 2009{
1673 return -1; 2010 const char *vmlinux_name = NULL;
2011 struct dso *kernel;
1674 2012
1675 variables = map__new2(0, kernel, MAP__VARIABLE); 2013 if (machine__is_host(self)) {
1676 if (variables == NULL) { 2014 vmlinux_name = symbol_conf.vmlinux_name;
1677 map__delete(functions); 2015 kernel = dso__new_kernel(vmlinux_name);
1678 return -1; 2016 } else {
2017 if (machine__is_default_guest(self))
2018 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2019 kernel = dso__new_guest_kernel(self, vmlinux_name);
1679 } 2020 }
1680 2021
1681 functions->map_ip = functions->unmap_ip = 2022 if (kernel != NULL) {
1682 variables->map_ip = variables->unmap_ip = identity__map_ip; 2023 dso__read_running_kernel_build_id(kernel, self);
1683 map_groups__insert(self, functions); 2024 dsos__add(&self->kernel_dsos, kernel);
1684 map_groups__insert(self, variables); 2025 }
2026 return kernel;
2027}
2028
2029int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2030{
2031 enum map_type type;
2032
2033 for (type = 0; type < MAP__NR_TYPES; ++type) {
2034 struct kmap *kmap;
2035
2036 self->vmlinux_maps[type] = map__new2(0, kernel, type);
2037 if (self->vmlinux_maps[type] == NULL)
2038 return -1;
2039
2040 self->vmlinux_maps[type]->map_ip =
2041 self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
2042
2043 kmap = map__kmap(self->vmlinux_maps[type]);
2044 kmap->kmaps = &self->kmaps;
2045 map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
2046 }
1685 2047
1686 return 0; 2048 return 0;
1687} 2049}
1688 2050
2051int machine__create_kernel_maps(struct machine *self)
2052{
2053 struct dso *kernel = machine__create_kernel(self);
2054
2055 if (kernel == NULL ||
2056 __machine__create_kernel_maps(self, kernel) < 0)
2057 return -1;
2058
2059 if (symbol_conf.use_modules && machine__create_modules(self) < 0)
2060 pr_debug("Problems creating module maps, continuing anyway...\n");
2061 /*
2062 * Now that we have all the maps created, just set the ->end of them:
2063 */
2064 map_groups__fixup_end(&self->kmaps);
2065 return 0;
2066}
2067
1689static void vmlinux_path__exit(void) 2068static void vmlinux_path__exit(void)
1690{ 2069{
1691 while (--vmlinux_path__nr_entries >= 0) { 2070 while (--vmlinux_path__nr_entries >= 0) {
@@ -1741,6 +2120,25 @@ out_fail:
1741 return -1; 2120 return -1;
1742} 2121}
1743 2122
2123size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp)
2124{
2125 int i;
2126 size_t printed = 0;
2127 struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso;
2128
2129 if (kdso->has_build_id) {
2130 char filename[PATH_MAX];
2131 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
2132 printed += fprintf(fp, "[0] %s\n", filename);
2133 }
2134
2135 for (i = 0; i < vmlinux_path__nr_entries; ++i)
2136 printed += fprintf(fp, "[%d] %s\n",
2137 i + kdso->has_build_id, vmlinux_path[i]);
2138
2139 return printed;
2140}
2141
1744static int setup_list(struct strlist **list, const char *list_str, 2142static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name) 2143 const char *list_name)
1746{ 2144{
@@ -1791,19 +2189,129 @@ out_free_comm_list:
1791 return -1; 2189 return -1;
1792} 2190}
1793 2191
1794int perf_session__create_kernel_maps(struct perf_session *self) 2192int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
1795{ 2193{
1796 if (map_groups__create_kernel_maps(&self->kmaps, 2194 struct machine *machine = machines__findnew(self, pid);
1797 symbol_conf.vmlinux_name) < 0) 2195
2196 if (machine == NULL)
1798 return -1; 2197 return -1;
1799 2198
1800 if (symbol_conf.use_modules && 2199 return machine__create_kernel_maps(machine);
1801 perf_session__create_module_maps(self) < 0) 2200}
1802 pr_debug("Failed to load list of modules for session %s, " 2201
1803 "continuing...\n", self->filename); 2202static int hex(char ch)
1804 /* 2203{
1805 * Now that we have all the maps created, just set the ->end of them: 2204 if ((ch >= '0') && (ch <= '9'))
1806 */ 2205 return ch - '0';
1807 map_groups__fixup_end(&self->kmaps); 2206 if ((ch >= 'a') && (ch <= 'f'))
1808 return 0; 2207 return ch - 'a' + 10;
2208 if ((ch >= 'A') && (ch <= 'F'))
2209 return ch - 'A' + 10;
2210 return -1;
2211}
2212
2213/*
2214 * While we find nice hex chars, build a long_val.
2215 * Return number of chars processed.
2216 */
2217int hex2u64(const char *ptr, u64 *long_val)
2218{
2219 const char *p = ptr;
2220 *long_val = 0;
2221
2222 while (*p) {
2223 const int hex_val = hex(*p);
2224
2225 if (hex_val < 0)
2226 break;
2227
2228 *long_val = (*long_val << 4) | hex_val;
2229 p++;
2230 }
2231
2232 return p - ptr;
2233}
2234
2235char *strxfrchar(char *s, char from, char to)
2236{
2237 char *p = s;
2238
2239 while ((p = strchr(p, from)) != NULL)
2240 *p++ = to;
2241
2242 return s;
2243}
2244
2245int machines__create_guest_kernel_maps(struct rb_root *self)
2246{
2247 int ret = 0;
2248 struct dirent **namelist = NULL;
2249 int i, items = 0;
2250 char path[PATH_MAX];
2251 pid_t pid;
2252
2253 if (symbol_conf.default_guest_vmlinux_name ||
2254 symbol_conf.default_guest_modules ||
2255 symbol_conf.default_guest_kallsyms) {
2256 machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
2257 }
2258
2259 if (symbol_conf.guestmount) {
2260 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2261 if (items <= 0)
2262 return -ENOENT;
2263 for (i = 0; i < items; i++) {
2264 if (!isdigit(namelist[i]->d_name[0])) {
2265 /* Filter out . and .. */
2266 continue;
2267 }
2268 pid = atoi(namelist[i]->d_name);
2269 sprintf(path, "%s/%s/proc/kallsyms",
2270 symbol_conf.guestmount,
2271 namelist[i]->d_name);
2272 ret = access(path, R_OK);
2273 if (ret) {
2274 pr_debug("Can't access file %s\n", path);
2275 goto failure;
2276 }
2277 machines__create_kernel_maps(self, pid);
2278 }
2279failure:
2280 free(namelist);
2281 }
2282
2283 return ret;
2284}
2285
2286int machine__load_kallsyms(struct machine *self, const char *filename,
2287 enum map_type type, symbol_filter_t filter)
2288{
2289 struct map *map = self->vmlinux_maps[type];
2290 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
2291
2292 if (ret > 0) {
2293 dso__set_loaded(map->dso, type);
2294 /*
2295 * Since /proc/kallsyms will have multiple sessions for the
2296 * kernel, with modules between them, fixup the end of all
2297 * sections.
2298 */
2299 __map_groups__fixup_end(&self->kmaps, type);
2300 }
2301
2302 return ret;
2303}
2304
2305int machine__load_vmlinux_path(struct machine *self, enum map_type type,
2306 symbol_filter_t filter)
2307{
2308 struct map *map = self->vmlinux_maps[type];
2309 int ret = dso__load_vmlinux_path(map->dso, map, filter);
2310
2311 if (ret > 0) {
2312 dso__set_loaded(map->dso, type);
2313 map__reloc_vmlinux(map);
2314 }
2315
2316 return ret;
1809} 2317}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8aded2356f79..5e02d2c17154 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -3,10 +3,13 @@
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>
11
12#define DEBUG_CACHE_DIR ".debug"
10 13
11#ifdef HAVE_CPLUS_DEMANGLE 14#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int); 15extern char *cplus_demangle(const char *, int);
@@ -27,6 +30,9 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
27#endif 30#endif
28#endif 31#endif
29 32
33int hex2u64(const char *ptr, u64 *val);
34char *strxfrchar(char *s, char from, char to);
35
30/* 36/*
31 * 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;
32 * for newer versions we can use mmap to reduce memory usage: 38 * for newer versions we can use mmap to reduce memory usage:
@@ -42,13 +48,18 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
42#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 48#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
43#endif 49#endif
44 50
51#define BUILD_ID_SIZE 20
52
45struct symbol { 53struct symbol {
46 struct rb_node rb_node; 54 struct rb_node rb_node;
47 u64 start; 55 u64 start;
48 u64 end; 56 u64 end;
57 u16 namelen;
49 char name[0]; 58 char name[0];
50}; 59};
51 60
61void symbol__delete(struct symbol *self);
62
52struct strlist; 63struct strlist;
53 64
54struct symbol_conf { 65struct symbol_conf {
@@ -58,10 +69,16 @@ struct symbol_conf {
58 sort_by_name, 69 sort_by_name,
59 show_nr_samples, 70 show_nr_samples,
60 use_callchain, 71 use_callchain,
61 exclude_other; 72 exclude_other,
73 full_paths,
74 show_cpu_utilization;
62 const char *vmlinux_name, 75 const char *vmlinux_name,
63 *field_sep; 76 *field_sep;
64 char *dso_list_str, 77 const char *default_guest_vmlinux_name,
78 *default_guest_kallsyms,
79 *default_guest_modules;
80 const char *guestmount;
81 const char *dso_list_str,
65 *comm_list_str, 82 *comm_list_str,
66 *sym_list_str, 83 *sym_list_str,
67 *col_width_list_str; 84 *col_width_list_str;
@@ -77,6 +94,17 @@ static inline void *symbol__priv(struct symbol *self)
77 return ((void *)self) - symbol_conf.priv_size; 94 return ((void *)self) - symbol_conf.priv_size;
78} 95}
79 96
97struct ref_reloc_sym {
98 const char *name;
99 u64 addr;
100 u64 unrelocated_addr;
101};
102
103struct map_symbol {
104 struct map *map;
105 struct symbol *sym;
106};
107
80struct addr_location { 108struct addr_location {
81 struct thread *thread; 109 struct thread *thread;
82 struct map *map; 110 struct map *map;
@@ -84,6 +112,13 @@ struct addr_location {
84 u64 addr; 112 u64 addr;
85 char level; 113 char level;
86 bool filtered; 114 bool filtered;
115 unsigned int cpumode;
116};
117
118enum dso_kernel_type {
119 DSO_TYPE_USER = 0,
120 DSO_TYPE_KERNEL,
121 DSO_TYPE_GUEST_KERNEL
87}; 122};
88 123
89struct dso { 124struct dso {
@@ -93,49 +128,94 @@ struct dso {
93 u8 adjust_symbols:1; 128 u8 adjust_symbols:1;
94 u8 slen_calculated:1; 129 u8 slen_calculated:1;
95 u8 has_build_id:1; 130 u8 has_build_id:1;
96 u8 kernel:1; 131 enum dso_kernel_type kernel;
132 u8 hit:1;
133 u8 annotate_warned:1;
97 unsigned char origin; 134 unsigned char origin;
98 u8 sorted_by_name; 135 u8 sorted_by_name;
99 u8 loaded; 136 u8 loaded;
100 u8 build_id[BUILD_ID_SIZE]; 137 u8 build_id[BUILD_ID_SIZE];
101 u16 long_name_len;
102 const char *short_name; 138 const char *short_name;
103 char *long_name; 139 char *long_name;
140 u16 long_name_len;
141 u16 short_name_len;
104 char name[0]; 142 char name[0];
105}; 143};
106 144
107struct dso *dso__new(const char *name); 145struct dso *dso__new(const char *name);
146struct dso *dso__new_kernel(const char *name);
108void dso__delete(struct dso *self); 147void dso__delete(struct dso *self);
109 148
110bool dso__loaded(const struct dso *self, enum map_type type); 149bool dso__loaded(const struct dso *self, enum map_type type);
111bool dso__sorted_by_name(const struct dso *self, enum map_type type); 150bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112 151
152static inline void dso__set_loaded(struct dso *self, enum map_type type)
153{
154 self->loaded |= (1 << type);
155}
156
113void dso__sort_by_name(struct dso *self, enum map_type type); 157void dso__sort_by_name(struct dso *self, enum map_type type);
114 158
115struct perf_session; 159struct dso *__dsos__findnew(struct list_head *head, const char *name);
160
161int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
162int dso__load_vmlinux_path(struct dso *self, struct map *map,
163 symbol_filter_t filter);
164int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
165 symbol_filter_t filter);
166int machine__load_kallsyms(struct machine *self, const char *filename,
167 enum map_type type, symbol_filter_t filter);
168int machine__load_vmlinux_path(struct machine *self, enum map_type type,
169 symbol_filter_t filter);
170
171size_t __dsos__fprintf(struct list_head *head, FILE *fp);
116 172
117struct dso *dsos__findnew(const char *name); 173size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits);
118int dso__load(struct dso *self, struct map *map, struct perf_session *session, 174size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
119 symbol_filter_t filter); 175size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits);
120void dsos__fprintf(FILE *fp);
121size_t dsos__fprintf_buildid(FILE *fp);
122 176
123size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 177size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 178size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
179
180enum dso_origin {
181 DSO__ORIG_KERNEL = 0,
182 DSO__ORIG_GUEST_KERNEL,
183 DSO__ORIG_JAVA_JIT,
184 DSO__ORIG_BUILD_ID_CACHE,
185 DSO__ORIG_FEDORA,
186 DSO__ORIG_UBUNTU,
187 DSO__ORIG_BUILDID,
188 DSO__ORIG_DSO,
189 DSO__ORIG_GUEST_KMODULE,
190 DSO__ORIG_KMODULE,
191 DSO__ORIG_NOT_FOUND,
192};
193
125char dso__symtab_origin(const struct dso *self); 194char dso__symtab_origin(const struct dso *self);
195void dso__set_long_name(struct dso *self, char *name);
126void dso__set_build_id(struct dso *self, void *build_id); 196void dso__set_build_id(struct dso *self, void *build_id);
197void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 198struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 199struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name); 200 const char *name);
130 201
131int filename__read_build_id(const char *filename, void *bf, size_t size); 202int filename__read_build_id(const char *filename, void *bf, size_t size);
132int sysfs__read_build_id(const char *filename, void *bf, size_t size); 203int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void); 204bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
134int build_id__sprintf(u8 *self, int len, char *bf); 205int build_id__sprintf(const u8 *self, int len, char *bf);
206int kallsyms__parse(const char *filename, void *arg,
207 int (*process_symbol)(void *arg, const char *name,
208 char type, u64 start));
209
210int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
211int machine__create_kernel_maps(struct machine *self);
212
213int machines__create_kernel_maps(struct rb_root *self, pid_t pid);
214int machines__create_guest_kernel_maps(struct rb_root *self);
135 215
136int symbol__init(void); 216int symbol__init(void);
137int perf_session__create_kernel_maps(struct perf_session *self); 217bool symbol_type__is_a(char symbol_type, enum map_type map_type);
218
219size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp);
138 220
139extern struct list_head dsos__user, dsos__kernel;
140extern struct dso *vdso;
141#endif /* __PERF_SYMBOL */ 221#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 4a08dcf50b68..9a448b47400c 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,13 +7,44 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10void map_groups__init(struct map_groups *self) 10/* Skip "." and ".." directories */
11static int filter(const struct dirent *dir)
11{ 12{
13 if (dir->d_name[0] == '.')
14 return 0;
15 else
16 return 1;
17}
18
19int find_all_tid(int pid, pid_t ** all_tid)
20{
21 char name[256];
22 int items;
23 struct dirent **namelist = NULL;
24 int ret = 0;
12 int i; 25 int i;
13 for (i = 0; i < MAP__NR_TYPES; ++i) { 26
14 self->maps[i] = RB_ROOT; 27 sprintf(name, "/proc/%d/task", pid);
15 INIT_LIST_HEAD(&self->removed_maps[i]); 28 items = scandir(name, &namelist, filter, NULL);
29 if (items <= 0)
30 return -ENOENT;
31 *all_tid = malloc(sizeof(pid_t) * items);
32 if (!*all_tid) {
33 ret = -ENOMEM;
34 goto failure;
16 } 35 }
36
37 for (i = 0; i < items; i++)
38 (*all_tid)[i] = atoi(namelist[i]->d_name);
39
40 ret = items;
41
42failure:
43 for (i=0; i<items; i++)
44 free(namelist[i]);
45 free(namelist);
46
47 return ret;
17} 48}
18 49
19static struct thread *thread__new(pid_t pid) 50static struct thread *thread__new(pid_t pid)
@@ -33,10 +64,17 @@ static struct thread *thread__new(pid_t pid)
33 64
34int thread__set_comm(struct thread *self, const char *comm) 65int thread__set_comm(struct thread *self, const char *comm)
35{ 66{
67 int err;
68
36 if (self->comm) 69 if (self->comm)
37 free(self->comm); 70 free(self->comm);
38 self->comm = strdup(comm); 71 self->comm = strdup(comm);
39 return self->comm ? 0 : -ENOMEM; 72 err = self->comm == NULL ? -ENOMEM : 0;
73 if (!err) {
74 self->comm_set = true;
75 map_groups__flush(&self->mg);
76 }
77 return err;
40} 78}
41 79
42int thread__comm_len(struct thread *self) 80int thread__comm_len(struct thread *self)
@@ -50,74 +88,10 @@ int thread__comm_len(struct thread *self)
50 return self->comm_len; 88 return self->comm_len;
51} 89}
52 90
53static const char *map_type__name[MAP__NR_TYPES] = {
54 [MAP__FUNCTION] = "Functions",
55 [MAP__VARIABLE] = "Variables",
56};
57
58static size_t __map_groups__fprintf_maps(struct map_groups *self,
59 enum map_type type, FILE *fp)
60{
61 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
62 struct rb_node *nd;
63
64 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
65 struct map *pos = rb_entry(nd, struct map, rb_node);
66 printed += fprintf(fp, "Map:");
67 printed += map__fprintf(pos, fp);
68 if (verbose > 1) {
69 printed += dso__fprintf(pos->dso, type, fp);
70 printed += fprintf(fp, "--\n");
71 }
72 }
73
74 return printed;
75}
76
77size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
78{
79 size_t printed = 0, i;
80 for (i = 0; i < MAP__NR_TYPES; ++i)
81 printed += __map_groups__fprintf_maps(self, i, fp);
82 return printed;
83}
84
85static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
86 enum map_type type, FILE *fp)
87{
88 struct map *pos;
89 size_t printed = 0;
90
91 list_for_each_entry(pos, &self->removed_maps[type], node) {
92 printed += fprintf(fp, "Map:");
93 printed += map__fprintf(pos, fp);
94 if (verbose > 1) {
95 printed += dso__fprintf(pos->dso, type, fp);
96 printed += fprintf(fp, "--\n");
97 }
98 }
99 return printed;
100}
101
102static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
103{
104 size_t printed = 0, i;
105 for (i = 0; i < MAP__NR_TYPES; ++i)
106 printed += __map_groups__fprintf_removed_maps(self, i, fp);
107 return printed;
108}
109
110static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
111{
112 size_t printed = map_groups__fprintf_maps(self, fp);
113 printed += fprintf(fp, "Removed maps:\n");
114 return printed + map_groups__fprintf_removed_maps(self, fp);
115}
116
117static size_t thread__fprintf(struct thread *self, FILE *fp) 91static size_t thread__fprintf(struct thread *self, FILE *fp)
118{ 92{
119 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 93 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
120 map_groups__fprintf(&self->mg, fp); 94 map_groups__fprintf(&self->mg, verbose, fp);
121} 95}
122 96
123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) 97struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
@@ -159,107 +133,24 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
159 return th; 133 return th;
160} 134}
161 135
162static void map_groups__remove_overlappings(struct map_groups *self,
163 struct map *map)
164{
165 struct rb_root *root = &self->maps[map->type];
166 struct rb_node *next = rb_first(root);
167
168 while (next) {
169 struct map *pos = rb_entry(next, struct map, rb_node);
170 next = rb_next(&pos->rb_node);
171
172 if (!map__overlap(pos, map))
173 continue;
174
175 if (verbose >= 2) {
176 fputs("overlapping maps:\n", stderr);
177 map__fprintf(map, stderr);
178 map__fprintf(pos, stderr);
179 }
180
181 rb_erase(&pos->rb_node, root);
182 /*
183 * We may have references to this map, for instance in some
184 * hist_entry instances, so just move them to a separate
185 * list.
186 */
187 list_add_tail(&pos->node, &self->removed_maps[map->type]);
188 }
189}
190
191void maps__insert(struct rb_root *maps, struct map *map)
192{
193 struct rb_node **p = &maps->rb_node;
194 struct rb_node *parent = NULL;
195 const u64 ip = map->start;
196 struct map *m;
197
198 while (*p != NULL) {
199 parent = *p;
200 m = rb_entry(parent, struct map, rb_node);
201 if (ip < m->start)
202 p = &(*p)->rb_left;
203 else
204 p = &(*p)->rb_right;
205 }
206
207 rb_link_node(&map->rb_node, parent, p);
208 rb_insert_color(&map->rb_node, maps);
209}
210
211struct map *maps__find(struct rb_root *maps, u64 ip)
212{
213 struct rb_node **p = &maps->rb_node;
214 struct rb_node *parent = NULL;
215 struct map *m;
216
217 while (*p != NULL) {
218 parent = *p;
219 m = rb_entry(parent, struct map, rb_node);
220 if (ip < m->start)
221 p = &(*p)->rb_left;
222 else if (ip > m->end)
223 p = &(*p)->rb_right;
224 else
225 return m;
226 }
227
228 return NULL;
229}
230
231void thread__insert_map(struct thread *self, struct map *map) 136void thread__insert_map(struct thread *self, struct map *map)
232{ 137{
233 map_groups__remove_overlappings(&self->mg, map); 138 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr);
234 map_groups__insert(&self->mg, map); 139 map_groups__insert(&self->mg, map);
235} 140}
236 141
237/*
238 * XXX This should not really _copy_ te maps, but refcount them.
239 */
240static int map_groups__clone(struct map_groups *self,
241 struct map_groups *parent, enum map_type type)
242{
243 struct rb_node *nd;
244 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
245 struct map *map = rb_entry(nd, struct map, rb_node);
246 struct map *new = map__clone(map);
247 if (new == NULL)
248 return -ENOMEM;
249 map_groups__insert(self, new);
250 }
251 return 0;
252}
253
254int thread__fork(struct thread *self, struct thread *parent) 142int thread__fork(struct thread *self, struct thread *parent)
255{ 143{
256 int i; 144 int i;
257 145
258 if (self->comm) 146 if (parent->comm_set) {
259 free(self->comm); 147 if (self->comm)
260 self->comm = strdup(parent->comm); 148 free(self->comm);
261 if (!self->comm) 149 self->comm = strdup(parent->comm);
262 return -ENOMEM; 150 if (!self->comm)
151 return -ENOMEM;
152 self->comm_set = true;
153 }
263 154
264 for (i = 0; i < MAP__NR_TYPES; ++i) 155 for (i = 0; i < MAP__NR_TYPES; ++i)
265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 156 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
@@ -280,16 +171,3 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
280 171
281 return ret; 172 return ret;
282} 173}
283
284struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
286 enum map_type type, u64 addr,
287 symbol_filter_t filter)
288{
289 struct map *map = map_groups__find(self, type, addr);
290
291 if (map != NULL)
292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
293
294 return NULL;
295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index c206f72c8881..ee6bbcf277ca 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,66 +5,43 @@
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
13struct thread { 8struct thread {
14 struct rb_node rb_node; 9 union {
10 struct rb_node rb_node;
11 struct list_head node;
12 };
15 struct map_groups mg; 13 struct map_groups mg;
16 pid_t pid; 14 pid_t pid;
17 char shortname[3]; 15 char shortname[3];
16 bool comm_set;
18 char *comm; 17 char *comm;
19 int comm_len; 18 int comm_len;
20}; 19};
21 20
22void map_groups__init(struct map_groups *self); 21struct perf_session;
22
23int find_all_tid(int pid, pid_t ** all_tid);
23int thread__set_comm(struct thread *self, const char *comm); 24int thread__set_comm(struct thread *self, const char *comm);
24int thread__comm_len(struct thread *self); 25int thread__comm_len(struct thread *self);
25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 26struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
26void thread__insert_map(struct thread *self, struct map *map); 27void thread__insert_map(struct thread *self, struct map *map);
27int thread__fork(struct thread *self, struct thread *parent); 28int thread__fork(struct thread *self, struct thread *parent);
28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
29size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 29size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
30 30
31void maps__insert(struct rb_root *maps, struct map *map);
32struct map *maps__find(struct rb_root *maps, u64 addr);
33
34static inline void map_groups__insert(struct map_groups *self, struct map *map)
35{
36 maps__insert(&self->maps[map->type], map);
37}
38
39static inline struct map *map_groups__find(struct map_groups *self,
40 enum map_type type, u64 addr)
41{
42 return maps__find(&self->maps[type], addr);
43}
44
45static inline struct map *thread__find_map(struct thread *self, 31static inline struct map *thread__find_map(struct thread *self,
46 enum map_type type, u64 addr) 32 enum map_type type, u64 addr)
47{ 33{
48 return self ? map_groups__find(&self->mg, type, addr) : NULL; 34 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49} 35}
50 36
37void thread__find_addr_map(struct thread *self,
38 struct perf_session *session, u8 cpumode,
39 enum map_type type, pid_t pid, u64 addr,
40 struct addr_location *al);
41
51void thread__find_addr_location(struct thread *self, 42void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode, 43 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr, 44 enum map_type type, pid_t pid, u64 addr,
54 struct addr_location *al, 45 struct addr_location *al,
55 symbol_filter_t filter); 46 symbol_filter_t filter);
56struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
58 enum map_type type, u64 addr,
59 symbol_filter_t filter);
60
61static inline struct symbol *
62map_groups__find_function(struct map_groups *self, struct perf_session *session,
63 u64 addr, symbol_filter_t filter)
64{
65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
70#endif /* __PERF_THREAD_H */ 47#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index cace35595530..b1572601286c 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#define _GNU_SOURCE 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
@@ -37,6 +38,7 @@
37 38
38#include "../perf.h" 39#include "../perf.h"
39#include "trace-event.h" 40#include "trace-event.h"
41#include "debugfs.h"
40 42
41#define VERSION "0.5" 43#define VERSION "0.5"
42 44
@@ -101,32 +103,12 @@ void *malloc_or_die(unsigned int size)
101 103
102static const char *find_debugfs(void) 104static const char *find_debugfs(void)
103{ 105{
104 static char debugfs[MAX_PATH+1]; 106 const char *path = debugfs_mount(NULL);
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126 107
127 debugfs_found = 1; 108 if (!path)
109 die("Your kernel not support debugfs filesystem");
128 110
129 return debugfs; 111 return path;
130} 112}
131 113
132/* 114/*
@@ -172,10 +154,17 @@ static void put_tracing_file(char *file)
172 free(file); 154 free(file);
173} 155}
174 156
157static ssize_t calc_data_size;
158
175static ssize_t write_or_die(const void *buf, size_t len) 159static ssize_t write_or_die(const void *buf, size_t len)
176{ 160{
177 int ret; 161 int ret;
178 162
163 if (calc_data_size) {
164 calc_data_size += len;
165 return len;
166 }
167
179 ret = write(output_fd, buf, len); 168 ret = write(output_fd, buf, len);
180 if (ret < 0) 169 if (ret < 0)
181 die("writing to '%s'", output_file); 170 die("writing to '%s'", output_file);
@@ -271,6 +260,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 260 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 261 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 262 check_size = copy_file_fd(fd);
263 close(fd);
264
274 if (size != check_size) 265 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 266 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 267 path, size, check_size);
@@ -289,6 +280,7 @@ static void read_header_files(void)
289 if (size != check_size) 280 if (size != check_size)
290 die("wrong size for '%s'", path); 281 die("wrong size for '%s'", path);
291 put_tracing_file(path); 282 put_tracing_file(path);
283 close(fd);
292} 284}
293 285
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 286static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +309,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 309 die("can't read directory '%s'", sys);
318 310
319 while ((dent = readdir(dir))) { 311 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 312 if (dent->d_type != DT_DIR ||
313 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 314 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 315 !name_in_tp_list(dent->d_name, tps))
323 continue; 316 continue;
@@ -334,7 +327,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 327
335 rewinddir(dir); 328 rewinddir(dir);
336 while ((dent = readdir(dir))) { 329 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 330 if (dent->d_type != DT_DIR ||
331 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 332 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 333 !name_in_tp_list(dent->d_name, tps))
340 continue; 334 continue;
@@ -353,6 +347,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 347
354 free(format); 348 free(format);
355 } 349 }
350 closedir(dir);
356} 351}
357 352
358static void read_ftrace_files(struct tracepoint_path *tps) 353static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +389,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 389 die("can't read directory '%s'", path);
395 390
396 while ((dent = readdir(dir))) { 391 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 392 if (dent->d_type != DT_DIR ||
393 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 394 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 395 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 396 !system_in_tp_list(dent->d_name, tps))
401 continue; 397 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 398 count++;
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 } 399 }
411 400
412 write_or_die(&count, 4); 401 write_or_die(&count, 4);
413 402
414 rewinddir(dir); 403 rewinddir(dir);
415 while ((dent = readdir(dir))) { 404 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 405 if (dent->d_type != DT_DIR ||
406 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 407 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 408 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 409 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +412,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 412 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 413 ret = stat(sys, &st);
424 if (ret >= 0) { 414 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 415 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 416 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 417 }
430 free(sys); 418 free(sys);
431 } 419 }
432 420
421 closedir(dir);
433 put_tracing_file(path); 422 put_tracing_file(path);
434} 423}
435 424
@@ -498,6 +487,17 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
498 return nr_tracepoints > 0 ? path.next : NULL; 487 return nr_tracepoints > 0 ? path.next : NULL;
499} 488}
500 489
490bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events)
491{
492 int i;
493
494 for (i = 0; i < nb_events; i++)
495 if (pattrs[i].type == PERF_TYPE_TRACEPOINT)
496 return true;
497
498 return false;
499}
500
501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
502{ 502{
503 char buf[BUFSIZ]; 503 char buf[BUFSIZ];
@@ -533,7 +533,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
533 write_or_die(buf, 1); 533 write_or_die(buf, 1);
534 534
535 /* save page_size */ 535 /* save page_size */
536 page_size = getpagesize(); 536 page_size = sysconf(_SC_PAGESIZE);
537 write_or_die(&page_size, 4); 537 write_or_die(&page_size, 4);
538 538
539 read_header_files(); 539 read_header_files();
@@ -544,3 +544,20 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
544 544
545 return 0; 545 return 0;
546} 546}
547
548ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
549 int nb_events)
550{
551 ssize_t size;
552 int err = 0;
553
554 calc_data_size = 1;
555 err = read_tracing_data(fd, pattrs, nb_events);
556 size = calc_data_size - 1;
557 calc_data_size = 0;
558
559 if (err < 0)
560 return err;
561
562 return size;
563}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index c5c32be040bf..73a02223c629 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -37,10 +37,12 @@ int header_page_ts_offset;
37int header_page_ts_size; 37int header_page_ts_size;
38int header_page_size_offset; 38int header_page_size_offset;
39int header_page_size_size; 39int header_page_size_size;
40int header_page_overwrite_offset;
41int header_page_overwrite_size;
40int header_page_data_offset; 42int header_page_data_offset;
41int header_page_data_size; 43int header_page_data_size;
42 44
43int latency_format; 45bool latency_format;
44 46
45static char *input_buf; 47static char *input_buf;
46static unsigned long long input_buf_ptr; 48static unsigned long long input_buf_ptr;
@@ -628,23 +630,32 @@ static int test_type(enum event_type type, enum event_type expect)
628 return 0; 630 return 0;
629} 631}
630 632
631static int test_type_token(enum event_type type, char *token, 633static int __test_type_token(enum event_type type, char *token,
632 enum event_type expect, const char *expect_tok) 634 enum event_type expect, const char *expect_tok,
635 bool warn)
633{ 636{
634 if (type != expect) { 637 if (type != expect) {
635 warning("Error: expected type %d but read %d", 638 if (warn)
636 expect, type); 639 warning("Error: expected type %d but read %d",
640 expect, type);
637 return -1; 641 return -1;
638 } 642 }
639 643
640 if (strcmp(token, expect_tok) != 0) { 644 if (strcmp(token, expect_tok) != 0) {
641 warning("Error: expected '%s' but read '%s'", 645 if (warn)
642 expect_tok, token); 646 warning("Error: expected '%s' but read '%s'",
647 expect_tok, token);
643 return -1; 648 return -1;
644 } 649 }
645 return 0; 650 return 0;
646} 651}
647 652
653static int test_type_token(enum event_type type, char *token,
654 enum event_type expect, const char *expect_tok)
655{
656 return __test_type_token(type, token, expect, expect_tok, true);
657}
658
648static int __read_expect_type(enum event_type expect, char **tok, int newline_ok) 659static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
649{ 660{
650 enum event_type type; 661 enum event_type type;
@@ -661,7 +672,8 @@ static int read_expect_type(enum event_type expect, char **tok)
661 return __read_expect_type(expect, tok, 1); 672 return __read_expect_type(expect, tok, 1);
662} 673}
663 674
664static int __read_expected(enum event_type expect, const char *str, int newline_ok) 675static int __read_expected(enum event_type expect, const char *str,
676 int newline_ok, bool warn)
665{ 677{
666 enum event_type type; 678 enum event_type type;
667 char *token; 679 char *token;
@@ -672,7 +684,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
672 else 684 else
673 type = read_token_item(&token); 685 type = read_token_item(&token);
674 686
675 ret = test_type_token(type, token, expect, str); 687 ret = __test_type_token(type, token, expect, str, warn);
676 688
677 free_token(token); 689 free_token(token);
678 690
@@ -681,12 +693,12 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
681 693
682static int read_expected(enum event_type expect, const char *str) 694static int read_expected(enum event_type expect, const char *str)
683{ 695{
684 return __read_expected(expect, str, 1); 696 return __read_expected(expect, str, 1, true);
685} 697}
686 698
687static int read_expected_item(enum event_type expect, const char *str) 699static int read_expected_item(enum event_type expect, const char *str)
688{ 700{
689 return __read_expected(expect, str, 0); 701 return __read_expected(expect, str, 0, true);
690} 702}
691 703
692static char *event_read_name(void) 704static char *event_read_name(void)
@@ -744,7 +756,7 @@ static int field_is_string(struct format_field *field)
744 756
745static int field_is_dynamic(struct format_field *field) 757static int field_is_dynamic(struct format_field *field)
746{ 758{
747 if (!strcmp(field->type, "__data_loc")) 759 if (!strncmp(field->type, "__data_loc", 10))
748 return 1; 760 return 1;
749 761
750 return 0; 762 return 0;
@@ -1925,6 +1937,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data)
1925 if (!field) 1937 if (!field)
1926 return NULL; 1938 return NULL;
1927 1939
1940 if (field->flags & FIELD_IS_DYNAMIC) {
1941 int offset;
1942
1943 offset = *(int *)(data + field->offset);
1944 offset &= 0xffff;
1945
1946 return data + offset;
1947 }
1948
1928 return data + field->offset; 1949 return data + field->offset;
1929} 1950}
1930 1951
@@ -3078,88 +3099,6 @@ static void print_args(struct print_arg *args)
3078 } 3099 }
3079} 3100}
3080 3101
3081static void parse_header_field(const char *field,
3082 int *offset, int *size)
3083{
3084 char *token;
3085 int type;
3086
3087 if (read_expected(EVENT_ITEM, "field") < 0)
3088 return;
3089 if (read_expected(EVENT_OP, ":") < 0)
3090 return;
3091
3092 /* type */
3093 if (read_expect_type(EVENT_ITEM, &token) < 0)
3094 goto fail;
3095 free_token(token);
3096
3097 if (read_expected(EVENT_ITEM, field) < 0)
3098 return;
3099 if (read_expected(EVENT_OP, ";") < 0)
3100 return;
3101 if (read_expected(EVENT_ITEM, "offset") < 0)
3102 return;
3103 if (read_expected(EVENT_OP, ":") < 0)
3104 return;
3105 if (read_expect_type(EVENT_ITEM, &token) < 0)
3106 goto fail;
3107 *offset = atoi(token);
3108 free_token(token);
3109 if (read_expected(EVENT_OP, ";") < 0)
3110 return;
3111 if (read_expected(EVENT_ITEM, "size") < 0)
3112 return;
3113 if (read_expected(EVENT_OP, ":") < 0)
3114 return;
3115 if (read_expect_type(EVENT_ITEM, &token) < 0)
3116 goto fail;
3117 *size = atoi(token);
3118 free_token(token);
3119 if (read_expected(EVENT_OP, ";") < 0)
3120 return;
3121 type = read_token(&token);
3122 if (type != EVENT_NEWLINE) {
3123 /* newer versions of the kernel have a "signed" type */
3124 if (type != EVENT_ITEM)
3125 goto fail;
3126
3127 if (strcmp(token, "signed") != 0)
3128 goto fail;
3129
3130 free_token(token);
3131
3132 if (read_expected(EVENT_OP, ":") < 0)
3133 return;
3134
3135 if (read_expect_type(EVENT_ITEM, &token))
3136 goto fail;
3137
3138 free_token(token);
3139 if (read_expected(EVENT_OP, ";") < 0)
3140 return;
3141
3142 if (read_expect_type(EVENT_NEWLINE, &token))
3143 goto fail;
3144 }
3145 fail:
3146 free_token(token);
3147}
3148
3149int parse_header_page(char *buf, unsigned long size)
3150{
3151 init_input_buf(buf, size);
3152
3153 parse_header_field("timestamp", &header_page_ts_offset,
3154 &header_page_ts_size);
3155 parse_header_field("commit", &header_page_size_offset,
3156 &header_page_size_size);
3157 parse_header_field("data", &header_page_data_offset,
3158 &header_page_data_size);
3159
3160 return 0;
3161}
3162
3163int parse_ftrace_file(char *buf, unsigned long size) 3102int parse_ftrace_file(char *buf, unsigned long size)
3164{ 3103{
3165 struct format_field *field; 3104 struct format_field *field;
@@ -3277,3 +3216,18 @@ void parse_set_info(int nr_cpus, int long_sz)
3277 cpus = nr_cpus; 3216 cpus = nr_cpus;
3278 long_size = long_sz; 3217 long_size = long_sz;
3279} 3218}
3219
3220int common_pc(struct scripting_context *context)
3221{
3222 return parse_common_pc(context->event_data);
3223}
3224
3225int common_flags(struct scripting_context *context)
3226{
3227 return parse_common_flags(context->event_data);
3228}
3229
3230int common_lock_depth(struct scripting_context *context)
3231{
3232 return parse_common_lock_depth(context->event_data);
3233}
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
deleted file mode 100644
index e88fb26137bb..000000000000
--- a/tools/perf/util/trace-event-perl.h
+++ /dev/null
@@ -1,55 +0,0 @@
1#ifndef __PERF_TRACE_EVENT_PERL_H
2#define __PERF_TRACE_EVENT_PERL_H
3#ifdef NO_LIBPERL
4typedef int INTERP;
5#define dSP
6#define ENTER
7#define SAVETMPS
8#define PUTBACK
9#define SPAGAIN
10#define FREETMPS
11#define LEAVE
12#define SP
13#define ERRSV
14#define G_SCALAR (0)
15#define G_DISCARD (0)
16#define G_NOARGS (0)
17#define PUSHMARK(a)
18#define SvTRUE(a) (0)
19#define XPUSHs(s)
20#define sv_2mortal(a)
21#define newSVpv(a,b)
22#define newSVuv(a)
23#define newSViv(a)
24#define get_cv(a,b) (0)
25#define call_pv(a,b) (0)
26#define perl_alloc() (0)
27#define perl_construct(a) (0)
28#define perl_parse(a,b,c,d,e) (0)
29#define perl_run(a) (0)
30#define perl_destruct(a) (0)
31#define perl_free(a) (0)
32#define pTHX void
33#define CV void
34#define dXSUB_SYS
35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
39#else
40#include <EXTERN.h>
41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
44typedef PerlInterpreter * INTERP;
45#endif
46
47struct scripting_context {
48 void *event_data;
49};
50
51int common_pc(struct scripting_context *context);
52int common_flags(struct scripting_context *context);
53int common_lock_depth(struct scripting_context *context);
54
55#endif /* __PERF_TRACE_EVENT_PERL_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1744422cafcb..f55cc3a765a1 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _LARGEFILE64_SOURCE 21#define _FILE_OFFSET_BITS 64
22 22
23#include <dirent.h> 23#include <dirent.h>
24#include <stdio.h> 24#include <stdio.h>
@@ -50,17 +50,61 @@ static int long_size;
50 50
51static unsigned long page_size; 51static unsigned long page_size;
52 52
53static ssize_t calc_data_size;
54static bool repipe;
55
56static int do_read(int fd, void *buf, int size)
57{
58 int rsize = size;
59
60 while (size) {
61 int ret = read(fd, buf, size);
62
63 if (ret <= 0)
64 return -1;
65
66 if (repipe) {
67 int retw = write(STDOUT_FILENO, buf, ret);
68
69 if (retw <= 0 || retw != ret)
70 die("repiping input file");
71 }
72
73 size -= ret;
74 buf += ret;
75 }
76
77 return rsize;
78}
79
53static int read_or_die(void *data, int size) 80static int read_or_die(void *data, int size)
54{ 81{
55 int r; 82 int r;
56 83
57 r = read(input_fd, data, size); 84 r = do_read(input_fd, data, size);
58 if (r != size) 85 if (r <= 0)
59 die("reading input file (size expected=%d received=%d)", 86 die("reading input file (size expected=%d received=%d)",
60 size, r); 87 size, r);
88
89 if (calc_data_size)
90 calc_data_size += r;
91
61 return r; 92 return r;
62} 93}
63 94
95/* If it fails, the next read will report it */
96static void skip(int size)
97{
98 char buf[BUFSIZ];
99 int r;
100
101 while (size) {
102 r = size > BUFSIZ ? BUFSIZ : size;
103 read_or_die(buf, r);
104 size -= r;
105 };
106}
107
64static unsigned int read4(void) 108static unsigned int read4(void)
65{ 109{
66 unsigned int data; 110 unsigned int data;
@@ -82,57 +126,36 @@ static char *read_string(void)
82 char buf[BUFSIZ]; 126 char buf[BUFSIZ];
83 char *str = NULL; 127 char *str = NULL;
84 int size = 0; 128 int size = 0;
85 int i; 129 off_t r;
86 int r; 130 char c;
87 131
88 for (;;) { 132 for (;;) {
89 r = read(input_fd, buf, BUFSIZ); 133 r = read(input_fd, &c, 1);
90 if (r < 0) 134 if (r < 0)
91 die("reading input file"); 135 die("reading input file");
92 136
93 if (!r) 137 if (!r)
94 die("no data"); 138 die("no data");
95 139
96 for (i = 0; i < r; i++) { 140 if (repipe) {
97 if (!buf[i]) 141 int retw = write(STDOUT_FILENO, &c, 1);
98 break;
99 }
100 if (i < r)
101 break;
102 142
103 if (str) { 143 if (retw <= 0 || retw != r)
104 size += BUFSIZ; 144 die("repiping input file string");
105 str = realloc(str, size);
106 if (!str)
107 die("malloc of size %d", size);
108 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
109 } else {
110 size = BUFSIZ;
111 str = malloc_or_die(size);
112 memcpy(str, buf, size);
113 } 145 }
114 }
115 146
116 /* trailing \0: */ 147 buf[size++] = c;
117 i++; 148
118 149 if (!c)
119 /* move the file descriptor to the end of the string */ 150 break;
120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0)
122 die("lseek");
123
124 if (str) {
125 size += i;
126 str = realloc(str, size);
127 if (!str)
128 die("malloc of size %d", size);
129 memcpy(str + (size - i), buf, i);
130 } else {
131 size = i;
132 str = malloc_or_die(i);
133 memcpy(str, buf, i);
134 } 151 }
135 152
153 if (calc_data_size)
154 calc_data_size += size;
155
156 str = malloc_or_die(size);
157 memcpy(str, buf, size);
158
136 return str; 159 return str;
137} 160}
138 161
@@ -174,7 +197,6 @@ static void read_ftrace_printk(void)
174static void read_header_files(void) 197static void read_header_files(void)
175{ 198{
176 unsigned long long size; 199 unsigned long long size;
177 char *header_page;
178 char *header_event; 200 char *header_event;
179 char buf[BUFSIZ]; 201 char buf[BUFSIZ];
180 202
@@ -184,10 +206,7 @@ static void read_header_files(void)
184 die("did not read header page"); 206 die("did not read header page");
185 207
186 size = read8(); 208 size = read8();
187 header_page = malloc_or_die(size); 209 skip(size);
188 read_or_die(header_page, size);
189 parse_header_page(header_page, size);
190 free(header_page);
191 210
192 /* 211 /*
193 * The size field in the page is of type long, 212 * The size field in the page is of type long,
@@ -282,8 +301,8 @@ static void update_cpu_data_index(int cpu)
282 301
283static void get_next_page(int cpu) 302static void get_next_page(int cpu)
284{ 303{
285 off64_t save_seek; 304 off_t save_seek;
286 off64_t ret; 305 off_t ret;
287 306
288 if (!cpu_data[cpu].page) 307 if (!cpu_data[cpu].page)
289 return; 308 return;
@@ -298,17 +317,17 @@ static void get_next_page(int cpu)
298 update_cpu_data_index(cpu); 317 update_cpu_data_index(cpu);
299 318
300 /* other parts of the code may expect the pointer to not move */ 319 /* other parts of the code may expect the pointer to not move */
301 save_seek = lseek64(input_fd, 0, SEEK_CUR); 320 save_seek = lseek(input_fd, 0, SEEK_CUR);
302 321
303 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 322 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
304 if (ret < 0) 323 if (ret == (off_t)-1)
305 die("failed to lseek"); 324 die("failed to lseek");
306 ret = read(input_fd, cpu_data[cpu].page, page_size); 325 ret = read(input_fd, cpu_data[cpu].page, page_size);
307 if (ret < 0) 326 if (ret < 0)
308 die("failed to read page"); 327 die("failed to read page");
309 328
310 /* reset the file pointer back */ 329 /* reset the file pointer back */
311 lseek64(input_fd, save_seek, SEEK_SET); 330 lseek(input_fd, save_seek, SEEK_SET);
312 331
313 return; 332 return;
314 } 333 }
@@ -459,7 +478,7 @@ struct record *trace_read_data(int cpu)
459 return data; 478 return data;
460} 479}
461 480
462void trace_report(int fd) 481ssize_t trace_report(int fd, bool __repipe)
463{ 482{
464 char buf[BUFSIZ]; 483 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 484 char test[] = { 23, 8, 68 };
@@ -467,6 +486,10 @@ void trace_report(int fd)
467 int show_version = 0; 486 int show_version = 0;
468 int show_funcs = 0; 487 int show_funcs = 0;
469 int show_printk = 0; 488 int show_printk = 0;
489 ssize_t size;
490
491 calc_data_size = 1;
492 repipe = __repipe;
470 493
471 input_fd = fd; 494 input_fd = fd;
472 495
@@ -499,14 +522,18 @@ void trace_report(int fd)
499 read_proc_kallsyms(); 522 read_proc_kallsyms();
500 read_ftrace_printk(); 523 read_ftrace_printk();
501 524
525 size = calc_data_size - 1;
526 calc_data_size = 0;
527 repipe = false;
528
502 if (show_funcs) { 529 if (show_funcs) {
503 print_funcs(); 530 print_funcs();
504 return; 531 return size;
505 } 532 }
506 if (show_printk) { 533 if (show_printk) {
507 print_printk(); 534 print_printk();
508 return; 535 return size;
509 } 536 }
510 537
511 return; 538 return size;
512} 539}
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
new file mode 100644
index 000000000000..7ea983acfaea
--- /dev/null
+++ b/tools/perf/util/trace-event-scripting.c
@@ -0,0 +1,167 @@
1/*
2 * trace-event-scripting. Scripting engine common and initialization code.
3 *
4 * Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../perf.h"
29#include "util.h"
30#include "trace-event.h"
31
32struct scripting_context *scripting_context;
33
34static int stop_script_unsupported(void)
35{
36 return 0;
37}
38
39static void process_event_unsupported(int cpu __unused,
40 void *data __unused,
41 int size __unused,
42 unsigned long long nsecs __unused,
43 char *comm __unused)
44{
45}
46
47static void print_python_unsupported_msg(void)
48{
49 fprintf(stderr, "Python scripting not supported."
50 " Install libpython and rebuild perf to enable it.\n"
51 "For example:\n # apt-get install python-dev (ubuntu)"
52 "\n # yum install python-devel (Fedora)"
53 "\n etc.\n");
54}
55
56static int python_start_script_unsupported(const char *script __unused,
57 int argc __unused,
58 const char **argv __unused)
59{
60 print_python_unsupported_msg();
61
62 return -1;
63}
64
65static int python_generate_script_unsupported(const char *outfile __unused)
66{
67 print_python_unsupported_msg();
68
69 return -1;
70}
71
72struct scripting_ops python_scripting_unsupported_ops = {
73 .name = "Python",
74 .start_script = python_start_script_unsupported,
75 .stop_script = stop_script_unsupported,
76 .process_event = process_event_unsupported,
77 .generate_script = python_generate_script_unsupported,
78};
79
80static void register_python_scripting(struct scripting_ops *scripting_ops)
81{
82 int err;
83 err = script_spec_register("Python", scripting_ops);
84 if (err)
85 die("error registering Python script extension");
86
87 err = script_spec_register("py", scripting_ops);
88 if (err)
89 die("error registering py script extension");
90
91 scripting_context = malloc(sizeof(struct scripting_context));
92}
93
94#ifdef NO_LIBPYTHON
95void setup_python_scripting(void)
96{
97 register_python_scripting(&python_scripting_unsupported_ops);
98}
99#else
100struct scripting_ops python_scripting_ops;
101
102void setup_python_scripting(void)
103{
104 register_python_scripting(&python_scripting_ops);
105}
106#endif
107
108static void print_perl_unsupported_msg(void)
109{
110 fprintf(stderr, "Perl scripting not supported."
111 " Install libperl and rebuild perf to enable it.\n"
112 "For example:\n # apt-get install libperl-dev (ubuntu)"
113 "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
114 "\n etc.\n");
115}
116
117static int perl_start_script_unsupported(const char *script __unused,
118 int argc __unused,
119 const char **argv __unused)
120{
121 print_perl_unsupported_msg();
122
123 return -1;
124}
125
126static int perl_generate_script_unsupported(const char *outfile __unused)
127{
128 print_perl_unsupported_msg();
129
130 return -1;
131}
132
133struct scripting_ops perl_scripting_unsupported_ops = {
134 .name = "Perl",
135 .start_script = perl_start_script_unsupported,
136 .stop_script = stop_script_unsupported,
137 .process_event = process_event_unsupported,
138 .generate_script = perl_generate_script_unsupported,
139};
140
141static void register_perl_scripting(struct scripting_ops *scripting_ops)
142{
143 int err;
144 err = script_spec_register("Perl", scripting_ops);
145 if (err)
146 die("error registering Perl script extension");
147
148 err = script_spec_register("pl", scripting_ops);
149 if (err)
150 die("error registering pl script extension");
151
152 scripting_context = malloc(sizeof(struct scripting_context));
153}
154
155#ifdef NO_LIBPERL
156void setup_perl_scripting(void)
157{
158 register_perl_scripting(&perl_scripting_unsupported_ops);
159}
160#else
161struct scripting_ops perl_scripting_ops;
162
163void setup_perl_scripting(void)
164{
165 register_perl_scripting(&perl_scripting_ops);
166}
167#endif
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 6ad405620c9b..b3e86b1e4444 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_TRACE_EVENTS_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define __PERF_TRACE_EVENTS_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include <stdbool.h>
4#include "parse-events.h" 5#include "parse-events.h"
5 6
6#define __unused __attribute__((unused)) 7#define __unused __attribute__((unused))
@@ -162,7 +163,7 @@ struct record *trace_read_data(int cpu);
162 163
163void parse_set_info(int nr_cpus, int long_sz); 164void parse_set_info(int nr_cpus, int long_sz);
164 165
165void trace_report(int fd); 166ssize_t trace_report(int fd, bool repipe);
166 167
167void *malloc_or_die(unsigned int size); 168void *malloc_or_die(unsigned int size);
168 169
@@ -232,7 +233,12 @@ static inline unsigned long long __data2host8(unsigned long long data)
232 233
233#define data2host2(ptr) __data2host2(*(unsigned short *)ptr) 234#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
234#define data2host4(ptr) __data2host4(*(unsigned int *)ptr) 235#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
235#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr) 236#define data2host8(ptr) ({ \
237 unsigned long long __val; \
238 \
239 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
240 __data2host8(__val); \
241})
236 242
237extern int header_page_ts_offset; 243extern int header_page_ts_offset;
238extern int header_page_ts_size; 244extern int header_page_ts_size;
@@ -241,9 +247,8 @@ extern int header_page_size_size;
241extern int header_page_data_offset; 247extern int header_page_data_offset;
242extern int header_page_data_size; 248extern int header_page_data_size;
243 249
244extern int latency_format; 250extern bool latency_format;
245 251
246int parse_header_page(char *buf, unsigned long size);
247int trace_parse_common_type(void *data); 252int trace_parse_common_type(void *data);
248int trace_parse_common_pid(void *data); 253int trace_parse_common_pid(void *data);
249int parse_common_pc(void *data); 254int parse_common_pc(void *data);
@@ -258,6 +263,8 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
258unsigned long long eval_flag(const char *flag); 263unsigned long long eval_flag(const char *flag);
259 264
260int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); 265int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
266ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
267 int nb_events);
261 268
262/* taken from kernel/trace/trace.h */ 269/* taken from kernel/trace/trace.h */
263enum trace_flag_type { 270enum trace_flag_type {
@@ -279,7 +286,15 @@ struct scripting_ops {
279 286
280int script_spec_register(const char *spec, struct scripting_ops *ops); 287int script_spec_register(const char *spec, struct scripting_ops *ops);
281 288
282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void); 289void setup_perl_scripting(void);
290void setup_python_scripting(void);
291
292struct scripting_context {
293 void *event_data;
294};
295
296int common_pc(struct scripting_context *context);
297int common_flags(struct scripting_context *context);
298int common_lock_depth(struct scripting_context *context);
284 299
285#endif /* __PERF_TRACE_EVENTS_H */ 300#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 000000000000..214265674ddd
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,116 @@
1#include "util.h"
2#include <sys/mman.h>
3
4int mkdir_p(char *path, mode_t mode)
5{
6 struct stat st;
7 int err;
8 char *d = path;
9
10 if (*d != '/')
11 return -1;
12
13 if (stat(path, &st) == 0)
14 return 0;
15
16 while (*++d == '/');
17
18 while ((d = strchr(d, '/'))) {
19 *d = '\0';
20 err = stat(path, &st) && mkdir(path, mode);
21 *d++ = '/';
22 if (err)
23 return -1;
24 while (*d == '/')
25 ++d;
26 }
27 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
28}
29
30static int slow_copyfile(const char *from, const char *to)
31{
32 int err = 0;
33 char *line = NULL;
34 size_t n;
35 FILE *from_fp = fopen(from, "r"), *to_fp;
36
37 if (from_fp == NULL)
38 goto out;
39
40 to_fp = fopen(to, "w");
41 if (to_fp == NULL)
42 goto out_fclose_from;
43
44 while (getline(&line, &n, from_fp) > 0)
45 if (fputs(line, to_fp) == EOF)
46 goto out_fclose_to;
47 err = 0;
48out_fclose_to:
49 fclose(to_fp);
50 free(line);
51out_fclose_from:
52 fclose(from_fp);
53out:
54 return err;
55}
56
57int copyfile(const char *from, const char *to)
58{
59 int fromfd, tofd;
60 struct stat st;
61 void *addr;
62 int err = -1;
63
64 if (stat(from, &st))
65 goto out;
66
67 if (st.st_size == 0) /* /proc? do it slowly... */
68 return slow_copyfile(from, to);
69
70 fromfd = open(from, O_RDONLY);
71 if (fromfd < 0)
72 goto out;
73
74 tofd = creat(to, 0755);
75 if (tofd < 0)
76 goto out_close_from;
77
78 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
79 if (addr == MAP_FAILED)
80 goto out_close_to;
81
82 if (write(tofd, addr, st.st_size) == st.st_size)
83 err = 0;
84
85 munmap(addr, st.st_size);
86out_close_to:
87 close(tofd);
88 if (err)
89 unlink(to);
90out_close_from:
91 close(fromfd);
92out:
93 return err;
94}
95
96unsigned long convert_unit(unsigned long value, char *unit)
97{
98 *unit = ' ';
99
100 if (value > 1000) {
101 value /= 1000;
102 *unit = 'K';
103 }
104
105 if (value > 1000) {
106 value /= 1000;
107 *unit = 'M';
108 }
109
110 if (value > 1000) {
111 value /= 1000;
112 *unit = 'G';
113 }
114
115 return value;
116}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c673d8825883..4e8b6b0c551c 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -42,12 +42,14 @@
42#define _ALL_SOURCE 1 42#define _ALL_SOURCE 1
43#define _GNU_SOURCE 1 43#define _GNU_SOURCE 1
44#define _BSD_SOURCE 1 44#define _BSD_SOURCE 1
45#define HAS_BOOL
45 46
46#include <unistd.h> 47#include <unistd.h>
47#include <stdio.h> 48#include <stdio.h>
48#include <sys/stat.h> 49#include <sys/stat.h>
49#include <sys/statfs.h> 50#include <sys/statfs.h>
50#include <fcntl.h> 51#include <fcntl.h>
52#include <stdbool.h>
51#include <stddef.h> 53#include <stddef.h>
52#include <stdlib.h> 54#include <stdlib.h>
53#include <stdarg.h> 55#include <stdarg.h>
@@ -78,7 +80,8 @@
78#include <pwd.h> 80#include <pwd.h>
79#include <inttypes.h> 81#include <inttypes.h>
80#include "../../../include/linux/magic.h" 82#include "../../../include/linux/magic.h"
81 83#include "types.h"
84#include <sys/ttydefaults.h>
82 85
83#ifndef NO_ICONV 86#ifndef NO_ICONV
84#include <iconv.h> 87#include <iconv.h>
@@ -149,7 +152,6 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
149extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); 152extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
150 153
151extern int prefixcmp(const char *str, const char *prefix); 154extern int prefixcmp(const char *str, const char *prefix);
152extern time_t tm_to_time_t(const struct tm *tm);
153 155
154static inline const char *skip_prefix(const char *str, const char *prefix) 156static inline const char *skip_prefix(const char *str, const char *prefix)
155{ 157{
@@ -157,119 +159,6 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
157 return strncmp(str, prefix, len) ? NULL : str + len; 159 return strncmp(str, prefix, len) ? NULL : str + len;
158} 160}
159 161
160#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
161
162#ifndef PROT_READ
163#define PROT_READ 1
164#define PROT_WRITE 2
165#define MAP_PRIVATE 1
166#define MAP_FAILED ((void*)-1)
167#endif
168
169#define mmap git_mmap
170#define munmap git_munmap
171extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
172extern int git_munmap(void *start, size_t length);
173
174#else /* NO_MMAP || USE_WIN32_MMAP */
175
176#include <sys/mman.h>
177
178#endif /* NO_MMAP || USE_WIN32_MMAP */
179
180#ifdef NO_MMAP
181
182/* This value must be multiple of (pagesize * 2) */
183#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
184
185#else /* NO_MMAP */
186
187/* This value must be multiple of (pagesize * 2) */
188#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
189 (sizeof(void*) >= 8 \
190 ? 1 * 1024 * 1024 * 1024 \
191 : 32 * 1024 * 1024)
192
193#endif /* NO_MMAP */
194
195#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
196#define on_disk_bytes(st) ((st).st_size)
197#else
198#define on_disk_bytes(st) ((st).st_blocks * 512)
199#endif
200
201#define DEFAULT_PACKED_GIT_LIMIT \
202 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
203
204#ifdef NO_PREAD
205#define pread git_pread
206extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
207#endif
208/*
209 * Forward decl that will remind us if its twin in cache.h changes.
210 * This function is used in compat/pread.c. But we can't include
211 * cache.h there.
212 */
213extern ssize_t read_in_full(int fd, void *buf, size_t count);
214
215#ifdef NO_SETENV
216#define setenv gitsetenv
217extern int gitsetenv(const char *, const char *, int);
218#endif
219
220#ifdef NO_MKDTEMP
221#define mkdtemp gitmkdtemp
222extern char *gitmkdtemp(char *);
223#endif
224
225#ifdef NO_UNSETENV
226#define unsetenv gitunsetenv
227extern void gitunsetenv(const char *);
228#endif
229
230#ifdef NO_STRCASESTR
231#define strcasestr gitstrcasestr
232extern char *gitstrcasestr(const char *haystack, const char *needle);
233#endif
234
235#ifdef NO_STRLCPY
236#define strlcpy gitstrlcpy
237extern size_t gitstrlcpy(char *, const char *, size_t);
238#endif
239
240#ifdef NO_STRTOUMAX
241#define strtoumax gitstrtoumax
242extern uintmax_t gitstrtoumax(const char *, char **, int);
243#endif
244
245#ifdef NO_HSTRERROR
246#define hstrerror githstrerror
247extern const char *githstrerror(int herror);
248#endif
249
250#ifdef NO_MEMMEM
251#define memmem gitmemmem
252void *gitmemmem(const void *haystack, size_t haystacklen,
253 const void *needle, size_t needlelen);
254#endif
255
256#ifdef FREAD_READS_DIRECTORIES
257#ifdef fopen
258#undef fopen
259#endif
260#define fopen(a,b) git_fopen(a,b)
261extern FILE *git_fopen(const char*, const char*);
262#endif
263
264#ifdef SNPRINTF_RETURNS_BOGUS
265#define snprintf git_snprintf
266extern int git_snprintf(char *str, size_t maxsize,
267 const char *format, ...);
268#define vsnprintf git_vsnprintf
269extern int git_vsnprintf(char *str, size_t maxsize,
270 const char *format, va_list ap);
271#endif
272
273#ifdef __GLIBC_PREREQ 162#ifdef __GLIBC_PREREQ
274#if __GLIBC_PREREQ(2, 1) 163#if __GLIBC_PREREQ(2, 1)
275#define HAVE_STRCHRNUL 164#define HAVE_STRCHRNUL
@@ -290,25 +179,19 @@ static inline char *gitstrchrnul(const char *s, int c)
290 * Wrappers: 179 * Wrappers:
291 */ 180 */
292extern char *xstrdup(const char *str); 181extern char *xstrdup(const char *str);
293extern void *xmalloc(size_t size) __attribute__((weak));
294extern void *xmemdupz(const void *data, size_t len);
295extern char *xstrndup(const char *str, size_t len);
296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak)); 182extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
297 183
184
298static inline void *zalloc(size_t size) 185static inline void *zalloc(size_t size)
299{ 186{
300 return calloc(1, size); 187 return calloc(1, size);
301} 188}
302 189
303static inline size_t xsize_t(off_t len)
304{
305 return (size_t)len;
306}
307
308static inline int has_extension(const char *filename, const char *ext) 190static inline int has_extension(const char *filename, const char *ext)
309{ 191{
310 size_t len = strlen(filename); 192 size_t len = strlen(filename);
311 size_t extlen = strlen(ext); 193 size_t extlen = strlen(ext);
194
312 return len > extlen && !memcmp(filename + len - extlen, ext, extlen); 195 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
313} 196}
314 197
@@ -322,6 +205,7 @@ static inline int has_extension(const char *filename, const char *ext)
322#undef isalnum 205#undef isalnum
323#undef tolower 206#undef tolower
324#undef toupper 207#undef toupper
208
325extern unsigned char sane_ctype[256]; 209extern unsigned char sane_ctype[256];
326#define GIT_SPACE 0x01 210#define GIT_SPACE 0x01
327#define GIT_DIGIT 0x02 211#define GIT_DIGIT 0x02
@@ -339,8 +223,6 @@ extern unsigned char sane_ctype[256];
339#define isalpha(x) sane_istest(x,GIT_ALPHA) 223#define isalpha(x) sane_istest(x,GIT_ALPHA)
340#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 224#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
341#define isprint(x) sane_istest(x,GIT_PRINT) 225#define isprint(x) sane_istest(x,GIT_PRINT)
342#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
343#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
344#define tolower(x) sane_case((unsigned char)(x), 0x20) 226#define tolower(x) sane_case((unsigned char)(x), 0x20)
345#define toupper(x) sane_case((unsigned char)(x), 0) 227#define toupper(x) sane_case((unsigned char)(x), 0)
346 228
@@ -351,38 +233,6 @@ static inline int sane_case(int x, int high)
351 return x; 233 return x;
352} 234}
353 235
354static inline int strtoul_ui(char const *s, int base, unsigned int *result)
355{
356 unsigned long ul;
357 char *p;
358
359 errno = 0;
360 ul = strtoul(s, &p, base);
361 if (errno || *p || p == s || (unsigned int) ul != ul)
362 return -1;
363 *result = ul;
364 return 0;
365}
366
367static inline int strtol_i(char const *s, int base, int *result)
368{
369 long ul;
370 char *p;
371
372 errno = 0;
373 ul = strtol(s, &p, base);
374 if (errno || *p || p == s || (int) ul != ul)
375 return -1;
376 *result = ul;
377 return 0;
378}
379
380#ifdef INTERNAL_QSORT
381void git_qsort(void *base, size_t nmemb, size_t size,
382 int(*compar)(const void *, const void *));
383#define qsort git_qsort
384#endif
385
386#ifndef DIR_HAS_BSD_GROUP_SEMANTICS 236#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
387# define FORCE_DIR_SET_GID S_ISGID 237# define FORCE_DIR_SET_GID S_ISGID
388#else 238#else
@@ -403,4 +253,30 @@ void git_qsort(void *base, size_t nmemb, size_t size,
403#endif 253#endif
404#endif 254#endif
405 255
256int mkdir_p(char *path, mode_t mode);
257int copyfile(const char *from, const char *to);
258
259s64 perf_atoll(const char *str);
260char **argv_split(const char *str, int *argcp);
261void argv_free(char **argv);
262bool strglobmatch(const char *str, const char *pat);
263bool strlazymatch(const char *str, const char *pat);
264unsigned long convert_unit(unsigned long value, char *unit);
265
266#ifndef ESC
267#define ESC 27
268#endif
269
270static inline bool is_exit_key(int key)
271{
272 char up;
273 if (key == CTRL('c') || key == ESC)
274 return true;
275 up = toupper(key);
276 return up == 'Q';
277}
278
279#define _STR(x) #x
280#define STR(x) _STR(x)
281
406#endif 282#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 1c15e39f99e3..cfa55d686e3b 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
172 free(counterwidth);
172} 173}
173 174
174static void perf_read_values__display_raw(FILE *fp, 175static void perf_read_values__display_raw(FILE *fp,
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index bf44ca85d23b..73e900edb5a2 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -23,46 +23,6 @@ char *xstrdup(const char *str)
23 return ret; 23 return ret;
24} 24}
25 25
26void *xmalloc(size_t size)
27{
28 void *ret = malloc(size);
29 if (!ret && !size)
30 ret = malloc(1);
31 if (!ret) {
32 release_pack_memory(size, -1);
33 ret = malloc(size);
34 if (!ret && !size)
35 ret = malloc(1);
36 if (!ret)
37 die("Out of memory, malloc failed");
38 }
39#ifdef XMALLOC_POISON
40 memset(ret, 0xA5, size);
41#endif
42 return ret;
43}
44
45/*
46 * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
47 * "data" to the allocated memory, zero terminates the allocated memory,
48 * and returns a pointer to the allocated memory. If the allocation fails,
49 * the program dies.
50 */
51void *xmemdupz(const void *data, size_t len)
52{
53 char *p = xmalloc(len + 1);
54 memcpy(p, data, len);
55 p[len] = '\0';
56 return p;
57}
58
59char *xstrndup(const char *str, size_t len)
60{
61 char *p = memchr(str, '\0', len);
62
63 return xmemdupz(str, p ? (size_t)(p - str) : len);
64}
65
66void *xrealloc(void *ptr, size_t size) 26void *xrealloc(void *ptr, size_t size)
67{ 27{
68 void *ret = realloc(ptr, size); 28 void *ret = realloc(ptr, size);
@@ -78,73 +38,3 @@ void *xrealloc(void *ptr, size_t size)
78 } 38 }
79 return ret; 39 return ret;
80} 40}
81
82/*
83 * xread() is the same a read(), but it automatically restarts read()
84 * operations with a recoverable error (EAGAIN and EINTR). xread()
85 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
86 */
87static ssize_t xread(int fd, void *buf, size_t len)
88{
89 ssize_t nr;
90 while (1) {
91 nr = read(fd, buf, len);
92 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
93 continue;
94 return nr;
95 }
96}
97
98/*
99 * xwrite() is the same a write(), but it automatically restarts write()
100 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
101 * GUARANTEE that "len" bytes is written even if the operation is successful.
102 */
103static ssize_t xwrite(int fd, const void *buf, size_t len)
104{
105 ssize_t nr;
106 while (1) {
107 nr = write(fd, buf, len);
108 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
109 continue;
110 return nr;
111 }
112}
113
114ssize_t read_in_full(int fd, void *buf, size_t count)
115{
116 char *p = buf;
117 ssize_t total = 0;
118
119 while (count > 0) {
120 ssize_t loaded = xread(fd, p, count);
121 if (loaded <= 0)
122 return total ? total : loaded;
123 count -= loaded;
124 p += loaded;
125 total += loaded;
126 }
127
128 return total;
129}
130
131ssize_t write_in_full(int fd, const void *buf, size_t count)
132{
133 const char *p = buf;
134 ssize_t total = 0;
135
136 while (count > 0) {
137 ssize_t written = xwrite(fd, p, count);
138 if (written < 0)
139 return -1;
140 if (!written) {
141 errno = ENOSPC;
142 return -1;
143 }
144 count -= written;
145 p += written;
146 total += written;
147 }
148
149 return total;
150}