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