16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 56ff6d951SJohn Birrell * Common Development and Distribution License, Version 1.0 only 66ff6d951SJohn Birrell * (the "License"). You may not use this file except in compliance 76ff6d951SJohn Birrell * with the License. 86ff6d951SJohn Birrell * 96ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 106ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 116ff6d951SJohn Birrell * See the License for the specific language governing permissions 126ff6d951SJohn Birrell * and limitations under the License. 136ff6d951SJohn Birrell * 146ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 156ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 166ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 176ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 186ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 196ff6d951SJohn Birrell * 206ff6d951SJohn Birrell * CDDL HEADER END 216ff6d951SJohn Birrell */ 226ff6d951SJohn Birrell /* 236ff6d951SJohn Birrell * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 246ff6d951SJohn Birrell * Use is subject to license terms. 256ff6d951SJohn Birrell */ 266ff6d951SJohn Birrell 276ff6d951SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 286ff6d951SJohn Birrell 296ff6d951SJohn Birrell #include <sys/types.h> 306ff6d951SJohn Birrell #include <sys/stat.h> 316ff6d951SJohn Birrell #include <sys/mman.h> 32*76429c36SJohn Birrell #include <sys/zmod.h> 336ff6d951SJohn Birrell #include <ctf_impl.h> 346ff6d951SJohn Birrell #include <unistd.h> 356ff6d951SJohn Birrell #include <fcntl.h> 366ff6d951SJohn Birrell #include <errno.h> 37*76429c36SJohn Birrell #if defined(sun) 386ff6d951SJohn Birrell #include <dlfcn.h> 39*76429c36SJohn Birrell #else 40*76429c36SJohn Birrell #include <zlib.h> 41*76429c36SJohn Birrell #endif 426ff6d951SJohn Birrell #include <gelf.h> 436ff6d951SJohn Birrell 44*76429c36SJohn Birrell #if defined(sun) 456ff6d951SJohn Birrell #ifdef _LP64 466ff6d951SJohn Birrell static const char *_libctf_zlib = "/usr/lib/64/libz.so"; 476ff6d951SJohn Birrell #else 486ff6d951SJohn Birrell static const char *_libctf_zlib = "/usr/lib/libz.so"; 496ff6d951SJohn Birrell #endif 50*76429c36SJohn Birrell #endif 516ff6d951SJohn Birrell 526ff6d951SJohn Birrell static struct { 536ff6d951SJohn Birrell int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t); 546ff6d951SJohn Birrell const char *(*z_error)(int); 556ff6d951SJohn Birrell void *z_dlp; 566ff6d951SJohn Birrell } zlib; 576ff6d951SJohn Birrell 586ff6d951SJohn Birrell static size_t _PAGESIZE; 596ff6d951SJohn Birrell static size_t _PAGEMASK; 606ff6d951SJohn Birrell 61*76429c36SJohn Birrell #if defined(sun) 626ff6d951SJohn Birrell #pragma init(_libctf_init) 63*76429c36SJohn Birrell #else 64*76429c36SJohn Birrell void _libctf_init(void) __attribute__ ((constructor)); 65*76429c36SJohn Birrell #endif 666ff6d951SJohn Birrell void 676ff6d951SJohn Birrell _libctf_init(void) 686ff6d951SJohn Birrell { 69*76429c36SJohn Birrell #if defined(sun) 706ff6d951SJohn Birrell const char *p = getenv("LIBCTF_DECOMPRESSOR"); 716ff6d951SJohn Birrell 726ff6d951SJohn Birrell if (p != NULL) 736ff6d951SJohn Birrell _libctf_zlib = p; /* use alternate decompression library */ 74*76429c36SJohn Birrell #endif 756ff6d951SJohn Birrell 766ff6d951SJohn Birrell _libctf_debug = getenv("LIBCTF_DEBUG") != NULL; 776ff6d951SJohn Birrell 786ff6d951SJohn Birrell _PAGESIZE = getpagesize(); 796ff6d951SJohn Birrell _PAGEMASK = ~(_PAGESIZE - 1); 806ff6d951SJohn Birrell } 816ff6d951SJohn Birrell 826ff6d951SJohn Birrell /* 836ff6d951SJohn Birrell * Attempt to dlopen the decompression library and locate the symbols of 846ff6d951SJohn Birrell * interest that we will need to call. This information in cached so 856ff6d951SJohn Birrell * that multiple calls to ctf_bufopen() do not need to reopen the library. 866ff6d951SJohn Birrell */ 876ff6d951SJohn Birrell void * 886ff6d951SJohn Birrell ctf_zopen(int *errp) 896ff6d951SJohn Birrell { 90*76429c36SJohn Birrell #if defined(sun) 916ff6d951SJohn Birrell ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib); 926ff6d951SJohn Birrell 936ff6d951SJohn Birrell if (zlib.z_dlp != NULL) 946ff6d951SJohn Birrell return (zlib.z_dlp); /* library is already loaded */ 956ff6d951SJohn Birrell 966ff6d951SJohn Birrell if (access(_libctf_zlib, R_OK) == -1) 976ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_ZMISSING)); 986ff6d951SJohn Birrell 996ff6d951SJohn Birrell if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL) 1006ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_ZINIT)); 1016ff6d951SJohn Birrell 102*76429c36SJohn Birrell zlib.z_uncompress = (int (*)(uchar_t *, ulong_t *, const uchar_t *, ulong_t)) dlsym(zlib.z_dlp, "uncompress"); 103*76429c36SJohn Birrell zlib.z_error = (const char *(*)(int)) dlsym(zlib.z_dlp, "zError"); 1046ff6d951SJohn Birrell 1056ff6d951SJohn Birrell if (zlib.z_uncompress == NULL || zlib.z_error == NULL) { 1066ff6d951SJohn Birrell (void) dlclose(zlib.z_dlp); 1076ff6d951SJohn Birrell bzero(&zlib, sizeof (zlib)); 1086ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_ZINIT)); 1096ff6d951SJohn Birrell } 110*76429c36SJohn Birrell #else 111*76429c36SJohn Birrell zlib.z_uncompress = uncompress; 112*76429c36SJohn Birrell zlib.z_error = zError; 113*76429c36SJohn Birrell 114*76429c36SJohn Birrell /* Dummy return variable as 'no error' */ 115*76429c36SJohn Birrell zlib.z_dlp = (void *) (uintptr_t) 1; 116*76429c36SJohn Birrell #endif 1176ff6d951SJohn Birrell 1186ff6d951SJohn Birrell return (zlib.z_dlp); 1196ff6d951SJohn Birrell } 1206ff6d951SJohn Birrell 1216ff6d951SJohn Birrell /* 1226ff6d951SJohn Birrell * The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>, 1236ff6d951SJohn Birrell * which we then patch through to the functions in the decompression library. 1246ff6d951SJohn Birrell */ 1256ff6d951SJohn Birrell int 1266ff6d951SJohn Birrell z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen) 1276ff6d951SJohn Birrell { 1286ff6d951SJohn Birrell return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen)); 1296ff6d951SJohn Birrell } 1306ff6d951SJohn Birrell 1316ff6d951SJohn Birrell const char * 1326ff6d951SJohn Birrell z_strerror(int err) 1336ff6d951SJohn Birrell { 1346ff6d951SJohn Birrell return (zlib.z_error(err)); 1356ff6d951SJohn Birrell } 1366ff6d951SJohn Birrell 1376ff6d951SJohn Birrell /* 1386ff6d951SJohn Birrell * Convert a 32-bit ELF file header into GElf. 1396ff6d951SJohn Birrell */ 1406ff6d951SJohn Birrell static void 1416ff6d951SJohn Birrell ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst) 1426ff6d951SJohn Birrell { 1436ff6d951SJohn Birrell bcopy(src->e_ident, dst->e_ident, EI_NIDENT); 1446ff6d951SJohn Birrell dst->e_type = src->e_type; 1456ff6d951SJohn Birrell dst->e_machine = src->e_machine; 1466ff6d951SJohn Birrell dst->e_version = src->e_version; 1476ff6d951SJohn Birrell dst->e_entry = (Elf64_Addr)src->e_entry; 1486ff6d951SJohn Birrell dst->e_phoff = (Elf64_Off)src->e_phoff; 1496ff6d951SJohn Birrell dst->e_shoff = (Elf64_Off)src->e_shoff; 1506ff6d951SJohn Birrell dst->e_flags = src->e_flags; 1516ff6d951SJohn Birrell dst->e_ehsize = src->e_ehsize; 1526ff6d951SJohn Birrell dst->e_phentsize = src->e_phentsize; 1536ff6d951SJohn Birrell dst->e_phnum = src->e_phnum; 1546ff6d951SJohn Birrell dst->e_shentsize = src->e_shentsize; 1556ff6d951SJohn Birrell dst->e_shnum = src->e_shnum; 1566ff6d951SJohn Birrell dst->e_shstrndx = src->e_shstrndx; 1576ff6d951SJohn Birrell } 1586ff6d951SJohn Birrell 1596ff6d951SJohn Birrell /* 1606ff6d951SJohn Birrell * Convert a 32-bit ELF section header into GElf. 1616ff6d951SJohn Birrell */ 1626ff6d951SJohn Birrell static void 1636ff6d951SJohn Birrell shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst) 1646ff6d951SJohn Birrell { 1656ff6d951SJohn Birrell dst->sh_name = src->sh_name; 1666ff6d951SJohn Birrell dst->sh_type = src->sh_type; 1676ff6d951SJohn Birrell dst->sh_flags = src->sh_flags; 1686ff6d951SJohn Birrell dst->sh_addr = src->sh_addr; 1696ff6d951SJohn Birrell dst->sh_offset = src->sh_offset; 1706ff6d951SJohn Birrell dst->sh_size = src->sh_size; 1716ff6d951SJohn Birrell dst->sh_link = src->sh_link; 1726ff6d951SJohn Birrell dst->sh_info = src->sh_info; 1736ff6d951SJohn Birrell dst->sh_addralign = src->sh_addralign; 1746ff6d951SJohn Birrell dst->sh_entsize = src->sh_entsize; 1756ff6d951SJohn Birrell } 1766ff6d951SJohn Birrell 1776ff6d951SJohn Birrell /* 1786ff6d951SJohn Birrell * In order to mmap a section from the ELF file, we must round down sh_offset 1796ff6d951SJohn Birrell * to the previous page boundary, and mmap the surrounding page. We store 1806ff6d951SJohn Birrell * the pointer to the start of the actual section data back into sp->cts_data. 1816ff6d951SJohn Birrell */ 1826ff6d951SJohn Birrell const void * 1836ff6d951SJohn Birrell ctf_sect_mmap(ctf_sect_t *sp, int fd) 1846ff6d951SJohn Birrell { 1856ff6d951SJohn Birrell size_t pageoff = sp->cts_offset & ~_PAGEMASK; 1866ff6d951SJohn Birrell 1876ff6d951SJohn Birrell caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ, 1886ff6d951SJohn Birrell MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK); 1896ff6d951SJohn Birrell 1906ff6d951SJohn Birrell if (base != MAP_FAILED) 1916ff6d951SJohn Birrell sp->cts_data = base + pageoff; 1926ff6d951SJohn Birrell 1936ff6d951SJohn Birrell return (base); 1946ff6d951SJohn Birrell } 1956ff6d951SJohn Birrell 1966ff6d951SJohn Birrell /* 1976ff6d951SJohn Birrell * Since sp->cts_data has the adjusted offset, we have to again round down 1986ff6d951SJohn Birrell * to get the actual mmap address and round up to get the size. 1996ff6d951SJohn Birrell */ 2006ff6d951SJohn Birrell void 2016ff6d951SJohn Birrell ctf_sect_munmap(const ctf_sect_t *sp) 2026ff6d951SJohn Birrell { 2036ff6d951SJohn Birrell uintptr_t addr = (uintptr_t)sp->cts_data; 2046ff6d951SJohn Birrell uintptr_t pageoff = addr & ~_PAGEMASK; 2056ff6d951SJohn Birrell 2066ff6d951SJohn Birrell (void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff); 2076ff6d951SJohn Birrell } 2086ff6d951SJohn Birrell 2096ff6d951SJohn Birrell /* 2106ff6d951SJohn Birrell * Open the specified file descriptor and return a pointer to a CTF container. 2116ff6d951SJohn Birrell * The file can be either an ELF file or raw CTF file. The caller is 2126ff6d951SJohn Birrell * responsible for closing the file descriptor when it is no longer needed. 2136ff6d951SJohn Birrell */ 2146ff6d951SJohn Birrell ctf_file_t * 2156ff6d951SJohn Birrell ctf_fdopen(int fd, int *errp) 2166ff6d951SJohn Birrell { 2176ff6d951SJohn Birrell ctf_sect_t ctfsect, symsect, strsect; 2186ff6d951SJohn Birrell ctf_file_t *fp = NULL; 2196ff6d951SJohn Birrell 2206ff6d951SJohn Birrell struct stat64 st; 2216ff6d951SJohn Birrell ssize_t nbytes; 2226ff6d951SJohn Birrell 2236ff6d951SJohn Birrell union { 2246ff6d951SJohn Birrell ctf_preamble_t ctf; 2256ff6d951SJohn Birrell Elf32_Ehdr e32; 2266ff6d951SJohn Birrell GElf_Ehdr e64; 2276ff6d951SJohn Birrell } hdr; 2286ff6d951SJohn Birrell 2296ff6d951SJohn Birrell bzero(&ctfsect, sizeof (ctf_sect_t)); 2306ff6d951SJohn Birrell bzero(&symsect, sizeof (ctf_sect_t)); 2316ff6d951SJohn Birrell bzero(&strsect, sizeof (ctf_sect_t)); 2326ff6d951SJohn Birrell bzero(&hdr.ctf, sizeof (hdr)); 2336ff6d951SJohn Birrell 2346ff6d951SJohn Birrell if (fstat64(fd, &st) == -1) 2356ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 2366ff6d951SJohn Birrell 2376ff6d951SJohn Birrell if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0) 2386ff6d951SJohn Birrell return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT)); 2396ff6d951SJohn Birrell 2406ff6d951SJohn Birrell /* 2416ff6d951SJohn Birrell * If we have read enough bytes to form a CTF header and the magic 2426ff6d951SJohn Birrell * string matches, attempt to interpret the file as raw CTF. 2436ff6d951SJohn Birrell */ 244*76429c36SJohn Birrell if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) && 2456ff6d951SJohn Birrell hdr.ctf.ctp_magic == CTF_MAGIC) { 2466ff6d951SJohn Birrell if (hdr.ctf.ctp_version > CTF_VERSION) 2476ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_CTFVERS)); 2486ff6d951SJohn Birrell 2496ff6d951SJohn Birrell ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ, 2506ff6d951SJohn Birrell MAP_PRIVATE, fd, 0); 2516ff6d951SJohn Birrell 2526ff6d951SJohn Birrell if (ctfsect.cts_data == MAP_FAILED) 2536ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 2546ff6d951SJohn Birrell 2556ff6d951SJohn Birrell ctfsect.cts_name = _CTF_SECTION; 2566ff6d951SJohn Birrell ctfsect.cts_type = SHT_PROGBITS; 2576ff6d951SJohn Birrell ctfsect.cts_flags = SHF_ALLOC; 2586ff6d951SJohn Birrell ctfsect.cts_size = (size_t)st.st_size; 2596ff6d951SJohn Birrell ctfsect.cts_entsize = 1; 2606ff6d951SJohn Birrell ctfsect.cts_offset = 0; 2616ff6d951SJohn Birrell 2626ff6d951SJohn Birrell if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL) 2636ff6d951SJohn Birrell ctf_sect_munmap(&ctfsect); 2646ff6d951SJohn Birrell 2656ff6d951SJohn Birrell return (fp); 2666ff6d951SJohn Birrell } 2676ff6d951SJohn Birrell 2686ff6d951SJohn Birrell /* 2696ff6d951SJohn Birrell * If we have read enough bytes to form an ELF header and the magic 2706ff6d951SJohn Birrell * string matches, attempt to interpret the file as an ELF file. We 2716ff6d951SJohn Birrell * do our own largefile ELF processing, and convert everything to 2726ff6d951SJohn Birrell * GElf structures so that clients can operate on any data model. 2736ff6d951SJohn Birrell */ 274*76429c36SJohn Birrell if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) && 2756ff6d951SJohn Birrell bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) { 2766ff6d951SJohn Birrell #ifdef _BIG_ENDIAN 2776ff6d951SJohn Birrell uchar_t order = ELFDATA2MSB; 2786ff6d951SJohn Birrell #else 2796ff6d951SJohn Birrell uchar_t order = ELFDATA2LSB; 2806ff6d951SJohn Birrell #endif 2816ff6d951SJohn Birrell GElf_Half i, n; 2826ff6d951SJohn Birrell GElf_Shdr *sp; 2836ff6d951SJohn Birrell 2846ff6d951SJohn Birrell void *strs_map; 2856ff6d951SJohn Birrell size_t strs_mapsz; 286*76429c36SJohn Birrell char *strs; 2876ff6d951SJohn Birrell 2886ff6d951SJohn Birrell if (hdr.e32.e_ident[EI_DATA] != order) 2896ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_ENDIAN)); 2906ff6d951SJohn Birrell if (hdr.e32.e_version != EV_CURRENT) 2916ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_ELFVERS)); 2926ff6d951SJohn Birrell 2936ff6d951SJohn Birrell if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) { 294*76429c36SJohn Birrell if (nbytes < (ssize_t) sizeof (GElf_Ehdr)) 2956ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_FMT)); 2966ff6d951SJohn Birrell } else { 2976ff6d951SJohn Birrell Elf32_Ehdr e32 = hdr.e32; 2986ff6d951SJohn Birrell ehdr_to_gelf(&e32, &hdr.e64); 2996ff6d951SJohn Birrell } 3006ff6d951SJohn Birrell 3016ff6d951SJohn Birrell if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum) 3026ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_CORRUPT)); 3036ff6d951SJohn Birrell 3046ff6d951SJohn Birrell n = hdr.e64.e_shnum; 3056ff6d951SJohn Birrell nbytes = sizeof (GElf_Shdr) * n; 3066ff6d951SJohn Birrell 3076ff6d951SJohn Birrell if ((sp = malloc(nbytes)) == NULL) 3086ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 3096ff6d951SJohn Birrell 3106ff6d951SJohn Birrell /* 3116ff6d951SJohn Birrell * Read in and convert to GElf the array of Shdr structures 3126ff6d951SJohn Birrell * from e_shoff so we can locate sections of interest. 3136ff6d951SJohn Birrell */ 3146ff6d951SJohn Birrell if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { 3156ff6d951SJohn Birrell Elf32_Shdr *sp32; 3166ff6d951SJohn Birrell 3176ff6d951SJohn Birrell nbytes = sizeof (Elf32_Shdr) * n; 3186ff6d951SJohn Birrell 3196ff6d951SJohn Birrell if ((sp32 = malloc(nbytes)) == NULL || pread64(fd, 3206ff6d951SJohn Birrell sp32, nbytes, hdr.e64.e_shoff) != nbytes) { 3216ff6d951SJohn Birrell free(sp); 3226ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 3236ff6d951SJohn Birrell } 3246ff6d951SJohn Birrell 3256ff6d951SJohn Birrell for (i = 0; i < n; i++) 3266ff6d951SJohn Birrell shdr_to_gelf(&sp32[i], &sp[i]); 3276ff6d951SJohn Birrell 3286ff6d951SJohn Birrell free(sp32); 3296ff6d951SJohn Birrell 3306ff6d951SJohn Birrell } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) { 3316ff6d951SJohn Birrell free(sp); 3326ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 3336ff6d951SJohn Birrell } 3346ff6d951SJohn Birrell 3356ff6d951SJohn Birrell /* 3366ff6d951SJohn Birrell * Now mmap the section header strings section so that we can 3376ff6d951SJohn Birrell * perform string comparison on the section names. 3386ff6d951SJohn Birrell */ 3396ff6d951SJohn Birrell strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size + 3406ff6d951SJohn Birrell (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK); 3416ff6d951SJohn Birrell 3426ff6d951SJohn Birrell strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE, 3436ff6d951SJohn Birrell fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK); 3446ff6d951SJohn Birrell 345*76429c36SJohn Birrell strs = (char *)strs_map + 3466ff6d951SJohn Birrell (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK); 3476ff6d951SJohn Birrell 3486ff6d951SJohn Birrell if (strs_map == MAP_FAILED) { 3496ff6d951SJohn Birrell free(sp); 3506ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_MMAP)); 3516ff6d951SJohn Birrell } 3526ff6d951SJohn Birrell 3536ff6d951SJohn Birrell /* 3546ff6d951SJohn Birrell * Iterate over the section header array looking for the CTF 3556ff6d951SJohn Birrell * section and symbol table. The strtab is linked to symtab. 3566ff6d951SJohn Birrell */ 3576ff6d951SJohn Birrell for (i = 0; i < n; i++) { 3586ff6d951SJohn Birrell const GElf_Shdr *shp = &sp[i]; 3596ff6d951SJohn Birrell const GElf_Shdr *lhp = &sp[shp->sh_link]; 3606ff6d951SJohn Birrell 3616ff6d951SJohn Birrell if (shp->sh_link >= hdr.e64.e_shnum) 3626ff6d951SJohn Birrell continue; /* corrupt sh_link field */ 3636ff6d951SJohn Birrell 3646ff6d951SJohn Birrell if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size || 3656ff6d951SJohn Birrell lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size) 3666ff6d951SJohn Birrell continue; /* corrupt sh_name field */ 3676ff6d951SJohn Birrell 3686ff6d951SJohn Birrell if (shp->sh_type == SHT_PROGBITS && 3696ff6d951SJohn Birrell strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) { 3706ff6d951SJohn Birrell ctfsect.cts_name = strs + shp->sh_name; 3716ff6d951SJohn Birrell ctfsect.cts_type = shp->sh_type; 3726ff6d951SJohn Birrell ctfsect.cts_flags = shp->sh_flags; 3736ff6d951SJohn Birrell ctfsect.cts_size = shp->sh_size; 3746ff6d951SJohn Birrell ctfsect.cts_entsize = shp->sh_entsize; 3756ff6d951SJohn Birrell ctfsect.cts_offset = (off64_t)shp->sh_offset; 3766ff6d951SJohn Birrell 3776ff6d951SJohn Birrell } else if (shp->sh_type == SHT_SYMTAB) { 3786ff6d951SJohn Birrell symsect.cts_name = strs + shp->sh_name; 3796ff6d951SJohn Birrell symsect.cts_type = shp->sh_type; 3806ff6d951SJohn Birrell symsect.cts_flags = shp->sh_flags; 3816ff6d951SJohn Birrell symsect.cts_size = shp->sh_size; 3826ff6d951SJohn Birrell symsect.cts_entsize = shp->sh_entsize; 3836ff6d951SJohn Birrell symsect.cts_offset = (off64_t)shp->sh_offset; 3846ff6d951SJohn Birrell 3856ff6d951SJohn Birrell strsect.cts_name = strs + lhp->sh_name; 3866ff6d951SJohn Birrell strsect.cts_type = lhp->sh_type; 3876ff6d951SJohn Birrell strsect.cts_flags = lhp->sh_flags; 3886ff6d951SJohn Birrell strsect.cts_size = lhp->sh_size; 3896ff6d951SJohn Birrell strsect.cts_entsize = lhp->sh_entsize; 3906ff6d951SJohn Birrell strsect.cts_offset = (off64_t)lhp->sh_offset; 3916ff6d951SJohn Birrell } 3926ff6d951SJohn Birrell } 3936ff6d951SJohn Birrell 3946ff6d951SJohn Birrell free(sp); /* free section header array */ 3956ff6d951SJohn Birrell 3966ff6d951SJohn Birrell if (ctfsect.cts_type == SHT_NULL) { 3976ff6d951SJohn Birrell (void) munmap(strs_map, strs_mapsz); 3986ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_NOCTFDATA)); 3996ff6d951SJohn Birrell } 4006ff6d951SJohn Birrell 4016ff6d951SJohn Birrell /* 4026ff6d951SJohn Birrell * Now mmap the CTF data, symtab, and strtab sections and 4036ff6d951SJohn Birrell * call ctf_bufopen() to do the rest of the work. 4046ff6d951SJohn Birrell */ 4056ff6d951SJohn Birrell if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) { 4066ff6d951SJohn Birrell (void) munmap(strs_map, strs_mapsz); 4076ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_MMAP)); 4086ff6d951SJohn Birrell } 4096ff6d951SJohn Birrell 4106ff6d951SJohn Birrell if (symsect.cts_type != SHT_NULL && 4116ff6d951SJohn Birrell strsect.cts_type != SHT_NULL) { 4126ff6d951SJohn Birrell if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED || 4136ff6d951SJohn Birrell ctf_sect_mmap(&strsect, fd) == MAP_FAILED) { 4146ff6d951SJohn Birrell (void) ctf_set_open_errno(errp, ECTF_MMAP); 4156ff6d951SJohn Birrell goto bad; /* unmap all and abort */ 4166ff6d951SJohn Birrell } 4176ff6d951SJohn Birrell fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp); 4186ff6d951SJohn Birrell } else 4196ff6d951SJohn Birrell fp = ctf_bufopen(&ctfsect, NULL, NULL, errp); 4206ff6d951SJohn Birrell bad: 4216ff6d951SJohn Birrell if (fp == NULL) { 4226ff6d951SJohn Birrell ctf_sect_munmap(&ctfsect); 4236ff6d951SJohn Birrell ctf_sect_munmap(&symsect); 4246ff6d951SJohn Birrell ctf_sect_munmap(&strsect); 4256ff6d951SJohn Birrell } else 4266ff6d951SJohn Birrell fp->ctf_flags |= LCTF_MMAP; 4276ff6d951SJohn Birrell 4286ff6d951SJohn Birrell (void) munmap(strs_map, strs_mapsz); 4296ff6d951SJohn Birrell return (fp); 4306ff6d951SJohn Birrell } 4316ff6d951SJohn Birrell 4326ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_FMT)); 4336ff6d951SJohn Birrell } 4346ff6d951SJohn Birrell 4356ff6d951SJohn Birrell /* 4366ff6d951SJohn Birrell * Open the specified file and return a pointer to a CTF container. The file 4376ff6d951SJohn Birrell * can be either an ELF file or raw CTF file. This is just a convenient 4386ff6d951SJohn Birrell * wrapper around ctf_fdopen() for callers. 4396ff6d951SJohn Birrell */ 4406ff6d951SJohn Birrell ctf_file_t * 4416ff6d951SJohn Birrell ctf_open(const char *filename, int *errp) 4426ff6d951SJohn Birrell { 4436ff6d951SJohn Birrell ctf_file_t *fp; 4446ff6d951SJohn Birrell int fd; 4456ff6d951SJohn Birrell 4466ff6d951SJohn Birrell if ((fd = open64(filename, O_RDONLY)) == -1) { 4476ff6d951SJohn Birrell if (errp != NULL) 4486ff6d951SJohn Birrell *errp = errno; 4496ff6d951SJohn Birrell return (NULL); 4506ff6d951SJohn Birrell } 4516ff6d951SJohn Birrell 4526ff6d951SJohn Birrell fp = ctf_fdopen(fd, errp); 4536ff6d951SJohn Birrell (void) close(fd); 4546ff6d951SJohn Birrell return (fp); 4556ff6d951SJohn Birrell } 4566ff6d951SJohn Birrell 4576ff6d951SJohn Birrell /* 4586ff6d951SJohn Birrell * Write the uncompressed CTF data stream to the specified file descriptor. 4596ff6d951SJohn Birrell * This is useful for saving the results of dynamic CTF containers. 4606ff6d951SJohn Birrell */ 4616ff6d951SJohn Birrell int 4626ff6d951SJohn Birrell ctf_write(ctf_file_t *fp, int fd) 4636ff6d951SJohn Birrell { 4646ff6d951SJohn Birrell const uchar_t *buf = fp->ctf_base; 4656ff6d951SJohn Birrell ssize_t resid = fp->ctf_size; 4666ff6d951SJohn Birrell ssize_t len; 4676ff6d951SJohn Birrell 4686ff6d951SJohn Birrell while (resid != 0) { 4696ff6d951SJohn Birrell if ((len = write(fd, buf, resid)) <= 0) 4706ff6d951SJohn Birrell return (ctf_set_errno(fp, errno)); 4716ff6d951SJohn Birrell resid -= len; 4726ff6d951SJohn Birrell buf += len; 4736ff6d951SJohn Birrell } 4746ff6d951SJohn Birrell 4756ff6d951SJohn Birrell return (0); 4766ff6d951SJohn Birrell } 4776ff6d951SJohn Birrell 4786ff6d951SJohn Birrell /* 4796ff6d951SJohn Birrell * Set the CTF library client version to the specified version. If version is 4806ff6d951SJohn Birrell * zero, we just return the default library version number. 4816ff6d951SJohn Birrell */ 4826ff6d951SJohn Birrell int 4836ff6d951SJohn Birrell ctf_version(int version) 4846ff6d951SJohn Birrell { 4856ff6d951SJohn Birrell if (version < 0) { 4866ff6d951SJohn Birrell errno = EINVAL; 4876ff6d951SJohn Birrell return (-1); 4886ff6d951SJohn Birrell } 4896ff6d951SJohn Birrell 4906ff6d951SJohn Birrell if (version > 0) { 4916ff6d951SJohn Birrell if (version > CTF_VERSION) { 4926ff6d951SJohn Birrell errno = ENOTSUP; 4936ff6d951SJohn Birrell return (-1); 4946ff6d951SJohn Birrell } 4956ff6d951SJohn Birrell ctf_dprintf("ctf_version: client using version %d\n", version); 4966ff6d951SJohn Birrell _libctf_version = version; 4976ff6d951SJohn Birrell } 4986ff6d951SJohn Birrell 4996ff6d951SJohn Birrell return (_libctf_version); 5006ff6d951SJohn Birrell } 501