GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ctfconv/generate.c Lines: 147 209 70.3 %
Date: 2017-11-07 Branches: 46 88 52.3 %

Line Branch Exec Source
1
/*	$OpenBSD: generate.c,v 1.4 2017/09/26 08:16:18 mpi Exp $ */
2
3
/*
4
 * Copyright (c) 2017 Martin Pieuchot
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/queue.h>
21
#include <sys/tree.h>
22
#include <sys/ctf.h>
23
24
#include <assert.h>
25
#include <err.h>
26
#include <fcntl.h>
27
#include <string.h>
28
#include <stdlib.h>
29
#include <stddef.h>
30
#include <stdint.h>
31
#include <unistd.h>
32
33
#ifdef ZLIB
34
#include <zlib.h>
35
#endif /* ZLIB */
36
37
#include "itype.h"
38
#include "xmalloc.h"
39
#include "hash.h"
40
41
#define ROUNDUP(x, y) ((((x) + (y) - 1) / (y)) * (y))
42
43
/*
44
 * Dynamic buffer, used for content & string table.
45
 */
46
struct dbuf {
47
	char		*data;	/* start data buffer */
48
	size_t		 size;	/* size of the buffer */
49
50
	char		*cptr; /* position in [data, data + size] */
51
	size_t		 coff; /* number of written bytes */
52
};
53
54
#define DBUF_CHUNKSZ	(64 * 1024)
55
56
/* In-memory representation of a CTF section. */
57
struct imcs {
58
	struct dbuf	 body;
59
	struct dbuf	 stab;	/* corresponding string table */
60
	struct hash	*htab;	/* hash table of known strings */
61
};
62
63
struct strentry {
64
	struct hash_entry se_key;	/* Must be first */
65
#define se_str se_key.hkey
66
	size_t		 se_off;
67
};
68
69
#ifdef ZLIB
70
char		*data_compress(const char *, size_t, off_t, size_t *);
71
#endif /* ZLIB */
72
73
void
74
dbuf_realloc(struct dbuf *dbuf, size_t len)
75
{
76
8
	assert(dbuf != NULL);
77
4
	assert(len != 0);
78
79
4
	dbuf->data = xrealloc(dbuf->data, dbuf->size + len);
80
4
	dbuf->size += len;
81
4
	dbuf->cptr = dbuf->data + dbuf->coff;
82
4
}
83
84
void
85
dbuf_copy(struct dbuf *dbuf, void const *data, size_t len)
86
{
87
	off_t left;
88
89
168
	assert(dbuf->cptr != NULL);
90
84
	assert(dbuf->data != NULL);
91
84
	assert(dbuf->size != 0);
92
93
84
	if (len == 0)
94
		return;
95
96
84
	left = dbuf->size - dbuf->coff;
97
84
	if (left < (off_t)len)
98
		dbuf_realloc(dbuf, ROUNDUP((len - left), DBUF_CHUNKSZ));
99
100
84
	memcpy(dbuf->cptr, data, len);
101
84
	dbuf->cptr += len;
102
84
	dbuf->coff += len;
103
168
}
104
105
size_t
106
dbuf_pad(struct dbuf *dbuf, int align)
107
{
108
12
	int i = (align - (dbuf->coff % align)) % align;
109
110
20
	while (i-- > 0)
111
4
		dbuf_copy(dbuf, "", 1);
112
113
6
	return dbuf->coff;
114
}
115
116
size_t
117
imcs_add_string(struct imcs *imcs, const char *str)
118
{
119
	struct strentry *se;
120
40
	unsigned int slot;
121
122

36
	if (str == NULL || *str == '\0')
123
4
		return 0;
124
125
16
	se = (struct strentry *)hash_find(imcs->htab, str, &slot);
126
16
	if (se == NULL) {
127
10
		se = xmalloc(sizeof(*se));
128
10
		hash_insert(imcs->htab, slot, &se->se_key, str);
129
10
		se->se_off = imcs->stab.coff;
130
131
10
		dbuf_copy(&imcs->stab, str, strlen(str) + 1);
132
10
	}
133
134
16
	return se->se_off;
135
20
}
136
137
void
138
imcs_add_func(struct imcs *imcs, struct itype *it)
139
{
140
16
	uint16_t		 func, arg;
141
	struct imember		*im;
142
	int			 kind, root, vlen;
143
144
8
	vlen = it->it_nelems;
145
8
	kind = it->it_type;
146
	root = 0;
147
148
8
	func = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN);
