main.c revision c6c9aed4d309e3d11be652b85e3bf8bb72f20c87
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Dump an elf file.
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <libelf.h>
#include <link.h>
#include <stdarg.h>
#include <unistd.h>
#include <libgen.h>
#include <libintl.h>
#include <locale.h>
#include <errno.h>
#include <strings.h>
#include <debug.h>
#include <conv.h>
#include <msg.h>
#include <_elfdump.h>
#include <sys/elf_SPARC.h>
#include <sys/elf_amd64.h>
/*
* The -I, -N, and -T options are called "match options", because
* they allow selecting the items to be displayed based on matching
* their index, name, or type.
*
* The ELF information to which -I, -N, or -T are applied in
* the current invocation is called the "match item".
*/
typedef enum {
MATCH_ITEM_PT, /* Program header (PT_) */
MATCH_ITEM_SHT /* Section header (SHT_) */
} match_item_t;
/* match_opt_t is used to note which match option was used */
typedef enum {
MATCH_OPT_NAME, /* Record contains a name */
MATCH_OPT_NDX, /* Record contains a single index */
MATCH_OPT_RANGE, /* Record contains an index range */
MATCH_OPT_TYPE, /* Record contains a type (shdr or phdr) */
} match_opt_t;
typedef struct _match {
union {
const char *name; /* MATCH_OPT_NAME */
struct { /* MATCH_OPT_NDX and MATCH_OPT_RANGE */
int start;
int end; /* Only for MATCH_OPT_RANGE */
} ndx;
} value;
} match_rec_t;
static struct {
} match_state;
/* Map names to their integer value */
typedef struct {
const char *sym_name;
} atoui_sym_t;
/*
* ELF section types.
*/
static atoui_sym_t sym_sht[] = {
{ NULL }
};
/*
* Program header PT_* type values
*/
static atoui_sym_t sym_pt[] = {
{ NULL }
};
const char *
{
}
/*
* Determine whether a symbol name should be demangled.
*/
const char *
{
if (flags & FLG_CTL_DEMANGLE)
return (Elf_demangle_name(name));
else
return ((char *)name);
}
/*
* Define our own standard error routine.
*/
void
{
}
/*
* The full usage message
*/
static void
{
}
/*
* Output a block of raw data as hex bytes. Each row is given
* the index of the first byte in the row.
*
* entry:
* data - Pointer to first byte of data to be displayed
* n - # of bytes of data
* prefix - String to be output before each line. Useful
* for indenting output.
* bytes_per_col - # of space separated bytes to output
* in each column.
* col_per_row - # of columns to output per row
*
* exit:
* The formatted data has been sent to stdout. Each row of output
* shows (bytes_per_col * col_per_row) bytes of data.
*/
void
int bytes_per_col, int col_per_row)
{
char index[MAXNDXSIZE];
int index_width;
int sp_prefix = 0;
/*
* Determine the width to use for the index string. We follow
* 8-byte tab rules, but don't use an actual \t character so
* that the output can be arbitrarily shifted without odd
* tab effects, and so that all the columns line up no matter
* how many lines of output are produced.
*/
ndx = n / bytes_per_row;
while (sp_prefix-- > 0)
*str++ = ' ';
str += 2;
sp_prefix = 1;
if (++byte == bytes_per_col) {
sp_prefix += 2;
word++;
byte = 0;
}
if (word == col_per_row) {
*str = '\0';
sp_prefix = 0;
word = 0;
ndx += bytes_per_row;
}
}
}
}
/*
* Convert the ASCII representation of an index, or index range, into
* binary form, and store it in rec:
*
* index: An positive or 0 valued integer
* range: Two indexes, separated by a ':' character, denoting
* a range of allowed values. If the second value is omitted,
* any values equal to or greater than the first will match.
*
* exit:
* On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
* value, and this function returns (1). On failure, the contents
* of *rec are undefined, and (0) is returned.
*/
int
{
char *endptr;
/* Value must use some of the input, and be 0 or positive */
return (0);
if (*str != ':') {
} else {
str++; /* Skip the ':' */
if (*str == '\0') {
} else {
return (0);
}
}
/* Syntax error if anything is left over */
if (*str != '\0')
return (0);
return (1);
}
/*
* Process the symbolic name to value mappings passed to the
* atoui() function.
*
* entry:
* sym - NULL terminated array of name->value mappings.
* value - Address of variable to receive corresponding value.
*
* exit:
* If a mapping is found, *value is set to it, and True is returned.
* Otherwise False is returned.
*/
static int
{
const char *tail;
str++;
tail--;
return (1);
}
}
/* No symbolic mapping was found */
return (0);
}
/*
* Convert a string to a numeric value. Strings starting with '0'
* are taken to be octal, those staring with '0x' are hex, and all
* others are decimal.
*
* entry:
* str - String to be converted
* v - Address of variable to receive resulting value.
*
* exit:
* On success, returns True (1) and *v is set to the value.
* On failure, returns False (0) and *v is undefined.
*/
static int
{
char *endptr;
return (1);
/* If the left over part contains anything but whitespace, fail */
return (0);
return (1);
}
/*
* Called after getopt() processing is finished if there is a non-empty
* match list. Prepares the matching code for use.
*
* exit:
* Returns True (1) if no errors are encountered. Writes an
* error string to stderr and returns False (0) otherwise.
*/
static int
{
const char *str;
/*
* Flag ambiguous attempt to use match option with both -p and
* and one or more section SHOW options. In this case, we
* can't tell what type of item we're supposed to match against.
*/
return (0);
}
/* Set the match type, based on the presence of the -p option */
if (minus_p) {
} else {
}
/*
* Scan match list and perform any necessary fixups:
*
* MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
* requests into MATCH_OPT_TYPE (-T).
*
* MATCH_OPT_TYPE: Now that we know item type we are matching
* against, we can convert the string saved in the name
* field during getopt() processing into an integer and
* write it into the type field.
*/
continue;
return (0);
}
}
return (1);
}
/*
* Returns True (1) if the item with the given name or index should
* be displayed, and False (0) if it should not be.
*
* entry:
* match_flags - Bitmask specifying matching options, as described
* in _elfdump.h.
* name - If MATCH_F_NAME flag is set, name of item under
* consideration. Otherwise ignored.
* should not be considered.
* ndx - If MATCH_F_NDX flag is set, index of item under consideration.
* type - If MATCH_F_TYPE is set, type of item under consideration.
* If MATCH_F_PHDR is set, this would be a program
* header type (PT_). Otherwise, a section header type (SHT_).
*
* exit:
* by one of the (-I, -N -T) command line options, or if no such option
* was used in the command invocation and MATCH_F_STRICT is not
* set.
*/
int
{
/*
* If there is no match list, then we use the MATCH_F_STRICT
* flag to decide what to return. In the strict case, we return
* False (0), in the normal case, True (1).
*/
return ((match_flags & MATCH_F_STRICT) == 0);
/*
* If item being checked is not the current match type,
* then allow it.
*/
return (1);
/* Run through the match records and check for a hit */
case MATCH_OPT_NAME:
if (((match_flags & MATCH_F_NAME) == 0) ||
break;
return (1);
break;
case MATCH_OPT_NDX:
if ((match_flags & MATCH_F_NDX) &&
return (1);
break;
case MATCH_OPT_RANGE:
/*
* A range end value less than 0 means that any value
* above the start is acceptible.
*/
if ((match_flags & MATCH_F_NDX) &&
return (1);
break;
case MATCH_OPT_TYPE:
if ((match_flags & MATCH_F_TYPE) &&
return (1);
break;
}
}
/* Nothing matched */
return (0);
}
/*
* Add an entry to match_state.list for use by match(). This routine is for
* use during getopt() processing. It should not be called once
* match_prepare() has been called.
*
* Return True (1) for success. On failure, an error is written
* to stderr, and False (0) is returned.
*/
static int
{
return (0);
}
/* Insert at end of match_state.list */
} else {
;
}
return (1);
}
static int
{
int r;
else
return (r);
}
static int
{
/*
* Determine if the archive symbol table itself is required.
*/
if ((flags & FLG_SHOW_SYMBOLS) &&
/*
* Get the archive symbol table.
*/
/*
* The arsym could be 0 even though there was no error.
* Print the error message only when there was
* real error from elf_getarsym().
*/
return (0);
}
}
/*
* Print the archive symbol table only when the archive symbol
* table exists and it was requested to print.
*/
if (arsym) {
char index[MAXNDXSIZE];
/*
* Print out all the symbol entries.
*/
/*
* For each object obtain an elf descriptor so that we
* can establish the members name. Note, we have had
* archives where the archive header has not been
* obtainable so be lenient with errors.
*/
if (_elf)
arhdr = 0;
ELF_C_READ, elf)) == 0) {
arhdr = 0;
arhdr = 0;
}
if (offset == 0)
}
/* LINTED */
MSG_INTL(MSG_STR_NULL)));
else
/* LINTED */
}
if (_elf)
/*
* If we only need the archive symbol table return.
*/
if ((flags & FLG_SHOW_SYMBOLS) &&
return (0);
/*
* Reset elf descriptor in preparation for processing each
* member.
*/
if (offset)
}
/*
* Process each object within the archive.
*/
char name[MAXPATHLEN];
return (0);
}
case ELF_K_AR:
return (1);
break;
case ELF_K_ELF:
return (1);
break;
default:
break;
}
}
}
return (0);
}
int
{
int ret;
/*
* If we're on a 64-bit kernel, try to exec a full 64-bit version of
* the binary. If successful, conv_check_native() won't return.
*/
/*
* Establish locale.
*/
opterr = 0;
switch (var) {
case 'C':
break;
case 'c':
flags |= FLG_SHOW_SHDR;
break;
case 'd':
break;
case 'e':
flags |= FLG_SHOW_EHDR;
break;
case 'G':
flags |= FLG_SHOW_GOT;
break;
case 'g':
flags |= FLG_SHOW_GROUP;
break;
case 'H':
flags |= FLG_SHOW_CAP;
break;
case 'h':
flags |= FLG_SHOW_HASH;
break;
case 'I':
goto usage_brief;
return (1);
flags |= FLG_CTL_MATCH;
break;
case 'i':
flags |= FLG_SHOW_INTERP;
break;
case 'k':
break;
case 'l':
break;
case 'm':
flags |= FLG_SHOW_MOVE;
break;
case 'N':
return (1);
flags |= FLG_CTL_MATCH;
break;
case 'n':
flags |= FLG_SHOW_NOTE;
break;
case 'P':
break;
case 'p':
flags |= FLG_SHOW_PHDR;
break;
case 'r':
flags |= FLG_SHOW_RELOC;
break;
case 'S':
flags |= FLG_SHOW_SORT;
break;
case 's':
break;
case 'T':
/*
* We can't evaluate the value yet, because
* we need to know if -p is used or not in
* order to tell if we're seeing section header
* or program header types. So, we save the
* string in the name field, and then convert
* it to a type integer in a following pass.
*/
return (1);
flags |= FLG_CTL_MATCH;
break;
case 'u':
flags |= FLG_SHOW_UNWIND;
break;
case 'v':
break;
case 'w':
break;
case 'y':
break;
case '?':
detail_usage();
return (1);
default:
break;
}
}
/* -p and -w are mutually exclusive. -w only works with sections */
goto usage_brief;
/* If a match argument is present, prepare the match state */
return (1);
/*
* Decide what to do if no options specifying something to
* show or do are present.
*
* If there is no -w and no match options, then we will set all
* the show flags, causing a full display of everything in the
* file that we know how to handle.
*
* Otherwise, if there is no match list, we generate a usage
* error and quit.
*
* In the case where there is a match list, we go ahead and call
* regular() anyway, leaving it to decide what to do. If -w is
* present, regular() will use the match list to handle it.
* will compare the section headers to the match list and use
* that to generate the FLG_ bits that will display the information
* specified by the match list.
*/
if ((flags & ~FLG_MASK_CTL) == 0) {
flags |= FLG_MASK_SHOW;
goto usage_brief;
}
/* There needs to be at least 1 filename left following the options */
goto usage_brief;
/*
* If the -l/-C option is specified, set up the liblddbg.so.
*/
if (flags & FLG_CTL_LONGNAME)
if (flags & FLG_CTL_DEMANGLE)
/*
* If the -w option has indicated an output file open it. It's
* arguable whether this option has much use when multiple files are
* being processed.
*
* If wname is non-NULL, we know that -p was not specified, due
* to the test above.
*/
if (wname) {
0666)) < 0) {
return (1);
}
}
/*
* Open the input file, initialize the elf interface, and
* process it.
*/
ret = 0;
continue;
}
(void) elf_version(EV_CURRENT);
continue;
}
if (var > 1)
case ELF_K_AR:
break;
case ELF_K_ELF:
break;
default:
break;
}
}
if (wfd)
return (ret);
/* Control comes here for a simple usage message and exit */
return (1);
}