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