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> 3276429c36SJohn 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> 3776429c36SJohn Birrell #if defined(sun) 386ff6d951SJohn Birrell #include <dlfcn.h> 3976429c36SJohn Birrell #else 4076429c36SJohn Birrell #include <zlib.h> 4176429c36SJohn Birrell #endif 426ff6d951SJohn Birrell #include <gelf.h> 436ff6d951SJohn Birrell 4476429c36SJohn 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 5076429c36SJohn 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 6176429c36SJohn Birrell #if defined(sun) 626ff6d951SJohn Birrell #pragma init(_libctf_init) 6376429c36SJohn Birrell #else 6476429c36SJohn Birrell void _libctf_init(void) __attribute__ ((constructor)); 6576429c36SJohn Birrell #endif 666ff6d951SJohn Birrell void 676ff6d951SJohn Birrell _libctf_init(void) 686ff6d951SJohn Birrell { 6976429c36SJohn 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 */ 7476429c36SJohn 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 { 9076429c36SJohn 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 10276429c36SJohn Birrell zlib.z_uncompress = (int (*)(uchar_t *, ulong_t *, const uchar_t *, ulong_t)) dlsym(zlib.z_dlp, "uncompress"); 10376429c36SJohn 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 } 11076429c36SJohn Birrell #else 11176429c36SJohn Birrell zlib.z_uncompress = uncompress; 11276429c36SJohn Birrell zlib.z_error = zError; 11376429c36SJohn Birrell 11476429c36SJohn Birrell /* Dummy return variable as 'no error' */ 11576429c36SJohn Birrell zlib.z_dlp = (void *) (uintptr_t) 1; 11676429c36SJohn 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; 219*cc16dea6SXin LI size_t shstrndx, shnum; 2206ff6d951SJohn Birrell 2216ff6d951SJohn Birrell struct stat64 st; 2226ff6d951SJohn Birrell ssize_t nbytes; 2236ff6d951SJohn Birrell 2246ff6d951SJohn Birrell union { 2256ff6d951SJohn Birrell ctf_preamble_t ctf; 2266ff6d951SJohn Birrell Elf32_Ehdr e32; 2276ff6d951SJohn Birrell GElf_Ehdr e64; 2286ff6d951SJohn Birrell } hdr; 2296ff6d951SJohn Birrell 2306ff6d951SJohn Birrell bzero(&ctfsect, sizeof (ctf_sect_t)); 2316ff6d951SJohn Birrell bzero(&symsect, sizeof (ctf_sect_t)); 2326ff6d951SJohn Birrell bzero(&strsect, sizeof (ctf_sect_t)); 2336ff6d951SJohn Birrell bzero(&hdr.ctf, sizeof (hdr)); 2346ff6d951SJohn Birrell 2356ff6d951SJohn Birrell if (fstat64(fd, &st) == -1) 2366ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 2376ff6d951SJohn Birrell 2386ff6d951SJohn Birrell if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0) 2396ff6d951SJohn Birrell return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT)); 2406ff6d951SJohn Birrell 2416ff6d951SJohn Birrell /* 2426ff6d951SJohn Birrell * If we have read enough bytes to form a CTF header and the magic 2436ff6d951SJohn Birrell * string matches, attempt to interpret the file as raw CTF. 2446ff6d951SJohn Birrell */ 24576429c36SJohn Birrell if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) && 2466ff6d951SJohn Birrell hdr.ctf.ctp_magic == CTF_MAGIC) { 2476ff6d951SJohn Birrell if (hdr.ctf.ctp_version > CTF_VERSION) 2486ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_CTFVERS)); 2496ff6d951SJohn Birrell 2506ff6d951SJohn Birrell ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ, 2516ff6d951SJohn Birrell MAP_PRIVATE, fd, 0); 2526ff6d951SJohn Birrell 2536ff6d951SJohn Birrell if (ctfsect.cts_data == MAP_FAILED) 2546ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 2556ff6d951SJohn Birrell 2566ff6d951SJohn Birrell ctfsect.cts_name = _CTF_SECTION; 2576ff6d951SJohn Birrell ctfsect.cts_type = SHT_PROGBITS; 2586ff6d951SJohn Birrell ctfsect.cts_flags = SHF_ALLOC; 2596ff6d951SJohn Birrell ctfsect.cts_size = (size_t)st.st_size; 2606ff6d951SJohn Birrell ctfsect.cts_entsize = 1; 2616ff6d951SJohn Birrell ctfsect.cts_offset = 0; 2626ff6d951SJohn Birrell 2636ff6d951SJohn Birrell if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL) 2646ff6d951SJohn Birrell ctf_sect_munmap(&ctfsect); 2656ff6d951SJohn Birrell 2666ff6d951SJohn Birrell return (fp); 2676ff6d951SJohn Birrell } 2686ff6d951SJohn Birrell 2696ff6d951SJohn Birrell /* 2706ff6d951SJohn Birrell * If we have read enough bytes to form an ELF header and the magic 2716ff6d951SJohn Birrell * string matches, attempt to interpret the file as an ELF file. We 2726ff6d951SJohn Birrell * do our own largefile ELF processing, and convert everything to 2736ff6d951SJohn Birrell * GElf structures so that clients can operate on any data model. 2746ff6d951SJohn Birrell */ 27576429c36SJohn Birrell if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) && 2766ff6d951SJohn Birrell bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) { 2776ff6d951SJohn Birrell #ifdef _BIG_ENDIAN 2786ff6d951SJohn Birrell uchar_t order = ELFDATA2MSB; 2796ff6d951SJohn Birrell #else 2806ff6d951SJohn Birrell uchar_t order = ELFDATA2LSB; 2816ff6d951SJohn Birrell #endif 2826ff6d951SJohn Birrell GElf_Shdr *sp; 2836ff6d951SJohn Birrell 2846ff6d951SJohn Birrell void *strs_map; 285*cc16dea6SXin LI size_t strs_mapsz, i; 28676429c36SJohn 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) { 29476429c36SJohn 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 301*cc16dea6SXin LI shnum = hdr.e64.e_shnum; 302*cc16dea6SXin LI shstrndx = hdr.e64.e_shstrndx; 303*cc16dea6SXin LI 304*cc16dea6SXin LI /* Extended ELF sections */ 305*cc16dea6SXin LI if ((shstrndx == SHN_XINDEX) || (shnum == 0)) { 306*cc16dea6SXin LI if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { 307*cc16dea6SXin LI Elf32_Shdr x32; 308*cc16dea6SXin LI 309*cc16dea6SXin LI if (pread64(fd, &x32, sizeof (x32), 310*cc16dea6SXin LI hdr.e64.e_shoff) != sizeof (x32)) 311*cc16dea6SXin LI return (ctf_set_open_errno(errp, 312*cc16dea6SXin LI errno)); 313*cc16dea6SXin LI 314*cc16dea6SXin LI shnum = x32.sh_size; 315*cc16dea6SXin LI shstrndx = x32.sh_link; 316*cc16dea6SXin LI } else { 317*cc16dea6SXin LI Elf64_Shdr x64; 318*cc16dea6SXin LI 319*cc16dea6SXin LI if (pread64(fd, &x64, sizeof (x64), 320*cc16dea6SXin LI hdr.e64.e_shoff) != sizeof (x64)) 321*cc16dea6SXin LI return (ctf_set_open_errno(errp, 322*cc16dea6SXin LI errno)); 323*cc16dea6SXin LI 324*cc16dea6SXin LI shnum = x64.sh_size; 325*cc16dea6SXin LI shstrndx = x64.sh_link; 326*cc16dea6SXin LI } 327*cc16dea6SXin LI } 328*cc16dea6SXin LI 329*cc16dea6SXin LI if (shstrndx >= shnum) 3306ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_CORRUPT)); 3316ff6d951SJohn Birrell 332*cc16dea6SXin LI nbytes = sizeof (GElf_Shdr) * shnum; 3336ff6d951SJohn Birrell 3346ff6d951SJohn Birrell if ((sp = malloc(nbytes)) == NULL) 3356ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 3366ff6d951SJohn Birrell 3376ff6d951SJohn Birrell /* 3386ff6d951SJohn Birrell * Read in and convert to GElf the array of Shdr structures 3396ff6d951SJohn Birrell * from e_shoff so we can locate sections of interest. 3406ff6d951SJohn Birrell */ 3416ff6d951SJohn Birrell if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { 3426ff6d951SJohn Birrell Elf32_Shdr *sp32; 3436ff6d951SJohn Birrell 344*cc16dea6SXin LI nbytes = sizeof (Elf32_Shdr) * shnum; 3456ff6d951SJohn Birrell 3466ff6d951SJohn Birrell if ((sp32 = malloc(nbytes)) == NULL || pread64(fd, 3476ff6d951SJohn Birrell sp32, nbytes, hdr.e64.e_shoff) != nbytes) { 3486ff6d951SJohn Birrell free(sp); 3496ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 3506ff6d951SJohn Birrell } 3516ff6d951SJohn Birrell 352*cc16dea6SXin LI for (i = 0; i < shnum; i++) 3536ff6d951SJohn Birrell shdr_to_gelf(&sp32[i], &sp[i]); 3546ff6d951SJohn Birrell 3556ff6d951SJohn Birrell free(sp32); 3566ff6d951SJohn Birrell 3576ff6d951SJohn Birrell } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) { 3586ff6d951SJohn Birrell free(sp); 3596ff6d951SJohn Birrell return (ctf_set_open_errno(errp, errno)); 3606ff6d951SJohn Birrell } 3616ff6d951SJohn Birrell 3626ff6d951SJohn Birrell /* 3636ff6d951SJohn Birrell * Now mmap the section header strings section so that we can 3646ff6d951SJohn Birrell * perform string comparison on the section names. 3656ff6d951SJohn Birrell */ 366*cc16dea6SXin LI strs_mapsz = sp[shstrndx].sh_size + 367*cc16dea6SXin LI (sp[shstrndx].sh_offset & ~_PAGEMASK); 3686ff6d951SJohn Birrell 3696ff6d951SJohn Birrell strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE, 370*cc16dea6SXin LI fd, sp[shstrndx].sh_offset & _PAGEMASK); 3716ff6d951SJohn Birrell 37276429c36SJohn Birrell strs = (char *)strs_map + 373*cc16dea6SXin LI (sp[shstrndx].sh_offset & ~_PAGEMASK); 3746ff6d951SJohn Birrell 3756ff6d951SJohn Birrell if (strs_map == MAP_FAILED) { 3766ff6d951SJohn Birrell free(sp); 3776ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_MMAP)); 3786ff6d951SJohn Birrell } 3796ff6d951SJohn Birrell 3806ff6d951SJohn Birrell /* 3816ff6d951SJohn Birrell * Iterate over the section header array looking for the CTF 3826ff6d951SJohn Birrell * section and symbol table. The strtab is linked to symtab. 3836ff6d951SJohn Birrell */ 384*cc16dea6SXin LI for (i = 0; i < shnum; i++) { 3856ff6d951SJohn Birrell const GElf_Shdr *shp = &sp[i]; 3866ff6d951SJohn Birrell const GElf_Shdr *lhp = &sp[shp->sh_link]; 3876ff6d951SJohn Birrell 388*cc16dea6SXin LI if (shp->sh_link >= shnum) 3896ff6d951SJohn Birrell continue; /* corrupt sh_link field */ 3906ff6d951SJohn Birrell 391*cc16dea6SXin LI if (shp->sh_name >= sp[shstrndx].sh_size || 392*cc16dea6SXin LI lhp->sh_name >= sp[shstrndx].sh_size) 3936ff6d951SJohn Birrell continue; /* corrupt sh_name field */ 3946ff6d951SJohn Birrell 3956ff6d951SJohn Birrell if (shp->sh_type == SHT_PROGBITS && 3966ff6d951SJohn Birrell strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) { 3976ff6d951SJohn Birrell ctfsect.cts_name = strs + shp->sh_name; 3986ff6d951SJohn Birrell ctfsect.cts_type = shp->sh_type; 3996ff6d951SJohn Birrell ctfsect.cts_flags = shp->sh_flags; 4006ff6d951SJohn Birrell ctfsect.cts_size = shp->sh_size; 4016ff6d951SJohn Birrell ctfsect.cts_entsize = shp->sh_entsize; 4026ff6d951SJohn Birrell ctfsect.cts_offset = (off64_t)shp->sh_offset; 4036ff6d951SJohn Birrell 4046ff6d951SJohn Birrell } else if (shp->sh_type == SHT_SYMTAB) { 4056ff6d951SJohn Birrell symsect.cts_name = strs + shp->sh_name; 4066ff6d951SJohn Birrell symsect.cts_type = shp->sh_type; 4076ff6d951SJohn Birrell symsect.cts_flags = shp->sh_flags; 4086ff6d951SJohn Birrell symsect.cts_size = shp->sh_size; 4096ff6d951SJohn Birrell symsect.cts_entsize = shp->sh_entsize; 4106ff6d951SJohn Birrell symsect.cts_offset = (off64_t)shp->sh_offset; 4116ff6d951SJohn Birrell 4126ff6d951SJohn Birrell strsect.cts_name = strs + lhp->sh_name; 4136ff6d951SJohn Birrell strsect.cts_type = lhp->sh_type; 4146ff6d951SJohn Birrell strsect.cts_flags = lhp->sh_flags; 4156ff6d951SJohn Birrell strsect.cts_size = lhp->sh_size; 4166ff6d951SJohn Birrell strsect.cts_entsize = lhp->sh_entsize; 4176ff6d951SJohn Birrell strsect.cts_offset = (off64_t)lhp->sh_offset; 4186ff6d951SJohn Birrell } 4196ff6d951SJohn Birrell } 4206ff6d951SJohn Birrell 4216ff6d951SJohn Birrell free(sp); /* free section header array */ 4226ff6d951SJohn Birrell 4236ff6d951SJohn Birrell if (ctfsect.cts_type == SHT_NULL) { 4246ff6d951SJohn Birrell (void) munmap(strs_map, strs_mapsz); 4256ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_NOCTFDATA)); 4266ff6d951SJohn Birrell } 4276ff6d951SJohn Birrell 4286ff6d951SJohn Birrell /* 4296ff6d951SJohn Birrell * Now mmap the CTF data, symtab, and strtab sections and 4306ff6d951SJohn Birrell * call ctf_bufopen() to do the rest of the work. 4316ff6d951SJohn Birrell */ 4326ff6d951SJohn Birrell if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) { 4336ff6d951SJohn Birrell (void) munmap(strs_map, strs_mapsz); 4346ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_MMAP)); 4356ff6d951SJohn Birrell } 4366ff6d951SJohn Birrell 4376ff6d951SJohn Birrell if (symsect.cts_type != SHT_NULL && 4386ff6d951SJohn Birrell strsect.cts_type != SHT_NULL) { 4396ff6d951SJohn Birrell if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED || 4406ff6d951SJohn Birrell ctf_sect_mmap(&strsect, fd) == MAP_FAILED) { 4416ff6d951SJohn Birrell (void) ctf_set_open_errno(errp, ECTF_MMAP); 4426ff6d951SJohn Birrell goto bad; /* unmap all and abort */ 4436ff6d951SJohn Birrell } 4446ff6d951SJohn Birrell fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp); 4456ff6d951SJohn Birrell } else 4466ff6d951SJohn Birrell fp = ctf_bufopen(&ctfsect, NULL, NULL, errp); 4476ff6d951SJohn Birrell bad: 4486ff6d951SJohn Birrell if (fp == NULL) { 4496ff6d951SJohn Birrell ctf_sect_munmap(&ctfsect); 4506ff6d951SJohn Birrell ctf_sect_munmap(&symsect); 4516ff6d951SJohn Birrell ctf_sect_munmap(&strsect); 4526ff6d951SJohn Birrell } else 4536ff6d951SJohn Birrell fp->ctf_flags |= LCTF_MMAP; 4546ff6d951SJohn Birrell 4556ff6d951SJohn Birrell (void) munmap(strs_map, strs_mapsz); 4566ff6d951SJohn Birrell return (fp); 4576ff6d951SJohn Birrell } 4586ff6d951SJohn Birrell 4596ff6d951SJohn Birrell return (ctf_set_open_errno(errp, ECTF_FMT)); 4606ff6d951SJohn Birrell } 4616ff6d951SJohn Birrell 4626ff6d951SJohn Birrell /* 4636ff6d951SJohn Birrell * Open the specified file and return a pointer to a CTF container. The file 4646ff6d951SJohn Birrell * can be either an ELF file or raw CTF file. This is just a convenient 4656ff6d951SJohn Birrell * wrapper around ctf_fdopen() for callers. 4666ff6d951SJohn Birrell */ 4676ff6d951SJohn Birrell ctf_file_t * 4686ff6d951SJohn Birrell ctf_open(const char *filename, int *errp) 4696ff6d951SJohn Birrell { 4706ff6d951SJohn Birrell ctf_file_t *fp; 4716ff6d951SJohn Birrell int fd; 4726ff6d951SJohn Birrell 4736ff6d951SJohn Birrell if ((fd = open64(filename, O_RDONLY)) == -1) { 4746ff6d951SJohn Birrell if (errp != NULL) 4756ff6d951SJohn Birrell *errp = errno; 4766ff6d951SJohn Birrell return (NULL); 4776ff6d951SJohn Birrell } 4786ff6d951SJohn Birrell 4796ff6d951SJohn Birrell fp = ctf_fdopen(fd, errp); 4806ff6d951SJohn Birrell (void) close(fd); 4816ff6d951SJohn Birrell return (fp); 4826ff6d951SJohn Birrell } 4836ff6d951SJohn Birrell 4846ff6d951SJohn Birrell /* 4856ff6d951SJohn Birrell * Write the uncompressed CTF data stream to the specified file descriptor. 4866ff6d951SJohn Birrell * This is useful for saving the results of dynamic CTF containers. 4876ff6d951SJohn Birrell */ 4886ff6d951SJohn Birrell int 4896ff6d951SJohn Birrell ctf_write(ctf_file_t *fp, int fd) 4906ff6d951SJohn Birrell { 4916ff6d951SJohn Birrell const uchar_t *buf = fp->ctf_base; 4926ff6d951SJohn Birrell ssize_t resid = fp->ctf_size; 4936ff6d951SJohn Birrell ssize_t len; 4946ff6d951SJohn Birrell 4956ff6d951SJohn Birrell while (resid != 0) { 4966ff6d951SJohn Birrell if ((len = write(fd, buf, resid)) <= 0) 4976ff6d951SJohn Birrell return (ctf_set_errno(fp, errno)); 4986ff6d951SJohn Birrell resid -= len; 4996ff6d951SJohn Birrell buf += len; 5006ff6d951SJohn Birrell } 5016ff6d951SJohn Birrell 5026ff6d951SJohn Birrell return (0); 5036ff6d951SJohn Birrell } 5046ff6d951SJohn Birrell 5056ff6d951SJohn Birrell /* 5066ff6d951SJohn Birrell * Set the CTF library client version to the specified version. If version is 5076ff6d951SJohn Birrell * zero, we just return the default library version number. 5086ff6d951SJohn Birrell */ 5096ff6d951SJohn Birrell int 5106ff6d951SJohn Birrell ctf_version(int version) 5116ff6d951SJohn Birrell { 5126ff6d951SJohn Birrell if (version < 0) { 5136ff6d951SJohn Birrell errno = EINVAL; 5146ff6d951SJohn Birrell return (-1); 5156ff6d951SJohn Birrell } 5166ff6d951SJohn Birrell 5176ff6d951SJohn Birrell if (version > 0) { 5186ff6d951SJohn Birrell if (version > CTF_VERSION) { 5196ff6d951SJohn Birrell errno = ENOTSUP; 5206ff6d951SJohn Birrell return (-1); 5216ff6d951SJohn Birrell } 5226ff6d951SJohn Birrell ctf_dprintf("ctf_version: client using version %d\n", version); 5236ff6d951SJohn Birrell _libctf_version = version; 5246ff6d951SJohn Birrell } 5256ff6d951SJohn Birrell 5266ff6d951SJohn Birrell return (_libctf_version); 5276ff6d951SJohn Birrell } 528