Annotation of src/usr.bin/ctfconv/generate.c, Revision 1.4
1.4 ! mpi 1: /* $OpenBSD: generate.c,v 1.3 2017/08/11 16:28:30 mpi 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
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: 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: {
87: off_t left;
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;
97: if (left < (off_t)len)
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) {
199: ctt.ctt_size = size;
200: ctsz = sizeof(struct ctf_stype);
201: } 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: dbuf_copy(&imcs->body, &ctt, ctsz);
209:
210: switch (kind) {
211: assert(1 == 0);
212: break;
213: case CTF_K_INTEGER:
214: case CTF_K_FLOAT:
215: eob = CTF_INT_DATA(it->it_enc, 0, size);
216: dbuf_copy(&imcs->body, &eob, sizeof(eob));
217: 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 =
1.3 mpi 233: imcs_add_string(imcs, im_name(im));
1.1 mpi 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 =
1.3 mpi 245: imcs_add_string(imcs, im_name(im));
1.1 mpi 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:
1.3 mpi 271: cte.cte_name = imcs_add_string(imcs, im_name(im));
1.1 mpi 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: }
286:
287: void
288: imcs_generate(struct imcs *imcs, struct ctf_header *cth, const char *label)
289: {
290: struct itype *it;
291: struct ctf_lblent lbl;
292:
293: memset(imcs, 0, sizeof(*imcs));
294:
295: dbuf_realloc(&imcs->body, DBUF_CHUNKSZ);
296: dbuf_realloc(&imcs->stab, DBUF_CHUNKSZ);
297:
298: imcs->htab = hash_init(10);
299: if (imcs->htab == NULL)
300: err(1, "hash_init");
301:
302: /* Add empty string */
303: dbuf_copy(&imcs->stab, "", 1);
304:
305: /* We don't use parent label */
306: cth->cth_parlabel = 0;
307: cth->cth_parname = 0;
308:
309: /* Insert a single label for all types. */
310: cth->cth_lbloff = 0;
311: lbl.ctl_label = imcs_add_string(imcs, label);
312: lbl.ctl_typeidx = tidx;
313: dbuf_copy(&imcs->body, &lbl, sizeof(lbl));
314:
315: /* Insert objects */
316: cth->cth_objtoff = dbuf_pad(&imcs->body, 2);
317: TAILQ_FOREACH(it, &iobjq, it_symb)
318: imcs_add_obj(imcs, it);
319:
320: /* Insert functions */
321: cth->cth_funcoff = dbuf_pad(&imcs->body, 2);
322: TAILQ_FOREACH(it, &ifuncq, it_symb)
323: imcs_add_func(imcs, it);
324:
325: /* Insert types */
326: cth->cth_typeoff = dbuf_pad(&imcs->body, 4);
327: TAILQ_FOREACH(it, &itypeq, it_next) {
328: if (it->it_flags & (ITF_FUNC|ITF_OBJ))
329: continue;
330:
331: imcs_add_type(imcs, it);
332: }
333:
334: /* String table is written from its own buffer. */
335: cth->cth_stroff = imcs->body.coff;
336: cth->cth_strlen = imcs->stab.coff;
337: }
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: struct ctf_header cth;
348: struct imcs imcs;
1.4 ! mpi 349: int error = 0, fd;
1.1 mpi 350:
351: memset(&cth, 0, sizeof(cth));
352:
353: cth.cth_magic = CTF_MAGIC;
354: cth.cth_version = CTF_VERSION;
355:
356: #ifdef ZLIB
357: if (compress)
358: cth.cth_flags = CTF_F_COMPRESS;
359: #endif /* ZLIB */
360:
361: imcs_generate(&imcs, &cth, label);
362:
363: ctflen = sizeof(cth) + imcs.body.coff + imcs.stab.coff;
364: p = ctfdata = xmalloc(ctflen);
365:
366: memcpy(p, &cth, sizeof(cth));
367: p += sizeof(cth);
368:
369: memcpy(p, imcs.body.data, imcs.body.coff);
370: p += imcs.body.coff;
371:
372: memcpy(p, imcs.stab.data, imcs.stab.coff);
373: p += imcs.stab.coff;
374:
375: assert((p - ctfdata) == ctflen);
376:
377: #ifdef ZLIB
378: if (compress) {
379: char *cdata;
380: size_t clen;
381:
382: cdata = data_compress(ctfdata + sizeof(cth),
383: ctflen - sizeof(cth), ctflen - sizeof(cth), &clen);
384: if (cdata == NULL) {
385: warnx("compressing CTF data");
386: free(ctfdata);
387: return -1;
388: }
389:
390: memcpy(ctfdata + sizeof(cth), cdata, clen);
391: ctflen = clen + sizeof(cth);
392:
393: free(cdata);
394: }
395: #endif /* ZLIB */
396:
397: fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
398: if (fd == -1) {
399: warn("open %s", path);
400: free(ctfdata);
401: return -1;
402: }
403:
404: if (write(fd, ctfdata, ctflen) != ctflen) {
405: warn("unable to write %zd bytes for %s", ctflen, path);
406: error = -1;
407: }
408:
409: close(fd);
410: free(ctfdata);
1.4 ! mpi 411: return error;
1.1 mpi 412: }
413:
414: #ifdef ZLIB
415: char *
416: data_compress(const char *buf, size_t size, off_t len, size_t *pclen)
417: {
418: z_stream stream;
419: char *data;
420: int error;
421:
422: data = malloc(len);
423: if (data == NULL) {
424: warn(NULL);
425: return NULL;
426: }
427:
428: memset(&stream, 0, sizeof(stream));
429: stream.zalloc = Z_NULL;
430: stream.zfree = Z_NULL;
431: stream.opaque = Z_NULL;
432:
433: if ((error = deflateInit(&stream, Z_BEST_COMPRESSION)) != Z_OK) {
434: warnx("zlib deflateInit failed: %s", zError(error));
435: goto exit;
436: }
437:
438: stream.next_in = (void *)buf;
439: stream.avail_in = size;
440: stream.next_out = (unsigned char *)data;
441: stream.avail_out = len;
442:
443: 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: if ((error = deflateEnd(&stream)) != Z_OK) {
450: warnx("zlib deflateEnd failed: %s", zError(error));
451: goto exit;
452: }
453:
454: if (pclen != NULL)
455: *pclen = stream.total_out;
456:
457: return data;
458:
459: exit:
460: free(data);
461: return NULL;
462: }
463: #endif /* ZLIB */