aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
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.h119
-rw-r--r--tools/perf/util/color.c241
-rw-r--r--tools/perf/util/color.h36
-rw-r--r--tools/perf/util/config.c873
-rw-r--r--tools/perf/util/ctype.c26
-rw-r--r--tools/perf/util/environment.c9
-rw-r--r--tools/perf/util/exec_cmd.c165
-rw-r--r--tools/perf/util/exec_cmd.h13
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh24
-rw-r--r--tools/perf/util/help.c367
-rw-r--r--tools/perf/util/help.h29
-rw-r--r--tools/perf/util/levenshtein.c84
-rw-r--r--tools/perf/util/levenshtein.h8
-rw-r--r--tools/perf/util/list.h603
-rw-r--r--tools/perf/util/pager.c99
-rw-r--r--tools/perf/util/parse-events.c316
-rw-r--r--tools/perf/util/parse-events.h17
-rw-r--r--tools/perf/util/parse-options.c508
-rw-r--r--tools/perf/util/parse-options.h174
-rw-r--r--tools/perf/util/path.c353
-rw-r--r--tools/perf/util/quote.c481
-rw-r--r--tools/perf/util/quote.h68
-rw-r--r--tools/perf/util/rbtree.c383
-rw-r--r--tools/perf/util/rbtree.h171
-rw-r--r--tools/perf/util/run-command.c395
-rw-r--r--tools/perf/util/run-command.h93
-rw-r--r--tools/perf/util/sigchain.c52
-rw-r--r--tools/perf/util/sigchain.h11
-rw-r--r--tools/perf/util/strbuf.c359
-rw-r--r--tools/perf/util/strbuf.h137
-rw-r--r--tools/perf/util/string.c34
-rw-r--r--tools/perf/util/string.h8
-rw-r--r--tools/perf/util/symbol.c641
-rw-r--r--tools/perf/util/symbol.h47
-rw-r--r--tools/perf/util/usage.c80
-rw-r--r--tools/perf/util/util.h410
-rw-r--r--tools/perf/util/wrapper.c206
40 files changed, 7876 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..9b3dd2b428df
--- /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)
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..393d6146d13b
--- /dev/null
+++ b/tools/perf/util/cache.h
@@ -0,0 +1,119 @@
1#ifndef CACHE_H
2#define CACHE_H
3
4#include "util.h"
5#include "strbuf.h"
6
7#define PERF_DIR_ENVIRONMENT "PERF_DIR"
8#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
9#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
10#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY"
11#define INDEX_ENVIRONMENT "PERF_INDEX_FILE"
12#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE"
13#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR"
14#define CONFIG_ENVIRONMENT "PERF_CONFIG"
15#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
16#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES"
17#define PERFATTRIBUTES_FILE ".perfattributes"
18#define INFOATTRIBUTES_FILE "info/attributes"
19#define ATTRIBUTE_MACRO_PREFIX "[attr]"
20
21typedef int (*config_fn_t)(const char *, const char *, void *);
22extern int perf_default_config(const char *, const char *, void *);
23extern int perf_config_from_file(config_fn_t fn, const char *, void *);
24extern int perf_config(config_fn_t fn, void *);
25extern int perf_parse_ulong(const char *, unsigned long *);
26extern int perf_config_int(const char *, const char *);
27extern unsigned long perf_config_ulong(const char *, const char *);
28extern int perf_config_bool_or_int(const char *, const char *, int *);
29extern int perf_config_bool(const char *, const char *);
30extern int perf_config_string(const char **, const char *, const char *);
31extern int perf_config_set(const char *, const char *);
32extern int perf_config_set_multivar(const char *, const char *, const char *, int);
33extern int perf_config_rename_section(const char *, const char *);
34extern const char *perf_etc_perfconfig(void);
35extern int check_repository_format_version(const char *var, const char *value, void *cb);
36extern int perf_config_system(void);
37extern int perf_config_global(void);
38extern int config_error_nonbool(const char *);
39extern const char *config_exclusive_filename;
40
41#define MAX_PERFNAME (1000)
42extern char perf_default_email[MAX_PERFNAME];
43extern char perf_default_name[MAX_PERFNAME];
44extern int user_ident_explicitly_given;
45
46extern const char *perf_log_output_encoding;
47extern const char *perf_mailmap_file;
48
49/* IO helper functions */
50extern void maybe_flush_or_die(FILE *, const char *);
51extern int copy_fd(int ifd, int ofd);
52extern int copy_file(const char *dst, const char *src, int mode);
53extern ssize_t read_in_full(int fd, void *buf, size_t count);
54extern ssize_t write_in_full(int fd, const void *buf, size_t count);
55extern void write_or_die(int fd, const void *buf, size_t count);
56extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
57extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
58extern void fsync_or_die(int fd, const char *);
59
60/* pager.c */
61extern void setup_pager(void);
62extern const char *pager_program;
63extern int pager_in_use(void);
64extern int pager_use_color;
65
66extern const char *editor_program;
67extern const char *excludes_file;
68
69char *alias_lookup(const char *alias);
70int split_cmdline(char *cmdline, const char ***argv);
71
72#define alloc_nr(x) (((x)+16)*3/2)
73
74/*
75 * Realloc the buffer pointed at by variable 'x' so that it can hold
76 * at least 'nr' entries; the number of entries currently allocated
77 * is 'alloc', using the standard growing factor alloc_nr() macro.
78 *
79 * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
80 */
81#define ALLOC_GROW(x, nr, alloc) \
82 do { \
83 if ((nr) > alloc) { \
84 if (alloc_nr(alloc) < (nr)) \
85 alloc = (nr); \
86 else \
87 alloc = alloc_nr(alloc); \
88 x = xrealloc((x), alloc * sizeof(*(x))); \
89 } \
90 } while(0)
91
92
93static inline int is_absolute_path(const char *path)
94{
95 return path[0] == '/';
96}
97
98const char *make_absolute_path(const char *path);
99const char *make_nonrelative_path(const char *path);
100const char *make_relative_path(const char *abs, const char *base);
101int normalize_path_copy(char *dst, const char *src);
102int longest_ancestor_length(const char *path, const char *prefix_list);
103char *strip_path_suffix(const char *path, const char *suffix);
104
105extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
106extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
107/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
108extern int perf_mkstemp(char *path, size_t len, const char *template);
109
110extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
111 __attribute__((format (printf, 3, 4)));
112extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
113 __attribute__((format (printf, 3, 4)));
114extern char *perf_pathdup(const char *fmt, ...)
115 __attribute__((format (printf, 1, 2)));
116
117extern size_t strlcpy(char *dest, const char *src, size_t size);
118
119#endif /* CACHE_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
new file mode 100644
index 000000000000..9a8c20ccc53e
--- /dev/null
+++ b/tools/perf/util/color.c
@@ -0,0 +1,241 @@
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 for (i = 0; i < ARRAY_SIZE(color_names); i++) {
15 const char *str = color_names[i];
16 if (!strncasecmp(name, str, len) && !str[len])
17 return i - 1;
18 }
19 i = strtol(name, &end, 10);
20 if (end - name == len && i >= -1 && i <= 255)
21 return i;
22 return -2;
23}
24
25static int parse_attr(const char *name, int len)
26{
27 static const int attr_values[] = { 1, 2, 4, 5, 7 };
28 static const char * const attr_names[] = {
29 "bold", "dim", "ul", "blink", "reverse"
30 };
31 int i;
32 for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
33 const char *str = attr_names[i];
34 if (!strncasecmp(name, str, len) && !str[len])
35 return attr_values[i];
36 }
37 return -1;
38}
39
40void color_parse(const char *value, const char *var, char *dst)
41{
42 color_parse_mem(value, strlen(value), var, dst);
43}
44
45void color_parse_mem(const char *value, int value_len, const char *var,
46 char *dst)
47{
48 const char *ptr = value;
49 int len = value_len;
50 int attr = -1;
51 int fg = -2;
52 int bg = -2;
53
54 if (!strncasecmp(value, "reset", len)) {
55 strcpy(dst, PERF_COLOR_RESET);
56 return;
57 }
58
59 /* [fg [bg]] [attr] */
60 while (len > 0) {
61 const char *word = ptr;
62 int val, wordlen = 0;
63
64 while (len > 0 && !isspace(word[wordlen])) {
65 wordlen++;
66 len--;
67 }
68
69 ptr = word + wordlen;
70 while (len > 0 && isspace(*ptr)) {
71 ptr++;
72 len--;
73 }
74
75 val = parse_color(word, wordlen);
76 if (val >= -1) {
77 if (fg == -2) {
78 fg = val;
79 continue;
80 }
81 if (bg == -2) {
82 bg = val;
83 continue;
84 }
85 goto bad;
86 }
87 val = parse_attr(word, wordlen);
88 if (val < 0 || attr != -1)
89 goto bad;
90 attr = val;
91 }
92
93 if (attr >= 0 || fg >= 0 || bg >= 0) {
94 int sep = 0;
95
96 *dst++ = '\033';
97 *dst++ = '[';
98 if (attr >= 0) {
99 *dst++ = '0' + attr;
100 sep++;
101 }
102 if (fg >= 0) {
103 if (sep++)
104 *dst++ = ';';
105 if (fg < 8) {
106 *dst++ = '3';
107 *dst++ = '0' + fg;
108 } else {
109 dst += sprintf(dst, "38;5;%d", fg);
110 }
111 }
112 if (bg >= 0) {
113 if (sep++)
114 *dst++ = ';';
115 if (bg < 8) {
116 *dst++ = '4';
117 *dst++ = '0' + bg;
118 } else {
119 dst += sprintf(dst, "48;5;%d", bg);
120 }
121 }
122 *dst++ = 'm';
123 }
124 *dst = 0;
125 return;
126bad:
127 die("bad color value '%.*s' for variable '%s'", value_len, value, var);
128}
129
130int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
131{
132 if (value) {
133 if (!strcasecmp(value, "never"))
134 return 0;
135 if (!strcasecmp(value, "always"))
136 return 1;
137 if (!strcasecmp(value, "auto"))
138 goto auto_color;
139 }
140
141 /* Missing or explicit false to turn off colorization */
142 if (!perf_config_bool(var, value))
143 return 0;
144
145 /* any normal truth value defaults to 'auto' */
146 auto_color:
147 if (stdout_is_tty < 0)
148 stdout_is_tty = isatty(1);
149 if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
150 char *term = getenv("TERM");
151 if (term && strcmp(term, "dumb"))
152 return 1;
153 }
154 return 0;
155}
156
157int perf_color_default_config(const char *var, const char *value, void *cb)
158{
159 if (!strcmp(var, "color.ui")) {
160 perf_use_color_default = perf_config_colorbool(var, value, -1);
161 return 0;
162 }
163
164 return perf_default_config(var, value, cb);
165}
166
167static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
168 va_list args, const char *trail)
169{
170 int r = 0;
171
172 /*
173 * Auto-detect:
174 */
175 if (perf_use_color_default < 0) {
176 if (isatty(1) || pager_in_use())
177 perf_use_color_default = 1;
178 else
179 perf_use_color_default = 0;
180 }
181
182 if (perf_use_color_default && *color)
183 r += fprintf(fp, "%s", color);
184 r += vfprintf(fp, fmt, args);
185 if (perf_use_color_default && *color)
186 r += fprintf(fp, "%s", PERF_COLOR_RESET);
187 if (trail)
188 r += fprintf(fp, "%s", trail);
189 return r;
190}
191
192
193
194int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
195{
196 va_list args;
197 int r;
198
199 va_start(args, fmt);
200 r = color_vfprintf(fp, color, fmt, args, NULL);
201 va_end(args);
202 return r;
203}
204
205int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
206{
207 va_list args;
208 int r;
209 va_start(args, fmt);
210 r = color_vfprintf(fp, color, fmt, args, "\n");
211 va_end(args);
212 return r;
213}
214
215/*
216 * This function splits the buffer by newlines and colors the lines individually.
217 *
218 * Returns 0 on success.
219 */
220int color_fwrite_lines(FILE *fp, const char *color,
221 size_t count, const char *buf)
222{
223 if (!*color)
224 return fwrite(buf, count, 1, fp) != 1;
225 while (count) {
226 char *p = memchr(buf, '\n', count);
227 if (p != buf && (fputs(color, fp) < 0 ||
228 fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
229 fputs(PERF_COLOR_RESET, fp) < 0))
230 return -1;
231 if (!p)
232 return 0;
233 if (fputc('\n', fp) < 0)
234 return -1;
235 count -= p + 1 - buf;
236 buf = p + 1;
237 }
238 return 0;
239}
240
241
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
new file mode 100644
index 000000000000..5abfd379582b
--- /dev/null
+++ b/tools/perf/util/color.h
@@ -0,0 +1,36 @@
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/*
19 * This variable stores the value of color.ui
20 */
21extern int perf_use_color_default;
22
23
24/*
25 * Use this instead of perf_default_config if you need the value of color.ui.
26 */
27int perf_color_default_config(const char *var, const char *value, void *cb);
28
29int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
30void color_parse(const char *value, const char *var, char *dst);
31void color_parse_mem(const char *value, int len, const char *var, char *dst);
32int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
33int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
34int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
35
36#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
new file mode 100644
index 000000000000..3dd13faa6a27
--- /dev/null
+++ b/tools/perf/util/config.c
@@ -0,0 +1,873 @@
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, len = 0, space = 0;
51
52 for (;;) {
53 int c = get_next_char();
54 if (len >= sizeof(value) - 1)
55 return NULL;
56 if (c == '\n') {
57 if (quote)
58 return NULL;
59 value[len] = 0;
60 return value;
61 }
62 if (comment)
63 continue;
64 if (isspace(c) && !quote) {
65 space = 1;
66 continue;
67 }
68 if (!quote) {
69 if (c == ';' || c == '#') {
70 comment = 1;
71 continue;
72 }
73 }
74 if (space) {
75 if (len)
76 value[len++] = ' ';
77 space = 0;
78 }
79 if (c == '\\') {
80 c = get_next_char();
81 switch (c) {
82 case '\n':
83 continue;
84 case 't':
85 c = '\t';
86 break;
87 case 'b':
88 c = '\b';
89 break;
90 case 'n':
91 c = '\n';
92 break;
93 /* Some characters escape as themselves */
94 case '\\': case '"':
95 break;
96 /* Reject unknown escape sequences */
97 default:
98 return NULL;
99 }
100 value[len++] = c;
101 continue;
102 }
103 if (c == '"') {
104 quote = 1-quote;
105 continue;
106 }
107 value[len++] = c;
108 }
109}
110
111static inline int iskeychar(int c)
112{
113 return isalnum(c) || c == '-';
114}
115
116static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
117{
118 int c;
119 char *value;
120
121 /* Get the full name */
122 for (;;) {
123 c = get_next_char();
124 if (config_file_eof)
125 break;
126 if (!iskeychar(c))
127 break;
128 name[len++] = tolower(c);
129 if (len >= MAXNAME)
130 return -1;
131 }
132 name[len] = 0;
133 while (c == ' ' || c == '\t')
134 c = get_next_char();
135
136 value = NULL;
137 if (c != '\n') {
138 if (c != '=')
139 return -1;
140 value = parse_value();
141 if (!value)
142 return -1;
143 }
144 return fn(name, value, data);
145}
146
147static int get_extended_base_var(char *name, int baselen, int c)
148{
149 do {
150 if (c == '\n')
151 return -1;
152 c = get_next_char();
153 } while (isspace(c));
154
155 /* We require the format to be '[base "extension"]' */
156 if (c != '"')
157 return -1;
158 name[baselen++] = '.';
159
160 for (;;) {
161 int c = get_next_char();
162 if (c == '\n')
163 return -1;
164 if (c == '"')
165 break;
166 if (c == '\\') {
167 c = get_next_char();
168 if (c == '\n')
169 return -1;
170 }
171 name[baselen++] = c;
172 if (baselen > MAXNAME / 2)
173 return -1;
174 }
175
176 /* Final ']' */
177 if (get_next_char() != ']')
178 return -1;
179 return baselen;
180}
181
182static int get_base_var(char *name)
183{
184 int baselen = 0;
185
186 for (;;) {
187 int c = get_next_char();
188 if (config_file_eof)
189 return -1;
190 if (c == ']')
191 return baselen;
192 if (isspace(c))
193 return get_extended_base_var(name, baselen, c);
194 if (!iskeychar(c) && c != '.')
195 return -1;
196 if (baselen > MAXNAME / 2)
197 return -1;
198 name[baselen++] = tolower(c);
199 }
200}
201
202static int perf_parse_file(config_fn_t fn, void *data)
203{
204 int comment = 0;
205 int baselen = 0;
206 static char var[MAXNAME];
207
208 /* U+FEFF Byte Order Mark in UTF8 */
209 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
210 const unsigned char *bomptr = utf8_bom;
211
212 for (;;) {
213 int c = get_next_char();
214 if (bomptr && *bomptr) {
215 /* We are at the file beginning; skip UTF8-encoded BOM
216 * if present. Sane editors won't put this in on their
217 * own, but e.g. Windows Notepad will do it happily. */
218 if ((unsigned char) c == *bomptr) {
219 bomptr++;
220 continue;
221 } else {
222 /* Do not tolerate partial BOM. */
223 if (bomptr != utf8_bom)
224 break;
225 /* No BOM at file beginning. Cool. */
226 bomptr = NULL;
227 }
228 }
229 if (c == '\n') {
230 if (config_file_eof)
231 return 0;
232 comment = 0;
233 continue;
234 }
235 if (comment || isspace(c))
236 continue;
237 if (c == '#' || c == ';') {
238 comment = 1;
239 continue;
240 }
241 if (c == '[') {
242 baselen = get_base_var(var);
243 if (baselen <= 0)
244 break;
245 var[baselen++] = '.';
246 var[baselen] = 0;
247 continue;
248 }
249 if (!isalpha(c))
250 break;
251 var[baselen] = tolower(c);
252 if (get_value(fn, data, var, baselen+1) < 0)
253 break;
254 }
255 die("bad config file line %d in %s", config_linenr, config_file_name);
256}
257
258static int parse_unit_factor(const char *end, unsigned long *val)
259{
260 if (!*end)
261 return 1;
262 else if (!strcasecmp(end, "k")) {
263 *val *= 1024;
264 return 1;
265 }
266 else if (!strcasecmp(end, "m")) {
267 *val *= 1024 * 1024;
268 return 1;
269 }
270 else if (!strcasecmp(end, "g")) {
271 *val *= 1024 * 1024 * 1024;
272 return 1;
273 }
274 return 0;
275}
276
277static int perf_parse_long(const char *value, long *ret)
278{
279 if (value && *value) {
280 char *end;
281 long val = strtol(value, &end, 0);
282 unsigned long factor = 1;
283 if (!parse_unit_factor(end, &factor))
284 return 0;
285 *ret = val * factor;
286 return 1;
287 }
288 return 0;
289}
290
291int perf_parse_ulong(const char *value, unsigned long *ret)
292{
293 if (value && *value) {
294 char *end;
295 unsigned long val = strtoul(value, &end, 0);
296 if (!parse_unit_factor(end, &val))
297 return 0;
298 *ret = val;
299 return 1;
300 }
301 return 0;
302}
303
304static void die_bad_config(const char *name)
305{
306 if (config_file_name)
307 die("bad config value for '%s' in %s", name, config_file_name);
308 die("bad config value for '%s'", name);
309}
310
311int perf_config_int(const char *name, const char *value)
312{
313 long ret = 0;
314 if (!perf_parse_long(value, &ret))
315 die_bad_config(name);
316 return ret;
317}
318
319unsigned long perf_config_ulong(const char *name, const char *value)
320{
321 unsigned long ret;
322 if (!perf_parse_ulong(value, &ret))
323 die_bad_config(name);
324 return ret;
325}
326
327int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
328{
329 *is_bool = 1;
330 if (!value)
331 return 1;
332 if (!*value)
333 return 0;
334 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
335 return 1;
336 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
337 return 0;
338 *is_bool = 0;
339 return perf_config_int(name, value);
340}
341
342int perf_config_bool(const char *name, const char *value)
343{
344 int discard;
345 return !!perf_config_bool_or_int(name, value, &discard);
346}
347
348int perf_config_string(const char **dest, const char *var, const char *value)
349{
350 if (!value)
351 return config_error_nonbool(var);
352 *dest = strdup(value);
353 return 0;
354}
355
356static int perf_default_core_config(const char *var, const char *value)
357{
358 /* Add other config variables here and to Documentation/config.txt. */
359 return 0;
360}
361
362int perf_default_config(const char *var, const char *value, void *dummy)
363{
364 if (!prefixcmp(var, "core."))
365 return perf_default_core_config(var, value);
366
367 /* Add other config variables here and to Documentation/config.txt. */
368 return 0;
369}
370
371int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
372{
373 int ret;
374 FILE *f = fopen(filename, "r");
375
376 ret = -1;
377 if (f) {
378 config_file = f;
379 config_file_name = filename;
380 config_linenr = 1;
381 config_file_eof = 0;
382 ret = perf_parse_file(fn, data);
383 fclose(f);
384 config_file_name = NULL;
385 }
386 return ret;
387}
388
389const char *perf_etc_perfconfig(void)
390{
391 static const char *system_wide;
392 if (!system_wide)
393 system_wide = system_path(ETC_PERFCONFIG);
394 return system_wide;
395}
396
397static int perf_env_bool(const char *k, int def)
398{
399 const char *v = getenv(k);
400 return v ? perf_config_bool(k, v) : def;
401}
402
403int perf_config_system(void)
404{
405 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
406}
407
408int perf_config_global(void)
409{
410 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
411}
412
413int perf_config(config_fn_t fn, void *data)
414{
415 int ret = 0, found = 0;
416 char *repo_config = NULL;
417 const char *home = NULL;
418
419 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
420 if (config_exclusive_filename)
421 return perf_config_from_file(fn, config_exclusive_filename, data);
422 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
423 ret += perf_config_from_file(fn, perf_etc_perfconfig(),
424 data);
425 found += 1;
426 }
427
428 home = getenv("HOME");
429 if (perf_config_global() && home) {
430 char *user_config = strdup(mkpath("%s/.perfconfig", home));
431 if (!access(user_config, R_OK)) {
432 ret += perf_config_from_file(fn, user_config, data);
433 found += 1;
434 }
435 free(user_config);
436 }
437
438 repo_config = perf_pathdup("config");
439 if (!access(repo_config, R_OK)) {
440 ret += perf_config_from_file(fn, repo_config, data);
441 found += 1;
442 }
443 free(repo_config);
444 if (found == 0)
445 return -1;
446 return ret;
447}
448
449/*
450 * Find all the stuff for perf_config_set() below.
451 */
452
453#define MAX_MATCHES 512
454
455static struct {
456 int baselen;
457 char* key;
458 int do_not_match;
459 regex_t* value_regex;
460 int multi_replace;
461 size_t offset[MAX_MATCHES];
462 enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
463 int seen;
464} store;
465
466static int matches(const char* key, const char* value)
467{
468 return !strcmp(key, store.key) &&
469 (store.value_regex == NULL ||
470 (store.do_not_match ^
471 !regexec(store.value_regex, value, 0, NULL, 0)));
472}
473
474static int store_aux(const char* key, const char* value, void *cb)
475{
476 const char *ep;
477 size_t section_len;
478
479 switch (store.state) {
480 case KEY_SEEN:
481 if (matches(key, value)) {
482 if (store.seen == 1 && store.multi_replace == 0) {
483 warning("%s has multiple values", key);
484 } else if (store.seen >= MAX_MATCHES) {
485 error("too many matches for %s", key);
486 return 1;
487 }
488
489 store.offset[store.seen] = ftell(config_file);
490 store.seen++;
491 }
492 break;
493 case SECTION_SEEN:
494 /*
495 * What we are looking for is in store.key (both
496 * section and var), and its section part is baselen
497 * long. We found key (again, both section and var).
498 * We would want to know if this key is in the same
499 * section as what we are looking for. We already
500 * know we are in the same section as what should
501 * hold store.key.
502 */
503 ep = strrchr(key, '.');
504 section_len = ep - key;
505
506 if ((section_len != store.baselen) ||
507 memcmp(key, store.key, section_len+1)) {
508 store.state = SECTION_END_SEEN;
509 break;
510 }
511
512 /*
513 * Do not increment matches: this is no match, but we
514 * just made sure we are in the desired section.
515 */
516 store.offset[store.seen] = ftell(config_file);
517 /* fallthru */
518 case SECTION_END_SEEN:
519 case START:
520 if (matches(key, value)) {
521 store.offset[store.seen] = ftell(config_file);
522 store.state = KEY_SEEN;
523 store.seen++;
524 } else {
525 if (strrchr(key, '.') - key == store.baselen &&
526 !strncmp(key, store.key, store.baselen)) {
527 store.state = SECTION_SEEN;
528 store.offset[store.seen] = ftell(config_file);
529 }
530 }
531 }
532 return 0;
533}
534
535static int store_write_section(int fd, const char* key)
536{
537 const char *dot;
538 int i, success;
539 struct strbuf sb = STRBUF_INIT;
540
541 dot = memchr(key, '.', store.baselen);
542 if (dot) {
543 strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
544 for (i = dot - key + 1; i < store.baselen; i++) {
545 if (key[i] == '"' || key[i] == '\\')
546 strbuf_addch(&sb, '\\');
547 strbuf_addch(&sb, key[i]);
548 }
549 strbuf_addstr(&sb, "\"]\n");
550 } else {
551 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
552 }
553
554 success = write_in_full(fd, sb.buf, sb.len) == sb.len;
555 strbuf_release(&sb);
556
557 return success;
558}
559
560static int store_write_pair(int fd, const char* key, const char* value)
561{
562 int i, success;
563 int length = strlen(key + store.baselen + 1);
564 const char *quote = "";
565 struct strbuf sb = STRBUF_INIT;
566
567 /*
568 * Check to see if the value needs to be surrounded with a dq pair.
569 * Note that problematic characters are always backslash-quoted; this
570 * check is about not losing leading or trailing SP and strings that
571 * follow beginning-of-comment characters (i.e. ';' and '#') by the
572 * configuration parser.
573 */
574 if (value[0] == ' ')
575 quote = "\"";
576 for (i = 0; value[i]; i++)
577 if (value[i] == ';' || value[i] == '#')
578 quote = "\"";
579 if (i && value[i - 1] == ' ')
580 quote = "\"";
581
582 strbuf_addf(&sb, "\t%.*s = %s",
583 length, key + store.baselen + 1, quote);
584
585 for (i = 0; value[i]; i++)
586 switch (value[i]) {
587 case '\n':
588 strbuf_addstr(&sb, "\\n");
589 break;
590 case '\t':
591 strbuf_addstr(&sb, "\\t");
592 break;
593 case '"':
594 case '\\':
595 strbuf_addch(&sb, '\\');
596 default:
597 strbuf_addch(&sb, value[i]);
598 break;
599 }
600 strbuf_addf(&sb, "%s\n", quote);
601
602 success = write_in_full(fd, sb.buf, sb.len) == sb.len;
603 strbuf_release(&sb);
604
605 return success;
606}
607
608static ssize_t find_beginning_of_line(const char* contents, size_t size,
609 size_t offset_, int* found_bracket)
610{
611 size_t equal_offset = size, bracket_offset = size;
612 ssize_t offset;
613
614contline:
615 for (offset = offset_-2; offset > 0
616 && contents[offset] != '\n'; offset--)
617 switch (contents[offset]) {
618 case '=': equal_offset = offset; break;
619 case ']': bracket_offset = offset; break;
620 }
621 if (offset > 0 && contents[offset-1] == '\\') {
622 offset_ = offset;
623 goto contline;
624 }
625 if (bracket_offset < equal_offset) {
626 *found_bracket = 1;
627 offset = bracket_offset+1;
628 } else
629 offset++;
630
631 return offset;
632}
633
634int perf_config_set(const char* key, const char* value)
635{
636 return perf_config_set_multivar(key, value, NULL, 0);
637}
638
639/*
640 * If value==NULL, unset in (remove from) config,
641 * if value_regex!=NULL, disregard key/value pairs where value does not match.
642 * if multi_replace==0, nothing, or only one matching key/value is replaced,
643 * else all matching key/values (regardless how many) are removed,
644 * before the new pair is written.
645 *
646 * Returns 0 on success.
647 *
648 * This function does this:
649 *
650 * - it locks the config file by creating ".perf/config.lock"
651 *
652 * - it then parses the config using store_aux() as validator to find
653 * the position on the key/value pair to replace. If it is to be unset,
654 * it must be found exactly once.
655 *
656 * - the config file is mmap()ed and the part before the match (if any) is
657 * written to the lock file, then the changed part and the rest.
658 *
659 * - the config file is removed and the lock file rename()d to it.
660 *
661 */
662int perf_config_set_multivar(const char* key, const char* value,
663 const char* value_regex, int multi_replace)
664{
665 int i, dot;
666 int fd = -1, in_fd;
667 int ret = 0;
668 char* config_filename;
669 const char* last_dot = strrchr(key, '.');
670
671 if (config_exclusive_filename)
672 config_filename = strdup(config_exclusive_filename);
673 else
674 config_filename = perf_pathdup("config");
675
676 /*
677 * Since "key" actually contains the section name and the real
678 * key name separated by a dot, we have to know where the dot is.
679 */
680
681 if (last_dot == NULL) {
682 error("key does not contain a section: %s", key);
683 ret = 2;
684 goto out_free;
685 }
686 store.baselen = last_dot - key;
687
688 store.multi_replace = multi_replace;
689
690 /*
691 * Validate the key and while at it, lower case it for matching.
692 */
693 store.key = malloc(strlen(key) + 1);
694 dot = 0;
695 for (i = 0; key[i]; i++) {
696 unsigned char c = key[i];
697 if (c == '.')
698 dot = 1;
699 /* Leave the extended basename untouched.. */
700 if (!dot || i > store.baselen) {
701 if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
702 error("invalid key: %s", key);
703 free(store.key);
704 ret = 1;
705 goto out_free;
706 }
707 c = tolower(c);
708 } else if (c == '\n') {
709 error("invalid key (newline): %s", key);
710 free(store.key);
711 ret = 1;
712 goto out_free;
713 }
714 store.key[i] = c;
715 }
716 store.key[i] = 0;
717
718 /*
719 * If .perf/config does not exist yet, write a minimal version.
720 */
721 in_fd = open(config_filename, O_RDONLY);
722 if ( in_fd < 0 ) {
723 free(store.key);
724
725 if ( ENOENT != errno ) {
726 error("opening %s: %s", config_filename,
727 strerror(errno));
728 ret = 3; /* same as "invalid config file" */
729 goto out_free;
730 }
731 /* if nothing to unset, error out */
732 if (value == NULL) {
733 ret = 5;
734 goto out_free;
735 }
736
737 store.key = (char*)key;
738 if (!store_write_section(fd, key) ||
739 !store_write_pair(fd, key, value))
740 goto write_err_out;
741 } else {
742 struct stat st;
743 char* contents;
744 size_t contents_sz, copy_begin, copy_end;
745 int i, new_line = 0;
746
747 if (value_regex == NULL)
748 store.value_regex = NULL;
749 else {
750 if (value_regex[0] == '!') {
751 store.do_not_match = 1;
752 value_regex++;
753 } else
754 store.do_not_match = 0;
755
756 store.value_regex = (regex_t*)malloc(sizeof(regex_t));
757 if (regcomp(store.value_regex, value_regex,
758 REG_EXTENDED)) {
759 error("invalid pattern: %s", value_regex);
760 free(store.value_regex);
761 ret = 6;
762 goto out_free;
763 }
764 }
765
766 store.offset[0] = 0;
767 store.state = START;
768 store.seen = 0;
769
770 /*
771 * After this, store.offset will contain the *end* offset
772 * of the last match, or remain at 0 if no match was found.
773 * As a side effect, we make sure to transform only a valid
774 * existing config file.
775 */
776 if (perf_config_from_file(store_aux, config_filename, NULL)) {
777 error("invalid config file %s", config_filename);
778 free(store.key);
779 if (store.value_regex != NULL) {
780 regfree(store.value_regex);
781 free(store.value_regex);
782 }
783 ret = 3;
784 goto out_free;
785 }
786
787 free(store.key);
788 if (store.value_regex != NULL) {
789 regfree(store.value_regex);
790 free(store.value_regex);
791 }
792
793 /* if nothing to unset, or too many matches, error out */
794 if ((store.seen == 0 && value == NULL) ||
795 (store.seen > 1 && multi_replace == 0)) {
796 ret = 5;
797 goto out_free;
798 }
799
800 fstat(in_fd, &st);
801 contents_sz = xsize_t(st.st_size);
802 contents = mmap(NULL, contents_sz, PROT_READ,
803 MAP_PRIVATE, in_fd, 0);
804 close(in_fd);
805
806 if (store.seen == 0)
807 store.seen = 1;
808
809 for (i = 0, copy_begin = 0; i < store.seen; i++) {
810 if (store.offset[i] == 0) {
811 store.offset[i] = copy_end = contents_sz;
812 } else if (store.state != KEY_SEEN) {
813 copy_end = store.offset[i];
814 } else
815 copy_end = find_beginning_of_line(
816 contents, contents_sz,
817 store.offset[i]-2, &new_line);
818
819 if (copy_end > 0 && contents[copy_end-1] != '\n')
820 new_line = 1;
821
822 /* write the first part of the config */
823 if (copy_end > copy_begin) {
824 if (write_in_full(fd, contents + copy_begin,
825 copy_end - copy_begin) <
826 copy_end - copy_begin)
827 goto write_err_out;
828 if (new_line &&
829 write_in_full(fd, "\n", 1) != 1)
830 goto write_err_out;
831 }
832 copy_begin = store.offset[i];
833 }
834
835 /* write the pair (value == NULL means unset) */
836 if (value != NULL) {
837 if (store.state == START) {
838 if (!store_write_section(fd, key))
839 goto write_err_out;
840 }
841 if (!store_write_pair(fd, key, value))
842 goto write_err_out;
843 }
844
845 /* write the rest of the config */
846 if (copy_begin < contents_sz)
847 if (write_in_full(fd, contents + copy_begin,
848 contents_sz - copy_begin) <
849 contents_sz - copy_begin)
850 goto write_err_out;
851
852 munmap(contents, contents_sz);
853 }
854
855 ret = 0;
856
857out_free:
858 free(config_filename);
859 return ret;
860
861write_err_out:
862 goto out_free;
863
864}
865
866/*
867 * Call this to report error for your variable that should not
868 * get a boolean value (i.e. "[my] var" means "true").
869 */
870int config_error_nonbool(const char *var)
871{
872 return error("Missing value for '%s'", var);
873}
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
new file mode 100644
index 000000000000..b90ec004f29c
--- /dev/null
+++ b/tools/perf/util/ctype.c
@@ -0,0 +1,26 @@
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};
15
16unsigned char sane_ctype[256] = {
17 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */
18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */
19 S, 0, 0, 0, R, 0, 0, 0, R, R, G, R, 0, 0, R, 0, /* 32.. 47 */
20 D, D, D, D, D, D, D, D, D, D, 0, 0, 0, 0, 0, G, /* 48.. 63 */
21 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
22 A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, 0, /* 80.. 95 */
23 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
24 A, A, A, A, A, A, A, A, A, A, A, R, R, 0, 0, 0, /* 112..127 */
25 /* Nothing in the 128.. range */
26};
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..d39292263153
--- /dev/null
+++ b/tools/perf/util/exec_cmd.c
@@ -0,0 +1,165 @@
1#include "cache.h"
2#include "exec_cmd.h"
3#include "quote.h"
4#define MAX_ARGS 32
5
6extern char **environ;
7static const char *argv_exec_path;
8static const char *argv0_path;
9
10const char *system_path(const char *path)
11{
12#ifdef RUNTIME_PREFIX
13 static const char *prefix;
14#else
15 static const char *prefix = PREFIX;
16#endif
17 struct strbuf d = STRBUF_INIT;
18
19 if (is_absolute_path(path))
20 return path;
21
22#ifdef RUNTIME_PREFIX
23 assert(argv0_path);
24 assert(is_absolute_path(argv0_path));
25
26 if (!prefix &&
27 !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) &&
28 !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
29 !(prefix = strip_path_suffix(argv0_path, "perf"))) {
30 prefix = PREFIX;
31 fprintf(stderr, "RUNTIME_PREFIX requested, "
32 "but prefix computation failed. "
33 "Using static fallback '%s'.\n", prefix);
34 }
35#endif
36
37 strbuf_addf(&d, "%s/%s", prefix, path);
38 path = strbuf_detach(&d, NULL);
39 return path;
40}
41
42const char *perf_extract_argv0_path(const char *argv0)
43{
44 const char *slash;
45
46 if (!argv0 || !*argv0)
47 return NULL;
48 slash = argv0 + strlen(argv0);
49
50 while (argv0 <= slash && !is_dir_sep(*slash))
51 slash--;
52
53 if (slash >= argv0) {
54 argv0_path = strndup(argv0, slash - argv0);
55 return slash + 1;
56 }
57
58 return argv0;
59}
60
61void perf_set_argv_exec_path(const char *exec_path)
62{
63 argv_exec_path = exec_path;
64 /*
65 * Propagate this setting to external programs.
66 */
67 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
68}
69
70
71/* Returns the highest-priority, location to look for perf programs. */
72const char *perf_exec_path(void)
73{
74 const char *env;
75
76 if (argv_exec_path)
77 return argv_exec_path;
78
79 env = getenv(EXEC_PATH_ENVIRONMENT);
80 if (env && *env) {
81 return env;
82 }
83
84 return system_path(PERF_EXEC_PATH);
85}
86
87static void add_path(struct strbuf *out, const char *path)
88{
89 if (path && *path) {
90 if (is_absolute_path(path))
91 strbuf_addstr(out, path);
92 else
93 strbuf_addstr(out, make_nonrelative_path(path));
94
95 strbuf_addch(out, PATH_SEP);
96 }
97}
98
99void setup_path(void)
100{
101 const char *old_path = getenv("PATH");
102 struct strbuf new_path = STRBUF_INIT;
103
104 add_path(&new_path, perf_exec_path());
105 add_path(&new_path, argv0_path);
106
107 if (old_path)
108 strbuf_addstr(&new_path, old_path);
109 else
110 strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
111
112 setenv("PATH", new_path.buf, 1);
113
114 strbuf_release(&new_path);
115}
116
117const char **prepare_perf_cmd(const char **argv)
118{
119 int argc;
120 const char **nargv;
121
122 for (argc = 0; argv[argc]; argc++)
123 ; /* just counting */
124 nargv = malloc(sizeof(*nargv) * (argc + 2));
125
126 nargv[0] = "perf";
127 for (argc = 0; argv[argc]; argc++)
128 nargv[argc + 1] = argv[argc];
129 nargv[argc + 1] = NULL;
130 return nargv;
131}
132
133int execv_perf_cmd(const char **argv) {
134 const char **nargv = prepare_perf_cmd(argv);
135
136 /* execvp() can only ever return if it fails */
137 execvp("perf", (char **)nargv);
138
139 free(nargv);
140 return -1;
141}
142
143
144int execl_perf_cmd(const char *cmd,...)
145{
146 int argc;
147 const char *argv[MAX_ARGS + 1];
148 const char *arg;
149 va_list param;
150
151 va_start(param, cmd);
152 argv[0] = cmd;
153 argc = 1;
154 while (argc < MAX_ARGS) {
155 arg = argv[argc++] = va_arg(param, char *);
156 if (!arg)
157 break;
158 }
159 va_end(param);
160 if (MAX_ARGS <= argc)
161 return error("too many args to run %s", cmd);
162
163 argv[argc] = NULL;
164 return execv_perf_cmd(argv);
165}
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/help.c b/tools/perf/util/help.c
new file mode 100644
index 000000000000..6653f7dd1d78
--- /dev/null
+++ b/tools/perf/util/help.c
@@ -0,0 +1,367 @@
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, int 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 int i;
44 for (i = 0; i < cmds->cnt; ++i)
45 free(cmds->names[i]);
46 free(cmds->names);
47 cmds->cnt = 0;
48 cmds->alloc = 0;
49}
50
51static int cmdname_compare(const void *a_, const void *b_)
52{
53 struct cmdname *a = *(struct cmdname **)a_;
54 struct cmdname *b = *(struct cmdname **)b_;
55 return strcmp(a->name, b->name);
56}
57
58static void uniq(struct cmdnames *cmds)
59{
60 int i, j;
61
62 if (!cmds->cnt)
63 return;
64
65 for (i = j = 1; i < cmds->cnt; i++)
66 if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
67 cmds->names[j++] = cmds->names[i];
68
69 cmds->cnt = j;
70}
71
72void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
73{
74 int ci, cj, ei;
75 int cmp;
76
77 ci = cj = ei = 0;
78 while (ci < cmds->cnt && ei < excludes->cnt) {
79 cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
80 if (cmp < 0)
81 cmds->names[cj++] = cmds->names[ci++];
82 else if (cmp == 0)
83 ci++, ei++;
84 else if (cmp > 0)
85 ei++;
86 }
87
88 while (ci < cmds->cnt)
89 cmds->names[cj++] = cmds->names[ci++];
90
91 cmds->cnt = cj;
92}
93
94static void pretty_print_string_list(struct cmdnames *cmds, int longest)
95{
96 int cols = 1, rows;
97 int space = longest + 1; /* min 1 SP between words */
98 int max_cols = term_columns() - 1; /* don't print *on* the edge */
99 int i, j;
100
101 if (space < max_cols)
102 cols = max_cols / space;
103 rows = (cmds->cnt + cols - 1) / cols;
104
105 for (i = 0; i < rows; i++) {
106 printf(" ");
107
108 for (j = 0; j < cols; j++) {
109 int n = j * rows + i;
110 int size = space;
111 if (n >= cmds->cnt)
112 break;
113 if (j == cols-1 || n + rows >= cmds->cnt)
114 size = 1;
115 printf("%-*s", size, cmds->names[n]->name);
116 }
117 putchar('\n');
118 }
119}
120
121static int is_executable(const char *name)
122{
123 struct stat st;
124
125 if (stat(name, &st) || /* stat, not lstat */
126 !S_ISREG(st.st_mode))
127 return 0;
128
129#ifdef __MINGW32__
130 /* cannot trust the executable bit, peek into the file instead */
131 char buf[3] = { 0 };
132 int n;
133 int fd = open(name, O_RDONLY);
134 st.st_mode &= ~S_IXUSR;
135 if (fd >= 0) {
136 n = read(fd, buf, 2);
137 if (n == 2)
138 /* DOS executables start with "MZ" */
139 if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
140 st.st_mode |= S_IXUSR;
141 close(fd);
142 }
143#endif
144 return st.st_mode & S_IXUSR;
145}
146
147static void list_commands_in_dir(struct cmdnames *cmds,
148 const char *path,
149 const char *prefix)
150{
151 int prefix_len;
152 DIR *dir = opendir(path);
153 struct dirent *de;
154 struct strbuf buf = STRBUF_INIT;
155 int len;
156
157 if (!dir)
158 return;
159 if (!prefix)
160 prefix = "perf-";
161 prefix_len = strlen(prefix);
162
163 strbuf_addf(&buf, "%s/", path);
164 len = buf.len;
165
166 while ((de = readdir(dir)) != NULL) {
167 int entlen;
168
169 if (prefixcmp(de->d_name, prefix))
170 continue;
171
172 strbuf_setlen(&buf, len);
173 strbuf_addstr(&buf, de->d_name);
174 if (!is_executable(buf.buf))
175 continue;
176
177 entlen = strlen(de->d_name) - prefix_len;
178 if (has_extension(de->d_name, ".exe"))
179 entlen -= 4;
180
181 add_cmdname(cmds, de->d_name + prefix_len, entlen);
182 }
183 closedir(dir);
184 strbuf_release(&buf);
185}
186
187void load_command_list(const char *prefix,
188 struct cmdnames *main_cmds,
189 struct cmdnames *other_cmds)
190{
191 const char *env_path = getenv("PATH");
192 const char *exec_path = perf_exec_path();
193
194 if (exec_path) {
195 list_commands_in_dir(main_cmds, exec_path, prefix);
196 qsort(main_cmds->names, main_cmds->cnt,
197 sizeof(*main_cmds->names), cmdname_compare);
198 uniq(main_cmds);
199 }
200
201 if (env_path) {
202 char *paths, *path, *colon;
203 path = paths = strdup(env_path);
204 while (1) {
205 if ((colon = strchr(path, PATH_SEP)))
206 *colon = 0;
207 if (!exec_path || strcmp(path, exec_path))
208 list_commands_in_dir(other_cmds, path, prefix);
209
210 if (!colon)
211 break;
212 path = colon + 1;
213 }
214 free(paths);
215
216 qsort(other_cmds->names, other_cmds->cnt,
217 sizeof(*other_cmds->names), cmdname_compare);
218 uniq(other_cmds);
219 }
220 exclude_cmds(other_cmds, main_cmds);
221}
222
223void list_commands(const char *title, struct cmdnames *main_cmds,
224 struct cmdnames *other_cmds)
225{
226 int i, longest = 0;
227
228 for (i = 0; i < main_cmds->cnt; i++)
229 if (longest < main_cmds->names[i]->len)
230 longest = main_cmds->names[i]->len;
231 for (i = 0; i < other_cmds->cnt; i++)
232 if (longest < other_cmds->names[i]->len)
233 longest = other_cmds->names[i]->len;
234
235 if (main_cmds->cnt) {
236 const char *exec_path = perf_exec_path();
237 printf("available %s in '%s'\n", title, exec_path);
238 printf("----------------");
239 mput_char('-', strlen(title) + strlen(exec_path));
240 putchar('\n');
241 pretty_print_string_list(main_cmds, longest);
242 putchar('\n');
243 }
244
245 if (other_cmds->cnt) {
246 printf("%s available from elsewhere on your $PATH\n", title);
247 printf("---------------------------------------");
248 mput_char('-', strlen(title));
249 putchar('\n');
250 pretty_print_string_list(other_cmds, longest);
251 putchar('\n');
252 }
253}
254
255int is_in_cmdlist(struct cmdnames *c, const char *s)
256{
257 int i;
258 for (i = 0; i < c->cnt; i++)
259 if (!strcmp(s, c->names[i]->name))
260 return 1;
261 return 0;
262}
263
264static int autocorrect;
265static struct cmdnames aliases;
266
267static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
268{
269 if (!strcmp(var, "help.autocorrect"))
270 autocorrect = perf_config_int(var,value);
271 /* Also use aliases for command lookup */
272 if (!prefixcmp(var, "alias."))
273 add_cmdname(&aliases, var + 6, strlen(var + 6));
274
275 return perf_default_config(var, value, cb);
276}
277
278static int levenshtein_compare(const void *p1, const void *p2)
279{
280 const struct cmdname *const *c1 = p1, *const *c2 = p2;
281 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
282 int l1 = (*c1)->len;
283 int l2 = (*c2)->len;
284 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
285}
286
287static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
288{
289 int i;
290 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
291
292 for (i = 0; i < old->cnt; i++)
293 cmds->names[cmds->cnt++] = old->names[i];
294 free(old->names);
295 old->cnt = 0;
296 old->names = NULL;
297}
298
299const char *help_unknown_cmd(const char *cmd)
300{
301 int i, n = 0, best_similarity = 0;
302 struct cmdnames main_cmds, other_cmds;
303
304 memset(&main_cmds, 0, sizeof(main_cmds));
305 memset(&other_cmds, 0, sizeof(main_cmds));
306 memset(&aliases, 0, sizeof(aliases));
307
308 perf_config(perf_unknown_cmd_config, NULL);
309
310 load_command_list("perf-", &main_cmds, &other_cmds);
311
312 add_cmd_list(&main_cmds, &aliases);
313 add_cmd_list(&main_cmds, &other_cmds);
314 qsort(main_cmds.names, main_cmds.cnt,
315 sizeof(main_cmds.names), cmdname_compare);
316 uniq(&main_cmds);
317
318 if (main_cmds.cnt) {
319 /* This reuses cmdname->len for similarity index */
320 for (i = 0; i < main_cmds.cnt; ++i)
321 main_cmds.names[i]->len =
322 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
323
324 qsort(main_cmds.names, main_cmds.cnt,
325 sizeof(*main_cmds.names), levenshtein_compare);
326
327 best_similarity = main_cmds.names[0]->len;
328 n = 1;
329 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
330 ++n;
331 }
332
333 if (autocorrect && n == 1) {
334 const char *assumed = main_cmds.names[0]->name;
335
336 main_cmds.names[0] = NULL;
337 clean_cmdnames(&main_cmds);
338 fprintf(stderr, "WARNING: You called a Git program named '%s', "
339 "which does not exist.\n"
340 "Continuing under the assumption that you meant '%s'\n",
341 cmd, assumed);
342 if (autocorrect > 0) {
343 fprintf(stderr, "in %0.1f seconds automatically...\n",
344 (float)autocorrect/10.0);
345 poll(NULL, 0, autocorrect * 100);
346 }
347 return assumed;
348 }
349
350 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
351
352 if (main_cmds.cnt && best_similarity < 6) {
353 fprintf(stderr, "\nDid you mean %s?\n",
354 n < 2 ? "this": "one of these");
355
356 for (i = 0; i < n; i++)
357 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
358 }
359
360 exit(1);
361}
362
363int cmd_version(int argc, const char **argv, const char *prefix)
364{
365 printf("perf version %s\n", perf_version_string);
366 return 0;
367}
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
new file mode 100644
index 000000000000..56bc15406ffc
--- /dev/null
+++ b/tools/perf/util/help.h
@@ -0,0 +1,29 @@
1#ifndef HELP_H
2#define HELP_H
3
4struct cmdnames {
5 int alloc;
6 int 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, int 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/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/list.h b/tools/perf/util/list.h
new file mode 100644
index 000000000000..e2548e8072cf
--- /dev/null
+++ b/tools/perf/util/list.h
@@ -0,0 +1,603 @@
1#ifndef _LINUX_LIST_H
2#define _LINUX_LIST_H
3/*
4 Copyright (C) Cast of dozens, comes from the Linux kernel
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
9*/
10
11#include <stddef.h>
12
13/*
14 * These are non-NULL pointers that will result in page faults
15 * under normal circumstances, used to verify that nobody uses
16 * non-initialized list entries.
17 */
18#define LIST_POISON1 ((void *)0x00100100)
19#define LIST_POISON2 ((void *)0x00200200)
20
21/**
22 * container_of - cast a member of a structure out to the containing structure
23 * @ptr: the pointer to the member.
24 * @type: the type of the container struct this is embedded in.
25 * @member: the name of the member within the struct.
26 *
27 */
28#define container_of(ptr, type, member) ({ \
29 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
30 (type *)( (char *)__mptr - offsetof(type,member) );})
31
32/*
33 * Simple doubly linked list implementation.
34 *
35 * Some of the internal functions ("__xxx") are useful when
36 * manipulating whole lists rather than single entries, as
37 * sometimes we already know the next/prev entries and we can
38 * generate better code by using them directly rather than
39 * using the generic single-entry routines.
40 */
41
42struct list_head {
43 struct list_head *next, *prev;
44};
45
46#define LIST_HEAD_INIT(name) { &(name), &(name) }
47
48#define LIST_HEAD(name) \
49 struct list_head name = LIST_HEAD_INIT(name)
50
51static inline void INIT_LIST_HEAD(struct list_head *list)
52{
53 list->next = list;
54 list->prev = list;
55}
56
57/*
58 * Insert a new entry between two known consecutive entries.
59 *
60 * This is only for internal list manipulation where we know
61 * the prev/next entries already!
62 */
63static inline void __list_add(struct list_head *new,
64 struct list_head *prev,
65 struct list_head *next)
66{
67 next->prev = new;
68 new->next = next;
69 new->prev = prev;
70 prev->next = new;
71}
72
73/**
74 * list_add - add a new entry
75 * @new: new entry to be added
76 * @head: list head to add it after
77 *
78 * Insert a new entry after the specified head.
79 * This is good for implementing stacks.
80 */
81static inline void list_add(struct list_head *new, struct list_head *head)
82{
83 __list_add(new, head, head->next);
84}
85
86/**
87 * list_add_tail - add a new entry
88 * @new: new entry to be added
89 * @head: list head to add it before
90 *
91 * Insert a new entry before the specified head.
92 * This is useful for implementing queues.
93 */
94static inline void list_add_tail(struct list_head *new, struct list_head *head)
95{
96 __list_add(new, head->prev, head);
97}
98
99/*
100 * Delete a list entry by making the prev/next entries
101 * point to each other.
102 *
103 * This is only for internal list manipulation where we know
104 * the prev/next entries already!
105 */
106static inline void __list_del(struct list_head * prev, struct list_head * next)
107{
108 next->prev = prev;
109 prev->next = next;
110}
111
112/**
113 * list_del - deletes entry from list.
114 * @entry: the element to delete from the list.
115 * Note: list_empty on entry does not return true after this, the entry is
116 * in an undefined state.
117 */
118static inline void list_del(struct list_head *entry)
119{
120 __list_del(entry->prev, entry->next);
121 entry->next = LIST_POISON1;
122 entry->prev = LIST_POISON2;
123}
124
125/**
126 * list_del_range - deletes range of entries from list.
127 * @beging: first element in the range to delete from the list.
128 * @beging: first element in the range to delete from the list.
129 * Note: list_empty on the range of entries does not return true after this,
130 * the entries is in an undefined state.
131 */
132static inline void list_del_range(struct list_head *begin,
133 struct list_head *end)
134{
135 begin->prev->next = end->next;
136 end->next->prev = begin->prev;
137}
138
139/**
140 * list_replace - replace old entry by new one
141 * @old : the element to be replaced
142 * @new : the new element to insert
143 * Note: if 'old' was empty, it will be overwritten.
144 */
145static inline void list_replace(struct list_head *old,
146 struct list_head *new)
147{
148 new->next = old->next;
149 new->next->prev = new;
150 new->prev = old->prev;
151 new->prev->next = new;
152}
153
154static inline void list_replace_init(struct list_head *old,
155 struct list_head *new)
156{
157 list_replace(old, new);
158 INIT_LIST_HEAD(old);
159}
160
161/**
162 * list_del_init - deletes entry from list and reinitialize it.
163 * @entry: the element to delete from the list.
164 */
165static inline void list_del_init(struct list_head *entry)
166{
167 __list_del(entry->prev, entry->next);
168 INIT_LIST_HEAD(entry);
169}
170
171/**
172 * list_move - delete from one list and add as another's head
173 * @list: the entry to move
174 * @head: the head that will precede our entry
175 */
176static inline void list_move(struct list_head *list, struct list_head *head)
177{
178 __list_del(list->prev, list->next);
179 list_add(list, head);
180}
181
182/**
183 * list_move_tail - delete from one list and add as another's tail
184 * @list: the entry to move
185 * @head: the head that will follow our entry
186 */
187static inline void list_move_tail(struct list_head *list,
188 struct list_head *head)
189{
190 __list_del(list->prev, list->next);
191 list_add_tail(list, head);
192}
193
194/**
195 * list_is_last - tests whether @list is the last entry in list @head
196 * @list: the entry to test
197 * @head: the head of the list
198 */
199static inline int list_is_last(const struct list_head *list,
200 const struct list_head *head)
201{
202 return list->next == head;
203}
204
205/**
206 * list_empty - tests whether a list is empty
207 * @head: the list to test.
208 */
209static inline int list_empty(const struct list_head *head)
210{
211 return head->next == head;
212}
213
214/**
215 * list_empty_careful - tests whether a list is empty and not being modified
216 * @head: the list to test
217 *
218 * Description:
219 * tests whether a list is empty _and_ checks that no other CPU might be
220 * in the process of modifying either member (next or prev)
221 *
222 * NOTE: using list_empty_careful() without synchronization
223 * can only be safe if the only activity that can happen
224 * to the list entry is list_del_init(). Eg. it cannot be used
225 * if another CPU could re-list_add() it.
226 */
227static inline int list_empty_careful(const struct list_head *head)
228{
229 struct list_head *next = head->next;
230 return (next == head) && (next == head->prev);
231}
232
233static inline void __list_splice(struct list_head *list,
234 struct list_head *head)
235{
236 struct list_head *first = list->next;
237 struct list_head *last = list->prev;
238 struct list_head *at = head->next;
239
240 first->prev = head;
241 head->next = first;
242
243 last->next = at;
244 at->prev = last;
245}
246
247/**
248 * list_splice - join two lists
249 * @list: the new list to add.
250 * @head: the place to add it in the first list.
251 */
252static inline void list_splice(struct list_head *list, struct list_head *head)
253{
254 if (!list_empty(list))
255 __list_splice(list, head);
256}
257
258/**
259 * list_splice_init - join two lists and reinitialise the emptied list.
260 * @list: the new list to add.
261 * @head: the place to add it in the first list.
262 *
263 * The list at @list is reinitialised
264 */
265static inline void list_splice_init(struct list_head *list,
266 struct list_head *head)
267{
268 if (!list_empty(list)) {
269 __list_splice(list, head);
270 INIT_LIST_HEAD(list);
271 }
272}
273
274/**
275 * list_entry - get the struct for this entry
276 * @ptr: the &struct list_head pointer.
277 * @type: the type of the struct this is embedded in.
278 * @member: the name of the list_struct within the struct.
279 */
280#define list_entry(ptr, type, member) \
281 container_of(ptr, type, member)
282
283/**
284 * list_first_entry - get the first element from a list
285 * @ptr: the list head to take the element from.
286 * @type: the type of the struct this is embedded in.
287 * @member: the name of the list_struct within the struct.
288 *
289 * Note, that list is expected to be not empty.
290 */
291#define list_first_entry(ptr, type, member) \
292 list_entry((ptr)->next, type, member)
293
294/**
295 * list_for_each - iterate over a list
296 * @pos: the &struct list_head to use as a loop cursor.
297 * @head: the head for your list.
298 */
299#define list_for_each(pos, head) \
300 for (pos = (head)->next; pos != (head); \
301 pos = pos->next)
302
303/**
304 * __list_for_each - iterate over a list
305 * @pos: the &struct list_head to use as a loop cursor.
306 * @head: the head for your list.
307 *
308 * This variant differs from list_for_each() in that it's the
309 * simplest possible list iteration code, no prefetching is done.
310 * Use this for code that knows the list to be very short (empty
311 * or 1 entry) most of the time.
312 */
313#define __list_for_each(pos, head) \
314 for (pos = (head)->next; pos != (head); pos = pos->next)
315
316/**
317 * list_for_each_prev - iterate over a list backwards
318 * @pos: the &struct list_head to use as a loop cursor.
319 * @head: the head for your list.
320 */
321#define list_for_each_prev(pos, head) \
322 for (pos = (head)->prev; pos != (head); \
323 pos = pos->prev)
324
325/**
326 * list_for_each_safe - iterate over a list safe against removal of list entry
327 * @pos: the &struct list_head to use as a loop cursor.
328 * @n: another &struct list_head to use as temporary storage
329 * @head: the head for your list.
330 */
331#define list_for_each_safe(pos, n, head) \
332 for (pos = (head)->next, n = pos->next; pos != (head); \
333 pos = n, n = pos->next)
334
335/**
336 * list_for_each_entry - iterate over list of given type
337 * @pos: the type * to use as a loop cursor.
338 * @head: the head for your list.
339 * @member: the name of the list_struct within the struct.
340 */
341#define list_for_each_entry(pos, head, member) \
342 for (pos = list_entry((head)->next, typeof(*pos), member); \
343 &pos->member != (head); \
344 pos = list_entry(pos->member.next, typeof(*pos), member))
345
346/**
347 * list_for_each_entry_reverse - iterate backwards over list of given type.
348 * @pos: the type * to use as a loop cursor.
349 * @head: the head for your list.
350 * @member: the name of the list_struct within the struct.
351 */
352#define list_for_each_entry_reverse(pos, head, member) \
353 for (pos = list_entry((head)->prev, typeof(*pos), member); \
354 &pos->member != (head); \
355 pos = list_entry(pos->member.prev, typeof(*pos), member))
356
357/**
358 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
359 * @pos: the type * to use as a start point
360 * @head: the head of the list
361 * @member: the name of the list_struct within the struct.
362 *
363 * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
364 */
365#define list_prepare_entry(pos, head, member) \
366 ((pos) ? : list_entry(head, typeof(*pos), member))
367
368/**
369 * list_for_each_entry_continue - continue iteration over list of given type
370 * @pos: the type * to use as a loop cursor.
371 * @head: the head for your list.
372 * @member: the name of the list_struct within the struct.
373 *
374 * Continue to iterate over list of given type, continuing after
375 * the current position.
376 */
377#define list_for_each_entry_continue(pos, head, member) \
378 for (pos = list_entry(pos->member.next, typeof(*pos), member); \
379 &pos->member != (head); \
380 pos = list_entry(pos->member.next, typeof(*pos), member))
381
382/**
383 * list_for_each_entry_from - iterate over list of given type from the current point
384 * @pos: the type * to use as a loop cursor.
385 * @head: the head for your list.
386 * @member: the name of the list_struct within the struct.
387 *
388 * Iterate over list of given type, continuing from current position.
389 */
390#define list_for_each_entry_from(pos, head, member) \
391 for (; &pos->member != (head); \
392 pos = list_entry(pos->member.next, typeof(*pos), member))
393
394/**
395 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
396 * @pos: the type * to use as a loop cursor.
397 * @n: another type * to use as temporary storage
398 * @head: the head for your list.
399 * @member: the name of the list_struct within the struct.
400 */
401#define list_for_each_entry_safe(pos, n, head, member) \
402 for (pos = list_entry((head)->next, typeof(*pos), member), \
403 n = list_entry(pos->member.next, typeof(*pos), member); \
404 &pos->member != (head); \
405 pos = n, n = list_entry(n->member.next, typeof(*n), member))
406
407/**
408 * list_for_each_entry_safe_continue
409 * @pos: the type * to use as a loop cursor.
410 * @n: another type * to use as temporary storage
411 * @head: the head for your list.
412 * @member: the name of the list_struct within the struct.
413 *
414 * Iterate over list of given type, continuing after current point,
415 * safe against removal of list entry.
416 */
417#define list_for_each_entry_safe_continue(pos, n, head, member) \
418 for (pos = list_entry(pos->member.next, typeof(*pos), member), \
419 n = list_entry(pos->member.next, typeof(*pos), member); \
420 &pos->member != (head); \
421 pos = n, n = list_entry(n->member.next, typeof(*n), member))
422
423/**
424 * list_for_each_entry_safe_from
425 * @pos: the type * to use as a loop cursor.
426 * @n: another type * to use as temporary storage
427 * @head: the head for your list.
428 * @member: the name of the list_struct within the struct.
429 *
430 * Iterate over list of given type from current point, safe against
431 * removal of list entry.
432 */
433#define list_for_each_entry_safe_from(pos, n, head, member) \
434 for (n = list_entry(pos->member.next, typeof(*pos), member); \
435 &pos->member != (head); \
436 pos = n, n = list_entry(n->member.next, typeof(*n), member))
437
438/**
439 * list_for_each_entry_safe_reverse
440 * @pos: the type * to use as a loop cursor.
441 * @n: another type * to use as temporary storage
442 * @head: the head for your list.
443 * @member: the name of the list_struct within the struct.
444 *
445 * Iterate backwards over list of given type, safe against removal
446 * of list entry.
447 */
448#define list_for_each_entry_safe_reverse(pos, n, head, member) \
449 for (pos = list_entry((head)->prev, typeof(*pos), member), \
450 n = list_entry(pos->member.prev, typeof(*pos), member); \
451 &pos->member != (head); \
452 pos = n, n = list_entry(n->member.prev, typeof(*n), member))
453
454/*
455 * Double linked lists with a single pointer list head.
456 * Mostly useful for hash tables where the two pointer list head is
457 * too wasteful.
458 * You lose the ability to access the tail in O(1).
459 */
460
461struct hlist_head {
462 struct hlist_node *first;
463};
464
465struct hlist_node {
466 struct hlist_node *next, **pprev;
467};
468
469#define HLIST_HEAD_INIT { .first = NULL }
470#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
471#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
472static inline void INIT_HLIST_NODE(struct hlist_node *h)
473{
474 h->next = NULL;
475 h->pprev = NULL;
476}
477
478static inline int hlist_unhashed(const struct hlist_node *h)
479{
480 return !h->pprev;
481}
482
483static inline int hlist_empty(const struct hlist_head *h)
484{
485 return !h->first;
486}
487
488static inline void __hlist_del(struct hlist_node *n)
489{
490 struct hlist_node *next = n->next;
491 struct hlist_node **pprev = n->pprev;
492 *pprev = next;
493 if (next)
494 next->pprev = pprev;
495}
496
497static inline void hlist_del(struct hlist_node *n)
498{
499 __hlist_del(n);
500 n->next = LIST_POISON1;
501 n->pprev = LIST_POISON2;
502}
503
504static inline void hlist_del_init(struct hlist_node *n)
505{
506 if (!hlist_unhashed(n)) {
507 __hlist_del(n);
508 INIT_HLIST_NODE(n);
509 }
510}
511
512static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
513{
514 struct hlist_node *first = h->first;
515 n->next = first;
516 if (first)
517 first->pprev = &n->next;
518 h->first = n;
519 n->pprev = &h->first;
520}
521
522/* next must be != NULL */
523static inline void hlist_add_before(struct hlist_node *n,
524 struct hlist_node *next)
525{
526 n->pprev = next->pprev;
527 n->next = next;
528 next->pprev = &n->next;
529 *(n->pprev) = n;
530}
531
532static inline void hlist_add_after(struct hlist_node *n,
533 struct hlist_node *next)
534{
535 next->next = n->next;
536 n->next = next;
537 next->pprev = &n->next;
538
539 if(next->next)
540 next->next->pprev = &next->next;
541}
542
543#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
544
545#define hlist_for_each(pos, head) \
546 for (pos = (head)->first; pos; \
547 pos = pos->next)
548
549#define hlist_for_each_safe(pos, n, head) \
550 for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
551 pos = n)
552
553/**
554 * hlist_for_each_entry - iterate over list of given type
555 * @tpos: the type * to use as a loop cursor.
556 * @pos: the &struct hlist_node to use as a loop cursor.
557 * @head: the head for your list.
558 * @member: the name of the hlist_node within the struct.
559 */
560#define hlist_for_each_entry(tpos, pos, head, member) \
561 for (pos = (head)->first; \
562 pos && \
563 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
564 pos = pos->next)
565
566/**
567 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
568 * @tpos: the type * to use as a loop cursor.
569 * @pos: the &struct hlist_node to use as a loop cursor.
570 * @member: the name of the hlist_node within the struct.
571 */
572#define hlist_for_each_entry_continue(tpos, pos, member) \
573 for (pos = (pos)->next; \
574 pos && \
575 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
576 pos = pos->next)
577
578/**
579 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
580 * @tpos: the type * to use as a loop cursor.
581 * @pos: the &struct hlist_node to use as a loop cursor.
582 * @member: the name of the hlist_node within the struct.
583 */
584#define hlist_for_each_entry_from(tpos, pos, member) \
585 for (; pos && \
586 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
587 pos = pos->next)
588
589/**
590 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
591 * @tpos: the type * to use as a loop cursor.
592 * @pos: the &struct hlist_node to use as a loop cursor.
593 * @n: another &struct hlist_node to use as temporary storage
594 * @head: the head for your list.
595 * @member: the name of the hlist_node within the struct.
596 */
597#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
598 for (pos = (head)->first; \
599 pos && ({ n = pos->next; 1; }) && \
600 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
601 pos = n)
602
603#endif
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
new file mode 100644
index 000000000000..a28bccae5458
--- /dev/null
+++ b/tools/perf/util/pager.c
@@ -0,0 +1,99 @@
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
12#ifndef __MINGW32__
13static void pager_preexec(void)
14{
15 /*
16 * Work around bug in "less" by not starting it until we
17 * have real input
18 */
19 fd_set in;
20
21 FD_ZERO(&in);
22 FD_SET(0, &in);
23 select(1, &in, NULL, &in, NULL);
24
25 setenv("LESS", "FRSX", 0);
26}
27#endif
28
29static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
30static struct child_process pager_process;
31
32static void wait_for_pager(void)
33{
34 fflush(stdout);
35 fflush(stderr);
36 /* signal EOF to pager */
37 close(1);
38 close(2);
39 finish_command(&pager_process);
40}
41
42static void wait_for_pager_signal(int signo)
43{
44 wait_for_pager();
45 sigchain_pop(signo);
46 raise(signo);
47}
48
49void setup_pager(void)
50{
51 const char *pager = getenv("PERF_PAGER");
52
53 if (!isatty(1))
54 return;
55 if (!pager) {
56 if (!pager_program)
57 perf_config(perf_default_config, NULL);
58 pager = pager_program;
59 }
60 if (!pager)
61 pager = getenv("PAGER");
62 if (!pager)
63 pager = "less";
64 else if (!*pager || !strcmp(pager, "cat"))
65 return;
66
67 spawned_pager = 1; /* means we are emitting to terminal */
68
69 /* spawn the pager */
70 pager_argv[2] = pager;
71 pager_process.argv = pager_argv;
72 pager_process.in = -1;
73#ifndef __MINGW32__
74 pager_process.preexec_cb = pager_preexec;
75#endif
76 if (start_command(&pager_process))
77 return;
78
79 /* original process continues, but writes to the pipe */
80 dup2(pager_process.in, 1);
81 if (isatty(2))
82 dup2(pager_process.in, 2);
83 close(pager_process.in);
84
85 /* this makes sure that the parent terminates after the pager */
86 sigchain_push_common(wait_for_pager_signal);
87 atexit(wait_for_pager);
88}
89
90int pager_in_use(void)
91{
92 const char *env;
93
94 if (spawned_pager)
95 return 1;
96
97 env = getenv("PERF_PAGER_IN_USE");
98 return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
99}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
new file mode 100644
index 000000000000..9d5f1ca50e6f
--- /dev/null
+++ b/tools/perf/util/parse-events.c
@@ -0,0 +1,316 @@
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
9extern char *strcasestr(const char *haystack, const char *needle);
10
11int nr_counters;
12
13struct perf_counter_attr attrs[MAX_COUNTERS];
14
15struct event_symbol {
16 __u8 type;
17 __u64 config;
18 char *symbol;
19};
20
21#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y
22#define CR(x, y) .type = PERF_TYPE_##x, .config = y
23
24static struct event_symbol event_symbols[] = {
25 { C(HARDWARE, HW_CPU_CYCLES), "cpu-cycles", },
26 { C(HARDWARE, HW_CPU_CYCLES), "cycles", },
27 { C(HARDWARE, HW_INSTRUCTIONS), "instructions", },
28 { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", },
29 { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", },
30 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", },
31 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", },
32 { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", },
33 { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", },
34
35 { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", },
36 { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", },
37 { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", },
38 { C(SOFTWARE, SW_PAGE_FAULTS), "faults", },
39 { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", },
40 { C(SOFTWARE, SW_PAGE_FAULTS_MAJ), "major-faults", },
41 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "context-switches", },
42 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "cs", },
43 { C(SOFTWARE, SW_CPU_MIGRATIONS), "cpu-migrations", },
44 { C(SOFTWARE, SW_CPU_MIGRATIONS), "migrations", },
45};
46
47#define __PERF_COUNTER_FIELD(config, name) \
48 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
49
50#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
51#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
52#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
53#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
54
55static char *hw_event_names[] = {
56 "cycles",
57 "instructions",
58 "cache-references",
59 "cache-misses",
60 "branches",
61 "branch-misses",
62 "bus-cycles",
63};
64
65static char *sw_event_names[] = {
66 "cpu-clock-ticks",
67 "task-clock-ticks",
68 "page-faults",
69 "context-switches",
70 "CPU-migrations",
71 "minor-faults",
72 "major-faults",
73};
74
75#define MAX_ALIASES 8
76
77static char *hw_cache [][MAX_ALIASES] = {
78 { "L1-data" , "l1-d", "l1d", "l1" },
79 { "L1-instruction" , "l1-i", "l1i" },
80 { "L2" , "l2" },
81 { "Data-TLB" , "dtlb", "d-tlb" },
82 { "Instruction-TLB" , "itlb", "i-tlb" },
83 { "Branch" , "bpu" , "btb", "bpc" },
84};
85
86static char *hw_cache_op [][MAX_ALIASES] = {
87 { "Load" , "read" },
88 { "Store" , "write" },
89 { "Prefetch" , "speculative-read", "speculative-load" },
90};
91
92static char *hw_cache_result [][MAX_ALIASES] = {
93 { "Reference" , "ops", "access" },
94 { "Miss" },
95};
96
97char *event_name(int counter)
98{
99 __u64 config = attrs[counter].config;
100 int type = attrs[counter].type;
101 static char buf[32];
102
103 if (attrs[counter].type == PERF_TYPE_RAW) {
104 sprintf(buf, "raw 0x%llx", config);
105 return buf;
106 }
107
108 switch (type) {
109 case PERF_TYPE_HARDWARE:
110 if (config < PERF_COUNT_HW_MAX)
111 return hw_event_names[config];
112 return "unknown-hardware";
113
114 case PERF_TYPE_HW_CACHE: {
115 __u8 cache_type, cache_op, cache_result;
116 static char name[100];
117
118 cache_type = (config >> 0) & 0xff;
119 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
120 return "unknown-ext-hardware-cache-type";
121
122 cache_op = (config >> 8) & 0xff;
123 if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
124 return "unknown-ext-hardware-cache-op";
125
126 cache_result = (config >> 16) & 0xff;
127 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
128 return "unknown-ext-hardware-cache-result";
129
130 sprintf(name, "%s-Cache-%s-%ses",
131 hw_cache[cache_type][0],
132 hw_cache_op[cache_op][0],
133 hw_cache_result[cache_result][0]);
134
135 return name;
136 }
137
138 case PERF_TYPE_SOFTWARE:
139 if (config < PERF_COUNT_SW_MAX)
140 return sw_event_names[config];
141 return "unknown-software";
142
143 default:
144 break;
145 }
146
147 return "unknown";
148}
149
150static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
151{
152 int i, j;
153
154 for (i = 0; i < size; i++) {
155 for (j = 0; j < MAX_ALIASES; j++) {
156 if (!names[i][j])
157 break;
158 if (strcasestr(str, names[i][j]))
159 return i;
160 }
161 }
162
163 return -1;
164}
165
166static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
167{
168 int cache_type = -1, cache_op = 0, cache_result = 0;
169
170 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX);
171 /*
172 * No fallback - if we cannot get a clear cache type
173 * then bail out:
174 */
175 if (cache_type == -1)
176 return -EINVAL;
177
178 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
179 /*
180 * Fall back to reads:
181 */
182 if (cache_op == -1)
183 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
184
185 cache_result = parse_aliases(str, hw_cache_result,
186 PERF_COUNT_HW_CACHE_RESULT_MAX);
187 /*
188 * Fall back to accesses:
189 */
190 if (cache_result == -1)
191 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
192
193 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
194 attr->type = PERF_TYPE_HW_CACHE;
195
196 return 0;
197}
198
199/*
200 * Each event can have multiple symbolic names.
201 * Symbolic names are (almost) exactly matched.
202 */
203static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
204{
205 __u64 config, id;
206 int type;
207 unsigned int i;
208 const char *sep, *pstr;
209
210 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
211 attr->type = PERF_TYPE_RAW;
212 attr->config = config;
213
214 return 0;
215 }
216
217 pstr = str;
218 sep = strchr(pstr, ':');
219 if (sep) {
220 type = atoi(pstr);
221 pstr = sep + 1;
222 id = atoi(pstr);
223 sep = strchr(pstr, ':');
224 if (sep) {
225 pstr = sep + 1;
226 if (strchr(pstr, 'k'))
227 attr->exclude_user = 1;
228 if (strchr(pstr, 'u'))
229 attr->exclude_kernel = 1;
230 }
231 attr->type = type;
232 attr->config = id;
233
234 return 0;
235 }
236
237 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
238 if (!strncmp(str, event_symbols[i].symbol,
239 strlen(event_symbols[i].symbol))) {
240
241 attr->type = event_symbols[i].type;
242 attr->config = event_symbols[i].config;
243
244 return 0;
245 }
246 }
247
248 return parse_generic_hw_symbols(str, attr);
249}
250
251int parse_events(const struct option *opt, const char *str, int unset)
252{
253 struct perf_counter_attr attr;
254 int ret;
255
256 memset(&attr, 0, sizeof(attr));
257again:
258 if (nr_counters == MAX_COUNTERS)
259 return -1;
260
261 ret = parse_event_symbols(str, &attr);
262 if (ret < 0)
263 return ret;
264
265 attrs[nr_counters] = attr;
266 nr_counters++;
267
268 str = strstr(str, ",");
269 if (str) {
270 str++;
271 goto again;
272 }
273
274 return 0;
275}
276
277static const char * const event_type_descriptors[] = {
278 "",
279 "Hardware event",
280 "Software event",
281 "Tracepoint event",
282 "Hardware cache event",
283};
284
285/*
286 * Print the help text for the event symbols:
287 */
288void print_events(void)
289{
290 struct event_symbol *syms = event_symbols;
291 unsigned int i, type, prev_type = -1;
292
293 fprintf(stderr, "\n");
294 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
295
296 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
297 type = syms->type + 1;
298 if (type > ARRAY_SIZE(event_type_descriptors))
299 type = 0;
300
301 if (type != prev_type)
302 fprintf(stderr, "\n");
303
304 fprintf(stderr, " %-30s [%s]\n", syms->symbol,
305 event_type_descriptors[type]);
306
307 prev_type = type;
308 }
309
310 fprintf(stderr, "\n");
311 fprintf(stderr, " %-30s [raw hardware event descriptor]\n",
312 "rNNN");
313 fprintf(stderr, "\n");
314
315 exit(129);
316}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
new file mode 100644
index 000000000000..e3d552908e60
--- /dev/null
+++ b/tools/perf/util/parse-events.h
@@ -0,0 +1,17 @@
1
2/*
3 * Parse symbolic events/counts passed in as options:
4 */
5
6extern int nr_counters;
7
8extern struct perf_counter_attr attrs[MAX_COUNTERS];
9
10extern char *event_name(int ctr);
11
12extern int parse_events(const struct option *opt, const char *str, int unset);
13
14#define EVENTS_HELP_MAX (128*1024)
15
16extern void print_events(void);
17
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
new file mode 100644
index 000000000000..b3affb1658d2
--- /dev/null
+++ b/tools/perf/util/parse-options.c
@@ -0,0 +1,508 @@
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 (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
24 *arg = (const char *)opt->defval;
25 } else if (p->argc > 1) {
26 p->argc--;
27 *arg = *++p->argv;
28 } else
29 return opterror(opt, "requires a value", flags);
30 return 0;
31}
32
33static int get_value(struct parse_opt_ctx_t *p,
34 const struct option *opt, int flags)
35{
36 const char *s, *arg = NULL;
37 const int unset = flags & OPT_UNSET;
38
39 if (unset && p->opt)
40 return opterror(opt, "takes no value", flags);
41 if (unset && (opt->flags & PARSE_OPT_NONEG))
42 return opterror(opt, "isn't available", flags);
43
44 if (!(flags & OPT_SHORT) && p->opt) {
45 switch (opt->type) {
46 case OPTION_CALLBACK:
47 if (!(opt->flags & PARSE_OPT_NOARG))
48 break;
49 /* FALLTHROUGH */
50 case OPTION_BOOLEAN:
51 case OPTION_BIT:
52 case OPTION_SET_INT:
53 case OPTION_SET_PTR:
54 return opterror(opt, "takes no value", flags);
55 default:
56 break;
57 }
58 }
59
60 switch (opt->type) {
61 case OPTION_BIT:
62 if (unset)
63 *(int *)opt->value &= ~opt->defval;
64 else
65 *(int *)opt->value |= opt->defval;
66 return 0;
67
68 case OPTION_BOOLEAN:
69 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
70 return 0;
71
72 case OPTION_SET_INT:
73 *(int *)opt->value = unset ? 0 : opt->defval;
74 return 0;
75
76 case OPTION_SET_PTR:
77 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
78 return 0;
79
80 case OPTION_STRING:
81 if (unset)
82 *(const char **)opt->value = NULL;
83 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
84 *(const char **)opt->value = (const char *)opt->defval;
85 else
86 return get_arg(p, opt, flags, (const char **)opt->value);
87 return 0;
88
89 case OPTION_CALLBACK:
90 if (unset)
91 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
92 if (opt->flags & PARSE_OPT_NOARG)
93 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
94 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
95 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
96 if (get_arg(p, opt, flags, &arg))
97 return -1;
98 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
99
100 case OPTION_INTEGER:
101 if (unset) {
102 *(int *)opt->value = 0;
103 return 0;
104 }
105 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
106 *(int *)opt->value = opt->defval;
107 return 0;
108 }
109 if (get_arg(p, opt, flags, &arg))
110 return -1;
111 *(int *)opt->value = strtol(arg, (char **)&s, 10);
112 if (*s)
113 return opterror(opt, "expects a numerical value", flags);
114 return 0;
115
116 case OPTION_LONG:
117 if (unset) {
118 *(long *)opt->value = 0;
119 return 0;
120 }
121 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
122 *(long *)opt->value = opt->defval;
123 return 0;
124 }
125 if (get_arg(p, opt, flags, &arg))
126 return -1;
127 *(long *)opt->value = strtol(arg, (char **)&s, 10);
128 if (*s)
129 return opterror(opt, "expects a numerical value", flags);
130 return 0;
131
132 default:
133 die("should not happen, someone must be hit on the forehead");
134 }
135}
136
137static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
138{
139 for (; options->type != OPTION_END; options++) {
140 if (options->short_name == *p->opt) {
141 p->opt = p->opt[1] ? p->opt + 1 : NULL;
142 return get_value(p, options, OPT_SHORT);
143 }
144 }
145 return -2;
146}
147
148static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
149 const struct option *options)
150{
151 const char *arg_end = strchr(arg, '=');
152 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
153 int abbrev_flags = 0, ambiguous_flags = 0;
154
155 if (!arg_end)
156 arg_end = arg + strlen(arg);
157
158 for (; options->type != OPTION_END; options++) {
159 const char *rest;
160 int flags = 0;
161
162 if (!options->long_name)
163 continue;
164
165 rest = skip_prefix(arg, options->long_name);
166 if (options->type == OPTION_ARGUMENT) {
167 if (!rest)
168 continue;
169 if (*rest == '=')
170 return opterror(options, "takes no value", flags);
171 if (*rest)
172 continue;
173 p->out[p->cpidx++] = arg - 2;
174 return 0;
175 }
176 if (!rest) {
177 /* abbreviated? */
178 if (!strncmp(options->long_name, arg, arg_end - arg)) {
179is_abbreviated:
180 if (abbrev_option) {
181 /*
182 * If this is abbreviated, it is
183 * ambiguous. So when there is no
184 * exact match later, we need to
185 * error out.
186 */
187 ambiguous_option = abbrev_option;
188 ambiguous_flags = abbrev_flags;
189 }
190 if (!(flags & OPT_UNSET) && *arg_end)
191 p->opt = arg_end + 1;
192 abbrev_option = options;
193 abbrev_flags = flags;
194 continue;
195 }
196 /* negated and abbreviated very much? */
197 if (!prefixcmp("no-", arg)) {
198 flags |= OPT_UNSET;
199 goto is_abbreviated;
200 }
201 /* negated? */
202 if (strncmp(arg, "no-", 3))
203 continue;
204 flags |= OPT_UNSET;
205 rest = skip_prefix(arg + 3, options->long_name);
206 /* abbreviated and negated? */
207 if (!rest && !prefixcmp(options->long_name, arg + 3))
208 goto is_abbreviated;
209 if (!rest)
210 continue;
211 }
212 if (*rest) {
213 if (*rest != '=')
214 continue;
215 p->opt = rest + 1;
216 }
217 return get_value(p, options, flags);
218 }
219
220 if (ambiguous_option)
221 return error("Ambiguous option: %s "
222 "(could be --%s%s or --%s%s)",
223 arg,
224 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
225 ambiguous_option->long_name,
226 (abbrev_flags & OPT_UNSET) ? "no-" : "",
227 abbrev_option->long_name);
228 if (abbrev_option)
229 return get_value(p, abbrev_option, abbrev_flags);
230 return -2;
231}
232
233static void check_typos(const char *arg, const struct option *options)
234{
235 if (strlen(arg) < 3)
236 return;
237
238 if (!prefixcmp(arg, "no-")) {
239 error ("did you mean `--%s` (with two dashes ?)", arg);
240 exit(129);
241 }
242
243 for (; options->type != OPTION_END; options++) {
244 if (!options->long_name)
245 continue;
246 if (!prefixcmp(options->long_name, arg)) {
247 error ("did you mean `--%s` (with two dashes ?)", arg);
248 exit(129);
249 }
250 }
251}
252
253void parse_options_start(struct parse_opt_ctx_t *ctx,
254 int argc, const char **argv, int flags)
255{
256 memset(ctx, 0, sizeof(*ctx));
257 ctx->argc = argc - 1;
258 ctx->argv = argv + 1;
259 ctx->out = argv;
260 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
261 ctx->flags = flags;
262 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
263 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
264 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
265}
266
267static int usage_with_options_internal(const char * const *,
268 const struct option *, int);
269
270int parse_options_step(struct parse_opt_ctx_t *ctx,
271 const struct option *options,
272 const char * const usagestr[])
273{
274 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
275
276 /* we must reset ->opt, unknown short option leave it dangling */
277 ctx->opt = NULL;
278
279 for (; ctx->argc; ctx->argc--, ctx->argv++) {
280 const char *arg = ctx->argv[0];
281
282 if (*arg != '-' || !arg[1]) {
283 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
284 break;
285 ctx->out[ctx->cpidx++] = ctx->argv[0];
286 continue;
287 }
288
289 if (arg[1] != '-') {
290 ctx->opt = arg + 1;
291 if (internal_help && *ctx->opt == 'h')
292 return parse_options_usage(usagestr, options);
293 switch (parse_short_opt(ctx, options)) {
294 case -1:
295 return parse_options_usage(usagestr, options);
296 case -2:
297 goto unknown;
298 }
299 if (ctx->opt)
300 check_typos(arg + 1, options);
301 while (ctx->opt) {
302 if (internal_help && *ctx->opt == 'h')
303 return parse_options_usage(usagestr, options);
304 switch (parse_short_opt(ctx, options)) {
305 case -1:
306 return parse_options_usage(usagestr, options);
307 case -2:
308 /* fake a short option thing to hide the fact that we may have
309 * started to parse aggregated stuff
310 *
311 * This is leaky, too bad.
312 */
313 ctx->argv[0] = strdup(ctx->opt - 1);
314 *(char *)ctx->argv[0] = '-';
315 goto unknown;
316 }
317 }
318 continue;
319 }
320
321 if (!arg[2]) { /* "--" */
322 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
323 ctx->argc--;
324 ctx->argv++;
325 }
326 break;
327 }
328
329 if (internal_help && !strcmp(arg + 2, "help-all"))
330 return usage_with_options_internal(usagestr, options, 1);
331 if (internal_help && !strcmp(arg + 2, "help"))
332 return parse_options_usage(usagestr, options);
333 switch (parse_long_opt(ctx, arg + 2, options)) {
334 case -1:
335 return parse_options_usage(usagestr, options);
336 case -2:
337 goto unknown;
338 }
339 continue;
340unknown:
341 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
342 return PARSE_OPT_UNKNOWN;
343 ctx->out[ctx->cpidx++] = ctx->argv[0];
344 ctx->opt = NULL;
345 }
346 return PARSE_OPT_DONE;
347}
348
349int parse_options_end(struct parse_opt_ctx_t *ctx)
350{
351 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
352 ctx->out[ctx->cpidx + ctx->argc] = NULL;
353 return ctx->cpidx + ctx->argc;
354}
355
356int parse_options(int argc, const char **argv, const struct option *options,
357 const char * const usagestr[], int flags)
358{
359 struct parse_opt_ctx_t ctx;
360
361 parse_options_start(&ctx, argc, argv, flags);
362 switch (parse_options_step(&ctx, options, usagestr)) {
363 case PARSE_OPT_HELP:
364 exit(129);
365 case PARSE_OPT_DONE:
366 break;
367 default: /* PARSE_OPT_UNKNOWN */
368 if (ctx.argv[0][1] == '-') {
369 error("unknown option `%s'", ctx.argv[0] + 2);
370 } else {
371 error("unknown switch `%c'", *ctx.opt);
372 }
373 usage_with_options(usagestr, options);
374 }
375
376 return parse_options_end(&ctx);
377}
378
379#define USAGE_OPTS_WIDTH 24
380#define USAGE_GAP 2
381
382int usage_with_options_internal(const char * const *usagestr,
383 const struct option *opts, int full)
384{
385 if (!usagestr)
386 return PARSE_OPT_HELP;
387
388 fprintf(stderr, "\n usage: %s\n", *usagestr++);
389 while (*usagestr && **usagestr)
390 fprintf(stderr, " or: %s\n", *usagestr++);
391 while (*usagestr) {
392 fprintf(stderr, "%s%s\n",
393 **usagestr ? " " : "",
394 *usagestr);
395 usagestr++;
396 }
397
398 if (opts->type != OPTION_GROUP)
399 fputc('\n', stderr);
400
401 for (; opts->type != OPTION_END; opts++) {
402 size_t pos;
403 int pad;
404
405 if (opts->type == OPTION_GROUP) {
406 fputc('\n', stderr);
407 if (*opts->help)
408 fprintf(stderr, "%s\n", opts->help);
409 continue;
410 }
411 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
412 continue;
413
414 pos = fprintf(stderr, " ");
415 if (opts->short_name)
416 pos += fprintf(stderr, "-%c", opts->short_name);
417 if (opts->long_name && opts->short_name)
418 pos += fprintf(stderr, ", ");
419 if (opts->long_name)
420 pos += fprintf(stderr, "--%s", opts->long_name);
421
422 switch (opts->type) {
423 case OPTION_ARGUMENT:
424 break;
425 case OPTION_INTEGER:
426 if (opts->flags & PARSE_OPT_OPTARG)
427 if (opts->long_name)
428 pos += fprintf(stderr, "[=<n>]");
429 else
430 pos += fprintf(stderr, "[<n>]");
431 else
432 pos += fprintf(stderr, " <n>");
433 break;
434 case OPTION_CALLBACK:
435 if (opts->flags & PARSE_OPT_NOARG)
436 break;
437 /* FALLTHROUGH */
438 case OPTION_STRING:
439 if (opts->argh) {
440 if (opts->flags & PARSE_OPT_OPTARG)
441 if (opts->long_name)
442 pos += fprintf(stderr, "[=<%s>]", opts->argh);
443 else
444 pos += fprintf(stderr, "[<%s>]", opts->argh);
445 else
446 pos += fprintf(stderr, " <%s>", opts->argh);
447 } else {
448 if (opts->flags & PARSE_OPT_OPTARG)
449 if (opts->long_name)
450 pos += fprintf(stderr, "[=...]");
451 else
452 pos += fprintf(stderr, "[...]");
453 else
454 pos += fprintf(stderr, " ...");
455 }
456 break;
457 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
458 break;
459 }
460
461 if (pos <= USAGE_OPTS_WIDTH)
462 pad = USAGE_OPTS_WIDTH - pos;
463 else {
464 fputc('\n', stderr);
465 pad = USAGE_OPTS_WIDTH;
466 }
467 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
468 }
469 fputc('\n', stderr);
470
471 return PARSE_OPT_HELP;
472}
473
474void usage_with_options(const char * const *usagestr,
475 const struct option *opts)
476{
477 usage_with_options_internal(usagestr, opts, 0);
478 exit(129);
479}
480
481int parse_options_usage(const char * const *usagestr,
482 const struct option *opts)
483{
484 return usage_with_options_internal(usagestr, opts, 0);
485}
486
487
488int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
489 int unset)
490{
491 int *target = opt->value;
492
493 if (unset)
494 /* --no-quiet, --no-verbose */
495 *target = 0;
496 else if (opt->short_name == 'v') {
497 if (*target >= 0)
498 (*target)++;
499 else
500 *target = 1;
501 } else {
502 if (*target <= 0)
503 (*target)--;
504 else
505 *target = -1;
506 }
507 return 0;
508}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
new file mode 100644
index 000000000000..a1039a6ce0eb
--- /dev/null
+++ b/tools/perf/util/parse-options.h
@@ -0,0 +1,174 @@
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() { OPTION_END }
94#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) }
95#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
96#define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
97#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
98#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
100#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
101#define OPT_LONG(s, l, v, h) { OPTION_LONG, (s), (l), (v), NULL, (h) }
102#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
103#define OPT_DATE(s, l, v, h) \
104 { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \
105 parse_opt_approxidate_cb }
106#define OPT_CALLBACK(s, l, v, a, h, f) \
107 { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
108
109/* parse_options() will filter out the processed options and leave the
110 * non-option argments in argv[].
111 * Returns the number of arguments left in argv[].
112 */
113extern int parse_options(int argc, const char **argv,
114 const struct option *options,
115 const char * const usagestr[], int flags);
116
117extern NORETURN void usage_with_options(const char * const *usagestr,
118 const struct option *options);
119
120/*----- incremantal advanced APIs -----*/
121
122enum {
123 PARSE_OPT_HELP = -1,
124 PARSE_OPT_DONE,
125 PARSE_OPT_UNKNOWN,
126};
127
128/*
129 * It's okay for the caller to consume argv/argc in the usual way.
130 * Other fields of that structure are private to parse-options and should not
131 * be modified in any way.
132 */
133struct parse_opt_ctx_t {
134 const char **argv;
135 const char **out;
136 int argc, cpidx;
137 const char *opt;
138 int flags;
139};
140
141extern int parse_options_usage(const char * const *usagestr,
142 const struct option *opts);
143
144extern void parse_options_start(struct parse_opt_ctx_t *ctx,
145 int argc, const char **argv, int flags);
146
147extern int parse_options_step(struct parse_opt_ctx_t *ctx,
148 const struct option *options,
149 const char * const usagestr[]);
150
151extern int parse_options_end(struct parse_opt_ctx_t *ctx);
152
153
154/*----- some often used options -----*/
155extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
156extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
157extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
158
159#define OPT__VERBOSE(var) OPT_BOOLEAN('v', "verbose", (var), "be verbose")
160#define OPT__QUIET(var) OPT_BOOLEAN('q', "quiet", (var), "be quiet")
161#define OPT__VERBOSITY(var) \
162 { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
163 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
164 { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
165 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
166#define OPT__DRY_RUN(var) OPT_BOOLEAN('n', "dry-run", (var), "dry run")
167#define OPT__ABBREV(var) \
168 { OPTION_CALLBACK, 0, "abbrev", (var), "n", \
169 "use <n> digits to display SHA-1s", \
170 PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
171
172extern const char *parse_options_fix_filename(const char *prefix, const char *file);
173
174#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..f18c5212bc92
--- /dev/null
+++ b/tools/perf/util/quote.c
@@ -0,0 +1,481 @@
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/* returns the longest prefix not needing a quote up to maxlen if positive.
166 This stops at the first \0 because it's marked as a character needing an
167 escape */
168static size_t next_quote_pos(const char *s, ssize_t maxlen)
169{
170 size_t len;
171 if (maxlen < 0) {
172 for (len = 0; !sq_must_quote(s[len]); len++);
173 } else {
174 for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
175 }
176 return len;
177}
178
179/*
180 * C-style name quoting.
181 *
182 * (1) if sb and fp are both NULL, inspect the input name and counts the
183 * number of bytes that are needed to hold c_style quoted version of name,
184 * counting the double quotes around it but not terminating NUL, and
185 * returns it.
186 * However, if name does not need c_style quoting, it returns 0.
187 *
188 * (2) if sb or fp are not NULL, it emits the c_style quoted version
189 * of name, enclosed with double quotes if asked and needed only.
190 * Return value is the same as in (1).
191 */
192static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
193 struct strbuf *sb, FILE *fp, int no_dq)
194{
195#undef EMIT
196#define EMIT(c) \
197 do { \
198 if (sb) strbuf_addch(sb, (c)); \
199 if (fp) fputc((c), fp); \
200 count++; \
201 } while (0)
202#define EMITBUF(s, l) \
203 do { \
204 int __ret; \
205 if (sb) strbuf_add(sb, (s), (l)); \
206 if (fp) __ret = fwrite((s), (l), 1, fp); \
207 count += (l); \
208 } while (0)
209
210 size_t len, count = 0;
211 const char *p = name;
212
213 for (;;) {
214 int ch;
215
216 len = next_quote_pos(p, maxlen);
217 if (len == maxlen || !p[len])
218 break;
219
220 if (!no_dq && p == name)
221 EMIT('"');
222
223 EMITBUF(p, len);
224 EMIT('\\');
225 p += len;
226 ch = (unsigned char)*p++;
227 if (sq_lookup[ch] >= ' ') {
228 EMIT(sq_lookup[ch]);
229 } else {
230 EMIT(((ch >> 6) & 03) + '0');
231 EMIT(((ch >> 3) & 07) + '0');
232 EMIT(((ch >> 0) & 07) + '0');
233 }
234 }
235
236 EMITBUF(p, len);
237 if (p == name) /* no ending quote needed */
238 return 0;
239
240 if (!no_dq)
241 EMIT('"');
242 return count;
243}
244
245size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
246{
247 return quote_c_style_counted(name, -1, sb, fp, nodq);
248}
249
250void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq)
251{
252 if (quote_c_style(prefix, NULL, NULL, 0) ||
253 quote_c_style(path, NULL, NULL, 0)) {
254 if (!nodq)
255 strbuf_addch(sb, '"');
256 quote_c_style(prefix, sb, NULL, 1);
257 quote_c_style(path, sb, NULL, 1);
258 if (!nodq)
259 strbuf_addch(sb, '"');
260 } else {
261 strbuf_addstr(sb, prefix);
262 strbuf_addstr(sb, path);
263 }
264}
265
266void write_name_quoted(const char *name, FILE *fp, int terminator)
267{
268 if (terminator) {
269 quote_c_style(name, NULL, fp, 0);
270 } else {
271 fputs(name, fp);
272 }
273 fputc(terminator, fp);
274}
275
276extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
277 const char *name, FILE *fp, int terminator)
278{
279 int needquote = 0;
280
281 if (terminator) {
282 needquote = next_quote_pos(pfx, pfxlen) < pfxlen
283 || name[next_quote_pos(name, -1)];
284 }
285 if (needquote) {
286 fputc('"', fp);
287 quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
288 quote_c_style(name, NULL, fp, 1);
289 fputc('"', fp);
290 } else {
291 int ret;
292
293 ret = fwrite(pfx, pfxlen, 1, fp);
294 fputs(name, fp);
295 }
296 fputc(terminator, fp);
297}
298
299/* quote path as relative to the given prefix */
300char *quote_path_relative(const char *in, int len,
301 struct strbuf *out, const char *prefix)
302{
303 int needquote;
304
305 if (len < 0)
306 len = strlen(in);
307
308 /* "../" prefix itself does not need quoting, but "in" might. */
309 needquote = next_quote_pos(in, len) < len;
310 strbuf_setlen(out, 0);
311 strbuf_grow(out, len);
312
313 if (needquote)
314 strbuf_addch(out, '"');
315 if (prefix) {
316 int off = 0;
317 while (prefix[off] && off < len && prefix[off] == in[off])
318 if (prefix[off] == '/') {
319 prefix += off + 1;
320 in += off + 1;
321 len -= off + 1;
322 off = 0;
323 } else
324 off++;
325
326 for (; *prefix; prefix++)
327 if (*prefix == '/')
328 strbuf_addstr(out, "../");
329 }
330
331 quote_c_style_counted (in, len, out, NULL, 1);
332
333 if (needquote)
334 strbuf_addch(out, '"');
335 if (!out->len)
336 strbuf_addstr(out, "./");
337
338 return out->buf;
339}
340
341/*
342 * C-style name unquoting.
343 *
344 * Quoted should point at the opening double quote.
345 * + Returns 0 if it was able to unquote the string properly, and appends the
346 * result in the strbuf `sb'.
347 * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
348 * that this function will allocate memory in the strbuf, so calling
349 * strbuf_release is mandatory whichever result unquote_c_style returns.
350 *
351 * Updates endp pointer to point at one past the ending double quote if given.
352 */
353int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
354{
355 size_t oldlen = sb->len, len;
356 int ch, ac;
357
358 if (*quoted++ != '"')
359 return -1;
360
361 for (;;) {
362 len = strcspn(quoted, "\"\\");
363 strbuf_add(sb, quoted, len);
364 quoted += len;
365
366 switch (*quoted++) {
367 case '"':
368 if (endp)
369 *endp = quoted;
370 return 0;
371 case '\\':
372 break;
373 default:
374 goto error;
375 }
376
377 switch ((ch = *quoted++)) {
378 case 'a': ch = '\a'; break;
379 case 'b': ch = '\b'; break;
380 case 'f': ch = '\f'; break;
381 case 'n': ch = '\n'; break;
382 case 'r': ch = '\r'; break;
383 case 't': ch = '\t'; break;
384 case 'v': ch = '\v'; break;
385
386 case '\\': case '"':
387 break; /* verbatim */
388
389 /* octal values with first digit over 4 overflow */
390 case '0': case '1': case '2': case '3':
391 ac = ((ch - '0') << 6);
392 if ((ch = *quoted++) < '0' || '7' < ch)
393 goto error;
394 ac |= ((ch - '0') << 3);
395 if ((ch = *quoted++) < '0' || '7' < ch)
396 goto error;
397 ac |= (ch - '0');
398 ch = ac;
399 break;
400 default:
401 goto error;
402 }
403 strbuf_addch(sb, ch);
404 }
405
406 error:
407 strbuf_setlen(sb, oldlen);
408 return -1;
409}
410
411/* quoting as a string literal for other languages */
412
413void perl_quote_print(FILE *stream, const char *src)
414{
415 const char sq = '\'';
416 const char bq = '\\';
417 char c;
418
419 fputc(sq, stream);
420 while ((c = *src++)) {
421 if (c == sq || c == bq)
422 fputc(bq, stream);
423 fputc(c, stream);
424 }
425 fputc(sq, stream);
426}
427
428void python_quote_print(FILE *stream, const char *src)
429{
430 const char sq = '\'';
431 const char bq = '\\';
432 const char nl = '\n';
433 char c;
434
435 fputc(sq, stream);
436 while ((c = *src++)) {
437 if (c == nl) {
438 fputc(bq, stream);
439 fputc('n', stream);
440 continue;
441 }
442 if (c == sq || c == bq)
443 fputc(bq, stream);
444 fputc(c, stream);
445 }
446 fputc(sq, stream);
447}
448
449void tcl_quote_print(FILE *stream, const char *src)
450{
451 char c;
452
453 fputc('"', stream);
454 while ((c = *src++)) {
455 switch (c) {
456 case '[': case ']':
457 case '{': case '}':
458 case '$': case '\\': case '"':
459 fputc('\\', stream);
460 default:
461 fputc(c, stream);
462 break;
463 case '\f':
464 fputs("\\f", stream);
465 break;
466 case '\r':
467 fputs("\\r", stream);
468 break;
469 case '\n':
470 fputs("\\n", stream);
471 break;
472 case '\t':
473 fputs("\\t", stream);
474 break;
475 case '\v':
476 fputs("\\v", stream);
477 break;
478 }
479 }
480 fputc('"', stream);
481}
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
new file mode 100644
index 000000000000..5dfad89816db
--- /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, size_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/rbtree.c b/tools/perf/util/rbtree.c
new file mode 100644
index 000000000000..b15ba9c7cb3f
--- /dev/null
+++ b/tools/perf/util/rbtree.c
@@ -0,0 +1,383 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4 (C) 2002 David Woodhouse <dwmw2@infradead.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 linux/lib/rbtree.c
21*/
22
23#include "rbtree.h"
24
25static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
26{
27 struct rb_node *right = node->rb_right;
28 struct rb_node *parent = rb_parent(node);
29
30 if ((node->rb_right = right->rb_left))
31 rb_set_parent(right->rb_left, node);
32 right->rb_left = node;
33
34 rb_set_parent(right, parent);
35
36 if (parent)
37 {
38 if (node == parent->rb_left)
39 parent->rb_left = right;
40 else
41 parent->rb_right = right;
42 }
43 else
44 root->rb_node = right;
45 rb_set_parent(node, right);
46}
47
48static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
49{
50 struct rb_node *left = node->rb_left;
51 struct rb_node *parent = rb_parent(node);
52
53 if ((node->rb_left = left->rb_right))
54 rb_set_parent(left->rb_right, node);
55 left->rb_right = node;
56
57 rb_set_parent(left, parent);
58
59 if (parent)
60 {
61 if (node == parent->rb_right)
62 parent->rb_right = left;
63 else
64 parent->rb_left = left;
65 }
66 else
67 root->rb_node = left;
68 rb_set_parent(node, left);
69}
70
71void rb_insert_color(struct rb_node *node, struct rb_root *root)
72{
73 struct rb_node *parent, *gparent;
74
75 while ((parent = rb_parent(node)) && rb_is_red(parent))
76 {
77 gparent = rb_parent(parent);
78
79 if (parent == gparent->rb_left)
80 {
81 {
82 register struct rb_node *uncle = gparent->rb_right;
83 if (uncle && rb_is_red(uncle))
84 {
85 rb_set_black(uncle);
86 rb_set_black(parent);
87 rb_set_red(gparent);
88 node = gparent;
89 continue;
90 }
91 }
92
93 if (parent->rb_right == node)
94 {
95 register struct rb_node *tmp;
96 __rb_rotate_left(parent, root);
97 tmp = parent;
98 parent = node;
99 node = tmp;
100 }
101
102 rb_set_black(parent);
103 rb_set_red(gparent);
104 __rb_rotate_right(gparent, root);
105 } else {
106 {
107 register struct rb_node *uncle = gparent->rb_left;
108 if (uncle && rb_is_red(uncle))
109 {
110 rb_set_black(uncle);
111 rb_set_black(parent);
112 rb_set_red(gparent);
113 node = gparent;
114 continue;
115 }
116 }
117
118 if (parent->rb_left == node)
119 {
120 register struct rb_node *tmp;
121 __rb_rotate_right(parent, root);
122 tmp = parent;
123 parent = node;
124 node = tmp;
125 }
126
127 rb_set_black(parent);
128 rb_set_red(gparent);
129 __rb_rotate_left(gparent, root);
130 }
131 }
132
133 rb_set_black(root->rb_node);
134}
135
136static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
137 struct rb_root *root)
138{
139 struct rb_node *other;
140
141 while ((!node || rb_is_black(node)) && node != root->rb_node)
142 {
143 if (parent->rb_left == node)
144 {
145 other = parent->rb_right;
146 if (rb_is_red(other))
147 {
148 rb_set_black(other);
149 rb_set_red(parent);
150 __rb_rotate_left(parent, root);
151 other = parent->rb_right;
152 }
153 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
154 (!other->rb_right || rb_is_black(other->rb_right)))
155 {
156 rb_set_red(other);
157 node = parent;
158 parent = rb_parent(node);
159 }
160 else
161 {
162 if (!other->rb_right || rb_is_black(other->rb_right))
163 {
164 rb_set_black(other->rb_left);
165 rb_set_red(other);
166 __rb_rotate_right(other, root);
167 other = parent->rb_right;
168 }
169 rb_set_color(other, rb_color(parent));
170 rb_set_black(parent);
171 rb_set_black(other->rb_right);
172 __rb_rotate_left(parent, root);
173 node = root->rb_node;
174 break;
175 }
176 }
177 else
178 {
179 other = parent->rb_left;
180 if (rb_is_red(other))
181 {
182 rb_set_black(other);
183 rb_set_red(parent);
184 __rb_rotate_right(parent, root);
185 other = parent->rb_left;
186 }
187 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
188 (!other->rb_right || rb_is_black(other->rb_right)))
189 {
190 rb_set_red(other);
191 node = parent;
192 parent = rb_parent(node);
193 }
194 else
195 {
196 if (!other->rb_left || rb_is_black(other->rb_left))
197 {
198 rb_set_black(other->rb_right);
199 rb_set_red(other);
200 __rb_rotate_left(other, root);
201 other = parent->rb_left;
202 }
203 rb_set_color(other, rb_color(parent));
204 rb_set_black(parent);
205 rb_set_black(other->rb_left);
206 __rb_rotate_right(parent, root);
207 node = root->rb_node;
208 break;
209 }
210 }
211 }
212 if (node)
213 rb_set_black(node);
214}
215
216void rb_erase(struct rb_node *node, struct rb_root *root)
217{
218 struct rb_node *child, *parent;
219 int color;
220
221 if (!node->rb_left)
222 child = node->rb_right;
223 else if (!node->rb_right)
224 child = node->rb_left;
225 else
226 {
227 struct rb_node *old = node, *left;
228
229 node = node->rb_right;
230 while ((left = node->rb_left) != NULL)
231 node = left;
232 child = node->rb_right;
233 parent = rb_parent(node);
234 color = rb_color(node);
235
236 if (child)
237 rb_set_parent(child, parent);
238 if (parent == old) {
239 parent->rb_right = child;
240 parent = node;
241 } else
242 parent->rb_left = child;
243
244 node->rb_parent_color = old->rb_parent_color;
245 node->rb_right = old->rb_right;
246 node->rb_left = old->rb_left;
247
248 if (rb_parent(old))
249 {
250 if (rb_parent(old)->rb_left == old)
251 rb_parent(old)->rb_left = node;
252 else
253 rb_parent(old)->rb_right = node;
254 } else
255 root->rb_node = node;
256
257 rb_set_parent(old->rb_left, node);
258 if (old->rb_right)
259 rb_set_parent(old->rb_right, node);
260 goto color;
261 }
262
263 parent = rb_parent(node);
264 color = rb_color(node);
265
266 if (child)
267 rb_set_parent(child, parent);
268 if (parent)
269 {
270 if (parent->rb_left == node)
271 parent->rb_left = child;
272 else
273 parent->rb_right = child;
274 }
275 else
276 root->rb_node = child;
277
278 color:
279 if (color == RB_BLACK)
280 __rb_erase_color(child, parent, root);
281}
282
283/*
284 * This function returns the first node (in sort order) of the tree.
285 */
286struct rb_node *rb_first(const struct rb_root *root)
287{
288 struct rb_node *n;
289
290 n = root->rb_node;
291 if (!n)
292 return NULL;
293 while (n->rb_left)
294 n = n->rb_left;
295 return n;
296}
297
298struct rb_node *rb_last(const struct rb_root *root)
299{
300 struct rb_node *n;
301
302 n = root->rb_node;
303 if (!n)
304 return NULL;
305 while (n->rb_right)
306 n = n->rb_right;
307 return n;
308}
309
310struct rb_node *rb_next(const struct rb_node *node)
311{
312 struct rb_node *parent;
313
314 if (rb_parent(node) == node)
315 return NULL;
316
317 /* If we have a right-hand child, go down and then left as far
318 as we can. */
319 if (node->rb_right) {
320 node = node->rb_right;
321 while (node->rb_left)
322 node=node->rb_left;
323 return (struct rb_node *)node;
324 }
325
326 /* No right-hand children. Everything down and left is
327 smaller than us, so any 'next' node must be in the general
328 direction of our parent. Go up the tree; any time the
329 ancestor is a right-hand child of its parent, keep going
330 up. First time it's a left-hand child of its parent, said
331 parent is our 'next' node. */
332 while ((parent = rb_parent(node)) && node == parent->rb_right)
333 node = parent;
334
335 return parent;
336}
337
338struct rb_node *rb_prev(const struct rb_node *node)
339{
340 struct rb_node *parent;
341
342 if (rb_parent(node) == node)
343 return NULL;
344
345 /* If we have a left-hand child, go down and then right as far
346 as we can. */
347 if (node->rb_left) {
348 node = node->rb_left;
349 while (node->rb_right)
350 node=node->rb_right;
351 return (struct rb_node *)node;
352 }
353
354 /* No left-hand children. Go up till we find an ancestor which
355 is a right-hand child of its parent */
356 while ((parent = rb_parent(node)) && node == parent->rb_left)
357 node = parent;
358
359 return parent;
360}
361
362void rb_replace_node(struct rb_node *victim, struct rb_node *new,
363 struct rb_root *root)
364{
365 struct rb_node *parent = rb_parent(victim);
366
367 /* Set the surrounding nodes to point to the replacement */
368 if (parent) {
369 if (victim == parent->rb_left)
370 parent->rb_left = new;
371 else
372 parent->rb_right = new;
373 } else {
374 root->rb_node = new;
375 }
376 if (victim->rb_left)
377 rb_set_parent(victim->rb_left, new);
378 if (victim->rb_right)
379 rb_set_parent(victim->rb_right, new);
380
381 /* Copy the pointers/colour from the victim to the replacement */
382 *new = *victim;
383}
diff --git a/tools/perf/util/rbtree.h b/tools/perf/util/rbtree.h
new file mode 100644
index 000000000000..6bdc488a47fb
--- /dev/null
+++ b/tools/perf/util/rbtree.h
@@ -0,0 +1,171 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 linux/include/linux/rbtree.h
20
21 To use rbtrees you'll have to implement your own insert and search cores.
22 This will avoid us to use callbacks and to drop drammatically performances.
23 I know it's not the cleaner way, but in C (not in C++) to get
24 performances and genericity...
25
26 Some example of insert and search follows here. The search is a plain
27 normal search over an ordered tree. The insert instead must be implemented
28 int two steps: as first thing the code must insert the element in
29 order as a red leaf in the tree, then the support library function
30 rb_insert_color() must be called. Such function will do the
31 not trivial work to rebalance the rbtree if necessary.
32
33-----------------------------------------------------------------------
34static inline struct page * rb_search_page_cache(struct inode * inode,
35 unsigned long offset)
36{
37 struct rb_node * n = inode->i_rb_page_cache.rb_node;
38 struct page * page;
39
40 while (n)
41 {
42 page = rb_entry(n, struct page, rb_page_cache);
43
44 if (offset < page->offset)
45 n = n->rb_left;
46 else if (offset > page->offset)
47 n = n->rb_right;
48 else
49 return page;
50 }
51 return NULL;
52}
53
54static inline struct page * __rb_insert_page_cache(struct inode * inode,
55 unsigned long offset,
56 struct rb_node * node)
57{
58 struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
59 struct rb_node * parent = NULL;
60 struct page * page;
61
62 while (*p)
63 {
64 parent = *p;
65 page = rb_entry(parent, struct page, rb_page_cache);
66
67 if (offset < page->offset)
68 p = &(*p)->rb_left;
69 else if (offset > page->offset)
70 p = &(*p)->rb_right;
71 else
72 return page;
73 }
74
75 rb_link_node(node, parent, p);
76
77 return NULL;
78}
79
80static inline struct page * rb_insert_page_cache(struct inode * inode,
81 unsigned long offset,
82 struct rb_node * node)
83{
84 struct page * ret;
85 if ((ret = __rb_insert_page_cache(inode, offset, node)))
86 goto out;
87 rb_insert_color(node, &inode->i_rb_page_cache);
88 out:
89 return ret;
90}
91-----------------------------------------------------------------------
92*/
93
94#ifndef _LINUX_RBTREE_H
95#define _LINUX_RBTREE_H
96
97#include <stddef.h>
98
99/**
100 * container_of - cast a member of a structure out to the containing structure
101 * @ptr: the pointer to the member.
102 * @type: the type of the container struct this is embedded in.
103 * @member: the name of the member within the struct.
104 *
105 */
106#define container_of(ptr, type, member) ({ \
107 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
108 (type *)( (char *)__mptr - offsetof(type,member) );})
109
110struct rb_node
111{
112 unsigned long rb_parent_color;
113#define RB_RED 0
114#define RB_BLACK 1
115 struct rb_node *rb_right;
116 struct rb_node *rb_left;
117} __attribute__((aligned(sizeof(long))));
118 /* The alignment might seem pointless, but allegedly CRIS needs it */
119
120struct rb_root
121{
122 struct rb_node *rb_node;
123};
124
125
126#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
127#define rb_color(r) ((r)->rb_parent_color & 1)
128#define rb_is_red(r) (!rb_color(r))
129#define rb_is_black(r) rb_color(r)
130#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
131#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
132
133static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
134{
135 rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
136}
137static inline void rb_set_color(struct rb_node *rb, int color)
138{
139 rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
140}
141
142#define RB_ROOT (struct rb_root) { NULL, }
143#define rb_entry(ptr, type, member) container_of(ptr, type, member)
144
145#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
146#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
147#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
148
149extern void rb_insert_color(struct rb_node *, struct rb_root *);
150extern void rb_erase(struct rb_node *, struct rb_root *);
151
152/* Find logical next and previous nodes in a tree */
153extern struct rb_node *rb_next(const struct rb_node *);
154extern struct rb_node *rb_prev(const struct rb_node *);
155extern struct rb_node *rb_first(const struct rb_root *);
156extern struct rb_node *rb_last(const struct rb_root *);
157
158/* Fast replacement of a single node without remove/rebalance/add/rebalance */
159extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
160 struct rb_root *root);
161
162static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
163 struct rb_node ** rb_link)
164{
165 node->rb_parent_color = (unsigned long )parent;
166 node->rb_left = node->rb_right = NULL;
167
168 *rb_link = node;
169}
170
171#endif /* _LINUX_RBTREE_H */
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
new file mode 100644
index 000000000000..b2f5e854f40a
--- /dev/null
+++ b/tools/perf/util/run-command.c
@@ -0,0 +1,395 @@
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#ifndef __MINGW32__
69 fflush(NULL);
70 cmd->pid = fork();
71 if (!cmd->pid) {
72 if (cmd->no_stdin)
73 dup_devnull(0);
74 else if (need_in) {
75 dup2(fdin[0], 0);
76 close_pair(fdin);
77 } else if (cmd->in) {
78 dup2(cmd->in, 0);
79 close(cmd->in);
80 }
81
82 if (cmd->no_stderr)
83 dup_devnull(2);
84 else if (need_err) {
85 dup2(fderr[1], 2);
86 close_pair(fderr);
87 }
88
89 if (cmd->no_stdout)
90 dup_devnull(1);
91 else if (cmd->stdout_to_stderr)
92 dup2(2, 1);
93 else if (need_out) {
94 dup2(fdout[1], 1);
95 close_pair(fdout);
96 } else if (cmd->out > 1) {
97 dup2(cmd->out, 1);
98 close(cmd->out);
99 }
100
101 if (cmd->dir && chdir(cmd->dir))
102 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
103 cmd->dir, strerror(errno));
104 if (cmd->env) {
105 for (; *cmd->env; cmd->env++) {
106 if (strchr(*cmd->env, '='))
107 putenv((char*)*cmd->env);
108 else
109 unsetenv(*cmd->env);
110 }
111 }
112 if (cmd->preexec_cb)
113 cmd->preexec_cb();
114 if (cmd->perf_cmd) {
115 execv_perf_cmd(cmd->argv);
116 } else {
117 execvp(cmd->argv[0], (char *const*) cmd->argv);
118 }
119 exit(127);
120 }
121#else
122 int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
123 const char **sargv = cmd->argv;
124 char **env = environ;
125
126 if (cmd->no_stdin) {
127 s0 = dup(0);
128 dup_devnull(0);
129 } else if (need_in) {
130 s0 = dup(0);
131 dup2(fdin[0], 0);
132 } else if (cmd->in) {
133 s0 = dup(0);
134 dup2(cmd->in, 0);
135 }
136
137 if (cmd->no_stderr) {
138 s2 = dup(2);
139 dup_devnull(2);
140 } else if (need_err) {
141 s2 = dup(2);
142 dup2(fderr[1], 2);
143 }
144
145 if (cmd->no_stdout) {
146 s1 = dup(1);
147 dup_devnull(1);
148 } else if (cmd->stdout_to_stderr) {
149 s1 = dup(1);
150 dup2(2, 1);
151 } else if (need_out) {
152 s1 = dup(1);
153 dup2(fdout[1], 1);
154 } else if (cmd->out > 1) {
155 s1 = dup(1);
156 dup2(cmd->out, 1);
157 }
158
159 if (cmd->dir)
160 die("chdir in start_command() not implemented");
161 if (cmd->env) {
162 env = copy_environ();
163 for (; *cmd->env; cmd->env++)
164 env = env_setenv(env, *cmd->env);
165 }
166
167 if (cmd->perf_cmd) {
168 cmd->argv = prepare_perf_cmd(cmd->argv);
169 }
170
171 cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
172
173 if (cmd->env)
174 free_environ(env);
175 if (cmd->perf_cmd)
176 free(cmd->argv);
177
178 cmd->argv = sargv;
179 if (s0 >= 0)
180 dup2(s0, 0), close(s0);
181 if (s1 >= 0)
182 dup2(s1, 1), close(s1);
183 if (s2 >= 0)
184 dup2(s2, 2), close(s2);
185#endif
186
187 if (cmd->pid < 0) {
188 int err = errno;
189 if (need_in)
190 close_pair(fdin);
191 else if (cmd->in)
192 close(cmd->in);
193 if (need_out)
194 close_pair(fdout);
195 else if (cmd->out)
196 close(cmd->out);
197 if (need_err)
198 close_pair(fderr);
199 return err == ENOENT ?
200 -ERR_RUN_COMMAND_EXEC :
201 -ERR_RUN_COMMAND_FORK;
202 }
203
204 if (need_in)
205 close(fdin[0]);
206 else if (cmd->in)
207 close(cmd->in);
208
209 if (need_out)
210 close(fdout[1]);
211 else if (cmd->out)
212 close(cmd->out);
213
214 if (need_err)
215 close(fderr[1]);
216
217 return 0;
218}
219
220static int wait_or_whine(pid_t pid)
221{
222 for (;;) {
223 int status, code;
224 pid_t waiting = waitpid(pid, &status, 0);
225
226 if (waiting < 0) {
227 if (errno == EINTR)
228 continue;
229 error("waitpid failed (%s)", strerror(errno));
230 return -ERR_RUN_COMMAND_WAITPID;
231 }
232 if (waiting != pid)
233 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
234 if (WIFSIGNALED(status))
235 return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
236
237 if (!WIFEXITED(status))
238 return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
239 code = WEXITSTATUS(status);
240 switch (code) {
241 case 127:
242 return -ERR_RUN_COMMAND_EXEC;
243 case 0:
244 return 0;
245 default:
246 return -code;
247 }
248 }
249}
250
251int finish_command(struct child_process *cmd)
252{
253 return wait_or_whine(cmd->pid);
254}
255
256int run_command(struct child_process *cmd)
257{
258 int code = start_command(cmd);
259 if (code)
260 return code;
261 return finish_command(cmd);
262}
263
264static void prepare_run_command_v_opt(struct child_process *cmd,
265 const char **argv,
266 int opt)
267{
268 memset(cmd, 0, sizeof(*cmd));
269 cmd->argv = argv;
270 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
271 cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
272 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
273}
274
275int run_command_v_opt(const char **argv, int opt)
276{
277 struct child_process cmd;
278 prepare_run_command_v_opt(&cmd, argv, opt);
279 return run_command(&cmd);
280}
281
282int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
283{
284 struct child_process cmd;
285 prepare_run_command_v_opt(&cmd, argv, opt);
286 cmd.dir = dir;
287 cmd.env = env;
288 return run_command(&cmd);
289}
290
291#ifdef __MINGW32__
292static __stdcall unsigned run_thread(void *data)
293{
294 struct async *async = data;
295 return async->proc(async->fd_for_proc, async->data);
296}
297#endif
298
299int start_async(struct async *async)
300{
301 int pipe_out[2];
302
303 if (pipe(pipe_out) < 0)
304 return error("cannot create pipe: %s", strerror(errno));
305 async->out = pipe_out[0];
306
307#ifndef __MINGW32__
308 /* Flush stdio before fork() to avoid cloning buffers */
309 fflush(NULL);
310
311 async->pid = fork();
312 if (async->pid < 0) {
313 error("fork (async) failed: %s", strerror(errno));
314 close_pair(pipe_out);
315 return -1;
316 }
317 if (!async->pid) {
318 close(pipe_out[0]);
319 exit(!!async->proc(pipe_out[1], async->data));
320 }
321 close(pipe_out[1]);
322#else
323 async->fd_for_proc = pipe_out[1];
324 async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
325 if (!async->tid) {
326 error("cannot create thread: %s", strerror(errno));
327 close_pair(pipe_out);
328 return -1;
329 }
330#endif
331 return 0;
332}
333
334int finish_async(struct async *async)
335{
336#ifndef __MINGW32__
337 int ret = 0;
338
339 if (wait_or_whine(async->pid))
340 ret = error("waitpid (async) failed");
341#else
342 DWORD ret = 0;
343 if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
344 ret = error("waiting for thread failed: %lu", GetLastError());
345 else if (!GetExitCodeThread(async->tid, &ret))
346 ret = error("cannot get thread exit code: %lu", GetLastError());
347 CloseHandle(async->tid);
348#endif
349 return ret;
350}
351
352int run_hook(const char *index_file, const char *name, ...)
353{
354 struct child_process hook;
355 const char **argv = NULL, *env[2];
356 char index[PATH_MAX];
357 va_list args;
358 int ret;
359 size_t i = 0, alloc = 0;
360
361 if (access(perf_path("hooks/%s", name), X_OK) < 0)
362 return 0;
363
364 va_start(args, name);
365 ALLOC_GROW(argv, i + 1, alloc);
366 argv[i++] = perf_path("hooks/%s", name);
367 while (argv[i-1]) {
368 ALLOC_GROW(argv, i + 1, alloc);
369 argv[i++] = va_arg(args, const char *);
370 }
371 va_end(args);
372
373 memset(&hook, 0, sizeof(hook));
374 hook.argv = argv;
375 hook.no_stdin = 1;
376 hook.stdout_to_stderr = 1;
377 if (index_file) {
378 snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file);
379 env[0] = index;
380 env[1] = NULL;
381 hook.env = env;
382 }
383
384 ret = start_command(&hook);
385 free(argv);
386 if (ret) {
387 warning("Could not spawn %s", argv[0]);
388 return ret;
389 }
390 ret = finish_command(&hook);
391 if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
392 warning("%s exited due to uncaught signal", argv[0]);
393
394 return ret;
395}
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
new file mode 100644
index 000000000000..328289f23669
--- /dev/null
+++ b/tools/perf/util/run-command.h
@@ -0,0 +1,93 @@
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#ifndef __MINGW32__
83 pid_t pid;
84#else
85 HANDLE tid;
86 int fd_for_proc;
87#endif
88};
89
90int start_async(struct async *async);
91int finish_async(struct async *async);
92
93#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..eaba09306802
--- /dev/null
+++ b/tools/perf/util/strbuf.c
@@ -0,0 +1,359 @@
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, size_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 int i;
96 for (i = 0; i < sb->len; i++)
97 sb->buf[i] = tolower(sb->buf[i]);
98}
99
100struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
101{
102 int alloc = 2, pos = 0;
103 char *n, *p;
104 struct strbuf **ret;
105 struct strbuf *t;
106
107 ret = calloc(alloc, sizeof(struct strbuf *));
108 p = n = sb->buf;
109 while (n < sb->buf + sb->len) {
110 int len;
111 n = memchr(n, delim, sb->len - (n - sb->buf));
112 if (pos + 1 >= alloc) {
113 alloc = alloc * 2;
114 ret = realloc(ret, sizeof(struct strbuf *) * alloc);
115 }
116 if (!n)
117 n = sb->buf + sb->len - 1;
118 len = n - p + 1;
119 t = malloc(sizeof(struct strbuf));
120 strbuf_init(t, len);
121 strbuf_add(t, p, len);
122 ret[pos] = t;
123 ret[++pos] = NULL;
124 p = ++n;
125 }
126 return ret;
127}
128
129void strbuf_list_free(struct strbuf **sbs)
130{
131 struct strbuf **s = sbs;
132
133 while (*s) {
134 strbuf_release(*s);
135 free(*s++);
136 }
137 free(sbs);
138}
139
140int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
141{
142 int len = a->len < b->len ? a->len: b->len;
143 int cmp = memcmp(a->buf, b->buf, len);
144 if (cmp)
145 return cmp;
146 return a->len < b->len ? -1: a->len != b->len;
147}
148
149void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
150 const void *data, size_t dlen)
151{
152 if (pos + len < pos)
153 die("you want to use way too much memory");
154 if (pos > sb->len)
155 die("`pos' is too far after the end of the buffer");
156 if (pos + len > sb->len)
157 die("`pos + len' is too far after the end of the buffer");
158
159 if (dlen >= len)
160 strbuf_grow(sb, dlen - len);
161 memmove(sb->buf + pos + dlen,
162 sb->buf + pos + len,
163 sb->len - pos - len);
164 memcpy(sb->buf + pos, data, dlen);
165 strbuf_setlen(sb, sb->len + dlen - len);
166}
167
168void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
169{
170 strbuf_splice(sb, pos, 0, data, len);
171}
172
173void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
174{
175 strbuf_splice(sb, pos, len, NULL, 0);
176}
177
178void strbuf_add(struct strbuf *sb, const void *data, size_t len)
179{
180 strbuf_grow(sb, len);
181 memcpy(sb->buf + sb->len, data, len);
182 strbuf_setlen(sb, sb->len + len);
183}
184
185void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
186{
187 strbuf_grow(sb, len);
188 memcpy(sb->buf + sb->len, sb->buf + pos, len);
189 strbuf_setlen(sb, sb->len + len);
190}
191
192void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
193{
194 int len;
195 va_list ap;
196
197 if (!strbuf_avail(sb))
198 strbuf_grow(sb, 64);
199 va_start(ap, fmt);
200 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
201 va_end(ap);
202 if (len < 0)
203 die("your vsnprintf is broken");
204 if (len > strbuf_avail(sb)) {
205 strbuf_grow(sb, len);
206 va_start(ap, fmt);
207 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
208 va_end(ap);
209 if (len > strbuf_avail(sb)) {
210 die("this should not happen, your snprintf is broken");
211 }
212 }
213 strbuf_setlen(sb, sb->len + len);
214}
215
216void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
217 void *context)
218{
219 for (;;) {
220 const char *percent;
221 size_t consumed;
222
223 percent = strchrnul(format, '%');
224 strbuf_add(sb, format, percent - format);
225 if (!*percent)
226 break;
227 format = percent + 1;
228
229 consumed = fn(sb, format, context);
230 if (consumed)
231 format += consumed;
232 else
233 strbuf_addch(sb, '%');
234 }
235}
236
237size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
238 void *context)
239{
240 struct strbuf_expand_dict_entry *e = context;
241 size_t len;
242
243 for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
244 if (!strncmp(placeholder, e->placeholder, len)) {
245 if (e->value)
246 strbuf_addstr(sb, e->value);
247 return len;
248 }
249 }
250 return 0;
251}
252
253size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
254{
255 size_t res;
256 size_t oldalloc = sb->alloc;
257
258 strbuf_grow(sb, size);
259 res = fread(sb->buf + sb->len, 1, size, f);
260 if (res > 0)
261 strbuf_setlen(sb, sb->len + res);
262 else if (res < 0 && oldalloc == 0)
263 strbuf_release(sb);
264 return res;
265}
266
267ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
268{
269 size_t oldlen = sb->len;
270 size_t oldalloc = sb->alloc;
271
272 strbuf_grow(sb, hint ? hint : 8192);
273 for (;;) {
274 ssize_t cnt;
275
276 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
277 if (cnt < 0) {
278 if (oldalloc == 0)
279 strbuf_release(sb);
280 else
281 strbuf_setlen(sb, oldlen);
282 return -1;
283 }
284 if (!cnt)
285 break;
286 sb->len += cnt;
287 strbuf_grow(sb, 8192);
288 }
289
290 sb->buf[sb->len] = '\0';
291 return sb->len - oldlen;
292}
293
294#define STRBUF_MAXLINK (2*PATH_MAX)
295
296int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
297{
298 size_t oldalloc = sb->alloc;
299
300 if (hint < 32)
301 hint = 32;
302
303 while (hint < STRBUF_MAXLINK) {
304 int len;
305
306 strbuf_grow(sb, hint);
307 len = readlink(path, sb->buf, hint);
308 if (len < 0) {
309 if (errno != ERANGE)
310 break;
311 } else if (len < hint) {
312 strbuf_setlen(sb, len);
313 return 0;
314 }
315
316 /* .. the buffer was too small - try again */
317 hint *= 2;
318 }
319 if (oldalloc == 0)
320 strbuf_release(sb);
321 return -1;
322}
323
324int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
325{
326 int ch;
327
328 strbuf_grow(sb, 0);
329 if (feof(fp))
330 return EOF;
331
332 strbuf_reset(sb);
333 while ((ch = fgetc(fp)) != EOF) {
334 if (ch == term)
335 break;
336 strbuf_grow(sb, 1);
337 sb->buf[sb->len++] = ch;
338 }
339 if (ch == EOF && sb->len == 0)
340 return EOF;
341
342 sb->buf[sb->len] = '\0';
343 return 0;
344}
345
346int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
347{
348 int fd, len;
349
350 fd = open(path, O_RDONLY);
351 if (fd < 0)
352 return -1;
353 len = strbuf_read(sb, fd, hint);
354 close(fd);
355 if (len < 0)
356 return -1;
357
358 return len;
359}
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
new file mode 100644
index 000000000000..9ee908a3ec5d
--- /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 *, size_t);
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 size_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, size_t hint);
126extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
127extern int strbuf_readlink(struct strbuf *sb, const char *path, size_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..ec33c0c7f4e2
--- /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..72812c1c9a7a
--- /dev/null
+++ b/tools/perf/util/string.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_STRING_H_
2#define _PERF_STRING_H_
3
4#include <linux/types.h>
5
6int hex2u64(const char *ptr, __u64 *val);
7
8#endif
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
new file mode 100644
index 000000000000..49a55f813712
--- /dev/null
+++ b/tools/perf/util/symbol.c
@@ -0,0 +1,641 @@
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
12static struct symbol *symbol__new(__u64 start, __u64 len,
13 const char *name, unsigned int priv_size,
14 __u64 obj_start, int verbose)
15{
16 size_t namelen = strlen(name) + 1;
17 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
18
19 if (!self)
20 return NULL;
21
22 if (verbose >= 2)
23 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
24 (__u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
25
26 self->obj_start= obj_start;
27 self->hist = NULL;
28 self->hist_sum = 0;
29
30 if (sym_hist_filter && !strcmp(name, sym_hist_filter))
31 self->hist = calloc(sizeof(__u64), len);
32
33 if (priv_size) {
34 memset(self, 0, priv_size);
35 self = ((void *)self) + priv_size;
36 }
37 self->start = start;
38 self->end = start + len - 1;
39 memcpy(self->name, name, namelen);
40
41 return self;
42}
43
44static void symbol__delete(struct symbol *self, unsigned int priv_size)
45{
46 free(((void *)self) - priv_size);
47}
48
49static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50{
51 return fprintf(fp, " %llx-%llx %s\n",
52 self->start, self->end, self->name);
53}
54
55struct dso *dso__new(const char *name, unsigned int sym_priv_size)
56{
57 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
58
59 if (self != NULL) {
60 strcpy(self->name, name);
61 self->syms = RB_ROOT;
62 self->sym_priv_size = sym_priv_size;
63 self->find_symbol = dso__find_symbol;
64 }
65
66 return self;
67}
68
69static void dso__delete_symbols(struct dso *self)
70{
71 struct symbol *pos;
72 struct rb_node *next = rb_first(&self->syms);
73
74 while (next) {
75 pos = rb_entry(next, struct symbol, rb_node);
76 next = rb_next(&pos->rb_node);
77 rb_erase(&pos->rb_node, &self->syms);
78 symbol__delete(pos, self->sym_priv_size);
79 }
80}
81
82void dso__delete(struct dso *self)
83{
84 dso__delete_symbols(self);
85 free(self);
86}
87
88static void dso__insert_symbol(struct dso *self, struct symbol *sym)
89{
90 struct rb_node **p = &self->syms.rb_node;
91 struct rb_node *parent = NULL;
92 const __u64 ip = sym->start;
93 struct symbol *s;
94
95 while (*p != NULL) {
96 parent = *p;
97 s = rb_entry(parent, struct symbol, rb_node);
98 if (ip < s->start)
99 p = &(*p)->rb_left;
100 else
101 p = &(*p)->rb_right;
102 }
103 rb_link_node(&sym->rb_node, parent, p);
104 rb_insert_color(&sym->rb_node, &self->syms);
105}
106
107struct symbol *dso__find_symbol(struct dso *self, __u64 ip)
108{
109 struct rb_node *n;
110
111 if (self == NULL)
112 return NULL;
113
114 n = self->syms.rb_node;
115
116 while (n) {
117 struct symbol *s = rb_entry(n, struct symbol, rb_node);
118
119 if (ip < s->start)
120 n = n->rb_left;
121 else if (ip > s->end)
122 n = n->rb_right;
123 else
124 return s;
125 }
126
127 return NULL;
128}
129
130size_t dso__fprintf(struct dso *self, FILE *fp)
131{
132 size_t ret = fprintf(fp, "dso: %s\n", self->name);
133
134 struct rb_node *nd;
135 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
136 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
137 ret += symbol__fprintf(pos, fp);
138 }
139
140 return ret;
141}
142
143static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
144{
145 struct rb_node *nd, *prevnd;
146 char *line = NULL;
147 size_t n;
148 FILE *file = fopen("/proc/kallsyms", "r");
149
150 if (file == NULL)
151 goto out_failure;
152
153 while (!feof(file)) {
154 __u64 start;
155 struct symbol *sym;
156 int line_len, len;
157 char symbol_type;
158
159 line_len = getline(&line, &n, file);
160 if (line_len < 0)
161 break;
162
163 if (!line)
164 goto out_failure;
165
166 line[--line_len] = '\0'; /* \n */
167
168 len = hex2u64(line, &start);
169
170 len++;
171 if (len + 2 >= line_len)
172 continue;
173
174 symbol_type = toupper(line[len]);
175 /*
176 * We're interested only in code ('T'ext)
177 */
178 if (symbol_type != 'T' && symbol_type != 'W')
179 continue;
180 /*
181 * Well fix up the end later, when we have all sorted.
182 */
183 sym = symbol__new(start, 0xdead, line + len + 2,
184 self->sym_priv_size, 0, verbose);
185
186 if (sym == NULL)
187 goto out_delete_line;
188
189 if (filter && filter(self, sym))
190 symbol__delete(sym, self->sym_priv_size);
191 else
192 dso__insert_symbol(self, sym);
193 }
194
195 /*
196 * Now that we have all sorted out, just set the ->end of all
197 * symbols
198 */
199 prevnd = rb_first(&self->syms);
200
201 if (prevnd == NULL)
202 goto out_delete_line;
203
204 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
205 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
206 *curr = rb_entry(nd, struct symbol, rb_node);
207
208 prev->end = curr->start - 1;
209 prevnd = nd;
210 }
211
212 free(line);
213 fclose(file);
214
215 return 0;
216
217out_delete_line:
218 free(line);
219out_failure:
220 return -1;
221}
222
223static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
224{
225 char *line = NULL;
226 size_t n;
227 FILE *file;
228 int nr_syms = 0;
229
230 file = fopen(self->name, "r");
231 if (file == NULL)
232 goto out_failure;
233
234 while (!feof(file)) {
235 __u64 start, size;
236 struct symbol *sym;
237 int line_len, len;
238
239 line_len = getline(&line, &n, file);
240 if (line_len < 0)
241 break;
242
243 if (!line)
244 goto out_failure;
245
246 line[--line_len] = '\0'; /* \n */
247
248 len = hex2u64(line, &start);
249
250 len++;
251 if (len + 2 >= line_len)
252 continue;
253
254 len += hex2u64(line + len, &size);
255
256 len++;
257 if (len + 2 >= line_len)
258 continue;
259
260 sym = symbol__new(start, size, line + len,
261 self->sym_priv_size, start, verbose);
262
263 if (sym == NULL)
264 goto out_delete_line;
265
266 if (filter && filter(self, sym))
267 symbol__delete(sym, self->sym_priv_size);
268 else {
269 dso__insert_symbol(self, sym);
270 nr_syms++;
271 }
272 }
273
274 free(line);
275 fclose(file);
276
277 return nr_syms;
278
279out_delete_line:
280 free(line);
281out_failure:
282 return -1;
283}
284
285/**
286 * elf_symtab__for_each_symbol - iterate thru all the symbols
287 *
288 * @self: struct elf_symtab instance to iterate
289 * @index: uint32_t index
290 * @sym: GElf_Sym iterator
291 */
292#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
293 for (index = 0, gelf_getsym(syms, index, &sym);\
294 index < nr_syms; \
295 index++, gelf_getsym(syms, index, &sym))
296
297static inline uint8_t elf_sym__type(const GElf_Sym *sym)
298{
299 return GELF_ST_TYPE(sym->st_info);
300}
301
302static inline int elf_sym__is_function(const GElf_Sym *sym)
303{
304 return elf_sym__type(sym) == STT_FUNC &&
305 sym->st_name != 0 &&
306 sym->st_shndx != SHN_UNDEF &&
307 sym->st_size != 0;
308}
309
310static inline const char *elf_sym__name(const GElf_Sym *sym,
311 const Elf_Data *symstrs)
312{
313 return symstrs->d_buf + sym->st_name;
314}
315
316static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
317 GElf_Shdr *shp, const char *name,
318 size_t *index)
319{
320 Elf_Scn *sec = NULL;
321 size_t cnt = 1;
322
323 while ((sec = elf_nextscn(elf, sec)) != NULL) {
324 char *str;
325
326 gelf_getshdr(sec, shp);
327 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
328 if (!strcmp(name, str)) {
329 if (index)
330 *index = cnt;
331 break;
332 }
333 ++cnt;
334 }
335
336 return sec;
337}
338
339#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
340 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
341 idx < nr_entries; \
342 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
343
344#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
345 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
346 idx < nr_entries; \
347 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
348
349static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
350 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
351 GElf_Shdr *shdr_dynsym,
352 size_t dynsym_idx, int verbose)
353{
354 uint32_t nr_rel_entries, idx;
355 GElf_Sym sym;
356 __u64 plt_offset;
357 GElf_Shdr shdr_plt;
358 struct symbol *f;
359 GElf_Shdr shdr_rel_plt;
360 Elf_Data *reldata, *syms, *symstrs;
361 Elf_Scn *scn_plt_rel, *scn_symstrs;
362 char sympltname[1024];
363 int nr = 0, symidx;
364
365 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
366 ".rela.plt", NULL);
367 if (scn_plt_rel == NULL) {
368 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
369 ".rel.plt", NULL);
370 if (scn_plt_rel == NULL)
371 return 0;
372 }
373
374 if (shdr_rel_plt.sh_link != dynsym_idx)
375 return 0;
376
377 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
378 return 0;
379
380 /*
381 * Fetch the relocation section to find the indexes to the GOT
382 * and the symbols in the .dynsym they refer to.
383 */
384 reldata = elf_getdata(scn_plt_rel, NULL);
385 if (reldata == NULL)
386 return -1;
387
388 syms = elf_getdata(scn_dynsym, NULL);
389 if (syms == NULL)
390 return -1;
391
392 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
393 if (scn_symstrs == NULL)
394 return -1;
395
396 symstrs = elf_getdata(scn_symstrs, NULL);
397 if (symstrs == NULL)
398 return -1;
399
400 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
401 plt_offset = shdr_plt.sh_offset;
402
403 if (shdr_rel_plt.sh_type == SHT_RELA) {
404 GElf_Rela pos_mem, *pos;
405
406 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
407 nr_rel_entries) {
408 symidx = GELF_R_SYM(pos->r_info);
409 plt_offset += shdr_plt.sh_entsize;
410 gelf_getsym(syms, symidx, &sym);
411 snprintf(sympltname, sizeof(sympltname),
412 "%s@plt", elf_sym__name(&sym, symstrs));
413
414 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
415 sympltname, self->sym_priv_size, 0, verbose);
416 if (!f)
417 return -1;
418
419 dso__insert_symbol(self, f);
420 ++nr;
421 }
422 } else if (shdr_rel_plt.sh_type == SHT_REL) {
423 GElf_Rel pos_mem, *pos;
424 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
425 nr_rel_entries) {
426 symidx = GELF_R_SYM(pos->r_info);
427 plt_offset += shdr_plt.sh_entsize;
428 gelf_getsym(syms, symidx, &sym);
429 snprintf(sympltname, sizeof(sympltname),
430 "%s@plt", elf_sym__name(&sym, symstrs));
431
432 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
433 sympltname, self->sym_priv_size, 0, verbose);
434 if (!f)
435 return -1;
436
437 dso__insert_symbol(self, f);
438 ++nr;
439 }
440 } else {
441 /*
442 * TODO: There are still one more shdr_rel_plt.sh_type
443 * I have to investigate, but probably should be ignored.
444 */
445 }
446
447 return nr;
448}
449
450static int dso__load_sym(struct dso *self, int fd, const char *name,
451 symbol_filter_t filter, int verbose)
452{
453 Elf_Data *symstrs;
454 uint32_t nr_syms;
455 int err = -1;
456 uint32_t index;
457 GElf_Ehdr ehdr;
458 GElf_Shdr shdr;
459 Elf_Data *syms;
460 GElf_Sym sym;
461 Elf_Scn *sec, *sec_dynsym;
462 Elf *elf;
463 size_t dynsym_idx;
464 int nr = 0;
465
466 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467 if (elf == NULL) {
468 if (verbose)
469 fprintf(stderr, "%s: cannot read %s ELF file.\n",
470 __func__, name);
471 goto out_close;
472 }
473
474 if (gelf_getehdr(elf, &ehdr) == NULL) {
475 if (verbose)
476 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
477 goto out_elf_end;
478 }
479
480 /*
481 * We need to check if we have a .dynsym, so that we can handle the
482 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
483 * .dynsym or .symtab)
484 */
485 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
486 ".dynsym", &dynsym_idx);
487 if (sec_dynsym != NULL) {
488 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
489 sec_dynsym, &shdr,
490 dynsym_idx, verbose);
491 if (nr < 0)
492 goto out_elf_end;
493 }
494
495 /*
496 * But if we have a full .symtab (that is a superset of .dynsym) we
497 * should add the symbols not in the .dynsyn
498 */
499 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
500 if (sec == NULL) {
501 if (sec_dynsym == NULL)
502 goto out_elf_end;
503
504 sec = sec_dynsym;
505 gelf_getshdr(sec, &shdr);
506 }
507
508 syms = elf_getdata(sec, NULL);
509 if (syms == NULL)
510 goto out_elf_end;
511
512 sec = elf_getscn(elf, shdr.sh_link);
513 if (sec == NULL)
514 goto out_elf_end;
515
516 symstrs = elf_getdata(sec, NULL);
517 if (symstrs == NULL)
518 goto out_elf_end;
519
520 nr_syms = shdr.sh_size / shdr.sh_entsize;
521
522 memset(&sym, 0, sizeof(sym));
523
524 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
525 struct symbol *f;
526 __u64 obj_start;
527
528 if (!elf_sym__is_function(&sym))
529 continue;
530
531 sec = elf_getscn(elf, sym.st_shndx);
532 if (!sec)
533 goto out_elf_end;
534
535 gelf_getshdr(sec, &shdr);
536 obj_start = sym.st_value;
537
538 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
539
540 f = symbol__new(sym.st_value, sym.st_size,
541 elf_sym__name(&sym, symstrs),
542 self->sym_priv_size, obj_start, verbose);
543 if (!f)
544 goto out_elf_end;
545
546 if (filter && filter(self, f))
547 symbol__delete(f, self->sym_priv_size);
548 else {
549 dso__insert_symbol(self, f);
550 nr++;
551 }
552 }
553
554 err = nr;
555out_elf_end:
556 elf_end(elf);
557out_close:
558 return err;
559}
560
561int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
562{
563 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
564 char *name = malloc(size);
565 int variant = 0;
566 int ret = -1;
567 int fd;
568
569 if (!name)
570 return -1;
571
572 if (strncmp(self->name, "/tmp/perf-", 10) == 0)
573 return dso__load_perf_map(self, filter, verbose);
574
575more:
576 do {
577 switch (variant) {
578 case 0: /* Fedora */
579 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
580 break;
581 case 1: /* Ubuntu */
582 snprintf(name, size, "/usr/lib/debug%s", self->name);
583 break;
584 case 2: /* Sane people */
585 snprintf(name, size, "%s", self->name);
586 break;
587
588 default:
589 goto out;
590 }
591 variant++;
592
593 fd = open(name, O_RDONLY);
594 } while (fd < 0);
595
596 ret = dso__load_sym(self, fd, name, filter, verbose);
597 close(fd);
598
599 /*
600 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
601 */
602 if (!ret)
603 goto more;
604
605out:
606 free(name);
607 return ret;
608}
609
610static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
611 symbol_filter_t filter, int verbose)
612{
613 int err, fd = open(vmlinux, O_RDONLY);
614
615 if (fd < 0)
616 return -1;
617
618 err = dso__load_sym(self, fd, vmlinux, filter, verbose);
619 close(fd);
620
621 return err;
622}
623
624int dso__load_kernel(struct dso *self, const char *vmlinux,
625 symbol_filter_t filter, int verbose)
626{
627 int err = -1;
628
629 if (vmlinux)
630 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
631
632 if (err)
633 err = dso__load_kallsyms(self, filter, verbose);
634
635 return err;
636}
637
638void symbol__init(void)
639{
640 elf_version(EV_CURRENT);
641}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
new file mode 100644
index 000000000000..0d1292bd8270
--- /dev/null
+++ b/tools/perf/util/symbol.h
@@ -0,0 +1,47 @@
1#ifndef _PERF_SYMBOL_
2#define _PERF_SYMBOL_ 1
3
4#include <linux/types.h>
5#include "list.h"
6#include "rbtree.h"
7
8struct symbol {
9 struct rb_node rb_node;
10 __u64 start;
11 __u64 end;
12 __u64 obj_start;
13 __u64 hist_sum;
14 __u64 *hist;
15 char name[0];
16};
17
18struct dso {
19 struct list_head node;
20 struct rb_root syms;
21 unsigned int sym_priv_size;
22 struct symbol *(*find_symbol)(struct dso *, __u64 ip);
23 char name[0];
24};
25
26const char *sym_hist_filter;
27
28typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
29
30struct dso *dso__new(const char *name, unsigned int sym_priv_size);
31void dso__delete(struct dso *self);
32
33static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
34{
35 return ((void *)sym) - self->sym_priv_size;
36}
37
38struct symbol *dso__find_symbol(struct dso *self, __u64 ip);
39
40int dso__load_kernel(struct dso *self, const char *vmlinux,
41 symbol_filter_t filter, int verbose);
42int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
43
44size_t dso__fprintf(struct dso *self, FILE *fp);
45
46void symbol__init(void);
47#endif /* _PERF_SYMBOL_ */
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..76590a16c271
--- /dev/null
+++ b/tools/perf/util/util.h
@@ -0,0 +1,410 @@
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 <fcntl.h>
54#include <stddef.h>
55#include <stdlib.h>
56#include <stdarg.h>
57#include <string.h>
58#include <errno.h>
59#include <limits.h>
60#include <sys/param.h>
61#include <sys/types.h>
62#include <dirent.h>
63#include <sys/time.h>
64#include <time.h>
65#include <signal.h>
66#include <fnmatch.h>
67#include <assert.h>
68#include <regex.h>
69#include <utime.h>
70#ifndef __MINGW32__
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#if defined(__CYGWIN__)
85#undef _XOPEN_SOURCE
86#include <grp.h>
87#define _XOPEN_SOURCE 600
88#include "compat/cygwin.h"
89#else
90#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
91#include <grp.h>
92#define _ALL_SOURCE 1
93#endif
94#else /* __MINGW32__ */
95/* pull in Windows compatibility stuff */
96#include "compat/mingw.h"
97#endif /* __MINGW32__ */
98
99#ifndef NO_ICONV
100#include <iconv.h>
101#endif
102
103#ifndef NO_OPENSSL
104#include <openssl/ssl.h>
105#include <openssl/err.h>
106#endif
107
108/* On most systems <limits.h> would have given us this, but
109 * not on some systems (e.g. GNU/Hurd).
110 */
111#ifndef PATH_MAX
112#define PATH_MAX 4096
113#endif
114
115#ifndef PRIuMAX
116#define PRIuMAX "llu"
117#endif
118
119#ifndef PRIu32
120#define PRIu32 "u"
121#endif
122
123#ifndef PRIx32
124#define PRIx32 "x"
125#endif
126
127#ifndef PATH_SEP
128#define PATH_SEP ':'
129#endif
130
131#ifndef STRIP_EXTENSION
132#define STRIP_EXTENSION ""
133#endif
134
135#ifndef has_dos_drive_prefix
136#define has_dos_drive_prefix(path) 0
137#endif
138
139#ifndef is_dir_sep
140#define is_dir_sep(c) ((c) == '/')
141#endif
142
143#ifdef __GNUC__
144#define NORETURN __attribute__((__noreturn__))
145#else
146#define NORETURN
147#ifndef __attribute__
148#define __attribute__(x)
149#endif
150#endif
151
152/* General helper functions */
153extern void usage(const char *err) NORETURN;
154extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
155extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
156extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
157
158extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
159
160extern int prefixcmp(const char *str, const char *prefix);
161extern time_t tm_to_time_t(const struct tm *tm);
162
163static inline const char *skip_prefix(const char *str, const char *prefix)
164{
165 size_t len = strlen(prefix);
166 return strncmp(str, prefix, len) ? NULL : str + len;
167}
168
169#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
170
171#ifndef PROT_READ
172#define PROT_READ 1
173#define PROT_WRITE 2
174#define MAP_PRIVATE 1
175#define MAP_FAILED ((void*)-1)
176#endif
177
178#define mmap git_mmap
179#define munmap git_munmap
180extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
181extern int git_munmap(void *start, size_t length);
182
183#else /* NO_MMAP || USE_WIN32_MMAP */
184
185#include <sys/mman.h>
186
187#endif /* NO_MMAP || USE_WIN32_MMAP */
188
189#ifdef NO_MMAP
190
191/* This value must be multiple of (pagesize * 2) */
192#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
193
194#else /* NO_MMAP */
195
196/* This value must be multiple of (pagesize * 2) */
197#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
198 (sizeof(void*) >= 8 \
199 ? 1 * 1024 * 1024 * 1024 \
200 : 32 * 1024 * 1024)
201
202#endif /* NO_MMAP */
203
204#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
205#define on_disk_bytes(st) ((st).st_size)
206#else
207#define on_disk_bytes(st) ((st).st_blocks * 512)
208#endif
209
210#define DEFAULT_PACKED_GIT_LIMIT \
211 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
212
213#ifdef NO_PREAD
214#define pread git_pread
215extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
216#endif
217/*
218 * Forward decl that will remind us if its twin in cache.h changes.
219 * This function is used in compat/pread.c. But we can't include
220 * cache.h there.
221 */
222extern ssize_t read_in_full(int fd, void *buf, size_t count);
223
224#ifdef NO_SETENV
225#define setenv gitsetenv
226extern int gitsetenv(const char *, const char *, int);
227#endif
228
229#ifdef NO_MKDTEMP
230#define mkdtemp gitmkdtemp
231extern char *gitmkdtemp(char *);
232#endif
233
234#ifdef NO_UNSETENV
235#define unsetenv gitunsetenv
236extern void gitunsetenv(const char *);
237#endif
238
239#ifdef NO_STRCASESTR
240#define strcasestr gitstrcasestr
241extern char *gitstrcasestr(const char *haystack, const char *needle);
242#endif
243
244#ifdef NO_STRLCPY
245#define strlcpy gitstrlcpy
246extern size_t gitstrlcpy(char *, const char *, size_t);
247#endif
248
249#ifdef NO_STRTOUMAX
250#define strtoumax gitstrtoumax
251extern uintmax_t gitstrtoumax(const char *, char **, int);
252#endif
253
254#ifdef NO_HSTRERROR
255#define hstrerror githstrerror
256extern const char *githstrerror(int herror);
257#endif
258
259#ifdef NO_MEMMEM
260#define memmem gitmemmem
261void *gitmemmem(const void *haystack, size_t haystacklen,
262 const void *needle, size_t needlelen);
263#endif
264
265#ifdef FREAD_READS_DIRECTORIES
266#ifdef fopen
267#undef fopen
268#endif
269#define fopen(a,b) git_fopen(a,b)
270extern FILE *git_fopen(const char*, const char*);
271#endif
272
273#ifdef SNPRINTF_RETURNS_BOGUS
274#define snprintf git_snprintf
275extern int git_snprintf(char *str, size_t maxsize,
276 const char *format, ...);
277#define vsnprintf git_vsnprintf
278extern int git_vsnprintf(char *str, size_t maxsize,
279 const char *format, va_list ap);
280#endif
281
282#ifdef __GLIBC_PREREQ
283#if __GLIBC_PREREQ(2, 1)
284#define HAVE_STRCHRNUL
285#endif
286#endif
287
288#ifndef HAVE_STRCHRNUL
289#define strchrnul gitstrchrnul
290static inline char *gitstrchrnul(const char *s, int c)
291{
292 while (*s && *s != c)
293 s++;
294 return (char *)s;
295}
296#endif
297
298/*
299 * Wrappers:
300 */
301extern char *xstrdup(const char *str);
302extern void *xmalloc(size_t size);
303extern void *xmemdupz(const void *data, size_t len);
304extern char *xstrndup(const char *str, size_t len);
305extern void *xrealloc(void *ptr, size_t size);
306extern void *xcalloc(size_t nmemb, size_t size);
307extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
308extern ssize_t xread(int fd, void *buf, size_t len);
309extern ssize_t xwrite(int fd, const void *buf, size_t len);
310extern int xdup(int fd);
311extern FILE *xfdopen(int fd, const char *mode);
312extern int xmkstemp(char *template);
313
314static inline size_t xsize_t(off_t len)
315{
316 return (size_t)len;
317}
318
319static inline int has_extension(const char *filename, const char *ext)
320{
321 size_t len = strlen(filename);
322 size_t extlen = strlen(ext);
323 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
324}
325
326/* Sane ctype - no locale, and works with signed chars */
327#undef isascii
328#undef isspace
329#undef isdigit
330#undef isalpha
331#undef isalnum
332#undef tolower
333#undef toupper
334extern unsigned char sane_ctype[256];
335#define GIT_SPACE 0x01
336#define GIT_DIGIT 0x02
337#define GIT_ALPHA 0x04
338#define GIT_GLOB_SPECIAL 0x08
339#define GIT_REGEX_SPECIAL 0x10
340#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
341#define isascii(x) (((x) & ~0x7f) == 0)
342#define isspace(x) sane_istest(x,GIT_SPACE)
343#define isdigit(x) sane_istest(x,GIT_DIGIT)
344#define isalpha(x) sane_istest(x,GIT_ALPHA)
345#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
346#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
347#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
348#define tolower(x) sane_case((unsigned char)(x), 0x20)
349#define toupper(x) sane_case((unsigned char)(x), 0)
350
351static inline int sane_case(int x, int high)
352{
353 if (sane_istest(x, GIT_ALPHA))
354 x = (x & ~0x20) | high;
355 return x;
356}
357
358static inline int strtoul_ui(char const *s, int base, unsigned int *result)
359{
360 unsigned long ul;
361 char *p;
362
363 errno = 0;
364 ul = strtoul(s, &p, base);
365 if (errno || *p || p == s || (unsigned int) ul != ul)
366 return -1;
367 *result = ul;
368 return 0;
369}
370
371static inline int strtol_i(char const *s, int base, int *result)
372{
373 long ul;
374 char *p;
375
376 errno = 0;
377 ul = strtol(s, &p, base);
378 if (errno || *p || p == s || (int) ul != ul)
379 return -1;
380 *result = ul;
381 return 0;
382}
383
384#ifdef INTERNAL_QSORT
385void git_qsort(void *base, size_t nmemb, size_t size,
386 int(*compar)(const void *, const void *));
387#define qsort git_qsort
388#endif
389
390#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
391# define FORCE_DIR_SET_GID S_ISGID
392#else
393# define FORCE_DIR_SET_GID 0
394#endif
395
396#ifdef NO_NSEC
397#undef USE_NSEC
398#define ST_CTIME_NSEC(st) 0
399#define ST_MTIME_NSEC(st) 0
400#else
401#ifdef USE_ST_TIMESPEC
402#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
403#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
404#else
405#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
406#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
407#endif
408#endif
409
410#endif
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
new file mode 100644
index 000000000000..6350d65f6d9e
--- /dev/null
+++ b/tools/perf/util/wrapper.c
@@ -0,0 +1,206 @@
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, int flag)
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 return xmemdupz(str, p ? p - str : len);
63}
64
65void *xrealloc(void *ptr, size_t size)
66{
67 void *ret = realloc(ptr, size);
68 if (!ret && !size)
69 ret = realloc(ptr, 1);
70 if (!ret) {
71 release_pack_memory(size, -1);
72 ret = realloc(ptr, size);
73 if (!ret && !size)
74 ret = realloc(ptr, 1);
75 if (!ret)
76 die("Out of memory, realloc failed");
77 }
78 return ret;
79}
80
81void *xcalloc(size_t nmemb, size_t size)
82{
83 void *ret = calloc(nmemb, size);
84 if (!ret && (!nmemb || !size))
85 ret = calloc(1, 1);
86 if (!ret) {
87 release_pack_memory(nmemb * size, -1);
88 ret = calloc(nmemb, size);
89 if (!ret && (!nmemb || !size))
90 ret = calloc(1, 1);
91 if (!ret)
92 die("Out of memory, calloc failed");
93 }
94 return ret;
95}
96
97void *xmmap(void *start, size_t length,
98 int prot, int flags, int fd, off_t offset)
99{
100 void *ret = mmap(start, length, prot, flags, fd, offset);
101 if (ret == MAP_FAILED) {
102 if (!length)
103 return NULL;
104 release_pack_memory(length, fd);
105 ret = mmap(start, length, prot, flags, fd, offset);
106 if (ret == MAP_FAILED)
107 die("Out of memory? mmap failed: %s", strerror(errno));
108 }
109 return ret;
110}
111
112/*
113 * xread() is the same a read(), but it automatically restarts read()
114 * operations with a recoverable error (EAGAIN and EINTR). xread()
115 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
116 */
117ssize_t xread(int fd, void *buf, size_t len)
118{
119 ssize_t nr;
120 while (1) {
121 nr = read(fd, buf, len);
122 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
123 continue;
124 return nr;
125 }
126}
127
128/*
129 * xwrite() is the same a write(), but it automatically restarts write()
130 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
131 * GUARANTEE that "len" bytes is written even if the operation is successful.
132 */
133ssize_t xwrite(int fd, const void *buf, size_t len)
134{
135 ssize_t nr;
136 while (1) {
137 nr = write(fd, buf, len);
138 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
139 continue;
140 return nr;
141 }
142}
143
144ssize_t read_in_full(int fd, void *buf, size_t count)
145{
146 char *p = buf;
147 ssize_t total = 0;
148
149 while (count > 0) {
150 ssize_t loaded = xread(fd, p, count);
151 if (loaded <= 0)
152 return total ? total : loaded;
153 count -= loaded;
154 p += loaded;
155 total += loaded;
156 }
157
158 return total;
159}
160
161ssize_t write_in_full(int fd, const void *buf, size_t count)
162{
163 const char *p = buf;
164 ssize_t total = 0;
165
166 while (count > 0) {
167 ssize_t written = xwrite(fd, p, count);
168 if (written < 0)
169 return -1;
170 if (!written) {
171 errno = ENOSPC;
172 return -1;
173 }
174 count -= written;
175 p += written;
176 total += written;
177 }
178
179 return total;
180}
181
182int xdup(int fd)
183{
184 int ret = dup(fd);
185 if (ret < 0)
186 die("dup failed: %s", strerror(errno));
187 return ret;
188}
189
190FILE *xfdopen(int fd, const char *mode)
191{
192 FILE *stream = fdopen(fd, mode);
193 if (stream == NULL)
194 die("Out of memory? fdopen failed: %s", strerror(errno));
195 return stream;
196}
197
198int xmkstemp(char *template)
199{
200 int fd;
201
202 fd = mkstemp(template);
203 if (fd < 0)
204 die("Unable to create temporary file: %s", strerror(errno));
205 return fd;
206}