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