dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libctf / common / ctf_lib.c
blob596896e16175f391279eb482b1548056761b1665
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright (c) 2015, Joyent, Inc.
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33 #include <ctf_impl.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <dlfcn.h>
38 #include <gelf.h>
39 #include <zlib.h>
40 #include <sys/debug.h>
42 #ifdef _LP64
43 static const char *_libctf_zlib = "/usr/lib/64/libz.so.1";
44 #else
45 static const char *_libctf_zlib = "/usr/lib/libz.so.1";
46 #endif
48 static struct {
49 int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t);
50 int (*z_initcomp)(z_stream *, int, const char *, int);
51 int (*z_compress)(z_stream *, int);
52 int (*z_finicomp)(z_stream *);
53 const char *(*z_error)(int);
54 void *z_dlp;
55 } zlib;
57 static size_t _PAGESIZE;
58 static size_t _PAGEMASK;
60 static uint64_t ctf_phase = 0;
62 #define CTF_COMPRESS_CHUNK (64*1024)
64 typedef struct ctf_zdata {
65 void *czd_buf;
66 void *czd_next;
67 ctf_file_t *czd_ctfp;
68 size_t czd_allocsz;
69 z_stream czd_zstr;
70 } ctf_zdata_t;
72 #pragma init(_libctf_init)
73 void
74 _libctf_init(void)
76 const char *p = getenv("LIBCTF_DECOMPRESSOR");
78 if (p != NULL)
79 _libctf_zlib = p; /* use alternate decompression library */
81 _libctf_debug = getenv("LIBCTF_DEBUG") != NULL;
83 _PAGESIZE = getpagesize();
84 _PAGEMASK = ~(_PAGESIZE - 1);
88 * Attempt to dlopen the decompression library and locate the symbols of
89 * interest that we will need to call. This information in cached so
90 * that multiple calls to ctf_bufopen() do not need to reopen the library.
92 void *
93 ctf_zopen(int *errp)
95 ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
97 if (zlib.z_dlp != NULL)
98 return (zlib.z_dlp); /* library is already loaded */
100 if (access(_libctf_zlib, R_OK) == -1)
101 return (ctf_set_open_errno(errp, ECTF_ZMISSING));
103 if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
104 return (ctf_set_open_errno(errp, ECTF_ZINIT));
106 zlib.z_uncompress = (int (*)()) dlsym(zlib.z_dlp, "uncompress");
107 zlib.z_initcomp = (int (*)()) dlsym(zlib.z_dlp, "deflateInit_");
108 zlib.z_compress = (int (*)()) dlsym(zlib.z_dlp, "deflate");
109 zlib.z_finicomp = (int (*)()) dlsym(zlib.z_dlp, "deflateEnd");
110 zlib.z_error = (const char *(*)()) dlsym(zlib.z_dlp, "zError");
112 if (zlib.z_uncompress == NULL || zlib.z_error == NULL ||
113 zlib.z_initcomp == NULL|| zlib.z_compress == NULL ||
114 zlib.z_finicomp == NULL) {
115 (void) dlclose(zlib.z_dlp);
116 bzero(&zlib, sizeof (zlib));
117 return (ctf_set_open_errno(errp, ECTF_ZINIT));
120 return (zlib.z_dlp);
124 * The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>,
125 * which we then patch through to the functions in the decompression library.
128 z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
130 return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen));
133 const char *
134 z_strerror(int err)
136 return (zlib.z_error(err));
139 static int
140 ctf_zdata_init(ctf_zdata_t *czd, ctf_file_t *fp)
142 ctf_header_t *cthp;
144 bzero(czd, sizeof (ctf_zdata_t));
146 czd->czd_allocsz = fp->ctf_size;
147 czd->czd_buf = ctf_data_alloc(czd->czd_allocsz);
148 if (czd->czd_buf == MAP_FAILED)
149 return (ctf_set_errno(fp, ENOMEM));
151 bcopy(fp->ctf_base, czd->czd_buf, sizeof (ctf_header_t));
152 czd->czd_ctfp = fp;
153 cthp = czd->czd_buf;
154 cthp->cth_flags |= CTF_F_COMPRESS;
155 czd->czd_next = (void *)((uintptr_t)czd->czd_buf +
156 sizeof (ctf_header_t));
158 if (zlib.z_initcomp(&czd->czd_zstr, Z_BEST_COMPRESSION,
159 ZLIB_VERSION, sizeof (z_stream)) != Z_OK)
160 return (ctf_set_errno(fp, ECTF_ZLIB));
162 return (0);
165 static int
166 ctf_zdata_grow(ctf_zdata_t *czd)
168 size_t off;
169 size_t newsz;
170 void *ndata;
172 off = (uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf;
173 newsz = czd->czd_allocsz + CTF_COMPRESS_CHUNK;
174 ndata = ctf_data_alloc(newsz);
175 if (ndata == MAP_FAILED) {
176 return (ctf_set_errno(czd->czd_ctfp, ENOMEM));
179 bcopy(czd->czd_buf, ndata, off);
180 ctf_data_free(czd->czd_buf, czd->czd_allocsz);
181 czd->czd_allocsz = newsz;
182 czd->czd_buf = ndata;
183 czd->czd_next = (void *)((uintptr_t)ndata + off);
185 czd->czd_zstr.next_out = (Bytef *)czd->czd_next;
186 czd->czd_zstr.avail_out = CTF_COMPRESS_CHUNK;
187 return (0);
190 static int
191 ctf_zdata_compress_buffer(ctf_zdata_t *czd, const void *buf, size_t bufsize)
193 int err;
195 czd->czd_zstr.next_out = czd->czd_next;
196 czd->czd_zstr.avail_out = czd->czd_allocsz -
197 ((uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf);
198 czd->czd_zstr.next_in = (Bytef *)buf;
199 czd->czd_zstr.avail_in = bufsize;
201 while (czd->czd_zstr.avail_in != 0) {
202 if (czd->czd_zstr.avail_out == 0) {
203 czd->czd_next = czd->czd_zstr.next_out;
204 if ((err = ctf_zdata_grow(czd)) != 0) {
205 return (err);
209 if ((err = zlib.z_compress(&czd->czd_zstr, Z_NO_FLUSH)) != Z_OK)
210 return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
212 czd->czd_next = czd->czd_zstr.next_out;
214 return (0);
217 static int
218 ctf_zdata_flush(ctf_zdata_t *czd, boolean_t finish)
220 int err;
221 int flag = finish == B_TRUE ? Z_FINISH : Z_FULL_FLUSH;
222 int bret = finish == B_TRUE ? Z_STREAM_END : Z_BUF_ERROR;
224 for (;;) {
225 if (czd->czd_zstr.avail_out == 0) {
226 czd->czd_next = czd->czd_zstr.next_out;
227 if ((err = ctf_zdata_grow(czd)) != 0) {
228 return (err);
232 err = zlib.z_compress(&czd->czd_zstr, flag);
233 if (err == bret) {
234 break;
236 if (err != Z_OK)
237 return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
241 czd->czd_next = czd->czd_zstr.next_out;
243 return (0);
246 static int
247 ctf_zdata_end(ctf_zdata_t *czd)
249 int ret;
251 if ((ret = ctf_zdata_flush(czd, B_TRUE)) != 0)
252 return (ret);
254 if ((ret = zlib.z_finicomp(&czd->czd_zstr)) != 0)
255 return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
257 return (0);
260 static void
261 ctf_zdata_cleanup(ctf_zdata_t *czd)
263 ctf_data_free(czd->czd_buf, czd->czd_allocsz);
264 (void) zlib.z_finicomp(&czd->czd_zstr);
268 * Compress our CTF data and return both the size of the compressed data and the
269 * size of the allocation. These may be different due to the nature of
270 * compression.
272 * In addition, we flush the compression inbetween our two phases such that we
273 * maintain a different dictionary bbetween the CTF data and the string section.
276 ctf_compress(ctf_file_t *fp, void **buf, size_t *allocsz, size_t *elfsize)
278 int err;
279 ctf_zdata_t czd;
280 ctf_header_t *cthp;
282 /* LINTED: E_BAD_PTR_CAST_ALIGN */
283 cthp = (ctf_header_t *)fp->ctf_base;
285 if ((err = ctf_zdata_init(&czd, fp)) != 0)
286 return (err);
288 if ((err = ctf_zdata_compress_buffer(&czd, fp->ctf_buf,
289 cthp->cth_stroff)) != 0) {
290 ctf_zdata_cleanup(&czd);
291 return (err);
294 if ((err = ctf_zdata_flush(&czd, B_FALSE)) != 0) {
295 ctf_zdata_cleanup(&czd);
296 return (err);
299 if ((err = ctf_zdata_compress_buffer(&czd,
300 fp->ctf_buf + cthp->cth_stroff, cthp->cth_strlen)) != 0) {
301 ctf_zdata_cleanup(&czd);
302 return (err);
305 if ((err = ctf_zdata_end(&czd)) != 0) {
306 ctf_zdata_cleanup(&czd);
307 return (err);
310 *buf = czd.czd_buf;
311 *allocsz = czd.czd_allocsz;
312 *elfsize = (uintptr_t)czd.czd_next - (uintptr_t)czd.czd_buf;
314 return (0);
318 z_compress(void *dst, size_t *dstlen, const void *src, size_t srclen)
320 z_stream zs;
321 int err;
323 bzero(&zs, sizeof (z_stream));
324 zs.next_in = (uchar_t *)src;
325 zs.avail_in = srclen;
326 zs.next_out = dst;
327 zs.avail_out = *dstlen;
329 if ((err = zlib.z_initcomp(&zs, Z_BEST_COMPRESSION, ZLIB_VERSION,
330 sizeof (z_stream))) != Z_OK)
331 return (err);
333 if ((err = zlib.z_compress(&zs, Z_FINISH)) != Z_STREAM_END) {
334 (void) zlib.z_finicomp(&zs);
335 return (err == Z_OK ? Z_BUF_ERROR : err);
338 *dstlen = zs.total_out;
339 return (zlib.z_finicomp(&zs));
343 * Convert a 32-bit ELF file header into GElf.
345 static void
346 ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
348 bcopy(src->e_ident, dst->e_ident, EI_NIDENT);
349 dst->e_type = src->e_type;
350 dst->e_machine = src->e_machine;
351 dst->e_version = src->e_version;
352 dst->e_entry = (Elf64_Addr)src->e_entry;
353 dst->e_phoff = (Elf64_Off)src->e_phoff;
354 dst->e_shoff = (Elf64_Off)src->e_shoff;
355 dst->e_flags = src->e_flags;
356 dst->e_ehsize = src->e_ehsize;
357 dst->e_phentsize = src->e_phentsize;
358 dst->e_phnum = src->e_phnum;
359 dst->e_shentsize = src->e_shentsize;
360 dst->e_shnum = src->e_shnum;
361 dst->e_shstrndx = src->e_shstrndx;
365 * Convert a 32-bit ELF section header into GElf.
367 static void
368 shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
370 dst->sh_name = src->sh_name;
371 dst->sh_type = src->sh_type;
372 dst->sh_flags = src->sh_flags;
373 dst->sh_addr = src->sh_addr;
374 dst->sh_offset = src->sh_offset;
375 dst->sh_size = src->sh_size;
376 dst->sh_link = src->sh_link;
377 dst->sh_info = src->sh_info;
378 dst->sh_addralign = src->sh_addralign;
379 dst->sh_entsize = src->sh_entsize;
383 * In order to mmap a section from the ELF file, we must round down sh_offset
384 * to the previous page boundary, and mmap the surrounding page. We store
385 * the pointer to the start of the actual section data back into sp->cts_data.
387 const void *
388 ctf_sect_mmap(ctf_sect_t *sp, int fd)
390 size_t pageoff = sp->cts_offset & ~_PAGEMASK;
392 caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ,
393 MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK);
395 if (base != MAP_FAILED)
396 sp->cts_data = base + pageoff;
398 return (base);
402 * Since sp->cts_data has the adjusted offset, we have to again round down
403 * to get the actual mmap address and round up to get the size.
405 void
406 ctf_sect_munmap(const ctf_sect_t *sp)
408 uintptr_t addr = (uintptr_t)sp->cts_data;
409 uintptr_t pageoff = addr & ~_PAGEMASK;
411 (void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff);
415 * Open the specified file descriptor and return a pointer to a CTF container.
416 * The file can be either an ELF file or raw CTF file. The caller is
417 * responsible for closing the file descriptor when it is no longer needed.
419 ctf_file_t *
420 ctf_fdcreate_int(int fd, int *errp, ctf_sect_t *ctfp)
422 ctf_sect_t ctfsect, symsect, strsect;
423 ctf_file_t *fp = NULL;
424 size_t shstrndx, shnum;
426 struct stat64 st;
427 ssize_t nbytes;
429 union {
430 ctf_preamble_t ctf;
431 Elf32_Ehdr e32;
432 GElf_Ehdr e64;
433 } hdr;
435 bzero(&ctfsect, sizeof (ctf_sect_t));
436 bzero(&symsect, sizeof (ctf_sect_t));
437 bzero(&strsect, sizeof (ctf_sect_t));
438 bzero(&hdr.ctf, sizeof (hdr));
440 if (fstat64(fd, &st) == -1)
441 return (ctf_set_open_errno(errp, errno));
443 if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0)
444 return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT));
447 * If we have read enough bytes to form a CTF header and the magic
448 * string matches, attempt to interpret the file as raw CTF.
450 if (nbytes >= sizeof (ctf_preamble_t) &&
451 hdr.ctf.ctp_magic == CTF_MAGIC) {
452 if (ctfp != NULL)
453 return (ctf_set_open_errno(errp, EINVAL));
455 if (hdr.ctf.ctp_version > CTF_VERSION)
456 return (ctf_set_open_errno(errp, ECTF_CTFVERS));
458 ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ,
459 MAP_PRIVATE, fd, 0);
461 if (ctfsect.cts_data == MAP_FAILED)
462 return (ctf_set_open_errno(errp, errno));
464 ctfsect.cts_name = _CTF_SECTION;
465 ctfsect.cts_type = SHT_PROGBITS;
466 ctfsect.cts_flags = SHF_ALLOC;
467 ctfsect.cts_size = (size_t)st.st_size;
468 ctfsect.cts_entsize = 1;
469 ctfsect.cts_offset = 0;
471 if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL)
472 ctf_sect_munmap(&ctfsect);
474 return (fp);
478 * If we have read enough bytes to form an ELF header and the magic
479 * string matches, attempt to interpret the file as an ELF file. We
480 * do our own largefile ELF processing, and convert everything to
481 * GElf structures so that clients can operate on any data model.
483 if (nbytes >= sizeof (Elf32_Ehdr) &&
484 bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
485 #ifdef _BIG_ENDIAN
486 uchar_t order = ELFDATA2MSB;
487 #else
488 uchar_t order = ELFDATA2LSB;
489 #endif
490 GElf_Shdr *sp;
492 void *strs_map;
493 size_t strs_mapsz, i;
494 const char *strs;
496 if (hdr.e32.e_ident[EI_DATA] != order)
497 return (ctf_set_open_errno(errp, ECTF_ENDIAN));
498 if (hdr.e32.e_version != EV_CURRENT)
499 return (ctf_set_open_errno(errp, ECTF_ELFVERS));
501 if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) {
502 if (nbytes < sizeof (GElf_Ehdr))
503 return (ctf_set_open_errno(errp, ECTF_FMT));
504 } else {
505 Elf32_Ehdr e32 = hdr.e32;
506 ehdr_to_gelf(&e32, &hdr.e64);
509 shnum = hdr.e64.e_shnum;
510 shstrndx = hdr.e64.e_shstrndx;
512 /* Extended ELF sections */
513 if ((shstrndx == SHN_XINDEX) || (shnum == 0)) {
514 if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
515 Elf32_Shdr x32;
517 if (pread64(fd, &x32, sizeof (x32),
518 hdr.e64.e_shoff) != sizeof (x32))
519 return (ctf_set_open_errno(errp,
520 errno));
522 shnum = x32.sh_size;
523 shstrndx = x32.sh_link;
524 } else {
525 Elf64_Shdr x64;
527 if (pread64(fd, &x64, sizeof (x64),
528 hdr.e64.e_shoff) != sizeof (x64))
529 return (ctf_set_open_errno(errp,
530 errno));
532 shnum = x64.sh_size;
533 shstrndx = x64.sh_link;
537 if (shstrndx >= shnum)
538 return (ctf_set_open_errno(errp, ECTF_CORRUPT));
540 nbytes = sizeof (GElf_Shdr) * shnum;
542 if ((sp = malloc(nbytes)) == NULL)
543 return (ctf_set_open_errno(errp, errno));
546 * Read in and convert to GElf the array of Shdr structures
547 * from e_shoff so we can locate sections of interest.
549 if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
550 Elf32_Shdr *sp32;
552 nbytes = sizeof (Elf32_Shdr) * shnum;
554 if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
555 sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
556 free(sp);
557 return (ctf_set_open_errno(errp, errno));
560 for (i = 0; i < shnum; i++)
561 shdr_to_gelf(&sp32[i], &sp[i]);
563 free(sp32);
565 } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {
566 free(sp);
567 return (ctf_set_open_errno(errp, errno));
571 * Now mmap the section header strings section so that we can
572 * perform string comparison on the section names.
574 strs_mapsz = sp[shstrndx].sh_size +
575 (sp[shstrndx].sh_offset & ~_PAGEMASK);
577 strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
578 fd, sp[shstrndx].sh_offset & _PAGEMASK);
580 strs = (const char *)strs_map +
581 (sp[shstrndx].sh_offset & ~_PAGEMASK);
583 if (strs_map == MAP_FAILED) {
584 free(sp);
585 return (ctf_set_open_errno(errp, ECTF_MMAP));
589 * Iterate over the section header array looking for the CTF
590 * section and symbol table. The strtab is linked to symtab.
592 for (i = 0; i < shnum; i++) {
593 const GElf_Shdr *shp = &sp[i];
594 const GElf_Shdr *lhp = &sp[shp->sh_link];
596 if (shp->sh_link >= shnum)
597 continue; /* corrupt sh_link field */
599 if (shp->sh_name >= sp[shstrndx].sh_size ||
600 lhp->sh_name >= sp[shstrndx].sh_size)
601 continue; /* corrupt sh_name field */
603 if (shp->sh_type == SHT_PROGBITS &&
604 strcmp(strs + shp->sh_name, _CTF_SECTION) == 0 &&
605 ctfp == NULL) {
606 ctfsect.cts_name = strs + shp->sh_name;
607 ctfsect.cts_type = shp->sh_type;
608 ctfsect.cts_flags = shp->sh_flags;
609 ctfsect.cts_size = shp->sh_size;
610 ctfsect.cts_entsize = shp->sh_entsize;
611 ctfsect.cts_offset = (off64_t)shp->sh_offset;
613 } else if (shp->sh_type == SHT_SYMTAB) {
614 symsect.cts_name = strs + shp->sh_name;
615 symsect.cts_type = shp->sh_type;
616 symsect.cts_flags = shp->sh_flags;
617 symsect.cts_size = shp->sh_size;
618 symsect.cts_entsize = shp->sh_entsize;
619 symsect.cts_offset = (off64_t)shp->sh_offset;
621 strsect.cts_name = strs + lhp->sh_name;
622 strsect.cts_type = lhp->sh_type;
623 strsect.cts_flags = lhp->sh_flags;
624 strsect.cts_size = lhp->sh_size;
625 strsect.cts_entsize = lhp->sh_entsize;
626 strsect.cts_offset = (off64_t)lhp->sh_offset;
630 free(sp); /* free section header array */
632 if (ctfp == NULL) {
633 if (ctfsect.cts_type == SHT_NULL && ctfp == NULL) {
634 (void) munmap(strs_map, strs_mapsz);
635 return (ctf_set_open_errno(errp,
636 ECTF_NOCTFDATA));
640 * Now mmap the CTF data, symtab, and strtab sections
641 * and call ctf_bufopen() to do the rest of the work.
643 if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
644 (void) munmap(strs_map, strs_mapsz);
645 return (ctf_set_open_errno(errp, ECTF_MMAP));
647 ctfp = &ctfsect;
650 if (symsect.cts_type != SHT_NULL &&
651 strsect.cts_type != SHT_NULL) {
652 if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED ||
653 ctf_sect_mmap(&strsect, fd) == MAP_FAILED) {
654 (void) ctf_set_open_errno(errp, ECTF_MMAP);
655 goto bad; /* unmap all and abort */
657 fp = ctf_bufopen(ctfp, &symsect, &strsect, errp);
658 } else
659 fp = ctf_bufopen(ctfp, NULL, NULL, errp);
660 bad:
661 if (fp == NULL) {
662 if (ctfp == NULL)
663 ctf_sect_munmap(&ctfsect);
664 ctf_sect_munmap(&symsect);
665 ctf_sect_munmap(&strsect);
666 } else
667 fp->ctf_flags |= LCTF_MMAP;
669 (void) munmap(strs_map, strs_mapsz);
670 return (fp);
673 return (ctf_set_open_errno(errp, ECTF_FMT));
676 ctf_file_t *
677 ctf_fdopen(int fd, int *errp)
679 return (ctf_fdcreate_int(fd, errp, NULL));
683 * Open the specified file and return a pointer to a CTF container. The file
684 * can be either an ELF file or raw CTF file. This is just a convenient
685 * wrapper around ctf_fdopen() for callers.
687 ctf_file_t *
688 ctf_open(const char *filename, int *errp)
690 ctf_file_t *fp;
691 int fd;
693 if ((fd = open64(filename, O_RDONLY)) == -1) {
694 if (errp != NULL)
695 *errp = errno;
696 return (NULL);
699 fp = ctf_fdopen(fd, errp);
700 (void) close(fd);
701 return (fp);
705 * Write the uncompressed CTF data stream to the specified file descriptor.
706 * This is useful for saving the results of dynamic CTF containers.
709 ctf_write(ctf_file_t *fp, int fd)
711 const uchar_t *buf = fp->ctf_base;
712 ssize_t resid = fp->ctf_size;
713 ssize_t len;
715 while (resid != 0) {
716 if ((len = write(fd, buf, resid)) <= 0)
717 return (ctf_set_errno(fp, errno));
718 resid -= len;
719 buf += len;
722 return (0);
726 * Set the CTF library client version to the specified version. If version is
727 * zero, we just return the default library version number.
730 ctf_version(int version)
732 if (version < 0) {
733 errno = EINVAL;
734 return (-1);
737 if (version > 0) {
738 if (version > CTF_VERSION) {
739 errno = ENOTSUP;
740 return (-1);
742 ctf_dprintf("ctf_version: client using version %d\n", version);
743 _libctf_version = version;
746 return (_libctf_version);
750 * A utility function for folks debugging CTF conversion and merging.
752 void
753 ctf_phase_dump(ctf_file_t *fp, const char *phase)
755 int fd;
756 static char *base;
757 char path[MAXPATHLEN];
759 if (base == NULL && (base = getenv("LIBCTF_WRITE_PHASES")) == NULL)
760 return;
762 (void) snprintf(path, sizeof (path), "%s/libctf.%s.%d.ctf", base,
763 phase != NULL ? phase : "",
764 ctf_phase);
765 if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0)
766 return;
767 (void) ctf_write(fp, fd);
768 (void) close(fd);