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