aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-14 00:16:56 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-14 00:16:56 -0400
commitfc8e1ead9314cf0e0f1922e661428b93d3a50d88 (patch)
treef3cb97c4769b74f6627a59769f1ed5c92a13c58a /tools/perf/util
parent2bcaa6a4238094c5695d5b1943078388d82d3004 (diff)
parent9de48cc300fb10f7d9faa978670becf5e352462a (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'tools/perf/util')
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN42
-rw-r--r--tools/perf/util/abspath.c117
-rw-r--r--tools/perf/util/alias.c77
-rw-r--r--tools/perf/util/cache.h121
-rw-r--r--tools/perf/util/callchain.c343
-rw-r--r--tools/perf/util/callchain.h60
-rw-r--r--tools/perf/util/color.c272
-rw-r--r--tools/perf/util/color.h41
-rw-r--r--tools/perf/util/config.c875
-rw-r--r--tools/perf/util/ctype.c31
-rw-r--r--tools/perf/util/environment.c9
-rw-r--r--tools/perf/util/exec_cmd.c168
-rw-r--r--tools/perf/util/exec_cmd.h13
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh24
-rw-r--r--tools/perf/util/header.c245
-rw-r--r--tools/perf/util/header.h37
-rw-r--r--tools/perf/util/help.c356
-rw-r--r--tools/perf/util/help.h29
-rw-r--r--tools/perf/util/include/asm/system.h1
-rw-r--r--tools/perf/util/include/linux/kernel.h29
-rw-r--r--tools/perf/util/include/linux/list.h18
-rw-r--r--tools/perf/util/include/linux/module.h6
-rw-r--r--tools/perf/util/include/linux/poison.h1
-rw-r--r--tools/perf/util/include/linux/prefetch.h6
-rw-r--r--tools/perf/util/include/linux/rbtree.h1
-rw-r--r--tools/perf/util/levenshtein.c84
-rw-r--r--tools/perf/util/levenshtein.h8
-rw-r--r--tools/perf/util/module.c509
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/pager.c96
-rw-r--r--tools/perf/util/parse-events.c682
-rw-r--r--tools/perf/util/parse-events.h23
-rw-r--r--tools/perf/util/parse-options.c509
-rw-r--r--tools/perf/util/parse-options.h175
-rw-r--r--tools/perf/util/path.c353
-rw-r--r--tools/perf/util/quote.c485
-rw-r--r--tools/perf/util/quote.h68
-rw-r--r--tools/perf/util/run-command.c304
-rw-r--r--tools/perf/util/run-command.h88
-rw-r--r--tools/perf/util/sigchain.c52
-rw-r--r--tools/perf/util/sigchain.h11
-rw-r--r--tools/perf/util/strbuf.c360
-rw-r--r--tools/perf/util/strbuf.h137
-rw-r--r--tools/perf/util/string.c34
-rw-r--r--tools/perf/util/string.h11
-rw-r--r--tools/perf/util/strlist.c200
-rw-r--r--tools/perf/util/strlist.h39
-rw-r--r--tools/perf/util/symbol.c930
-rw-r--r--tools/perf/util/symbol.h80
-rw-r--r--tools/perf/util/types.h17
-rw-r--r--tools/perf/util/usage.c80
-rw-r--r--tools/perf/util/util.h395
-rw-r--r--tools/perf/util/wrapper.c207
53 files changed, 8912 insertions, 0 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
new file mode 100755
index 000000000000..c561d1538c03
--- /dev/null
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -0,0 +1,42 @@
1#!/bin/sh
2
3GVF=PERF-VERSION-FILE
4DEF_VER=v0.0.1.PERF
5
6LF='
7'
8
9# First see if there is a version file (included in release tarballs),
10# then try git-describe, then default.
11if test -f version
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) &&
16 case "$VN" in
17 *$LF*) (exit 1) ;;
18 v[0-9]*)
19 git update-index -q --refresh
20 test -z "$(git diff-index --name-only HEAD --)" ||
21 VN="$VN-dirty" ;;
22 esac
23then
24 VN=$(echo "$VN" | sed -e 's/-/./g');
25else
26 VN="$DEF_VER"
27fi
28
29VN=$(expr "$VN" : v*'\(.*\)')
30
31if test -r $GVF
32then
33 VC=$(sed -e 's/^PERF_VERSION = //' <$GVF)
34else
35 VC=unset
36fi
37test "$VN" = "$VC" || {
38 echo >&2 "PERF_VERSION = $VN"
39 echo "PERF_VERSION = $VN" >$GVF
40}
41
42
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
new file mode 100644
index 000000000000..61d33b81fc97
--- /dev/null
+++ b/tools/perf/util/abspath.c
@@ -0,0 +1,117 @@
1#include "cache.h"
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 int len = strlen(buf);
54 if (len + strlen(last_elem) + 2 > PATH_MAX)
55 die ("Too long path name: '%s/%s'",
56 buf, last_elem);
57 buf[len] = '/';
58 strcpy(buf + len + 1, last_elem);
59 free(last_elem);
60 last_elem = NULL;
61 }
62
63 if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
64 len = readlink(buf, next_buf, PATH_MAX);
65 if (len < 0)
66 die ("Invalid symlink: %s", buf);
67 if (PATH_MAX <= len)
68 die("symbolic link too long: %s", buf);
69 next_buf[len] = '\0';
70 buf = next_buf;
71 buf_index = 1 - buf_index;
72 next_buf = bufs[buf_index];
73 } else
74 break;
75 }
76
77 if (*cwd && chdir(cwd))
78 die ("Could not change back to '%s'", cwd);
79
80 return buf;
81}
82
83static const char *get_pwd_cwd(void)
84{
85 static char cwd[PATH_MAX + 1];
86 char *pwd;
87 struct stat cwd_stat, pwd_stat;
88 if (getcwd(cwd, PATH_MAX) == NULL)
89 return NULL;
90 pwd = getenv("PWD");
91 if (pwd && strcmp(pwd, cwd)) {
92 stat(cwd, &cwd_stat);
93 if (!stat(pwd, &pwd_stat) &&
94 pwd_stat.st_dev == cwd_stat.st_dev &&
95 pwd_stat.st_ino == cwd_stat.st_ino) {
96 strlcpy(cwd, pwd, PATH_MAX);
97 }
98 }
99 return cwd;
100}
101
102const char *make_nonrelative_path(const char *path)
103{
104 static char buf[PATH_MAX + 1];
105
106 if (is_absolute_path(path)) {
107 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
108 die("Too long path: %.*s", 60, path);
109 } else {
110 const char *cwd = get_pwd_cwd();
111 if (!cwd)
112 die("Cannot determine the current working directory");
113 if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
114 die("Too long path: %.*s", 60, path);
115 }
116 return buf;
117}
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
new file mode 100644
index 000000000000..b8144e80bb1e
--- /dev/null
+++ b/tools/perf/util/alias.c
@@ -0,0 +1,77 @@
1#include "cache.h"
2
3static const char *alias_key;
4static char *alias_val;
5
6static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
7{
8 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
9 if (!v)
10 return config_error_nonbool(k);
11 alias_val = strdup(v);
12 return 0;
13 }
14 return 0;
15}
16
17char *alias_lookup(const char *alias)
18{
19 alias_key = alias;
20 alias_val = NULL;
21 perf_config(alias_lookup_cb, NULL);
22 return alias_val;
23}
24
25int split_cmdline(char *cmdline, const char ***argv)
26{
27 int src, dst, count = 0, size = 16;
28 char quoted = 0;
29
30 *argv = malloc(sizeof(char*) * size);
31
32 /* split alias_string */
33 (*argv)[count++] = cmdline;
34 for (src = dst = 0; cmdline[src];) {
35 char c = cmdline[src];
36 if (!quoted && isspace(c)) {
37 cmdline[dst++] = 0;
38 while (cmdline[++src]
39 && isspace(cmdline[src]))
40 ; /* skip */
41 if (count >= size) {
42 size += 16;
43 *argv = realloc(*argv, sizeof(char*) * size);
44 }
45 (*argv)[count++] = cmdline + dst;
46 } else if (!quoted && (c == '\'' || c == '"')) {
47 quoted = c;
48 src++;
49 } else if (c == quoted) {
50 quoted = 0;
51 src++;
52 } else {
53 if (c == '\\' && quoted != '\'') {
54 src++;
55 c = cmdline[src];
56 if (!c) {
57 free(*argv);
58 *argv = NULL;
59 return error("cmdline ends with \\");
60 }
61 }
62 cmdline[dst++] = c;
63 src++;
64 }
65 }
66
67 cmdline[dst] = 0;
68
69 if (quoted) {
70 free(*argv);
71 *argv = NULL;
72 return error("unclosed quote");
73 }
74
75 return count;
76}
77
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
new file mode 100644
index 000000000000..4b50c412b9c5
--- /dev/null
+++ b/tools/perf/util/cache.h
@@ -0,0 +1,121 @@
1#ifndef CACHE_H
2#define CACHE_H
3
4#include "util.h"
5#include "strbuf.h"
6#include "../perf.h"
7
8#define PERF_DIR_ENVIRONMENT "PERF_DIR"
9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
10#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
11#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY"
12#define INDEX_ENVIRONMENT "PERF_INDEX_FILE"
13#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE"
14#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR"
15#define CONFIG_ENVIRONMENT "PERF_CONFIG"
16#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
17#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES"
18#define PERFATTRIBUTES_FILE ".perfattributes"
19#define INFOATTRIBUTES_FILE "info/attributes"
20#define ATTRIBUTE_MACRO_PREFIX "[attr]"
21#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
22
23typedef int (*config_fn_t)(const char *, const char *, void *);
24extern int perf_default_config(const char *, const char *, void *);
25extern int perf_config_from_file(config_fn_t fn, const char *, void *);
26extern int perf_config(config_fn_t fn, void *);
27extern int perf_parse_ulong(const char *, unsigned long *);
28extern int perf_config_int(const char *, const char *);
29extern unsigned long perf_config_ulong(const char *, const char *);
30extern int perf_config_bool_or_int(const char *, const char *, int *);
31extern int perf_config_bool(const char *, const char *);
32extern int perf_config_string(const char **, const char *, const char *);
33extern int perf_config_set(const char *, const char *);
34extern int perf_config_set_multivar(const char *, const char *, const char *, int);
35extern int perf_config_rename_section(const char *, const char *);
36extern const char *perf_etc_perfconfig(void);
37extern int check_repository_format_version(const char *var, const char *value, void *cb);
38extern int perf_config_system(void);
39extern int perf_config_global(void);
40extern int config_error_nonbool(const char *);
41extern const char *config_exclusive_filename;
42
43#define MAX_PERFNAME (1000)
44extern char perf_default_email[MAX_PERFNAME];
45extern char perf_default_name[MAX_PERFNAME];
46extern int user_ident_explicitly_given;
47
48extern const char *perf_log_output_encoding;
49extern const char *perf_mailmap_file;
50
51/* IO helper functions */
52extern void maybe_flush_or_die(FILE *, const char *);
53extern int copy_fd(int ifd, int ofd);
54extern int copy_file(const char *dst, const char *src, int mode);
55extern ssize_t read_in_full(int fd, void *buf, size_t count);
56extern ssize_t write_in_full(int fd, const void *buf, size_t count);
57extern void write_or_die(int fd, const void *buf, size_t count);
58extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
59extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
60extern void fsync_or_die(int fd, const char *);
61
62/* pager.c */
63extern void setup_pager(void);
64extern const char *pager_program;
65extern int pager_in_use(void);
66extern int pager_use_color;
67
68extern const char *editor_program;
69extern const char *excludes_file;
70
71char *alias_lookup(const char *alias);
72int split_cmdline(char *cmdline, const char ***argv);
73
74#define alloc_nr(x) (((x)+16)*3/2)
75
76/*
77 * Realloc the buffer pointed at by variable 'x' so that it can hold
78 * at least 'nr' entries; the number of entries currently allocated
79 * is 'alloc', using the standard growing factor alloc_nr() macro.
80 *
81 * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
82 */
83#define ALLOC_GROW(x, nr, alloc) \
84 do { \
85 if ((nr) > alloc) { \
86 if (alloc_nr(alloc) < (nr)) \
87 alloc = (nr); \
88 else \
89 alloc = alloc_nr(alloc); \
90 x = xrealloc((x), alloc * sizeof(*(x))); \
91 } \
92 } while(0)
93
94
95static inline int is_absolute_path(const char *path)
96{
97 return path[0] == '/';
98}
99
100const char *make_absolute_path(const char *path);
101const char *make_nonrelative_path(const char *path);
102const char *make_relative_path(const char *abs, const char *base);
103int normalize_path_copy(char *dst, const char *src);
104int longest_ancestor_length(const char *path, const char *prefix_list);
105char *strip_path_suffix(const char *path, const char *suffix);
106
107extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
108extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
109/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
110extern int perf_mkstemp(char *path, size_t len, const char *template);
111
112extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
113 __attribute__((format (printf, 3, 4)));
114extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
115 __attribute__((format (printf, 3, 4)));
116extern char *perf_pathdup(const char *fmt, ...)
117 __attribute__((format (printf, 1, 2)));
118
119extern size_t strlcpy(char *dest, const char *src, size_t size);
120
121#endif /* CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
new file mode 100644
index 000000000000..011473411642
--- /dev/null
+++ b/tools/perf/util/callchain.c
@@ -0,0 +1,343 @@
1/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree.
6 *
7 * Using a radix for code path provides a fast retrieval and factorizes
8 * memory use. Also that lets us use the paths in a hierarchical graph view.
9 *
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <errno.h>
16#include <math.h>
17
18#include "callchain.h"
19
20#define chain_for_each_child(child, parent) \
21 list_for_each_entry(child, &parent->children, brothers)
22
23static void
24rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
25 enum chain_mode mode)
26{
27 struct rb_node **p = &root->rb_node;
28 struct rb_node *parent = NULL;
29 struct callchain_node *rnode;
30 u64 chain_cumul = cumul_hits(chain);
31
32 while (*p) {
33 u64 rnode_cumul;
34
35 parent = *p;
36 rnode = rb_entry(parent, struct callchain_node, rb_node);
37 rnode_cumul = cumul_hits(rnode);
38
39 switch (mode) {
40 case CHAIN_FLAT:
41 if (rnode->hit < chain->hit)
42 p = &(*p)->rb_left;
43 else
44 p = &(*p)->rb_right;
45 break;
46 case CHAIN_GRAPH_ABS: /* Falldown */
47 case CHAIN_GRAPH_REL:
48 if (rnode_cumul < chain_cumul)
49 p = &(*p)->rb_left;
50 else
51 p = &(*p)->rb_right;
52 break;
53 default:
54 break;
55 }
56 }
57
58 rb_link_node(&chain->rb_node, parent, p);
59 rb_insert_color(&chain->rb_node, root);
60}
61
62static void
63__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
64 u64 min_hit)
65{
66 struct callchain_node *child;
67
68 chain_for_each_child(child, node)
69 __sort_chain_flat(rb_root, child, min_hit);
70
71 if (node->hit && node->hit >= min_hit)
72 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
73}
74
75/*
76 * Once we get every callchains from the stream, we can now
77 * sort them by hit
78 */
79static void
80sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
81 u64 min_hit, struct callchain_param *param __used)
82{
83 __sort_chain_flat(rb_root, node, min_hit);
84}
85
86static void __sort_chain_graph_abs(struct callchain_node *node,
87 u64 min_hit)
88{
89 struct callchain_node *child;
90
91 node->rb_root = RB_ROOT;
92
93 chain_for_each_child(child, node) {
94 __sort_chain_graph_abs(child, min_hit);
95 if (cumul_hits(child) >= min_hit)
96 rb_insert_callchain(&node->rb_root, child,
97 CHAIN_GRAPH_ABS);
98 }
99}
100
101static void
102sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
103 u64 min_hit, struct callchain_param *param __used)
104{
105 __sort_chain_graph_abs(chain_root, min_hit);
106 rb_root->rb_node = chain_root->rb_root.rb_node;
107}
108
109static void __sort_chain_graph_rel(struct callchain_node *node,
110 double min_percent)
111{
112 struct callchain_node *child;
113 u64 min_hit;
114
115 node->rb_root = RB_ROOT;
116 min_hit = ceil(node->children_hit * min_percent);
117
118 chain_for_each_child(child, node) {
119 __sort_chain_graph_rel(child, min_percent);
120 if (cumul_hits(child) >= min_hit)
121 rb_insert_callchain(&node->rb_root, child,
122 CHAIN_GRAPH_REL);
123 }
124}
125
126static void
127sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
128 u64 min_hit __used, struct callchain_param *param)
129{
130 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
131 rb_root->rb_node = chain_root->rb_root.rb_node;
132}
133
134int register_callchain_param(struct callchain_param *param)
135{
136 switch (param->mode) {
137 case CHAIN_GRAPH_ABS:
138 param->sort = sort_chain_graph_abs;
139 break;
140 case CHAIN_GRAPH_REL:
141 param->sort = sort_chain_graph_rel;
142 break;
143 case CHAIN_FLAT:
144 param->sort = sort_chain_flat;
145 break;
146 default:
147 return -1;
148 }
149 return 0;
150}
151
152/*
153 * Create a child for a parent. If inherit_children, then the new child
154 * will become the new parent of it's parent children
155 */
156static struct callchain_node *
157create_child(struct callchain_node *parent, bool inherit_children)
158{
159 struct callchain_node *new;
160
161 new = malloc(sizeof(*new));
162 if (!new) {
163 perror("not enough memory to create child for code path tree");
164 return NULL;
165 }
166 new->parent = parent;
167 INIT_LIST_HEAD(&new->children);
168 INIT_LIST_HEAD(&new->val);
169
170 if (inherit_children) {
171 struct callchain_node *next;
172
173 list_splice(&parent->children, &new->children);
174 INIT_LIST_HEAD(&parent->children);
175
176 chain_for_each_child(next, new)
177 next->parent = new;
178 }
179 list_add_tail(&new->brothers, &parent->children);
180
181 return new;
182}
183
184/*
185 * Fill the node with callchain values
186 */
187static void
188fill_node(struct callchain_node *node, struct ip_callchain *chain,
189 int start, struct symbol **syms)
190{
191 unsigned int i;
192
193 for (i = start; i < chain->nr; i++) {
194 struct callchain_list *call;
195
196 call = malloc(sizeof(*call));
197 if (!call) {
198 perror("not enough memory for the code path tree");
199 return;
200 }
201 call->ip = chain->ips[i];
202 call->sym = syms[i];
203 list_add_tail(&call->list, &node->val);
204 }
205 node->val_nr = chain->nr - start;
206 if (!node->val_nr)
207 printf("Warning: empty node in callchain tree\n");
208}
209
210static void
211add_child(struct callchain_node *parent, struct ip_callchain *chain,
212 int start, struct symbol **syms)
213{
214 struct callchain_node *new;
215
216 new = create_child(parent, false);
217 fill_node(new, chain, start, syms);
218
219 new->children_hit = 0;
220 new->hit = 1;
221}
222
223/*
224 * Split the parent in two parts (a new child is created) and
225 * give a part of its callchain to the created child.
226 * Then create another child to host the given callchain of new branch
227 */
228static void
229split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
230 struct callchain_list *to_split, int idx_parents, int idx_local,
231 struct symbol **syms)
232{
233 struct callchain_node *new;
234 struct list_head *old_tail;
235 unsigned int idx_total = idx_parents + idx_local;
236
237 /* split */
238 new = create_child(parent, true);
239
240 /* split the callchain and move a part to the new child */
241 old_tail = parent->val.prev;
242 list_del_range(&to_split->list, old_tail);
243 new->val.next = &to_split->list;
244 new->val.prev = old_tail;
245 to_split->list.prev = &new->val;
246 old_tail->next = &new->val;
247
248 /* split the hits */
249 new->hit = parent->hit;
250 new->children_hit = parent->children_hit;
251 parent->children_hit = cumul_hits(new);
252 new->val_nr = parent->val_nr - idx_local;
253 parent->val_nr = idx_local;
254
255 /* create a new child for the new branch if any */
256 if (idx_total < chain->nr) {
257 parent->hit = 0;
258 add_child(parent, chain, idx_total, syms);
259 parent->children_hit++;
260 } else {
261 parent->hit = 1;
262 }
263}
264
265static int
266__append_chain(struct callchain_node *root, struct ip_callchain *chain,
267 unsigned int start, struct symbol **syms);
268
269static void
270__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
271 struct symbol **syms, unsigned int start)
272{
273 struct callchain_node *rnode;
274
275 /* lookup in childrens */
276 chain_for_each_child(rnode, root) {
277 unsigned int ret = __append_chain(rnode, chain, start, syms);
278
279 if (!ret)
280 goto inc_children_hit;
281 }
282 /* nothing in children, add to the current node */
283 add_child(root, chain, start, syms);
284
285inc_children_hit:
286 root->children_hit++;
287}
288
289static int
290__append_chain(struct callchain_node *root, struct ip_callchain *chain,
291 unsigned int start, struct symbol **syms)
292{
293 struct callchain_list *cnode;
294 unsigned int i = start;
295 bool found = false;
296
297 /*
298 * Lookup in the current node
299 * If we have a symbol, then compare the start to match
300 * anywhere inside a function.
301 */
302 list_for_each_entry(cnode, &root->val, list) {
303 if (i == chain->nr)
304 break;
305 if (cnode->sym && syms[i]) {
306 if (cnode->sym->start != syms[i]->start)
307 break;
308 } else if (cnode->ip != chain->ips[i])
309 break;
310 if (!found)
311 found = true;
312 i++;
313 }
314
315 /* matches not, relay on the parent */
316 if (!found)
317 return -1;
318
319 /* we match only a part of the node. Split it and add the new chain */
320 if (i - start < root->val_nr) {
321 split_add_child(root, chain, cnode, start, i - start, syms);
322 return 0;
323 }
324
325 /* we match 100% of the path, increment the hit */
326 if (i - start == root->val_nr && i == chain->nr) {
327 root->hit++;
328 return 0;
329 }
330
331 /* We match the node and still have a part remaining */
332 __append_chain_children(root, chain, syms, i);
333
334 return 0;
335}
336
337void append_chain(struct callchain_node *root, struct ip_callchain *chain,
338 struct symbol **syms)
339{
340 if (!chain->nr)
341 return;
342 __append_chain_children(root, chain, syms, 0);
343}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
new file mode 100644
index 000000000000..a926ae4f5a16
--- /dev/null
+++ b/tools/perf/util/callchain.h
@@ -0,0 +1,60 @@
1#ifndef __PERF_CALLCHAIN_H
2#define __PERF_CALLCHAIN_H
3
4#include "../perf.h"
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include "symbol.h"
8
9enum chain_mode {
10 CHAIN_NONE,
11 CHAIN_FLAT,
12 CHAIN_GRAPH_ABS,
13 CHAIN_GRAPH_REL
14};
15
16struct callchain_node {
17 struct callchain_node *parent;
18 struct list_head brothers;
19 struct list_head children;
20 struct list_head val;
21 struct rb_node rb_node; /* to sort nodes in an rbtree */
22 struct rb_root rb_root; /* sorted tree of children */
23 unsigned int val_nr;
24 u64 hit;
25 u64 children_hit;
26};
27
28struct callchain_param;
29
30typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
31 u64, struct callchain_param *);
32
33struct callchain_param {
34 enum chain_mode mode;
35 double min_percent;
36 sort_chain_func_t sort;
37};
38
39struct callchain_list {
40 u64 ip;
41 struct symbol *sym;
42 struct list_head list;
43};
44
45static inline void callchain_init(struct callchain_node *node)
46{
47 INIT_LIST_HEAD(&node->brothers);
48 INIT_LIST_HEAD(&node->children);
49 INIT_LIST_HEAD(&node->val);
50}
51
52static inline u64 cumul_hits(struct callchain_node *node)
53{
54 return node->hit + node->children_hit;
55}
56
57int register_callchain_param(struct callchain_param *param);
58void append_chain(struct callchain_node *root, struct ip_callchain *chain,
59 struct symbol **syms);
60#endif
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
new file mode 100644
index 000000000000..90a044d1fe7d
--- /dev/null
+++ b/tools/perf/util/color.c
@@ -0,0 +1,272 @@
1#include "cache.h"
2#include "color.h"
3
4int perf_use_color_default = -1;
5
6static int parse_color(const char *name, int len)
7{
8 static const char * const color_names[] = {
9 "normal", "black", "red", "green", "yellow",
10 "blue", "magenta", "cyan", "white"
11 };
12 char *end;
13 int i;
14
15 for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
16 const char *str = color_names[i];
17 if (!strncasecmp(name, str, len) && !str[len])
18 return i - 1;
19 }
20 i = strtol(name, &end, 10);
21 if (end - name == len && i >= -1 && i <= 255)
22 return i;
23 return -2;
24}
25
26static int parse_attr(const char *name, int len)
27{
28 static const int attr_values[] = { 1, 2, 4, 5, 7 };
29 static const char * const attr_names[] = {
30 "bold", "dim", "ul", "blink", "reverse"
31 };
32 unsigned int i;
33
34 for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
35 const char *str = attr_names[i];
36 if (!strncasecmp(name, str, len) && !str[len])
37 return attr_values[i];
38 }
39 return -1;
40}
41
42void color_parse(const char *value, const char *var, char *dst)
43{
44 color_parse_mem(value, strlen(value), var, dst);
45}
46
47void color_parse_mem(const char *value, int value_len, const char *var,
48 char *dst)
49{
50 const char *ptr = value;
51 int len = value_len;
52 int attr = -1;
53 int fg = -2;
54 int bg = -2;
55
56 if (!strncasecmp(value, "reset", len)) {
57 strcpy(dst, PERF_COLOR_RESET);
58 return;
59 }
60
61 /* [fg [bg]] [attr] */
62 while (len > 0) {
63 const char *word = ptr;
64 int val, wordlen = 0;
65
66 while (len > 0 && !isspace(word[wordlen])) {
67 wordlen++;
68 len--;
69 }
70
71 ptr = word + wordlen;
72 while (len > 0 && isspace(*ptr)) {
73 ptr++;
74 len--;
75 }
76
77 val = parse_color(word, wordlen);
78 if (val >= -1) {
79 if (fg == -2) {
80 fg = val;
81 continue;
82 }
83 if (bg == -2) {
84 bg = val;
85 continue;
86 }
87 goto bad;
88 }
89 val = parse_attr(word, wordlen);
90 if (val < 0 || attr != -1)
91 goto bad;
92 attr = val;
93 }
94
95 if (attr >= 0 || fg >= 0 || bg >= 0) {
96 int sep = 0;
97
98 *dst++ = '\033';
99 *dst++ = '[';
100 if (attr >= 0) {
101 *dst++ = '0' + attr;
102 sep++;
103 }
104 if (fg >= 0) {
105 if (sep++)
106 *dst++ = ';';
107 if (fg < 8) {
108 *dst++ = '3';
109 *dst++ = '0' + fg;
110 } else {
111 dst += sprintf(dst, "38;5;%d", fg);
112 }
113 }
114 if (bg >= 0) {
115 if (sep++)
116 *dst++ = ';';
117 if (bg < 8) {
118 *dst++ = '4';
119 *dst++ = '0' + bg;
120 } else {
121 dst += sprintf(dst, "48;5;%d", bg);
122 }
123 }
124 *dst++ = 'm';
125 }
126 *dst = 0;
127 return;
128bad:
129 die("bad color value '%.*s' for variable '%s'", value_len, value, var);
130}
131
132int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
133{
134 if (value) {
135 if (!strcasecmp(value, "never"))
136 return 0;
137 if (!strcasecmp(value, "always"))
138 return 1;
139 if (!strcasecmp(value, "auto"))
140 goto auto_color;
141 }
142
143 /* Missing or explicit false to turn off colorization */
144 if (!perf_config_bool(var, value))
145 return 0;
146
147 /* any normal truth value defaults to 'auto' */
148 auto_color:
149 if (stdout_is_tty < 0)
150 stdout_is_tty = isatty(1);
151 if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
152 char *term = getenv("TERM");
153 if (term && strcmp(term, "dumb"))
154 return 1;
155 }
156 return 0;
157}
158
159int perf_color_default_config(const char *var, const char *value, void *cb)
160{
161 if (!strcmp(var, "color.ui")) {
162 perf_use_color_default = perf_config_colorbool(var, value, -1);
163 return 0;
164 }
165
166 return perf_default_config(var, value, cb);
167}
168
169static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
170 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 += fprintf(fp, "%s", color);
186 r += vfprintf(fp, fmt, args);
187 if (perf_use_color_default && *color)
188 r += fprintf(fp, "%s", PERF_COLOR_RESET);
189 if (trail)
190 r += fprintf(fp, "%s", trail);
191 return r;
192}
193
194
195
196int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
197{
198 va_list args;
199 int r;
200
201 va_start(args, fmt);
202 r = color_vfprintf(fp, color, fmt, args, NULL);
203 va_end(args);
204 return r;
205}
206
207int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
208{
209 va_list args;
210 int r;
211 va_start(args, fmt);
212 r = color_vfprintf(fp, color, fmt, args, "\n");
213 va_end(args);
214 return r;
215}
216
217/*
218 * This function splits the buffer by newlines and colors the lines individually.
219 *
220 * Returns 0 on success.
221 */
222int color_fwrite_lines(FILE *fp, const char *color,
223 size_t count, const char *buf)
224{
225 if (!*color)
226 return fwrite(buf, count, 1, fp) != 1;
227
228 while (count) {
229 char *p = memchr(buf, '\n', count);
230
231 if (p != buf && (fputs(color, fp) < 0 ||
232 fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
233 fputs(PERF_COLOR_RESET, fp) < 0))
234 return -1;
235 if (!p)
236 return 0;
237 if (fputc('\n', fp) < 0)
238 return -1;
239 count -= p + 1 - buf;
240 buf = p + 1;
241 }
242 return 0;
243}
244
245char *get_percent_color(double percent)
246{
247 char *color = PERF_COLOR_NORMAL;
248
249 /*
250 * We color high-overhead entries in red, mid-overhead
251 * entries in green - and keep the low overhead places
252 * normal:
253 */
254 if (percent >= MIN_RED)
255 color = PERF_COLOR_RED;
256 else {
257 if (percent > MIN_GREEN)
258 color = PERF_COLOR_GREEN;
259 }
260 return color;
261}
262
263int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
264{
265 int r;
266 char *color;
267
268 color = get_percent_color(percent);
269 r = color_fprintf(fp, color, fmt, percent);
270
271 return r;
272}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
new file mode 100644
index 000000000000..706cec50bd25
--- /dev/null
+++ b/tools/perf/util/color.h
@@ -0,0 +1,41 @@
1#ifndef COLOR_H
2#define COLOR_H
3
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24
6
7#define PERF_COLOR_NORMAL ""
8#define PERF_COLOR_RESET "\033[m"
9#define PERF_COLOR_BOLD "\033[1m"
10#define PERF_COLOR_RED "\033[31m"
11#define PERF_COLOR_GREEN "\033[32m"
12#define PERF_COLOR_YELLOW "\033[33m"
13#define PERF_COLOR_BLUE "\033[34m"
14#define PERF_COLOR_MAGENTA "\033[35m"
15#define PERF_COLOR_CYAN "\033[36m"
16#define PERF_COLOR_BG_RED "\033[41m"
17
18#define MIN_GREEN 0.5
19#define MIN_RED 5.0
20
21/*
22 * This variable stores the value of color.ui
23 */
24extern int perf_use_color_default;
25
26
27/*
28 * Use this instead of perf_default_config if you need the value of color.ui.
29 */
30int perf_color_default_config(const char *var, const char *value, void *cb);
31
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);
34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
36int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
37int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
38int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
39char *get_percent_color(double percent);
40
41#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
new file mode 100644
index 000000000000..780df541006d
--- /dev/null
+++ b/tools/perf/util/config.c
@@ -0,0 +1,875 @@
1/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 * Copyright (C) Johannes Schindelin, 2005
6 *
7 */
8#include "util.h"
9#include "cache.h"
10#include "exec_cmd.h"
11
12#define MAXNAME (256)
13
14static FILE *config_file;
15static const char *config_file_name;
16static int config_linenr;
17static int config_file_eof;
18
19const char *config_exclusive_filename = NULL;
20
21static int get_next_char(void)
22{
23 int c;
24 FILE *f;
25
26 c = '\n';
27 if ((f = config_file) != NULL) {
28 c = fgetc(f);
29 if (c == '\r') {
30 /* DOS like systems */
31 c = fgetc(f);
32 if (c != '\n') {
33 ungetc(c, f);
34 c = '\r';
35 }
36 }
37 if (c == '\n')
38 config_linenr++;
39 if (c == EOF) {
40 config_file_eof = 1;
41 c = '\n';
42 }
43 }
44 return c;
45}
46
47static char *parse_value(void)
48{
49 static char value[1024];
50 int quote = 0, comment = 0, space = 0;
51 size_t len = 0;
52
53 for (;;) {
54 int c = get_next_char();
55
56 if (len >= sizeof(value) - 1)
57 return NULL;
58 if (c == '\n') {
59 if (quote)
60 return NULL;
61 value[len] = 0;
62 return value;
63 }
64 if (comment)
65 continue;
66 if (isspace(c) && !quote) {
67 space = 1;
68 continue;
69 }
70 if (!quote) {
71 if (c == ';' || c == '#') {
72 comment = 1;
73 continue;
74 }
75 }
76 if (space) {
77 if (len)
78 value[len++] = ' ';
79 space = 0;
80 }
81 if (c == '\\') {
82 c = get_next_char();
83 switch (c) {
84 case '\n':
85 continue;
86 case 't':
87 c = '\t';
88 break;
89 case 'b':
90 c = '\b';
91 break;
92 case 'n':
93 c = '\n';
94 break;
95 /* Some characters escape as themselves */
96 case '\\': case '"':
97 break;
98 /* Reject unknown escape sequences */
99 default:
100 return NULL;
101 }
102 value[len++] = c;
103 continue;
104 }
105 if (c == '"') {
106 quote = 1-quote;
107 continue;
108 }
109 value[len++] = c;
110 }
111}
112
113static inline int iskeychar(int c)
114{
115 return isalnum(c) || c == '-';
116}
117
118static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
119{
120 int c;
121 char *value;
122
123 /* Get the full name */
124 for (;;) {
125 c = get_next_char();
126 if (config_file_eof)
127 break;
128 if (!iskeychar(c))
129 break;
130 name[len++] = tolower(c);
131 if (len >= MAXNAME)
132 return -1;
133 }
134 name[len] = 0;
135 while (c == ' ' || c == '\t')
136 c = get_next_char();
137
138 value = NULL;
139 if (c != '\n') {
140 if (c != '=')
141 return -1;
142 value = parse_value();
143 if (!value)
144 return -1;
145 }
146 return fn(name, value, data);
147}
148
149static int get_extended_base_var(char *name, int baselen, int c)
150{
151 do {
152 if (c == '\n')
153 return -1;
154 c = get_next_char();
155 } while (isspace(c));
156
157 /* We require the format to be '[base "extension"]' */
158 if (c != '"')
159 return -1;
160 name[baselen++] = '.';
161
162 for (;;) {
163 int c = get_next_char();
164 if (c == '\n')
165 return -1;
166 if (c == '"')
167 break;
168 if (c == '\\') {
169 c = get_next_char();
170 if (c == '\n')
171 return -1;
172 }
173 name[baselen++] = c;
174 if (baselen > MAXNAME / 2)
175 return -1;
176 }
177
178 /* Final ']' */
179 if (get_next_char() != ']')
180 return -1;
181 return baselen;
182}
183
184static int get_base_var(char *name)
185{
186 int baselen = 0;
187
188 for (;;) {
189 int c = get_next_char();
190 if (config_file_eof)
191 return -1;
192 if (c == ']')
193 return baselen;
194 if (isspace(c))
195 return get_extended_base_var(name, baselen, c);
196 if (!iskeychar(c) && c != '.')
197 return -1;
198 if (baselen > MAXNAME / 2)
199 return -1;
200 name[baselen++] = tolower(c);
201 }
202}
203
204static int perf_parse_file(config_fn_t fn, void *data)
205{
206 int comment = 0;
207 int baselen = 0;
208 static char var[MAXNAME];
209
210 /* U+FEFF Byte Order Mark in UTF8 */
211 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
212 const unsigned char *bomptr = utf8_bom;
213
214 for (;;) {
215 int c = get_next_char();
216 if (bomptr && *bomptr) {
217 /* We are at the file beginning; skip UTF8-encoded BOM
218 * if present. Sane editors won't put this in on their
219 * own, but e.g. Windows Notepad will do it happily. */
220 if ((unsigned char) c == *bomptr) {
221 bomptr++;
222 continue;
223 } else {
224 /* Do not tolerate partial BOM. */
225 if (bomptr != utf8_bom)
226 break;
227 /* No BOM at file beginning. Cool. */
228 bomptr = NULL;
229 }
230 }
231 if (c == '\n') {
232 if (config_file_eof)
233 return 0;
234 comment = 0;
235 continue;
236 }
237 if (comment || isspace(c))
238 continue;
239 if (c == '#' || c == ';') {
240 comment = 1;
241 continue;
242 }
243 if (c == '[') {
244 baselen = get_base_var(var);
245 if (baselen <= 0)
246 break;
247 var[baselen++] = '.';
248 var[baselen] = 0;
249 continue;
250 }
251 if (!isalpha(c))
252 break;
253 var[baselen] = tolower(c);
254 if (get_value(fn, data, var, baselen+1) < 0)
255 break;
256 }
257 die("bad config file line %d in %s", config_linenr, config_file_name);
258}
259
260static int parse_unit_factor(const char *end, unsigned long *val)
261{
262 if (!*end)
263 return 1;
264 else if (!strcasecmp(end, "k")) {
265 *val *= 1024;
266 return 1;
267 }
268 else if (!strcasecmp(end, "m")) {
269 *val *= 1024 * 1024;
270 return 1;
271 }
272 else if (!strcasecmp(end, "g")) {
273 *val *= 1024 * 1024 * 1024;
274 return 1;
275 }
276 return 0;
277}
278
279static int perf_parse_long(const char *value, long *ret)
280{
281 if (value && *value) {
282 char *end;
283 long val = strtol(value, &end, 0);
284 unsigned long factor = 1;
285 if (!parse_unit_factor(end, &factor))
286 return 0;
287 *ret = val * factor;
288 return 1;
289 }
290 return 0;
291}
292
293int perf_parse_ulong(const char *value, unsigned long *ret)
294{
295 if (value && *value) {
296 char *end;
297 unsigned long val = strtoul(value, &end, 0);
298 if (!parse_unit_factor(end, &val))
299 return 0;
300 *ret = val;
301 return 1;
302 }
303 return 0;
304}
305
306static void die_bad_config(const char *name)
307{
308 if (config_file_name)
309 die("bad config value for '%s' in %s", name, config_file_name);
310 die("bad config value for '%s'", name);
311}
312
313int perf_config_int(const char *name, const char *value)
314{
315 long ret = 0;
316 if (!perf_parse_long(value, &ret))
317 die_bad_config(name);
318 return ret;
319}
320
321unsigned long perf_config_ulong(const char *name, const char *value)
322{
323 unsigned long ret;
324 if (!perf_parse_ulong(value, &ret))
325 die_bad_config(name);
326 return ret;
327}
328
329int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
330{
331 *is_bool = 1;
332 if (!value)
333 return 1;
334 if (!*value)
335 return 0;
336 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
337 return 1;
338 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
339 return 0;
340 *is_bool = 0;
341 return perf_config_int(name, value);
342}
343
344int perf_config_bool(const char *name, const char *value)
345{
346 int discard;
347 return !!perf_config_bool_or_int(name, value, &discard);
348}
349
350int perf_config_string(const char **dest, const char *var, const char *value)
351{
352 if (!value)
353 return config_error_nonbool(var);
354 *dest = strdup(value);
355 return 0;
356}
357
358static int perf_default_core_config(const char *var __used, const char *value __used)
359{
360 /* Add other config variables here and to Documentation/config.txt. */
361 return 0;
362}
363
364int perf_default_config(const char *var, const char *value, void *dummy __used)
365{
366 if (!prefixcmp(var, "core."))
367 return perf_default_core_config(var, value);
368
369 /* Add other config variables here and to Documentation/config.txt. */
370 return 0;
371}
372
373int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
374{
375 int ret;
376 FILE *f = fopen(filename, "r");
377
378 ret = -1;
379 if (f) {
380 config_file = f;
381 config_file_name = filename;
382 config_linenr = 1;
383 config_file_eof = 0;
384 ret = perf_parse_file(fn, data);
385 fclose(f);
386 config_file_name = NULL;
387 }
388 return ret;
389}
390
391const char *perf_etc_perfconfig(void)
392{
393 static const char *system_wide;
394 if (!system_wide)
395 system_wide = system_path(ETC_PERFCONFIG);
396 return system_wide;
397}
398
399static int perf_env_bool(const char *k, int def)
400{
401 const char *v = getenv(k);
402 return v ? perf_config_bool(k, v) : def;
403}
404
405int perf_config_system(void)
406{
407 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
408}
409
410int perf_config_global(void)
411{
412 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
413}
414
415int perf_config(config_fn_t fn, void *data)
416{
417 int ret = 0, found = 0;
418 char *repo_config = NULL;
419 const char *home = NULL;
420
421 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
422 if (config_exclusive_filename)
423 return perf_config_from_file(fn, config_exclusive_filename, data);
424 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
425 ret += perf_config_from_file(fn, perf_etc_perfconfig(),
426 data);
427 found += 1;
428 }
429
430 home = getenv("HOME");
431 if (perf_config_global() && home) {
432 char *user_config = strdup(mkpath("%s/.perfconfig", home));
433 if (!access(user_config, R_OK)) {
434 ret += perf_config_from_file(fn, user_config, data);
435 found += 1;
436 }
437 free(user_config);
438 }
439
440 repo_config = perf_pathdup("config");
441 if (!access(repo_config, R_OK)) {
442 ret += perf_config_from_file(fn, repo_config, data);
443 found += 1;
444 }
445 free(repo_config);
446 if (found == 0)
447 return -1;
448 return ret;
449}
450
451/*
452 * Find all the stuff for perf_config_set() below.
453 */
454
455#define MAX_MATCHES 512
456
457static struct {
458 int baselen;
459 char* key;
460 int do_not_match;
461 regex_t* value_regex;
462 int multi_replace;
463 size_t offset[MAX_MATCHES];
464 enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
465 int seen;
466} store;
467
468static int matches(const char* key, const char* value)
469{
470 return !strcmp(key, store.key) &&
471 (store.value_regex == NULL ||
472 (store.do_not_match ^
473 !regexec(store.value_regex, value, 0, NULL, 0)));
474}
475
476static int store_aux(const char* key, const char* value, void *cb __used)
477{
478 int section_len;
479 const char *ep;
480
481 switch (store.state) {
482 case KEY_SEEN:
483 if (matches(key, value)) {
484 if (store.seen == 1 && store.multi_replace == 0) {
485 warning("%s has multiple values", key);
486 } else if (store.seen >= MAX_MATCHES) {
487 error("too many matches for %s", key);
488 return 1;
489 }
490
491 store.offset[store.seen] = ftell(config_file);
492 store.seen++;
493 }
494 break;
495 case SECTION_SEEN:
496 /*
497 * What we are looking for is in store.key (both
498 * section and var), and its section part is baselen
499 * long. We found key (again, both section and var).
500 * We would want to know if this key is in the same
501 * section as what we are looking for. We already
502 * know we are in the same section as what should
503 * hold store.key.
504 */
505 ep = strrchr(key, '.');
506 section_len = ep - key;
507
508 if ((section_len != store.baselen) ||
509 memcmp(key, store.key, section_len+1)) {
510 store.state = SECTION_END_SEEN;
511 break;
512 }
513
514 /*
515 * Do not increment matches: this is no match, but we
516 * just made sure we are in the desired section.
517 */
518 store.offset[store.seen] = ftell(config_file);
519 /* fallthru */
520 case SECTION_END_SEEN:
521 case START:
522 if (matches(key, value)) {
523 store.offset[store.seen] = ftell(config_file);
524 store.state = KEY_SEEN;
525 store.seen++;
526 } else {
527 if (strrchr(key, '.') - key == store.baselen &&
528 !strncmp(key, store.key, store.baselen)) {
529 store.state = SECTION_SEEN;
530 store.offset[store.seen] = ftell(config_file);
531 }
532 }
533 }
534 return 0;
535}
536
537static int store_write_section(int fd, const char* key)
538{
539 const char *dot;
540 int i, success;
541 struct strbuf sb = STRBUF_INIT;
542
543 dot = memchr(key, '.', store.baselen);
544 if (dot) {
545 strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
546 for (i = dot - key + 1; i < store.baselen; i++) {
547 if (key[i] == '"' || key[i] == '\\')
548 strbuf_addch(&sb, '\\');
549 strbuf_addch(&sb, key[i]);
550 }
551 strbuf_addstr(&sb, "\"]\n");
552 } else {
553 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
554 }
555
556 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
557 strbuf_release(&sb);
558
559 return success;
560}
561
562static int store_write_pair(int fd, const char* key, const char* value)
563{
564 int i, success;
565 int length = strlen(key + store.baselen + 1);
566 const char *quote = "";
567 struct strbuf sb = STRBUF_INIT;
568
569 /*
570 * Check to see if the value needs to be surrounded with a dq pair.
571 * Note that problematic characters are always backslash-quoted; this
572 * check is about not losing leading or trailing SP and strings that
573 * follow beginning-of-comment characters (i.e. ';' and '#') by the
574 * configuration parser.
575 */
576 if (value[0] == ' ')
577 quote = "\"";
578 for (i = 0; value[i]; i++)
579 if (value[i] == ';' || value[i] == '#')
580 quote = "\"";
581 if (i && value[i - 1] == ' ')
582 quote = "\"";
583
584 strbuf_addf(&sb, "\t%.*s = %s",
585 length, key + store.baselen + 1, quote);
586
587 for (i = 0; value[i]; i++)
588 switch (value[i]) {
589 case '\n':
590 strbuf_addstr(&sb, "\\n");
591 break;
592 case '\t':
593 strbuf_addstr(&sb, "\\t");
594 break;
595 case '"':
596 case '\\':
597 strbuf_addch(&sb, '\\');
598 default:
599 strbuf_addch(&sb, value[i]);
600 break;
601 }
602 strbuf_addf(&sb, "%s\n", quote);
603
604 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
605 strbuf_release(&sb);
606
607 return success;
608}
609
610static ssize_t find_beginning_of_line(const char* contents, size_t size,
611 size_t offset_, int* found_bracket)
612{
613 size_t equal_offset = size, bracket_offset = size;
614 ssize_t offset;
615
616contline:
617 for (offset = offset_-2; offset > 0
618 && contents[offset] != '\n'; offset--)
619 switch (contents[offset]) {
620 case '=': equal_offset = offset; break;
621 case ']': bracket_offset = offset; break;
622 }
623 if (offset > 0 && contents[offset-1] == '\\') {
624 offset_ = offset;
625 goto contline;
626 }
627 if (bracket_offset < equal_offset) {
628 *found_bracket = 1;
629 offset = bracket_offset+1;
630 } else
631 offset++;
632
633 return offset;
634}
635
636int perf_config_set(const char* key, const char* value)
637{
638 return perf_config_set_multivar(key, value, NULL, 0);
639}
640
641/*
642 * If value==NULL, unset in (remove from) config,
643 * if value_regex!=NULL, disregard key/value pairs where value does not match.
644 * if multi_replace==0, nothing, or only one matching key/value is replaced,
645 * else all matching key/values (regardless how many) are removed,
646 * before the new pair is written.
647 *
648 * Returns 0 on success.
649 *
650 * This function does this:
651 *
652 * - it locks the config file by creating ".perf/config.lock"
653 *
654 * - it then parses the config using store_aux() as validator to find
655 * the position on the key/value pair to replace. If it is to be unset,
656 * it must be found exactly once.
657 *
658 * - the config file is mmap()ed and the part before the match (if any) is
659 * written to the lock file, then the changed part and the rest.
660 *
661 * - the config file is removed and the lock file rename()d to it.
662 *
663 */
664int perf_config_set_multivar(const char* key, const char* value,
665 const char* value_regex, int multi_replace)
666{
667 int i, dot;
668 int fd = -1, in_fd;
669 int ret = 0;
670 char* config_filename;
671 const char* last_dot = strrchr(key, '.');
672
673 if (config_exclusive_filename)
674 config_filename = strdup(config_exclusive_filename);
675 else
676 config_filename = perf_pathdup("config");
677
678 /*
679 * Since "key" actually contains the section name and the real
680 * key name separated by a dot, we have to know where the dot is.
681 */
682
683 if (last_dot == NULL) {
684 error("key does not contain a section: %s", key);
685 ret = 2;
686 goto out_free;
687 }
688 store.baselen = last_dot - key;
689
690 store.multi_replace = multi_replace;
691
692 /*
693 * Validate the key and while at it, lower case it for matching.
694 */
695 store.key = malloc(strlen(key) + 1);
696 dot = 0;
697 for (i = 0; key[i]; i++) {
698 unsigned char c = key[i];
699 if (c == '.')
700 dot = 1;
701 /* Leave the extended basename untouched.. */
702 if (!dot || i > store.baselen) {
703 if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
704 error("invalid key: %s", key);
705 free(store.key);
706 ret = 1;
707 goto out_free;
708 }
709 c = tolower(c);
710 } else if (c == '\n') {
711 error("invalid key (newline): %s", key);
712 free(store.key);
713 ret = 1;
714 goto out_free;
715 }
716 store.key[i] = c;
717 }
718 store.key[i] = 0;
719
720 /*
721 * If .perf/config does not exist yet, write a minimal version.
722 */
723 in_fd = open(config_filename, O_RDONLY);
724 if ( in_fd < 0 ) {
725 free(store.key);
726
727 if ( ENOENT != errno ) {
728 error("opening %s: %s", config_filename,
729 strerror(errno));
730 ret = 3; /* same as "invalid config file" */
731 goto out_free;
732 }
733 /* if nothing to unset, error out */
734 if (value == NULL) {
735 ret = 5;
736 goto out_free;
737 }
738
739 store.key = (char*)key;
740 if (!store_write_section(fd, key) ||
741 !store_write_pair(fd, key, value))
742 goto write_err_out;
743 } else {
744 struct stat st;
745 char* contents;
746 ssize_t contents_sz, copy_begin, copy_end;
747 int i, new_line = 0;
748
749 if (value_regex == NULL)
750 store.value_regex = NULL;
751 else {
752 if (value_regex[0] == '!') {
753 store.do_not_match = 1;
754 value_regex++;
755 } else
756 store.do_not_match = 0;
757
758 store.value_regex = (regex_t*)malloc(sizeof(regex_t));
759 if (regcomp(store.value_regex, value_regex,
760 REG_EXTENDED)) {
761 error("invalid pattern: %s", value_regex);
762 free(store.value_regex);
763 ret = 6;
764 goto out_free;
765 }
766 }
767
768 store.offset[0] = 0;
769 store.state = START;
770 store.seen = 0;
771
772 /*
773 * After this, store.offset will contain the *end* offset
774 * of the last match, or remain at 0 if no match was found.
775 * As a side effect, we make sure to transform only a valid
776 * existing config file.
777 */
778 if (perf_config_from_file(store_aux, config_filename, NULL)) {
779 error("invalid config file %s", config_filename);
780 free(store.key);
781 if (store.value_regex != NULL) {
782 regfree(store.value_regex);
783 free(store.value_regex);
784 }
785 ret = 3;
786 goto out_free;
787 }
788
789 free(store.key);
790 if (store.value_regex != NULL) {
791 regfree(store.value_regex);
792 free(store.value_regex);
793 }
794
795 /* if nothing to unset, or too many matches, error out */
796 if ((store.seen == 0 && value == NULL) ||
797 (store.seen > 1 && multi_replace == 0)) {
798 ret = 5;
799 goto out_free;
800 }
801
802 fstat(in_fd, &st);
803 contents_sz = xsize_t(st.st_size);
804 contents = mmap(NULL, contents_sz, PROT_READ,
805 MAP_PRIVATE, in_fd, 0);
806 close(in_fd);
807
808 if (store.seen == 0)
809 store.seen = 1;
810
811 for (i = 0, copy_begin = 0; i < store.seen; i++) {
812 if (store.offset[i] == 0) {
813 store.offset[i] = copy_end = contents_sz;
814 } else if (store.state != KEY_SEEN) {
815 copy_end = store.offset[i];
816 } else
817 copy_end = find_beginning_of_line(
818 contents, contents_sz,
819 store.offset[i]-2, &new_line);
820
821 if (copy_end > 0 && contents[copy_end-1] != '\n')
822 new_line = 1;
823
824 /* write the first part of the config */
825 if (copy_end > copy_begin) {
826 if (write_in_full(fd, contents + copy_begin,
827 copy_end - copy_begin) <
828 copy_end - copy_begin)
829 goto write_err_out;
830 if (new_line &&
831 write_in_full(fd, "\n", 1) != 1)
832 goto write_err_out;
833 }
834 copy_begin = store.offset[i];
835 }
836
837 /* write the pair (value == NULL means unset) */
838 if (value != NULL) {
839 if (store.state == START) {
840 if (!store_write_section(fd, key))
841 goto write_err_out;
842 }
843 if (!store_write_pair(fd, key, value))
844 goto write_err_out;
845 }
846
847 /* write the rest of the config */
848 if (copy_begin < contents_sz)
849 if (write_in_full(fd, contents + copy_begin,
850 contents_sz - copy_begin) <
851 contents_sz - copy_begin)
852 goto write_err_out;
853
854 munmap(contents, contents_sz);
855 }
856
857 ret = 0;
858
859out_free:
860 free(config_filename);
861 return ret;
862
863write_err_out:
864 goto out_free;
865
866}
867
868/*
869 * Call this to report error for your variable that should not
870 * get a boolean value (i.e. "[my] var" means "true").
871 */
872int config_error_nonbool(const char *var)
873{
874 return error("Missing value for '%s'", var);
875}
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
new file mode 100644
index 000000000000..0b791bd346bc
--- /dev/null
+++ b/tools/perf/util/ctype.c
@@ -0,0 +1,31 @@
1/*
2 * Sane locale-independent, ASCII ctype.
3 *
4 * No surprises, and works with signed and unsigned chars.
5 */
6#include "cache.h"
7
8enum {
9 S = GIT_SPACE,
10 A = GIT_ALPHA,
11 D = GIT_DIGIT,
12 G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */
13 R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */
14 P = GIT_PRINT_EXTRA, /* printable - alpha - digit - glob - regex */
15
16 PS = GIT_SPACE | GIT_PRINT_EXTRA,
17};
18
19unsigned char sane_ctype[256] = {
20/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
21
22 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */
23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */
24 PS,P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */
25 D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */
26 P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
27 A, A, A, A, A, A, A, A, A, A, A, G, G, P, R, P, /* 80.. 95 */
28 P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
30 /* Nothing in the 128.. range */
31};
diff --git a/tools/perf/util/environment.c b/tools/perf/util/environment.c
new file mode 100644
index 000000000000..275b0ee345f5
--- /dev/null
+++ b/tools/perf/util/environment.c
@@ -0,0 +1,9 @@
1/*
2 * We put all the perf config variables in this same object
3 * file, so that programs can link against the config parser
4 * without having to link against all the rest of perf.
5 */
6#include "cache.h"
7
8const char *pager_program;
9int pager_use_color = 1;
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
new file mode 100644
index 000000000000..34a352867382
--- /dev/null
+++ b/tools/perf/util/exec_cmd.c
@@ -0,0 +1,168 @@
1#include "cache.h"
2#include "exec_cmd.h"
3#include "quote.h"
4
5#include <string.h>
6
7#define MAX_ARGS 32
8
9extern char **environ;
10static const char *argv_exec_path;
11static const char *argv0_path;
12
13const char *system_path(const char *path)
14{
15#ifdef RUNTIME_PREFIX
16 static const char *prefix;
17#else
18 static const char *prefix = PREFIX;
19#endif
20 struct strbuf d = STRBUF_INIT;
21
22 if (is_absolute_path(path))
23 return path;
24
25#ifdef RUNTIME_PREFIX
26 assert(argv0_path);
27 assert(is_absolute_path(argv0_path));
28
29 if (!prefix &&
30 !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) &&
31 !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
32 !(prefix = strip_path_suffix(argv0_path, "perf"))) {
33 prefix = PREFIX;
34 fprintf(stderr, "RUNTIME_PREFIX requested, "
35 "but prefix computation failed. "
36 "Using static fallback '%s'.\n", prefix);
37 }
38#endif
39
40 strbuf_addf(&d, "%s/%s", prefix, path);
41 path = strbuf_detach(&d, NULL);
42 return path;
43}
44
45const char *perf_extract_argv0_path(const char *argv0)
46{
47 const char *slash;
48
49 if (!argv0 || !*argv0)
50 return NULL;
51 slash = argv0 + strlen(argv0);
52
53 while (argv0 <= slash && !is_dir_sep(*slash))
54 slash--;
55
56 if (slash >= argv0) {
57 argv0_path = xstrndup(argv0, slash - argv0);
58 return slash + 1;
59 }
60
61 return argv0;
62}
63
64void perf_set_argv_exec_path(const char *exec_path)
65{
66 argv_exec_path = exec_path;
67 /*
68 * Propagate this setting to external programs.
69 */
70 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
71}
72
73
74/* Returns the highest-priority, location to look for perf programs. */
75const char *perf_exec_path(void)
76{
77 const char *env;
78
79 if (argv_exec_path)
80 return argv_exec_path;
81
82 env = getenv(EXEC_PATH_ENVIRONMENT);
83 if (env && *env) {
84 return env;
85 }
86
87 return system_path(PERF_EXEC_PATH);
88}
89
90static void add_path(struct strbuf *out, const char *path)
91{
92 if (path && *path) {
93 if (is_absolute_path(path))
94 strbuf_addstr(out, path);
95 else
96 strbuf_addstr(out, make_nonrelative_path(path));
97
98 strbuf_addch(out, PATH_SEP);
99 }
100}
101
102void setup_path(void)
103{
104 const char *old_path = getenv("PATH");
105 struct strbuf new_path = STRBUF_INIT;
106
107 add_path(&new_path, perf_exec_path());
108 add_path(&new_path, argv0_path);
109
110 if (old_path)
111 strbuf_addstr(&new_path, old_path);
112 else
113 strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
114
115 setenv("PATH", new_path.buf, 1);
116
117 strbuf_release(&new_path);
118}
119
120const char **prepare_perf_cmd(const char **argv)
121{
122 int argc;
123 const char **nargv;
124
125 for (argc = 0; argv[argc]; argc++)
126 ; /* just counting */
127 nargv = malloc(sizeof(*nargv) * (argc + 2));
128
129 nargv[0] = "perf";
130 for (argc = 0; argv[argc]; argc++)
131 nargv[argc + 1] = argv[argc];
132 nargv[argc + 1] = NULL;
133 return nargv;
134}
135
136int execv_perf_cmd(const char **argv) {
137 const char **nargv = prepare_perf_cmd(argv);
138
139 /* execvp() can only ever return if it fails */
140 execvp("perf", (char **)nargv);
141
142 free(nargv);
143 return -1;
144}
145
146
147int execl_perf_cmd(const char *cmd,...)
148{
149 int argc;
150 const char *argv[MAX_ARGS + 1];
151 const char *arg;
152 va_list param;
153
154 va_start(param, cmd);
155 argv[0] = cmd;
156 argc = 1;
157 while (argc < MAX_ARGS) {
158 arg = argv[argc++] = va_arg(param, char *);
159 if (!arg)
160 break;
161 }
162 va_end(param);
163 if (MAX_ARGS <= argc)
164 return error("too many args to run %s", cmd);
165
166 argv[argc] = NULL;
167 return execv_perf_cmd(argv);
168}
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
new file mode 100644
index 000000000000..effe25eb1545
--- /dev/null
+++ b/tools/perf/util/exec_cmd.h
@@ -0,0 +1,13 @@
1#ifndef PERF_EXEC_CMD_H
2#define PERF_EXEC_CMD_H
3
4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path);
6extern const char *perf_exec_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 */
10extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path);
12
13#endif /* PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
new file mode 100755
index 000000000000..f06f6fd148f8
--- /dev/null
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -0,0 +1,24 @@
1#!/bin/sh
2
3echo "/* Automatically generated by $0 */
4struct cmdname_help
5{
6 char name[16];
7 char help[80];
8};
9
10static struct cmdname_help common_cmds[] = {"
11
12sed -n -e 's/^perf-\([^ ]*\)[ ].* common.*/\1/p' command-list.txt |
13sort |
14while read cmd
15do
16 sed -n '
17 /^NAME/,/perf-'"$cmd"'/H
18 ${
19 x
20 s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/
21 p
22 }' "Documentation/perf-$cmd.txt"
23done
24echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
new file mode 100644
index 000000000000..b92a457ca32e
--- /dev/null
+++ b/tools/perf/util/header.c
@@ -0,0 +1,245 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5
6#include "util.h"
7#include "header.h"
8
9/*
10 *
11 */
12
13struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
14{
15 struct perf_header_attr *self = malloc(sizeof(*self));
16
17 if (!self)
18 die("nomem");
19
20 self->attr = *attr;
21 self->ids = 0;
22 self->size = 1;
23 self->id = malloc(sizeof(u64));
24
25 if (!self->id)
26 die("nomem");
27
28 return self;
29}
30
31void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
32{
33 int pos = self->ids;
34
35 self->ids++;
36 if (self->ids > self->size) {
37 self->size *= 2;
38 self->id = realloc(self->id, self->size * sizeof(u64));
39 if (!self->id)
40 die("nomem");
41 }
42 self->id[pos] = id;
43}
44
45/*
46 *
47 */
48
49struct perf_header *perf_header__new(void)
50{
51 struct perf_header *self = malloc(sizeof(*self));
52
53 if (!self)
54 die("nomem");
55
56 self->frozen = 0;
57
58 self->attrs = 0;
59 self->size = 1;
60 self->attr = malloc(sizeof(void *));
61
62 if (!self->attr)
63 die("nomem");
64
65 self->data_offset = 0;
66 self->data_size = 0;
67
68 return self;
69}
70
71void perf_header__add_attr(struct perf_header *self,
72 struct perf_header_attr *attr)
73{
74 int pos = self->attrs;
75
76 if (self->frozen)
77 die("frozen");
78
79 self->attrs++;
80 if (self->attrs > self->size) {
81 self->size *= 2;
82 self->attr = realloc(self->attr, self->size * sizeof(void *));
83 if (!self->attr)
84 die("nomem");
85 }
86 self->attr[pos] = attr;
87}
88
89static const char *__perf_magic = "PERFFILE";
90
91#define PERF_MAGIC (*(u64 *)__perf_magic)
92
93struct perf_file_section {
94 u64 offset;
95 u64 size;
96};
97
98struct perf_file_attr {
99 struct perf_counter_attr attr;
100 struct perf_file_section ids;
101};
102
103struct perf_file_header {
104 u64 magic;
105 u64 size;
106 u64 attr_size;
107 struct perf_file_section attrs;
108 struct perf_file_section data;
109};
110
111static void do_write(int fd, void *buf, size_t size)
112{
113 while (size) {
114 int ret = write(fd, buf, size);
115
116 if (ret < 0)
117 die("failed to write");
118
119 size -= ret;
120 buf += ret;
121 }
122}
123
124void perf_header__write(struct perf_header *self, int fd)
125{
126 struct perf_file_header f_header;
127 struct perf_file_attr f_attr;
128 struct perf_header_attr *attr;
129 int i;
130
131 lseek(fd, sizeof(f_header), SEEK_SET);
132
133
134 for (i = 0; i < self->attrs; i++) {
135 attr = self->attr[i];
136
137 attr->id_offset = lseek(fd, 0, SEEK_CUR);
138 do_write(fd, attr->id, attr->ids * sizeof(u64));
139 }
140
141
142 self->attr_offset = lseek(fd, 0, SEEK_CUR);
143
144 for (i = 0; i < self->attrs; i++) {
145 attr = self->attr[i];
146
147 f_attr = (struct perf_file_attr){
148 .attr = attr->attr,
149 .ids = {
150 .offset = attr->id_offset,
151 .size = attr->ids * sizeof(u64),
152 }
153 };
154 do_write(fd, &f_attr, sizeof(f_attr));
155 }
156
157
158 self->data_offset = lseek(fd, 0, SEEK_CUR);
159
160 f_header = (struct perf_file_header){
161 .magic = PERF_MAGIC,
162 .size = sizeof(f_header),
163 .attr_size = sizeof(f_attr),
164 .attrs = {
165 .offset = self->attr_offset,
166 .size = self->attrs * sizeof(f_attr),
167 },
168 .data = {
169 .offset = self->data_offset,
170 .size = self->data_size,
171 },
172 };
173
174 lseek(fd, 0, SEEK_SET);
175 do_write(fd, &f_header, sizeof(f_header));
176 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
177
178 self->frozen = 1;
179}
180
181static void do_read(int fd, void *buf, size_t size)
182{
183 while (size) {
184 int ret = read(fd, buf, size);
185
186 if (ret < 0)
187 die("failed to read");
188 if (ret == 0)
189 die("failed to read: missing data");
190
191 size -= ret;
192 buf += ret;
193 }
194}
195
196struct perf_header *perf_header__read(int fd)
197{
198 struct perf_header *self = perf_header__new();
199 struct perf_file_header f_header;
200 struct perf_file_attr f_attr;
201 u64 f_id;
202
203 int nr_attrs, nr_ids, i, j;
204
205 lseek(fd, 0, SEEK_SET);
206 do_read(fd, &f_header, sizeof(f_header));
207
208 if (f_header.magic != PERF_MAGIC ||
209 f_header.size != sizeof(f_header) ||
210 f_header.attr_size != sizeof(f_attr))
211 die("incompatible file format");
212
213 nr_attrs = f_header.attrs.size / sizeof(f_attr);
214 lseek(fd, f_header.attrs.offset, SEEK_SET);
215
216 for (i = 0; i < nr_attrs; i++) {
217 struct perf_header_attr *attr;
218 off_t tmp;
219
220 do_read(fd, &f_attr, sizeof(f_attr));
221 tmp = lseek(fd, 0, SEEK_CUR);
222
223 attr = perf_header_attr__new(&f_attr.attr);
224
225 nr_ids = f_attr.ids.size / sizeof(u64);
226 lseek(fd, f_attr.ids.offset, SEEK_SET);
227
228 for (j = 0; j < nr_ids; j++) {
229 do_read(fd, &f_id, sizeof(f_id));
230
231 perf_header_attr__add_id(attr, f_id);
232 }
233 perf_header__add_attr(self, attr);
234 lseek(fd, tmp, SEEK_SET);
235 }
236
237 self->data_offset = f_header.data.offset;
238 self->data_size = f_header.data.size;
239
240 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
241
242 self->frozen = 1;
243
244 return self;
245}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644
index 000000000000..bf280449fcfd
--- /dev/null
+++ b/tools/perf/util/header.h
@@ -0,0 +1,37 @@
1#ifndef _PERF_HEADER_H
2#define _PERF_HEADER_H
3
4#include "../../../include/linux/perf_counter.h"
5#include <sys/types.h>
6#include "types.h"
7
8struct perf_header_attr {
9 struct perf_counter_attr attr;
10 int ids, size;
11 u64 *id;
12 off_t id_offset;
13};
14
15struct perf_header {
16 int frozen;
17 int attrs, size;
18 struct perf_header_attr **attr;
19 s64 attr_offset;
20 u64 data_offset;
21 u64 data_size;
22};
23
24struct perf_header *perf_header__read(int fd);
25void perf_header__write(struct perf_header *self, int fd);
26
27void perf_header__add_attr(struct perf_header *self,
28 struct perf_header_attr *attr);
29
30struct perf_header_attr *
31perf_header_attr__new(struct perf_counter_attr *attr);
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
33
34
35struct perf_header *perf_header__new(void);
36
37#endif /* _PERF_HEADER_H */
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
new file mode 100644
index 000000000000..fbb00978b2e2
--- /dev/null
+++ b/tools/perf/util/help.c
@@ -0,0 +1,356 @@
1#include "cache.h"
2#include "../builtin.h"
3#include "exec_cmd.h"
4#include "levenshtein.h"
5#include "help.h"
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)
30{
31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
32
33 ent->len = len;
34 memcpy(ent->name, name, len);
35 ent->name[len] = 0;
36
37 ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
38 cmds->names[cmds->cnt++] = ent;
39}
40
41static void clean_cmdnames(struct cmdnames *cmds)
42{
43 unsigned int i;
44
45 for (i = 0; i < cmds->cnt; ++i)
46 free(cmds->names[i]);
47 free(cmds->names);
48 cmds->cnt = 0;
49 cmds->alloc = 0;
50}
51
52static int cmdname_compare(const void *a_, const void *b_)
53{
54 struct cmdname *a = *(struct cmdname **)a_;
55 struct cmdname *b = *(struct cmdname **)b_;
56 return strcmp(a->name, b->name);
57}
58
59static void uniq(struct cmdnames *cmds)
60{
61 unsigned int i, j;
62
63 if (!cmds->cnt)
64 return;
65
66 for (i = j = 1; i < cmds->cnt; i++)
67 if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
68 cmds->names[j++] = cmds->names[i];
69
70 cmds->cnt = j;
71}
72
73void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
74{
75 size_t ci, cj, ei;
76 int cmp;
77
78 ci = cj = ei = 0;
79 while (ci < cmds->cnt && ei < excludes->cnt) {
80 cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
81 if (cmp < 0)
82 cmds->names[cj++] = cmds->names[ci++];
83 else if (cmp == 0)
84 ci++, ei++;
85 else if (cmp > 0)
86 ei++;
87 }
88
89 while (ci < cmds->cnt)
90 cmds->names[cj++] = cmds->names[ci++];
91
92 cmds->cnt = cj;
93}
94
95static void pretty_print_string_list(struct cmdnames *cmds, int longest)
96{
97 int cols = 1, rows;
98 int space = longest + 1; /* min 1 SP between words */
99 int max_cols = term_columns() - 1; /* don't print *on* the edge */
100 int i, j;
101
102 if (space < max_cols)
103 cols = max_cols / space;
104 rows = (cmds->cnt + cols - 1) / cols;
105
106 for (i = 0; i < rows; i++) {
107 printf(" ");
108
109 for (j = 0; j < cols; j++) {
110 unsigned int n = j * rows + i;
111 unsigned int size = space;
112
113 if (n >= cmds->cnt)
114 break;
115 if (j == cols-1 || n + rows >= cmds->cnt)
116 size = 1;
117 printf("%-*s", size, cmds->names[n]->name);
118 }
119 putchar('\n');
120 }
121}
122
123static int is_executable(const char *name)
124{
125 struct stat st;
126
127 if (stat(name, &st) || /* stat, not lstat */
128 !S_ISREG(st.st_mode))
129 return 0;
130
131 return st.st_mode & S_IXUSR;
132}
133
134static void list_commands_in_dir(struct cmdnames *cmds,
135 const char *path,
136 const char *prefix)
137{
138 int prefix_len;
139 DIR *dir = opendir(path);
140 struct dirent *de;
141 struct strbuf buf = STRBUF_INIT;
142 int len;
143
144 if (!dir)
145 return;
146 if (!prefix)
147 prefix = "perf-";
148 prefix_len = strlen(prefix);
149
150 strbuf_addf(&buf, "%s/", path);
151 len = buf.len;
152
153 while ((de = readdir(dir)) != NULL) {
154 int entlen;
155
156 if (prefixcmp(de->d_name, prefix))
157 continue;
158
159 strbuf_setlen(&buf, len);
160 strbuf_addstr(&buf, de->d_name);
161 if (!is_executable(buf.buf))
162 continue;
163
164 entlen = strlen(de->d_name) - prefix_len;
165 if (has_extension(de->d_name, ".exe"))
166 entlen -= 4;
167
168 add_cmdname(cmds, de->d_name + prefix_len, entlen);
169 }
170 closedir(dir);
171 strbuf_release(&buf);
172}
173
174void load_command_list(const char *prefix,
175 struct cmdnames *main_cmds,
176 struct cmdnames *other_cmds)
177{
178 const char *env_path = getenv("PATH");
179 const char *exec_path = perf_exec_path();
180
181 if (exec_path) {
182 list_commands_in_dir(main_cmds, exec_path, prefix);
183 qsort(main_cmds->names, main_cmds->cnt,
184 sizeof(*main_cmds->names), cmdname_compare);
185 uniq(main_cmds);
186 }
187
188 if (env_path) {
189 char *paths, *path, *colon;
190 path = paths = strdup(env_path);
191 while (1) {
192 if ((colon = strchr(path, PATH_SEP)))
193 *colon = 0;
194 if (!exec_path || strcmp(path, exec_path))
195 list_commands_in_dir(other_cmds, path, prefix);
196
197 if (!colon)
198 break;
199 path = colon + 1;
200 }
201 free(paths);
202
203 qsort(other_cmds->names, other_cmds->cnt,
204 sizeof(*other_cmds->names), cmdname_compare);
205 uniq(other_cmds);
206 }
207 exclude_cmds(other_cmds, main_cmds);
208}
209
210void list_commands(const char *title, struct cmdnames *main_cmds,
211 struct cmdnames *other_cmds)
212{
213 unsigned int i, longest = 0;
214
215 for (i = 0; i < main_cmds->cnt; i++)
216 if (longest < main_cmds->names[i]->len)
217 longest = main_cmds->names[i]->len;
218 for (i = 0; i < other_cmds->cnt; i++)
219 if (longest < other_cmds->names[i]->len)
220 longest = other_cmds->names[i]->len;
221
222 if (main_cmds->cnt) {
223 const char *exec_path = perf_exec_path();
224 printf("available %s in '%s'\n", title, exec_path);
225 printf("----------------");
226 mput_char('-', strlen(title) + strlen(exec_path));
227 putchar('\n');
228 pretty_print_string_list(main_cmds, longest);
229 putchar('\n');
230 }
231
232 if (other_cmds->cnt) {
233 printf("%s available from elsewhere on your $PATH\n", title);
234 printf("---------------------------------------");
235 mput_char('-', strlen(title));
236 putchar('\n');
237 pretty_print_string_list(other_cmds, longest);
238 putchar('\n');
239 }
240}
241
242int is_in_cmdlist(struct cmdnames *c, const char *s)
243{
244 unsigned int i;
245
246 for (i = 0; i < c->cnt; i++)
247 if (!strcmp(s, c->names[i]->name))
248 return 1;
249 return 0;
250}
251
252static int autocorrect;
253static struct cmdnames aliases;
254
255static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
256{
257 if (!strcmp(var, "help.autocorrect"))
258 autocorrect = perf_config_int(var,value);
259 /* Also use aliases for command lookup */
260 if (!prefixcmp(var, "alias."))
261 add_cmdname(&aliases, var + 6, strlen(var + 6));
262
263 return perf_default_config(var, value, cb);
264}
265
266static int levenshtein_compare(const void *p1, const void *p2)
267{
268 const struct cmdname *const *c1 = p1, *const *c2 = p2;
269 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
270 int l1 = (*c1)->len;
271 int l2 = (*c2)->len;
272 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
273}
274
275static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
276{
277 unsigned int i;
278
279 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
280
281 for (i = 0; i < old->cnt; i++)
282 cmds->names[cmds->cnt++] = old->names[i];
283 free(old->names);
284 old->cnt = 0;
285 old->names = NULL;
286}
287
288const char *help_unknown_cmd(const char *cmd)
289{
290 unsigned int i, n = 0, best_similarity = 0;
291 struct cmdnames main_cmds, other_cmds;
292
293 memset(&main_cmds, 0, sizeof(main_cmds));
294 memset(&other_cmds, 0, sizeof(main_cmds));
295 memset(&aliases, 0, sizeof(aliases));
296
297 perf_config(perf_unknown_cmd_config, NULL);
298
299 load_command_list("perf-", &main_cmds, &other_cmds);
300
301 add_cmd_list(&main_cmds, &aliases);
302 add_cmd_list(&main_cmds, &other_cmds);
303 qsort(main_cmds.names, main_cmds.cnt,
304 sizeof(main_cmds.names), cmdname_compare);
305 uniq(&main_cmds);
306
307 if (main_cmds.cnt) {
308 /* This reuses cmdname->len for similarity index */
309 for (i = 0; i < main_cmds.cnt; ++i)
310 main_cmds.names[i]->len =
311 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
312
313 qsort(main_cmds.names, main_cmds.cnt,
314 sizeof(*main_cmds.names), levenshtein_compare);
315
316 best_similarity = main_cmds.names[0]->len;
317 n = 1;
318 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
319 ++n;
320 }
321
322 if (autocorrect && n == 1) {
323 const char *assumed = main_cmds.names[0]->name;
324
325 main_cmds.names[0] = NULL;
326 clean_cmdnames(&main_cmds);
327 fprintf(stderr, "WARNING: You called a Git program named '%s', "
328 "which does not exist.\n"
329 "Continuing under the assumption that you meant '%s'\n",
330 cmd, assumed);
331 if (autocorrect > 0) {
332 fprintf(stderr, "in %0.1f seconds automatically...\n",
333 (float)autocorrect/10.0);
334 poll(NULL, 0, autocorrect * 100);
335 }
336 return assumed;
337 }
338
339 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
340
341 if (main_cmds.cnt && best_similarity < 6) {
342 fprintf(stderr, "\nDid you mean %s?\n",
343 n < 2 ? "this": "one of these");
344
345 for (i = 0; i < n; i++)
346 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
347 }
348
349 exit(1);
350}
351
352int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
353{
354 printf("perf version %s\n", perf_version_string);
355 return 0;
356}
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
new file mode 100644
index 000000000000..7128783637b4
--- /dev/null
+++ b/tools/perf/util/help.h
@@ -0,0 +1,29 @@
1#ifndef HELP_H
2#define HELP_H
3
4struct cmdnames {
5 size_t alloc;
6 size_t cnt;
7 struct cmdname {
8 size_t len; /* also used for similarity index in help.c */
9 char name[FLEX_ARRAY];
10 } **names;
11};
12
13static inline void mput_char(char c, unsigned int num)
14{
15 while(num--)
16 putchar(c);
17}
18
19void load_command_list(const char *prefix,
20 struct cmdnames *main_cmds,
21 struct cmdnames *other_cmds);
22void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
23/* Here we require that excludes is a sorted list. */
24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
25int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds);
28
29#endif /* HELP_H */
diff --git a/tools/perf/util/include/asm/system.h b/tools/perf/util/include/asm/system.h
new file mode 100644
index 000000000000..710cecca972d
--- /dev/null
+++ b/tools/perf/util/include/asm/system.h
@@ -0,0 +1 @@
/* Empty */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
new file mode 100644
index 000000000000..a6b87390cb52
--- /dev/null
+++ b/tools/perf/util/include/linux/kernel.h
@@ -0,0 +1,29 @@
1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_
3
4#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif
7
8#ifndef container_of
9/**
10 * container_of - cast a member of a structure out to the containing structure
11 * @ptr: the pointer to the member.
12 * @type: the type of the container struct this is embedded in.
13 * @member: the name of the member within the struct.
14 *
15 */
16#define container_of(ptr, type, member) ({ \
17 const typeof(((type *)0)->member) * __mptr = (ptr); \
18 (type *)((char *)__mptr - offsetof(type, member)); })
19#endif
20
21#ifndef max
22#define max(x, y) ({ \
23 typeof(x) _max1 = (x); \
24 typeof(y) _max2 = (y); \
25 (void) (&_max1 == &_max2); \
26 _max1 > _max2 ? _max1 : _max2; })
27#endif
28
29#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
new file mode 100644
index 000000000000..dbe4b814382a
--- /dev/null
+++ b/tools/perf/util/include/linux/list.h
@@ -0,0 +1,18 @@
1#include "../../../../include/linux/list.h"
2
3#ifndef PERF_LIST_H
4#define PERF_LIST_H
5/**
6 * list_del_range - deletes range of entries from list.
7 * @begin: first element in the range to delete from the list.
8 * @end: last element in the range to delete from the list.
9 * Note: list_empty on the range of entries does not return true after this,
10 * the entries is in an undefined state.
11 */
12static inline void list_del_range(struct list_head *begin,
13 struct list_head *end)
14{
15 begin->prev->next = end->next;
16 end->next->prev = begin->prev;
17}
18#endif
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/module.h
new file mode 100644
index 000000000000..b43e2dc21e04
--- /dev/null
+++ b/tools/perf/util/include/linux/module.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/poison.h b/tools/perf/util/include/linux/poison.h
new file mode 100644
index 000000000000..fef6dbc9ce13
--- /dev/null
+++ b/tools/perf/util/include/linux/poison.h
@@ -0,0 +1 @@
#include "../../../../include/linux/poison.h"
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
new file mode 100644
index 000000000000..7841e485d8c3
--- /dev/null
+++ b/tools/perf/util/include/linux/prefetch.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_PREFETCH_H
2#define PERF_LINUX_PREFETCH_H
3
4static inline void prefetch(void *a __attribute__((unused))) { }
5
6#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
new file mode 100644
index 000000000000..7a243a143037
--- /dev/null
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -0,0 +1 @@
#include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/levenshtein.c b/tools/perf/util/levenshtein.c
new file mode 100644
index 000000000000..e521d1516df6
--- /dev/null
+++ b/tools/perf/util/levenshtein.c
@@ -0,0 +1,84 @@
1#include "cache.h"
2#include "levenshtein.h"
3
4/*
5 * This function implements the Damerau-Levenshtein algorithm to
6 * calculate a distance between strings.
7 *
8 * Basically, it says how many letters need to be swapped, substituted,
9 * deleted from, or added to string1, at least, to get string2.
10 *
11 * The idea is to build a distance matrix for the substrings of both
12 * strings. To avoid a large space complexity, only the last three rows
13 * are kept in memory (if swaps had the same or higher cost as one deletion
14 * plus one insertion, only two rows would be needed).
15 *
16 * At any stage, "i + 1" denotes the length of the current substring of
17 * string1 that the distance is calculated for.
18 *
19 * row2 holds the current row, row1 the previous row (i.e. for the substring
20 * of string1 of length "i"), and row0 the row before that.
21 *
22 * In other words, at the start of the big loop, row2[j + 1] contains the
23 * Damerau-Levenshtein distance between the substring of string1 of length
24 * "i" and the substring of string2 of length "j + 1".
25 *
26 * All the big loop does is determine the partial minimum-cost paths.
27 *
28 * It does so by calculating the costs of the path ending in characters
29 * i (in string1) and j (in string2), respectively, given that the last
30 * operation is a substition, a swap, a deletion, or an insertion.
31 *
32 * This implementation allows the costs to be weighted:
33 *
34 * - w (as in "sWap")
35 * - s (as in "Substitution")
36 * - a (for insertion, AKA "Add")
37 * - d (as in "Deletion")
38 *
39 * Note that this algorithm calculates a distance _iff_ d == a.
40 */
41int levenshtein(const char *string1, const char *string2,
42 int w, int s, int a, int d)
43{
44 int len1 = strlen(string1), len2 = strlen(string2);
45 int *row0 = malloc(sizeof(int) * (len2 + 1));
46 int *row1 = malloc(sizeof(int) * (len2 + 1));
47 int *row2 = malloc(sizeof(int) * (len2 + 1));
48 int i, j;
49
50 for (j = 0; j <= len2; j++)
51 row1[j] = j * a;
52 for (i = 0; i < len1; i++) {
53 int *dummy;
54
55 row2[0] = (i + 1) * d;
56 for (j = 0; j < len2; j++) {
57 /* substitution */
58 row2[j + 1] = row1[j] + s * (string1[i] != string2[j]);
59 /* swap */
60 if (i > 0 && j > 0 && string1[i - 1] == string2[j] &&
61 string1[i] == string2[j - 1] &&
62 row2[j + 1] > row0[j - 1] + w)
63 row2[j + 1] = row0[j - 1] + w;
64 /* deletion */
65 if (row2[j + 1] > row1[j + 1] + d)
66 row2[j + 1] = row1[j + 1] + d;
67 /* insertion */
68 if (row2[j + 1] > row2[j] + a)
69 row2[j + 1] = row2[j] + a;
70 }
71
72 dummy = row0;
73 row0 = row1;
74 row1 = row2;
75 row2 = dummy;
76 }
77
78 i = row1[len2];
79 free(row0);
80 free(row1);
81 free(row2);
82
83 return i;
84}
diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h
new file mode 100644
index 000000000000..0173abeef52c
--- /dev/null
+++ b/tools/perf/util/levenshtein.h
@@ -0,0 +1,8 @@
1#ifndef LEVENSHTEIN_H
2#define LEVENSHTEIN_H
3
4int levenshtein(const char *string1, const char *string2,
5 int swap_penalty, int substition_penalty,
6 int insertion_penalty, int deletion_penalty);
7
8#endif
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
new file mode 100644
index 000000000000..ddabe925d65d
--- /dev/null
+++ b/tools/perf/util/module.c
@@ -0,0 +1,509 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <gelf.h>
8#include <elf.h>
9#include <dirent.h>
10#include <sys/utsname.h>
11
12static unsigned int crc32(const char *p, unsigned int len)
13{
14 int i;
15 unsigned int crc = 0;
16
17 while (len--) {
18 crc ^= *p++;
19 for (i = 0; i < 8; i++)
20 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
21 }
22 return crc;
23}
24
25/* module section methods */
26
27struct sec_dso *sec_dso__new_dso(const char *name)
28{
29 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
30
31 if (self != NULL) {
32 strcpy(self->name, name);
33 self->secs = RB_ROOT;
34 self->find_section = sec_dso__find_section;
35 }
36
37 return self;
38}
39
40static void sec_dso__delete_section(struct section *self)
41{
42 free(((void *)self));
43}
44
45void sec_dso__delete_sections(struct sec_dso *self)
46{
47 struct section *pos;
48 struct rb_node *next = rb_first(&self->secs);
49
50 while (next) {
51 pos = rb_entry(next, struct section, rb_node);
52 next = rb_next(&pos->rb_node);
53 rb_erase(&pos->rb_node, &self->secs);
54 sec_dso__delete_section(pos);
55 }
56}
57
58void sec_dso__delete_self(struct sec_dso *self)
59{
60 sec_dso__delete_sections(self);
61 free(self);
62}
63
64static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
65{
66 struct rb_node **p = &self->secs.rb_node;
67 struct rb_node *parent = NULL;
68 const u64 hash = sec->hash;
69 struct section *s;
70
71 while (*p != NULL) {
72 parent = *p;
73 s = rb_entry(parent, struct section, rb_node);
74 if (hash < s->hash)
75 p = &(*p)->rb_left;
76 else
77 p = &(*p)->rb_right;
78 }
79 rb_link_node(&sec->rb_node, parent, p);
80 rb_insert_color(&sec->rb_node, &self->secs);
81}
82
83struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
84{
85 struct rb_node *n;
86 u64 hash;
87 int len;
88
89 if (self == NULL)
90 return NULL;
91
92 len = strlen(name);
93 hash = crc32(name, len);
94
95 n = self->secs.rb_node;
96
97 while (n) {
98 struct section *s = rb_entry(n, struct section, rb_node);
99
100 if (hash < s->hash)
101 n = n->rb_left;
102 else if (hash > s->hash)
103 n = n->rb_right;
104 else {
105 if (!strcmp(name, s->name))
106 return s;
107 else
108 n = rb_next(&s->rb_node);
109 }
110 }
111
112 return NULL;
113}
114
115static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
116{
117 return fprintf(fp, "name:%s vma:%llx path:%s\n",
118 self->name, self->vma, self->path);
119}
120
121size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
122{
123 size_t ret = fprintf(fp, "dso: %s\n", self->name);
124
125 struct rb_node *nd;
126 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
127 struct section *pos = rb_entry(nd, struct section, rb_node);
128 ret += sec_dso__fprintf_section(pos, fp);
129 }
130
131 return ret;
132}
133
134static struct section *section__new(const char *name, const char *path)
135{
136 struct section *self = calloc(1, sizeof(*self));
137
138 if (!self)
139 goto out_failure;
140
141 self->name = calloc(1, strlen(name) + 1);
142 if (!self->name)
143 goto out_failure;
144
145 self->path = calloc(1, strlen(path) + 1);
146 if (!self->path)
147 goto out_failure;
148
149 strcpy(self->name, name);
150 strcpy(self->path, path);
151 self->hash = crc32(self->name, strlen(name));
152
153 return self;
154
155out_failure:
156 if (self) {
157 if (self->name)
158 free(self->name);
159 if (self->path)
160 free(self->path);
161 free(self);
162 }
163
164 return NULL;
165}
166
167/* module methods */
168
169struct mod_dso *mod_dso__new_dso(const char *name)
170{
171 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
172
173 if (self != NULL) {
174 strcpy(self->name, name);
175 self->mods = RB_ROOT;
176 self->find_module = mod_dso__find_module;
177 }
178
179 return self;
180}
181
182static void mod_dso__delete_module(struct module *self)
183{
184 free(((void *)self));
185}
186
187void mod_dso__delete_modules(struct mod_dso *self)
188{
189 struct module *pos;
190 struct rb_node *next = rb_first(&self->mods);
191
192 while (next) {
193 pos = rb_entry(next, struct module, rb_node);
194 next = rb_next(&pos->rb_node);
195 rb_erase(&pos->rb_node, &self->mods);
196 mod_dso__delete_module(pos);
197 }
198}
199
200void mod_dso__delete_self(struct mod_dso *self)
201{
202 mod_dso__delete_modules(self);
203 free(self);
204}
205
206static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
207{
208 struct rb_node **p = &self->mods.rb_node;
209 struct rb_node *parent = NULL;
210 const u64 hash = mod->hash;
211 struct module *m;
212
213 while (*p != NULL) {
214 parent = *p;
215 m = rb_entry(parent, struct module, rb_node);
216 if (hash < m->hash)
217 p = &(*p)->rb_left;
218 else
219 p = &(*p)->rb_right;
220 }
221 rb_link_node(&mod->rb_node, parent, p);
222 rb_insert_color(&mod->rb_node, &self->mods);
223}
224
225struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
226{
227 struct rb_node *n;
228 u64 hash;
229 int len;
230
231 if (self == NULL)
232 return NULL;
233
234 len = strlen(name);
235 hash = crc32(name, len);
236
237 n = self->mods.rb_node;
238
239 while (n) {
240 struct module *m = rb_entry(n, struct module, rb_node);
241
242 if (hash < m->hash)
243 n = n->rb_left;
244 else if (hash > m->hash)
245 n = n->rb_right;
246 else {
247 if (!strcmp(name, m->name))
248 return m;
249 else
250 n = rb_next(&m->rb_node);
251 }
252 }
253
254 return NULL;
255}
256
257static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
258{
259 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
260}
261
262size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
263{
264 struct rb_node *nd;
265 size_t ret;
266
267 ret = fprintf(fp, "dso: %s\n", self->name);
268
269 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
270 struct module *pos = rb_entry(nd, struct module, rb_node);
271
272 ret += mod_dso__fprintf_module(pos, fp);
273 }
274
275 return ret;
276}
277
278static struct module *module__new(const char *name, const char *path)
279{
280 struct module *self = calloc(1, sizeof(*self));
281
282 if (!self)
283 goto out_failure;
284
285 self->name = calloc(1, strlen(name) + 1);
286 if (!self->name)
287 goto out_failure;
288
289 self->path = calloc(1, strlen(path) + 1);
290 if (!self->path)
291 goto out_failure;
292
293 strcpy(self->name, name);
294 strcpy(self->path, path);
295 self->hash = crc32(self->name, strlen(name));
296
297 return self;
298
299out_failure:
300 if (self) {
301 if (self->name)
302 free(self->name);
303 if (self->path)
304 free(self->path);
305 free(self);
306 }
307
308 return NULL;
309}
310
311static int mod_dso__load_sections(struct module *mod)
312{
313 int count = 0, path_len;
314 struct dirent *entry;
315 char *line = NULL;
316 char *dir_path;
317 DIR *dir;
318 size_t n;
319
320 path_len = strlen("/sys/module/");
321 path_len += strlen(mod->name);
322 path_len += strlen("/sections/");
323
324 dir_path = calloc(1, path_len + 1);
325 if (dir_path == NULL)
326 goto out_failure;
327
328 strcat(dir_path, "/sys/module/");
329 strcat(dir_path, mod->name);
330 strcat(dir_path, "/sections/");
331
332 dir = opendir(dir_path);
333 if (dir == NULL)
334 goto out_free;
335
336 while ((entry = readdir(dir))) {
337 struct section *section;
338 char *path, *vma;
339 int line_len;
340 FILE *file;
341
342 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
343 continue;
344
345 path = calloc(1, path_len + strlen(entry->d_name) + 1);
346 if (path == NULL)
347 break;
348 strcat(path, dir_path);
349 strcat(path, entry->d_name);
350
351 file = fopen(path, "r");
352 if (file == NULL) {
353 free(path);
354 break;
355 }
356
357 line_len = getline(&line, &n, file);
358 if (line_len < 0) {
359 free(path);
360 fclose(file);
361 break;
362 }
363
364 if (!line) {
365 free(path);
366 fclose(file);
367 break;
368 }
369
370 line[--line_len] = '\0'; /* \n */
371
372 vma = strstr(line, "0x");
373 if (!vma) {
374 free(path);
375 fclose(file);
376 break;
377 }
378 vma += 2;
379
380 section = section__new(entry->d_name, path);
381 if (!section) {
382 fprintf(stderr, "load_sections: allocation error\n");
383 free(path);
384 fclose(file);
385 break;
386 }
387
388 hex2u64(vma, &section->vma);
389 sec_dso__insert_section(mod->sections, section);
390
391 free(path);
392 fclose(file);
393 count++;
394 }
395
396 closedir(dir);
397 free(line);
398 free(dir_path);
399
400 return count;
401
402out_free:
403 free(dir_path);
404
405out_failure:
406 return count;
407}
408
409static int mod_dso__load_module_paths(struct mod_dso *self)
410{
411 struct utsname uts;
412 int count = 0, len;
413 char *line = NULL;
414 FILE *file;
415 char *path;
416 size_t n;
417
418 if (uname(&uts) < 0)
419 goto out_failure;
420
421 len = strlen("/lib/modules/");
422 len += strlen(uts.release);
423 len += strlen("/modules.dep");
424
425 path = calloc(1, len);
426 if (path == NULL)
427 goto out_failure;
428
429 strcat(path, "/lib/modules/");
430 strcat(path, uts.release);
431 strcat(path, "/modules.dep");
432
433 file = fopen(path, "r");
434 free(path);
435 if (file == NULL)
436 goto out_failure;
437
438 while (!feof(file)) {
439 char *path, *name, *tmp;
440 struct module *module;
441 int line_len, len;
442
443 line_len = getline(&line, &n, file);
444 if (line_len < 0)
445 break;
446
447 if (!line)
448 goto out_failure;
449
450 line[--line_len] = '\0'; /* \n */
451
452 path = strtok(line, ":");
453 if (!path)
454 goto out_failure;
455
456 name = strdup(path);
457 name = strtok(name, "/");
458
459 tmp = name;
460
461 while (tmp) {
462 tmp = strtok(NULL, "/");
463 if (tmp)
464 name = tmp;
465 }
466 name = strsep(&name, ".");
467
468 /* Quirk: replace '-' with '_' in sound modules */
469 for (len = strlen(name); len; len--) {
470 if (*(name+len) == '-')
471 *(name+len) = '_';
472 }
473
474 module = module__new(name, path);
475 if (!module) {
476 fprintf(stderr, "load_module_paths: allocation error\n");
477 goto out_failure;
478 }
479 mod_dso__insert_module(self, module);
480
481 module->sections = sec_dso__new_dso("sections");
482 if (!module->sections) {
483 fprintf(stderr, "load_module_paths: allocation error\n");
484 goto out_failure;
485 }
486
487 module->active = mod_dso__load_sections(module);
488
489 if (module->active > 0)
490 count++;
491 }
492
493 free(line);
494 fclose(file);
495
496 return count;
497
498out_failure:
499 return -1;
500}
501
502int mod_dso__load_modules(struct mod_dso *dso)
503{
504 int err;
505
506 err = mod_dso__load_module_paths(dso);
507
508 return err;
509}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
new file mode 100644
index 000000000000..8a592ef641ca
--- /dev/null
+++ b/tools/perf/util/module.h
@@ -0,0 +1,53 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
new file mode 100644
index 000000000000..1915de20dcac
--- /dev/null
+++ b/tools/perf/util/pager.c
@@ -0,0 +1,96 @@
1#include "cache.h"
2#include "run-command.h"
3#include "sigchain.h"
4
5/*
6 * This is split up from the rest of git so that we can do
7 * something different on Windows.
8 */
9
10static int spawned_pager;
11
12static void pager_preexec(void)
13{
14 /*
15 * Work around bug in "less" by not starting it until we
16 * have real input
17 */
18 fd_set in;
19
20 FD_ZERO(&in);
21 FD_SET(0, &in);
22 select(1, &in, NULL, &in, NULL);
23
24 setenv("LESS", "FRSX", 0);
25}
26
27static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
28static struct child_process pager_process;
29
30static void wait_for_pager(void)
31{
32 fflush(stdout);
33 fflush(stderr);
34 /* signal EOF to pager */
35 close(1);
36 close(2);
37 finish_command(&pager_process);
38}
39
40static void wait_for_pager_signal(int signo)
41{
42 wait_for_pager();
43 sigchain_pop(signo);
44 raise(signo);
45}
46
47void setup_pager(void)
48{
49 const char *pager = getenv("PERF_PAGER");
50
51 if (!isatty(1))
52 return;
53 if (!pager) {
54 if (!pager_program)
55 perf_config(perf_default_config, NULL);
56 pager = pager_program;
57 }
58 if (!pager)
59 pager = getenv("PAGER");
60 if (!pager)
61 pager = "less";
62 else if (!*pager || !strcmp(pager, "cat"))
63 return;
64
65 spawned_pager = 1; /* means we are emitting to terminal */
66
67 /* spawn the pager */
68 pager_argv[2] = pager;
69 pager_process.argv = pager_argv;
70 pager_process.in = -1;
71 pager_process.preexec_cb = pager_preexec;
72
73 if (start_command(&pager_process))
74 return;
75
76 /* original process continues, but writes to the pipe */
77 dup2(pager_process.in, 1);
78 if (isatty(2))
79 dup2(pager_process.in, 2);
80 close(pager_process.in);
81
82 /* this makes sure that the parent terminates after the pager */
83 sigchain_push_common(wait_for_pager_signal);
84 atexit(wait_for_pager);
85}
86
87int pager_in_use(void)
88{
89 const char *env;
90
91 if (spawned_pager)
92 return 1;
93
94 env = getenv("PERF_PAGER_IN_USE");
95 return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
96}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
new file mode 100644
index 000000000000..044178408783
--- /dev/null
+++ b/tools/perf/util/parse-events.c
@@ -0,0 +1,682 @@
1
2#include "../perf.h"
3#include "util.h"
4#include "parse-options.h"
5#include "parse-events.h"
6#include "exec_cmd.h"
7#include "string.h"
8#include "cache.h"
9
10extern char *strcasestr(const char *haystack, const char *needle);
11
12int nr_counters;
13
14struct perf_counter_attr attrs[MAX_COUNTERS];
15
16struct event_symbol {
17 u8 type;
18 u64 config;
19 char *symbol;
20 char *alias;
21};
22
23char debugfs_path[MAXPATHLEN];
24
25#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
26#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
27
28static struct event_symbol event_symbols[] = {
29 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
30 { CHW(INSTRUCTIONS), "instructions", "" },
31 { CHW(CACHE_REFERENCES), "cache-references", "" },
32 { CHW(CACHE_MISSES), "cache-misses", "" },
33 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
34 { CHW(BRANCH_MISSES), "branch-misses", "" },
35 { CHW(BUS_CYCLES), "bus-cycles", "" },
36
37 { CSW(CPU_CLOCK), "cpu-clock", "" },
38 { CSW(TASK_CLOCK), "task-clock", "" },
39 { CSW(PAGE_FAULTS), "page-faults", "faults" },
40 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
41 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
42 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
43 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
44};
45
46#define __PERF_COUNTER_FIELD(config, name) \
47 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
48
49#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
50#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
51#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
52#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
53
54static char *hw_event_names[] = {
55 "cycles",
56 "instructions",
57 "cache-references",
58 "cache-misses",
59 "branches",
60 "branch-misses",
61 "bus-cycles",
62};
63
64static char *sw_event_names[] = {
65 "cpu-clock-msecs",
66 "task-clock-msecs",
67 "page-faults",
68 "context-switches",
69 "CPU-migrations",
70 "minor-faults",
71 "major-faults",
72};
73
74#define MAX_ALIASES 8
75
76static char *hw_cache[][MAX_ALIASES] = {
77 { "L1-dcache", "l1-d", "l1d", "L1-data", },
78 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
79 { "LLC", "L2" },
80 { "dTLB", "d-tlb", "Data-TLB", },
81 { "iTLB", "i-tlb", "Instruction-TLB", },
82 { "branch", "branches", "bpu", "btb", "bpc", },
83};
84
85static char *hw_cache_op[][MAX_ALIASES] = {
86 { "load", "loads", "read", },
87 { "store", "stores", "write", },
88 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
89};
90
91static char *hw_cache_result[][MAX_ALIASES] = {
92 { "refs", "Reference", "ops", "access", },
93 { "misses", "miss", },
94};
95
96#define C(x) PERF_COUNT_HW_CACHE_##x
97#define CACHE_READ (1 << C(OP_READ))
98#define CACHE_WRITE (1 << C(OP_WRITE))
99#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
100#define COP(x) (1 << x)
101
102/*
103 * cache operartion stat
104 * L1I : Read and prefetch only
105 * ITLB and BPU : Read-only
106 */
107static unsigned long hw_cache_stat[C(MAX)] = {
108 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
109 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
110 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
111 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
112 [C(ITLB)] = (CACHE_READ),
113 [C(BPU)] = (CACHE_READ),
114};
115
116#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \
117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
118 if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \
119 sys_dirent.d_name) && \
120 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
121 (strcmp(sys_dirent.d_name, ".")) && \
122 (strcmp(sys_dirent.d_name, "..")))
123
124static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
125{
126 char evt_path[MAXPATHLEN];
127 int fd;
128
129 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
130 sys_dir->d_name, evt_dir->d_name);
131 fd = open(evt_path, O_RDONLY);
132 if (fd < 0)
133 return -EINVAL;
134 close(fd);
135
136 return 0;
137}
138
139#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
140 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
141 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
142 sys_dirent.d_name, evt_dirent.d_name) && \
143 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
144 (strcmp(evt_dirent.d_name, ".")) && \
145 (strcmp(evt_dirent.d_name, "..")) && \
146 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
147
148#define MAX_EVENT_LENGTH 30
149
150int valid_debugfs_mount(const char *debugfs)
151{
152 struct statfs st_fs;
153
154 if (statfs(debugfs, &st_fs) < 0)
155 return -ENOENT;
156 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
157 return -ENOENT;
158 return 0;
159}
160
161static char *tracepoint_id_to_name(u64 config)
162{
163 static char tracepoint_name[2 * MAX_EVENT_LENGTH];
164 DIR *sys_dir, *evt_dir;
165 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
166 struct stat st;
167 char id_buf[4];
168 int fd;
169 u64 id;
170 char evt_path[MAXPATHLEN];
171
172 if (valid_debugfs_mount(debugfs_path))
173 return "unkown";
174
175 sys_dir = opendir(debugfs_path);
176 if (!sys_dir)
177 goto cleanup;
178
179 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
180 evt_dir = opendir(evt_path);
181 if (!evt_dir)
182 goto cleanup;
183 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
184 evt_path, st) {
185 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
186 debugfs_path, sys_dirent.d_name,
187 evt_dirent.d_name);
188 fd = open(evt_path, O_RDONLY);
189 if (fd < 0)
190 continue;
191 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
192 close(fd);
193 continue;
194 }
195 close(fd);
196 id = atoll(id_buf);
197 if (id == config) {
198 closedir(evt_dir);
199 closedir(sys_dir);
200 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
201 "%s:%s", sys_dirent.d_name,
202 evt_dirent.d_name);
203 return tracepoint_name;
204 }
205 }
206 closedir(evt_dir);
207 }
208
209cleanup:
210 closedir(sys_dir);
211 return "unkown";
212}
213
214static int is_cache_op_valid(u8 cache_type, u8 cache_op)
215{
216 if (hw_cache_stat[cache_type] & COP(cache_op))
217 return 1; /* valid */
218 else
219 return 0; /* invalid */
220}
221
222static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
223{
224 static char name[50];
225
226 if (cache_result) {
227 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
228 hw_cache_op[cache_op][0],
229 hw_cache_result[cache_result][0]);
230 } else {
231 sprintf(name, "%s-%s", hw_cache[cache_type][0],
232 hw_cache_op[cache_op][1]);
233 }
234
235 return name;
236}
237
238char *event_name(int counter)
239{
240 u64 config = attrs[counter].config;
241 int type = attrs[counter].type;
242
243 return __event_name(type, config);
244}
245
246char *__event_name(int type, u64 config)
247{
248 static char buf[32];
249
250 if (type == PERF_TYPE_RAW) {
251 sprintf(buf, "raw 0x%llx", config);
252 return buf;
253 }
254
255 switch (type) {
256 case PERF_TYPE_HARDWARE:
257 if (config < PERF_COUNT_HW_MAX)
258 return hw_event_names[config];
259 return "unknown-hardware";
260
261 case PERF_TYPE_HW_CACHE: {
262 u8 cache_type, cache_op, cache_result;
263
264 cache_type = (config >> 0) & 0xff;
265 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
266 return "unknown-ext-hardware-cache-type";
267
268 cache_op = (config >> 8) & 0xff;
269 if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
270 return "unknown-ext-hardware-cache-op";
271
272 cache_result = (config >> 16) & 0xff;
273 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
274 return "unknown-ext-hardware-cache-result";
275
276 if (!is_cache_op_valid(cache_type, cache_op))
277 return "invalid-cache";
278
279 return event_cache_name(cache_type, cache_op, cache_result);
280 }
281
282 case PERF_TYPE_SOFTWARE:
283 if (config < PERF_COUNT_SW_MAX)
284 return sw_event_names[config];
285 return "unknown-software";
286
287 case PERF_TYPE_TRACEPOINT:
288 return tracepoint_id_to_name(config);
289
290 default:
291 break;
292 }
293
294 return "unknown";
295}
296
297static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
298{
299 int i, j;
300 int n, longest = -1;
301
302 for (i = 0; i < size; i++) {
303 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
304 n = strlen(names[i][j]);
305 if (n > longest && !strncasecmp(*str, names[i][j], n))
306 longest = n;
307 }
308 if (longest > 0) {
309 *str += longest;
310 return i;
311 }
312 }
313
314 return -1;
315}
316
317static int
318parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
319{
320 const char *s = *str;
321 int cache_type = -1, cache_op = -1, cache_result = -1;
322
323 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
324 /*
325 * No fallback - if we cannot get a clear cache type
326 * then bail out:
327 */
328 if (cache_type == -1)
329 return 0;
330
331 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
332 ++s;
333
334 if (cache_op == -1) {
335 cache_op = parse_aliases(&s, hw_cache_op,
336 PERF_COUNT_HW_CACHE_OP_MAX);
337 if (cache_op >= 0) {
338 if (!is_cache_op_valid(cache_type, cache_op))
339 return 0;
340 continue;
341 }
342 }
343
344 if (cache_result == -1) {
345 cache_result = parse_aliases(&s, hw_cache_result,
346 PERF_COUNT_HW_CACHE_RESULT_MAX);
347 if (cache_result >= 0)
348 continue;
349 }
350
351 /*
352 * Can't parse this as a cache op or result, so back up
353 * to the '-'.
354 */
355 --s;
356 break;
357 }
358
359 /*
360 * Fall back to reads:
361 */
362 if (cache_op == -1)
363 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
364
365 /*
366 * Fall back to accesses:
367 */
368 if (cache_result == -1)
369 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
370
371 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
372 attr->type = PERF_TYPE_HW_CACHE;
373
374 *str = s;
375 return 1;
376}
377
378static int parse_tracepoint_event(const char **strp,
379 struct perf_counter_attr *attr)
380{
381 const char *evt_name;
382 char *flags;
383 char sys_name[MAX_EVENT_LENGTH];
384 char id_buf[4];
385 int fd;
386 unsigned int sys_length, evt_length;
387 u64 id;
388 char evt_path[MAXPATHLEN];
389
390 if (valid_debugfs_mount(debugfs_path))
391 return 0;
392
393 evt_name = strchr(*strp, ':');
394 if (!evt_name)
395 return 0;
396
397 sys_length = evt_name - *strp;
398 if (sys_length >= MAX_EVENT_LENGTH)
399 return 0;
400
401 strncpy(sys_name, *strp, sys_length);
402 sys_name[sys_length] = '\0';
403 evt_name = evt_name + 1;
404
405 flags = strchr(evt_name, ':');
406 if (flags) {
407 *flags = '\0';
408 flags++;
409 if (!strncmp(flags, "record", strlen(flags)))
410 attr->sample_type |= PERF_SAMPLE_RAW;
411 }
412
413 evt_length = strlen(evt_name);
414 if (evt_length >= MAX_EVENT_LENGTH)
415 return 0;
416
417 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
418 sys_name, evt_name);
419 fd = open(evt_path, O_RDONLY);
420 if (fd < 0)
421 return 0;
422
423 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
424 close(fd);
425 return 0;
426 }
427 close(fd);
428 id = atoll(id_buf);
429 attr->config = id;
430 attr->type = PERF_TYPE_TRACEPOINT;
431 *strp = evt_name + evt_length;
432 return 1;
433}
434
435static int check_events(const char *str, unsigned int i)
436{
437 int n;
438
439 n = strlen(event_symbols[i].symbol);
440 if (!strncmp(str, event_symbols[i].symbol, n))
441 return n;
442
443 n = strlen(event_symbols[i].alias);
444 if (n)
445 if (!strncmp(str, event_symbols[i].alias, n))
446 return n;
447 return 0;
448}
449
450static int
451parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
452{
453 const char *str = *strp;
454 unsigned int i;
455 int n;
456
457 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
458 n = check_events(str, i);
459 if (n > 0) {
460 attr->type = event_symbols[i].type;
461 attr->config = event_symbols[i].config;
462 *strp = str + n;
463 return 1;
464 }
465 }
466 return 0;
467}
468
469static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
470{
471 const char *str = *strp;
472 u64 config;
473 int n;
474
475 if (*str != 'r')
476 return 0;
477 n = hex2u64(str + 1, &config);
478 if (n > 0) {
479 *strp = str + n + 1;
480 attr->type = PERF_TYPE_RAW;
481 attr->config = config;
482 return 1;
483 }
484 return 0;
485}
486
487static int
488parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
489{
490 const char *str = *strp;
491 char *endp;
492 unsigned long type;
493 u64 config;
494
495 type = strtoul(str, &endp, 0);
496 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
497 str = endp + 1;
498 config = strtoul(str, &endp, 0);
499 if (endp > str) {
500 attr->type = type;
501 attr->config = config;
502 *strp = endp;
503 return 1;
504 }
505 }
506 return 0;
507}
508
509static int
510parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
511{
512 const char *str = *strp;
513 int eu = 1, ek = 1, eh = 1;
514
515 if (*str++ != ':')
516 return 0;
517 while (*str) {
518 if (*str == 'u')
519 eu = 0;
520 else if (*str == 'k')
521 ek = 0;
522 else if (*str == 'h')
523 eh = 0;
524 else
525 break;
526 ++str;
527 }
528 if (str >= *strp + 2) {
529 *strp = str;
530 attr->exclude_user = eu;
531 attr->exclude_kernel = ek;
532 attr->exclude_hv = eh;
533 return 1;
534 }
535 return 0;
536}
537
538/*
539 * Each event can have multiple symbolic names.
540 * Symbolic names are (almost) exactly matched.
541 */
542static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
543{
544 if (!(parse_tracepoint_event(str, attr) ||
545 parse_raw_event(str, attr) ||
546 parse_numeric_event(str, attr) ||
547 parse_symbolic_event(str, attr) ||
548 parse_generic_hw_event(str, attr)))
549 return 0;
550
551 parse_event_modifier(str, attr);
552
553 return 1;
554}
555
556int parse_events(const struct option *opt __used, const char *str, int unset __used)
557{
558 struct perf_counter_attr attr;
559
560 for (;;) {
561 if (nr_counters == MAX_COUNTERS)
562 return -1;
563
564 memset(&attr, 0, sizeof(attr));
565 if (!parse_event_symbols(&str, &attr))
566 return -1;
567
568 if (!(*str == 0 || *str == ',' || isspace(*str)))
569 return -1;
570
571 attrs[nr_counters] = attr;
572 nr_counters++;
573
574 if (*str == 0)
575 break;
576 if (*str == ',')
577 ++str;
578 while (isspace(*str))
579 ++str;
580 }
581
582 return 0;
583}
584
585static const char * const event_type_descriptors[] = {
586 "",
587 "Hardware event",
588 "Software event",
589 "Tracepoint event",
590 "Hardware cache event",
591};
592
593/*
594 * Print the events from <debugfs_mount_point>/tracing/events
595 */
596
597static void print_tracepoint_events(void)
598{
599 DIR *sys_dir, *evt_dir;
600 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
601 struct stat st;
602 char evt_path[MAXPATHLEN];
603
604 if (valid_debugfs_mount(debugfs_path))
605 return;
606
607 sys_dir = opendir(debugfs_path);
608 if (!sys_dir)
609 goto cleanup;
610
611 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
612 evt_dir = opendir(evt_path);
613 if (!evt_dir)
614 goto cleanup;
615 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
616 evt_path, st) {
617 snprintf(evt_path, MAXPATHLEN, "%s:%s",
618 sys_dirent.d_name, evt_dirent.d_name);
619 fprintf(stderr, " %-40s [%s]\n", evt_path,
620 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
621 }
622 closedir(evt_dir);
623 }
624
625cleanup:
626 closedir(sys_dir);
627}
628
629/*
630 * Print the help text for the event symbols:
631 */
632void print_events(void)
633{
634 struct event_symbol *syms = event_symbols;
635 unsigned int i, type, op, prev_type = -1;
636 char name[40];
637
638 fprintf(stderr, "\n");
639 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
640
641 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
642 type = syms->type + 1;
643 if (type >= ARRAY_SIZE(event_type_descriptors))
644 type = 0;
645
646 if (type != prev_type)
647 fprintf(stderr, "\n");
648
649 if (strlen(syms->alias))
650 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
651 else
652 strcpy(name, syms->symbol);
653 fprintf(stderr, " %-40s [%s]\n", name,
654 event_type_descriptors[type]);
655
656 prev_type = type;
657 }
658
659 fprintf(stderr, "\n");
660 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
661 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
662 /* skip invalid cache type */
663 if (!is_cache_op_valid(type, op))
664 continue;
665
666 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
667 fprintf(stderr, " %-40s [%s]\n",
668 event_cache_name(type, op, i),
669 event_type_descriptors[4]);
670 }
671 }
672 }
673
674 fprintf(stderr, "\n");
675 fprintf(stderr, " %-40s [raw hardware event descriptor]\n",
676 "rNNN");
677 fprintf(stderr, "\n");
678
679 print_tracepoint_events();
680
681 exit(129);
682}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
new file mode 100644
index 000000000000..192a962e3a0f
--- /dev/null
+++ b/tools/perf/util/parse-events.h
@@ -0,0 +1,23 @@
1
2/*
3 * Parse symbolic events/counts passed in as options:
4 */
5
6struct option;
7
8extern int nr_counters;
9
10extern struct perf_counter_attr attrs[MAX_COUNTERS];
11
12extern char *event_name(int ctr);
13extern char *__event_name(int type, u64 config);
14
15extern int parse_events(const struct option *opt, const char *str, int unset);
16
17#define EVENTS_HELP_MAX (128*1024)
18
19extern void print_events(void);
20
21extern char debugfs_path[];
22extern int valid_debugfs_mount(const char *debugfs);
23
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
new file mode 100644
index 000000000000..1bf67190c820
--- /dev/null
+++ b/tools/perf/util/parse-options.c
@@ -0,0 +1,509 @@
1#include "util.h"
2#include "parse-options.h"
3#include "cache.h"
4
5#define OPT_SHORT 1
6#define OPT_UNSET 2
7
8static int opterror(const struct option *opt, const char *reason, int flags)
9{
10 if (flags & OPT_SHORT)
11 return error("switch `%c' %s", opt->short_name, reason);
12 if (flags & OPT_UNSET)
13 return error("option `no-%s' %s", opt->long_name, reason);
14 return error("option `%s' %s", opt->long_name, reason);
15}
16
17static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
18 int flags, const char **arg)
19{
20 if (p->opt) {
21 *arg = p->opt;
22 p->opt = NULL;
23 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
24 **(p->argv + 1) == '-')) {
25 *arg = (const char *)opt->defval;
26 } else if (p->argc > 1) {
27 p->argc--;
28 *arg = *++p->argv;
29 } else
30 return opterror(opt, "requires a value", flags);
31 return 0;
32}
33
34static int get_value(struct parse_opt_ctx_t *p,
35 const struct option *opt, int flags)
36{
37 const char *s, *arg = NULL;
38 const int unset = flags & OPT_UNSET;
39
40 if (unset && p->opt)
41 return opterror(opt, "takes no value", flags);
42 if (unset && (opt->flags & PARSE_OPT_NONEG))
43 return opterror(opt, "isn't available", flags);
44
45 if (!(flags & OPT_SHORT) && p->opt) {
46 switch (opt->type) {
47 case OPTION_CALLBACK:
48 if (!(opt->flags & PARSE_OPT_NOARG))
49 break;
50 /* FALLTHROUGH */
51 case OPTION_BOOLEAN:
52 case OPTION_BIT:
53 case OPTION_SET_INT:
54 case OPTION_SET_PTR:
55 return opterror(opt, "takes no value", flags);
56 default:
57 break;
58 }
59 }
60
61 switch (opt->type) {
62 case OPTION_BIT:
63 if (unset)
64 *(int *)opt->value &= ~opt->defval;
65 else
66 *(int *)opt->value |= opt->defval;
67 return 0;
68
69 case OPTION_BOOLEAN:
70 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
71 return 0;
72
73 case OPTION_SET_INT:
74 *(int *)opt->value = unset ? 0 : opt->defval;
75 return 0;
76
77 case OPTION_SET_PTR:
78 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
79 return 0;
80
81 case OPTION_STRING:
82 if (unset)
83 *(const char **)opt->value = NULL;
84 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
85 *(const char **)opt->value = (const char *)opt->defval;
86 else
87 return get_arg(p, opt, flags, (const char **)opt->value);
88 return 0;
89
90 case OPTION_CALLBACK:
91 if (unset)
92 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
93 if (opt->flags & PARSE_OPT_NOARG)
94 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
95 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
96 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
97 if (get_arg(p, opt, flags, &arg))
98 return -1;
99 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
100
101 case OPTION_INTEGER:
102 if (unset) {
103 *(int *)opt->value = 0;
104 return 0;
105 }
106 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
107 *(int *)opt->value = opt->defval;
108 return 0;
109 }
110 if (get_arg(p, opt, flags, &arg))
111 return -1;
112 *(int *)opt->value = strtol(arg, (char **)&s, 10);
113 if (*s)
114 return opterror(opt, "expects a numerical value", flags);
115 return 0;
116
117 case OPTION_LONG:
118 if (unset) {
119 *(long *)opt->value = 0;
120 return 0;
121 }
122 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
123 *(long *)opt->value = opt->defval;
124 return 0;
125 }
126 if (get_arg(p, opt, flags, &arg))
127 return -1;
128 *(long *)opt->value = strtol(arg, (char **)&s, 10);
129 if (*s)
130 return opterror(opt, "expects a numerical value", flags);
131 return 0;
132
133 default:
134 die("should not happen, someone must be hit on the forehead");
135 }
136}
137
138static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
139{
140 for (; options->type != OPTION_END; options++) {
141 if (options->short_name == *p->opt) {
142 p->opt = p->opt[1] ? p->opt + 1 : NULL;
143 return get_value(p, options, OPT_SHORT);
144 }
145 }
146 return -2;
147}
148
149static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
150 const struct option *options)
151{
152 const char *arg_end = strchr(arg, '=');
153 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
154 int abbrev_flags = 0, ambiguous_flags = 0;
155
156 if (!arg_end)
157 arg_end = arg + strlen(arg);
158
159 for (; options->type != OPTION_END; options++) {
160 const char *rest;
161 int flags = 0;
162
163 if (!options->long_name)
164 continue;
165
166 rest = skip_prefix(arg, options->long_name);
167 if (options->type == OPTION_ARGUMENT) {
168 if (!rest)
169 continue;
170 if (*rest == '=')
171 return opterror(options, "takes no value", flags);
172 if (*rest)
173 continue;
174 p->out[p->cpidx++] = arg - 2;
175 return 0;
176 }
177 if (!rest) {
178 /* abbreviated? */
179 if (!strncmp(options->long_name, arg, arg_end - arg)) {
180is_abbreviated:
181 if (abbrev_option) {
182 /*
183 * If this is abbreviated, it is
184 * ambiguous. So when there is no
185 * exact match later, we need to
186 * error out.
187 */
188 ambiguous_option = abbrev_option;
189 ambiguous_flags = abbrev_flags;
190 }
191 if (!(flags & OPT_UNSET) && *arg_end)
192 p->opt = arg_end + 1;
193 abbrev_option = options;
194 abbrev_flags = flags;
195 continue;
196 }
197 /* negated and abbreviated very much? */
198 if (!prefixcmp("no-", arg)) {
199 flags |= OPT_UNSET;
200 goto is_abbreviated;
201 }
202 /* negated? */
203 if (strncmp(arg, "no-", 3))
204 continue;
205 flags |= OPT_UNSET;
206 rest = skip_prefix(arg + 3, options->long_name);
207 /* abbreviated and negated? */
208 if (!rest && !prefixcmp(options->long_name, arg + 3))
209 goto is_abbreviated;
210 if (!rest)
211 continue;
212 }
213 if (*rest) {
214 if (*rest != '=')
215 continue;
216 p->opt = rest + 1;
217 }
218 return get_value(p, options, flags);
219 }
220
221 if (ambiguous_option)
222 return error("Ambiguous option: %s "
223 "(could be --%s%s or --%s%s)",
224 arg,
225 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
226 ambiguous_option->long_name,
227 (abbrev_flags & OPT_UNSET) ? "no-" : "",
228 abbrev_option->long_name);
229 if (abbrev_option)
230 return get_value(p, abbrev_option, abbrev_flags);
231 return -2;
232}
233
234static void check_typos(const char *arg, const struct option *options)
235{
236 if (strlen(arg) < 3)
237 return;
238
239 if (!prefixcmp(arg, "no-")) {
240 error ("did you mean `--%s` (with two dashes ?)", arg);
241 exit(129);
242 }
243
244 for (; options->type != OPTION_END; options++) {
245 if (!options->long_name)
246 continue;
247 if (!prefixcmp(options->long_name, arg)) {
248 error ("did you mean `--%s` (with two dashes ?)", arg);
249 exit(129);
250 }
251 }
252}
253
254void parse_options_start(struct parse_opt_ctx_t *ctx,
255 int argc, const char **argv, int flags)
256{
257 memset(ctx, 0, sizeof(*ctx));
258 ctx->argc = argc - 1;
259 ctx->argv = argv + 1;
260 ctx->out = argv;
261 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
262 ctx->flags = flags;
263 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
264 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
265 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
266}
267
268static int usage_with_options_internal(const char * const *,
269 const struct option *, int);
270
271int parse_options_step(struct parse_opt_ctx_t *ctx,
272 const struct option *options,
273 const char * const usagestr[])
274{
275 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
276
277 /* we must reset ->opt, unknown short option leave it dangling */
278 ctx->opt = NULL;
279
280 for (; ctx->argc; ctx->argc--, ctx->argv++) {
281 const char *arg = ctx->argv[0];
282
283 if (*arg != '-' || !arg[1]) {
284 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
285 break;
286 ctx->out[ctx->cpidx++] = ctx->argv[0];
287 continue;
288 }
289
290 if (arg[1] != '-') {
291 ctx->opt = arg + 1;
292 if (internal_help && *ctx->opt == 'h')
293 return parse_options_usage(usagestr, options);
294 switch (parse_short_opt(ctx, options)) {
295 case -1:
296 return parse_options_usage(usagestr, options);
297 case -2:
298 goto unknown;
299 }
300 if (ctx->opt)
301 check_typos(arg + 1, options);
302 while (ctx->opt) {
303 if (internal_help && *ctx->opt == 'h')
304 return parse_options_usage(usagestr, options);
305 switch (parse_short_opt(ctx, options)) {
306 case -1:
307 return parse_options_usage(usagestr, options);
308 case -2:
309 /* fake a short option thing to hide the fact that we may have
310 * started to parse aggregated stuff
311 *
312 * This is leaky, too bad.
313 */
314 ctx->argv[0] = strdup(ctx->opt - 1);
315 *(char *)ctx->argv[0] = '-';
316 goto unknown;
317 }
318 }
319 continue;
320 }
321
322 if (!arg[2]) { /* "--" */
323 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
324 ctx->argc--;
325 ctx->argv++;
326 }
327 break;
328 }
329
330 if (internal_help && !strcmp(arg + 2, "help-all"))
331 return usage_with_options_internal(usagestr, options, 1);
332 if (internal_help && !strcmp(arg + 2, "help"))
333 return parse_options_usage(usagestr, options);
334 switch (parse_long_opt(ctx, arg + 2, options)) {
335 case -1:
336 return parse_options_usage(usagestr, options);
337 case -2:
338 goto unknown;
339 }
340 continue;
341unknown:
342 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
343 return PARSE_OPT_UNKNOWN;
344 ctx->out[ctx->cpidx++] = ctx->argv[0];
345 ctx->opt = NULL;
346 }
347 return PARSE_OPT_DONE;
348}
349
350int parse_options_end(struct parse_opt_ctx_t *ctx)
351{
352 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
353 ctx->out[ctx->cpidx + ctx->argc] = NULL;
354 return ctx->cpidx + ctx->argc;
355}
356
357int parse_options(int argc, const char **argv, const struct option *options,
358 const char * const usagestr[], int flags)
359{
360 struct parse_opt_ctx_t ctx;
361
362 parse_options_start(&ctx, argc, argv, flags);
363 switch (parse_options_step(&ctx, options, usagestr)) {
364 case PARSE_OPT_HELP:
365 exit(129);
366 case PARSE_OPT_DONE:
367 break;
368 default: /* PARSE_OPT_UNKNOWN */
369 if (ctx.argv[0][1] == '-') {
370 error("unknown option `%s'", ctx.argv[0] + 2);
371 } else {
372 error("unknown switch `%c'", *ctx.opt);
373 }
374 usage_with_options(usagestr, options);
375 }
376
377 return parse_options_end(&ctx);
378}
379
380#define USAGE_OPTS_WIDTH 24
381#define USAGE_GAP 2
382
383int usage_with_options_internal(const char * const *usagestr,
384 const struct option *opts, int full)
385{
386 if (!usagestr)
387 return PARSE_OPT_HELP;
388
389 fprintf(stderr, "\n usage: %s\n", *usagestr++);
390 while (*usagestr && **usagestr)
391 fprintf(stderr, " or: %s\n", *usagestr++);
392 while (*usagestr) {
393 fprintf(stderr, "%s%s\n",
394 **usagestr ? " " : "",
395 *usagestr);
396 usagestr++;
397 }
398
399 if (opts->type != OPTION_GROUP)
400 fputc('\n', stderr);
401
402 for (; opts->type != OPTION_END; opts++) {
403 size_t pos;
404 int pad;
405
406 if (opts->type == OPTION_GROUP) {
407 fputc('\n', stderr);
408 if (*opts->help)
409 fprintf(stderr, "%s\n", opts->help);
410 continue;
411 }
412 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
413 continue;
414
415 pos = fprintf(stderr, " ");
416 if (opts->short_name)
417 pos += fprintf(stderr, "-%c", opts->short_name);
418 if (opts->long_name && opts->short_name)
419 pos += fprintf(stderr, ", ");
420 if (opts->long_name)
421 pos += fprintf(stderr, "--%s", opts->long_name);
422
423 switch (opts->type) {
424 case OPTION_ARGUMENT:
425 break;
426 case OPTION_INTEGER:
427 if (opts->flags & PARSE_OPT_OPTARG)
428 if (opts->long_name)
429 pos += fprintf(stderr, "[=<n>]");
430 else
431 pos += fprintf(stderr, "[<n>]");
432 else
433 pos += fprintf(stderr, " <n>");
434 break;
435 case OPTION_CALLBACK:
436 if (opts->flags & PARSE_OPT_NOARG)
437 break;
438 /* FALLTHROUGH */
439 case OPTION_STRING:
440 if (opts->argh) {
441 if (opts->flags & PARSE_OPT_OPTARG)
442 if (opts->long_name)
443 pos += fprintf(stderr, "[=<%s>]", opts->argh);
444 else
445 pos += fprintf(stderr, "[<%s>]", opts->argh);
446 else
447 pos += fprintf(stderr, " <%s>", opts->argh);
448 } else {
449 if (opts->flags & PARSE_OPT_OPTARG)
450 if (opts->long_name)
451 pos += fprintf(stderr, "[=...]");
452 else
453 pos += fprintf(stderr, "[...]");
454 else
455 pos += fprintf(stderr, " ...");
456 }
457 break;
458 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
459 break;
460 }
461
462 if (pos <= USAGE_OPTS_WIDTH)
463 pad = USAGE_OPTS_WIDTH - pos;
464 else {
465 fputc('\n', stderr);
466 pad = USAGE_OPTS_WIDTH;
467 }
468 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
469 }
470 fputc('\n', stderr);
471
472 return PARSE_OPT_HELP;
473}
474
475void usage_with_options(const char * const *usagestr,
476 const struct option *opts)
477{
478 usage_with_options_internal(usagestr, opts, 0);
479 exit(129);
480}
481
482int parse_options_usage(const char * const *usagestr,
483 const struct option *opts)
484{
485 return usage_with_options_internal(usagestr, opts, 0);
486}
487
488
489int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
490 int unset)
491{
492 int *target = opt->value;
493
494 if (unset)
495 /* --no-quiet, --no-verbose */
496 *target = 0;
497 else if (opt->short_name == 'v') {
498 if (*target >= 0)
499 (*target)++;
500 else
501 *target = 1;
502 } else {
503 if (*target <= 0)
504 (*target)--;
505 else
506 *target = -1;
507 }
508 return 0;
509}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
new file mode 100644
index 000000000000..8aa3464c7090
--- /dev/null
+++ b/tools/perf/util/parse-options.h
@@ -0,0 +1,175 @@
1#ifndef PARSE_OPTIONS_H
2#define PARSE_OPTIONS_H
3
4enum parse_opt_type {
5 /* special types */
6 OPTION_END,
7 OPTION_ARGUMENT,
8 OPTION_GROUP,
9 /* options with no arguments */
10 OPTION_BIT,
11 OPTION_BOOLEAN, /* _INCR would have been a better name */
12 OPTION_SET_INT,
13 OPTION_SET_PTR,
14 /* options with arguments (usually) */
15 OPTION_STRING,
16 OPTION_INTEGER,
17 OPTION_LONG,
18 OPTION_CALLBACK,
19};
20
21enum parse_opt_flags {
22 PARSE_OPT_KEEP_DASHDASH = 1,
23 PARSE_OPT_STOP_AT_NON_OPTION = 2,
24 PARSE_OPT_KEEP_ARGV0 = 4,
25 PARSE_OPT_KEEP_UNKNOWN = 8,
26 PARSE_OPT_NO_INTERNAL_HELP = 16,
27};
28
29enum parse_opt_option_flags {
30 PARSE_OPT_OPTARG = 1,
31 PARSE_OPT_NOARG = 2,
32 PARSE_OPT_NONEG = 4,
33 PARSE_OPT_HIDDEN = 8,
34 PARSE_OPT_LASTARG_DEFAULT = 16,
35};
36
37struct option;
38typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
39
40/*
41 * `type`::
42 * holds the type of the option, you must have an OPTION_END last in your
43 * array.
44 *
45 * `short_name`::
46 * the character to use as a short option name, '\0' if none.
47 *
48 * `long_name`::
49 * the long option name, without the leading dashes, NULL if none.
50 *
51 * `value`::
52 * stores pointers to the values to be filled.
53 *
54 * `argh`::
55 * token to explain the kind of argument this option wants. Keep it
56 * homogenous across the repository.
57 *
58 * `help`::
59 * the short help associated to what the option does.
60 * Must never be NULL (except for OPTION_END).
61 * OPTION_GROUP uses this pointer to store the group header.
62 *
63 * `flags`::
64 * mask of parse_opt_option_flags.
65 * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
66 * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
67 * PARSE_OPT_NONEG: says that this option cannot be negated
68 * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
69 * the long one.
70 *
71 * `callback`::
72 * pointer to the callback to use for OPTION_CALLBACK.
73 *
74 * `defval`::
75 * 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
77 * the value when met.
78 * CALLBACKS can use it like they want.
79 */
80struct option {
81 enum parse_opt_type type;
82 int short_name;
83 const char *long_name;
84 void *value;
85 const char *argh;
86 const char *help;
87
88 int flags;
89 parse_opt_cb *callback;
90 intptr_t defval;
91};
92
93#define OPT_END() { .type = OPTION_END }
94#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
95#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) }
97#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
98#define OPT_SET_INT(s, l, v, h, i) { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { .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) }
101#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
102#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) }
103#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 }
105#define OPT_CALLBACK(s, l, v, a, h, f) \
106 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
107#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
108 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
109
110/* parse_options() will filter out the processed options and leave the
111 * non-option argments in argv[].
112 * Returns the number of arguments left in argv[].
113 */
114extern int parse_options(int argc, const char **argv,
115 const struct option *options,
116 const char * const usagestr[], int flags);
117
118extern NORETURN void usage_with_options(const char * const *usagestr,
119 const struct option *options);
120
121/*----- incremantal advanced APIs -----*/
122
123enum {
124 PARSE_OPT_HELP = -1,
125 PARSE_OPT_DONE,
126 PARSE_OPT_UNKNOWN,
127};
128
129/*
130 * It's okay for the caller to consume argv/argc in the usual way.
131 * Other fields of that structure are private to parse-options and should not
132 * be modified in any way.
133 */
134struct parse_opt_ctx_t {
135 const char **argv;
136 const char **out;
137 int argc, cpidx;
138 const char *opt;
139 int flags;
140};
141
142extern int parse_options_usage(const char * const *usagestr,
143 const struct option *opts);
144
145extern void parse_options_start(struct parse_opt_ctx_t *ctx,
146 int argc, const char **argv, int flags);
147
148extern int parse_options_step(struct parse_opt_ctx_t *ctx,
149 const struct option *options,
150 const char * const usagestr[]);
151
152extern int parse_options_end(struct parse_opt_ctx_t *ctx);
153
154
155/*----- some often used options -----*/
156extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
157extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
158extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
159
160#define OPT__VERBOSE(var) OPT_BOOLEAN('v', "verbose", (var), "be verbose")
161#define OPT__QUIET(var) OPT_BOOLEAN('q', "quiet", (var), "be quiet")
162#define OPT__VERBOSITY(var) \
163 { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
164 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
165 { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
166 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
167#define OPT__DRY_RUN(var) OPT_BOOLEAN('n', "dry-run", (var), "dry run")
168#define OPT__ABBREV(var) \
169 { OPTION_CALLBACK, 0, "abbrev", (var), "n", \
170 "use <n> digits to display SHA-1s", \
171 PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
172
173extern const char *parse_options_fix_filename(const char *prefix, const char *file);
174
175#endif
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
new file mode 100644
index 000000000000..a501a40dd2cb
--- /dev/null
+++ b/tools/perf/util/path.c
@@ -0,0 +1,353 @@
1/*
2 * I'm tired of doing "vsnprintf()" etc just to open a
3 * file, so here's a "return static buffer with printf"
4 * interface for paths.
5 *
6 * It's obviously not thread-safe. Sue me. But it's quite
7 * useful for doing things like
8 *
9 * f = open(mkpath("%s/%s.perf", base, name), O_RDONLY);
10 *
11 * which is what it's designed for.
12 */
13#include "cache.h"
14
15static char bad_path[] = "/bad-path/";
16/*
17 * Two hacks:
18 */
19
20static char *get_perf_dir(void)
21{
22 return ".";
23}
24
25size_t strlcpy(char *dest, const char *src, size_t size)
26{
27 size_t ret = strlen(src);
28
29 if (size) {
30 size_t len = (ret >= size) ? size - 1 : ret;
31 memcpy(dest, src, len);
32 dest[len] = '\0';
33 }
34 return ret;
35}
36
37
38static char *get_pathname(void)
39{
40 static char pathname_array[4][PATH_MAX];
41 static int index;
42 return pathname_array[3 & ++index];
43}
44
45static char *cleanup_path(char *path)
46{
47 /* Clean it up */
48 if (!memcmp(path, "./", 2)) {
49 path += 2;
50 while (*path == '/')
51 path++;
52 }
53 return path;
54}
55
56char *mksnpath(char *buf, size_t n, const char *fmt, ...)
57{
58 va_list args;
59 unsigned len;
60
61 va_start(args, fmt);
62 len = vsnprintf(buf, n, fmt, args);
63 va_end(args);
64 if (len >= n) {
65 strlcpy(buf, bad_path, n);
66 return buf;
67 }
68 return cleanup_path(buf);
69}
70
71static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
72{
73 const char *perf_dir = get_perf_dir();
74 size_t len;
75
76 len = strlen(perf_dir);
77 if (n < len + 1)
78 goto bad;
79 memcpy(buf, perf_dir, len);
80 if (len && !is_dir_sep(perf_dir[len-1]))
81 buf[len++] = '/';
82 len += vsnprintf(buf + len, n - len, fmt, args);
83 if (len >= n)
84 goto bad;
85 return cleanup_path(buf);
86bad:
87 strlcpy(buf, bad_path, n);
88 return buf;
89}
90
91char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
92{
93 va_list args;
94 va_start(args, fmt);
95 (void)perf_vsnpath(buf, n, fmt, args);
96 va_end(args);
97 return buf;
98}
99
100char *perf_pathdup(const char *fmt, ...)
101{
102 char path[PATH_MAX];
103 va_list args;
104 va_start(args, fmt);
105 (void)perf_vsnpath(path, sizeof(path), fmt, args);
106 va_end(args);
107 return xstrdup(path);
108}
109
110char *mkpath(const char *fmt, ...)
111{
112 va_list args;
113 unsigned len;
114 char *pathname = get_pathname();
115
116 va_start(args, fmt);
117 len = vsnprintf(pathname, PATH_MAX, fmt, args);
118 va_end(args);
119 if (len >= PATH_MAX)
120 return bad_path;
121 return cleanup_path(pathname);
122}
123
124char *perf_path(const char *fmt, ...)
125{
126 const char *perf_dir = get_perf_dir();
127 char *pathname = get_pathname();
128 va_list args;
129 unsigned len;
130
131 len = strlen(perf_dir);
132 if (len > PATH_MAX-100)
133 return bad_path;
134 memcpy(pathname, perf_dir, len);
135 if (len && perf_dir[len-1] != '/')
136 pathname[len++] = '/';
137 va_start(args, fmt);
138 len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
139 va_end(args);
140 if (len >= PATH_MAX)
141 return bad_path;
142 return cleanup_path(pathname);
143}
144
145
146/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
147int perf_mkstemp(char *path, size_t len, const char *template)
148{
149 const char *tmp;
150 size_t n;
151
152 tmp = getenv("TMPDIR");
153 if (!tmp)
154 tmp = "/tmp";
155 n = snprintf(path, len, "%s/%s", tmp, template);
156 if (len <= n) {
157 errno = ENAMETOOLONG;
158 return -1;
159 }
160 return mkstemp(path);
161}
162
163
164const char *make_relative_path(const char *abs, const char *base)
165{
166 static char buf[PATH_MAX + 1];
167 int baselen;
168 if (!base)
169 return abs;
170 baselen = strlen(base);
171 if (prefixcmp(abs, base))
172 return abs;
173 if (abs[baselen] == '/')
174 baselen++;
175 else if (base[baselen - 1] != '/')
176 return abs;
177 strcpy(buf, abs + baselen);
178 return buf;
179}
180
181/*
182 * It is okay if dst == src, but they should not overlap otherwise.
183 *
184 * Performs the following normalizations on src, storing the result in dst:
185 * - Ensures that components are separated by '/' (Windows only)
186 * - Squashes sequences of '/'.
187 * - Removes "." components.
188 * - Removes ".." components, and the components the precede them.
189 * Returns failure (non-zero) if a ".." component appears as first path
190 * component anytime during the normalization. Otherwise, returns success (0).
191 *
192 * Note that this function is purely textual. It does not follow symlinks,
193 * verify the existence of the path, or make any system calls.
194 */
195int normalize_path_copy(char *dst, const char *src)
196{
197 char *dst0;
198
199 if (has_dos_drive_prefix(src)) {
200 *dst++ = *src++;
201 *dst++ = *src++;
202 }
203 dst0 = dst;
204
205 if (is_dir_sep(*src)) {
206 *dst++ = '/';
207 while (is_dir_sep(*src))
208 src++;
209 }
210
211 for (;;) {
212 char c = *src;
213
214 /*
215 * A path component that begins with . could be
216 * special:
217 * (1) "." and ends -- ignore and terminate.
218 * (2) "./" -- ignore them, eat slash and continue.
219 * (3) ".." and ends -- strip one and terminate.
220 * (4) "../" -- strip one, eat slash and continue.
221 */
222 if (c == '.') {
223 if (!src[1]) {
224 /* (1) */
225 src++;
226 } else if (is_dir_sep(src[1])) {
227 /* (2) */
228 src += 2;
229 while (is_dir_sep(*src))
230 src++;
231 continue;
232 } else if (src[1] == '.') {
233 if (!src[2]) {
234 /* (3) */
235 src += 2;
236 goto up_one;
237 } else if (is_dir_sep(src[2])) {
238 /* (4) */
239 src += 3;
240 while (is_dir_sep(*src))
241 src++;
242 goto up_one;
243 }
244 }
245 }
246
247 /* copy up to the next '/', and eat all '/' */
248 while ((c = *src++) != '\0' && !is_dir_sep(c))
249 *dst++ = c;
250 if (is_dir_sep(c)) {
251 *dst++ = '/';
252 while (is_dir_sep(c))
253 c = *src++;
254 src--;
255 } else if (!c)
256 break;
257 continue;
258
259 up_one:
260 /*
261 * dst0..dst is prefix portion, and dst[-1] is '/';
262 * go up one level.
263 */
264 dst--; /* go to trailing '/' */
265 if (dst <= dst0)
266 return -1;
267 /* Windows: dst[-1] cannot be backslash anymore */
268 while (dst0 < dst && dst[-1] != '/')
269 dst--;
270 }
271 *dst = '\0';
272 return 0;
273}
274
275/*
276 * path = Canonical absolute path
277 * prefix_list = Colon-separated list of absolute paths
278 *
279 * Determines, for each path in prefix_list, whether the "prefix" really
280 * is an ancestor directory of path. Returns the length of the longest
281 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
282 * is an ancestor. (Note that this means 0 is returned if prefix_list is
283 * "/".) "/foo" is not considered an ancestor of "/foobar". Directories
284 * are not considered to be their own ancestors. path must be in a
285 * canonical form: empty components, or "." or ".." components are not
286 * allowed. prefix_list may be null, which is like "".
287 */
288int longest_ancestor_length(const char *path, const char *prefix_list)
289{
290 char buf[PATH_MAX+1];
291 const char *ceil, *colon;
292 int len, max_len = -1;
293
294 if (prefix_list == NULL || !strcmp(path, "/"))
295 return -1;
296
297 for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
298 for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
299 len = colon - ceil;
300 if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
301 continue;
302 strlcpy(buf, ceil, len+1);
303 if (normalize_path_copy(buf, buf) < 0)
304 continue;
305 len = strlen(buf);
306 if (len > 0 && buf[len-1] == '/')
307 buf[--len] = '\0';
308
309 if (!strncmp(path, buf, len) &&
310 path[len] == '/' &&
311 len > max_len) {
312 max_len = len;
313 }
314 }
315
316 return max_len;
317}
318
319/* strip arbitrary amount of directory separators at end of path */
320static inline int chomp_trailing_dir_sep(const char *path, int len)
321{
322 while (len && is_dir_sep(path[len - 1]))
323 len--;
324 return len;
325}
326
327/*
328 * If path ends with suffix (complete path components), returns the
329 * part before suffix (sans trailing directory separators).
330 * Otherwise returns NULL.
331 */
332char *strip_path_suffix(const char *path, const char *suffix)
333{
334 int path_len = strlen(path), suffix_len = strlen(suffix);
335
336 while (suffix_len) {
337 if (!path_len)
338 return NULL;
339
340 if (is_dir_sep(path[path_len - 1])) {
341 if (!is_dir_sep(suffix[suffix_len - 1]))
342 return NULL;
343 path_len = chomp_trailing_dir_sep(path, path_len);
344 suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
345 }
346 else if (path[--path_len] != suffix[--suffix_len])
347 return NULL;
348 }
349
350 if (path_len && !is_dir_sep(path[path_len - 1]))
351 return NULL;
352 return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
353}
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
new file mode 100644
index 000000000000..2726fe40eb5d
--- /dev/null
+++ b/tools/perf/util/quote.c
@@ -0,0 +1,485 @@
1#include "cache.h"
2#include "quote.h"
3
4int quote_path_fully = 1;
5
6/* Help to copy the thing properly quoted for the shell safety.
7 * any single quote is replaced with '\'', any exclamation point
8 * is replaced with '\!', and the whole thing is enclosed in a
9 *
10 * E.g.
11 * original sq_quote result
12 * name ==> name ==> 'name'
13 * a b ==> a b ==> 'a b'
14 * a'b ==> a'\''b ==> 'a'\''b'
15 * a!b ==> a'\!'b ==> 'a'\!'b'
16 */
17static inline int need_bs_quote(char c)
18{
19 return (c == '\'' || c == '!');
20}
21
22void sq_quote_buf(struct strbuf *dst, const char *src)
23{
24 char *to_free = NULL;
25
26 if (dst->buf == src)
27 to_free = strbuf_detach(dst, NULL);
28
29 strbuf_addch(dst, '\'');
30 while (*src) {
31 size_t len = strcspn(src, "'!");
32 strbuf_add(dst, src, len);
33 src += len;
34 while (need_bs_quote(*src)) {
35 strbuf_addstr(dst, "'\\");
36 strbuf_addch(dst, *src++);
37 strbuf_addch(dst, '\'');
38 }
39 }
40 strbuf_addch(dst, '\'');
41 free(to_free);
42}
43
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)
62{
63 int i;
64
65 /* Copy into destination buffer. */
66 strbuf_grow(dst, 255);
67 for (i = 0; argv[i]; ++i) {
68 strbuf_addch(dst, ' ');
69 sq_quote_buf(dst, argv[i]);
70 if (maxlen && dst->len > maxlen)
71 die("Too many or long arguments");
72 }
73}
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
new file mode 100644
index 000000000000..a5454a1d1c13
--- /dev/null
+++ b/tools/perf/util/quote.h
@@ -0,0 +1,68 @@
1#ifndef QUOTE_H
2#define QUOTE_H
3
4#include <stddef.h>
5#include <stdio.h>
6
7/* Help to copy the thing properly quoted for the shell safety.
8 * any single quote is replaced with '\'', any exclamation point
9 * is replaced with '\!', and the whole thing is enclosed in a
10 * single quote pair.
11 *
12 * For example, if you are passing the result to system() as an
13 * argument:
14 *
15 * sprintf(cmd, "foobar %s %s", sq_quote(arg0), sq_quote(arg1))
16 *
17 * would be appropriate. If the system() is going to call ssh to
18 * run the command on the other side:
19 *
20 * sprintf(cmd, "git-diff-tree %s %s", sq_quote(arg0), sq_quote(arg1));
21 * sprintf(rcmd, "ssh %s %s", sq_util/quote.host), sq_quote(cmd));
22 *
23 * Note that the above examples leak memory! Remember to free result from
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 */
30
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);
35
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
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
new file mode 100644
index 000000000000..a3935343091a
--- /dev/null
+++ b/tools/perf/util/run-command.c
@@ -0,0 +1,304 @@
1#include "cache.h"
2#include "run-command.h"
3#include "exec_cmd.h"
4
5static inline void close_pair(int fd[2])
6{
7 close(fd[0]);
8 close(fd[1]);
9}
10
11static inline void dup_devnull(int to)
12{
13 int fd = open("/dev/null", O_RDWR);
14 dup2(fd, to);
15 close(fd);
16}
17
18int start_command(struct child_process *cmd)
19{
20 int need_in, need_out, need_err;
21 int fdin[2], fdout[2], fderr[2];
22
23 /*
24 * In case of errors we must keep the promise to close FDs
25 * that have been passed in via ->in and ->out.
26 */
27
28 need_in = !cmd->no_stdin && cmd->in < 0;
29 if (need_in) {
30 if (pipe(fdin) < 0) {
31 if (cmd->out > 0)
32 close(cmd->out);
33 return -ERR_RUN_COMMAND_PIPE;
34 }
35 cmd->in = fdin[1];
36 }
37
38 need_out = !cmd->no_stdout
39 && !cmd->stdout_to_stderr
40 && cmd->out < 0;
41 if (need_out) {
42 if (pipe(fdout) < 0) {
43 if (need_in)
44 close_pair(fdin);
45 else if (cmd->in)
46 close(cmd->in);
47 return -ERR_RUN_COMMAND_PIPE;
48 }
49 cmd->out = fdout[0];
50 }
51
52 need_err = !cmd->no_stderr && cmd->err < 0;
53 if (need_err) {
54 if (pipe(fderr) < 0) {
55 if (need_in)
56 close_pair(fdin);
57 else if (cmd->in)
58 close(cmd->in);
59 if (need_out)
60 close_pair(fdout);
61 else if (cmd->out)
62 close(cmd->out);
63 return -ERR_RUN_COMMAND_PIPE;
64 }
65 cmd->err = fderr[0];
66 }
67
68 fflush(NULL);
69 cmd->pid = fork();
70 if (!cmd->pid) {
71 if (cmd->no_stdin)
72 dup_devnull(0);
73 else if (need_in) {
74 dup2(fdin[0], 0);
75 close_pair(fdin);
76 } else if (cmd->in) {
77 dup2(cmd->in, 0);
78 close(cmd->in);
79 }
80
81 if (cmd->no_stderr)
82 dup_devnull(2);
83 else if (need_err) {
84 dup2(fderr[1], 2);
85 close_pair(fderr);
86 }
87
88 if (cmd->no_stdout)
89 dup_devnull(1);
90 else if (cmd->stdout_to_stderr)
91 dup2(2, 1);
92 else if (need_out) {
93 dup2(fdout[1], 1);
94 close_pair(fdout);
95 } else if (cmd->out > 1) {
96 dup2(cmd->out, 1);
97 close(cmd->out);
98 }
99
100 if (cmd->dir && chdir(cmd->dir))
101 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
102 cmd->dir, strerror(errno));
103 if (cmd->env) {
104 for (; *cmd->env; cmd->env++) {
105 if (strchr(*cmd->env, '='))
106 putenv((char*)*cmd->env);
107 else
108 unsetenv(*cmd->env);
109 }
110 }
111 if (cmd->preexec_cb)
112 cmd->preexec_cb();
113 if (cmd->perf_cmd) {
114 execv_perf_cmd(cmd->argv);
115 } else {
116 execvp(cmd->argv[0], (char *const*) cmd->argv);
117 }
118 exit(127);
119 }
120
121 if (cmd->pid < 0) {
122 int err = errno;
123 if (need_in)
124 close_pair(fdin);
125 else if (cmd->in)
126 close(cmd->in);
127 if (need_out)
128 close_pair(fdout);
129 else if (cmd->out)
130 close(cmd->out);
131 if (need_err)
132 close_pair(fderr);
133 return err == ENOENT ?
134 -ERR_RUN_COMMAND_EXEC :
135 -ERR_RUN_COMMAND_FORK;
136 }
137
138 if (need_in)
139 close(fdin[0]);
140 else if (cmd->in)
141 close(cmd->in);
142
143 if (need_out)
144 close(fdout[1]);
145 else if (cmd->out)
146 close(cmd->out);
147
148 if (need_err)
149 close(fderr[1]);
150
151 return 0;
152}
153
154static int wait_or_whine(pid_t pid)
155{
156 for (;;) {
157 int status, code;
158 pid_t waiting = waitpid(pid, &status, 0);
159
160 if (waiting < 0) {
161 if (errno == EINTR)
162 continue;
163 error("waitpid failed (%s)", strerror(errno));
164 return -ERR_RUN_COMMAND_WAITPID;
165 }
166 if (waiting != pid)
167 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
168 if (WIFSIGNALED(status))
169 return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
170
171 if (!WIFEXITED(status))
172 return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
173 code = WEXITSTATUS(status);
174 switch (code) {
175 case 127:
176 return -ERR_RUN_COMMAND_EXEC;
177 case 0:
178 return 0;
179 default:
180 return -code;
181 }
182 }
183}
184
185int finish_command(struct child_process *cmd)
186{
187 return wait_or_whine(cmd->pid);
188}
189
190int run_command(struct child_process *cmd)
191{
192 int code = start_command(cmd);
193 if (code)
194 return code;
195 return finish_command(cmd);
196}
197
198static void prepare_run_command_v_opt(struct child_process *cmd,
199 const char **argv,
200 int opt)
201{
202 memset(cmd, 0, sizeof(*cmd));
203 cmd->argv = argv;
204 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
205 cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
206 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
207}
208
209int run_command_v_opt(const char **argv, int opt)
210{
211 struct child_process cmd;
212 prepare_run_command_v_opt(&cmd, argv, opt);
213 return run_command(&cmd);
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 index[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(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file);
288 env[0] = index;
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
new file mode 100644
index 000000000000..cc1837deba88
--- /dev/null
+++ b/tools/perf/util/run-command.h
@@ -0,0 +1,88 @@
1#ifndef RUN_COMMAND_H
2#define RUN_COMMAND_H
3
4enum {
5 ERR_RUN_COMMAND_FORK = 10000,
6 ERR_RUN_COMMAND_EXEC,
7 ERR_RUN_COMMAND_PIPE,
8 ERR_RUN_COMMAND_WAITPID,
9 ERR_RUN_COMMAND_WAITPID_WRONG_PID,
10 ERR_RUN_COMMAND_WAITPID_SIGNAL,
11 ERR_RUN_COMMAND_WAITPID_NOEXIT,
12};
13#define IS_RUN_COMMAND_ERR(x) (-(x) >= ERR_RUN_COMMAND_FORK)
14
15struct child_process {
16 const char **argv;
17 pid_t pid;
18 /*
19 * Using .in, .out, .err:
20 * - Specify 0 for no redirections (child inherits stdin, stdout,
21 * stderr from parent).
22 * - Specify -1 to have a pipe allocated as follows:
23 * .in: returns the writable pipe end; parent writes to it,
24 * the readable pipe end becomes child's stdin
25 * .out, .err: returns the readable pipe end; parent reads from
26 * it, the writable pipe end becomes child's stdout/stderr
27 * The caller of start_command() must close the returned FDs
28 * after it has completed reading from/writing to it!
29 * - Specify > 0 to set a channel to a particular FD as follows:
30 * .in: a readable FD, becomes child's stdin
31 * .out: a writable FD, becomes child's stdout/stderr
32 * .err > 0 not supported
33 * The specified FD is closed by start_command(), even in case
34 * of errors!
35 */
36 int in;
37 int out;
38 int err;
39 const char *dir;
40 const char *const *env;
41 unsigned no_stdin:1;
42 unsigned no_stdout:1;
43 unsigned no_stderr:1;
44 unsigned perf_cmd:1; /* if this is to be perf sub-command */
45 unsigned stdout_to_stderr:1;
46 void (*preexec_cb)(void);
47};
48
49int start_command(struct child_process *);
50int finish_command(struct child_process *);
51int run_command(struct child_process *);
52
53extern int run_hook(const char *index_file, const char *name, ...);
54
55#define RUN_COMMAND_NO_STDIN 1
56#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */
57#define RUN_COMMAND_STDOUT_TO_STDERR 4
58int run_command_v_opt(const char **argv, int opt);
59
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
diff --git a/tools/perf/util/sigchain.c b/tools/perf/util/sigchain.c
new file mode 100644
index 000000000000..1118b99e57d3
--- /dev/null
+++ b/tools/perf/util/sigchain.c
@@ -0,0 +1,52 @@
1#include "sigchain.h"
2#include "cache.h"
3
4#define SIGCHAIN_MAX_SIGNALS 32
5
6struct sigchain_signal {
7 sigchain_fun *old;
8 int n;
9 int alloc;
10};
11static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
12
13static void check_signum(int sig)
14{
15 if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
16 die("BUG: signal out of range: %d", sig);
17}
18
19int sigchain_push(int sig, sigchain_fun f)
20{
21 struct sigchain_signal *s = signals + sig;
22 check_signum(sig);
23
24 ALLOC_GROW(s->old, s->n + 1, s->alloc);
25 s->old[s->n] = signal(sig, f);
26 if (s->old[s->n] == SIG_ERR)
27 return -1;
28 s->n++;
29 return 0;
30}
31
32int sigchain_pop(int sig)
33{
34 struct sigchain_signal *s = signals + sig;
35 check_signum(sig);
36 if (s->n < 1)
37 return 0;
38
39 if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
40 return -1;
41 s->n--;
42 return 0;
43}
44
45void sigchain_push_common(sigchain_fun f)
46{
47 sigchain_push(SIGINT, f);
48 sigchain_push(SIGHUP, f);
49 sigchain_push(SIGTERM, f);
50 sigchain_push(SIGQUIT, f);
51 sigchain_push(SIGPIPE, f);
52}
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
new file mode 100644
index 000000000000..618083bce0c6
--- /dev/null
+++ b/tools/perf/util/sigchain.h
@@ -0,0 +1,11 @@
1#ifndef SIGCHAIN_H
2#define SIGCHAIN_H
3
4typedef void (*sigchain_fun)(int);
5
6int sigchain_push(int sig, sigchain_fun f);
7int sigchain_pop(int sig);
8
9void sigchain_push_common(sigchain_fun f);
10
11#endif /* SIGCHAIN_H */
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
new file mode 100644
index 000000000000..5249d5a1b0c2
--- /dev/null
+++ b/tools/perf/util/strbuf.c
@@ -0,0 +1,360 @@
1#include "cache.h"
2
3int prefixcmp(const char *str, const char *prefix)
4{
5 for (; ; str++, prefix++)
6 if (!*prefix)
7 return 0;
8 else if (*str != *prefix)
9 return (unsigned char)*prefix - (unsigned char)*str;
10}
11
12/*
13 * Used as the default ->buf value, so that people can always assume
14 * buf is non NULL and ->buf is NUL terminated even for a freshly
15 * initialized strbuf.
16 */
17char strbuf_slopbuf[1];
18
19void strbuf_init(struct strbuf *sb, ssize_t hint)
20{
21 sb->alloc = sb->len = 0;
22 sb->buf = strbuf_slopbuf;
23 if (hint)
24 strbuf_grow(sb, hint);
25}
26
27void strbuf_release(struct strbuf *sb)
28{
29 if (sb->alloc) {
30 free(sb->buf);
31 strbuf_init(sb, 0);
32 }
33}
34
35char *strbuf_detach(struct strbuf *sb, size_t *sz)
36{
37 char *res = sb->alloc ? sb->buf : NULL;
38 if (sz)
39 *sz = sb->len;
40 strbuf_init(sb, 0);
41 return res;
42}
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)
55{
56 if (sb->len + extra + 1 <= sb->len)
57 die("you want to use way too much memory");
58 if (!sb->alloc)
59 sb->buf = NULL;
60 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
61}
62
63void strbuf_trim(struct strbuf *sb)
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)
152{
153 if (pos + len < pos)
154 die("you want to use way too much memory");
155 if (pos > sb->len)
156 die("`pos' is too far after the end of the buffer");
157 if (pos + len > sb->len)
158 die("`pos + len' is too far after the end of the buffer");
159
160 if (dlen >= len)
161 strbuf_grow(sb, dlen - len);
162 memmove(sb->buf + pos + dlen,
163 sb->buf + pos + len,
164 sb->len - pos - len);
165 memcpy(sb->buf + pos, data, dlen);
166 strbuf_setlen(sb, sb->len + dlen - len);
167}
168
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)
175{
176 strbuf_splice(sb, pos, len, NULL, 0);
177}
178
179void strbuf_add(struct strbuf *sb, const void *data, size_t len)
180{
181 strbuf_grow(sb, len);
182 memcpy(sb->buf + sb->len, data, len);
183 strbuf_setlen(sb, sb->len + len);
184}
185
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, ...)
194{
195 int len;
196 va_list ap;
197
198 if (!strbuf_avail(sb))
199 strbuf_grow(sb, 64);
200 va_start(ap, fmt);
201 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
202 va_end(ap);
203 if (len < 0)
204 die("your vsnprintf is broken");
205 if (len > strbuf_avail(sb)) {
206 strbuf_grow(sb, len);
207 va_start(ap, fmt);
208 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
209 va_end(ap);
210 if (len > strbuf_avail(sb)) {
211 die("this should not happen, your snprintf is broken");
212 }
213 }
214 strbuf_setlen(sb, sb->len + len);
215}
216
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)
269{
270 size_t oldlen = sb->len;
271 size_t oldalloc = sb->alloc;
272
273 strbuf_grow(sb, hint ? hint : 8192);
274 for (;;) {
275 ssize_t cnt;
276
277 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
278 if (cnt < 0) {
279 if (oldalloc == 0)
280 strbuf_release(sb);
281 else
282 strbuf_setlen(sb, oldlen);
283 return -1;
284 }
285 if (!cnt)
286 break;
287 sb->len += cnt;
288 strbuf_grow(sb, 8192);
289 }
290
291 sb->buf[sb->len] = '\0';
292 return sb->len - oldlen;
293}
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
new file mode 100644
index 000000000000..d2aa86c014c1
--- /dev/null
+++ b/tools/perf/util/strbuf.h
@@ -0,0 +1,137 @@
1#ifndef STRBUF_H
2#define STRBUF_H
3
4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
6 * long, overflow safe strings.
7 *
8 * Strbufs has some invariants that are very important to keep in mind:
9 *
10 * 1. the ->buf member is always malloc-ed, hence strbuf's can be used to
11 * build complex strings/buffers whose final size isn't easily known.
12 *
13 * It is NOT legal to copy the ->buf pointer away.
14 * `strbuf_detach' is the operation that detachs a buffer from its shell
15 * while keeping the shell valid wrt its invariants.
16 *
17 * 2. the ->buf member is a byte array that has at least ->len + 1 bytes
18 * allocated. The extra byte is used to store a '\0', allowing the ->buf
19 * member to be a valid C-string. Every strbuf function ensure this
20 * invariant is preserved.
21 *
22 * Note that it is OK to "play" with the buffer directly if you work it
23 * that way:
24 *
25 * strbuf_grow(sb, SOME_SIZE);
26 * ... Here, the memory array starting at sb->buf, and of length
27 * ... strbuf_avail(sb) is all yours, and you are sure that
28 * ... strbuf_avail(sb) is at least SOME_SIZE.
29 * strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
30 *
31 * Of course, SOME_OTHER_SIZE must be smaller or equal to strbuf_avail(sb).
32 *
33 * Doing so is safe, though if it has to be done in many places, adding the
34 * missing API to the strbuf module is the way to go.
35 *
36 * XXX: do _not_ assume that the area that is yours is of size ->alloc - 1
37 * even if it's true in the current implementation. Alloc is somehow a
38 * "private" member that should not be messed with.
39 */
40
41#include <assert.h>
42
43extern char strbuf_slopbuf[];
44struct strbuf {
45 size_t alloc;
46 size_t len;
47 char *buf;
48};
49
50#define STRBUF_INIT { 0, 0, strbuf_slopbuf }
51
52/*----- strbuf life cycle -----*/
53extern void strbuf_init(struct strbuf *buf, ssize_t hint);
54extern void strbuf_release(struct strbuf *);
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
63/*----- strbuf size related -----*/
64static inline ssize_t strbuf_avail(const struct strbuf *sb) {
65 return sb->alloc ? sb->alloc - sb->len - 1 : 0;
66}
67
68extern void strbuf_grow(struct strbuf *, size_t);
69
70static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
71 if (!sb->alloc)
72 strbuf_grow(sb, 0);
73 assert(len < sb->alloc);
74 sb->len = len;
75 sb->buf[len] = '\0';
76}
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
89/*----- add data in your buffer -----*/
90static inline void strbuf_addch(struct strbuf *sb, int c) {
91 strbuf_grow(sb, 1);
92 sb->buf[sb->len++] = c;
93 sb->buf[sb->len] = '\0';
94}
95
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);
98
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);
104static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
105 strbuf_add(sb, s, strlen(s));
106}
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
120__attribute__((format(printf,2,3)))
121extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
122
123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
124/* XXX: if read fails, any partial read is undone */
125extern 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
137#endif /* STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
new file mode 100644
index 000000000000..c93eca9a7be3
--- /dev/null
+++ b/tools/perf/util/string.c
@@ -0,0 +1,34 @@
1#include "string.h"
2
3static int hex(char ch)
4{
5 if ((ch >= '0') && (ch <= '9'))
6 return ch - '0';
7 if ((ch >= 'a') && (ch <= 'f'))
8 return ch - 'a' + 10;
9 if ((ch >= 'A') && (ch <= 'F'))
10 return ch - 'A' + 10;
11 return -1;
12}
13
14/*
15 * While we find nice hex chars, build a long_val.
16 * Return number of chars processed.
17 */
18int hex2u64(const char *ptr, u64 *long_val)
19{
20 const char *p = ptr;
21 *long_val = 0;
22
23 while (*p) {
24 const int hex_val = hex(*p);
25
26 if (hex_val < 0)
27 break;
28
29 *long_val = (*long_val << 4) | hex_val;
30 p++;
31 }
32
33 return p - ptr;
34}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
new file mode 100644
index 000000000000..bf39dfadfd24
--- /dev/null
+++ b/tools/perf/util/string.h
@@ -0,0 +1,11 @@
1#ifndef _PERF_STRING_H_
2#define _PERF_STRING_H_
3
4#include "types.h"
5
6int hex2u64(const char *ptr, u64 *val);
7
8#define _STR(x) #x
9#define STR(x) _STR(x)
10
11#endif
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
new file mode 100644
index 000000000000..7ad38171dc2b
--- /dev/null
+++ b/tools/perf/util/strlist.c
@@ -0,0 +1,200 @@
1/*
2 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Licensed under the GPLv2.
5 */
6
7#include "strlist.h"
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13static struct str_node *str_node__new(const char *s, bool dupstr)
14{
15 struct str_node *self = malloc(sizeof(*self));
16
17 if (self != NULL) {
18 if (dupstr) {
19 s = strdup(s);
20 if (s == NULL)
21 goto out_delete;
22 }
23 self->s = s;
24 }
25
26 return self;
27
28out_delete:
29 free(self);
30 return NULL;
31}
32
33static void str_node__delete(struct str_node *self, bool dupstr)
34{
35 if (dupstr)
36 free((void *)self->s);
37 free(self);
38}
39
40int strlist__add(struct strlist *self, const char *new_entry)
41{
42 struct rb_node **p = &self->entries.rb_node;
43 struct rb_node *parent = NULL;
44 struct str_node *sn;
45
46 while (*p != NULL) {
47 int rc;
48
49 parent = *p;
50 sn = rb_entry(parent, struct str_node, rb_node);
51 rc = strcmp(sn->s, new_entry);
52
53 if (rc > 0)
54 p = &(*p)->rb_left;
55 else if (rc < 0)
56 p = &(*p)->rb_right;
57 else
58 return -EEXIST;
59 }
60
61 sn = str_node__new(new_entry, self->dupstr);
62 if (sn == NULL)
63 return -ENOMEM;
64
65 rb_link_node(&sn->rb_node, parent, p);
66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
68
69 return 0;
70}
71
72int strlist__load(struct strlist *self, const char *filename)
73{
74 char entry[1024];
75 int err;
76 FILE *fp = fopen(filename, "r");
77
78 if (fp == NULL)
79 return errno;
80
81 while (fgets(entry, sizeof(entry), fp) != NULL) {
82 const size_t len = strlen(entry);
83
84 if (len == 0)
85 continue;
86 entry[len - 1] = '\0';
87
88 err = strlist__add(self, entry);
89 if (err != 0)
90 goto out;
91 }
92
93 err = 0;
94out:
95 fclose(fp);
96 return err;
97}
98
99void strlist__remove(struct strlist *self, struct str_node *sn)
100{
101 rb_erase(&sn->rb_node, &self->entries);
102 str_node__delete(sn, self->dupstr);
103}
104
105bool strlist__has_entry(struct strlist *self, const char *entry)
106{
107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL;
109
110 while (*p != NULL) {
111 struct str_node *sn;
112 int rc;
113
114 parent = *p;
115 sn = rb_entry(parent, struct str_node, rb_node);
116 rc = strcmp(sn->s, entry);
117
118 if (rc > 0)
119 p = &(*p)->rb_left;
120 else if (rc < 0)
121 p = &(*p)->rb_right;
122 else
123 return true;
124 }
125
126 return false;
127}
128
129static int strlist__parse_list_entry(struct strlist *self, const char *s)
130{
131 if (strncmp(s, "file://", 7) == 0)
132 return strlist__load(self, s + 7);
133
134 return strlist__add(self, s);
135}
136
137int strlist__parse_list(struct strlist *self, const char *s)
138{
139 char *sep;
140 int err;
141
142 while ((sep = strchr(s, ',')) != NULL) {
143 *sep = '\0';
144 err = strlist__parse_list_entry(self, s);
145 *sep = ',';
146 if (err != 0)
147 return err;
148 s = sep + 1;
149 }
150
151 return *s ? strlist__parse_list_entry(self, s) : 0;
152}
153
154struct strlist *strlist__new(bool dupstr, const char *slist)
155{
156 struct strlist *self = malloc(sizeof(*self));
157
158 if (self != NULL) {
159 self->entries = RB_ROOT;
160 self->dupstr = dupstr;
161 self->nr_entries = 0;
162 if (slist && strlist__parse_list(self, slist) != 0)
163 goto out_error;
164 }
165
166 return self;
167out_error:
168 free(self);
169 return NULL;
170}
171
172void strlist__delete(struct strlist *self)
173{
174 if (self != NULL) {
175 struct str_node *pos;
176 struct rb_node *next = rb_first(&self->entries);
177
178 while (next) {
179 pos = rb_entry(next, struct str_node, rb_node);
180 next = rb_next(&pos->rb_node);
181 strlist__remove(self, pos);
182 }
183 self->entries = RB_ROOT;
184 free(self);
185 }
186}
187
188struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
189{
190 struct rb_node *nd;
191
192 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
193 struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
194
195 if (!idx--)
196 return pos;
197 }
198
199 return NULL;
200}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
new file mode 100644
index 000000000000..921818e44a54
--- /dev/null
+++ b/tools/perf/util/strlist.h
@@ -0,0 +1,39 @@
1#ifndef STRLIST_H_
2#define STRLIST_H_
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7struct str_node {
8 struct rb_node rb_node;
9 const char *s;
10};
11
12struct strlist {
13 struct rb_root entries;
14 unsigned int nr_entries;
15 bool dupstr;
16};
17
18struct strlist *strlist__new(bool dupstr, const char *slist);
19void strlist__delete(struct strlist *self);
20
21void strlist__remove(struct strlist *self, struct str_node *sn);
22int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str);
24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry);
27
28static inline bool strlist__empty(const struct strlist *self)
29{
30 return self->nr_entries == 0;
31}
32
33static inline unsigned int strlist__nr_entries(const struct strlist *self)
34{
35 return self->nr_entries;
36}
37
38int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
new file mode 100644
index 000000000000..5c0f42e6b33b
--- /dev/null
+++ b/tools/perf/util/symbol.c
@@ -0,0 +1,930 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "symbol.h"
5
6#include <libelf.h>
7#include <gelf.h>
8#include <elf.h>
9
10const char *sym_hist_filter;
11
12enum dso_origin {
13 DSO__ORIG_KERNEL = 0,
14 DSO__ORIG_JAVA_JIT,
15 DSO__ORIG_FEDORA,
16 DSO__ORIG_UBUNTU,
17 DSO__ORIG_BUILDID,
18 DSO__ORIG_DSO,
19 DSO__ORIG_NOT_FOUND,
20};
21
22static struct symbol *symbol__new(u64 start, u64 len,
23 const char *name, unsigned int priv_size,
24 u64 obj_start, int verbose)
25{
26 size_t namelen = strlen(name) + 1;
27 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
28
29 if (!self)
30 return NULL;
31
32 if (verbose >= 2)
33 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
34 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
35
36 self->obj_start= obj_start;
37 self->hist = NULL;
38 self->hist_sum = 0;
39
40 if (sym_hist_filter && !strcmp(name, sym_hist_filter))
41 self->hist = calloc(sizeof(u64), len);
42
43 if (priv_size) {
44 memset(self, 0, priv_size);
45 self = ((void *)self) + priv_size;
46 }
47 self->start = start;
48 self->end = len ? start + len - 1 : start;
49 memcpy(self->name, name, namelen);
50
51 return self;
52}
53
54static void symbol__delete(struct symbol *self, unsigned int priv_size)
55{
56 free(((void *)self) - priv_size);
57}
58
59static size_t symbol__fprintf(struct symbol *self, FILE *fp)
60{
61 if (!self->module)
62 return fprintf(fp, " %llx-%llx %s\n",
63 self->start, self->end, self->name);
64 else
65 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
66 self->start, self->end, self->name, self->module->name);
67}
68
69struct dso *dso__new(const char *name, unsigned int sym_priv_size)
70{
71 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
72
73 if (self != NULL) {
74 strcpy(self->name, name);
75 self->syms = RB_ROOT;
76 self->sym_priv_size = sym_priv_size;
77 self->find_symbol = dso__find_symbol;
78 self->slen_calculated = 0;
79 self->origin = DSO__ORIG_NOT_FOUND;
80 }
81
82 return self;
83}
84
85static void dso__delete_symbols(struct dso *self)
86{
87 struct symbol *pos;
88 struct rb_node *next = rb_first(&self->syms);
89
90 while (next) {
91 pos = rb_entry(next, struct symbol, rb_node);
92 next = rb_next(&pos->rb_node);
93 rb_erase(&pos->rb_node, &self->syms);
94 symbol__delete(pos, self->sym_priv_size);
95 }
96}
97
98void dso__delete(struct dso *self)
99{
100 dso__delete_symbols(self);
101 free(self);
102}
103
104static void dso__insert_symbol(struct dso *self, struct symbol *sym)
105{
106 struct rb_node **p = &self->syms.rb_node;
107 struct rb_node *parent = NULL;
108 const u64 ip = sym->start;
109 struct symbol *s;
110
111 while (*p != NULL) {
112 parent = *p;
113 s = rb_entry(parent, struct symbol, rb_node);
114 if (ip < s->start)
115 p = &(*p)->rb_left;
116 else
117 p = &(*p)->rb_right;
118 }
119 rb_link_node(&sym->rb_node, parent, p);
120 rb_insert_color(&sym->rb_node, &self->syms);
121}
122
123struct symbol *dso__find_symbol(struct dso *self, u64 ip)
124{
125 struct rb_node *n;
126
127 if (self == NULL)
128 return NULL;
129
130 n = self->syms.rb_node;
131
132 while (n) {
133 struct symbol *s = rb_entry(n, struct symbol, rb_node);
134
135 if (ip < s->start)
136 n = n->rb_left;
137 else if (ip > s->end)
138 n = n->rb_right;
139 else
140 return s;
141 }
142
143 return NULL;
144}
145
146size_t dso__fprintf(struct dso *self, FILE *fp)
147{
148 size_t ret = fprintf(fp, "dso: %s\n", self->name);
149
150 struct rb_node *nd;
151 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
152 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
153 ret += symbol__fprintf(pos, fp);
154 }
155
156 return ret;
157}
158
159static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
160{
161 struct rb_node *nd, *prevnd;
162 char *line = NULL;
163 size_t n;
164 FILE *file = fopen("/proc/kallsyms", "r");
165 int count = 0;
166
167 if (file == NULL)
168 goto out_failure;
169
170 while (!feof(file)) {
171 u64 start;
172 struct symbol *sym;
173 int line_len, len;
174 char symbol_type;
175
176 line_len = getline(&line, &n, file);
177 if (line_len < 0)
178 break;
179
180 if (!line)
181 goto out_failure;
182
183 line[--line_len] = '\0'; /* \n */
184
185 len = hex2u64(line, &start);
186
187 len++;
188 if (len + 2 >= line_len)
189 continue;
190
191 symbol_type = toupper(line[len]);
192 /*
193 * We're interested only in code ('T'ext)
194 */
195 if (symbol_type != 'T' && symbol_type != 'W')
196 continue;
197 /*
198 * Well fix up the end later, when we have all sorted.
199 */
200 sym = symbol__new(start, 0xdead, line + len + 2,
201 self->sym_priv_size, 0, verbose);
202
203 if (sym == NULL)
204 goto out_delete_line;
205
206 if (filter && filter(self, sym))
207 symbol__delete(sym, self->sym_priv_size);
208 else {
209 dso__insert_symbol(self, sym);
210 count++;
211 }
212 }
213
214 /*
215 * Now that we have all sorted out, just set the ->end of all
216 * symbols
217 */
218 prevnd = rb_first(&self->syms);
219
220 if (prevnd == NULL)
221 goto out_delete_line;
222
223 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
224 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
225 *curr = rb_entry(nd, struct symbol, rb_node);
226
227 prev->end = curr->start - 1;
228 prevnd = nd;
229 }
230
231 free(line);
232 fclose(file);
233
234 return count;
235
236out_delete_line:
237 free(line);
238out_failure:
239 return -1;
240}
241
242static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
243{
244 char *line = NULL;
245 size_t n;
246 FILE *file;
247 int nr_syms = 0;
248
249 file = fopen(self->name, "r");
250 if (file == NULL)
251 goto out_failure;
252
253 while (!feof(file)) {
254 u64 start, size;
255 struct symbol *sym;
256 int line_len, len;
257
258 line_len = getline(&line, &n, file);
259 if (line_len < 0)
260 break;
261
262 if (!line)
263 goto out_failure;
264
265 line[--line_len] = '\0'; /* \n */
266
267 len = hex2u64(line, &start);
268
269 len++;
270 if (len + 2 >= line_len)
271 continue;
272
273 len += hex2u64(line + len, &size);
274
275 len++;
276 if (len + 2 >= line_len)
277 continue;
278
279 sym = symbol__new(start, size, line + len,
280 self->sym_priv_size, start, verbose);
281
282 if (sym == NULL)
283 goto out_delete_line;
284
285 if (filter && filter(self, sym))
286 symbol__delete(sym, self->sym_priv_size);
287 else {
288 dso__insert_symbol(self, sym);
289 nr_syms++;
290 }
291 }
292
293 free(line);
294 fclose(file);
295
296 return nr_syms;
297
298out_delete_line:
299 free(line);
300out_failure:
301 return -1;
302}
303
304/**
305 * elf_symtab__for_each_symbol - iterate thru all the symbols
306 *
307 * @self: struct elf_symtab instance to iterate
308 * @index: uint32_t index
309 * @sym: GElf_Sym iterator
310 */
311#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
312 for (index = 0, gelf_getsym(syms, index, &sym);\
313 index < nr_syms; \
314 index++, gelf_getsym(syms, index, &sym))
315
316static inline uint8_t elf_sym__type(const GElf_Sym *sym)
317{
318 return GELF_ST_TYPE(sym->st_info);
319}
320
321static inline int elf_sym__is_function(const GElf_Sym *sym)
322{
323 return elf_sym__type(sym) == STT_FUNC &&
324 sym->st_name != 0 &&
325 sym->st_shndx != SHN_UNDEF &&
326 sym->st_size != 0;
327}
328
329static inline int elf_sym__is_label(const GElf_Sym *sym)
330{
331 return elf_sym__type(sym) == STT_NOTYPE &&
332 sym->st_name != 0 &&
333 sym->st_shndx != SHN_UNDEF &&
334 sym->st_shndx != SHN_ABS;
335}
336
337static inline const char *elf_sec__name(const GElf_Shdr *shdr,
338 const Elf_Data *secstrs)
339{
340 return secstrs->d_buf + shdr->sh_name;
341}
342
343static inline int elf_sec__is_text(const GElf_Shdr *shdr,
344 const Elf_Data *secstrs)
345{
346 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
347}
348
349static inline const char *elf_sym__name(const GElf_Sym *sym,
350 const Elf_Data *symstrs)
351{
352 return symstrs->d_buf + sym->st_name;
353}
354
355static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
356 GElf_Shdr *shp, const char *name,
357 size_t *index)
358{
359 Elf_Scn *sec = NULL;
360 size_t cnt = 1;
361
362 while ((sec = elf_nextscn(elf, sec)) != NULL) {
363 char *str;
364
365 gelf_getshdr(sec, shp);
366 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
367 if (!strcmp(name, str)) {
368 if (index)
369 *index = cnt;
370 break;
371 }
372 ++cnt;
373 }
374
375 return sec;
376}
377
378#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
379 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
380 idx < nr_entries; \
381 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
382
383#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
384 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
385 idx < nr_entries; \
386 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
387
388/*
389 * We need to check if we have a .dynsym, so that we can handle the
390 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
391 * .dynsym or .symtab).
392 * And always look at the original dso, not at debuginfo packages, that
393 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
394 */
395static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
396{
397 uint32_t nr_rel_entries, idx;
398 GElf_Sym sym;
399 u64 plt_offset;
400 GElf_Shdr shdr_plt;
401 struct symbol *f;
402 GElf_Shdr shdr_rel_plt, shdr_dynsym;
403 Elf_Data *reldata, *syms, *symstrs;
404 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
405 size_t dynsym_idx;
406 GElf_Ehdr ehdr;
407 char sympltname[1024];
408 Elf *elf;
409 int nr = 0, symidx, fd, err = 0;
410
411 fd = open(self->name, O_RDONLY);
412 if (fd < 0)
413 goto out;
414
415 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
416 if (elf == NULL)
417 goto out_close;
418
419 if (gelf_getehdr(elf, &ehdr) == NULL)
420 goto out_elf_end;
421
422 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
423 ".dynsym", &dynsym_idx);
424 if (scn_dynsym == NULL)
425 goto out_elf_end;
426
427 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
428 ".rela.plt", NULL);
429 if (scn_plt_rel == NULL) {
430 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
431 ".rel.plt", NULL);
432 if (scn_plt_rel == NULL)
433 goto out_elf_end;
434 }
435
436 err = -1;
437
438 if (shdr_rel_plt.sh_link != dynsym_idx)
439 goto out_elf_end;
440
441 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
442 goto out_elf_end;
443
444 /*
445 * Fetch the relocation section to find the indexes to the GOT
446 * and the symbols in the .dynsym they refer to.
447 */
448 reldata = elf_getdata(scn_plt_rel, NULL);
449 if (reldata == NULL)
450 goto out_elf_end;
451
452 syms = elf_getdata(scn_dynsym, NULL);
453 if (syms == NULL)
454 goto out_elf_end;
455
456 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
457 if (scn_symstrs == NULL)
458 goto out_elf_end;
459
460 symstrs = elf_getdata(scn_symstrs, NULL);
461 if (symstrs == NULL)
462 goto out_elf_end;
463
464 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
465 plt_offset = shdr_plt.sh_offset;
466
467 if (shdr_rel_plt.sh_type == SHT_RELA) {
468 GElf_Rela pos_mem, *pos;
469
470 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
471 nr_rel_entries) {
472 symidx = GELF_R_SYM(pos->r_info);
473 plt_offset += shdr_plt.sh_entsize;
474 gelf_getsym(syms, symidx, &sym);
475 snprintf(sympltname, sizeof(sympltname),
476 "%s@plt", elf_sym__name(&sym, symstrs));
477
478 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
479 sympltname, self->sym_priv_size, 0, verbose);
480 if (!f)
481 goto out_elf_end;
482
483 dso__insert_symbol(self, f);
484 ++nr;
485 }
486 } else if (shdr_rel_plt.sh_type == SHT_REL) {
487 GElf_Rel pos_mem, *pos;
488 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
489 nr_rel_entries) {
490 symidx = GELF_R_SYM(pos->r_info);
491 plt_offset += shdr_plt.sh_entsize;
492 gelf_getsym(syms, symidx, &sym);
493 snprintf(sympltname, sizeof(sympltname),
494 "%s@plt", elf_sym__name(&sym, symstrs));
495
496 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
497 sympltname, self->sym_priv_size, 0, verbose);
498 if (!f)
499 goto out_elf_end;
500
501 dso__insert_symbol(self, f);
502 ++nr;
503 }
504 }
505
506 err = 0;
507out_elf_end:
508 elf_end(elf);
509out_close:
510 close(fd);
511
512 if (err == 0)
513 return nr;
514out:
515 fprintf(stderr, "%s: problems reading %s PLT info.\n",
516 __func__, self->name);
517 return 0;
518}
519
520static int dso__load_sym(struct dso *self, int fd, const char *name,
521 symbol_filter_t filter, int verbose, struct module *mod)
522{
523 Elf_Data *symstrs, *secstrs;
524 uint32_t nr_syms;
525 int err = -1;
526 uint32_t index;
527 GElf_Ehdr ehdr;
528 GElf_Shdr shdr;
529 Elf_Data *syms;
530 GElf_Sym sym;
531 Elf_Scn *sec, *sec_strndx;
532 Elf *elf;
533 int nr = 0, kernel = !strcmp("[kernel]", self->name);
534
535 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
536 if (elf == NULL) {
537 if (verbose)
538 fprintf(stderr, "%s: cannot read %s ELF file.\n",
539 __func__, name);
540 goto out_close;
541 }
542
543 if (gelf_getehdr(elf, &ehdr) == NULL) {
544 if (verbose)
545 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
546 goto out_elf_end;
547 }
548
549 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
550 if (sec == NULL) {
551 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
552 if (sec == NULL)
553 goto out_elf_end;
554 }
555
556 syms = elf_getdata(sec, NULL);
557 if (syms == NULL)
558 goto out_elf_end;
559
560 sec = elf_getscn(elf, shdr.sh_link);
561 if (sec == NULL)
562 goto out_elf_end;
563
564 symstrs = elf_getdata(sec, NULL);
565 if (symstrs == NULL)
566 goto out_elf_end;
567
568 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
569 if (sec_strndx == NULL)
570 goto out_elf_end;
571
572 secstrs = elf_getdata(sec_strndx, NULL);
573 if (secstrs == NULL)
574 goto out_elf_end;
575
576 nr_syms = shdr.sh_size / shdr.sh_entsize;
577
578 memset(&sym, 0, sizeof(sym));
579 if (!kernel) {
580 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
581 elf_section_by_name(elf, &ehdr, &shdr,
582 ".gnu.prelink_undo",
583 NULL) != NULL);
584 } else self->adjust_symbols = 0;
585
586 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
587 struct symbol *f;
588 const char *name;
589 char *demangled;
590 u64 obj_start;
591 struct section *section = NULL;
592 int is_label = elf_sym__is_label(&sym);
593 const char *section_name;
594
595 if (!is_label && !elf_sym__is_function(&sym))
596 continue;
597
598 sec = elf_getscn(elf, sym.st_shndx);
599 if (!sec)
600 goto out_elf_end;
601
602 gelf_getshdr(sec, &shdr);
603
604 if (is_label && !elf_sec__is_text(&shdr, secstrs))
605 continue;
606
607 section_name = elf_sec__name(&shdr, secstrs);
608 obj_start = sym.st_value;
609
610 if (self->adjust_symbols) {
611 if (verbose >= 2)
612 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
613 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
614
615 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
616 }
617
618 if (mod) {
619 section = mod->sections->find_section(mod->sections, section_name);
620 if (section)
621 sym.st_value += section->vma;
622 else {
623 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
624 mod->name, section_name);
625 goto out_elf_end;
626 }
627 }
628 /*
629 * We need to figure out if the object was created from C++ sources
630 * DWARF DW_compile_unit has this, but we don't always have access
631 * to it...
632 */
633 name = elf_sym__name(&sym, symstrs);
634 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
635 if (demangled != NULL)
636 name = demangled;
637
638 f = symbol__new(sym.st_value, sym.st_size, name,
639 self->sym_priv_size, obj_start, verbose);
640 free(demangled);
641 if (!f)
642 goto out_elf_end;
643
644 if (filter && filter(self, f))
645 symbol__delete(f, self->sym_priv_size);
646 else {
647 f->module = mod;
648 dso__insert_symbol(self, f);
649 nr++;
650 }
651 }
652
653 err = nr;
654out_elf_end:
655 elf_end(elf);
656out_close:
657 return err;
658}
659
660#define BUILD_ID_SIZE 128
661
662static char *dso__read_build_id(struct dso *self, int verbose)
663{
664 int i;
665 GElf_Ehdr ehdr;
666 GElf_Shdr shdr;
667 Elf_Data *build_id_data;
668 Elf_Scn *sec;
669 char *build_id = NULL, *bid;
670 unsigned char *raw;
671 Elf *elf;
672 int fd = open(self->name, O_RDONLY);
673
674 if (fd < 0)
675 goto out;
676
677 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
678 if (elf == NULL) {
679 if (verbose)
680 fprintf(stderr, "%s: cannot read %s ELF file.\n",
681 __func__, self->name);
682 goto out_close;
683 }
684
685 if (gelf_getehdr(elf, &ehdr) == NULL) {
686 if (verbose)
687 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
688 goto out_elf_end;
689 }
690
691 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
692 if (sec == NULL)
693 goto out_elf_end;
694
695 build_id_data = elf_getdata(sec, NULL);
696 if (build_id_data == NULL)
697 goto out_elf_end;
698 build_id = malloc(BUILD_ID_SIZE);
699 if (build_id == NULL)
700 goto out_elf_end;
701 raw = build_id_data->d_buf + 16;
702 bid = build_id;
703
704 for (i = 0; i < 20; ++i) {
705 sprintf(bid, "%02x", *raw);
706 ++raw;
707 bid += 2;
708 }
709 if (verbose >= 2)
710 printf("%s(%s): %s\n", __func__, self->name, build_id);
711out_elf_end:
712 elf_end(elf);
713out_close:
714 close(fd);
715out:
716 return build_id;
717}
718
719char dso__symtab_origin(const struct dso *self)
720{
721 static const char origin[] = {
722 [DSO__ORIG_KERNEL] = 'k',
723 [DSO__ORIG_JAVA_JIT] = 'j',
724 [DSO__ORIG_FEDORA] = 'f',
725 [DSO__ORIG_UBUNTU] = 'u',
726 [DSO__ORIG_BUILDID] = 'b',
727 [DSO__ORIG_DSO] = 'd',
728 };
729
730 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
731 return '!';
732 return origin[self->origin];
733}
734
735int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
736{
737 int size = PATH_MAX;
738 char *name = malloc(size), *build_id = NULL;
739 int ret = -1;
740 int fd;
741
742 if (!name)
743 return -1;
744
745 self->adjust_symbols = 0;
746
747 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
748 ret = dso__load_perf_map(self, filter, verbose);
749 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
750 DSO__ORIG_NOT_FOUND;
751 return ret;
752 }
753
754 self->origin = DSO__ORIG_FEDORA - 1;
755
756more:
757 do {
758 self->origin++;
759 switch (self->origin) {
760 case DSO__ORIG_FEDORA:
761 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
762 break;
763 case DSO__ORIG_UBUNTU:
764 snprintf(name, size, "/usr/lib/debug%s", self->name);
765 break;
766 case DSO__ORIG_BUILDID:
767 build_id = dso__read_build_id(self, verbose);
768 if (build_id != NULL) {
769 snprintf(name, size,
770 "/usr/lib/debug/.build-id/%.2s/%s.debug",
771 build_id, build_id + 2);
772 free(build_id);
773 break;
774 }
775 self->origin++;
776 /* Fall thru */
777 case DSO__ORIG_DSO:
778 snprintf(name, size, "%s", self->name);
779 break;
780
781 default:
782 goto out;
783 }
784
785 fd = open(name, O_RDONLY);
786 } while (fd < 0);
787
788 ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
789 close(fd);
790
791 /*
792 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
793 */
794 if (!ret)
795 goto more;
796
797 if (ret > 0) {
798 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
799 if (nr_plt > 0)
800 ret += nr_plt;
801 }
802out:
803 free(name);
804 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
805 return 0;
806 return ret;
807}
808
809static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
810 symbol_filter_t filter, int verbose)
811{
812 struct module *mod = mod_dso__find_module(mods, name);
813 int err = 0, fd;
814
815 if (mod == NULL || !mod->active)
816 return err;
817
818 fd = open(mod->path, O_RDONLY);
819
820 if (fd < 0)
821 return err;
822
823 err = dso__load_sym(self, fd, name, filter, verbose, mod);
824 close(fd);
825
826 return err;
827}
828
829int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
830{
831 struct mod_dso *mods = mod_dso__new_dso("modules");
832 struct module *pos;
833 struct rb_node *next;
834 int err;
835
836 err = mod_dso__load_modules(mods);
837
838 if (err <= 0)
839 return err;
840
841 /*
842 * Iterate over modules, and load active symbols.
843 */
844 next = rb_first(&mods->mods);
845 while (next) {
846 pos = rb_entry(next, struct module, rb_node);
847 err = dso__load_module(self, mods, pos->name, filter, verbose);
848
849 if (err < 0)
850 break;
851
852 next = rb_next(&pos->rb_node);
853 }
854
855 if (err < 0) {
856 mod_dso__delete_modules(mods);
857 mod_dso__delete_self(mods);
858 }
859
860 return err;
861}
862
863static inline void dso__fill_symbol_holes(struct dso *self)
864{
865 struct symbol *prev = NULL;
866 struct rb_node *nd;
867
868 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
869 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
870
871 if (prev) {
872 u64 hole = 0;
873 int alias = pos->start == prev->start;
874
875 if (!alias)
876 hole = prev->start - pos->end - 1;
877
878 if (hole || alias) {
879 if (alias)
880 pos->end = prev->end;
881 else if (hole)
882 pos->end = prev->start - 1;
883 }
884 }
885 prev = pos;
886 }
887}
888
889static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
890 symbol_filter_t filter, int verbose)
891{
892 int err, fd = open(vmlinux, O_RDONLY);
893
894 if (fd < 0)
895 return -1;
896
897 err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
898
899 if (err > 0)
900 dso__fill_symbol_holes(self);
901
902 close(fd);
903
904 return err;
905}
906
907int dso__load_kernel(struct dso *self, const char *vmlinux,
908 symbol_filter_t filter, int verbose, int modules)
909{
910 int err = -1;
911
912 if (vmlinux) {
913 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
914 if (err > 0 && modules)
915 err = dso__load_modules(self, filter, verbose);
916 }
917
918 if (err <= 0)
919 err = dso__load_kallsyms(self, filter, verbose);
920
921 if (err > 0)
922 self->origin = DSO__ORIG_KERNEL;
923
924 return err;
925}
926
927void symbol__init(void)
928{
929 elf_version(EV_CURRENT);
930}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
new file mode 100644
index 000000000000..b53bf0125c1b
--- /dev/null
+++ b/tools/perf/util/symbol.h
@@ -0,0 +1,80 @@
1#ifndef _PERF_SYMBOL_
2#define _PERF_SYMBOL_ 1
3
4#include <linux/types.h>
5#include "types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8#include "module.h"
9
10#ifdef HAVE_CPLUS_DEMANGLE
11extern char *cplus_demangle(const char *, int);
12
13static inline char *bfd_demangle(void __used *v, const char *c, int i)
14{
15 return cplus_demangle(c, i);
16}
17#else
18#ifdef NO_DEMANGLE
19static inline char *bfd_demangle(void __used *v, const char __used *c,
20 int __used i)
21{
22 return NULL;
23}
24#else
25#include <bfd.h>
26#endif
27#endif
28
29#ifndef DMGL_PARAMS
30#define DMGL_PARAMS (1 << 0) /* Include function args */
31#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
32#endif
33
34struct symbol {
35 struct rb_node rb_node;
36 u64 start;
37 u64 end;
38 u64 obj_start;
39 u64 hist_sum;
40 u64 *hist;
41 struct module *module;
42 void *priv;
43 char name[0];
44};
45
46struct dso {
47 struct list_head node;
48 struct rb_root syms;
49 struct symbol *(*find_symbol)(struct dso *, u64 ip);
50 unsigned int sym_priv_size;
51 unsigned char adjust_symbols;
52 unsigned char slen_calculated;
53 unsigned char origin;
54 char name[0];
55};
56
57const char *sym_hist_filter;
58
59typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
60
61struct dso *dso__new(const char *name, unsigned int sym_priv_size);
62void dso__delete(struct dso *self);
63
64static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
65{
66 return ((void *)sym) - self->sym_priv_size;
67}
68
69struct symbol *dso__find_symbol(struct dso *self, u64 ip);
70
71int dso__load_kernel(struct dso *self, const char *vmlinux,
72 symbol_filter_t filter, int verbose, int modules);
73int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
74int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
75
76size_t dso__fprintf(struct dso *self, FILE *fp);
77char dso__symtab_origin(const struct dso *self);
78
79void symbol__init(void);
80#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
new file mode 100644
index 000000000000..5e75f9005940
--- /dev/null
+++ b/tools/perf/util/types.h
@@ -0,0 +1,17 @@
1#ifndef _PERF_TYPES_H
2#define _PERF_TYPES_H
3
4/*
5 * We define u64 as unsigned long long for every architecture
6 * so that we can print it with %Lx without getting warnings.
7 */
8typedef unsigned long long u64;
9typedef signed long long s64;
10typedef unsigned int u32;
11typedef signed int s32;
12typedef unsigned short u16;
13typedef signed short s16;
14typedef unsigned char u8;
15typedef signed char s8;
16
17#endif /* _PERF_TYPES_H */
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
new file mode 100644
index 000000000000..e16bf9a707e8
--- /dev/null
+++ b/tools/perf/util/usage.c
@@ -0,0 +1,80 @@
1/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6#include "util.h"
7
8static void report(const char *prefix, const char *err, va_list params)
9{
10 char msg[1024];
11 vsnprintf(msg, sizeof(msg), err, params);
12 fprintf(stderr, " %s%s\n", prefix, msg);
13}
14
15static NORETURN void usage_builtin(const char *err)
16{
17 fprintf(stderr, "\n Usage: %s\n", err);
18 exit(129);
19}
20
21static NORETURN void die_builtin(const char *err, va_list params)
22{
23 report(" Fatal: ", err, params);
24 exit(128);
25}
26
27static void error_builtin(const char *err, va_list params)
28{
29 report(" Error: ", err, params);
30}
31
32static void warn_builtin(const char *warn, va_list params)
33{
34 report(" Warning: ", warn, params);
35}
36
37/* If we are in a dlopen()ed .so write to a global variable would segfault
38 * (ugh), so keep things static. */
39static void (*usage_routine)(const char *err) NORETURN = usage_builtin;
40static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin;
41static void (*error_routine)(const char *err, va_list params) = error_builtin;
42static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
43
44void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN)
45{
46 die_routine = routine;
47}
48
49void usage(const char *err)
50{
51 usage_routine(err);
52}
53
54void die(const char *err, ...)
55{
56 va_list params;
57
58 va_start(params, err);
59 die_routine(err, params);
60 va_end(params);
61}
62
63int error(const char *err, ...)
64{
65 va_list params;
66
67 va_start(params, err);
68 error_routine(err, params);
69 va_end(params);
70 return -1;
71}
72
73void warning(const char *warn, ...)
74{
75 va_list params;
76
77 va_start(params, warn);
78 warn_routine(warn, params);
79 va_end(params);
80}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
new file mode 100644
index 000000000000..68fe157d72fb
--- /dev/null
+++ b/tools/perf/util/util.h
@@ -0,0 +1,395 @@
1#ifndef GIT_COMPAT_UTIL_H
2#define GIT_COMPAT_UTIL_H
3
4#define _FILE_OFFSET_BITS 64
5
6#ifndef FLEX_ARRAY
7/*
8 * See if our compiler is known to support flexible array members.
9 */
10#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
11# define FLEX_ARRAY /* empty */
12#elif defined(__GNUC__)
13# if (__GNUC__ >= 3)
14# define FLEX_ARRAY /* empty */
15# else
16# define FLEX_ARRAY 0 /* older GNU extension */
17# endif
18#endif
19
20/*
21 * Otherwise, default to safer but a bit wasteful traditional style
22 */
23#ifndef FLEX_ARRAY
24# define FLEX_ARRAY 1
25#endif
26#endif
27
28#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
29
30#ifdef __GNUC__
31#define TYPEOF(x) (__typeof__(x))
32#else
33#define TYPEOF(x)
34#endif
35
36#define MSB(x, bits) ((x) & TYPEOF(x)(~0ULL << (sizeof(x) * 8 - (bits))))
37#define HAS_MULTI_BITS(i) ((i) & ((i) - 1)) /* checks if an integer has more than 1 bit set */
38
39/* Approximation of the length of the decimal representation of this type. */
40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
41
42#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
43#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
44#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
45#endif
46#define _ALL_SOURCE 1
47#define _GNU_SOURCE 1
48#define _BSD_SOURCE 1
49
50#include <unistd.h>
51#include <stdio.h>
52#include <sys/stat.h>
53#include <sys/statfs.h>
54#include <fcntl.h>
55#include <stddef.h>
56#include <stdlib.h>
57#include <stdarg.h>
58#include <string.h>
59#include <errno.h>
60#include <limits.h>
61#include <sys/param.h>
62#include <sys/types.h>
63#include <dirent.h>
64#include <sys/time.h>
65#include <time.h>
66#include <signal.h>
67#include <fnmatch.h>
68#include <assert.h>
69#include <regex.h>
70#include <utime.h>
71#include <sys/wait.h>
72#include <sys/poll.h>
73#include <sys/socket.h>
74#include <sys/ioctl.h>
75#ifndef NO_SYS_SELECT_H
76#include <sys/select.h>
77#endif
78#include <netinet/in.h>
79#include <netinet/tcp.h>
80#include <arpa/inet.h>
81#include <netdb.h>
82#include <pwd.h>
83#include <inttypes.h>
84#include "../../../include/linux/magic.h"
85
86#ifndef NO_ICONV
87#include <iconv.h>
88#endif
89
90/* On most systems <limits.h> would have given us this, but
91 * not on some systems (e.g. GNU/Hurd).
92 */
93#ifndef PATH_MAX
94#define PATH_MAX 4096
95#endif
96
97#ifndef PRIuMAX
98#define PRIuMAX "llu"
99#endif
100
101#ifndef PRIu32
102#define PRIu32 "u"
103#endif
104
105#ifndef PRIx32
106#define PRIx32 "x"
107#endif
108
109#ifndef PATH_SEP
110#define PATH_SEP ':'
111#endif
112
113#ifndef STRIP_EXTENSION
114#define STRIP_EXTENSION ""
115#endif
116
117#ifndef has_dos_drive_prefix
118#define has_dos_drive_prefix(path) 0
119#endif
120
121#ifndef is_dir_sep
122#define is_dir_sep(c) ((c) == '/')
123#endif
124
125#ifdef __GNUC__
126#define NORETURN __attribute__((__noreturn__))
127#else
128#define NORETURN
129#ifndef __attribute__
130#define __attribute__(x)
131#endif
132#endif
133
134/* General helper functions */
135extern void usage(const char *err) NORETURN;
136extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
137extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
138extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
139
140extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
141
142extern int prefixcmp(const char *str, const char *prefix);
143extern time_t tm_to_time_t(const struct tm *tm);
144
145static inline const char *skip_prefix(const char *str, const char *prefix)
146{
147 size_t len = strlen(prefix);
148 return strncmp(str, prefix, len) ? NULL : str + len;
149}
150
151#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
152
153#ifndef PROT_READ
154#define PROT_READ 1
155#define PROT_WRITE 2
156#define MAP_PRIVATE 1
157#define MAP_FAILED ((void*)-1)
158#endif
159
160#define mmap git_mmap
161#define munmap git_munmap
162extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
163extern int git_munmap(void *start, size_t length);
164
165#else /* NO_MMAP || USE_WIN32_MMAP */
166
167#include <sys/mman.h>
168
169#endif /* NO_MMAP || USE_WIN32_MMAP */
170
171#ifdef NO_MMAP
172
173/* This value must be multiple of (pagesize * 2) */
174#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
175
176#else /* NO_MMAP */
177
178/* This value must be multiple of (pagesize * 2) */
179#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
180 (sizeof(void*) >= 8 \
181 ? 1 * 1024 * 1024 * 1024 \
182 : 32 * 1024 * 1024)
183
184#endif /* NO_MMAP */
185
186#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
187#define on_disk_bytes(st) ((st).st_size)
188#else
189#define on_disk_bytes(st) ((st).st_blocks * 512)
190#endif
191
192#define DEFAULT_PACKED_GIT_LIMIT \
193 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
194
195#ifdef NO_PREAD
196#define pread git_pread
197extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
198#endif
199/*
200 * Forward decl that will remind us if its twin in cache.h changes.
201 * This function is used in compat/pread.c. But we can't include
202 * cache.h there.
203 */
204extern ssize_t read_in_full(int fd, void *buf, size_t count);
205
206#ifdef NO_SETENV
207#define setenv gitsetenv
208extern int gitsetenv(const char *, const char *, int);
209#endif
210
211#ifdef NO_MKDTEMP
212#define mkdtemp gitmkdtemp
213extern char *gitmkdtemp(char *);
214#endif
215
216#ifdef NO_UNSETENV
217#define unsetenv gitunsetenv
218extern void gitunsetenv(const char *);
219#endif
220
221#ifdef NO_STRCASESTR
222#define strcasestr gitstrcasestr
223extern char *gitstrcasestr(const char *haystack, const char *needle);
224#endif
225
226#ifdef NO_STRLCPY
227#define strlcpy gitstrlcpy
228extern size_t gitstrlcpy(char *, const char *, size_t);
229#endif
230
231#ifdef NO_STRTOUMAX
232#define strtoumax gitstrtoumax
233extern uintmax_t gitstrtoumax(const char *, char **, int);
234#endif
235
236#ifdef NO_HSTRERROR
237#define hstrerror githstrerror
238extern const char *githstrerror(int herror);
239#endif
240
241#ifdef NO_MEMMEM
242#define memmem gitmemmem
243void *gitmemmem(const void *haystack, size_t haystacklen,
244 const void *needle, size_t needlelen);
245#endif
246
247#ifdef FREAD_READS_DIRECTORIES
248#ifdef fopen
249#undef fopen
250#endif
251#define fopen(a,b) git_fopen(a,b)
252extern FILE *git_fopen(const char*, const char*);
253#endif
254
255#ifdef SNPRINTF_RETURNS_BOGUS
256#define snprintf git_snprintf
257extern int git_snprintf(char *str, size_t maxsize,
258 const char *format, ...);
259#define vsnprintf git_vsnprintf
260extern int git_vsnprintf(char *str, size_t maxsize,
261 const char *format, va_list ap);
262#endif
263
264#ifdef __GLIBC_PREREQ
265#if __GLIBC_PREREQ(2, 1)
266#define HAVE_STRCHRNUL
267#endif
268#endif
269
270#ifndef HAVE_STRCHRNUL
271#define strchrnul gitstrchrnul
272static inline char *gitstrchrnul(const char *s, int c)
273{
274 while (*s && *s != c)
275 s++;
276 return (char *)s;
277}
278#endif
279
280/*
281 * Wrappers:
282 */
283extern char *xstrdup(const char *str);
284extern void *xmalloc(size_t size);
285extern void *xmemdupz(const void *data, size_t len);
286extern char *xstrndup(const char *str, size_t len);
287extern void *xrealloc(void *ptr, size_t size);
288extern void *xcalloc(size_t nmemb, size_t size);
289extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
290extern ssize_t xread(int fd, void *buf, size_t len);
291extern ssize_t xwrite(int fd, const void *buf, size_t len);
292extern int xdup(int fd);
293extern FILE *xfdopen(int fd, const char *mode);
294extern int xmkstemp(char *template);
295
296static inline size_t xsize_t(off_t len)
297{
298 return (size_t)len;
299}
300
301static inline int has_extension(const char *filename, const char *ext)
302{
303 size_t len = strlen(filename);
304 size_t extlen = strlen(ext);
305 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
306}
307
308/* Sane ctype - no locale, and works with signed chars */
309#undef isascii
310#undef isspace
311#undef isdigit
312#undef isalpha
313#undef isalnum
314#undef tolower
315#undef toupper
316extern unsigned char sane_ctype[256];
317#define GIT_SPACE 0x01
318#define GIT_DIGIT 0x02
319#define GIT_ALPHA 0x04
320#define GIT_GLOB_SPECIAL 0x08
321#define GIT_REGEX_SPECIAL 0x10
322#define GIT_PRINT_EXTRA 0x20
323#define GIT_PRINT 0x3E
324#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
325#define isascii(x) (((x) & ~0x7f) == 0)
326#define isspace(x) sane_istest(x,GIT_SPACE)
327#define isdigit(x) sane_istest(x,GIT_DIGIT)
328#define isalpha(x) sane_istest(x,GIT_ALPHA)
329#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
330#define isprint(x) sane_istest(x,GIT_PRINT)
331#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
332#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
333#define tolower(x) sane_case((unsigned char)(x), 0x20)
334#define toupper(x) sane_case((unsigned char)(x), 0)
335
336static inline int sane_case(int x, int high)
337{
338 if (sane_istest(x, GIT_ALPHA))
339 x = (x & ~0x20) | high;
340 return x;
341}
342
343static inline int strtoul_ui(char const *s, int base, unsigned int *result)
344{
345 unsigned long ul;
346 char *p;
347
348 errno = 0;
349 ul = strtoul(s, &p, base);
350 if (errno || *p || p == s || (unsigned int) ul != ul)
351 return -1;
352 *result = ul;
353 return 0;
354}
355
356static inline int strtol_i(char const *s, int base, int *result)
357{
358 long ul;
359 char *p;
360
361 errno = 0;
362 ul = strtol(s, &p, base);
363 if (errno || *p || p == s || (int) ul != ul)
364 return -1;
365 *result = ul;
366 return 0;
367}
368
369#ifdef INTERNAL_QSORT
370void git_qsort(void *base, size_t nmemb, size_t size,
371 int(*compar)(const void *, const void *));
372#define qsort git_qsort
373#endif
374
375#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
376# define FORCE_DIR_SET_GID S_ISGID
377#else
378# define FORCE_DIR_SET_GID 0
379#endif
380
381#ifdef NO_NSEC
382#undef USE_NSEC
383#define ST_CTIME_NSEC(st) 0
384#define ST_MTIME_NSEC(st) 0
385#else
386#ifdef USE_ST_TIMESPEC
387#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
388#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
389#else
390#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
391#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
392#endif
393#endif
394
395#endif
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
new file mode 100644
index 000000000000..4574ac28396f
--- /dev/null
+++ b/tools/perf/util/wrapper.c
@@ -0,0 +1,207 @@
1/*
2 * Various trivial helper wrappers around standard functions
3 */
4#include "cache.h"
5
6/*
7 * There's no pack memory to release - but stay close to the Git
8 * version so wrap this away:
9 */
10static inline void release_pack_memory(size_t size __used, int flag __used)
11{
12}
13
14char *xstrdup(const char *str)
15{
16 char *ret = strdup(str);
17 if (!ret) {
18 release_pack_memory(strlen(str) + 1, -1);
19 ret = strdup(str);
20 if (!ret)
21 die("Out of memory, strdup failed");
22 }
23 return ret;
24}
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)
67{
68 void *ret = realloc(ptr, size);
69 if (!ret && !size)
70 ret = realloc(ptr, 1);
71 if (!ret) {
72 release_pack_memory(size, -1);
73 ret = realloc(ptr, size);
74 if (!ret && !size)
75 ret = realloc(ptr, 1);
76 if (!ret)
77 die("Out of memory, realloc failed");
78 }
79 return ret;
80}
81
82void *xcalloc(size_t nmemb, size_t size)
83{
84 void *ret = calloc(nmemb, size);
85 if (!ret && (!nmemb || !size))
86 ret = calloc(1, 1);
87 if (!ret) {
88 release_pack_memory(nmemb * size, -1);
89 ret = calloc(nmemb, size);
90 if (!ret && (!nmemb || !size))
91 ret = calloc(1, 1);
92 if (!ret)
93 die("Out of memory, calloc failed");
94 }
95 return ret;
96}
97
98void *xmmap(void *start, size_t length,
99 int prot, int flags, int fd, off_t offset)
100{
101 void *ret = mmap(start, length, prot, flags, fd, offset);
102 if (ret == MAP_FAILED) {
103 if (!length)
104 return NULL;
105 release_pack_memory(length, fd);
106 ret = mmap(start, length, prot, flags, fd, offset);
107 if (ret == MAP_FAILED)
108 die("Out of memory? mmap failed: %s", strerror(errno));
109 }
110 return ret;
111}
112
113/*
114 * xread() is the same a read(), but it automatically restarts read()
115 * operations with a recoverable error (EAGAIN and EINTR). xread()
116 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
117 */
118ssize_t xread(int fd, void *buf, size_t len)
119{
120 ssize_t nr;
121 while (1) {
122 nr = read(fd, buf, len);
123 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
124 continue;
125 return nr;
126 }
127}
128
129/*
130 * xwrite() is the same a write(), but it automatically restarts write()
131 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
132 * GUARANTEE that "len" bytes is written even if the operation is successful.
133 */
134ssize_t xwrite(int fd, const void *buf, size_t len)
135{
136 ssize_t nr;
137 while (1) {
138 nr = write(fd, buf, len);
139 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
140 continue;
141 return nr;
142 }
143}
144
145ssize_t read_in_full(int fd, void *buf, size_t count)
146{
147 char *p = buf;
148 ssize_t total = 0;
149
150 while (count > 0) {
151 ssize_t loaded = xread(fd, p, count);
152 if (loaded <= 0)
153 return total ? total : loaded;
154 count -= loaded;
155 p += loaded;
156 total += loaded;
157 }
158
159 return total;
160}
161
162ssize_t write_in_full(int fd, const void *buf, size_t count)
163{
164 const char *p = buf;
165 ssize_t total = 0;
166
167 while (count > 0) {
168 ssize_t written = xwrite(fd, p, count);
169 if (written < 0)
170 return -1;
171 if (!written) {
172 errno = ENOSPC;
173 return -1;
174 }
175 count -= written;
176 p += written;
177 total += written;
178 }
179
180 return total;
181}
182
183int xdup(int fd)
184{
185 int ret = dup(fd);
186 if (ret < 0)
187 die("dup failed: %s", strerror(errno));
188 return ret;
189}
190
191FILE *xfdopen(int fd, const char *mode)
192{
193 FILE *stream = fdopen(fd, mode);
194 if (stream == NULL)
195 die("Out of memory? fdopen failed: %s", strerror(errno));
196 return stream;
197}
198
199int xmkstemp(char *template)
200{
201 int fd;
202
203 fd = mkstemp(template);
204 if (fd < 0)
205 die("Unable to create temporary file: %s", strerror(errno));
206 return fd;
207}