/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <gelf.h>
#include <zlib.h>
#include "ctf_headers.h"
#include "utils.h"
#include "symbol.h"
/*
* Flags that indicate what data is to be displayed. An explicit `all' value is
* provided to allow the code to distinguish between a request for everything
* (currently requested by invoking ctfdump without flags) and individual
* requests for all of the types of data (an invocation with all flags). In the
* former case, we want to be able to implicitly adjust the definition of `all'
* based on the CTF version of the file being dumped. For example, if a v2 file
* is being dumped, `all' includes F_LABEL - a request to dump the label
* section. If a v1 file is being dumped, `all' does not include F_LABEL,
* because v1 CTF doesn't support labels. We need to be able to distinguish
* between `ctfdump foo', which has an implicit request for labels if `foo'
* supports them, and `ctfdump -l foo', which has an explicity request. In the
* latter case, we exit with an error if `foo' is a v1 CTF file.
*/
static enum {
} flags = 0;
static struct {
} stats;
typedef struct ctf_data {
/*
* cd_symdata will be non-NULL if the CTF data is being retrieved from
* an ELF file with a symbol table. cd_strdata and cd_nsyms should be
* used only if cd_symdata is non-NULL.
*/
} ctf_data_t;
static const char *
{
return ("<< ??? - name in external strtab >>");
return ("<< ??? - name exceeds strlab len >>");
return ("<< ??? - file truncated >>");
if (s[0] == '\0')
return ("(anon)");
return (s);
}
static const char *
{
CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)
else {
buf[0] = '\0';
if (encoding & CTF_INT_SIGNED)
if (encoding & CTF_INT_CHAR)
if (encoding & CTF_INT_BOOL)
if (encoding & CTF_INT_VARARGS)
}
return (buf + 1);
}
static const char *
{
static const char *const encs[] = {
"LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
"DIMAGINARY", "LDIMAGINARY"
};
return (buf);
}
}
static void
print_line(const char *s)
{
"----------------------------------------";
}
static int
{
print_line("- CTF Header ");
(void) printf(" cth_parlabel = %s\n",
(void) printf(" cth_parname = %s\n",
return (E_SUCCESS);
}
static int
{
/* LINTED - pointer alignment */
hp->cth_lbloff);
print_line("- Label Table ");
WARN("cth_lbloff is not aligned properly\n");
WARN("file is truncated or cth_lbloff is corrupt\n");
WARN("file is truncated or cth_objtoff is corrupt\n");
WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
for (i = 0; i < n; i++, ctl++) {
}
return (E_SUCCESS);
}
/*
* Given the current symbol index (-1 to start at the beginning of the symbol
* table) and the type of symbol to match, this function returns the index of
* the next matching symbol (if any), and places the name of that symbol in
* *namep. If no symbol is found, -1 is returned.
*/
static int
char **namep)
{
int i;
char *name;
int type;
return (-1);
/*
* Skip various types of symbol table entries.
*/
continue;
/* Found one */
return (i);
}
return (-1);
}
static int
{
/* LINTED - pointer alignment */
print_line("- Data Objects ");
WARN("cth_objtoff is not aligned properly\n");
WARN("file is truncated or cth_objtoff is corrupt\n");
WARN("file is truncated or cth_funcoff is corrupt\n");
WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");
for (symidx = -1, i = 0; i < n; i++) {
int nextsym;
else
(void) putchar('\n');
}
}
return (E_SUCCESS);
}
static int
{
/* LINTED - pointer alignment */
/* LINTED - pointer alignment */
int symidx;
print_line("- Functions ");
WARN("cth_funcoff is not aligned properly\n");
WARN("file is truncated or cth_funcoff is corrupt\n");
WARN("file is truncated or cth_typeoff is corrupt\n");
WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
ushort_t i;
int nextsym;
char *name;
else
if (kind == CTF_K_UNKNOWN && n == 0)
continue; /* skip padding */
if (kind != CTF_K_FUNCTION) {
(void) printf(" [%lu] unexpected kind -- %u\n",
return (E_ERROR);
}
(void) printf(" [%lu] vlen %u extends past section "
"boundary\n", id, n);
return (E_ERROR);
}
if (n != 0) {
for (i = 1; i < n; i++)
}
(void) printf(")\n");
} else
}
return (E_SUCCESS);
}
static int
{
/* LINTED - pointer alignment */
/* LINTED - pointer alignment */
print_line("- Types ");
WARN("cth_typeoff is not aligned properly\n");
WARN("file is truncated or cth_typeoff is corrupt\n");
WARN("file is truncated or cth_stroff is corrupt\n");
WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
id = 1;
union {
const void *ptr;
} u;
(void) printf(" %c%lu%c ",
}
increment = sizeof (ctf_type_t);
} else {
increment = sizeof (ctf_stype_t);
}
switch (kind) {
case CTF_K_INTEGER:
(void) printf("INTEGER %s encoding=%s offset=%u"
}
break;
case CTF_K_FLOAT:
(void) printf("FLOAT %s encoding=%s offset=%u "
}
break;
case CTF_K_POINTER:
(void) printf("POINTER %s refers to %u",
}
break;
case CTF_K_ARRAY:
(void) printf("ARRAY %s content: %u index: %u "
}
vlen = sizeof (ctf_array_t);
break;
case CTF_K_FUNCTION:
(void) printf("FUNCTION %s returns: %u args: (",
if (n != 0) {
for (i = 1; i < n; i++, u.argp++)
}
(void) printf(")");
}
break;
case CTF_K_STRUCT:
case CTF_K_UNION:
if (kind == CTF_K_STRUCT) {
(void) printf("STRUCT");
} else {
(void) printf("UNION");
}
(void) printf(" %s (%d bytes)\n",
if (size >= CTF_LSTRUCT_THRESH) {
for (i = 0; i < n; i++, u.lmp++) {
(void) printf(
"\t%s type=%u off=%llu\n",
CTF_LMEM_OFFSET(u.lmp));
}
} else {
for (i = 0; i < n; i++, u.mp++) {
(void) printf(
"\t%s type=%u off=%u\n",
u.mp->ctm_offset);
}
}
}
sizeof (ctf_lmember_t) : sizeof (ctf_member_t));
break;
case CTF_K_ENUM:
(void) printf("ENUM %s\n",
for (i = 0; i < n; i++, u.ep++) {
(void) printf("\t%s = %d\n",
}
}
vlen = sizeof (ctf_enum_t) * n;
break;
case CTF_K_FORWARD:
(void) printf("FORWARD %s",
}
break;
case CTF_K_TYPEDEF:
(void) printf("TYPEDEF %s refers to %u",
}
break;
case CTF_K_VOLATILE:
(void) printf("VOLATILE %s refers to %u",
}
break;
case CTF_K_CONST:
(void) printf("CONST %s refers to %u",
}
break;
case CTF_K_RESTRICT:
(void) printf("RESTRICT %s refers to %u",
}
break;
case CTF_K_UNKNOWN:
break; /* hole in type id space */
default:
return (E_ERROR);
}
(void) printf("\n");
}
return (E_SUCCESS);
}
static int
{
print_line("- String Table ");
WARN("file is truncated or cth_stroff is corrupt\n");
WARN("file is truncated or cth_strlen is corrupt\n");
s[0] == '\0' ? "\\0" : s);
}
n = strlen(s) + 1;
len -= n;
s += n;
}
return (E_SUCCESS);
}
static void
{
}
static void
{
}
static int
print_stats(void)
{
print_line("- CTF Statistics ");
(void) printf("\n");
fp_stat("average argument list length",
}
(void) printf("\n");
long_stat("total number of volatile types",
long_stat("total number of restrict types",
long_stat("total number of unknowns (holes)",
(void) printf("\n");
fp_stat("average number of struct members",
}
(void) printf("\n");
fp_stat("average number of union members",
}
(void) printf("\n");
fp_stat("average number of enum members",
}
(void) printf("\n");
fp_stat("average string length",
}
(void) printf("\n");
return (E_SUCCESS);
}
static int
{
if (verbose) {
"\t-d dump data object section\n"
"\t-f dump function section\n"
"\t-h dump file header\n"
"\t-l dump label table\n"
"\t-s dump string table\n"
"\t-S dump statistics\n"
"\t-t dump type section\n"
"\t-u save uncompressed CTF to a file\n");
}
return (E_USAGE);
}
static Elf_Scn *
{
char *name;
return (scn);
}
return (NULL);
}
int
{
int error = 0;
(void) elf_version(EV_CURRENT);
switch (c) {
case 'd':
break;
case 'f':
break;
case 'h':
break;
case 'l':
break;
case 's':
break;
case 'S':
break;
case 't':
break;
case 'u':
break;
default:
if (optopt == '?')
return (print_usage(stderr, 0));
}
}
return (print_usage(stderr, 0));
}
}
return (print_usage(stderr, 0));
/*
* If the sh_link field of the CTF section header is non-zero
* it indicates which section contains the symbol table that
* should be used. We default to the .symtab section if sh_link
* is zero or if there's an error reading the section header.
*/
} else {
}
/* If we found a symbol table, find the corresponding strings */
}
}
} else {
MAP_PRIVATE, fd, 0);
}
/*
* Get a pointer to the CTF data buffer and interpret the first portion
* as a ctf_header_t. Validate the magic number and size.
*/
/* LINTED - pointer alignment */
/* LINTED - pointer alignment */
}
} else {
pp->ctp_version);
}
/*
* If the data buffer is compressed, then malloc a buffer large enough
* to hold the decompressed data, and use zlib to decompress it.
*/
void *buf;
int rc;
die("failed to allocate decompression buffer");
die("CTF data is corrupt -- short decompression\n");
}
error |= print_stats();
/*
* If the -u option is specified, write the uncompressed CTF data to a
* raw CTF file. CTF data can already be extracted compressed by
* applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
*/
ctf_header_t h;
h.cth_flags &= ~CTF_F_COMPRESS;
}
}
return (error);
}