xref: /onnv-gate/usr/src/lib/libctf/common/ctf_lib.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/stat.h>
31*0Sstevel@tonic-gate #include <sys/mman.h>
32*0Sstevel@tonic-gate #include <ctf_impl.h>
33*0Sstevel@tonic-gate #include <unistd.h>
34*0Sstevel@tonic-gate #include <fcntl.h>
35*0Sstevel@tonic-gate #include <errno.h>
36*0Sstevel@tonic-gate #include <dlfcn.h>
37*0Sstevel@tonic-gate #include <gelf.h>
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #ifdef _LP64
40*0Sstevel@tonic-gate static const char *_libctf_zlib = "/usr/lib/64/libz.so";
41*0Sstevel@tonic-gate #else
42*0Sstevel@tonic-gate static const char *_libctf_zlib = "/usr/lib/libz.so";
43*0Sstevel@tonic-gate #endif
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate static struct {
46*0Sstevel@tonic-gate 	int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t);
47*0Sstevel@tonic-gate 	const char *(*z_error)(int);
48*0Sstevel@tonic-gate 	void *z_dlp;
49*0Sstevel@tonic-gate } zlib;
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate static size_t _PAGESIZE;
52*0Sstevel@tonic-gate static size_t _PAGEMASK;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #pragma init(_libctf_init)
55*0Sstevel@tonic-gate void
_libctf_init(void)56*0Sstevel@tonic-gate _libctf_init(void)
57*0Sstevel@tonic-gate {
58*0Sstevel@tonic-gate 	const char *p = getenv("LIBCTF_DECOMPRESSOR");
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate 	if (p != NULL)
61*0Sstevel@tonic-gate 		_libctf_zlib = p; /* use alternate decompression library */
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 	_libctf_debug = getenv("LIBCTF_DEBUG") != NULL;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 	_PAGESIZE = getpagesize();
66*0Sstevel@tonic-gate 	_PAGEMASK = ~(_PAGESIZE - 1);
67*0Sstevel@tonic-gate }
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate /*
70*0Sstevel@tonic-gate  * Attempt to dlopen the decompression library and locate the symbols of
71*0Sstevel@tonic-gate  * interest that we will need to call.  This information in cached so
72*0Sstevel@tonic-gate  * that multiple calls to ctf_bufopen() do not need to reopen the library.
73*0Sstevel@tonic-gate  */
74*0Sstevel@tonic-gate void *
ctf_zopen(int * errp)75*0Sstevel@tonic-gate ctf_zopen(int *errp)
76*0Sstevel@tonic-gate {
77*0Sstevel@tonic-gate 	ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	if (zlib.z_dlp != NULL)
80*0Sstevel@tonic-gate 		return (zlib.z_dlp); /* library is already loaded */
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	if (access(_libctf_zlib, R_OK) == -1)
83*0Sstevel@tonic-gate 		return (ctf_set_open_errno(errp, ECTF_ZMISSING));
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
86*0Sstevel@tonic-gate 		return (ctf_set_open_errno(errp, ECTF_ZINIT));
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	zlib.z_uncompress = (int (*)()) dlsym(zlib.z_dlp, "uncompress");
89*0Sstevel@tonic-gate 	zlib.z_error = (const char *(*)()) dlsym(zlib.z_dlp, "zError");
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	if (zlib.z_uncompress == NULL || zlib.z_error == NULL) {
92*0Sstevel@tonic-gate 		(void) dlclose(zlib.z_dlp);
93*0Sstevel@tonic-gate 		bzero(&zlib, sizeof (zlib));
94*0Sstevel@tonic-gate 		return (ctf_set_open_errno(errp, ECTF_ZINIT));
95*0Sstevel@tonic-gate 	}
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	return (zlib.z_dlp);
98*0Sstevel@tonic-gate }
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>,
102*0Sstevel@tonic-gate  * which we then patch through to the functions in the decompression library.
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate int
z_uncompress(void * dst,size_t * dstlen,const void * src,size_t srclen)105*0Sstevel@tonic-gate z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen));
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate const char *
z_strerror(int err)111*0Sstevel@tonic-gate z_strerror(int err)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	return (zlib.z_error(err));
114*0Sstevel@tonic-gate }
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate /*
117*0Sstevel@tonic-gate  * Convert a 32-bit ELF file header into GElf.
118*0Sstevel@tonic-gate  */
119*0Sstevel@tonic-gate static void
ehdr_to_gelf(const Elf32_Ehdr * src,GElf_Ehdr * dst)120*0Sstevel@tonic-gate ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	bcopy(src->e_ident, dst->e_ident, EI_NIDENT);
123*0Sstevel@tonic-gate 	dst->e_type = src->e_type;
124*0Sstevel@tonic-gate 	dst->e_machine = src->e_machine;
125*0Sstevel@tonic-gate 	dst->e_version = src->e_version;
126*0Sstevel@tonic-gate 	dst->e_entry = (Elf64_Addr)src->e_entry;
127*0Sstevel@tonic-gate 	dst->e_phoff = (Elf64_Off)src->e_phoff;
128*0Sstevel@tonic-gate 	dst->e_shoff = (Elf64_Off)src->e_shoff;
129*0Sstevel@tonic-gate 	dst->e_flags = src->e_flags;
130*0Sstevel@tonic-gate 	dst->e_ehsize = src->e_ehsize;
131*0Sstevel@tonic-gate 	dst->e_phentsize = src->e_phentsize;
132*0Sstevel@tonic-gate 	dst->e_phnum = src->e_phnum;
133*0Sstevel@tonic-gate 	dst->e_shentsize = src->e_shentsize;
134*0Sstevel@tonic-gate 	dst->e_shnum = src->e_shnum;
135*0Sstevel@tonic-gate 	dst->e_shstrndx = src->e_shstrndx;
136*0Sstevel@tonic-gate }
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate /*
139*0Sstevel@tonic-gate  * Convert a 32-bit ELF section header into GElf.
140*0Sstevel@tonic-gate  */
141*0Sstevel@tonic-gate static void
shdr_to_gelf(const Elf32_Shdr * src,GElf_Shdr * dst)142*0Sstevel@tonic-gate shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
143*0Sstevel@tonic-gate {
144*0Sstevel@tonic-gate 	dst->sh_name = src->sh_name;
145*0Sstevel@tonic-gate 	dst->sh_type = src->sh_type;
146*0Sstevel@tonic-gate 	dst->sh_flags = src->sh_flags;
147*0Sstevel@tonic-gate 	dst->sh_addr = src->sh_addr;
148*0Sstevel@tonic-gate 	dst->sh_offset = src->sh_offset;
149*0Sstevel@tonic-gate 	dst->sh_size = src->sh_size;
150*0Sstevel@tonic-gate 	dst->sh_link = src->sh_link;
151*0Sstevel@tonic-gate 	dst->sh_info = src->sh_info;
152*0Sstevel@tonic-gate 	dst->sh_addralign = src->sh_addralign;
153*0Sstevel@tonic-gate 	dst->sh_entsize = src->sh_entsize;
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate /*
157*0Sstevel@tonic-gate  * In order to mmap a section from the ELF file, we must round down sh_offset
158*0Sstevel@tonic-gate  * to the previous page boundary, and mmap the surrounding page.  We store
159*0Sstevel@tonic-gate  * the pointer to the start of the actual section data back into sp->cts_data.
160*0Sstevel@tonic-gate  */
161*0Sstevel@tonic-gate const void *
ctf_sect_mmap(ctf_sect_t * sp,int fd)162*0Sstevel@tonic-gate ctf_sect_mmap(ctf_sect_t *sp, int fd)
163*0Sstevel@tonic-gate {
164*0Sstevel@tonic-gate 	size_t pageoff = sp->cts_offset & ~_PAGEMASK;
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ,
167*0Sstevel@tonic-gate 	    MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK);
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	if (base != MAP_FAILED)
170*0Sstevel@tonic-gate 		sp->cts_data = base + pageoff;
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	return (base);
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate /*
176*0Sstevel@tonic-gate  * Since sp->cts_data has the adjusted offset, we have to again round down
177*0Sstevel@tonic-gate  * to get the actual mmap address and round up to get the size.
178*0Sstevel@tonic-gate  */
179*0Sstevel@tonic-gate void
ctf_sect_munmap(const ctf_sect_t * sp)180*0Sstevel@tonic-gate ctf_sect_munmap(const ctf_sect_t *sp)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate 	uintptr_t addr = (uintptr_t)sp->cts_data;
183*0Sstevel@tonic-gate 	uintptr_t pageoff = addr & ~_PAGEMASK;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	(void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate /*
189*0Sstevel@tonic-gate  * Open the specified file descriptor and return a pointer to a CTF container.
190*0Sstevel@tonic-gate  * The file can be either an ELF file or raw CTF file.  The caller is
191*0Sstevel@tonic-gate  * responsible for closing the file descriptor when it is no longer needed.
192*0Sstevel@tonic-gate  */
193*0Sstevel@tonic-gate ctf_file_t *
ctf_fdopen(int fd,int * errp)194*0Sstevel@tonic-gate ctf_fdopen(int fd, int *errp)
195*0Sstevel@tonic-gate {
196*0Sstevel@tonic-gate 	ctf_sect_t ctfsect, symsect, strsect;
197*0Sstevel@tonic-gate 	ctf_file_t *fp = NULL;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	struct stat64 st;
200*0Sstevel@tonic-gate 	ssize_t nbytes;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	union {
203*0Sstevel@tonic-gate 		ctf_preamble_t ctf;
204*0Sstevel@tonic-gate 		Elf32_Ehdr e32;
205*0Sstevel@tonic-gate 		GElf_Ehdr e64;
206*0Sstevel@tonic-gate 	} hdr;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	bzero(&ctfsect, sizeof (ctf_sect_t));
209*0Sstevel@tonic-gate 	bzero(&symsect, sizeof (ctf_sect_t));
210*0Sstevel@tonic-gate 	bzero(&strsect, sizeof (ctf_sect_t));
211*0Sstevel@tonic-gate 	bzero(&hdr.ctf, sizeof (hdr));
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	if (fstat64(fd, &st) == -1)
214*0Sstevel@tonic-gate 		return (ctf_set_open_errno(errp, errno));
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0)
217*0Sstevel@tonic-gate 		return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT));
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	/*
220*0Sstevel@tonic-gate 	 * If we have read enough bytes to form a CTF header and the magic
221*0Sstevel@tonic-gate 	 * string matches, attempt to interpret the file as raw CTF.
222*0Sstevel@tonic-gate 	 */
223*0Sstevel@tonic-gate 	if (nbytes >= sizeof (ctf_preamble_t) &&
224*0Sstevel@tonic-gate 	    hdr.ctf.ctp_magic == CTF_MAGIC) {
225*0Sstevel@tonic-gate 		if (hdr.ctf.ctp_version > CTF_VERSION)
226*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, ECTF_CTFVERS));
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 		ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ,
229*0Sstevel@tonic-gate 		    MAP_PRIVATE, fd, 0);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		if (ctfsect.cts_data == MAP_FAILED)
232*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, errno));
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 		ctfsect.cts_name = _CTF_SECTION;
235*0Sstevel@tonic-gate 		ctfsect.cts_type = SHT_PROGBITS;
236*0Sstevel@tonic-gate 		ctfsect.cts_flags = SHF_ALLOC;
237*0Sstevel@tonic-gate 		ctfsect.cts_size = (size_t)st.st_size;
238*0Sstevel@tonic-gate 		ctfsect.cts_entsize = 1;
239*0Sstevel@tonic-gate 		ctfsect.cts_offset = 0;
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 		if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL)
242*0Sstevel@tonic-gate 			ctf_sect_munmap(&ctfsect);
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 		return (fp);
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	/*
248*0Sstevel@tonic-gate 	 * If we have read enough bytes to form an ELF header and the magic
249*0Sstevel@tonic-gate 	 * string matches, attempt to interpret the file as an ELF file.  We
250*0Sstevel@tonic-gate 	 * do our own largefile ELF processing, and convert everything to
251*0Sstevel@tonic-gate 	 * GElf structures so that clients can operate on any data model.
252*0Sstevel@tonic-gate 	 */
253*0Sstevel@tonic-gate 	if (nbytes >= sizeof (Elf32_Ehdr) &&
254*0Sstevel@tonic-gate 	    bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
255*0Sstevel@tonic-gate #ifdef	_BIG_ENDIAN
256*0Sstevel@tonic-gate 		uchar_t order = ELFDATA2MSB;
257*0Sstevel@tonic-gate #else
258*0Sstevel@tonic-gate 		uchar_t order = ELFDATA2LSB;
259*0Sstevel@tonic-gate #endif
260*0Sstevel@tonic-gate 		GElf_Half i, n;
261*0Sstevel@tonic-gate 		GElf_Shdr *sp;
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 		void *strs_map;
264*0Sstevel@tonic-gate 		size_t strs_mapsz;
265*0Sstevel@tonic-gate 		const char *strs;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 		if (hdr.e32.e_ident[EI_DATA] != order)
268*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, ECTF_ENDIAN));
269*0Sstevel@tonic-gate 		if (hdr.e32.e_version != EV_CURRENT)
270*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, ECTF_ELFVERS));
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 		if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) {
273*0Sstevel@tonic-gate 			if (nbytes < sizeof (GElf_Ehdr))
274*0Sstevel@tonic-gate 				return (ctf_set_open_errno(errp, ECTF_FMT));
275*0Sstevel@tonic-gate 		} else {
276*0Sstevel@tonic-gate 			Elf32_Ehdr e32 = hdr.e32;
277*0Sstevel@tonic-gate 			ehdr_to_gelf(&e32, &hdr.e64);
278*0Sstevel@tonic-gate 		}
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 		if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
281*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, ECTF_CORRUPT));
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		n = hdr.e64.e_shnum;
284*0Sstevel@tonic-gate 		nbytes = sizeof (GElf_Shdr) * n;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 		if ((sp = malloc(nbytes)) == NULL)
287*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, errno));
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 		/*
290*0Sstevel@tonic-gate 		 * Read in and convert to GElf the array of Shdr structures
291*0Sstevel@tonic-gate 		 * from e_shoff so we can locate sections of interest.
292*0Sstevel@tonic-gate 		 */
293*0Sstevel@tonic-gate 		if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
294*0Sstevel@tonic-gate 			Elf32_Shdr *sp32;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 			nbytes = sizeof (Elf32_Shdr) * n;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 			if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
299*0Sstevel@tonic-gate 			    sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
300*0Sstevel@tonic-gate 				free(sp);
301*0Sstevel@tonic-gate 				return (ctf_set_open_errno(errp, errno));
302*0Sstevel@tonic-gate 			}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 			for (i = 0; i < n; i++)
305*0Sstevel@tonic-gate 				shdr_to_gelf(&sp32[i], &sp[i]);
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 			free(sp32);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 		} else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {
310*0Sstevel@tonic-gate 			free(sp);
311*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, errno));
312*0Sstevel@tonic-gate 		}
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 		/*
315*0Sstevel@tonic-gate 		 * Now mmap the section header strings section so that we can
316*0Sstevel@tonic-gate 		 * perform string comparison on the section names.
317*0Sstevel@tonic-gate 		 */
318*0Sstevel@tonic-gate 		strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size +
319*0Sstevel@tonic-gate 		    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 		strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
322*0Sstevel@tonic-gate 		    fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 		strs = (const char *)strs_map +
325*0Sstevel@tonic-gate 		    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 		if (strs_map == MAP_FAILED) {
328*0Sstevel@tonic-gate 			free(sp);
329*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, ECTF_MMAP));
330*0Sstevel@tonic-gate 		}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 		/*
333*0Sstevel@tonic-gate 		 * Iterate over the section header array looking for the CTF
334*0Sstevel@tonic-gate 		 * section and symbol table.  The strtab is linked to symtab.
335*0Sstevel@tonic-gate 		 */
336*0Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
337*0Sstevel@tonic-gate 			const GElf_Shdr *shp = &sp[i];
338*0Sstevel@tonic-gate 			const GElf_Shdr *lhp = &sp[shp->sh_link];
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 			if (shp->sh_link >= hdr.e64.e_shnum)
341*0Sstevel@tonic-gate 				continue; /* corrupt sh_link field */
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 			if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
344*0Sstevel@tonic-gate 			    lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size)
345*0Sstevel@tonic-gate 				continue; /* corrupt sh_name field */
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 			if (shp->sh_type == SHT_PROGBITS &&
348*0Sstevel@tonic-gate 			    strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) {
349*0Sstevel@tonic-gate 				ctfsect.cts_name = strs + shp->sh_name;
350*0Sstevel@tonic-gate 				ctfsect.cts_type = shp->sh_type;
351*0Sstevel@tonic-gate 				ctfsect.cts_flags = shp->sh_flags;
352*0Sstevel@tonic-gate 				ctfsect.cts_size = shp->sh_size;
353*0Sstevel@tonic-gate 				ctfsect.cts_entsize = shp->sh_entsize;
354*0Sstevel@tonic-gate 				ctfsect.cts_offset = (off64_t)shp->sh_offset;
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 			} else if (shp->sh_type == SHT_SYMTAB) {
357*0Sstevel@tonic-gate 				symsect.cts_name = strs + shp->sh_name;
358*0Sstevel@tonic-gate 				symsect.cts_type = shp->sh_type;
359*0Sstevel@tonic-gate 				symsect.cts_flags = shp->sh_flags;
360*0Sstevel@tonic-gate 				symsect.cts_size = shp->sh_size;
361*0Sstevel@tonic-gate 				symsect.cts_entsize = shp->sh_entsize;
362*0Sstevel@tonic-gate 				symsect.cts_offset = (off64_t)shp->sh_offset;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 				strsect.cts_name = strs + lhp->sh_name;
365*0Sstevel@tonic-gate 				strsect.cts_type = lhp->sh_type;
366*0Sstevel@tonic-gate 				strsect.cts_flags = lhp->sh_flags;
367*0Sstevel@tonic-gate 				strsect.cts_size = lhp->sh_size;
368*0Sstevel@tonic-gate 				strsect.cts_entsize = lhp->sh_entsize;
369*0Sstevel@tonic-gate 				strsect.cts_offset = (off64_t)lhp->sh_offset;
370*0Sstevel@tonic-gate 			}
371*0Sstevel@tonic-gate 		}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 		free(sp); /* free section header array */
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 		if (ctfsect.cts_type == SHT_NULL) {
376*0Sstevel@tonic-gate 			(void) munmap(strs_map, strs_mapsz);
377*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, ECTF_NOCTFDATA));
378*0Sstevel@tonic-gate 		}
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		/*
381*0Sstevel@tonic-gate 		 * Now mmap the CTF data, symtab, and strtab sections and
382*0Sstevel@tonic-gate 		 * call ctf_bufopen() to do the rest of the work.
383*0Sstevel@tonic-gate 		 */
384*0Sstevel@tonic-gate 		if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
385*0Sstevel@tonic-gate 			(void) munmap(strs_map, strs_mapsz);
386*0Sstevel@tonic-gate 			return (ctf_set_open_errno(errp, ECTF_MMAP));
387*0Sstevel@tonic-gate 		}
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 		if (symsect.cts_type != SHT_NULL &&
390*0Sstevel@tonic-gate 		    strsect.cts_type != SHT_NULL) {
391*0Sstevel@tonic-gate 			if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED ||
392*0Sstevel@tonic-gate 			    ctf_sect_mmap(&strsect, fd) == MAP_FAILED) {
393*0Sstevel@tonic-gate 				(void) ctf_set_open_errno(errp, ECTF_MMAP);
394*0Sstevel@tonic-gate 				goto bad; /* unmap all and abort */
395*0Sstevel@tonic-gate 			}
396*0Sstevel@tonic-gate 			fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp);
397*0Sstevel@tonic-gate 		} else
398*0Sstevel@tonic-gate 			fp = ctf_bufopen(&ctfsect, NULL, NULL, errp);
399*0Sstevel@tonic-gate bad:
400*0Sstevel@tonic-gate 		if (fp == NULL) {
401*0Sstevel@tonic-gate 			ctf_sect_munmap(&ctfsect);
402*0Sstevel@tonic-gate 			ctf_sect_munmap(&symsect);
403*0Sstevel@tonic-gate 			ctf_sect_munmap(&strsect);
404*0Sstevel@tonic-gate 		} else
405*0Sstevel@tonic-gate 			fp->ctf_flags |= LCTF_MMAP;
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 		(void) munmap(strs_map, strs_mapsz);
408*0Sstevel@tonic-gate 		return (fp);
409*0Sstevel@tonic-gate 	}
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	return (ctf_set_open_errno(errp, ECTF_FMT));
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate  * Open the specified file and return a pointer to a CTF container.  The file
416*0Sstevel@tonic-gate  * can be either an ELF file or raw CTF file.  This is just a convenient
417*0Sstevel@tonic-gate  * wrapper around ctf_fdopen() for callers.
418*0Sstevel@tonic-gate  */
419*0Sstevel@tonic-gate ctf_file_t *
ctf_open(const char * filename,int * errp)420*0Sstevel@tonic-gate ctf_open(const char *filename, int *errp)
421*0Sstevel@tonic-gate {
422*0Sstevel@tonic-gate 	ctf_file_t *fp;
423*0Sstevel@tonic-gate 	int fd;
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	if ((fd = open64(filename, O_RDONLY)) == -1) {
426*0Sstevel@tonic-gate 		if (errp != NULL)
427*0Sstevel@tonic-gate 			*errp = errno;
428*0Sstevel@tonic-gate 		return (NULL);
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	fp = ctf_fdopen(fd, errp);
432*0Sstevel@tonic-gate 	(void) close(fd);
433*0Sstevel@tonic-gate 	return (fp);
434*0Sstevel@tonic-gate }
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate /*
437*0Sstevel@tonic-gate  * Write the uncompressed CTF data stream to the specified file descriptor.
438*0Sstevel@tonic-gate  * This is useful for saving the results of dynamic CTF containers.
439*0Sstevel@tonic-gate  */
440*0Sstevel@tonic-gate int
ctf_write(ctf_file_t * fp,int fd)441*0Sstevel@tonic-gate ctf_write(ctf_file_t *fp, int fd)
442*0Sstevel@tonic-gate {
443*0Sstevel@tonic-gate 	const uchar_t *buf = fp->ctf_base;
444*0Sstevel@tonic-gate 	ssize_t resid = fp->ctf_size;
445*0Sstevel@tonic-gate 	ssize_t len;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	while (resid != 0) {
448*0Sstevel@tonic-gate 		if ((len = write(fd, buf, resid)) <= 0)
449*0Sstevel@tonic-gate 			return (ctf_set_errno(fp, errno));
450*0Sstevel@tonic-gate 		resid -= len;
451*0Sstevel@tonic-gate 		buf += len;
452*0Sstevel@tonic-gate 	}
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	return (0);
455*0Sstevel@tonic-gate }
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate /*
458*0Sstevel@tonic-gate  * Set the CTF library client version to the specified version.  If version is
459*0Sstevel@tonic-gate  * zero, we just return the default library version number.
460*0Sstevel@tonic-gate  */
461*0Sstevel@tonic-gate int
ctf_version(int version)462*0Sstevel@tonic-gate ctf_version(int version)
463*0Sstevel@tonic-gate {
464*0Sstevel@tonic-gate 	if (version < 0) {
465*0Sstevel@tonic-gate 		errno = EINVAL;
466*0Sstevel@tonic-gate 		return (-1);
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	if (version > 0) {
470*0Sstevel@tonic-gate 		if (version > CTF_VERSION) {
471*0Sstevel@tonic-gate 			errno = ENOTSUP;
472*0Sstevel@tonic-gate 			return (-1);
473*0Sstevel@tonic-gate 		}
474*0Sstevel@tonic-gate 		ctf_dprintf("ctf_version: client using version %d\n", version);
475*0Sstevel@tonic-gate 		_libctf_version = version;
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	return (_libctf_version);
479*0Sstevel@tonic-gate }
480