149
8
	dbuf_copy(&imcs->body, &func, sizeof(func));
150
151
8
	if (kind == CTF_K_UNKNOWN)
152
6
		return;
153
154
2
	func = it->it_refp->it_idx;
155
2
	dbuf_copy(&imcs->body, &func, sizeof(func));
156
157
12
	TAILQ_FOREACH(im, &it->it_members, im_next) {
158
4
		arg = im->im_refp->it_idx;
159
4
		dbuf_copy(&imcs->body, &arg, sizeof(arg));
160
	}
161
10
}
162
163
void
164
imcs_add_obj(struct imcs *imcs, struct itype *it)
165
{
166
40
	uint16_t		 type;
167
168
20
	type = it->it_refp->it_idx;
169
20
	dbuf_copy(&imcs->body, &type, sizeof(type));
170
20
}
171
172
void
173
imcs_add_type(struct imcs *imcs, struct itype *it)
174
{
175
	struct imember		*im;
176
36
	struct ctf_type		 ctt;
177
18
	struct ctf_array	 cta;
178
18
	unsigned int		 eob;
179
	uint32_t		 size;
180
18
	uint16_t		 arg;
181
	size_t			 ctsz;
182
	int			 kind, root, vlen;
183
184

36
	assert(it->it_type != CTF_K_UNKNOWN && it->it_type != CTF_K_FORWARD);
185
186
18
	vlen = it->it_nelems;
187
18
	size = it->it_size;
188
	kind = it->it_type;
189
	root = 0;
190
191
18
	ctt.ctt_name = imcs_add_string(imcs, it_name(it));
192
18
	ctt.ctt_info = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN);
193
194
	/* Base types don't have reference, typedef & pointer don't have size */
195
18
	if (it->it_refp != NULL && kind != CTF_K_ARRAY) {
196
4
		ctt.ctt_type = it->it_refp->it_idx;
197
		ctsz = sizeof(struct ctf_stype);
198
18
	} else if (size <= CTF_MAX_SIZE) {
199
14
		ctt.ctt_size = size;
200
		ctsz = sizeof(struct ctf_stype);
201
14
	} else {
202
		ctt.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);
203
		ctt.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);
204
		ctt.ctt_size = CTF_LSIZE_SENT;
205
		ctsz = sizeof(struct ctf_type);
206
	}
207
208
32
	dbuf_copy(&imcs->body, &ctt, ctsz);
209
210


