1 #include "../perf.h"
2 #include "util.h"
3 #include <sys/mman.h>
4 #ifdef BACKTRACE_SUPPORT
5 #include <execinfo.h>
6 #endif
7 #include <stdio.h>
8 #include <stdlib.h>
9 
10 /*
11  * XXX We need to find a better place for these things...
12  */
13 unsigned int page_size;
14 
15 bool test_attr__enabled;
16 
17 bool perf_host  = true;
18 bool perf_guest = false;
19 
20 char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
21 
event_attr_init(struct perf_event_attr * attr)22 void event_attr_init(struct perf_event_attr *attr)
23 {
24 	if (!perf_host)
25 		attr->exclude_host  = 1;
26 	if (!perf_guest)
27 		attr->exclude_guest = 1;
28 	/* to capture ABI version */
29 	attr->size = sizeof(*attr);
30 }
31 
mkdir_p(char * path,mode_t mode)32 int mkdir_p(char *path, mode_t mode)
33 {
34 	struct stat st;
35 	int err;
36 	char *d = path;
37 
38 	if (*d != '/')
39 		return -1;
40 
41 	if (stat(path, &st) == 0)
42 		return 0;
43 
44 	while (*++d == '/');
45 
46 	while ((d = strchr(d, '/'))) {
47 		*d = '\0';
48 		err = stat(path, &st) && mkdir(path, mode);
49 		*d++ = '/';
50 		if (err)
51 			return -1;
52 		while (*d == '/')
53 			++d;
54 	}
55 	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
56 }
57 
slow_copyfile(const char * from,const char * to)58 static int slow_copyfile(const char *from, const char *to)
59 {
60 	int err = 0;
61 	char *line = NULL;
62 	size_t n;
63 	FILE *from_fp = fopen(from, "r"), *to_fp;
64 
65 	if (from_fp == NULL)
66 		goto out;
67 
68 	to_fp = fopen(to, "w");
69 	if (to_fp == NULL)
70 		goto out_fclose_from;
71 
72 	while (getline(&line, &n, from_fp) > 0)
73 		if (fputs(line, to_fp) == EOF)
74 			goto out_fclose_to;
75 	err = 0;
76 out_fclose_to:
77 	fclose(to_fp);
78 	free(line);
79 out_fclose_from:
80 	fclose(from_fp);
81 out:
82 	return err;
83 }
84 
copyfile(const char * from,const char * to)85 int copyfile(const char *from, const char *to)
86 {
87 	int fromfd, tofd;
88 	struct stat st;
89 	void *addr;
90 	int err = -1;
91 
92 	if (stat(from, &st))
93 		goto out;
94 
95 	if (st.st_size == 0) /* /proc? do it slowly... */
96 		return slow_copyfile(from, to);
97 
98 	fromfd = open(from, O_RDONLY);
99 	if (fromfd < 0)
100 		goto out;
101 
102 	tofd = creat(to, 0755);
103 	if (tofd < 0)
104 		goto out_close_from;
105 
106 	addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
107 	if (addr == MAP_FAILED)
108 		goto out_close_to;
109 
110 	if (write(tofd, addr, st.st_size) == st.st_size)
111 		err = 0;
112 
113 	munmap(addr, st.st_size);
114 out_close_to:
115 	close(tofd);
116 	if (err)
117 		unlink(to);
118 out_close_from:
119 	close(fromfd);
120 out:
121 	return err;
122 }
123 
convert_unit(unsigned long value,char * unit)124 unsigned long convert_unit(unsigned long value, char *unit)
125 {
126 	*unit = ' ';
127 
128 	if (value > 1000) {
129 		value /= 1000;
130 		*unit = 'K';
131 	}
132 
133 	if (value > 1000) {
134 		value /= 1000;
135 		*unit = 'M';
136 	}
137 
138 	if (value > 1000) {
139 		value /= 1000;
140 		*unit = 'G';
141 	}
142 
143 	return value;
144 }
145 
readn(int fd,void * buf,size_t n)146 int readn(int fd, void *buf, size_t n)
147 {
148 	void *buf_start = buf;
149 
150 	while (n) {
151 		int ret = read(fd, buf, n);
152 
153 		if (ret <= 0)
154 			return ret;
155 
156 		n -= ret;
157 		buf += ret;
158 	}
159 
160 	return buf - buf_start;
161 }
162 
hex_width(u64 v)163 size_t hex_width(u64 v)
164 {
165 	size_t n = 1;
166 
167 	while ((v >>= 4))
168 		++n;
169 
170 	return n;
171 }
172 
hex(char ch)173 static int hex(char ch)
174 {
175 	if ((ch >= '0') && (ch <= '9'))
176 		return ch - '0';
177 	if ((ch >= 'a') && (ch <= 'f'))
178 		return ch - 'a' + 10;
179 	if ((ch >= 'A') && (ch <= 'F'))
180 		return ch - 'A' + 10;
181 	return -1;
182 }
183 
184 /*
185  * While we find nice hex chars, build a long_val.
186  * Return number of chars processed.
187  */
hex2u64(const char * ptr,u64 * long_val)188 int hex2u64(const char *ptr, u64 *long_val)
189 {
190 	const char *p = ptr;
191 	*long_val = 0;
192 
193 	while (*p) {
194 		const int hex_val = hex(*p);
195 
196 		if (hex_val < 0)
197 			break;
198 
199 		*long_val = (*long_val << 4) | hex_val;
200 		p++;
201 	}
202 
203 	return p - ptr;
204 }
205 
206 /* Obtain a backtrace and print it to stdout. */
207 #ifdef BACKTRACE_SUPPORT
dump_stack(void)208 void dump_stack(void)
209 {
210 	void *array[16];
211 	size_t size = backtrace(array, ARRAY_SIZE(array));
212 	char **strings = backtrace_symbols(array, size);
213 	size_t i;
214 
215 	printf("Obtained %zd stack frames.\n", size);
216 
217 	for (i = 0; i < size; i++)
218 		printf("%s\n", strings[i]);
219 
220 	free(strings);
221 }
222 #else
dump_stack(void)223 void dump_stack(void) {}
224 #endif
225 
get_term_dimensions(struct winsize * ws)226 void get_term_dimensions(struct winsize *ws)
227 {
228 	char *s = getenv("LINES");
229 
230 	if (s != NULL) {
231 		ws->ws_row = atoi(s);
232 		s = getenv("COLUMNS");
233 		if (s != NULL) {
234 			ws->ws_col = atoi(s);
235 			if (ws->ws_row && ws->ws_col)
236 				return;
237 		}
238 	}
239 #ifdef TIOCGWINSZ
240 	if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
241 	    ws->ws_row && ws->ws_col)
242 		return;
243 #endif
244 	ws->ws_row = 25;
245 	ws->ws_col = 80;
246 }
247 
set_tracing_events_path(const char * mountpoint)248 static void set_tracing_events_path(const char *mountpoint)
249 {
250 	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
251 		 mountpoint, "tracing/events");
252 }
253 
perf_debugfs_mount(const char * mountpoint)254 const char *perf_debugfs_mount(const char *mountpoint)
255 {
256 	const char *mnt;
257 
258 	mnt = debugfs_mount(mountpoint);
259 	if (!mnt)
260 		return NULL;
261 
262 	set_tracing_events_path(mnt);
263 
264 	return mnt;
265 }
266 
perf_debugfs_set_path(const char * mntpt)267 void perf_debugfs_set_path(const char *mntpt)
268 {
269 	snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
270 	set_tracing_events_path(mntpt);
271 }
272 
find_debugfs(void)273 static const char *find_debugfs(void)
274 {
275 	const char *path = perf_debugfs_mount(NULL);
276 
277 	if (!path)
278 		fprintf(stderr, "Your kernel does not support the debugfs filesystem");
279 
280 	return path;
281 }
282 
283 /*
284  * Finds the path to the debugfs/tracing
285  * Allocates the string and stores it.
286  */
find_tracing_dir(void)287 const char *find_tracing_dir(void)
288 {
289 	static char *tracing;
290 	static int tracing_found;
291 	const char *debugfs;
292 
293 	if (tracing_found)
294 		return tracing;
295 
296 	debugfs = find_debugfs();
297 	if (!debugfs)
298 		return NULL;
299 
300 	tracing = malloc(strlen(debugfs) + 9);
301 	if (!tracing)
302 		return NULL;
303 
304 	sprintf(tracing, "%s/tracing", debugfs);
305 
306 	tracing_found = 1;
307 	return tracing;
308 }
309 
get_tracing_file(const char * name)310 char *get_tracing_file(const char *name)
311 {
312 	const char *tracing;
313 	char *file;
314 
315 	tracing = find_tracing_dir();
316 	if (!tracing)
317 		return NULL;
318 
319 	file = malloc(strlen(tracing) + strlen(name) + 2);
320 	if (!file)
321 		return NULL;
322 
323 	sprintf(file, "%s/%s", tracing, name);
324 	return file;
325 }
326 
put_tracing_file(char * file)327 void put_tracing_file(char *file)
328 {
329 	free(file);
330 }
331 
parse_nsec_time(const char * str,u64 * ptime)332 int parse_nsec_time(const char *str, u64 *ptime)
333 {
334 	u64 time_sec, time_nsec;
335 	char *end;
336 
337 	time_sec = strtoul(str, &end, 10);
338 	if (*end != '.' && *end != '\0')
339 		return -1;
340 
341 	if (*end == '.') {
342 		int i;
343 		char nsec_buf[10];
344 
345 		if (strlen(++end) > 9)
346 			return -1;
347 
348 		strncpy(nsec_buf, end, 9);
349 		nsec_buf[9] = '\0';
350 
351 		/* make it nsec precision */
352 		for (i = strlen(nsec_buf); i < 9; i++)
353 			nsec_buf[i] = '0';
354 
355 		time_nsec = strtoul(nsec_buf, &end, 10);
356 		if (*end != '\0')
357 			return -1;
358 	} else
359 		time_nsec = 0;
360 
361 	*ptime = time_sec * NSEC_PER_SEC + time_nsec;
362 	return 0;
363 }
364