1270866Simp/*
2270866Simp * CDDL HEADER START
3270866Simp *
4270866Simp * The contents of this file are subject to the terms of the
5270866Simp * Common Development and Distribution License, Version 1.0 only
6270866Simp * (the "License").  You may not use this file except in compliance
7270866Simp * with the License.
8270866Simp *
9270866Simp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10270866Simp * or http://www.opensolaris.org/os/licensing.
11270866Simp * See the License for the specific language governing permissions
12270866Simp * and limitations under the License.
13270866Simp *
14270866Simp * When distributing Covered Code, include this CDDL HEADER in each
15270866Simp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16270866Simp * If applicable, add the following below this CDDL HEADER, with the
17270866Simp * fields enclosed by brackets "[]" replaced with your own identifying
18270866Simp * information: Portions Copyright [yyyy] [name of copyright owner]
19270866Simp *
20270866Simp * CDDL HEADER END
21270866Simp */
22270866Simp/*
23270866Simp * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24270866Simp * Use is subject to license terms.
25270866Simp */
26270866Simp
27270866Simp#pragma ident	"%Z%%M%	%I%	%E% SMI"
28270866Simp
29270866Simp#include <sys/types.h>
30270866Simp#include <sys/endian.h>
31270866Simp#include <sys/stat.h>
32270866Simp#include <sys/mman.h>
33270866Simp#include <sys/zmod.h>
34270866Simp#include <ctf_impl.h>
35270866Simp#include <unistd.h>
36270866Simp#include <fcntl.h>
37270866Simp#include <errno.h>
38270866Simp#ifdef illumos
39270866Simp#include <dlfcn.h>
40270866Simp#else
41270866Simp#include <zlib.h>
42270866Simp#endif
43270866Simp#include <gelf.h>
44270866Simp
45270866Simp#ifdef illumos
46270866Simp#ifdef _LP64
47270866Simpstatic const char *_libctf_zlib = "/usr/lib/64/libz.so";
48270866Simp#else
49270866Simpstatic const char *_libctf_zlib = "/usr/lib/libz.so";
50270866Simp#endif
51270866Simp#endif
52270866Simp
53270866Simpstatic struct {
54270866Simp	int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t);
55270866Simp	const char *(*z_error)(int);
56270866Simp	void *z_dlp;
57270866Simp} zlib;
58270866Simp
59270866Simpstatic size_t _PAGESIZE;
60270866Simpstatic size_t _PAGEMASK;
61270866Simp
62270866Simp#ifdef illumos
63270866Simp#pragma init(_libctf_init)
64270866Simp#else
65270866Simpvoid    _libctf_init(void) __attribute__ ((constructor));
66270866Simp#endif
67270866Simpvoid
68270866Simp_libctf_init(void)
69270866Simp{
70270866Simp#ifdef illumos
71270866Simp	const char *p = getenv("LIBCTF_DECOMPRESSOR");
72270866Simp
73270866Simp	if (p != NULL)
74270866Simp		_libctf_zlib = p; /* use alternate decompression library */
75270866Simp#endif
76270866Simp
77270866Simp	_libctf_debug = getenv("LIBCTF_DEBUG") != NULL;
78270866Simp
79270866Simp	_PAGESIZE = getpagesize();
80270866Simp	_PAGEMASK = ~(_PAGESIZE - 1);
81270866Simp}
82270866Simp
83270866Simp/*
84270866Simp * Attempt to dlopen the decompression library and locate the symbols of
85270866Simp * interest that we will need to call.  This information in cached so
86270866Simp * that multiple calls to ctf_bufopen() do not need to reopen the library.
87270866Simp */
88270866Simpvoid *
89270866Simpctf_zopen(int *errp)
90270866Simp{
91270866Simp#ifdef illumos
92270866Simp	ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
93270866Simp
94270866Simp	if (zlib.z_dlp != NULL)
95270866Simp		return (zlib.z_dlp); /* library is already loaded */
96270866Simp
97270866Simp	if (access(_libctf_zlib, R_OK) == -1)
98270866Simp		return (ctf_set_open_errno(errp, ECTF_ZMISSING));
99270866Simp
100270866Simp	if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
101270866Simp		return (ctf_set_open_errno(errp, ECTF_ZINIT));
102270866Simp
103270866Simp	zlib.z_uncompress = (int (*)(uchar_t *, ulong_t *, const uchar_t *, ulong_t)) dlsym(zlib.z_dlp, "uncompress");
104270866Simp	zlib.z_error = (const char *(*)(int)) dlsym(zlib.z_dlp, "zError");
105270866Simp
106270866Simp	if (zlib.z_uncompress == NULL || zlib.z_error == NULL) {
107270866Simp		(void) dlclose(zlib.z_dlp);
108270866Simp		bzero(&zlib, sizeof (zlib));
109		return (ctf_set_open_errno(errp, ECTF_ZINIT));
110	}
111#else
112	zlib.z_uncompress = uncompress;
113	zlib.z_error = zError;
114
115	/* Dummy return variable as 'no error' */
116	zlib.z_dlp = (void *) (uintptr_t) 1;
117#endif
118
119	return (zlib.z_dlp);
120}
121
122/*
123 * The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>,
124 * which we then patch through to the functions in the decompression library.
125 */
126int
127z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
128{
129	return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen));
130}
131
132const char *
133z_strerror(int err)
134{
135	return (zlib.z_error(err));
136}
137
138/*
139 * Convert a 32-bit ELF file header into GElf.
140 */
141static void
142ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
143{
144	bcopy(src->e_ident, dst->e_ident, EI_NIDENT);
145	dst->e_type = src->e_type;
146	dst->e_machine = src->e_machine;
147	dst->e_version = src->e_version;
148	dst->e_entry = (Elf64_Addr)src->e_entry;
149	dst->e_phoff = (Elf64_Off)src->e_phoff;
150	dst->e_shoff = (Elf64_Off)src->e_shoff;
151	dst->e_flags = src->e_flags;
152	dst->e_ehsize = src->e_ehsize;
153	dst->e_phentsize = src->e_phentsize;
154	dst->e_phnum = src->e_phnum;
155	dst->e_shentsize = src->e_shentsize;
156	dst->e_shnum = src->e_shnum;
157	dst->e_shstrndx = src->e_shstrndx;
158}
159
160/*
161 * Convert a 32-bit ELF section header into GElf.
162 */
163static void
164shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
165{
166	dst->sh_name = src->sh_name;
167	dst->sh_type = src->sh_type;
168	dst->sh_flags = src->sh_flags;
169	dst->sh_addr = src->sh_addr;
170	dst->sh_offset = src->sh_offset;
171	dst->sh_size = src->sh_size;
172	dst->sh_link = src->sh_link;
173	dst->sh_info = src->sh_info;
174	dst->sh_addralign = src->sh_addralign;
175	dst->sh_entsize = src->sh_entsize;
176}
177
178/*
179 * In order to mmap a section from the ELF file, we must round down sh_offset
180 * to the previous page boundary, and mmap the surrounding page.  We store
181 * the pointer to the start of the actual section data back into sp->cts_data.
182 */
183const void *
184ctf_sect_mmap(ctf_sect_t *sp, int fd)
185{
186	size_t pageoff = sp->cts_offset & ~_PAGEMASK;
187
188	caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ,
189	    MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK);
190
191	if (base != MAP_FAILED)
192		sp->cts_data = base + pageoff;
193
194	return (base);
195}
196
197/*
198 * Since sp->cts_data has the adjusted offset, we have to again round down
199 * to get the actual mmap address and round up to get the size.
200 */
201void
202ctf_sect_munmap(const ctf_sect_t *sp)
203{
204	uintptr_t addr = (uintptr_t)sp->cts_data;
205	uintptr_t pageoff = addr & ~_PAGEMASK;
206
207	(void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff);
208}
209
210/*
211 * Open the specified file descriptor and return a pointer to a CTF container.
212 * The file can be either an ELF file or raw CTF file.  The caller is
213 * responsible for closing the file descriptor when it is no longer needed.
214 */
215ctf_file_t *
216ctf_fdopen(int fd, int *errp)
217{
218	ctf_sect_t ctfsect, symsect, strsect;
219	ctf_file_t *fp = NULL;
220	size_t shstrndx, shnum;
221
222	struct stat64 st;
223	ssize_t nbytes;
224
225	union {
226		ctf_preamble_t ctf;
227		Elf32_Ehdr e32;
228		GElf_Ehdr e64;
229	} hdr;
230
231	bzero(&ctfsect, sizeof (ctf_sect_t));
232	bzero(&symsect, sizeof (ctf_sect_t));
233	bzero(&strsect, sizeof (ctf_sect_t));
234	bzero(&hdr, sizeof (hdr));
235
236	if (fstat64(fd, &st) == -1)
237		return (ctf_set_open_errno(errp, errno));
238
239	if ((nbytes = pread64(fd, &hdr, sizeof (hdr), 0)) <= 0)
240		return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT));
241
242	/*
243	 * If we have read enough bytes to form a CTF header and the magic
244	 * string matches, attempt to interpret the file as raw CTF.
245	 */
246	if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) &&
247	    hdr.ctf.ctp_magic == CTF_MAGIC) {
248		if (hdr.ctf.ctp_version != CTF_VERSION_2 &&
249		    hdr.ctf.ctp_version != CTF_VERSION_3)
250			return (ctf_set_open_errno(errp, ECTF_CTFVERS));
251
252		ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ,
253		    MAP_PRIVATE, fd, 0);
254
255		if (ctfsect.cts_data == MAP_FAILED)
256			return (ctf_set_open_errno(errp, errno));
257
258		ctfsect.cts_name = _CTF_SECTION;
259		ctfsect.cts_type = SHT_PROGBITS;
260		ctfsect.cts_flags = SHF_ALLOC;
261		ctfsect.cts_size = (size_t)st.st_size;
262		ctfsect.cts_entsize = 1;
263		ctfsect.cts_offset = 0;
264
265		if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL)
266			ctf_sect_munmap(&ctfsect);
267
268		return (fp);
269	}
270
271	/*
272	 * If we have read enough bytes to form an ELF header and the magic
273	 * string matches, attempt to interpret the file as an ELF file.  We
274	 * do our own largefile ELF processing, and convert everything to
275	 * GElf structures so that clients can operate on any data model.
276	 */
277	if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) &&
278	    bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
279#if BYTE_ORDER == _BIG_ENDIAN
280		uchar_t order = ELFDATA2MSB;
281#else
282		uchar_t order = ELFDATA2LSB;
283#endif
284		GElf_Shdr *sp;
285
286		void *strs_map;
287		size_t strs_mapsz, i;
288		char *strs;
289
290		if (hdr.e32.e_ident[EI_DATA] != order)
291			return (ctf_set_open_errno(errp, ECTF_ENDIAN));
292		if (hdr.e32.e_version != EV_CURRENT)
293			return (ctf_set_open_errno(errp, ECTF_ELFVERS));
294
295		if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) {
296			if (nbytes < (ssize_t) sizeof (GElf_Ehdr))
297				return (ctf_set_open_errno(errp, ECTF_FMT));
298		} else {
299			Elf32_Ehdr e32 = hdr.e32;
300			ehdr_to_gelf(&e32, &hdr.e64);
301		}
302
303		shnum = hdr.e64.e_shnum;
304		shstrndx = hdr.e64.e_shstrndx;
305
306		/* Extended ELF sections */
307		if ((shstrndx == SHN_XINDEX) || (shnum == 0)) {
308			if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
309				Elf32_Shdr x32;
310
311				if (pread64(fd, &x32, sizeof (x32),
312				    hdr.e64.e_shoff) != sizeof (x32))
313					return (ctf_set_open_errno(errp,
314					    errno));
315
316				shnum = x32.sh_size;
317				shstrndx = x32.sh_link;
318			} else {
319				Elf64_Shdr x64;
320
321				if (pread64(fd, &x64, sizeof (x64),
322				    hdr.e64.e_shoff) != sizeof (x64))
323					return (ctf_set_open_errno(errp,
324					    errno));
325
326				shnum = x64.sh_size;
327				shstrndx = x64.sh_link;
328			}
329		}
330
331		if (shstrndx >= shnum)
332			return (ctf_set_open_errno(errp, ECTF_CORRUPT));
333
334		nbytes = sizeof (GElf_Shdr) * shnum;
335
336		if ((sp = malloc(nbytes)) == NULL)
337			return (ctf_set_open_errno(errp, errno));
338
339		/*
340		 * Read in and convert to GElf the array of Shdr structures
341		 * from e_shoff so we can locate sections of interest.
342		 */
343		if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
344			Elf32_Shdr *sp32;
345
346			nbytes = sizeof (Elf32_Shdr) * shnum;
347
348			if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
349			    sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
350				free(sp);
351				free(sp32);
352				return (ctf_set_open_errno(errp, errno));
353			}
354
355			for (i = 0; i < shnum; i++)
356				shdr_to_gelf(&sp32[i], &sp[i]);
357
358			free(sp32);
359
360		} else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {
361			free(sp);
362			return (ctf_set_open_errno(errp, errno));
363		}
364
365		/*
366		 * Now mmap the section header strings section so that we can
367		 * perform string comparison on the section names.
368		 */
369		strs_mapsz = sp[shstrndx].sh_size +
370		    (sp[shstrndx].sh_offset & ~_PAGEMASK);
371
372		strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
373		    fd, sp[shstrndx].sh_offset & _PAGEMASK);
374
375		strs = (char *)strs_map +
376		    (sp[shstrndx].sh_offset & ~_PAGEMASK);
377
378		if (strs_map == MAP_FAILED) {
379			free(sp);
380			return (ctf_set_open_errno(errp, ECTF_MMAP));
381		}
382
383		/*
384		 * Iterate over the section header array looking for the CTF
385		 * section and symbol table.  The strtab is linked to symtab.
386		 */
387		for (i = 0; i < shnum; i++) {
388			const GElf_Shdr *shp = &sp[i];
389			const GElf_Shdr *lhp = &sp[shp->sh_link];
390
391			if (shp->sh_link >= shnum)
392				continue; /* corrupt sh_link field */
393
394			if (shp->sh_name >= sp[shstrndx].sh_size ||
395			    lhp->sh_name >= sp[shstrndx].sh_size)
396				continue; /* corrupt sh_name field */
397
398			if (shp->sh_type == SHT_PROGBITS &&
399			    strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) {
400				ctfsect.cts_name = strs + shp->sh_name;
401				ctfsect.cts_type = shp->sh_type;
402				ctfsect.cts_flags = shp->sh_flags;
403				ctfsect.cts_size = shp->sh_size;
404				ctfsect.cts_entsize = shp->sh_entsize;
405				ctfsect.cts_offset = (off64_t)shp->sh_offset;
406
407			} else if (shp->sh_type == SHT_SYMTAB) {
408				symsect.cts_name = strs + shp->sh_name;
409				symsect.cts_type = shp->sh_type;
410				symsect.cts_flags = shp->sh_flags;
411				symsect.cts_size = shp->sh_size;
412				symsect.cts_entsize = shp->sh_entsize;
413				symsect.cts_offset = (off64_t)shp->sh_offset;
414
415				strsect.cts_name = strs + lhp->sh_name;
416				strsect.cts_type = lhp->sh_type;
417				strsect.cts_flags = lhp->sh_flags;
418				strsect.cts_size = lhp->sh_size;
419				strsect.cts_entsize = lhp->sh_entsize;
420				strsect.cts_offset = (off64_t)lhp->sh_offset;
421			}
422		}
423
424		free(sp); /* free section header array */
425
426		if (ctfsect.cts_type == SHT_NULL) {
427			(void) munmap(strs_map, strs_mapsz);
428			return (ctf_set_open_errno(errp, ECTF_NOCTFDATA));
429		}
430
431		/*
432		 * Now mmap the CTF data, symtab, and strtab sections and
433		 * call ctf_bufopen() to do the rest of the work.
434		 */
435		if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
436			(void) munmap(strs_map, strs_mapsz);
437			return (ctf_set_open_errno(errp, ECTF_MMAP));
438		}
439
440		if (symsect.cts_type != SHT_NULL &&
441		    strsect.cts_type != SHT_NULL) {
442			if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED ||
443			    ctf_sect_mmap(&strsect, fd) == MAP_FAILED) {
444				(void) ctf_set_open_errno(errp, ECTF_MMAP);
445				goto bad; /* unmap all and abort */
446			}
447			fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp);
448		} else
449			fp = ctf_bufopen(&ctfsect, NULL, NULL, errp);
450bad:
451		if (fp == NULL) {
452			ctf_sect_munmap(&ctfsect);
453			ctf_sect_munmap(&symsect);
454			ctf_sect_munmap(&strsect);
455		} else
456			fp->ctf_flags |= LCTF_MMAP;
457
458		(void) munmap(strs_map, strs_mapsz);
459		return (fp);
460	}
461
462	return (ctf_set_open_errno(errp, ECTF_FMT));
463}
464
465/*
466 * Open the specified file and return a pointer to a CTF container.  The file
467 * can be either an ELF file or raw CTF file.  This is just a convenient
468 * wrapper around ctf_fdopen() for callers.
469 */
470ctf_file_t *
471ctf_open(const char *filename, int *errp)
472{
473	ctf_file_t *fp;
474	int fd;
475
476	if ((fd = open64(filename, O_RDONLY)) == -1) {
477		if (errp != NULL)
478			*errp = errno;
479		return (NULL);
480	}
481
482	fp = ctf_fdopen(fd, errp);
483	(void) close(fd);
484	return (fp);
485}
486
487/*
488 * Write the uncompressed CTF data stream to the specified file descriptor.
489 * This is useful for saving the results of dynamic CTF containers.
490 */
491int
492ctf_write(ctf_file_t *fp, int fd)
493{
494	const uchar_t *buf = fp->ctf_base;
495	ssize_t resid = fp->ctf_size;
496	ssize_t len;
497
498	while (resid != 0) {
499		if ((len = write(fd, buf, resid)) <= 0)
500			return (ctf_set_errno(fp, errno));
501		resid -= len;
502		buf += len;
503	}
504
505	return (0);
506}
507
508/*
509 * Set the CTF library client version to the specified version.  If version is
510 * zero, we just return the default library version number.
511 */
512int
513ctf_version(int version)
514{
515	if (version < 0) {
516		errno = EINVAL;
517		return (-1);
518	}
519
520	if (version > 0) {
521		if (version > CTF_VERSION) {
522			errno = ENOTSUP;
523			return (-1);
524		}
525		ctf_dprintf("ctf_version: client using version %d\n", version);
526		_libctf_version = version;
527	}
528
529	return (_libctf_version);
530}
531