File: | src/usr.bin/ctfconv/generate.c |
Warning: | line 220, column 22 Access to field 'it_idx' results in a dereference of a null pointer (loaded from field 'it_refp') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: generate.c,v 1.5 2022/08/14 14:54:13 millert 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 ZLIB1 | |||
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)) ((((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) (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_strse_key.hkey se_key.hkey | |||
66 | size_t se_off; | |||
67 | }; | |||
68 | ||||
69 | #ifdef ZLIB1 | |||
70 | char *data_compress(const char *, size_t, size_t, size_t *); | |||
71 | #endif /* ZLIB */ | |||
72 | ||||
73 | void | |||
74 | dbuf_realloc(struct dbuf *dbuf, size_t len) | |||
75 | { | |||
76 | assert(dbuf != NULL)((dbuf != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c" , 76, __func__, "dbuf != NULL")); | |||
77 | assert(len != 0)((len != 0) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c" , 77, __func__, "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 | size_t left; | |||
88 | ||||
89 | assert(dbuf->cptr != NULL)((dbuf->cptr != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c" , 89, __func__, "dbuf->cptr != NULL")); | |||
90 | assert(dbuf->data != NULL)((dbuf->data != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c" , 90, __func__, "dbuf->data != NULL")); | |||
91 | assert(dbuf->size != 0)((dbuf->size != 0) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c" , 91, __func__, "dbuf->size != 0")); | |||
92 | ||||
93 | if (len == 0) | |||
94 | return; | |||
95 | ||||
96 | left = dbuf->size - dbuf->coff; | |||
97 | if (left < len) | |||
98 | dbuf_realloc(dbuf, ROUNDUP((len - left), DBUF_CHUNKSZ)(((((len - left)) + ((64 * 1024)) - 1) / ((64 * 1024))) * ((64 * 1024)))); | |||
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((void *)0) || *str == '\0') | |||
123 | return 0; | |||
124 | ||||
125 | se = (struct strentry *)hash_find(imcs->htab, str, &slot); | |||
126 | if (se == NULL((void *)0)) { | |||
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_VLEN0x03ff); | |||
149 | dbuf_copy(&imcs->body, &func, sizeof(func)); | |||
150 | ||||
151 | if (kind == CTF_K_UNKNOWN0) | |||
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)for((im) = ((&it->it_members)->tqh_first); (im) != ( (void *)0); (im) = ((im)->im_next.tqe_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)((it->it_type != 0 && it->it_type != 9) ? (void )0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c", 184, __func__ , "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_ctt_stype.cts_name = imcs_add_string(imcs, it_name(it)); | |||
192 | ctt.ctt_info_ctt_stype.cts_info = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN0x03ff); | |||
193 | ||||
194 | /* Base types don't have reference, typedef & pointer don't have size */ | |||
195 | if (it->it_refp != NULL((void *)0) && kind != CTF_K_ARRAY4) { | |||
196 | ctt.ctt_type_ctt_stype._ST._type = it->it_refp->it_idx; | |||
197 | ctsz = sizeof(struct ctf_stype); | |||
198 | } else if (size <= CTF_MAX_SIZE0xfffe) { | |||
199 | ctt.ctt_size_ctt_stype._ST._size = size; | |||
200 | ctsz = sizeof(struct ctf_stype); | |||
201 | } else { | |||
202 | ctt.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size)((uint32_t)((uint64_t)(size) >> 32)); | |||
203 | ctt.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size)((uint32_t)(size)); | |||
204 | ctt.ctt_size_ctt_stype._ST._size = CTF_LSIZE_SENT0xfffe +1; | |||
205 | ctsz = sizeof(struct ctf_type); | |||
206 | } | |||
207 | ||||
208 | dbuf_copy(&imcs->body, &ctt, ctsz); | |||
209 | ||||
210 | switch (kind) { | |||
211 | assert(1 == 0)((1 == 0) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c" , 211, __func__, "1 == 0")); | |||
212 | break; | |||
213 | case CTF_K_INTEGER1: | |||
214 | case CTF_K_FLOAT2: | |||
215 | eob = CTF_INT_DATA(it->it_enc, 0, size)(((it->it_enc) << 24) | ((0) << 16) | (size)); | |||
216 | dbuf_copy(&imcs->body, &eob, sizeof(eob)); | |||
217 | break; | |||
218 | case CTF_K_ARRAY4: | |||
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_STRUCT6: | |||
226 | case CTF_K_UNION7: | |||
227 | if (size < CTF_LSTRUCT_THRESH8192) { | |||
228 | struct ctf_member ctm; | |||
229 | ||||
230 | memset(&ctm, 0, sizeof(ctm)); | |||
231 | TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != ( (void *)0); (im) = ((im)->im_next.tqe_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)for((im) = ((&it->it_members)->tqh_first); (im) != ( (void *)0); (im) = ((im)->im_next.tqe_next)) { | |||
244 | ctlm.ctlm_name_ctlm_member.ctm_name = | |||
245 | imcs_add_string(imcs, im_name(im)); | |||
246 | ctlm.ctlm_type_ctlm_member.ctm_type = im->im_refp->it_idx; | |||
247 | ctlm.ctlm_offsethi = | |||
248 | CTF_OFFSET_TO_LMEMHI(im->im_off)((uint32_t)((uint64_t)(im->im_off) >> 32)); | |||
249 | ctlm.ctlm_offsetlo = | |||
250 | CTF_OFFSET_TO_LMEMLO(im->im_off)((uint32_t)(im->im_off)); | |||
251 | ||||
252 | ||||
253 | dbuf_copy(&imcs->body, &ctlm, sizeof(ctlm)); | |||
254 | } | |||
255 | } | |||
256 | break; | |||
257 | case CTF_K_FUNCTION5: | |||
258 | TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != ( (void *)0); (im) = ((im)->im_next.tqe_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_ENUM8: | |||
268 | TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != ( (void *)0); (im) = ((im)->im_next.tqe_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_POINTER3: | |||
278 | case CTF_K_TYPEDEF10: | |||
279 | case CTF_K_VOLATILE11: | |||
280 | case CTF_K_CONST12: | |||
281 | case CTF_K_RESTRICT13: | |||
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(64 * 1024)); | |||
296 | dbuf_realloc(&imcs->stab, DBUF_CHUNKSZ(64 * 1024)); | |||
297 | ||||
298 | imcs->htab = hash_init(10); | |||
299 | if (imcs->htab == NULL((void *)0)) | |||
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)for((it) = ((&iobjq)->tqh_first); (it) != ((void *)0); (it) = ((it)->it_symb.tqe_next)) | |||
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)for((it) = ((&ifuncq)->tqh_first); (it) != ((void *)0) ; (it) = ((it)->it_symb.tqe_next)) | |||
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)for((it) = ((&itypeq)->tqh_first); (it) != ((void *)0) ; (it) = ((it)->it_next.tqe_next)) { | |||
328 | if (it->it_flags & (ITF_FUNC0x04|ITF_OBJ0x08)) | |||
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((void *)0); | |||
346 | ssize_t ctflen; | |||
347 | struct ctf_header cth; | |||
348 | struct imcs imcs; | |||
349 | int error = 0, fd; | |||
350 | ||||
351 | memset(&cth, 0, sizeof(cth)); | |||
352 | ||||
353 | cth.cth_magic = CTF_MAGIC0xcff1; | |||
354 | cth.cth_version = CTF_VERSION2; | |||
355 | ||||
356 | #ifdef ZLIB1 | |||
357 | if (compress) | |||
| ||||
358 | cth.cth_flags = CTF_F_COMPRESS(1 << 0); | |||
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)(((p - ctfdata) == ctflen) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c" , 375, __func__, "(p - ctfdata) == ctflen")); | |||
376 | ||||
377 | #ifdef ZLIB1 | |||
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((void *)0)) { | |||
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_WRONLY0x0001 | O_CREAT0x0200 | O_TRUNC0x0400, 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); | |||
411 | return error; | |||
412 | } | |||
413 | ||||
414 | #ifdef ZLIB1 | |||
415 | char * | |||
416 | data_compress(const char *buf, size_t size, size_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((void *)0)) { | |||
424 | warn(NULL((void *)0)); | |||
425 | return NULL((void *)0); | |||
426 | } | |||
427 | ||||
428 | memset(&stream, 0, sizeof(stream)); | |||
429 | stream.zalloc = Z_NULL0; | |||
430 | stream.zfree = Z_NULL0; | |||
431 | stream.opaque = Z_NULL0; | |||
432 | ||||
433 | if ((error = deflateInit(&stream, Z_BEST_COMPRESSION)deflateInit_((&stream), (9), "1.3.0.1-motley", (int)sizeof (z_stream))) != Z_OK0) { | |||
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_FINISH4)) != Z_STREAM_END1) { | |||
444 | warnx("zlib deflate failed: %s", zError(error)); | |||
445 | deflateEnd(&stream); | |||
446 | goto exit; | |||
447 | } | |||
448 | ||||
449 | if ((error = deflateEnd(&stream)) != Z_OK0) { | |||
450 | warnx("zlib deflateEnd failed: %s", zError(error)); | |||
451 | goto exit; | |||
452 | } | |||
453 | ||||
454 | if (pclen != NULL((void *)0)) | |||
455 | *pclen = stream.total_out; | |||
456 | ||||
457 | return data; | |||
458 | ||||
459 | exit: | |||
460 | free(data); | |||
461 | return NULL((void *)0); | |||
462 | } | |||
463 | #endif /* ZLIB */ |