xref: /linux/tools/perf/util/header.c (revision ac6a0cf6716bb46813d0161024c66c2af66e53d1)
1 #include <sys/types.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 
6 #include "util.h"
7 #include "header.h"
8 
9 /*
10  *
11  */
12 
13 struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
14 {
15 	struct perf_header_attr *self = malloc(sizeof(*self));
16 
17 	if (!self)
18 		die("nomem");
19 
20 	self->attr = *attr;
21 	self->ids = 0;
22 	self->size = 1;
23 	self->id = malloc(sizeof(u64));
24 
25 	if (!self->id)
26 		die("nomem");
27 
28 	return self;
29 }
30 
31 void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
32 {
33 	int pos = self->ids;
34 
35 	self->ids++;
36 	if (self->ids > self->size) {
37 		self->size *= 2;
38 		self->id = realloc(self->id, self->size * sizeof(u64));
39 		if (!self->id)
40 			die("nomem");
41 	}
42 	self->id[pos] = id;
43 }
44 
45 /*
46  *
47  */
48 
49 struct perf_header *perf_header__new(void)
50 {
51 	struct perf_header *self = malloc(sizeof(*self));
52 
53 	if (!self)
54 		die("nomem");
55 
56 	self->frozen = 0;
57 
58 	self->attrs = 0;
59 	self->size = 1;
60 	self->attr = malloc(sizeof(void *));
61 
62 	if (!self->attr)
63 		die("nomem");
64 
65 	self->data_offset = 0;
66 	self->data_size = 0;
67 
68 	return self;
69 }
70 
71 void perf_header__add_attr(struct perf_header *self,
72 			   struct perf_header_attr *attr)
73 {
74 	int pos = self->attrs;
75 
76 	if (self->frozen)
77 		die("frozen");
78 
79 	self->attrs++;
80 	if (self->attrs > self->size) {
81 		self->size *= 2;
82 		self->attr = realloc(self->attr, self->size * sizeof(void *));
83 		if (!self->attr)
84 			die("nomem");
85 	}
86 	self->attr[pos] = attr;
87 }
88 
89 static const char *__perf_magic = "PERFFILE";
90 
91 #define PERF_MAGIC	(*(u64 *)__perf_magic)
92 
93 struct perf_file_section {
94 	u64 offset;
95 	u64 size;
96 };
97 
98 struct perf_file_attr {
99 	struct perf_counter_attr	attr;
100 	struct perf_file_section	ids;
101 };
102 
103 struct perf_file_header {
104 	u64				magic;
105 	u64				size;
106 	u64				attr_size;
107 	struct perf_file_section	attrs;
108 	struct perf_file_section	data;
109 };
110 
111 static void do_write(int fd, void *buf, size_t size)
112 {
113 	while (size) {
114 		int ret = write(fd, buf, size);
115 
116 		if (ret < 0)
117 			die("failed to write");
118 
119 		size -= ret;
120 		buf += ret;
121 	}
122 }
123 
124 void perf_header__write(struct perf_header *self, int fd)
125 {
126 	struct perf_file_header f_header;
127 	struct perf_file_attr   f_attr;
128 	struct perf_header_attr	*attr;
129 	int i;
130 
131 	lseek(fd, sizeof(f_header), SEEK_SET);
132 
133 
134 	for (i = 0; i < self->attrs; i++) {
135 		attr = self->attr[i];
136 
137 		attr->id_offset = lseek(fd, 0, SEEK_CUR);
138 		do_write(fd, attr->id, attr->ids * sizeof(u64));
139 	}
140 
141 
142 	self->attr_offset = lseek(fd, 0, SEEK_CUR);
143 
144 	for (i = 0; i < self->attrs; i++) {
145 		attr = self->attr[i];
146 
147 		f_attr = (struct perf_file_attr){
148 			.attr = attr->attr,
149 			.ids  = {
150 				.offset = attr->id_offset,
151 				.size   = attr->ids * sizeof(u64),
152 			}
153 		};
154 		do_write(fd, &f_attr, sizeof(f_attr));
155 	}
156 
157 
158 	self->data_offset = lseek(fd, 0, SEEK_CUR);
159 
160 	f_header = (struct perf_file_header){
161 		.magic	   = PERF_MAGIC,
162 		.size	   = sizeof(f_header),
163 		.attr_size = sizeof(f_attr),
164 		.attrs = {
165 			.offset = self->attr_offset,
166 			.size   = self->attrs * sizeof(f_attr),
167 		},
168 		.data = {
169 			.offset = self->data_offset,
170 			.size	= self->data_size,
171 		},
172 	};
173 
174 	lseek(fd, 0, SEEK_SET);
175 	do_write(fd, &f_header, sizeof(f_header));
176 	lseek(fd, self->data_offset + self->data_size, SEEK_SET);
177 
178 	self->frozen = 1;
179 }
180 
181 static void do_read(int fd, void *buf, size_t size)
182 {
183 	while (size) {
184 		int ret = read(fd, buf, size);
185 
186 		if (ret < 0)
187 			die("failed to read");
188 		if (ret == 0)
189 			die("failed to read: missing data");
190 
191 		size -= ret;
192 		buf += ret;
193 	}
194 }
195 
196 struct perf_header *perf_header__read(int fd)
197 {
198 	struct perf_header	*self = perf_header__new();
199 	struct perf_file_header f_header;
200 	struct perf_file_attr	f_attr;
201 	u64			f_id;
202 
203 	int nr_attrs, nr_ids, i, j;
204 
205 	lseek(fd, 0, SEEK_SET);
206 	do_read(fd, &f_header, sizeof(f_header));
207 
208 	if (f_header.magic	!= PERF_MAGIC		||
209 	    f_header.size	!= sizeof(f_header)	||
210 	    f_header.attr_size	!= sizeof(f_attr))
211 		die("incompatible file format");
212 
213 	nr_attrs = f_header.attrs.size / sizeof(f_attr);
214 	lseek(fd, f_header.attrs.offset, SEEK_SET);
215 
216 	for (i = 0; i < nr_attrs; i++) {
217 		struct perf_header_attr *attr;
218 		off_t tmp;
219 
220 		do_read(fd, &f_attr, sizeof(f_attr));
221 		tmp = lseek(fd, 0, SEEK_CUR);
222 
223 		attr = perf_header_attr__new(&f_attr.attr);
224 
225 		nr_ids = f_attr.ids.size / sizeof(u64);
226 		lseek(fd, f_attr.ids.offset, SEEK_SET);
227 
228 		for (j = 0; j < nr_ids; j++) {
229 			do_read(fd, &f_id, sizeof(f_id));
230 
231 			perf_header_attr__add_id(attr, f_id);
232 		}
233 		perf_header__add_attr(self, attr);
234 		lseek(fd, tmp, SEEK_SET);
235 	}
236 
237 	self->data_offset = f_header.data.offset;
238 	self->data_size   = f_header.data.size;
239 
240 	lseek(fd, self->data_offset + self->data_size, SEEK_SET);
241 
242 	self->frozen = 1;
243 
244 	return self;
245 }
246