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 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, size_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 size_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 < 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 = 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 } 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; 349 int error = 0, fd; 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); 411 return error; 412 } 413 414 #ifdef ZLIB 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) { 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 */ 464