brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · 1162c49 Raw
481 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>4 */5#include <dirent.h>6#include <stdio.h>7#include <stdlib.h>8#include <string.h>9#include <stdarg.h>10#include <sys/types.h>11#include <sys/stat.h>12#include <sys/wait.h>13#include <sys/mman.h>14#include <traceevent/event-parse.h>15#include <fcntl.h>16#include <unistd.h>17#include <errno.h>18 19#include "trace-event.h"20#include "debug.h"21#include "util.h"22 23static int input_fd;24 25static ssize_t trace_data_size;26static bool repipe;27 28static int __do_read(int fd, void *buf, int size)29{30	int rsize = size;31 32	while (size) {33		int ret = read(fd, buf, size);34 35		if (ret <= 0)36			return -1;37 38		if (repipe) {39			int retw = write(STDOUT_FILENO, buf, ret);40 41			if (retw <= 0 || retw != ret) {42				pr_debug("repiping input file");43				return -1;44			}45		}46 47		size -= ret;48		buf += ret;49	}50 51	return rsize;52}53 54static int do_read(void *data, int size)55{56	int r;57 58	r = __do_read(input_fd, data, size);59	if (r <= 0) {60		pr_debug("reading input file (size expected=%d received=%d)",61			 size, r);62		return -1;63	}64 65	trace_data_size += r;66 67	return r;68}69 70/* If it fails, the next read will report it */71static void skip(int size)72{73	char buf[BUFSIZ];74	int r;75 76	while (size) {77		r = size > BUFSIZ ? BUFSIZ : size;78		do_read(buf, r);79		size -= r;80	}81}82 83static unsigned int read4(struct tep_handle *pevent)84{85	unsigned int data;86 87	if (do_read(&data, 4) < 0)88		return 0;89	return tep_read_number(pevent, &data, 4);90}91 92static unsigned long long read8(struct tep_handle *pevent)93{94	unsigned long long data;95 96	if (do_read(&data, 8) < 0)97		return 0;98	return tep_read_number(pevent, &data, 8);99}100 101static char *read_string(void)102{103	char buf[BUFSIZ];104	char *str = NULL;105	int size = 0;106	off_t r;107	char c;108 109	for (;;) {110		r = read(input_fd, &c, 1);111		if (r < 0) {112			pr_debug("reading input file");113			goto out;114		}115 116		if (!r) {117			pr_debug("no data");118			goto out;119		}120 121		if (repipe) {122			int retw = write(STDOUT_FILENO, &c, 1);123 124			if (retw <= 0 || retw != r) {125				pr_debug("repiping input file string");126				goto out;127			}128		}129 130		buf[size++] = c;131 132		if (!c)133			break;134	}135 136	trace_data_size += size;137 138	str = malloc(size);139	if (str)140		memcpy(str, buf, size);141out:142	return str;143}144 145static int read_proc_kallsyms(struct tep_handle *pevent)146{147	unsigned int size;148 149	size = read4(pevent);150	if (!size)151		return 0;152	/*153	 * Just skip it, now that we configure libtraceevent to use the154	 * tools/perf/ symbol resolver.155	 *156	 * We need to skip it so that we can continue parsing old perf.data157	 * files, that contains this /proc/kallsyms payload.158	 *159	 * Newer perf.data files will have just the 4-bytes zeros "kallsyms160	 * payload", so that older tools can continue reading it and interpret161	 * it as "no kallsyms payload is present".162	 */163	lseek(input_fd, size, SEEK_CUR);164	trace_data_size += size;165	return 0;166}167 168static int read_ftrace_printk(struct tep_handle *pevent)169{170	unsigned int size;171	char *buf;172 173	/* it can have 0 size */174	size = read4(pevent);175	if (!size)176		return 0;177 178	buf = malloc(size + 1);179	if (buf == NULL)180		return -1;181 182	if (do_read(buf, size) < 0) {183		free(buf);184		return -1;185	}186 187	buf[size] = '\0';188 189	parse_ftrace_printk(pevent, buf, size);190 191	free(buf);192	return 0;193}194 195static int read_header_files(struct tep_handle *pevent)196{197	unsigned long long size;198	char *header_page;199	char buf[BUFSIZ];200	int ret = 0;201 202	if (do_read(buf, 12) < 0)203		return -1;204 205	if (memcmp(buf, "header_page", 12) != 0) {206		pr_debug("did not read header page");207		return -1;208	}209 210	size = read8(pevent);211 212	header_page = malloc(size);213	if (header_page == NULL)214		return -1;215 216	if (do_read(header_page, size) < 0) {217		pr_debug("did not read header page");218		free(header_page);219		return -1;220	}221 222	if (!tep_parse_header_page(pevent, header_page, size,223				   tep_get_long_size(pevent))) {224		/*225		 * The commit field in the page is of type long,226		 * use that instead, since it represents the kernel.227		 */228		tep_set_long_size(pevent, tep_get_header_page_size(pevent));229	}230	free(header_page);231 232	if (do_read(buf, 13) < 0)233		return -1;234 235	if (memcmp(buf, "header_event", 13) != 0) {236		pr_debug("did not read header event");237		return -1;238	}239 240	size = read8(pevent);241	skip(size);242 243	return ret;244}245 246static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)247{248	int ret;249	char *buf;250 251	buf = malloc(size);252	if (buf == NULL) {253		pr_debug("memory allocation failure\n");254		return -1;255	}256 257	ret = do_read(buf, size);258	if (ret < 0) {259		pr_debug("error reading ftrace file.\n");260		goto out;261	}262 263	ret = parse_ftrace_file(pevent, buf, size);264	if (ret < 0)265		pr_debug("error parsing ftrace file.\n");266out:267	free(buf);268	return ret;269}270 271static int read_event_file(struct tep_handle *pevent, char *sys,272			   unsigned long long size)273{274	int ret;275	char *buf;276 277	buf = malloc(size);278	if (buf == NULL) {279		pr_debug("memory allocation failure\n");280		return -1;281	}282 283	ret = do_read(buf, size);284	if (ret < 0)285		goto out;286 287	ret = parse_event_file(pevent, buf, size, sys);288	if (ret < 0)289		pr_debug("error parsing event file.\n");290out:291	free(buf);292	return ret;293}294 295static int read_ftrace_files(struct tep_handle *pevent)296{297	unsigned long long size;298	int count;299	int i;300	int ret;301 302	count = read4(pevent);303 304	for (i = 0; i < count; i++) {305		size = read8(pevent);306		ret = read_ftrace_file(pevent, size);307		if (ret)308			return ret;309	}310	return 0;311}312 313static int read_event_files(struct tep_handle *pevent)314{315	unsigned long long size;316	char *sys;317	int systems;318	int count;319	int i,x;320	int ret;321 322	systems = read4(pevent);323 324	for (i = 0; i < systems; i++) {325		sys = read_string();326		if (sys == NULL)327			return -1;328 329		count = read4(pevent);330 331		for (x=0; x < count; x++) {332			size = read8(pevent);333			ret = read_event_file(pevent, sys, size);334			if (ret) {335				free(sys);336				return ret;337			}338		}339		free(sys);340	}341	return 0;342}343 344static int read_saved_cmdline(struct tep_handle *pevent)345{346	unsigned long long size;347	char *buf;348	int ret;349 350	/* it can have 0 size */351	size = read8(pevent);352	if (!size)353		return 0;354 355	buf = malloc(size + 1);356	if (buf == NULL) {357		pr_debug("memory allocation failure\n");358		return -1;359	}360 361	ret = do_read(buf, size);362	if (ret < 0) {363		pr_debug("error reading saved cmdlines\n");364		goto out;365	}366	buf[ret] = '\0';367 368	parse_saved_cmdline(pevent, buf, size);369	ret = 0;370out:371	free(buf);372	return ret;373}374 375ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)376{377	char buf[BUFSIZ];378	char test[] = { 23, 8, 68 };379	char *version;380	int show_version = 0;381	int show_funcs = 0;382	int show_printk = 0;383	ssize_t size = -1;384	int file_bigendian;385	int host_bigendian;386	int file_long_size;387	int file_page_size;388	struct tep_handle *pevent = NULL;389	int err;390 391	repipe = __repipe;392	input_fd = fd;393 394	if (do_read(buf, 3) < 0)395		return -1;396	if (memcmp(buf, test, 3) != 0) {397		pr_debug("no trace data in the file");398		return -1;399	}400 401	if (do_read(buf, 7) < 0)402		return -1;403	if (memcmp(buf, "tracing", 7) != 0) {404		pr_debug("not a trace file (missing 'tracing' tag)");405		return -1;406	}407 408	version = read_string();409	if (version == NULL)410		return -1;411	if (show_version)412		printf("version = %s\n", version);413 414	if (do_read(buf, 1) < 0) {415		free(version);416		return -1;417	}418	file_bigendian = buf[0];419	host_bigendian = host_is_bigendian() ? 1 : 0;420 421	if (trace_event__init(tevent)) {422		pr_debug("trace_event__init failed");423		goto out;424	}425 426	pevent = tevent->pevent;427 428	tep_set_flag(pevent, TEP_NSEC_OUTPUT);429	tep_set_file_bigendian(pevent, file_bigendian);430	tep_set_local_bigendian(pevent, host_bigendian);431 432	if (do_read(buf, 1) < 0)433		goto out;434	file_long_size = buf[0];435 436	file_page_size = read4(pevent);437	if (!file_page_size)438		goto out;439 440	tep_set_long_size(pevent, file_long_size);441	tep_set_page_size(pevent, file_page_size);442 443	err = read_header_files(pevent);444	if (err)445		goto out;446	err = read_ftrace_files(pevent);447	if (err)448		goto out;449	err = read_event_files(pevent);450	if (err)451		goto out;452	err = read_proc_kallsyms(pevent);453	if (err)454		goto out;455	err = read_ftrace_printk(pevent);456	if (err)457		goto out;458	if (atof(version) >= 0.6) {459		err = read_saved_cmdline(pevent);460		if (err)461			goto out;462	}463 464	size = trace_data_size;465	repipe = false;466 467	if (show_funcs) {468		tep_print_funcs(pevent);469	} else if (show_printk) {470		tep_print_printk(pevent);471	}472 473	pevent = NULL;474 475out:476	if (pevent)477		trace_event__cleanup(tevent);478	free(version);479	return size;480}481