17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 26*7fd79137SRobert Mustacchi /* 27*7fd79137SRobert Mustacchi * Copyright (c) 2015, Joyent, Inc. 28*7fd79137SRobert Mustacchi */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/stat.h> 327c478bd9Sstevel@tonic-gate #include <sys/mman.h> 337c478bd9Sstevel@tonic-gate #include <ctf_impl.h> 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <fcntl.h> 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <dlfcn.h> 387c478bd9Sstevel@tonic-gate #include <gelf.h> 39*7fd79137SRobert Mustacchi #include <zlib.h> 40*7fd79137SRobert Mustacchi #include <sys/debug.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #ifdef _LP64 432f970cc1SKeith M Wesolowski static const char *_libctf_zlib = "/usr/lib/64/libz.so.1"; 447c478bd9Sstevel@tonic-gate #else 452f970cc1SKeith M Wesolowski static const char *_libctf_zlib = "/usr/lib/libz.so.1"; 467c478bd9Sstevel@tonic-gate #endif 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate static struct { 497c478bd9Sstevel@tonic-gate int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t); 50*7fd79137SRobert Mustacchi int (*z_initcomp)(z_stream *, int, const char *, int); 51*7fd79137SRobert Mustacchi int (*z_compress)(z_stream *, int); 52*7fd79137SRobert Mustacchi int (*z_finicomp)(z_stream *); 537c478bd9Sstevel@tonic-gate const char *(*z_error)(int); 547c478bd9Sstevel@tonic-gate void *z_dlp; 557c478bd9Sstevel@tonic-gate } zlib; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static size_t _PAGESIZE; 587c478bd9Sstevel@tonic-gate static size_t _PAGEMASK; 597c478bd9Sstevel@tonic-gate 60*7fd79137SRobert Mustacchi static uint64_t ctf_phase = 0; 61*7fd79137SRobert Mustacchi 62*7fd79137SRobert Mustacchi #define CTF_COMPRESS_CHUNK (64*1024) 63*7fd79137SRobert Mustacchi 64*7fd79137SRobert Mustacchi typedef struct ctf_zdata { 65*7fd79137SRobert Mustacchi void *czd_buf; 66*7fd79137SRobert Mustacchi void *czd_next; 67*7fd79137SRobert Mustacchi ctf_file_t *czd_ctfp; 68*7fd79137SRobert Mustacchi size_t czd_allocsz; 69*7fd79137SRobert Mustacchi z_stream czd_zstr; 70*7fd79137SRobert Mustacchi } ctf_zdata_t; 71*7fd79137SRobert Mustacchi 727c478bd9Sstevel@tonic-gate #pragma init(_libctf_init) 737c478bd9Sstevel@tonic-gate void 747c478bd9Sstevel@tonic-gate _libctf_init(void) 757c478bd9Sstevel@tonic-gate { 767c478bd9Sstevel@tonic-gate const char *p = getenv("LIBCTF_DECOMPRESSOR"); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate if (p != NULL) 797c478bd9Sstevel@tonic-gate _libctf_zlib = p; /* use alternate decompression library */ 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate _libctf_debug = getenv("LIBCTF_DEBUG") != NULL; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate _PAGESIZE = getpagesize(); 847c478bd9Sstevel@tonic-gate _PAGEMASK = ~(_PAGESIZE - 1); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * Attempt to dlopen the decompression library and locate the symbols of 897c478bd9Sstevel@tonic-gate * interest that we will need to call. This information in cached so 907c478bd9Sstevel@tonic-gate * that multiple calls to ctf_bufopen() do not need to reopen the library. 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate void * 937c478bd9Sstevel@tonic-gate ctf_zopen(int *errp) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib); 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate if (zlib.z_dlp != NULL) 987c478bd9Sstevel@tonic-gate return (zlib.z_dlp); /* library is already loaded */ 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate if (access(_libctf_zlib, R_OK) == -1) 1017c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ZMISSING)); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL) 1047c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ZINIT)); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate zlib.z_uncompress = (int (*)()) dlsym(zlib.z_dlp, "uncompress"); 107*7fd79137SRobert Mustacchi zlib.z_initcomp = (int (*)()) dlsym(zlib.z_dlp, "deflateInit_"); 108*7fd79137SRobert Mustacchi zlib.z_compress = (int (*)()) dlsym(zlib.z_dlp, "deflate"); 109*7fd79137SRobert Mustacchi zlib.z_finicomp = (int (*)()) dlsym(zlib.z_dlp, "deflateEnd"); 1107c478bd9Sstevel@tonic-gate zlib.z_error = (const char *(*)()) dlsym(zlib.z_dlp, "zError"); 1117c478bd9Sstevel@tonic-gate 112*7fd79137SRobert Mustacchi if (zlib.z_uncompress == NULL || zlib.z_error == NULL || 113*7fd79137SRobert Mustacchi zlib.z_initcomp == NULL|| zlib.z_compress == NULL || 114*7fd79137SRobert Mustacchi zlib.z_finicomp == NULL) { 1157c478bd9Sstevel@tonic-gate (void) dlclose(zlib.z_dlp); 1167c478bd9Sstevel@tonic-gate bzero(&zlib, sizeof (zlib)); 1177c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ZINIT)); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate return (zlib.z_dlp); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>, 1257c478bd9Sstevel@tonic-gate * which we then patch through to the functions in the decompression library. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate int 1287c478bd9Sstevel@tonic-gate z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen)); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate const char * 1347c478bd9Sstevel@tonic-gate z_strerror(int err) 1357c478bd9Sstevel@tonic-gate { 1367c478bd9Sstevel@tonic-gate return (zlib.z_error(err)); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 139*7fd79137SRobert Mustacchi static int 140*7fd79137SRobert Mustacchi ctf_zdata_init(ctf_zdata_t *czd, ctf_file_t *fp) 141*7fd79137SRobert Mustacchi { 142*7fd79137SRobert Mustacchi ctf_header_t *cthp; 143*7fd79137SRobert Mustacchi 144*7fd79137SRobert Mustacchi bzero(czd, sizeof (ctf_zdata_t)); 145*7fd79137SRobert Mustacchi 146*7fd79137SRobert Mustacchi czd->czd_allocsz = fp->ctf_size; 147*7fd79137SRobert Mustacchi czd->czd_buf = ctf_data_alloc(czd->czd_allocsz); 148*7fd79137SRobert Mustacchi if (czd->czd_buf == MAP_FAILED) 149*7fd79137SRobert Mustacchi return (ctf_set_errno(fp, ENOMEM)); 150*7fd79137SRobert Mustacchi 151*7fd79137SRobert Mustacchi bcopy(fp->ctf_base, czd->czd_buf, sizeof (ctf_header_t)); 152*7fd79137SRobert Mustacchi czd->czd_ctfp = fp; 153*7fd79137SRobert Mustacchi cthp = czd->czd_buf; 154*7fd79137SRobert Mustacchi cthp->cth_flags |= CTF_F_COMPRESS; 155*7fd79137SRobert Mustacchi czd->czd_next = (void *)((uintptr_t)czd->czd_buf + 156*7fd79137SRobert Mustacchi sizeof (ctf_header_t)); 157*7fd79137SRobert Mustacchi 158*7fd79137SRobert Mustacchi if (zlib.z_initcomp(&czd->czd_zstr, Z_BEST_COMPRESSION, 159*7fd79137SRobert Mustacchi ZLIB_VERSION, sizeof (z_stream)) != Z_OK) 160*7fd79137SRobert Mustacchi return (ctf_set_errno(fp, ECTF_ZLIB)); 161*7fd79137SRobert Mustacchi 162*7fd79137SRobert Mustacchi return (0); 163*7fd79137SRobert Mustacchi } 164*7fd79137SRobert Mustacchi 165*7fd79137SRobert Mustacchi static int 166*7fd79137SRobert Mustacchi ctf_zdata_grow(ctf_zdata_t *czd) 167*7fd79137SRobert Mustacchi { 168*7fd79137SRobert Mustacchi size_t off; 169*7fd79137SRobert Mustacchi size_t newsz; 170*7fd79137SRobert Mustacchi void *ndata; 171*7fd79137SRobert Mustacchi 172*7fd79137SRobert Mustacchi off = (uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf; 173*7fd79137SRobert Mustacchi newsz = czd->czd_allocsz + CTF_COMPRESS_CHUNK; 174*7fd79137SRobert Mustacchi ndata = ctf_data_alloc(newsz); 175*7fd79137SRobert Mustacchi if (ndata == MAP_FAILED) { 176*7fd79137SRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ENOMEM)); 177*7fd79137SRobert Mustacchi } 178*7fd79137SRobert Mustacchi 179*7fd79137SRobert Mustacchi bcopy(czd->czd_buf, ndata, off); 180*7fd79137SRobert Mustacchi ctf_data_free(czd->czd_buf, czd->czd_allocsz); 181*7fd79137SRobert Mustacchi czd->czd_allocsz = newsz; 182*7fd79137SRobert Mustacchi czd->czd_buf = ndata; 183*7fd79137SRobert Mustacchi czd->czd_next = (void *)((uintptr_t)ndata + off); 184*7fd79137SRobert Mustacchi 185*7fd79137SRobert Mustacchi czd->czd_zstr.next_out = (Bytef *)czd->czd_next; 186*7fd79137SRobert Mustacchi czd->czd_zstr.avail_out = CTF_COMPRESS_CHUNK; 187*7fd79137SRobert Mustacchi return (0); 188*7fd79137SRobert Mustacchi } 189*7fd79137SRobert Mustacchi 190*7fd79137SRobert Mustacchi static int 191*7fd79137SRobert Mustacchi ctf_zdata_compress_buffer(ctf_zdata_t *czd, const void *buf, size_t bufsize) 192*7fd79137SRobert Mustacchi { 193*7fd79137SRobert Mustacchi int err; 194*7fd79137SRobert Mustacchi 195*7fd79137SRobert Mustacchi czd->czd_zstr.next_out = czd->czd_next; 196*7fd79137SRobert Mustacchi czd->czd_zstr.avail_out = czd->czd_allocsz - 197*7fd79137SRobert Mustacchi ((uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf); 198*7fd79137SRobert Mustacchi czd->czd_zstr.next_in = (Bytef *)buf; 199*7fd79137SRobert Mustacchi czd->czd_zstr.avail_in = bufsize; 200*7fd79137SRobert Mustacchi 201*7fd79137SRobert Mustacchi while (czd->czd_zstr.avail_in != 0) { 202*7fd79137SRobert Mustacchi if (czd->czd_zstr.avail_out == 0) { 203*7fd79137SRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out; 204*7fd79137SRobert Mustacchi if ((err = ctf_zdata_grow(czd)) != 0) { 205*7fd79137SRobert Mustacchi return (err); 206*7fd79137SRobert Mustacchi } 207*7fd79137SRobert Mustacchi } 208*7fd79137SRobert Mustacchi 209*7fd79137SRobert Mustacchi if ((err = zlib.z_compress(&czd->czd_zstr, Z_NO_FLUSH)) != Z_OK) 210*7fd79137SRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB)); 211*7fd79137SRobert Mustacchi } 212*7fd79137SRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out; 213*7fd79137SRobert Mustacchi 214*7fd79137SRobert Mustacchi return (0); 215*7fd79137SRobert Mustacchi } 216*7fd79137SRobert Mustacchi 217*7fd79137SRobert Mustacchi static int 218*7fd79137SRobert Mustacchi ctf_zdata_flush(ctf_zdata_t *czd, boolean_t finish) 219*7fd79137SRobert Mustacchi { 220*7fd79137SRobert Mustacchi int err; 221*7fd79137SRobert Mustacchi int flag = finish == B_TRUE ? Z_FINISH : Z_FULL_FLUSH; 222*7fd79137SRobert Mustacchi int bret = finish == B_TRUE ? Z_STREAM_END : Z_BUF_ERROR; 223*7fd79137SRobert Mustacchi 224*7fd79137SRobert Mustacchi for (;;) { 225*7fd79137SRobert Mustacchi if (czd->czd_zstr.avail_out == 0) { 226*7fd79137SRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out; 227*7fd79137SRobert Mustacchi if ((err = ctf_zdata_grow(czd)) != 0) { 228*7fd79137SRobert Mustacchi return (err); 229*7fd79137SRobert Mustacchi } 230*7fd79137SRobert Mustacchi } 231*7fd79137SRobert Mustacchi 232*7fd79137SRobert Mustacchi err = zlib.z_compress(&czd->czd_zstr, flag); 233*7fd79137SRobert Mustacchi if (err == bret) { 234*7fd79137SRobert Mustacchi break; 235*7fd79137SRobert Mustacchi } 236*7fd79137SRobert Mustacchi if (err != Z_OK) 237*7fd79137SRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB)); 238*7fd79137SRobert Mustacchi 239*7fd79137SRobert Mustacchi } 240*7fd79137SRobert Mustacchi 241*7fd79137SRobert Mustacchi czd->czd_next = czd->czd_zstr.next_out; 242*7fd79137SRobert Mustacchi 243*7fd79137SRobert Mustacchi return (0); 244*7fd79137SRobert Mustacchi } 245*7fd79137SRobert Mustacchi 246*7fd79137SRobert Mustacchi static int 247*7fd79137SRobert Mustacchi ctf_zdata_end(ctf_zdata_t *czd) 248*7fd79137SRobert Mustacchi { 249*7fd79137SRobert Mustacchi int ret; 250*7fd79137SRobert Mustacchi 251*7fd79137SRobert Mustacchi if ((ret = ctf_zdata_flush(czd, B_TRUE)) != 0) 252*7fd79137SRobert Mustacchi return (ret); 253*7fd79137SRobert Mustacchi 254*7fd79137SRobert Mustacchi if ((ret = zlib.z_finicomp(&czd->czd_zstr)) != 0) 255*7fd79137SRobert Mustacchi return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB)); 256*7fd79137SRobert Mustacchi 257*7fd79137SRobert Mustacchi return (0); 258*7fd79137SRobert Mustacchi } 259*7fd79137SRobert Mustacchi 260*7fd79137SRobert Mustacchi static void 261*7fd79137SRobert Mustacchi ctf_zdata_cleanup(ctf_zdata_t *czd) 262*7fd79137SRobert Mustacchi { 263*7fd79137SRobert Mustacchi ctf_data_free(czd->czd_buf, czd->czd_allocsz); 264*7fd79137SRobert Mustacchi (void) zlib.z_finicomp(&czd->czd_zstr); 265*7fd79137SRobert Mustacchi } 266*7fd79137SRobert Mustacchi 267*7fd79137SRobert Mustacchi /* 268*7fd79137SRobert Mustacchi * Compress our CTF data and return both the size of the compressed data and the 269*7fd79137SRobert Mustacchi * size of the allocation. These may be different due to the nature of 270*7fd79137SRobert Mustacchi * compression. 271*7fd79137SRobert Mustacchi * 272*7fd79137SRobert Mustacchi * In addition, we flush the compression between our two phases such that we 273*7fd79137SRobert Mustacchi * maintain a different dictionary between the CTF data and the string section. 274*7fd79137SRobert Mustacchi */ 275*7fd79137SRobert Mustacchi int 276*7fd79137SRobert Mustacchi ctf_compress(ctf_file_t *fp, void **buf, size_t *allocsz, size_t *elfsize) 277*7fd79137SRobert Mustacchi { 278*7fd79137SRobert Mustacchi int err; 279*7fd79137SRobert Mustacchi ctf_zdata_t czd; 280*7fd79137SRobert Mustacchi ctf_header_t *cthp = (ctf_header_t *)fp->ctf_base; 281*7fd79137SRobert Mustacchi 282*7fd79137SRobert Mustacchi if ((err = ctf_zdata_init(&czd, fp)) != 0) 283*7fd79137SRobert Mustacchi return (err); 284*7fd79137SRobert Mustacchi 285*7fd79137SRobert Mustacchi if ((err = ctf_zdata_compress_buffer(&czd, fp->ctf_buf, 286*7fd79137SRobert Mustacchi cthp->cth_stroff)) != 0) { 287*7fd79137SRobert Mustacchi ctf_zdata_cleanup(&czd); 288*7fd79137SRobert Mustacchi return (err); 289*7fd79137SRobert Mustacchi } 290*7fd79137SRobert Mustacchi 291*7fd79137SRobert Mustacchi if ((err = ctf_zdata_flush(&czd, B_FALSE)) != 0) { 292*7fd79137SRobert Mustacchi ctf_zdata_cleanup(&czd); 293*7fd79137SRobert Mustacchi return (err); 294*7fd79137SRobert Mustacchi } 295*7fd79137SRobert Mustacchi 296*7fd79137SRobert Mustacchi if ((err = ctf_zdata_compress_buffer(&czd, 297*7fd79137SRobert Mustacchi fp->ctf_buf + cthp->cth_stroff, cthp->cth_strlen)) != 0) { 298*7fd79137SRobert Mustacchi ctf_zdata_cleanup(&czd); 299*7fd79137SRobert Mustacchi return (err); 300*7fd79137SRobert Mustacchi } 301*7fd79137SRobert Mustacchi 302*7fd79137SRobert Mustacchi if ((err = ctf_zdata_end(&czd)) != 0) { 303*7fd79137SRobert Mustacchi ctf_zdata_cleanup(&czd); 304*7fd79137SRobert Mustacchi return (err); 305*7fd79137SRobert Mustacchi } 306*7fd79137SRobert Mustacchi 307*7fd79137SRobert Mustacchi *buf = czd.czd_buf; 308*7fd79137SRobert Mustacchi *allocsz = czd.czd_allocsz; 309*7fd79137SRobert Mustacchi *elfsize = (uintptr_t)czd.czd_next - (uintptr_t)czd.czd_buf; 310*7fd79137SRobert Mustacchi 311*7fd79137SRobert Mustacchi return (0); 312*7fd79137SRobert Mustacchi } 313*7fd79137SRobert Mustacchi 314*7fd79137SRobert Mustacchi int 315*7fd79137SRobert Mustacchi z_compress(void *dst, size_t *dstlen, const void *src, size_t srclen) 316*7fd79137SRobert Mustacchi { 317*7fd79137SRobert Mustacchi z_stream zs; 318*7fd79137SRobert Mustacchi int err; 319*7fd79137SRobert Mustacchi 320*7fd79137SRobert Mustacchi bzero(&zs, sizeof (z_stream)); 321*7fd79137SRobert Mustacchi zs.next_in = (uchar_t *)src; 322*7fd79137SRobert Mustacchi zs.avail_in = srclen; 323*7fd79137SRobert Mustacchi zs.next_out = dst; 324*7fd79137SRobert Mustacchi zs.avail_out = *dstlen; 325*7fd79137SRobert Mustacchi 326*7fd79137SRobert Mustacchi if ((err = zlib.z_initcomp(&zs, Z_BEST_COMPRESSION, ZLIB_VERSION, 327*7fd79137SRobert Mustacchi sizeof (z_stream))) != Z_OK) 328*7fd79137SRobert Mustacchi return (err); 329*7fd79137SRobert Mustacchi 330*7fd79137SRobert Mustacchi if ((err = zlib.z_compress(&zs, Z_FINISH)) != Z_STREAM_END) { 331*7fd79137SRobert Mustacchi (void) zlib.z_finicomp(&zs); 332*7fd79137SRobert Mustacchi return (err == Z_OK ? Z_BUF_ERROR : err); 333*7fd79137SRobert Mustacchi } 334*7fd79137SRobert Mustacchi 335*7fd79137SRobert Mustacchi *dstlen = zs.total_out; 336*7fd79137SRobert Mustacchi return (zlib.z_finicomp(&zs)); 337*7fd79137SRobert Mustacchi } 338*7fd79137SRobert Mustacchi 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * Convert a 32-bit ELF file header into GElf. 3417c478bd9Sstevel@tonic-gate */ 3427c478bd9Sstevel@tonic-gate static void 3437c478bd9Sstevel@tonic-gate ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst) 3447c478bd9Sstevel@tonic-gate { 3457c478bd9Sstevel@tonic-gate bcopy(src->e_ident, dst->e_ident, EI_NIDENT); 3467c478bd9Sstevel@tonic-gate dst->e_type = src->e_type; 3477c478bd9Sstevel@tonic-gate dst->e_machine = src->e_machine; 3487c478bd9Sstevel@tonic-gate dst->e_version = src->e_version; 3497c478bd9Sstevel@tonic-gate dst->e_entry = (Elf64_Addr)src->e_entry; 3507c478bd9Sstevel@tonic-gate dst->e_phoff = (Elf64_Off)src->e_phoff; 3517c478bd9Sstevel@tonic-gate dst->e_shoff = (Elf64_Off)src->e_shoff; 3527c478bd9Sstevel@tonic-gate dst->e_flags = src->e_flags; 3537c478bd9Sstevel@tonic-gate dst->e_ehsize = src->e_ehsize; 3547c478bd9Sstevel@tonic-gate dst->e_phentsize = src->e_phentsize; 3557c478bd9Sstevel@tonic-gate dst->e_phnum = src->e_phnum; 3567c478bd9Sstevel@tonic-gate dst->e_shentsize = src->e_shentsize; 3577c478bd9Sstevel@tonic-gate dst->e_shnum = src->e_shnum; 3587c478bd9Sstevel@tonic-gate dst->e_shstrndx = src->e_shstrndx; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * Convert a 32-bit ELF section header into GElf. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate static void 3657c478bd9Sstevel@tonic-gate shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate dst->sh_name = src->sh_name; 3687c478bd9Sstevel@tonic-gate dst->sh_type = src->sh_type; 3697c478bd9Sstevel@tonic-gate dst->sh_flags = src->sh_flags; 3707c478bd9Sstevel@tonic-gate dst->sh_addr = src->sh_addr; 3717c478bd9Sstevel@tonic-gate dst->sh_offset = src->sh_offset; 3727c478bd9Sstevel@tonic-gate dst->sh_size = src->sh_size; 3737c478bd9Sstevel@tonic-gate dst->sh_link = src->sh_link; 3747c478bd9Sstevel@tonic-gate dst->sh_info = src->sh_info; 3757c478bd9Sstevel@tonic-gate dst->sh_addralign = src->sh_addralign; 3767c478bd9Sstevel@tonic-gate dst->sh_entsize = src->sh_entsize; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * In order to mmap a section from the ELF file, we must round down sh_offset 3817c478bd9Sstevel@tonic-gate * to the previous page boundary, and mmap the surrounding page. We store 3827c478bd9Sstevel@tonic-gate * the pointer to the start of the actual section data back into sp->cts_data. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate const void * 3857c478bd9Sstevel@tonic-gate ctf_sect_mmap(ctf_sect_t *sp, int fd) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate size_t pageoff = sp->cts_offset & ~_PAGEMASK; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ, 3907c478bd9Sstevel@tonic-gate MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK); 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate if (base != MAP_FAILED) 3937c478bd9Sstevel@tonic-gate sp->cts_data = base + pageoff; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate return (base); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* 3997c478bd9Sstevel@tonic-gate * Since sp->cts_data has the adjusted offset, we have to again round down 4007c478bd9Sstevel@tonic-gate * to get the actual mmap address and round up to get the size. 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate void 4037c478bd9Sstevel@tonic-gate ctf_sect_munmap(const ctf_sect_t *sp) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate uintptr_t addr = (uintptr_t)sp->cts_data; 4067c478bd9Sstevel@tonic-gate uintptr_t pageoff = addr & ~_PAGEMASK; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate (void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * Open the specified file descriptor and return a pointer to a CTF container. 4137c478bd9Sstevel@tonic-gate * The file can be either an ELF file or raw CTF file. The caller is 4147c478bd9Sstevel@tonic-gate * responsible for closing the file descriptor when it is no longer needed. 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate ctf_file_t * 417*7fd79137SRobert Mustacchi ctf_fdcreate_int(int fd, int *errp, ctf_sect_t *ctfp) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate ctf_sect_t ctfsect, symsect, strsect; 4207c478bd9Sstevel@tonic-gate ctf_file_t *fp = NULL; 421c894effdSRichard Lowe size_t shstrndx, shnum; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate struct stat64 st; 4247c478bd9Sstevel@tonic-gate ssize_t nbytes; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate union { 4277c478bd9Sstevel@tonic-gate ctf_preamble_t ctf; 4287c478bd9Sstevel@tonic-gate Elf32_Ehdr e32; 4297c478bd9Sstevel@tonic-gate GElf_Ehdr e64; 4307c478bd9Sstevel@tonic-gate } hdr; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate bzero(&ctfsect, sizeof (ctf_sect_t)); 4337c478bd9Sstevel@tonic-gate bzero(&symsect, sizeof (ctf_sect_t)); 4347c478bd9Sstevel@tonic-gate bzero(&strsect, sizeof (ctf_sect_t)); 4357c478bd9Sstevel@tonic-gate bzero(&hdr.ctf, sizeof (hdr)); 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate if (fstat64(fd, &st) == -1) 4387c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno)); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0) 4417c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT)); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * If we have read enough bytes to form a CTF header and the magic 4457c478bd9Sstevel@tonic-gate * string matches, attempt to interpret the file as raw CTF. 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate if (nbytes >= sizeof (ctf_preamble_t) && 4487c478bd9Sstevel@tonic-gate hdr.ctf.ctp_magic == CTF_MAGIC) { 449*7fd79137SRobert Mustacchi if (ctfp != NULL) 450*7fd79137SRobert Mustacchi return (ctf_set_open_errno(errp, EINVAL)); 451*7fd79137SRobert Mustacchi 4527c478bd9Sstevel@tonic-gate if (hdr.ctf.ctp_version > CTF_VERSION) 4537c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_CTFVERS)); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ, 4567c478bd9Sstevel@tonic-gate MAP_PRIVATE, fd, 0); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate if (ctfsect.cts_data == MAP_FAILED) 4597c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno)); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate ctfsect.cts_name = _CTF_SECTION; 4627c478bd9Sstevel@tonic-gate ctfsect.cts_type = SHT_PROGBITS; 4637c478bd9Sstevel@tonic-gate ctfsect.cts_flags = SHF_ALLOC; 4647c478bd9Sstevel@tonic-gate ctfsect.cts_size = (size_t)st.st_size; 4657c478bd9Sstevel@tonic-gate ctfsect.cts_entsize = 1; 4667c478bd9Sstevel@tonic-gate ctfsect.cts_offset = 0; 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL) 4697c478bd9Sstevel@tonic-gate ctf_sect_munmap(&ctfsect); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate return (fp); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * If we have read enough bytes to form an ELF header and the magic 4767c478bd9Sstevel@tonic-gate * string matches, attempt to interpret the file as an ELF file. We 4777c478bd9Sstevel@tonic-gate * do our own largefile ELF processing, and convert everything to 4787c478bd9Sstevel@tonic-gate * GElf structures so that clients can operate on any data model. 4797c478bd9Sstevel@tonic-gate */ 4807c478bd9Sstevel@tonic-gate if (nbytes >= sizeof (Elf32_Ehdr) && 4817c478bd9Sstevel@tonic-gate bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) { 4827c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 4837c478bd9Sstevel@tonic-gate uchar_t order = ELFDATA2MSB; 4847c478bd9Sstevel@tonic-gate #else 4857c478bd9Sstevel@tonic-gate uchar_t order = ELFDATA2LSB; 4867c478bd9Sstevel@tonic-gate #endif 4877c478bd9Sstevel@tonic-gate GElf_Shdr *sp; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate void *strs_map; 490c894effdSRichard Lowe size_t strs_mapsz, i; 4917c478bd9Sstevel@tonic-gate const char *strs; 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate if (hdr.e32.e_ident[EI_DATA] != order) 4947c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ENDIAN)); 4957c478bd9Sstevel@tonic-gate if (hdr.e32.e_version != EV_CURRENT) 4967c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_ELFVERS)); 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) { 4997c478bd9Sstevel@tonic-gate if (nbytes < sizeof (GElf_Ehdr)) 5007c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_FMT)); 5017c478bd9Sstevel@tonic-gate } else { 5027c478bd9Sstevel@tonic-gate Elf32_Ehdr e32 = hdr.e32; 5037c478bd9Sstevel@tonic-gate ehdr_to_gelf(&e32, &hdr.e64); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 506c894effdSRichard Lowe shnum = hdr.e64.e_shnum; 507c894effdSRichard Lowe shstrndx = hdr.e64.e_shstrndx; 508c894effdSRichard Lowe 509c894effdSRichard Lowe /* Extended ELF sections */ 510c894effdSRichard Lowe if ((shstrndx == SHN_XINDEX) || (shnum == 0)) { 511c894effdSRichard Lowe if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { 512c894effdSRichard Lowe Elf32_Shdr x32; 513c894effdSRichard Lowe 514c894effdSRichard Lowe if (pread64(fd, &x32, sizeof (x32), 515c894effdSRichard Lowe hdr.e64.e_shoff) != sizeof (x32)) 516c894effdSRichard Lowe return (ctf_set_open_errno(errp, 517c894effdSRichard Lowe errno)); 518c894effdSRichard Lowe 519c894effdSRichard Lowe shnum = x32.sh_size; 520c894effdSRichard Lowe shstrndx = x32.sh_link; 521c894effdSRichard Lowe } else { 522c894effdSRichard Lowe Elf64_Shdr x64; 523c894effdSRichard Lowe 524c894effdSRichard Lowe if (pread64(fd, &x64, sizeof (x64), 525c894effdSRichard Lowe hdr.e64.e_shoff) != sizeof (x64)) 526c894effdSRichard Lowe return (ctf_set_open_errno(errp, 527c894effdSRichard Lowe errno)); 528c894effdSRichard Lowe 529c894effdSRichard Lowe shnum = x64.sh_size; 530c894effdSRichard Lowe shstrndx = x64.sh_link; 531c894effdSRichard Lowe } 532c894effdSRichard Lowe } 533c894effdSRichard Lowe 534c894effdSRichard Lowe if (shstrndx >= shnum) 5357c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_CORRUPT)); 5367c478bd9Sstevel@tonic-gate 537c894effdSRichard Lowe nbytes = sizeof (GElf_Shdr) * shnum; 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate if ((sp = malloc(nbytes)) == NULL) 5407c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno)); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* 5437c478bd9Sstevel@tonic-gate * Read in and convert to GElf the array of Shdr structures 5447c478bd9Sstevel@tonic-gate * from e_shoff so we can locate sections of interest. 5457c478bd9Sstevel@tonic-gate */ 5467c478bd9Sstevel@tonic-gate if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { 5477c478bd9Sstevel@tonic-gate Elf32_Shdr *sp32; 5487c478bd9Sstevel@tonic-gate 549c894effdSRichard Lowe nbytes = sizeof (Elf32_Shdr) * shnum; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if ((sp32 = malloc(nbytes)) == NULL || pread64(fd, 5527c478bd9Sstevel@tonic-gate sp32, nbytes, hdr.e64.e_shoff) != nbytes) { 5537c478bd9Sstevel@tonic-gate free(sp); 5547c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno)); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 557c894effdSRichard Lowe for (i = 0; i < shnum; i++) 5587c478bd9Sstevel@tonic-gate shdr_to_gelf(&sp32[i], &sp[i]); 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate free(sp32); 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) { 5637c478bd9Sstevel@tonic-gate free(sp); 5647c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, errno)); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * Now mmap the section header strings section so that we can 5697c478bd9Sstevel@tonic-gate * perform string comparison on the section names. 5707c478bd9Sstevel@tonic-gate */ 571c894effdSRichard Lowe strs_mapsz = sp[shstrndx].sh_size + 572c894effdSRichard Lowe (sp[shstrndx].sh_offset & ~_PAGEMASK); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE, 575c894effdSRichard Lowe fd, sp[shstrndx].sh_offset & _PAGEMASK); 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate strs = (const char *)strs_map + 578c894effdSRichard Lowe (sp[shstrndx].sh_offset & ~_PAGEMASK); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate if (strs_map == MAP_FAILED) { 5817c478bd9Sstevel@tonic-gate free(sp); 5827c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_MMAP)); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * Iterate over the section header array looking for the CTF 5877c478bd9Sstevel@tonic-gate * section and symbol table. The strtab is linked to symtab. 5887c478bd9Sstevel@tonic-gate */ 589c894effdSRichard Lowe for (i = 0; i < shnum; i++) { 5907c478bd9Sstevel@tonic-gate const GElf_Shdr *shp = &sp[i]; 5917c478bd9Sstevel@tonic-gate const GElf_Shdr *lhp = &sp[shp->sh_link]; 5927c478bd9Sstevel@tonic-gate 593c894effdSRichard Lowe if (shp->sh_link >= shnum) 5947c478bd9Sstevel@tonic-gate continue; /* corrupt sh_link field */ 5957c478bd9Sstevel@tonic-gate 596c894effdSRichard Lowe if (shp->sh_name >= sp[shstrndx].sh_size || 597c894effdSRichard Lowe lhp->sh_name >= sp[shstrndx].sh_size) 5987c478bd9Sstevel@tonic-gate continue; /* corrupt sh_name field */ 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate if (shp->sh_type == SHT_PROGBITS && 601*7fd79137SRobert Mustacchi strcmp(strs + shp->sh_name, _CTF_SECTION) == 0 && 602*7fd79137SRobert Mustacchi ctfp == NULL) { 6037c478bd9Sstevel@tonic-gate ctfsect.cts_name = strs + shp->sh_name; 6047c478bd9Sstevel@tonic-gate ctfsect.cts_type = shp->sh_type; 6057c478bd9Sstevel@tonic-gate ctfsect.cts_flags = shp->sh_flags; 6067c478bd9Sstevel@tonic-gate ctfsect.cts_size = shp->sh_size; 6077c478bd9Sstevel@tonic-gate ctfsect.cts_entsize = shp->sh_entsize; 6087c478bd9Sstevel@tonic-gate ctfsect.cts_offset = (off64_t)shp->sh_offset; 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate } else if (shp->sh_type == SHT_SYMTAB) { 6117c478bd9Sstevel@tonic-gate symsect.cts_name = strs + shp->sh_name; 6127c478bd9Sstevel@tonic-gate symsect.cts_type = shp->sh_type; 6137c478bd9Sstevel@tonic-gate symsect.cts_flags = shp->sh_flags; 6147c478bd9Sstevel@tonic-gate symsect.cts_size = shp->sh_size; 6157c478bd9Sstevel@tonic-gate symsect.cts_entsize = shp->sh_entsize; 6167c478bd9Sstevel@tonic-gate symsect.cts_offset = (off64_t)shp->sh_offset; 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate strsect.cts_name = strs + lhp->sh_name; 6197c478bd9Sstevel@tonic-gate strsect.cts_type = lhp->sh_type; 6207c478bd9Sstevel@tonic-gate strsect.cts_flags = lhp->sh_flags; 6217c478bd9Sstevel@tonic-gate strsect.cts_size = lhp->sh_size; 6227c478bd9Sstevel@tonic-gate strsect.cts_entsize = lhp->sh_entsize; 6237c478bd9Sstevel@tonic-gate strsect.cts_offset = (off64_t)lhp->sh_offset; 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate free(sp); /* free section header array */ 6287c478bd9Sstevel@tonic-gate 629*7fd79137SRobert Mustacchi if (ctfp == NULL) { 630*7fd79137SRobert Mustacchi if (ctfsect.cts_type == SHT_NULL && ctfp == NULL) { 6317c478bd9Sstevel@tonic-gate (void) munmap(strs_map, strs_mapsz); 632*7fd79137SRobert Mustacchi return (ctf_set_open_errno(errp, 633*7fd79137SRobert Mustacchi ECTF_NOCTFDATA)); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate /* 637*7fd79137SRobert Mustacchi * Now mmap the CTF data, symtab, and strtab sections 638*7fd79137SRobert Mustacchi * and call ctf_bufopen() to do the rest of the work. 6397c478bd9Sstevel@tonic-gate */ 6407c478bd9Sstevel@tonic-gate if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) { 6417c478bd9Sstevel@tonic-gate (void) munmap(strs_map, strs_mapsz); 6427c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_MMAP)); 6437c478bd9Sstevel@tonic-gate } 644*7fd79137SRobert Mustacchi ctfp = &ctfsect; 645*7fd79137SRobert Mustacchi } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate if (symsect.cts_type != SHT_NULL && 6487c478bd9Sstevel@tonic-gate strsect.cts_type != SHT_NULL) { 6497c478bd9Sstevel@tonic-gate if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED || 6507c478bd9Sstevel@tonic-gate ctf_sect_mmap(&strsect, fd) == MAP_FAILED) { 6517c478bd9Sstevel@tonic-gate (void) ctf_set_open_errno(errp, ECTF_MMAP); 6527c478bd9Sstevel@tonic-gate goto bad; /* unmap all and abort */ 6537c478bd9Sstevel@tonic-gate } 654*7fd79137SRobert Mustacchi fp = ctf_bufopen(ctfp, &symsect, &strsect, errp); 6557c478bd9Sstevel@tonic-gate } else 656*7fd79137SRobert Mustacchi fp = ctf_bufopen(ctfp, NULL, NULL, errp); 6577c478bd9Sstevel@tonic-gate bad: 6587c478bd9Sstevel@tonic-gate if (fp == NULL) { 659*7fd79137SRobert Mustacchi if (ctfp == NULL) 6607c478bd9Sstevel@tonic-gate ctf_sect_munmap(&ctfsect); 6617c478bd9Sstevel@tonic-gate ctf_sect_munmap(&symsect); 6627c478bd9Sstevel@tonic-gate ctf_sect_munmap(&strsect); 6637c478bd9Sstevel@tonic-gate } else 6647c478bd9Sstevel@tonic-gate fp->ctf_flags |= LCTF_MMAP; 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate (void) munmap(strs_map, strs_mapsz); 6677c478bd9Sstevel@tonic-gate return (fp); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate return (ctf_set_open_errno(errp, ECTF_FMT)); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 673*7fd79137SRobert Mustacchi ctf_file_t * 674*7fd79137SRobert Mustacchi ctf_fdopen(int fd, int *errp) 675*7fd79137SRobert Mustacchi { 676*7fd79137SRobert Mustacchi return (ctf_fdcreate_int(fd, errp, NULL)); 677*7fd79137SRobert Mustacchi } 678*7fd79137SRobert Mustacchi 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * Open the specified file and return a pointer to a CTF container. The file 6817c478bd9Sstevel@tonic-gate * can be either an ELF file or raw CTF file. This is just a convenient 6827c478bd9Sstevel@tonic-gate * wrapper around ctf_fdopen() for callers. 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate ctf_file_t * 6857c478bd9Sstevel@tonic-gate ctf_open(const char *filename, int *errp) 6867c478bd9Sstevel@tonic-gate { 6877c478bd9Sstevel@tonic-gate ctf_file_t *fp; 6887c478bd9Sstevel@tonic-gate int fd; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate if ((fd = open64(filename, O_RDONLY)) == -1) { 6917c478bd9Sstevel@tonic-gate if (errp != NULL) 6927c478bd9Sstevel@tonic-gate *errp = errno; 6937c478bd9Sstevel@tonic-gate return (NULL); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate fp = ctf_fdopen(fd, errp); 6977c478bd9Sstevel@tonic-gate (void) close(fd); 6987c478bd9Sstevel@tonic-gate return (fp); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Write the uncompressed CTF data stream to the specified file descriptor. 7037c478bd9Sstevel@tonic-gate * This is useful for saving the results of dynamic CTF containers. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate int 7067c478bd9Sstevel@tonic-gate ctf_write(ctf_file_t *fp, int fd) 7077c478bd9Sstevel@tonic-gate { 7087c478bd9Sstevel@tonic-gate const uchar_t *buf = fp->ctf_base; 7097c478bd9Sstevel@tonic-gate ssize_t resid = fp->ctf_size; 7107c478bd9Sstevel@tonic-gate ssize_t len; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate while (resid != 0) { 7137c478bd9Sstevel@tonic-gate if ((len = write(fd, buf, resid)) <= 0) 7147c478bd9Sstevel@tonic-gate return (ctf_set_errno(fp, errno)); 7157c478bd9Sstevel@tonic-gate resid -= len; 7167c478bd9Sstevel@tonic-gate buf += len; 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate return (0); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * Set the CTF library client version to the specified version. If version is 7247c478bd9Sstevel@tonic-gate * zero, we just return the default library version number. 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate int 7277c478bd9Sstevel@tonic-gate ctf_version(int version) 7287c478bd9Sstevel@tonic-gate { 7297c478bd9Sstevel@tonic-gate if (version < 0) { 7307c478bd9Sstevel@tonic-gate errno = EINVAL; 7317c478bd9Sstevel@tonic-gate return (-1); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate if (version > 0) { 7357c478bd9Sstevel@tonic-gate if (version > CTF_VERSION) { 7367c478bd9Sstevel@tonic-gate errno = ENOTSUP; 7377c478bd9Sstevel@tonic-gate return (-1); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate ctf_dprintf("ctf_version: client using version %d\n", version); 7407c478bd9Sstevel@tonic-gate _libctf_version = version; 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate return (_libctf_version); 7447c478bd9Sstevel@tonic-gate } 745*7fd79137SRobert Mustacchi 746*7fd79137SRobert Mustacchi /* 747*7fd79137SRobert Mustacchi * A utility function for folks debugging CTF conversion and merging. 748*7fd79137SRobert Mustacchi */ 749*7fd79137SRobert Mustacchi void 750*7fd79137SRobert Mustacchi ctf_phase_dump(ctf_file_t *fp, const char *phase) 751*7fd79137SRobert Mustacchi { 752*7fd79137SRobert Mustacchi int fd; 753*7fd79137SRobert Mustacchi static char *base; 754*7fd79137SRobert Mustacchi char path[MAXPATHLEN]; 755*7fd79137SRobert Mustacchi 756*7fd79137SRobert Mustacchi if (base == NULL && (base = getenv("LIBCTF_WRITE_PHASES")) == NULL) 757*7fd79137SRobert Mustacchi return; 758*7fd79137SRobert Mustacchi 759*7fd79137SRobert Mustacchi (void) snprintf(path, sizeof (path), "%s/libctf.%s.%d.ctf", base, 760*7fd79137SRobert Mustacchi phase != NULL ? phase : "", 761*7fd79137SRobert Mustacchi ctf_phase); 762*7fd79137SRobert Mustacchi if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0) 763*7fd79137SRobert Mustacchi return; 764*7fd79137SRobert Mustacchi (void) ctf_write(fp, fd); 765*7fd79137SRobert Mustacchi (void) close(fd); 766*7fd79137SRobert Mustacchi } 767