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