32
	switch (kind) {
211
		assert(1 == 0);
212
		break;
213
	case CTF_K_INTEGER:
214
	case CTF_K_FLOAT:
215
14
		eob = CTF_INT_DATA(it->it_enc, 0, size);
216
14
		dbuf_copy(&imcs->body, &eob, sizeof(eob));
217
14
		break;
218
	case CTF_K_ARRAY:
219
		memset(&cta, 0, sizeof(cta));
220
		cta.cta_contents = it->it_refp->it_idx;
221
		cta.cta_index = long_tidx;
222
		cta.cta_nelems = it->it_nelems;
223
		dbuf_copy(&imcs->body, &cta, sizeof(cta));
224
		break;
225
	case CTF_K_STRUCT:
226
	case CTF_K_UNION:
227
		if (size < CTF_LSTRUCT_THRESH) {
228
			struct ctf_member	 ctm;
229
230
			memset(&ctm, 0, sizeof(ctm));
231
			TAILQ_FOREACH(im, &it->it_members, im_next) {
232
				ctm.ctm_name =
233
				    imcs_add_string(imcs, im_name(im));
234
				ctm.ctm_type = im->im_refp->it_idx;
235
				ctm.ctm_offset = im->im_off;
236
237
				dbuf_copy(&imcs->body, &ctm, sizeof(ctm));
238
			}
239
		} else {
240
			struct ctf_lmember	 ctlm;
241
242
			memset(&ctlm, 0, sizeof(ctlm));
243
			TAILQ_FOREACH(im, &it->it_members, im_next) {
244
				ctlm.ctlm_name =
245
				    imcs_add_string(imcs, im_name(im));
246
				ctlm.ctlm_type = im->im_refp->it_idx;
247
				ctlm.ctlm_offsethi =
248
				    CTF_OFFSET_TO_LMEMHI(im->im_off);
249
				ctlm.ctlm_offsetlo =
250
				    CTF_OFFSET_TO_LMEMLO(im->im_off);
251
252
253
				dbuf_copy(&imcs->body, &ctlm, sizeof(ctlm));
254
			}
255
		}
256
		break;
257
	case CTF_K_FUNCTION:
258
		TAILQ_FOREACH(im, &it->it_members, im_next) {
259
			arg = im->im_refp->it_idx;
260
			dbuf_copy(&imcs->body, &arg, sizeof(arg));
261
		}
262
		if (vlen & 1) {
263
			arg = 0;
264
			dbuf_copy(&imcs->body, &arg, sizeof(arg));
265
		}
266
		break;
267
	case CTF_K_ENUM:
268
		TAILQ_FOREACH(im, &it->it_members, im_next) {
269
			struct ctf_enum	cte;
270
271
			cte.cte_name = imcs_add_string(imcs, im_name(im));
272
			cte.cte_value = im->im_ref;
273
274
			dbuf_copy(&imcs->body, &cte, sizeof(cte));
275
		}
276
		break;
277
	case CTF_K_POINTER:
278
	case CTF_K_TYPEDEF:
279
	case CTF_K_VOLATILE:
280
	case CTF_K_CONST:
281
	case CTF_K_RESTRICT:
282
	default:
283
		break;
284
	}
285
18
}
286
287
void
288
imcs_generate(struct imcs *imcs, struct ctf_header *cth, const char *label)
289
{
290
	struct itype		*it;
291
4
	struct ctf_lblent	 lbl;
292
293
2
	memset(imcs, 0, sizeof(*imcs));
294
295
2
	dbuf_realloc(&imcs->body, DBUF_CHUNKSZ);
296
2
	dbuf_realloc(&imcs->stab, DBUF_CHUNKSZ);
297
298
2
	imcs->htab = hash_init(10);
299
2
	if (imcs->htab == NULL)
300
		err(1, "hash_init");
301
302
	/* Add empty string */
303
2
	dbuf_copy(&imcs->stab, "", 1);
304
305
	/* We don't use parent label */
306
2
	cth->cth_parlabel = 0;
307
2
	cth->cth_parname = 0;
308
309
	/* Insert a single label for all types. */
310
2
	cth->cth_lbloff = 0;
311
2
	lbl.ctl_label = imcs_add_string(imcs, label);
312
2
	lbl.ctl_typeidx = tidx;
313
2
	dbuf_copy(&imcs->body, &lbl, sizeof(lbl));
314
315
	/* Insert objects */
316
2
	cth->cth_objtoff = dbuf_pad(&imcs->body, 2);
317
44
	TAILQ_FOREACH(it, &iobjq, it_symb)
318
20
		imcs_add_obj(imcs, it);
319
320
	/* Insert functions */
321
2
	cth->cth_funcoff = dbuf_pad(&imcs->body, 2);
322
20
	TAILQ_FOREACH(it, &ifuncq, it_symb)
323
8
		imcs_add_func(imcs, it);
324
325
	/* Insert types */
326
2
	cth->cth_typeoff = dbuf_pad(&imcs->body, 4);
327
68
	TAILQ_FOREACH(it, &itypeq, it_next) {
328
32
		if (it->it_flags & (ITF_FUNC|ITF_OBJ))
329
			continue;
330
331
18
		imcs_add_type(imcs, it);
332
18
	}
333
334
	/* String table is written from its own buffer. */
335
2
	cth->cth_stroff = imcs->body.coff;
336
2
	cth->cth_strlen = imcs->stab.coff;
337
2
}
338
339
/*
340
 * Generate a CTF buffer from the internal type representation.
341
 */
