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