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 */
13unsigned int page_size;
14
15bool test_attr__enabled;
16
17bool perf_host  = true;
18bool perf_guest = false;
19
20char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
21
22void 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
32int 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
58static 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;
76out_fclose_to:
77	fclose(to_fp);
78	free(line);
79out_fclose_from:
80	fclose(from_fp);
81out:
82	return err;
83}
84
85int 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);
114out_close_to:
115	close(tofd);
116	if (err)
117		unlink(to);
118out_close_from:
119	close(fromfd);
120out:
121	return err;
122}
123
124unsigned 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
146int 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
163size_t hex_width(u64 v)
164{
165	size_t n = 1;
166
167	while ((v >>= 4))
168		++n;
169
170	return n;
171}
172
173static 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 */
188int 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
208void 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
223void dump_stack(void) {}
224#endif
225
226void 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
248static 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
254const 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
267void 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
273static 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 */
287const 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
310char *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
327void put_tracing_file(char *file)
328{
329	free(file);
330}
331
332int 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