17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
26*f3e7f55eSRobert Mustacchi /*
27*f3e7f55eSRobert Mustacchi * Copyright (c) 2015, Joyent, Inc.
28*f3e7f55eSRobert Mustacchi */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/stat.h>
327c478bd9Sstevel@tonic-gate #include <sys/mman.h>
337c478bd9Sstevel@tonic-gate #include <ctf_impl.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <dlfcn.h>
387c478bd9Sstevel@tonic-gate #include <gelf.h>
39*f3e7f55eSRobert Mustacchi #include <zlib.h>
40*f3e7f55eSRobert Mustacchi #include <sys/debug.h>
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate #ifdef _LP64
432f970cc1SKeith M Wesolowski static const char *_libctf_zlib = "/usr/lib/64/libz.so.1";
447c478bd9Sstevel@tonic-gate #else
452f970cc1SKeith M Wesolowski static const char *_libctf_zlib = "/usr/lib/libz.so.1";
467c478bd9Sstevel@tonic-gate #endif
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate static struct {
497c478bd9Sstevel@tonic-gate int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t);
50*f3e7f55eSRobert Mustacchi int (*z_initcomp)(z_stream *, int, const char *, int);
51*f3e7f55eSRobert Mustacchi int (*z_compress)(z_stream *, int);
52*f3e7f55eSRobert Mustacchi int (*z_finicomp)(z_stream *);
537c478bd9Sstevel@tonic-gate const char *(*z_error)(int);
547c478bd9Sstevel@tonic-gate void *z_dlp;
557c478bd9Sstevel@tonic-gate } zlib;
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate static size_t _PAGESIZE;
587c478bd9Sstevel@tonic-gate static size_t _PAGEMASK;
597c478bd9Sstevel@tonic-gate
60*f3e7f55eSRobert Mustacchi static uint64_t ctf_phase = 0;
61*f3e7f55eSRobert Mustacchi
62*f3e7f55eSRobert Mustacchi #define CTF_COMPRESS_CHUNK (64*1024)
63*f3e7f55eSRobert Mustacchi
64*f3e7f55eSRobert Mustacchi typedef struct ctf_zdata {
65*f3e7f55eSRobert Mustacchi void *czd_buf;
66*f3e7f55eSRobert Mustacchi void *czd_next;
67*f3e7f55eSRobert Mustacchi ctf_file_t *czd_ctfp;
68*f3e7f55eSRobert Mustacchi size_t czd_allocsz;
69*f3e7f55eSRobert Mustacchi z_stream czd_zstr;
70*f3e7f55eSRobert Mustacchi } ctf_zdata_t;
71*f3e7f55eSRobert Mustacchi
727c478bd9Sstevel@tonic-gate #pragma init(_libctf_init)
737c478bd9Sstevel@tonic-gate void
_libctf_init(void)747c478bd9Sstevel@tonic-gate _libctf_init(void)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate const char *p = getenv("LIBCTF_DECOMPRESSOR");
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate if (p != NULL)
797c478bd9Sstevel@tonic-gate _libctf_zlib = p; /* use alternate decompression library */
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate _libctf_debug = getenv("LIBCTF_DEBUG") != NULL;
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate _PAGESIZE = getpagesize();
847c478bd9Sstevel@tonic-gate _PAGEMASK = ~(_PAGESIZE - 1);
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate * Attempt to dlopen the decompression library and locate the symbols of
897c478bd9Sstevel@tonic-gate * interest that we will need to call. This information in cached so
907c478bd9Sstevel@tonic-gate * that multiple calls to ctf_bufopen() do not need to reopen the library.
917c478bd9Sstevel@tonic-gate */
927c478bd9Sstevel@tonic-gate void *
ctf_zopen(int * errp)937c478bd9Sstevel@tonic-gate ctf_zopen(int *errp)
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate if (zlib.z_dlp != NULL)
987c478bd9Sstevel@tonic-gate return (zlib.z_dlp); /* library is already loaded */
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate if (access(_libctf_zlib, R_OK) == -1)
1017c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ZMISSING));
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
1047c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ZINIT));
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate zlib.z_uncompress = (int (*)()) dlsym(zlib.z_dlp, "uncompress");
107*f3e7f55eSRobert Mustacchi zlib.z_initcomp = (int (*)()) dlsym(zlib.z_dlp, "deflateInit_");
108*f3e7f55eSRobert Mustacchi zlib.z_compress = (int (*)()) dlsym(zlib.z_dlp, "deflate");
109*f3e7f55eSRobert Mustacchi zlib.z_finicomp = (int (*)()) dlsym(zlib.z_dlp, "deflateEnd");
1107c478bd9Sstevel@tonic-gate zlib.z_error = (const char *(*)()) dlsym(zlib.z_dlp, "zError");
1117c478bd9Sstevel@tonic-gate
112*f3e7f55eSRobert Mustacchi if (zlib.z_uncompress == NULL || zlib.z_error == NULL ||
113*f3e7f55eSRobert Mustacchi zlib.z_initcomp == NULL|| zlib.z_compress == NULL ||
114*f3e7f55eSRobert Mustacchi zlib.z_finicomp == NULL) {
1157c478bd9Sstevel@tonic-gate (void) dlclose(zlib.z_dlp);
1167c478bd9Sstevel@tonic-gate bzero(&zlib, sizeof (zlib));
1177c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ZINIT));
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate return (zlib.z_dlp);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>,
1257c478bd9Sstevel@tonic-gate * which we then patch through to the functions in the decompression library.
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate int
z_uncompress(void * dst,size_t * dstlen,const void * src,size_t srclen)1287c478bd9Sstevel@tonic-gate z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen));
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate const char *
z_strerror(int err)1347c478bd9Sstevel@tonic-gate z_strerror(int err)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate return (zlib.z_error(err));
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate
139*f3e7f55eSRobert Mustacchi static int
ctf_zdata_init(ctf_zdata_t * czd,ctf_file_t * fp)140*f3e7f55eSRobert Mustacchi ctf_zdata_init(ctf_zdata_t *czd, ctf_file_t *fp)
141*f3e7f55eSRobert Mustacchi {
142*f3e7f55eSRobert Mustacchi ctf_header_t *cthp;
143*f3e7f55eSRobert Mustacchi
144*f3e7f55eSRobert Mustacchi bzero(czd, sizeof (ctf_zdata_t));
145*f3e7f55eSRobert Mustacchi
146*f3e7f55eSRobert Mustacchi czd->czd_allocsz = fp->ctf_size;
147*f3e7f55eSRobert Mustacchi czd->czd_buf = ctf_data_alloc(czd->czd_allocsz);
148*f3e7f55eSRobert Mustacchi if (czd->czd_buf == MAP_FAILED)
149*f3e7f55eSRobert Mustacchi return (ctf_set_errno(fp, ENOMEM));
150*f3e7f55eSRobert Mustacchi
151*f3e7f55eSRobert Mustacchi bcopy(fp->ctf_base, czd->czd_buf, sizeof (ctf_header_t));
152*f3e7f55eSRobert Mustacchi czd->czd_ctfp = fp;
153*f3e7f55eSRobert Mustacchi cthp = czd->czd_buf;
154*f3e7f55eSRobert Mustacchi cthp->cth_flags |= CTF_F_COMPRESS;
155*f3e7f55eSRobert Mustacchi czd->czd_next = (void *)((uintptr_t)czd->czd_buf +
156*f3e7f55eSRobert Mustacchi sizeof (ctf_header_t));
157*f3e7f55eSRobert Mustacchi
158*f3e7f55eSRobert Mustacchi if (zlib.z_initcomp(&czd->czd_zstr, Z_BEST_COMPRESSION,
159*f3e7f55eSRobert Mustacchi ZLIB_VERSION, sizeof (z_stream)) != Z_OK)
160*f3e7f55eSRobert Mustacchi return (ctf_set_errno(fp, ECTF_ZLIB));
161*f3e7f55eSRobert Mustacchi
162*f3e7f55eSRobert Mustacchi return (0);
163*f3e7f55eSRobert Mustacchi }
164*f3e7f55eSRobert Mustacchi
165*f3e7f55eSRobert Mustacchi static int
ctf_zdata_grow(ctf_zdata_t * czd)166*f3e7f55eSRobert Mustacchi ctf_zdata_grow(ctf_zdata_t *czd)
167*f3e7f55eSRobert Mustacchi {
168*f3e7f55eSRobert Mustacchi size_t off;
169*f3e7f55eSRobert Mustacchi size_t newsz;
170*f3e7f55eSRobert Mustacchi void *ndata;
171*f3e7f55eSRobert Mustacchi
172*f3e7f55eSRobert Mustacchi off = (uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf;
173*f3e7f55eSRobert Mustacchi newsz = czd->czd_allocsz + CTF_COMPRESS_CHUNK;
174*f3e7f55eSRobert Mustacchi ndata = ctf_data_alloc(newsz);
175*f3e7f55eSRobert Mustacchi if (ndata == MAP_FAILED) {
176*f3e7f55eSRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ENOMEM));
177*f3e7f55eSRobert Mustacchi }
178*f3e7f55eSRobert Mustacchi
179*f3e7f55eSRobert Mustacchi bcopy(czd->czd_buf, ndata, off);
180*f3e7f55eSRobert Mustacchi ctf_data_free(czd->czd_buf, czd->czd_allocsz);
181*f3e7f55eSRobert Mustacchi czd->czd_allocsz = newsz;
182*f3e7f55eSRobert Mustacchi czd->czd_buf = ndata;
183*f3e7f55eSRobert Mustacchi czd->czd_next = (void *)((uintptr_t)ndata + off);
184*f3e7f55eSRobert Mustacchi
185*f3e7f55eSRobert Mustacchi czd->czd_zstr.next_out = (Bytef *)czd->czd_next;
186*f3e7f55eSRobert Mustacchi czd->czd_zstr.avail_out = CTF_COMPRESS_CHUNK;
187*f3e7f55eSRobert Mustacchi return (0);
188*f3e7f55eSRobert Mustacchi }
189*f3e7f55eSRobert Mustacchi
190*f3e7f55eSRobert Mustacchi static int
ctf_zdata_compress_buffer(ctf_zdata_t * czd,const void * buf,size_t bufsize)191*f3e7f55eSRobert Mustacchi ctf_zdata_compress_buffer(ctf_zdata_t *czd, const void *buf, size_t bufsize)
192*f3e7f55eSRobert Mustacchi {
193*f3e7f55eSRobert Mustacchi int err;
194*f3e7f55eSRobert Mustacchi
195*f3e7f55eSRobert Mustacchi czd->czd_zstr.next_out = czd->czd_next;
196*f3e7f55eSRobert Mustacchi czd->czd_zstr.avail_out = czd->czd_allocsz -
197*f3e7f55eSRobert Mustacchi ((uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf);
198*f3e7f55eSRobert Mustacchi czd->czd_zstr.next_in = (Bytef *)buf;
199*f3e7f55eSRobert Mustacchi czd->czd_zstr.avail_in = bufsize;
200*f3e7f55eSRobert Mustacchi
201*f3e7f55eSRobert Mustacchi while (czd->czd_zstr.avail_in != 0) {
202*f3e7f55eSRobert Mustacchi if (czd->czd_zstr.avail_out == 0) {
203*f3e7f55eSRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out;
204*f3e7f55eSRobert Mustacchi if ((err = ctf_zdata_grow(czd)) != 0) {
205*f3e7f55eSRobert Mustacchi return (err);
206*f3e7f55eSRobert Mustacchi }
207*f3e7f55eSRobert Mustacchi }
208*f3e7f55eSRobert Mustacchi
209*f3e7f55eSRobert Mustacchi if ((err = zlib.z_compress(&czd->czd_zstr, Z_NO_FLUSH)) != Z_OK)
210*f3e7f55eSRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
211*f3e7f55eSRobert Mustacchi }
212*f3e7f55eSRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out;
213*f3e7f55eSRobert Mustacchi
214*f3e7f55eSRobert Mustacchi return (0);
215*f3e7f55eSRobert Mustacchi }
216*f3e7f55eSRobert Mustacchi
217*f3e7f55eSRobert Mustacchi static int
ctf_zdata_flush(ctf_zdata_t * czd,boolean_t finish)218*f3e7f55eSRobert Mustacchi ctf_zdata_flush(ctf_zdata_t *czd, boolean_t finish)
219*f3e7f55eSRobert Mustacchi {
220*f3e7f55eSRobert Mustacchi int err;
221*f3e7f55eSRobert Mustacchi int flag = finish == B_TRUE ? Z_FINISH : Z_FULL_FLUSH;
222*f3e7f55eSRobert Mustacchi int bret = finish == B_TRUE ? Z_STREAM_END : Z_BUF_ERROR;
223*f3e7f55eSRobert Mustacchi
224*f3e7f55eSRobert Mustacchi for (;;) {
225*f3e7f55eSRobert Mustacchi if (czd->czd_zstr.avail_out == 0) {
226*f3e7f55eSRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out;
227*f3e7f55eSRobert Mustacchi if ((err = ctf_zdata_grow(czd)) != 0) {
228*f3e7f55eSRobert Mustacchi return (err);
229*f3e7f55eSRobert Mustacchi }
230*f3e7f55eSRobert Mustacchi }
231*f3e7f55eSRobert Mustacchi
232*f3e7f55eSRobert Mustacchi err = zlib.z_compress(&czd->czd_zstr, flag);
233*f3e7f55eSRobert Mustacchi if (err == bret) {
234*f3e7f55eSRobert Mustacchi break;
235*f3e7f55eSRobert Mustacchi }
236*f3e7f55eSRobert Mustacchi if (err != Z_OK)
237*f3e7f55eSRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
238*f3e7f55eSRobert Mustacchi
239*f3e7f55eSRobert Mustacchi }
240*f3e7f55eSRobert Mustacchi
241*f3e7f55eSRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out;
242*f3e7f55eSRobert Mustacchi
243*f3e7f55eSRobert Mustacchi return (0);
244*f3e7f55eSRobert Mustacchi }
245*f3e7f55eSRobert Mustacchi
246*f3e7f55eSRobert Mustacchi static int
ctf_zdata_end(ctf_zdata_t * czd)247*f3e7f55eSRobert Mustacchi ctf_zdata_end(ctf_zdata_t *czd)
248*f3e7f55eSRobert Mustacchi {
249*f3e7f55eSRobert Mustacchi int ret;
250*f3e7f55eSRobert Mustacchi
251*f3e7f55eSRobert Mustacchi if ((ret = ctf_zdata_flush(czd, B_TRUE)) != 0)
252*f3e7f55eSRobert Mustacchi return (ret);
253*f3e7f55eSRobert Mustacchi
254*f3e7f55eSRobert Mustacchi if ((ret = zlib.z_finicomp(&czd->czd_zstr)) != 0)
255*f3e7f55eSRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
256*f3e7f55eSRobert Mustacchi
257*f3e7f55eSRobert Mustacchi return (0);
258*f3e7f55eSRobert Mustacchi }
259*f3e7f55eSRobert Mustacchi
260*f3e7f55eSRobert Mustacchi static void
ctf_zdata_cleanup(ctf_zdata_t * czd)261*f3e7f55eSRobert Mustacchi ctf_zdata_cleanup(ctf_zdata_t *czd)
262*f3e7f55eSRobert Mustacchi {
263*f3e7f55eSRobert Mustacchi ctf_data_free(czd->czd_buf, czd->czd_allocsz);
264*f3e7f55eSRobert Mustacchi (void) zlib.z_finicomp(&czd->czd_zstr);
265*f3e7f55eSRobert Mustacchi }
266*f3e7f55eSRobert Mustacchi
267*f3e7f55eSRobert Mustacchi /*
268*f3e7f55eSRobert Mustacchi * Compress our CTF data and return both the size of the compressed data and the
269*f3e7f55eSRobert Mustacchi * size of the allocation. These may be different due to the nature of
270*f3e7f55eSRobert Mustacchi * compression.
271*f3e7f55eSRobert Mustacchi *
272*f3e7f55eSRobert Mustacchi * In addition, we flush the compression between our two phases such that we
273*f3e7f55eSRobert Mustacchi * maintain a different dictionary between the CTF data and the string section.
274*f3e7f55eSRobert Mustacchi */
275*f3e7f55eSRobert Mustacchi int
ctf_compress(ctf_file_t * fp,void ** buf,size_t * allocsz,size_t * elfsize)276*f3e7f55eSRobert Mustacchi ctf_compress(ctf_file_t *fp, void **buf, size_t *allocsz, size_t *elfsize)
277*f3e7f55eSRobert Mustacchi {
278*f3e7f55eSRobert Mustacchi int err;
279*f3e7f55eSRobert Mustacchi ctf_zdata_t czd;
280*f3e7f55eSRobert Mustacchi ctf_header_t *cthp = (ctf_header_t *)fp->ctf_base;
281*f3e7f55eSRobert Mustacchi
282*f3e7f55eSRobert Mustacchi if ((err = ctf_zdata_init(&czd, fp)) != 0)
283*f3e7f55eSRobert Mustacchi return (err);
284*f3e7f55eSRobert Mustacchi
285*f3e7f55eSRobert Mustacchi if ((err = ctf_zdata_compress_buffer(&czd, fp->ctf_buf,
286*f3e7f55eSRobert Mustacchi cthp->cth_stroff)) != 0) {
287*f3e7f55eSRobert Mustacchi ctf_zdata_cleanup(&czd);
288*f3e7f55eSRobert Mustacchi return (err);
289*f3e7f55eSRobert Mustacchi }
290*f3e7f55eSRobert Mustacchi
291*f3e7f55eSRobert Mustacchi if ((err = ctf_zdata_flush(&czd, B_FALSE)) != 0) {
292*f3e7f55eSRobert Mustacchi ctf_zdata_cleanup(&czd);
293*f3e7f55eSRobert Mustacchi return (err);
294*f3e7f55eSRobert Mustacchi }
295*f3e7f55eSRobert Mustacchi
296*f3e7f55eSRobert Mustacchi if ((err = ctf_zdata_compress_buffer(&czd,
297*f3e7f55eSRobert Mustacchi fp->ctf_buf + cthp->cth_stroff, cthp->cth_strlen)) != 0) {
298*f3e7f55eSRobert Mustacchi ctf_zdata_cleanup(&czd);
299*f3e7f55eSRobert Mustacchi return (err);
300*f3e7f55eSRobert Mustacchi }
301*f3e7f55eSRobert Mustacchi
302*f3e7f55eSRobert Mustacchi if ((err = ctf_zdata_end(&czd)) != 0) {
303*f3e7f55eSRobert Mustacchi ctf_zdata_cleanup(&czd);
304*f3e7f55eSRobert Mustacchi return (err);
305*f3e7f55eSRobert Mustacchi }
306*f3e7f55eSRobert Mustacchi
307*f3e7f55eSRobert Mustacchi *buf = czd.czd_buf;
308*f3e7f55eSRobert Mustacchi *allocsz = czd.czd_allocsz;
309*f3e7f55eSRobert Mustacchi *elfsize = (uintptr_t)czd.czd_next - (uintptr_t)czd.czd_buf;
310*f3e7f55eSRobert Mustacchi
311*f3e7f55eSRobert Mustacchi return (0);
312*f3e7f55eSRobert Mustacchi }
313*f3e7f55eSRobert Mustacchi
314*f3e7f55eSRobert Mustacchi int
z_compress(void * dst,size_t * dstlen,const void * src,size_t srclen)315*f3e7f55eSRobert Mustacchi z_compress(void *dst, size_t *dstlen, const void *src, size_t srclen)
316*f3e7f55eSRobert Mustacchi {
317*f3e7f55eSRobert Mustacchi z_stream zs;
318*f3e7f55eSRobert Mustacchi int err;
319*f3e7f55eSRobert Mustacchi
320*f3e7f55eSRobert Mustacchi bzero(&zs, sizeof (z_stream));
321*f3e7f55eSRobert Mustacchi zs.next_in = (uchar_t *)src;
322*f3e7f55eSRobert Mustacchi zs.avail_in = srclen;
323*f3e7f55eSRobert Mustacchi zs.next_out = dst;
324*f3e7f55eSRobert Mustacchi zs.avail_out = *dstlen;
325*f3e7f55eSRobert Mustacchi
326*f3e7f55eSRobert Mustacchi if ((err = zlib.z_initcomp(&zs, Z_BEST_COMPRESSION, ZLIB_VERSION,
327*f3e7f55eSRobert Mustacchi sizeof (z_stream))) != Z_OK)
328*f3e7f55eSRobert Mustacchi return (err);
329*f3e7f55eSRobert Mustacchi
330*f3e7f55eSRobert Mustacchi if ((err = zlib.z_compress(&zs, Z_FINISH)) != Z_STREAM_END) {
331*f3e7f55eSRobert Mustacchi (void) zlib.z_finicomp(&zs);
332*f3e7f55eSRobert Mustacchi return (err == Z_OK ? Z_BUF_ERROR : err);
333*f3e7f55eSRobert Mustacchi }
334*f3e7f55eSRobert Mustacchi
335*f3e7f55eSRobert Mustacchi *dstlen = zs.total_out;
336*f3e7f55eSRobert Mustacchi return (zlib.z_finicomp(&zs));
337*f3e7f55eSRobert Mustacchi }
338*f3e7f55eSRobert Mustacchi
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate * Convert a 32-bit ELF file header into GElf.
3417c478bd9Sstevel@tonic-gate */
3427c478bd9Sstevel@tonic-gate static void
ehdr_to_gelf(const Elf32_Ehdr * src,GElf_Ehdr * dst)3437c478bd9Sstevel@tonic-gate ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate bcopy(src->e_ident, dst->e_ident, EI_NIDENT);
3467c478bd9Sstevel@tonic-gate dst->e_type = src->e_type;
3477c478bd9Sstevel@tonic-gate dst->e_machine = src->e_machine;
3487c478bd9Sstevel@tonic-gate dst->e_version = src->e_version;
3497c478bd9Sstevel@tonic-gate dst->e_entry = (Elf64_Addr)src->e_entry;
3507c478bd9Sstevel@tonic-gate dst->e_phoff = (Elf64_Off)src->e_phoff;
3517c478bd9Sstevel@tonic-gate dst->e_shoff = (Elf64_Off)src->e_shoff;
3527c478bd9Sstevel@tonic-gate dst->e_flags = src->e_flags;
3537c478bd9Sstevel@tonic-gate dst->e_ehsize = src->e_ehsize;
3547c478bd9Sstevel@tonic-gate dst->e_phentsize = src->e_phentsize;
3557c478bd9Sstevel@tonic-gate dst->e_phnum = src->e_phnum;
3567c478bd9Sstevel@tonic-gate dst->e_shentsize = src->e_shentsize;
3577c478bd9Sstevel@tonic-gate dst->e_shnum = src->e_shnum;
3587c478bd9Sstevel@tonic-gate dst->e_shstrndx = src->e_shstrndx;
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate * Convert a 32-bit ELF section header into GElf.
3637c478bd9Sstevel@tonic-gate */
3647c478bd9Sstevel@tonic-gate static void
shdr_to_gelf(const Elf32_Shdr * src,GElf_Shdr * dst)3657c478bd9Sstevel@tonic-gate shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate dst->sh_name = src->sh_name;
3687c478bd9Sstevel@tonic-gate dst->sh_type = src->sh_type;
3697c478bd9Sstevel@tonic-gate dst->sh_flags = src->sh_flags;
3707c478bd9Sstevel@tonic-gate dst->sh_addr = src->sh_addr;
3717c478bd9Sstevel@tonic-gate dst->sh_offset = src->sh_offset;
3727c478bd9Sstevel@tonic-gate dst->sh_size = src->sh_size;
3737c478bd9Sstevel@tonic-gate dst->sh_link = src->sh_link;
3747c478bd9Sstevel@tonic-gate dst->sh_info = src->sh_info;
3757c478bd9Sstevel@tonic-gate dst->sh_addralign = src->sh_addralign;
3767c478bd9Sstevel@tonic-gate dst->sh_entsize = src->sh_entsize;
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * In order to mmap a section from the ELF file, we must round down sh_offset
3817c478bd9Sstevel@tonic-gate * to the previous page boundary, and mmap the surrounding page. We store
3827c478bd9Sstevel@tonic-gate * the pointer to the start of the actual section data back into sp->cts_data.
3837c478bd9Sstevel@tonic-gate */
3847c478bd9Sstevel@tonic-gate const void *
ctf_sect_mmap(ctf_sect_t * sp,int fd)3857c478bd9Sstevel@tonic-gate ctf_sect_mmap(ctf_sect_t *sp, int fd)
3867c478bd9Sstevel@tonic-gate {
3877c478bd9Sstevel@tonic-gate size_t pageoff = sp->cts_offset & ~_PAGEMASK;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ,
3907c478bd9Sstevel@tonic-gate MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK);
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate if (base != MAP_FAILED)
3937c478bd9Sstevel@tonic-gate sp->cts_data = base + pageoff;
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate return (base);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate * Since sp->cts_data has the adjusted offset, we have to again round down
4007c478bd9Sstevel@tonic-gate * to get the actual mmap address and round up to get the size.
4017c478bd9Sstevel@tonic-gate */
4027c478bd9Sstevel@tonic-gate void
ctf_sect_munmap(const ctf_sect_t * sp)4037c478bd9Sstevel@tonic-gate ctf_sect_munmap(const ctf_sect_t *sp)
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate uintptr_t addr = (uintptr_t)sp->cts_data;
4067c478bd9Sstevel@tonic-gate uintptr_t pageoff = addr & ~_PAGEMASK;
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate (void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate * Open the specified file descriptor and return a pointer to a CTF container.
4137c478bd9Sstevel@tonic-gate * The file can be either an ELF file or raw CTF file. The caller is
4147c478bd9Sstevel@tonic-gate * responsible for closing the file descriptor when it is no longer needed.
4157c478bd9Sstevel@tonic-gate */
4167c478bd9Sstevel@tonic-gate ctf_file_t *
ctf_fdcreate_int(int fd,int * errp,ctf_sect_t * ctfp)417*f3e7f55eSRobert Mustacchi ctf_fdcreate_int(int fd, int *errp, ctf_sect_t *ctfp)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate ctf_sect_t ctfsect, symsect, strsect;
4207c478bd9Sstevel@tonic-gate ctf_file_t *fp = NULL;
421c894effdSRichard Lowe size_t shstrndx, shnum;
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate struct stat64 st;
4247c478bd9Sstevel@tonic-gate ssize_t nbytes;
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate union {
4277c478bd9Sstevel@tonic-gate ctf_preamble_t ctf;
4287c478bd9Sstevel@tonic-gate Elf32_Ehdr e32;
4297c478bd9Sstevel@tonic-gate GElf_Ehdr e64;
4307c478bd9Sstevel@tonic-gate } hdr;
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate bzero(&ctfsect, sizeof (ctf_sect_t));
4337c478bd9Sstevel@tonic-gate bzero(&symsect, sizeof (ctf_sect_t));
4347c478bd9Sstevel@tonic-gate bzero(&strsect, sizeof (ctf_sect_t));
4357c478bd9Sstevel@tonic-gate bzero(&hdr.ctf, sizeof (hdr));
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate if (fstat64(fd, &st) == -1)
4387c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno));
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0)
4417c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT));
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate /*
4447c478bd9Sstevel@tonic-gate * If we have read enough bytes to form a CTF header and the magic
4457c478bd9Sstevel@tonic-gate * string matches, attempt to interpret the file as raw CTF.
4467c478bd9Sstevel@tonic-gate */
4477c478bd9Sstevel@tonic-gate if (nbytes >= sizeof (ctf_preamble_t) &&
4487c478bd9Sstevel@tonic-gate hdr.ctf.ctp_magic == CTF_MAGIC) {
449*f3e7f55eSRobert Mustacchi if (ctfp != NULL)
450*f3e7f55eSRobert Mustacchi return (ctf_set_open_errno(errp, EINVAL));
451*f3e7f55eSRobert Mustacchi
4527c478bd9Sstevel@tonic-gate if (hdr.ctf.ctp_version > CTF_VERSION)
4537c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_CTFVERS));
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ,
4567c478bd9Sstevel@tonic-gate MAP_PRIVATE, fd, 0);
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate if (ctfsect.cts_data == MAP_FAILED)
4597c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno));
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate ctfsect.cts_name = _CTF_SECTION;
4627c478bd9Sstevel@tonic-gate ctfsect.cts_type = SHT_PROGBITS;
4637c478bd9Sstevel@tonic-gate ctfsect.cts_flags = SHF_ALLOC;
4647c478bd9Sstevel@tonic-gate ctfsect.cts_size = (size_t)st.st_size;
4657c478bd9Sstevel@tonic-gate ctfsect.cts_entsize = 1;
4667c478bd9Sstevel@tonic-gate ctfsect.cts_offset = 0;
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL)
4697c478bd9Sstevel@tonic-gate ctf_sect_munmap(&ctfsect);
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate return (fp);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate * If we have read enough bytes to form an ELF header and the magic
4767c478bd9Sstevel@tonic-gate * string matches, attempt to interpret the file as an ELF file. We
4777c478bd9Sstevel@tonic-gate * do our own largefile ELF processing, and convert everything to
4787c478bd9Sstevel@tonic-gate * GElf structures so that clients can operate on any data model.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate if (nbytes >= sizeof (Elf32_Ehdr) &&
4817c478bd9Sstevel@tonic-gate bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
4827c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN
4837c478bd9Sstevel@tonic-gate uchar_t order = ELFDATA2MSB;
4847c478bd9Sstevel@tonic-gate #else
4857c478bd9Sstevel@tonic-gate uchar_t order = ELFDATA2LSB;
4867c478bd9Sstevel@tonic-gate #endif
4877c478bd9Sstevel@tonic-gate GElf_Shdr *sp;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate void *strs_map;
490c894effdSRichard Lowe size_t strs_mapsz, i;
4917c478bd9Sstevel@tonic-gate const char *strs;
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate if (hdr.e32.e_ident[EI_DATA] != order)
4947c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ENDIAN));
4957c478bd9Sstevel@tonic-gate if (hdr.e32.e_version != EV_CURRENT)
4967c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ELFVERS));
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) {
4997c478bd9Sstevel@tonic-gate if (nbytes < sizeof (GElf_Ehdr))
5007c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_FMT));
5017c478bd9Sstevel@tonic-gate } else {
5027c478bd9Sstevel@tonic-gate Elf32_Ehdr e32 = hdr.e32;
5037c478bd9Sstevel@tonic-gate ehdr_to_gelf(&e32, &hdr.e64);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate
506c894effdSRichard Lowe shnum = hdr.e64.e_shnum;
507c894effdSRichard Lowe shstrndx = hdr.e64.e_shstrndx;
508c894effdSRichard Lowe
509c894effdSRichard Lowe /* Extended ELF sections */
510c894effdSRichard Lowe if ((shstrndx == SHN_XINDEX) || (shnum == 0)) {
511c894effdSRichard Lowe if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
512c894effdSRichard Lowe Elf32_Shdr x32;
513c894effdSRichard Lowe
514c894effdSRichard Lowe if (pread64(fd, &x32, sizeof (x32),
515c894effdSRichard Lowe hdr.e64.e_shoff) != sizeof (x32))
516c894effdSRichard Lowe return (ctf_set_open_errno(errp,
517c894effdSRichard Lowe errno));
518c894effdSRichard Lowe
519c894effdSRichard Lowe shnum = x32.sh_size;
520c894effdSRichard Lowe shstrndx = x32.sh_link;
521c894effdSRichard Lowe } else {
522c894effdSRichard Lowe Elf64_Shdr x64;
523c894effdSRichard Lowe
524c894effdSRichard Lowe if (pread64(fd, &x64, sizeof (x64),
525c894effdSRichard Lowe hdr.e64.e_shoff) != sizeof (x64))
526c894effdSRichard Lowe return (ctf_set_open_errno(errp,
527c894effdSRichard Lowe errno));
528c894effdSRichard Lowe
529c894effdSRichard Lowe shnum = x64.sh_size;
530c894effdSRichard Lowe shstrndx = x64.sh_link;
531c894effdSRichard Lowe }
532c894effdSRichard Lowe }
533c894effdSRichard Lowe
534c894effdSRichard Lowe if (shstrndx >= shnum)
5357c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_CORRUPT));
5367c478bd9Sstevel@tonic-gate
537c894effdSRichard Lowe nbytes = sizeof (GElf_Shdr) * shnum;
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate if ((sp = malloc(nbytes)) == NULL)
5407c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno));
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate * Read in and convert to GElf the array of Shdr structures
5447c478bd9Sstevel@tonic-gate * from e_shoff so we can locate sections of interest.
5457c478bd9Sstevel@tonic-gate */
5467c478bd9Sstevel@tonic-gate if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
5477c478bd9Sstevel@tonic-gate Elf32_Shdr *sp32;
5487c478bd9Sstevel@tonic-gate
549c894effdSRichard Lowe nbytes = sizeof (Elf32_Shdr) * shnum;
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
5527c478bd9Sstevel@tonic-gate sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
5537c478bd9Sstevel@tonic-gate free(sp);
5547c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno));
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate
557c894effdSRichard Lowe for (i = 0; i < shnum; i++)
5587c478bd9Sstevel@tonic-gate shdr_to_gelf(&sp32[i], &sp[i]);
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate free(sp32);
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {
5637c478bd9Sstevel@tonic-gate free(sp);
5647c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno));
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate /*
5687c478bd9Sstevel@tonic-gate * Now mmap the section header strings section so that we can
5697c478bd9Sstevel@tonic-gate * perform string comparison on the section names.
5707c478bd9Sstevel@tonic-gate */
571c894effdSRichard Lowe strs_mapsz = sp[shstrndx].sh_size +
572c894effdSRichard Lowe (sp[shstrndx].sh_offset & ~_PAGEMASK);
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
575c894effdSRichard Lowe fd, sp[shstrndx].sh_offset & _PAGEMASK);
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate strs = (const char *)strs_map +
578c894effdSRichard Lowe (sp[shstrndx].sh_offset & ~_PAGEMASK);
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate if (strs_map == MAP_FAILED) {
5817c478bd9Sstevel@tonic-gate free(sp);
5827c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_MMAP));
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate /*
5867c478bd9Sstevel@tonic-gate * Iterate over the section header array looking for the CTF
5877c478bd9Sstevel@tonic-gate * section and symbol table. The strtab is linked to symtab.
5887c478bd9Sstevel@tonic-gate */
589c894effdSRichard Lowe for (i = 0; i < shnum; i++) {
5907c478bd9Sstevel@tonic-gate const GElf_Shdr *shp = &sp[i];
5917c478bd9Sstevel@tonic-gate const GElf_Shdr *lhp = &sp[shp->sh_link];
5927c478bd9Sstevel@tonic-gate
593c894effdSRichard Lowe if (shp->sh_link >= shnum)
5947c478bd9Sstevel@tonic-gate continue; /* corrupt sh_link field */
5957c478bd9Sstevel@tonic-gate
596c894effdSRichard Lowe if (shp->sh_name >= sp[shstrndx].sh_size ||
597c894effdSRichard Lowe lhp->sh_name >= sp[shstrndx].sh_size)
5987c478bd9Sstevel@tonic-gate continue; /* corrupt sh_name field */
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate if (shp->sh_type == SHT_PROGBITS &&
601*f3e7f55eSRobert Mustacchi strcmp(strs + shp->sh_name, _CTF_SECTION) == 0 &&
602*f3e7f55eSRobert Mustacchi ctfp == NULL) {
6037c478bd9Sstevel@tonic-gate ctfsect.cts_name = strs + shp->sh_name;
6047c478bd9Sstevel@tonic-gate ctfsect.cts_type = shp->sh_type;
6057c478bd9Sstevel@tonic-gate ctfsect.cts_flags = shp->sh_flags;
6067c478bd9Sstevel@tonic-gate ctfsect.cts_size = shp->sh_size;
6077c478bd9Sstevel@tonic-gate ctfsect.cts_entsize = shp->sh_entsize;
6087c478bd9Sstevel@tonic-gate ctfsect.cts_offset = (off64_t)shp->sh_offset;
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate } else if (shp->sh_type == SHT_SYMTAB) {
6117c478bd9Sstevel@tonic-gate symsect.cts_name = strs + shp->sh_name;
6127c478bd9Sstevel@tonic-gate symsect.cts_type = shp->sh_type;
6137c478bd9Sstevel@tonic-gate symsect.cts_flags = shp->sh_flags;
6147c478bd9Sstevel@tonic-gate symsect.cts_size = shp->sh_size;
6157c478bd9Sstevel@tonic-gate symsect.cts_entsize = shp->sh_entsize;
6167c478bd9Sstevel@tonic-gate symsect.cts_offset = (off64_t)shp->sh_offset;
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate strsect.cts_name = strs + lhp->sh_name;
6197c478bd9Sstevel@tonic-gate strsect.cts_type = lhp->sh_type;
6207c478bd9Sstevel@tonic-gate strsect.cts_flags = lhp->sh_flags;
6217c478bd9Sstevel@tonic-gate strsect.cts_size = lhp->sh_size;
6227c478bd9Sstevel@tonic-gate strsect.cts_entsize = lhp->sh_entsize;
6237c478bd9Sstevel@tonic-gate strsect.cts_offset = (off64_t)lhp->sh_offset;
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate free(sp); /* free section header array */
6287c478bd9Sstevel@tonic-gate
629*f3e7f55eSRobert Mustacchi if (ctfp == NULL) {
630*f3e7f55eSRobert Mustacchi if (ctfsect.cts_type == SHT_NULL && ctfp == NULL) {
6317c478bd9Sstevel@tonic-gate (void) munmap(strs_map, strs_mapsz);
632*f3e7f55eSRobert Mustacchi return (ctf_set_open_errno(errp,
633*f3e7f55eSRobert Mustacchi ECTF_NOCTFDATA));
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate /*
637*f3e7f55eSRobert Mustacchi * Now mmap the CTF data, symtab, and strtab sections
638*f3e7f55eSRobert Mustacchi * and call ctf_bufopen() to do the rest of the work.
6397c478bd9Sstevel@tonic-gate */
6407c478bd9Sstevel@tonic-gate if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
6417c478bd9Sstevel@tonic-gate (void) munmap(strs_map, strs_mapsz);
6427c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_MMAP));
6437c478bd9Sstevel@tonic-gate }
644*f3e7f55eSRobert Mustacchi ctfp = &ctfsect;
645*f3e7f55eSRobert Mustacchi }
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate if (symsect.cts_type != SHT_NULL &&
6487c478bd9Sstevel@tonic-gate strsect.cts_type != SHT_NULL) {
6497c478bd9Sstevel@tonic-gate if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED ||
6507c478bd9Sstevel@tonic-gate ctf_sect_mmap(&strsect, fd) == MAP_FAILED) {
6517c478bd9Sstevel@tonic-gate (void) ctf_set_open_errno(errp, ECTF_MMAP);
6527c478bd9Sstevel@tonic-gate goto bad; /* unmap all and abort */
6537c478bd9Sstevel@tonic-gate }
654*f3e7f55eSRobert Mustacchi fp = ctf_bufopen(ctfp, &symsect, &strsect, errp);
6557c478bd9Sstevel@tonic-gate } else
656*f3e7f55eSRobert Mustacchi fp = ctf_bufopen(ctfp, NULL, NULL, errp);
6577c478bd9Sstevel@tonic-gate bad:
6587c478bd9Sstevel@tonic-gate if (fp == NULL) {
659*f3e7f55eSRobert Mustacchi if (ctfp == NULL)
6607c478bd9Sstevel@tonic-gate ctf_sect_munmap(&ctfsect);
6617c478bd9Sstevel@tonic-gate ctf_sect_munmap(&symsect);
6627c478bd9Sstevel@tonic-gate ctf_sect_munmap(&strsect);
6637c478bd9Sstevel@tonic-gate } else
6647c478bd9Sstevel@tonic-gate fp->ctf_flags |= LCTF_MMAP;
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate (void) munmap(strs_map, strs_mapsz);
6677c478bd9Sstevel@tonic-gate return (fp);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_FMT));
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate
673*f3e7f55eSRobert Mustacchi ctf_file_t *
ctf_fdopen(int fd,int * errp)674*f3e7f55eSRobert Mustacchi ctf_fdopen(int fd, int *errp)
675*f3e7f55eSRobert Mustacchi {
676*f3e7f55eSRobert Mustacchi return (ctf_fdcreate_int(fd, errp, NULL));
677*f3e7f55eSRobert Mustacchi }
678*f3e7f55eSRobert Mustacchi
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate * Open the specified file and return a pointer to a CTF container. The file
6817c478bd9Sstevel@tonic-gate * can be either an ELF file or raw CTF file. This is just a convenient
6827c478bd9Sstevel@tonic-gate * wrapper around ctf_fdopen() for callers.
6837c478bd9Sstevel@tonic-gate */
6847c478bd9Sstevel@tonic-gate ctf_file_t *
ctf_open(const char * filename,int * errp)6857c478bd9Sstevel@tonic-gate ctf_open(const char *filename, int *errp)
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate ctf_file_t *fp;
6887c478bd9Sstevel@tonic-gate int fd;
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate if ((fd = open64(filename, O_RDONLY)) == -1) {
6917c478bd9Sstevel@tonic-gate if (errp != NULL)
6927c478bd9Sstevel@tonic-gate *errp = errno;
6937c478bd9Sstevel@tonic-gate return (NULL);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate fp = ctf_fdopen(fd, errp);
6977c478bd9Sstevel@tonic-gate (void) close(fd);
6987c478bd9Sstevel@tonic-gate return (fp);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate * Write the uncompressed CTF data stream to the specified file descriptor.
7037c478bd9Sstevel@tonic-gate * This is useful for saving the results of dynamic CTF containers.
7047c478bd9Sstevel@tonic-gate */
7057c478bd9Sstevel@tonic-gate int
ctf_write(ctf_file_t * fp,int fd)7067c478bd9Sstevel@tonic-gate ctf_write(ctf_file_t *fp, int fd)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate const uchar_t *buf = fp->ctf_base;
7097c478bd9Sstevel@tonic-gate ssize_t resid = fp->ctf_size;
7107c478bd9Sstevel@tonic-gate ssize_t len;
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate while (resid != 0) {
7137c478bd9Sstevel@tonic-gate if ((len = write(fd, buf, resid)) <= 0)
7147c478bd9Sstevel@tonic-gate return (ctf_set_errno(fp, errno));
7157c478bd9Sstevel@tonic-gate resid -= len;
7167c478bd9Sstevel@tonic-gate buf += len;
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate return (0);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * Set the CTF library client version to the specified version. If version is
7247c478bd9Sstevel@tonic-gate * zero, we just return the default library version number.
7257c478bd9Sstevel@tonic-gate */
7267c478bd9Sstevel@tonic-gate int
ctf_version(int version)7277c478bd9Sstevel@tonic-gate ctf_version(int version)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate if (version < 0) {
7307c478bd9Sstevel@tonic-gate errno = EINVAL;
7317c478bd9Sstevel@tonic-gate return (-1);
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate if (version > 0) {
7357c478bd9Sstevel@tonic-gate if (version > CTF_VERSION) {
7367c478bd9Sstevel@tonic-gate errno = ENOTSUP;
7377c478bd9Sstevel@tonic-gate return (-1);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate ctf_dprintf("ctf_version: client using version %d\n", version);
7407c478bd9Sstevel@tonic-gate _libctf_version = version;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate return (_libctf_version);
7447c478bd9Sstevel@tonic-gate }
745*f3e7f55eSRobert Mustacchi
746*f3e7f55eSRobert Mustacchi /*
747*f3e7f55eSRobert Mustacchi * A utility function for folks debugging CTF conversion and merging.
748*f3e7f55eSRobert Mustacchi */
749*f3e7f55eSRobert Mustacchi void
ctf_phase_dump(ctf_file_t * fp,const char * phase)750*f3e7f55eSRobert Mustacchi ctf_phase_dump(ctf_file_t *fp, const char *phase)
751*f3e7f55eSRobert Mustacchi {
752*f3e7f55eSRobert Mustacchi int fd;
753*f3e7f55eSRobert Mustacchi static char *base;
754*f3e7f55eSRobert Mustacchi char path[MAXPATHLEN];
755*f3e7f55eSRobert Mustacchi
756*f3e7f55eSRobert Mustacchi if (base == NULL && (base = getenv("LIBCTF_WRITE_PHASES")) == NULL)
757*f3e7f55eSRobert Mustacchi return;
758*f3e7f55eSRobert Mustacchi
759*f3e7f55eSRobert Mustacchi (void) snprintf(path, sizeof (path), "%s/libctf.%s.%d.ctf", base,
760*f3e7f55eSRobert Mustacchi phase != NULL ? phase : "",
761*f3e7f55eSRobert Mustacchi ctf_phase);
762*f3e7f55eSRobert Mustacchi if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0)
763*f3e7f55eSRobert Mustacchi return;
764*f3e7f55eSRobert Mustacchi (void) ctf_write(fp, fd);
765*f3e7f55eSRobert Mustacchi (void) close(fd);
766*f3e7f55eSRobert Mustacchi }
767