Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/cddl/contrib/opensolaris/tools/ctf/dump/dump.c
39562 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 2004 Sun Microsystems, Inc. All rights reserved.
24
* Use is subject to license terms.
25
*/
26
27
#include <sys/types.h>
28
#include <sys/sysmacros.h>
29
#include <sys/stat.h>
30
#include <sys/mman.h>
31
32
#include <err.h>
33
#include <strings.h>
34
#include <unistd.h>
35
#include <stdlib.h>
36
#include <stdio.h>
37
#include <fcntl.h>
38
#include <gelf.h>
39
#include <zlib.h>
40
41
#include "ctf_headers.h"
42
#include "utils.h"
43
#include "symbol.h"
44
45
#define WARN(x) { warn(x); return (E_ERROR); }
46
47
/*
48
* Flags that indicate what data is to be displayed. An explicit `all' value is
49
* provided to allow the code to distinguish between a request for everything
50
* (currently requested by invoking ctfdump without flags) and individual
51
* requests for all of the types of data (an invocation with all flags). In the
52
* former case, we want to be able to implicitly adjust the definition of `all'
53
* based on the CTF version of the file being dumped. For example, if a v2 file
54
* is being dumped, `all' includes F_LABEL - a request to dump the label
55
* section. If a v1 file is being dumped, `all' does not include F_LABEL,
56
* because v1 CTF doesn't support labels. We need to be able to distinguish
57
* between `ctfdump foo', which has an implicit request for labels if `foo'
58
* supports them, and `ctfdump -l foo', which has an explicity request. In the
59
* latter case, we exit with an error if `foo' is a v1 CTF file.
60
*/
61
static enum {
62
F_DATA = 0x01, /* show data object section */
63
F_FUNC = 0x02, /* show function section */
64
F_HDR = 0x04, /* show header */
65
F_STR = 0x08, /* show string table */
66
F_TYPES = 0x10, /* show type section */
67
F_STATS = 0x20, /* show statistics */
68
F_LABEL = 0x40, /* show label section */
69
F_ALL = 0x80, /* explicit request for `all' */
70
F_ALLMSK = 0xff /* show all sections and statistics */
71
} flags = 0;
72
73
static struct {
74
ulong_t s_ndata; /* total number of data objects */
75
ulong_t s_nfunc; /* total number of functions */
76
ulong_t s_nargs; /* total number of function arguments */
77
ulong_t s_argmax; /* longest argument list */
78
ulong_t s_ntypes; /* total number of types */
79
ulong_t s_types[16]; /* number of types by kind */
80
ulong_t s_nsmem; /* total number of struct members */
81
ulong_t s_nsbytes; /* total size of all structs */
82
ulong_t s_smmax; /* largest struct in terms of members */
83
ulong_t s_sbmax; /* largest struct in terms of bytes */
84
ulong_t s_numem; /* total number of union members */
85
ulong_t s_nubytes; /* total size of all unions */
86
ulong_t s_ummax; /* largest union in terms of members */
87
ulong_t s_ubmax; /* largest union in terms of bytes */
88
ulong_t s_nemem; /* total number of enum members */
89
ulong_t s_emmax; /* largest enum in terms of members */
90
ulong_t s_nstr; /* total number of strings */
91
size_t s_strlen; /* total length of all strings */
92
size_t s_strmax; /* longest string length */
93
} stats;
94
95
typedef struct ctf_data {
96
caddr_t cd_ctfdata; /* Pointer to the CTF data */
97
size_t cd_ctflen; /* Length of CTF data */
98
99
size_t cd_idwidth; /* Size of a type ID, in bytes */
100
101
/*
102
* cd_symdata will be non-NULL if the CTF data is being retrieved from
103
* an ELF file with a symbol table. cd_strdata and cd_nsyms should be
104
* used only if cd_symdata is non-NULL.
105
*/
106
Elf_Data *cd_symdata; /* Symbol table */
107
Elf_Data *cd_strdata; /* Symbol table strings */
108
int cd_nsyms; /* Number of symbol table entries */
109
} ctf_data_t;
110
111
static const char *
112
ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd)
113
{
114
size_t offset = CTF_NAME_OFFSET(name);
115
const char *s = cd->cd_ctfdata + hp->cth_stroff + offset;
116
117
if (CTF_NAME_STID(name) != CTF_STRTAB_0)
118
return ("<< ??? - name in external strtab >>");
119
120
if (offset >= hp->cth_strlen)
121
return ("<< ??? - name exceeds strlab len >>");
122
123
if (hp->cth_stroff + offset >= cd->cd_ctflen)
124
return ("<< ??? - file truncated >>");
125
126
if (s[0] == '\0')
127
return ("(anon)");
128
129
return (s);
130
}
131
132
static const char *
133
int_encoding_to_str(uint_t encoding)
134
{
135
static char buf[32];
136
137
if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR |
138
CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)
139
(void) snprintf(buf, sizeof (buf), " 0x%x", encoding);
140
else {
141
buf[0] = '\0';
142
if (encoding & CTF_INT_SIGNED)
143
(void) strcat(buf, " SIGNED");
144
if (encoding & CTF_INT_CHAR)
145
(void) strcat(buf, " CHAR");
146
if (encoding & CTF_INT_BOOL)
147
(void) strcat(buf, " BOOL");
148
if (encoding & CTF_INT_VARARGS)
149
(void) strcat(buf, " VARARGS");
150
}
151
152
return (buf + 1);
153
}
154
155
static const char *
156
fp_encoding_to_str(uint_t encoding)
157
{
158
static const char *const encs[] = {
159
NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",
160
"LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
161
"DIMAGINARY", "LDIMAGINARY"
162
};
163
164
static char buf[16];
165
166
if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) {
167
(void) snprintf(buf, sizeof (buf), "%u", encoding);
168
return (buf);
169
}
170
171
return (encs[encoding]);
172
}
173
174
static void
175
print_line(const char *s)
176
{
177
static const char line[] = "----------------------------------------"
178
"----------------------------------------";
179
(void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line);
180
}
181
182
static int
183
print_header(const ctf_header_t *hp, const ctf_data_t *cd)
184
{
185
print_line("- CTF Header ");
186
187
(void) printf(" cth_magic = 0x%04x\n", hp->cth_magic);
188
(void) printf(" cth_version = %u\n", hp->cth_version);
189
(void) printf(" cth_flags = 0x%02x\n", hp->cth_flags);
190
(void) printf(" cth_parlabel = %s\n",
191
ref_to_str(hp->cth_parlabel, hp, cd));
192
(void) printf(" cth_parname = %s\n",
193
ref_to_str(hp->cth_parname, hp, cd));
194
(void) printf(" cth_lbloff = %u\n", hp->cth_lbloff);
195
(void) printf(" cth_objtoff = %u\n", hp->cth_objtoff);
196
(void) printf(" cth_funcoff = %u\n", hp->cth_funcoff);
197
(void) printf(" cth_typeoff = %u\n", hp->cth_typeoff);
198
(void) printf(" cth_stroff = %u\n", hp->cth_stroff);
199
(void) printf(" cth_strlen = %u\n", hp->cth_strlen);
200
201
return (E_SUCCESS);
202
}
203
204
static int
205
print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd)
206
{
207
void *v = (void *) (cd->cd_ctfdata + hp->cth_lbloff);
208
const ctf_lblent_t *ctl = v;
209
ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl);
210
211
print_line("- Label Table ");
212
213
if (hp->cth_lbloff & 3)
214
WARN("cth_lbloff is not aligned properly\n");
215
if (hp->cth_lbloff >= cd->cd_ctflen)
216
WARN("file is truncated or cth_lbloff is corrupt\n");
217
if (hp->cth_objtoff >= cd->cd_ctflen)
218
WARN("file is truncated or cth_objtoff is corrupt\n");
219
if (hp->cth_lbloff > hp->cth_objtoff)
220
WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
221
222
for (i = 0; i < n; i++, ctl++) {
223
(void) printf(" %5u %s\n", ctl->ctl_typeidx,
224
ref_to_str(ctl->ctl_label, hp, cd));
225
}
226
227
return (E_SUCCESS);
228
}
229
230
/*
231
* Given the current symbol index (-1 to start at the beginning of the symbol
232
* table) and the type of symbol to match, this function returns the index of
233
* the next matching symbol (if any), and places the name of that symbol in
234
* *namep. If no symbol is found, -1 is returned.
235
*/
236
static int
237
next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
238
char **namep)
239
{
240
int i;
241
242
for (i = symidx + 1; i < cd->cd_nsyms; i++) {
243
GElf_Sym sym;
244
char *name;
245
int type;
246
247
if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)
248
return (-1);
249
250
name = (char *)cd->cd_strdata->d_buf + sym.st_name;
251
type = GELF_ST_TYPE(sym.st_info);
252
253
/*
254
* Skip various types of symbol table entries.
255
*/
256
if (type != matchtype || ignore_symbol(&sym, name))
257
continue;
258
259
/* Found one */
260
*namep = name;
261
return (i);
262
}
263
264
return (-1);
265
}
266
267
static int
268
read_data(const ctf_header_t *hp, const ctf_data_t *cd)
269
{
270
const char *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff);
271
ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / cd->cd_idwidth;
272
273
if (flags != F_STATS)
274
print_line("- Data Objects ");
275
276
if (hp->cth_objtoff & 1)
277
WARN("cth_objtoff is not aligned properly\n");
278
if (hp->cth_objtoff >= cd->cd_ctflen)
279
WARN("file is truncated or cth_objtoff is corrupt\n");
280
if (hp->cth_funcoff >= cd->cd_ctflen)
281
WARN("file is truncated or cth_funcoff is corrupt\n");
282
if (hp->cth_objtoff > hp->cth_funcoff)
283
WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");
284
285
if (flags != F_STATS) {
286
int symidx, len, i;
287
char *name = NULL;
288
289
for (symidx = -1, i = 0; i < (int) n; i++) {
290
uint32_t id = 0;
291
int nextsym;
292
293
if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,
294
symidx, STT_OBJECT, &name)) < 0)
295
name = NULL;
296
else
297
symidx = nextsym;
298
299
memcpy(&id, v, cd->cd_idwidth);
300
v += cd->cd_idwidth;
301
len = printf(" [%u] %u", i, id);
302
if (name != NULL)
303
(void) printf("%*s%s (%u)", (15 - len), "",
304
name, symidx);
305
(void) putchar('\n');
306
}
307
}
308
309
stats.s_ndata = n;
310
return (E_SUCCESS);
311
}
312
313
static int
314
read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)
315
{
316
const char *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff);
317
uint_t f = 0, info;
318
319
const char *end = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
320
321
ulong_t id;
322
int symidx;
323
324
if (flags != F_STATS)
325
print_line("- Functions ");
326
327
if (hp->cth_funcoff & 1)
328
WARN("cth_funcoff is not aligned properly\n");
329
if (hp->cth_funcoff >= cd->cd_ctflen)
330
WARN("file is truncated or cth_funcoff is corrupt\n");
331
if (hp->cth_typeoff >= cd->cd_ctflen)
332
WARN("file is truncated or cth_typeoff is corrupt\n");
333
if (hp->cth_funcoff > hp->cth_typeoff)
334
WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
335
336
for (symidx = -1, id = 0; v < end; id++) {
337
info = 0;
338
memcpy(&info, v, cd->cd_idwidth);
339
v += cd->cd_idwidth;
340
ushort_t kind = hp->cth_version == CTF_VERSION_2 ?
341
CTF_V2_INFO_KIND(info) : CTF_V3_INFO_KIND(info);
342
ushort_t n = hp->cth_version == CTF_VERSION_2 ?
343
CTF_V2_INFO_VLEN(info) : CTF_V3_INFO_VLEN(info);
344
ushort_t i;
345
int nextsym;
346
char *name;
347
348
if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx,
349
STT_FUNC, &name)) < 0)
350
name = NULL;
351
else
352
symidx = nextsym;
353
354
if (kind == CTF_K_UNKNOWN && n == 0)
355
continue; /* skip padding */
356
357
if (kind != CTF_K_FUNCTION) {
358
(void) printf(" [%lu] unexpected kind -- %u\n",
359
id, kind);
360
return (E_ERROR);
361
}
362
363
if (v + n * cd->cd_idwidth > end) {
364
(void) printf(" [%lu] vlen %u extends past section "
365
"boundary\n", id, n);
366
return (E_ERROR);
367
}
368
369
if (flags != F_STATS) {
370
(void) printf(" [%lu] FUNC ", id);
371
if (name != NULL)
372
(void) printf("(%s) ", name);
373
memcpy(&f, v, cd->cd_idwidth);
374
v += cd->cd_idwidth;
375
(void) printf("returns: %u args: (", f);
376
377
if (n != 0) {
378
memcpy(&f, v, cd->cd_idwidth);
379
v += cd->cd_idwidth;
380
(void) printf("%u", f);
381
for (i = 1; i < n; i++) {
382
memcpy(&f, v, cd->cd_idwidth);
383
v += cd->cd_idwidth;
384
(void) printf(", %u", f);
385
}
386
}
387
388
(void) printf(")\n");
389
} else
390
v += n * cd->cd_idwidth + 1; /* skip to next function definition */
391
392
stats.s_nfunc++;
393
stats.s_nargs += n;
394
stats.s_argmax = MAX(stats.s_argmax, n);
395
}
396
397
return (E_SUCCESS);
398
}
399
400
static int
401
read_types(const ctf_header_t *hp, const ctf_data_t *cd)
402
{
403
const char *v = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
404
const char *end = (void *) (cd->cd_ctfdata + hp->cth_stroff);
405
ulong_t id;
406
uint_t version;
407
408
if (flags != F_STATS)
409
print_line("- Types ");
410
411
if (hp->cth_typeoff & 3)
412
WARN("cth_typeoff is not aligned properly\n");
413
if (hp->cth_typeoff >= cd->cd_ctflen)
414
WARN("file is truncated or cth_typeoff is corrupt\n");
415
if (hp->cth_stroff >= cd->cd_ctflen)
416
WARN("file is truncated or cth_stroff is corrupt\n");
417
if (hp->cth_typeoff > hp->cth_stroff)
418
WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
419
420
version = hp->cth_version;
421
422
id = 1;
423
if (hp->cth_parlabel || hp->cth_parname)
424
id += 1ul << (hp->cth_version == CTF_VERSION_2 ?
425
CTF_V2_PARENT_SHIFT : CTF_V3_PARENT_SHIFT);
426
427
for (/* */; v < end; id++) {
428
struct ctf_type_v2 t2;
429
struct ctf_type_v3 t3;
430
ulong_t i, n;
431
size_t size, increment, vlen = 0;
432
uint_t isroot, name, type;
433
int kind;
434
435
if (version == CTF_VERSION_2) {
436
memcpy(&t2, v, sizeof(t2));
437
name = t2.ctt_name;
438
n = CTF_V2_INFO_VLEN(t2.ctt_info);
439
isroot = CTF_V2_INFO_ISROOT(t2.ctt_info);
440
kind = CTF_V2_INFO_KIND(t2.ctt_info);
441
type = t2.ctt_type;
442
443
if (t2.ctt_size == CTF_V2_LSIZE_SENT) {
444
increment = sizeof (struct ctf_type_v2);
445
size = (size_t)CTF_TYPE_LSIZE(&t2);
446
} else {
447
increment = sizeof (struct ctf_stype_v2);
448
size = t2.ctt_size;
449
}
450
} else {
451
memcpy(&t3, v, sizeof(t3));
452
name = t3.ctt_name;
453
n = CTF_V3_INFO_VLEN(t3.ctt_info);
454
isroot = CTF_V3_INFO_ISROOT(t3.ctt_info);
455
kind = CTF_V3_INFO_KIND(t3.ctt_info);
456
type = t3.ctt_type;
457
458
if (t3.ctt_size == CTF_V3_LSIZE_SENT) {
459
increment = sizeof (struct ctf_type_v3);
460
size = (size_t)CTF_TYPE_LSIZE(&t3);
461
} else {
462
increment = sizeof (struct ctf_stype_v3);
463
size = t3.ctt_size;
464
}
465
}
466
467
union {
468
const char *ptr;
469
struct ctf_array_v2 *ap2;
470
struct ctf_array_v3 *ap3;
471
const struct ctf_member_v2 *mp2;
472
const struct ctf_member_v3 *mp3;
473
const struct ctf_lmember_v2 *lmp2;
474
const struct ctf_lmember_v3 *lmp3;
475
const ctf_enum_t *ep;
476
} u;
477
478
u.ptr = v + increment;
479
480
if (flags != F_STATS) {
481
(void) printf(" %c%lu%c ",
482
"[<"[isroot], id, "]>"[isroot]);
483
}
484
485
switch (kind) {
486
case CTF_K_INTEGER:
487
if (flags != F_STATS) {
488
uint_t encoding =
489
*((const uint_t *)(const void *)u.ptr);
490
491
(void) printf("INTEGER %s encoding=%s offset=%u"
492
" bits=%u", ref_to_str(name, hp, cd),
493
int_encoding_to_str(
494
CTF_INT_ENCODING(encoding)),
495
CTF_INT_OFFSET(encoding),
496
CTF_INT_BITS(encoding));
497
}
498
vlen = sizeof (uint32_t);
499
break;
500
501
case CTF_K_FLOAT:
502
if (flags != F_STATS) {
503
uint_t encoding =
504
*((const uint_t *)(const void *)u.ptr);
505
506
(void) printf("FLOAT %s encoding=%s offset=%u "
507
"bits=%u", ref_to_str(name, hp, cd),
508
fp_encoding_to_str(
509
CTF_FP_ENCODING(encoding)),
510
CTF_FP_OFFSET(encoding),
511
CTF_FP_BITS(encoding));
512
}
513
vlen = sizeof (uint32_t);
514
break;
515
516
case CTF_K_POINTER:
517
if (flags != F_STATS) {
518
(void) printf("POINTER %s refers to %u",
519
ref_to_str(name, hp, cd), type);
520
}
521
break;
522
523
case CTF_K_ARRAY: {
524
uint_t contents, index, nelems;
525
526
if (version == CTF_VERSION_2) {
527
contents = u.ap2->cta_contents;
528
index = u.ap2->cta_index;
529
nelems = u.ap2->cta_nelems;
530
} else {
531
contents = u.ap3->cta_contents;
532
index = u.ap3->cta_index;
533
nelems = u.ap3->cta_nelems;
534
}
535
if (flags != F_STATS) {
536
(void) printf("ARRAY %s content: %u index: %u "
537
"nelems: %u\n", ref_to_str(name, hp, cd),
538
contents, index, nelems);
539
}
540
if (version == 2)
541
vlen = sizeof (struct ctf_array_v2);
542
else
543
vlen = sizeof (struct ctf_array_v3);
544
break;
545
}
546
547
case CTF_K_FUNCTION: {
548
uint_t arg = 0;
549
550
if (flags != F_STATS) {
551
(void) printf("FUNCTION %s returns: %u args: (",
552
ref_to_str(name, hp, cd), type);
553
554
if (n != 0) {
555
memcpy(&arg, u.ptr, cd->cd_idwidth);
556
u.ptr += cd->cd_idwidth;
557
(void) printf("%u", arg);
558
for (i = 1; i < n;
559
i++, u.ptr += cd->cd_idwidth) {
560
memcpy(&arg, u.ptr,
561
cd->cd_idwidth);
562
(void) printf(", %u", arg);
563
}
564
}
565
566
(void) printf(")");
567
}
568
569
vlen = roundup2(cd->cd_idwidth * n, 4);
570
break;
571
}
572
573
case CTF_K_STRUCT:
574
case CTF_K_UNION:
575
if (kind == CTF_K_STRUCT) {
576
stats.s_nsmem += n;
577
stats.s_smmax = MAX(stats.s_smmax, n);
578
stats.s_nsbytes += size;
579
stats.s_sbmax = MAX(stats.s_sbmax, size);
580
581
if (flags != F_STATS)
582
(void) printf("STRUCT");
583
} else {
584
stats.s_numem += n;
585
stats.s_ummax = MAX(stats.s_ummax, n);
586
stats.s_nubytes += size;
587
stats.s_ubmax = MAX(stats.s_ubmax, size);
588
589
if (flags != F_STATS)
590
(void) printf("UNION");
591
}
592
593
if (flags != F_STATS) {
594
(void) printf(" %s (%zd bytes)\n",
595
ref_to_str(name, hp, cd), size);
596
597
if (version == CTF_VERSION_2) {
598
if (size >= CTF_V2_LSTRUCT_THRESH) {
599
for (i = 0; i < n; i++, u.lmp2++) {
600
(void) printf(
601
"\t%s type=%u off=%llu\n",
602
ref_to_str(u.lmp2->ctlm_name,
603
hp, cd), u.lmp2->ctlm_type,
604
(unsigned long long)
605
CTF_LMEM_OFFSET(u.lmp2));
606
}
607
} else {
608
for (i = 0; i < n; i++, u.mp2++) {
609
(void) printf(
610
"\t%s type=%u off=%u\n",
611
ref_to_str(u.mp2->ctm_name,
612
hp, cd), u.mp2->ctm_type,
613
u.mp2->ctm_offset);
614
}
615
}
616
} else {
617
if (size >= CTF_V3_LSTRUCT_THRESH) {
618
for (i = 0; i < n; i++, u.lmp3++) {
619
(void) printf(
620
"\t%s type=%u off=%llu\n",
621
ref_to_str(u.lmp3->ctlm_name,
622
hp, cd), u.lmp3->ctlm_type,
623
(unsigned long long)
624
CTF_LMEM_OFFSET(u.lmp3));
625
}
626
} else {
627
for (i = 0; i < n; i++, u.mp3++) {
628
(void) printf(
629
"\t%s type=%u off=%u\n",
630
ref_to_str(u.mp3->ctm_name,
631
hp, cd), u.mp3->ctm_type,
632
u.mp3->ctm_offset);
633
}
634
}
635
}
636
}
637
638
if (version == CTF_VERSION_2) {
639
vlen = n * (size >= CTF_V2_LSTRUCT_THRESH ?
640
sizeof (struct ctf_lmember_v2) :
641
sizeof (struct ctf_member_v2));
642
} else {
643
vlen = n * (size >= CTF_V3_LSTRUCT_THRESH ?
644
sizeof (struct ctf_lmember_v3) :
645
sizeof (struct ctf_member_v3));
646
}
647
break;
648
649
case CTF_K_ENUM:
650
if (flags != F_STATS) {
651
(void) printf("ENUM %s\n",
652
ref_to_str(name, hp, cd));
653
654
for (i = 0; i < n; i++, u.ep++) {
655
(void) printf("\t%s = %d\n",
656
ref_to_str(u.ep->cte_name, hp, cd),
657
u.ep->cte_value);
658
}
659
}
660
661
stats.s_nemem += n;
662
stats.s_emmax = MAX(stats.s_emmax, n);
663
664
vlen = sizeof (ctf_enum_t) * n;
665
break;
666
667
case CTF_K_FORWARD:
668
if (flags != F_STATS) {
669
(void) printf("FORWARD %s",
670
ref_to_str(name, hp, cd));
671
}
672
break;
673
674
case CTF_K_TYPEDEF:
675
if (flags != F_STATS) {
676
(void) printf("TYPEDEF %s refers to %u",
677
ref_to_str(name, hp, cd), type);
678
}
679
break;
680
681
case CTF_K_VOLATILE:
682
if (flags != F_STATS) {
683
(void) printf("VOLATILE %s refers to %u",
684
ref_to_str(name, hp, cd), type);
685
}
686
break;
687
688
case CTF_K_CONST:
689
if (flags != F_STATS) {
690
(void) printf("CONST %s refers to %u",
691
ref_to_str(name, hp, cd), type);
692
}
693
break;
694
695
case CTF_K_RESTRICT:
696
if (flags != F_STATS) {
697
(void) printf("RESTRICT %s refers to %u",
698
ref_to_str(name, hp, cd), type);
699
}
700
break;
701
702
case CTF_K_UNKNOWN:
703
break; /* hole in type id space */
704
705
default:
706
(void) printf("unexpected kind %u\n", kind);
707
return (E_ERROR);
708
}
709
710
if (flags != F_STATS)
711
(void) printf("\n");
712
713
stats.s_ntypes++;
714
stats.s_types[kind]++;
715
716
v += increment + vlen;
717
}
718
719
return (E_SUCCESS);
720
}
721
722
static int
723
read_strtab(const ctf_header_t *hp, const ctf_data_t *cd)
724
{
725
size_t n, off, len = hp->cth_strlen;
726
const char *s = cd->cd_ctfdata + hp->cth_stroff;
727
728
if (flags != F_STATS)
729
print_line("- String Table ");
730
731
if (hp->cth_stroff >= cd->cd_ctflen)
732
WARN("file is truncated or cth_stroff is corrupt\n");
733
if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)
734
WARN("file is truncated or cth_strlen is corrupt\n");
735
736
for (off = 0; len != 0; off += n) {
737
if (flags != F_STATS) {
738
(void) printf(" [%lu] %s\n", (ulong_t)off,
739
s[0] == '\0' ? "\\0" : s);
740
}
741
n = strlen(s) + 1;
742
len -= n;
743
s += n;
744
745
stats.s_nstr++;
746
stats.s_strlen += n;
747
stats.s_strmax = MAX(stats.s_strmax, n);
748
}
749
750
return (E_SUCCESS);
751
}
752
753
static void
754
long_stat(const char *name, ulong_t value)
755
{
756
(void) printf(" %-36s= %lu\n", name, value);
757
}
758
759
static void
760
fp_stat(const char *name, float value)
761
{
762
(void) printf(" %-36s= %.2f\n", name, value);
763
}
764
765
static int
766
print_stats(void)
767
{
768
print_line("- CTF Statistics ");
769
770
long_stat("total number of data objects", stats.s_ndata);
771
(void) printf("\n");
772
773
long_stat("total number of functions", stats.s_nfunc);
774
long_stat("total number of function arguments", stats.s_nargs);
775
long_stat("maximum argument list length", stats.s_argmax);
776
777
if (stats.s_nfunc != 0) {
778
fp_stat("average argument list length",
779
(float)stats.s_nargs / (float)stats.s_nfunc);
780
}
781
782
(void) printf("\n");
783
784
long_stat("total number of types", stats.s_ntypes);
785
long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]);
786
long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]);
787
long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]);
788
long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]);
789
long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]);
790
long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]);
791
long_stat("total number of unions", stats.s_types[CTF_K_UNION]);
792
long_stat("total number of enums", stats.s_types[CTF_K_ENUM]);
793
long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]);
794
long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]);
795
long_stat("total number of volatile types",
796
stats.s_types[CTF_K_VOLATILE]);
797
long_stat("total number of const types", stats.s_types[CTF_K_CONST]);
798
long_stat("total number of restrict types",
799
stats.s_types[CTF_K_RESTRICT]);
800
long_stat("total number of unknowns (holes)",
801
stats.s_types[CTF_K_UNKNOWN]);
802
803
(void) printf("\n");
804
805
long_stat("total number of struct members", stats.s_nsmem);
806
long_stat("maximum number of struct members", stats.s_smmax);
807
long_stat("total size of all structs", stats.s_nsbytes);
808
long_stat("maximum size of a struct", stats.s_sbmax);
809
810
if (stats.s_types[CTF_K_STRUCT] != 0) {
811
fp_stat("average number of struct members",
812
(float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]);
813
fp_stat("average size of a struct", (float)stats.s_nsbytes /
814
(float)stats.s_types[CTF_K_STRUCT]);
815
}
816
817
(void) printf("\n");
818
819
long_stat("total number of union members", stats.s_numem);
820
long_stat("maximum number of union members", stats.s_ummax);
821
long_stat("total size of all unions", stats.s_nubytes);
822
long_stat("maximum size of a union", stats.s_ubmax);
823
824
if (stats.s_types[CTF_K_UNION] != 0) {
825
fp_stat("average number of union members",
826
(float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]);
827
fp_stat("average size of a union", (float)stats.s_nubytes /
828
(float)stats.s_types[CTF_K_UNION]);
829
}
830
831
(void) printf("\n");
832
833
long_stat("total number of enum members", stats.s_nemem);
834
long_stat("maximum number of enum members", stats.s_emmax);
835
836
if (stats.s_types[CTF_K_ENUM] != 0) {
837
fp_stat("average number of enum members",
838
(float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]);
839
}
840
841
(void) printf("\n");
842
843
long_stat("total number of unique strings", stats.s_nstr);
844
long_stat("bytes of string data", stats.s_strlen);
845
long_stat("maximum string length", stats.s_strmax);
846
847
if (stats.s_nstr != 0) {
848
fp_stat("average string length",
849
(float)stats.s_strlen / (float)stats.s_nstr);
850
}
851
852
(void) printf("\n");
853
return (E_SUCCESS);
854
}
855
856
static int
857
print_usage(FILE *fp, int verbose)
858
{
859
(void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getprogname());
860
861
if (verbose) {
862
(void) fprintf(fp,
863
"\t-d dump data object section\n"
864
"\t-f dump function section\n"
865
"\t-h dump file header\n"
866
"\t-l dump label table\n"
867
"\t-s dump string table\n"
868
"\t-S dump statistics\n"
869
"\t-t dump type section\n"
870
"\t-u save uncompressed CTF to a file\n");
871
}
872
873
return (E_USAGE);
874
}
875
876
static Elf_Scn *
877
findelfscn(Elf *elf, GElf_Ehdr *ehdr, const char *secname)
878
{
879
GElf_Shdr shdr;
880
Elf_Scn *scn;
881
char *name;
882
883
for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) {
884
if (gelf_getshdr(scn, &shdr) != NULL && (name =
885
elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL &&
886
strcmp(name, secname) == 0)
887
return (scn);
888
}
889
890
return (NULL);
891
}
892
893
int
894
main(int argc, char *argv[])
895
{
896
const char *filename = NULL;
897
const char *ufile = NULL;
898
int error = 0;
899
int c, fd, ufd;
900
901
ctf_data_t cd;
902
const ctf_preamble_t *pp;
903
ctf_header_t *hp = NULL;
904
Elf *elf;
905
GElf_Ehdr ehdr;
906
907
(void) elf_version(EV_CURRENT);
908
909
for (opterr = 0; optind < argc; optind++) {
910
while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) {
911
switch (c) {
912
case 'd':
913
flags |= F_DATA;
914
break;
915
case 'f':
916
flags |= F_FUNC;
917
break;
918
case 'h':
919
flags |= F_HDR;
920
break;
921
case 'l':
922
flags |= F_LABEL;
923
break;
924
case 's':
925
flags |= F_STR;
926
break;
927
case 'S':
928
flags |= F_STATS;
929
break;
930
case 't':
931
flags |= F_TYPES;
932
break;
933
case 'u':
934
ufile = optarg;
935
break;
936
default:
937
if (optopt == '?')
938
return (print_usage(stdout, 1));
939
warn("illegal option -- %c\n", optopt);
940
return (print_usage(stderr, 0));
941
}
942
}
943
944
if (optind < argc) {
945
if (filename != NULL)
946
return (print_usage(stderr, 0));
947
filename = argv[optind];
948
}
949
}
950
951
if (filename == NULL)
952
return (print_usage(stderr, 0));
953
954
if (flags == 0 && ufile == NULL)
955
flags = F_ALLMSK;
956
957
if ((fd = open(filename, O_RDONLY)) == -1)
958
die("failed to open %s", filename);
959
960
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL &&
961
gelf_getehdr(elf, &ehdr) != NULL) {
962
963
Elf_Data *dp = NULL;
964
Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf");
965
Elf_Scn *symscn;
966
GElf_Shdr ctfshdr;
967
968
if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL)
969
die("%s does not contain .SUNW_ctf data\n", filename);
970
971
cd.cd_ctfdata = dp->d_buf;
972
cd.cd_ctflen = dp->d_size;
973
974
/*
975
* If the sh_link field of the CTF section header is non-zero
976
* it indicates which section contains the symbol table that
977
* should be used. We default to the .symtab section if sh_link
978
* is zero or if there's an error reading the section header.
979
*/
980
if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&
981
ctfshdr.sh_link != 0) {
982
symscn = elf_getscn(elf, ctfshdr.sh_link);
983
} else {
984
symscn = findelfscn(elf, &ehdr, ".symtab");
985
}
986
987
/* If we found a symbol table, find the corresponding strings */
988
if (symscn != NULL) {
989
GElf_Shdr shdr;
990
Elf_Scn *symstrscn;
991
992
if (gelf_getshdr(symscn, &shdr) != NULL) {
993
symstrscn = elf_getscn(elf, shdr.sh_link);
994
995
cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
996
cd.cd_symdata = elf_getdata(symscn, NULL);
997
cd.cd_strdata = elf_getdata(symstrscn, NULL);
998
}
999
}
1000
} else {
1001
struct stat st;
1002
1003
if (fstat(fd, &st) == -1)
1004
die("failed to fstat %s", filename);
1005
1006
cd.cd_ctflen = st.st_size;
1007
cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ,
1008
MAP_PRIVATE, fd, 0);
1009
if (cd.cd_ctfdata == MAP_FAILED)
1010
die("failed to mmap %s", filename);
1011
}
1012
1013
/*
1014
* Get a pointer to the CTF data buffer and interpret the first portion
1015
* as a ctf_header_t. Validate the magic number and size.
1016
*/
1017
1018
if (cd.cd_ctflen < sizeof (ctf_preamble_t))
1019
die("%s does not contain a CTF preamble\n", filename);
1020
1021
void *v = (void *) cd.cd_ctfdata;
1022
pp = v;
1023
1024
if (pp->ctp_magic != CTF_MAGIC)
1025
die("%s does not appear to contain CTF data\n", filename);
1026
1027
if (pp->ctp_version >= CTF_VERSION_2) {
1028
v = (void *) cd.cd_ctfdata;
1029
hp = v;
1030
cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t);
1031
1032
cd.cd_idwidth = pp->ctp_version == CTF_VERSION_2 ? 2 : 4;
1033
1034
if (cd.cd_ctflen < sizeof (ctf_header_t)) {
1035
die("%s does not contain a v%d CTF header\n", filename,
1036
pp->ctp_version);
1037
}
1038
1039
} else {
1040
die("%s contains unsupported CTF version %d\n", filename,
1041
pp->ctp_version);
1042
}
1043
1044
/*
1045
* If the data buffer is compressed, then malloc a buffer large enough
1046
* to hold the decompressed data, and use zlib to decompress it.
1047
*/
1048
if (hp->cth_flags & CTF_F_COMPRESS) {
1049
z_stream zstr;
1050
void *buf;
1051
int rc;
1052
1053
if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL)
1054
die("failed to allocate decompression buffer");
1055
1056
bzero(&zstr, sizeof (z_stream));
1057
zstr.next_in = (void *)cd.cd_ctfdata;
1058
zstr.avail_in = cd.cd_ctflen;
1059
zstr.next_out = buf;
1060
zstr.avail_out = hp->cth_stroff + hp->cth_strlen;
1061
1062
if ((rc = inflateInit(&zstr)) != Z_OK)
1063
die("failed to initialize zlib: %s\n", zError(rc));
1064
1065
if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END)
1066
die("failed to decompress CTF data: %s\n", zError(rc));
1067
1068
if ((rc = inflateEnd(&zstr)) != Z_OK)
1069
die("failed to finish decompression: %s\n", zError(rc));
1070
1071
if (zstr.total_out != hp->cth_stroff + hp->cth_strlen)
1072
die("CTF data is corrupt -- short decompression\n");
1073
1074
cd.cd_ctfdata = buf;
1075
cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen;
1076
}
1077
1078
if (flags & F_HDR)
1079
error |= print_header(hp, &cd);
1080
if (flags & (F_LABEL))
1081
error |= print_labeltable(hp, &cd);
1082
if (flags & (F_DATA | F_STATS))
1083
error |= read_data(hp, &cd);
1084
if (flags & (F_FUNC | F_STATS))
1085
error |= read_funcs(hp, &cd);
1086
if (flags & (F_TYPES | F_STATS))
1087
error |= read_types(hp, &cd);
1088
if (flags & (F_STR | F_STATS))
1089
error |= read_strtab(hp, &cd);
1090
if (flags & F_STATS)
1091
error |= print_stats();
1092
1093
/*
1094
* If the -u option is specified, write the uncompressed CTF data to a
1095
* raw CTF file. CTF data can already be extracted compressed by
1096
* applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
1097
*/
1098
if (ufile != NULL) {
1099
ctf_header_t h;
1100
1101
bcopy(hp, &h, sizeof (h));
1102
h.cth_flags &= ~CTF_F_COMPRESS;
1103
1104
if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 ||
1105
write(ufd, &h, sizeof (h)) != sizeof (h) ||
1106
write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != (int) cd.cd_ctflen) {
1107
warn("failed to write CTF data to '%s'", ufile);
1108
error |= E_ERROR;
1109
}
1110
1111
(void) close(ufd);
1112
}
1113
1114
if (elf != NULL)
1115
(void) elf_end(elf);
1116
1117
(void) close(fd);
1118
return (error);
1119
}
1120
1121