Annotation of src/usr.bin/ctfconv/generate.c, Revision 1.6
1.6 ! claudio 1: /* $OpenBSD: generate.c,v 1.5 2022/08/14 14:54:13 millert Exp $ */
1.2 jasper 2:
1.1 mpi 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
1.5 millert 70: char *data_compress(const char *, size_t, size_t, size_t *);
1.1 mpi 71: #endif /* ZLIB */
72:
73: void
74: dbuf_realloc(struct dbuf *dbuf, size_t len)
75: {
76: assert(dbuf != NULL);
77: assert(len != 0);
78:
79: dbuf->data = xrealloc(dbuf->data, dbuf->size + len);
80: dbuf->size += len;
81: dbuf->cptr = dbuf->data + dbuf->coff;
82: }
83:
84: void
85: dbuf_copy(struct dbuf *dbuf, void const *data, size_t len)
86: {
1.5 millert 87: size_t left;
1.1 mpi 88:
89: assert(dbuf->cptr != NULL);
90: assert(dbuf->data != NULL);
91: assert(dbuf->size != 0);
92:
93: if (len == 0)
94: return;
95:
96: left = dbuf->size - dbuf->coff;
1.5 millert 97: if (left < len)
1.1 mpi 98: dbuf_realloc(dbuf, ROUNDUP((len - left), DBUF_CHUNKSZ));
99:
100: memcpy(dbuf->cptr, data, len);
101: dbuf->cptr += len;
102: dbuf->coff += len;
103: }
104:
105: size_t
106: dbuf_pad(struct dbuf *dbuf, int align)
107: {
108: int i = (align - (dbuf->coff % align)) % align;
109:
110: while (i-- > 0)
111: dbuf_copy(dbuf, "", 1);
112:
113: return dbuf->coff;
114: }
115:
116: size_t
117: imcs_add_string(struct imcs *imcs, const char *str)
118: {
119: struct strentry *se;
120: unsigned int slot;
121:
122: if (str == NULL || *str == '\0')
123: return 0;
124:
125: se = (struct strentry *)hash_find(imcs->htab, str, &slot);
126: if (se == NULL) {
127: se = xmalloc(sizeof(*se));
128: hash_insert(imcs->htab, slot, &se->se_key, str);
129: se->se_off = imcs->stab.coff;
130:
131: dbuf_copy(&imcs->stab, str, strlen(str) + 1);
132: }
133:
134: return se->se_off;
135: }
136:
137: void
138: imcs_add_func(struct imcs *imcs, struct itype *it)
139: {
140: uint16_t func, arg;
141: struct imember *im;
142: int kind, root, vlen;
143:
144: vlen = it->it_nelems;
145: kind = it->it_type;
146: root = 0;
147:
148: func = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN);
149: dbuf_copy(&imcs->body, &func, sizeof(func));
150:
151: if (kind == CTF_K_UNKNOWN)
152: return;
153:
154: func = it->it_refp->it_idx;
155: dbuf_copy(&imcs->body, &func, sizeof(func));
156:
157: TAILQ_FOREACH(im, &it->it_members, im_next) {
158: arg = im->im_refp->it_idx;
159: dbuf_copy(&imcs->body, &arg, sizeof(arg));
160: }
161: }
162:
163: void
164: imcs_add_obj(struct imcs *imcs, struct itype *it)
165: {
166: uint16_t type;
167:
168: type = it->it_refp->it_idx;
169: dbuf_copy(&imcs->body, &type, sizeof(type));
170: }
171:
172: void
173: imcs_add_type(struct imcs *imcs, struct itype *it)
174: {
175: struct imember *im;
176: struct ctf_type ctt;
177: struct ctf_array cta;
178: unsigned int eob;
179: uint32_t size;
180: uint16_t arg;
181: size_t ctsz;
182: int kind, root, vlen;
183:
184: assert(it->it_type != CTF_K_UNKNOWN && it->it_type != CTF_K_FORWARD);
185:
186: vlen = it->it_nelems;
187: size = it->it_size;
188: kind = it->it_type;
189: root = 0;
190:
191: ctt.ctt_name = imcs_add_string(imcs, it_name(it));
192: 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: if (it->it_refp != NULL && kind != CTF_K_ARRAY) {
196: ctt.ctt_type = it->it_refp->it_idx;
197: ctsz = sizeof(struct ctf_stype);
198: } else if (size <= CTF_MAX_SIZE) {
1.6 ! claudio 199: if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) {
! 200: assert(size <= 64);
! 201: if (size == 0)
! 202: ctt.ctt_size = 0;
! 203: else if (size <= 8)
! 204: ctt.ctt_size = 1;
! 205: else if (size <= 16)
! 206: ctt.ctt_size = 2;
! 207: else if (size <= 32)
! 208: ctt.ctt_size = 4;
! 209: else
! 210: ctt.ctt_size = 8;
! 211: } else
! 212: ctt.ctt_size = size;
1.1 mpi 213: ctsz = sizeof(struct ctf_stype);
214: } else {
215: ctt.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);
216: ctt.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);
217: ctt.ctt_size = CTF_LSIZE_SENT;
218: ctsz = sizeof(struct ctf_type);
219: }
220:
221: dbuf_copy(&imcs->body, &ctt, ctsz);
222:
223: switch (kind) {
224: assert(1 == 0);
225: break;
226: case CTF_K_INTEGER:
227: case CTF_K_FLOAT:
228: eob = CTF_INT_DATA(it->it_enc, 0, size);
229: dbuf_copy(&imcs->body, &eob, sizeof(eob));
230: break;
231: case CTF_K_ARRAY:
232: memset(&cta, 0, sizeof(cta));
233: cta.cta_contents = it->it_refp->it_idx;
234: cta.cta_index = long_tidx;
235: cta.cta_nelems = it->it_nelems;
236: dbuf_copy(&imcs->body, &cta, sizeof(cta));
237: break;
238: case CTF_K_STRUCT:
239: case CTF_K_UNION:
240: if (size < CTF_LSTRUCT_THRESH) {
241: struct ctf_member ctm;
242:
243: memset(&ctm, 0, sizeof(ctm));
244: TAILQ_FOREACH(im, &it->it_members, im_next) {
245: ctm.ctm_name =
1.3 mpi 246: imcs_add_string(imcs, im_name(im));
1.1 mpi 247: ctm.ctm_type = im->im_refp->it_idx;
248: ctm.ctm_offset = im->im_off;
249:
250: dbuf_copy(&imcs->body, &ctm, sizeof(ctm));
251: }
252: } else {
253: struct ctf_lmember ctlm;
254:
255: memset(&ctlm, 0, sizeof(ctlm));
256: TAILQ_FOREACH(im, &it->it_members, im_next) {
257: ctlm.ctlm_name =
1.3 mpi 258: imcs_add_string(imcs, im_name(im));
1.1 mpi 259: ctlm.ctlm_type = im->im_refp->it_idx;
260: ctlm.ctlm_offsethi =
261: CTF_OFFSET_TO_LMEMHI(im->im_off);
262: ctlm.ctlm_offsetlo =
263: CTF_OFFSET_TO_LMEMLO(im->im_off);
264:
265:
266: dbuf_copy(&imcs->body, &ctlm, sizeof(ctlm));
267: }
268: }
269: break;
270: case CTF_K_FUNCTION:
271: TAILQ_FOREACH(im, &it->it_members, im_next) {
272: arg = im->im_refp->it_idx;
273: dbuf_copy(&imcs->body, &arg, sizeof(arg));
274: }
275: if (vlen & 1) {
276: arg = 0;
277: dbuf_copy(&imcs->body, &arg, sizeof(arg));
278: }
279: break;
280: case CTF_K_ENUM:
281: TAILQ_FOREACH(im, &it->it_members, im_next) {
282: struct ctf_enum cte;
283:
1.3 mpi 284: cte.cte_name = imcs_add_string(imcs, im_name(im));
1.1 mpi 285: cte.cte_value = im->im_ref;
286:
287: dbuf_copy(&imcs->body, &cte, sizeof(cte));
288: }
289: break;
290: case CTF_K_POINTER:
291: case CTF_K_TYPEDEF:
292: case CTF_K_VOLATILE:
293: case CTF_K_CONST:
294: case CTF_K_RESTRICT:
295: default:
296: break;
297: }
298: }
299:
300: void
301: imcs_generate(struct imcs *imcs, struct ctf_header *cth, const char *label)
302: {
303: struct itype *it;
304: struct ctf_lblent lbl;
305:
306: memset(imcs, 0, sizeof(*imcs));
307:
308: dbuf_realloc(&imcs->body, DBUF_CHUNKSZ);
309: dbuf_realloc(&imcs->stab, DBUF_CHUNKSZ);
310:
311: imcs->htab = hash_init(10);
312: if (imcs->htab == NULL)
313: err(1, "hash_init");
314:
315: /* Add empty string */
316: dbuf_copy(&imcs->stab, "", 1);
317:
318: /* We don't use parent label */
319: cth->cth_parlabel = 0;
320: cth->cth_parname = 0;
321:
322: /* Insert a single label for all types. */
323: cth->cth_lbloff = 0;
324: lbl.ctl_label = imcs_add_string(imcs, label);
325: lbl.ctl_typeidx = tidx;
326: dbuf_copy(&imcs->body, &lbl, sizeof(lbl));
327:
328: /* Insert objects */
329: cth->cth_objtoff = dbuf_pad(&imcs->body, 2);
330: TAILQ_FOREACH(it, &iobjq, it_symb)
331: imcs_add_obj(imcs, it);
332:
333: /* Insert functions */
334: cth->cth_funcoff = dbuf_pad(&imcs->body, 2);
335: TAILQ_FOREACH(it, &ifuncq, it_symb)
336: imcs_add_func(imcs, it);
337:
338: /* Insert types */
339: cth->cth_typeoff = dbuf_pad(&imcs->body, 4);
340: TAILQ_FOREACH(it, &itypeq, it_next) {
341: if (it->it_flags & (ITF_FUNC|ITF_OBJ))
342: continue;
343:
344: imcs_add_type(imcs, it);
345: }
346:
347: /* String table is written from its own buffer. */
348: cth->cth_stroff = imcs->body.coff;
349: cth->cth_strlen = imcs->stab.coff;
350: }
351:
352: /*
353: * Generate a CTF buffer from the internal type representation.
354: */
355: int
356: generate(const char *path, const char *label, int compress)
357: {
358: char *p, *ctfdata = NULL;
359: ssize_t ctflen;
360: struct ctf_header cth;
361: struct imcs imcs;
1.4 mpi 362: int error = 0, fd;
1.1 mpi 363:
364: memset(&cth, 0, sizeof(cth));
365:
366: cth.cth_magic = CTF_MAGIC;
367: cth.cth_version = CTF_VERSION;
368:
369: #ifdef ZLIB
370: if (compress)
371: cth.cth_flags = CTF_F_COMPRESS;
372: #endif /* ZLIB */
373:
374: imcs_generate(&imcs, &cth, label);
375:
376: ctflen = sizeof(cth) + imcs.body.coff + imcs.stab.coff;
377: p = ctfdata = xmalloc(ctflen);
378:
379: memcpy(p, &cth, sizeof(cth));
380: p += sizeof(cth);
381:
382: memcpy(p, imcs.body.data, imcs.body.coff);
383: p += imcs.body.coff;
384:
385: memcpy(p, imcs.stab.data, imcs.stab.coff);
386: p += imcs.stab.coff;
387:
388: assert((p - ctfdata) == ctflen);
389:
390: #ifdef ZLIB
391: if (compress) {
392: char *cdata;
393: size_t clen;
394:
395: cdata = data_compress(ctfdata + sizeof(cth),
396: ctflen - sizeof(cth), ctflen - sizeof(cth), &clen);
397: if (cdata == NULL) {
398: warnx("compressing CTF data");
399: free(ctfdata);
400: return -1;
401: }
402:
403: memcpy(ctfdata + sizeof(cth), cdata, clen);
404: ctflen = clen + sizeof(cth);
405:
406: free(cdata);
407: }
408: #endif /* ZLIB */
409:
410: fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
411: if (fd == -1) {
412: warn("open %s", path);
413: free(ctfdata);
414: return -1;
415: }
416:
417: if (write(fd, ctfdata, ctflen) != ctflen) {
418: warn("unable to write %zd bytes for %s", ctflen, path);
419: error = -1;
420: }
421:
422: close(fd);
423: free(ctfdata);
1.4 mpi 424: return error;
1.1 mpi 425: }
426:
427: #ifdef ZLIB
428: char *
1.5 millert 429: data_compress(const char *buf, size_t size, size_t len, size_t *pclen)
1.1 mpi 430: {
431: z_stream stream;
432: char *data;
433: int error;
434:
435: data = malloc(len);
436: if (data == NULL) {
437: warn(NULL);
438: return NULL;
439: }
440:
441: memset(&stream, 0, sizeof(stream));
442: stream.zalloc = Z_NULL;
443: stream.zfree = Z_NULL;
444: stream.opaque = Z_NULL;
445:
446: if ((error = deflateInit(&stream, Z_BEST_COMPRESSION)) != Z_OK) {
447: warnx("zlib deflateInit failed: %s", zError(error));
448: goto exit;
449: }
450:
451: stream.next_in = (void *)buf;
452: stream.avail_in = size;
453: stream.next_out = (unsigned char *)data;
454: stream.avail_out = len;
455:
456: if ((error = deflate(&stream, Z_FINISH)) != Z_STREAM_END) {
457: warnx("zlib deflate failed: %s", zError(error));
458: deflateEnd(&stream);
459: goto exit;
460: }
461:
462: if ((error = deflateEnd(&stream)) != Z_OK) {
463: warnx("zlib deflateEnd failed: %s", zError(error));
464: goto exit;
465: }
466:
467: if (pclen != NULL)
468: *pclen = stream.total_out;
469:
470: return data;
471:
472: exit:
473: free(data);
474: return NULL;
475: }
476: #endif /* ZLIB */