342
int
343
generate(const char *path, const char *label, int compress)
344
{
345
	char			*p, *ctfdata = NULL;
346
	ssize_t			 ctflen;
347
4
	struct ctf_header	 cth;
348
2
	struct imcs		 imcs;
349
	int			 error = 0, fd;
350
351
2
	memset(&cth, 0, sizeof(cth));
352
353
2
	cth.cth_magic = CTF_MAGIC;
354
2
	cth.cth_version = CTF_VERSION;
355
356
#ifdef ZLIB
357
2
	if (compress)
358
2
		cth.cth_flags = CTF_F_COMPRESS;
359
#endif /* ZLIB */
360
361
2
	imcs_generate(&imcs, &cth, label);
362
363
2
	ctflen = sizeof(cth) + imcs.body.coff + imcs.stab.coff;
364
2
	p = ctfdata = xmalloc(ctflen);
365
366
2
	memcpy(p, &cth, sizeof(cth));
367
2
	p += sizeof(cth);
368
369
2
	memcpy(p, imcs.body.data, imcs.body.coff);
370
2
	p += imcs.body.coff;
371
372
2
	memcpy(p, imcs.stab.data, imcs.stab.coff);
373
2
	p += imcs.stab.coff;
374
375
2
	assert((p - ctfdata) == ctflen);
376
377
#ifdef ZLIB
378
2
	if (compress) {
379
		char *cdata;
380
2
		size_t clen;
381
382
2
		cdata = data_compress(ctfdata + sizeof(cth),
383
2
		    ctflen - sizeof(cth), ctflen - sizeof(cth), &clen);
384
2
		if (cdata == NULL) {
385
			warnx("compressing CTF data");
386
			free(ctfdata);
387
			return -1;
388
		}
389
390
2
		memcpy(ctfdata + sizeof(cth), cdata, clen);
391
2
		ctflen = clen + sizeof(cth);
392
393
2
		free(cdata);
394
4
	}
395
#endif /* ZLIB */
396
397
2
	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
398
2
	if (fd == -1) {
399
		warn("open %s", path);
400
		free(ctfdata);
401
		return -1;
402
	}
403
404
2
	if (write(fd, ctfdata, ctflen) != ctflen) {
405
		warn("unable to write %zd bytes for %s", ctflen, path);
406
		error = -1;
407
	}
408
409
2
	close(fd);
410
2
	free(ctfdata);
411
2
	return error;
412
2
}
413
414
#ifdef ZLIB
415
char *
416
data_compress(const char *buf, size_t size, off_t len, size_t *pclen)
417
{
418
4
	z_stream		 stream;
419
	char			*data;
420
	int			 error;
421
422
2
	data = malloc(len);
423
2
	if (data == NULL) {
424
		warn(NULL);
425
		return NULL;
426
	}
427
428
2
	memset(&stream, 0, sizeof(stream));
429
2
	stream.zalloc = Z_NULL;
430
2
	stream.zfree = Z_NULL;
431
2
	stream.opaque = Z_NULL;
432
433
2
	if ((error = deflateInit(&stream, Z_BEST_COMPRESSION)) != Z_OK) {
434
		warnx("zlib deflateInit failed: %s", zError(error));
435
		goto exit;
436
	}
437
438
2
	stream.next_in = (void *)buf;
439
2
	stream.avail_in = size;
440
2
	stream.next_out = (unsigned char *)data;
441
2
	stream.avail_out = len;
442
443
2
	if ((error = deflate(&stream, Z_FINISH)) != Z_STREAM_END) {
444
		warnx("zlib deflate failed: %s", zError(error));
445
		deflateEnd(&stream);
446
		goto exit;
447
	}
448
449
2
	if ((error = deflateEnd(&stream)) != Z_OK) {
450
		warnx("zlib deflateEnd failed: %s", zError(error));
451
		goto exit;
452
	}
453
454
2
	if (pclen != NULL)
455
2
		*pclen = stream.total_out;
456
457
2
	return data;
458
459
exit:
460
	free(data);
461
	return NULL;
462
2
}
463
#endif /* ZLIB */