static_prof.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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.
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/* ------------------------------------------------------------------------ */
/* include headers */
/* ------------------------------------------------------------------------ */
#include "static_prof.h"
/* ========== elf_hash ==================================================== */
/*
* DESCRIPTION:
* The hash function copied from libelf.so.1
*/
/* ======================================================================== */
static unsigned long
my_elf_hash(const char *name)
{
unsigned long g, h = 0;
while (*nm != '\0') {
h = (h << 4) + *nm++;
if ((g = h & MASK) != 0)
h ^= g >> 24;
h &= ~MASK;
}
return (h);
}
/* ========== output_dtneeded ============================================= */
/*
* DESCRIPTION:
* Outputs all the dt_needed entries if any.
*/
/* ======================================================================== */
static void
{
if (!p) {
return;
} else {
while (p != NULL) {
" %s",
p->libname);
p = p->next;
}
}
}
/* ========== store_binding =============================================== */
/*
* DESCRIPTION:
* Read in the symbol binding information from the symbol table and
* store them into the hash table of buckets.
*/
/* ======================================================================== */
static void
{
unsigned long bktno;
unsigned long orig_bktno;
int table_full = FALSE;
int i;
orig_bktno = bktno;
} else {
if (i == orig_bktno) {
table_full = TRUE;
exit(1);
}
break;
}
}
}
}
/* ========== check_store_binding ========================================= */
/*
* DESCRIPTION:
* Check what's already on the hash table with the new symbol binding
* information from the dependencies and record it into the bucket.
*/
/* ======================================================================== */
static void
{
unsigned long bktno;
unsigned long orig_bktno;
unsigned long i;
orig_bktno = bktno;
return;
} else {
if (i == orig_bktno)
break;
continue;
break;
}
}
}
}
/* ========== stringcompare =============================================== */
/*
* DESCRIPTION:
* Compares two strings for qsort().
*/
/* ======================================================================== */
static int
binding_bucket * b)
{
char *x = "\0";
char *y = "\0";
int retcode;
if (a->sym)
x = a->sym;
if (b->sym)
y = b->sym;
return (retcode);
}
/* ========== profile_binding ============================================= */
/*
* DESCRIPTION:
* Output the bindings directly to stdout or a file.
*/
/* ======================================================================== */
static void
{
char *ref_lib_ptr;
ref_lib_ptr++;
"%s|%s|%s|%s|%s|%s|%s\n",
"%s|%s|%s|%s|%s|%s|%s\n",
"%s|%s|%s|%s|%s\n",
}
/* ========== output_binding ============================================== */
/*
* DESCRIPTION:
* Output the hash table to either stdout or a file.
*/
/* ======================================================================== */
static void
output_binding(char *prog_name,
char *target)
{
int i;
char *ref_lib_ptr;
sizeof (binding_bucket),
(int (*) (const void *, const void *)) stringcompare);
if (oflag) {
if (sflag)
"\nfopen failed to open <%s>...\n\n",
exit(1);
}
}
/* generates profile report */
"#generated by %s\n",
"#profiling symbols in .text section of %s\n",
target);
for (i = 0; i < DEFBKTS; i++) {
ref_lib_ptr++;
"%s|%s|%s|%s|%s|%s|%s\n",
"%s|%s|%s|%s|%s|%s|%s\n",
"%s|%s|%s|%s|%s\n",
}
}
/* ========== obj_init ==================================================== */
/*
* DESCRIPTION:
* Open (object) file, get ELF descriptor, and verify that the file is
* an ELF file.
*/
/* ======================================================================== */
static int
{
/* open the file */
if (sflag) {
"Cannot open <<%s>> : \
No such file or directory.\n",
"File <<%s>> : Already opened.\n",
}
return (FAIL);
}
/*
* queries the ELF library's internal version.
* Passing ver equal to EV_NONE causes elf_version() to return
* the library's internal version, without altering the working
* version. If ver is a version known to the library,
* elf_version() returns the previous or initial working
* version number. Otherwise, the working version remains
* unchanged and elf_version() returns EV_NONE.
*/
/* check if libelf.so is at the right level */
if (sflag)
"Library out of date in ELF access routines.\n");
return (FAIL);
}
/*
* Before the first call to elf_begin(), it must call
* elf_version() to coordinate versions.
*/
/*
* get elf descriptor just to examine the contents of an existing
* file
*/
== (Elf *) 0) {
if (sflag)
"File is not in executable and \
linking format(ELF).\n");
return (FAIL);
}
/* Rule out COFF, a.out and shell script files */
if (sflag) {
"File is not in executable \
and linking format(ELF) or archive.\n");
}
return (FAIL);
}
if (sflag) {
"File is not in executable and linking \
format(ELF) or archive.\n");
}
return (FAIL);
}
return (SUCCEED);
}
/* ========== obj_elf_hdr ================================================= */
/*
* DESCRIPTION:
* Obtain the elf header, verify elf header information
*/
/* ======================================================================== */
static int
obj_elf_hdr(obj_list * c)
{
#if defined(_LP64)
#else
#endif
/*
* get the elf header if one is available for the ELF descriptor
* c->elf
*/
#if defined(_LP64)
if (sflag)
"File is not in 64-bit format.\n");
return (FAIL);
}
#else
if (sflag)
"File is not in 32-bit format.\n");
return (FAIL);
}
#endif
/* if there is elf header, save the pointer */
#if defined(_LP64)
#else
#endif
/* e_ident[] is identification index which holds values */
/*
* we could also use elf_getident() to retrieve file identification
* data.
*/
/*
* e_ident[EI_CLASS] identifies the file's class:
* ELFCLASSNONE - invalid class
* ELFCLASS32 - 32-bit objects
* ELFCLASS64 - 64-bit objects
*/
#if defined(_LP64)
if (sflag)
"File is not in 64-bit format.\n");
return (FAIL);
}
#else
if (sflag)
"File is not in 32-bit format.\n");
return (FAIL);
}
#endif
/*
* e_ident[EI_DATA] specifies the data encoding of the
* processor-specific data in the object file:
* ELFDATANONE - invalid data encoding
* ELFDATA2LSB - specifies 2's complement values, with the least
* significant byte occupying the lowest address
* ELFDATA2MSB - specifies 2's complement values, with the most
* significant byte occupying the lowest address
*/
/*
* e_ident[EI_VERSION] specifies the ELF header version number.
* Currently, this value must be EV_CURRENT.
*/
if (sflag)
"File is recorded in an \
incompatible ELF version.\n");
return (FAIL);
}
/* only interested in relocatable, shared object, or executable file */
case ET_REL:
case ET_EXEC:
case ET_DYN:
break;
default:
if (sflag) {
"File is not relocatable, ");
"executable, or shared object.\n");
}
return (FAIL);
}
/*
* e_machine's value specifies the required architecture for an
* individual file
*/
#if defined(__sparcv9)
if (sflag)
"File is not for 64-bit \
SPARC machine architecture.\n");
return (FAIL);
}
if (sflag)
"File is not for 64-bit \
amd64 machine architecture.\n");
return (FAIL);
}
if (sflag)
"File is not for 32-bit \
i386 machine architecture.\n");
return (FAIL);
}
#else
if (sflag)
"File is not for 32-bit \
SPARC machine architecture.\n");
return (FAIL);
}
#endif
return (SUCCEED);
}
/* ========== obj_prog_hdr ============================================= */
/*
* DESCRIPTION:
* For executable files and shared objects only, check if it has
* a program header table.
*/
/* ===================================================================== */
static int
obj_prog_hdr(obj_list * c)
{
/*
* Assume: the elf header has already been read, and the file
* has already been determined to be
* executable, shared object, or relocatable
*/
/*
* Program headers are meaningful only for executable and shared
* object files. It is an array of structures, each describing a
* segment or other information needs to prepare the program for
* execution.
*/
/* skip if file is not executable or shared object */
/* e_type == ET_REL meaning Relocatable file */
return (SUCCEED);
/*
* ehdr->e_phoff holds the program header table's file offset in
* bytes.
*/
/* If the file has no program header table, this member holds zero. */
/*
* ehdr->e_phnum holds the number of entries in the program header
* table.
*/
/*
* If a file has no program header table, e_phnum holds the value
* zero.
*/
/* make sure there's a program header table */
if (sflag)
"File has no program header table.\n");
return (FAIL);
}
return (SUCCEED);
}
/* ========== find_dynamic_sect ========================================== */
/*
* DESCRIPTION:
* Find the dynamic section.
*/
/* ======================================================================= */
static int
{
#if defined(_LP64)
#else
#endif
/* only process executables and shared objects */
return (SUCCEED);
/* there are no sections */
return (SUCCEED);
}
/* search the section header table for dynamic section */
/* start with null section; section index = 0 */
scn = 0;
/* retrieve the section header */
#if defined(_LP64)
#else
#endif
/* check for dynamic section; (i.e., .dynamic) */
ddata = 0;
return (SUCCEED);
/* now, we got data of dynamic section */
/* index to section header for dynamic string table */
/* get scn descriptor of dynamic string table */
/* get dynamic string table section header */
#if defined(_LP64)
#else
#endif
/* get the dynamic string table data descriptor */
/* save the pointer to dynamic string table data */
/*
* now, we got dynamic strtab and dynamic section
* information
*/
break;
}
}
return (SUCCEED);
}
/* ========== find_symtabs ================================================ */
/*
* DESCRIPTION:
* Find and check symbol tables for an application file
*/
/* ======================================================================== */
static int
find_symtabs(obj_list * c)
{
#if defined(_LP64)
#else
#endif
scn = 0;
/*
* loop through the section header table looking for symbol tables.
* There must be one or two: .symtab and .dynsym
* upon finding a symbol table, save its pointer in obj_com.
*/
/* get section descriptor */
#if defined(_LP64)
#else
#endif
int symn;
char *strs;
/* point to section header */
#if defined(_LP64)
#else
#endif
if (shdr == 0)
return (FAIL);
/* skip if this section is not a symbol table */
continue;
/* get data descriptor for the symbol table itself */
continue;
/* save pointer to symbol table */
#if defined(_LP64)
#else
#endif
/*
* now start looking for the string table associated with
* this symbol table section
*/
/* get section descriptor first */
continue;
/* get data descriptor for the string table section */
continue;
/* save pointer to name string table */
/* save information in obj_com */
} else { /* must be the dynamic linking symbol table */
} /* end if */
} /* end while */
return (SUCCEED);
}
/* ========== obj_app_symtab ============================================== */
/*
* DESCRIPTION:
* Check existence of application's symbol tables.
*/
/* ======================================================================== */
static int
obj_app_symtab(obj_list * c)
{
/* issue error if a relocatable file has no symbol table */
if (sflag)
"ELF error: no symbol \
table in object file.\n");
return (FAIL);
} else {
if (sflag) {
"Warning: Binary is \
completely statically \
linked and stripped.\n");
}
return (FAIL);
}
if (sflag)
"Binary is stripped.\n");
}
}
return (SUCCEED);
}
/* ========== obj_finis =================================================== */
/*
* DESCRIPTION:
* It checks the c->fd and c->elf pointers. If they are not NULL,
* close the file descriptor and ELF descriptor.
*/
/* ======================================================================== */
static void
{
obj_list *p;
if (c) {
while (c) {
p = c;
c = c->next;
free(p);
}
}
}
/* ========= is_text_section ============================================== */
/*
* DESCRIPTION:
* Scan through every section and returns TRUE(1) if the given section
* is ".text", otherwise, returns FALSE(0).
* INPUTS: shndx - section header index
* elf_file - ELF descriptor of the object file under test
* ehdr - ELF header of the object file under test
*/
/* ======================================================================== */
static int
is_text_section(int shndx,
#if defined(_LP64)
Elf64_Ehdr * ehdr)
#else
Elf32_Ehdr * ehdr)
#endif
{
char *sym_name;
#if defined(_LP64)
#else
#endif
return (1);
}
return (0);
}
/* ========== scan_archive_symbols ======================================= */
/*
* DESCRIPTION:
* Scan through the archive symbol tables and write them out.
* INPUTS: syms - pointer to application symbol table
* symn - number of entries in application symbol table
* buf - first byte of application string table
*/
/* ======================================================================= */
static void
#if defined(_LP64)
#else
#endif
int symn,
char *buf,
#if defined(_LP64)
Elf64_Ehdr * ehdr)
#else
Elf32_Ehdr * ehdr)
#endif
{
#if defined(_LP64)
#else
#endif
int i;
char *sym_name;
int sttype;
int stbind;
symtab_entry = syms;
for (i = 0; i < symn; i++, symtab_entry++) {
/* look only at .text section symbols */
continue;
/* look only at weak and global symbols */
#if defined(_LP64)
#else
#endif
if (stbind != STB_GLOBAL) {
continue;
}
/* look only at functions and objects */
#if defined(_LP64)
#else
#endif
if (sttype != STT_OBJECT)
continue;
}
binding = (struct binding_bucket *)
malloc(sizeof (binding_bucket));
if (stbind == STB_GLOBAL)
else if (sttype == STT_OBJECT)
if (pflag)
else
} /* end for */
}
/* ========== scan_symbols ================================================ */
/*
* DESCRIPTION:
* Scan through the symbol table and write them out.
* INPUTS: syms - pointer to application symbol table
* symn - number of entries in application symbol table
* buf - first byte of application string table
*/
/* ======================================================================== */
static void
scan_symbols(obj_list * c,
#if defined(_LP64)
#else
#endif
int symn,
char *buf)
{
#if defined(_LP64)
#else
#endif
int i;
char *sym_name;
int sttype;
int stbind;
symtab_entry = syms;
if (pflag) {
"#profiling symbols in .text section of %s\n",
}
for (i = 0; i < symn; i++, symtab_entry++) {
/* look only at .text section symbols */
continue;
/* look only at weak and global symbols */
#if defined(_LP64)
#else
#endif
if (stbind != STB_GLOBAL) {
continue;
}
/* look only at functions and objects */
#if defined(_LP64)
#else
#endif
if (sttype != STT_OBJECT)
continue;
}
binding = (struct binding_bucket *)
malloc(sizeof (binding_bucket));
if (stbind == STB_GLOBAL)
else if (sttype == STT_OBJECT)
if (pflag)
else
} /* end for */
}
/* ========= bind_symbols ================================================= */
/*
* DESCRIPTION:
* Scan through the dynamic symbol table and write them out.
* INPUTS: syms - pointer to application symbol table
* symn - number of entries in application symbol table
* buf - first byte of application string table
*/
/* ======================================================================== */
static void
bind_symbols(obj_list * c,
#if defined(_LP64)
#else
#endif
int symn,
char *buf)
{
#if defined(_LP64)
#else
#endif
int i;
char *sym_name;
int sttype;
int stbind;
symtab_entry = syms;
for (i = 0; i < symn; i++, symtab_entry++) {
/* look only at global symbols */
#if defined(_LP64)
#else
#endif
continue;
continue;
if (stbind != STB_GLOBAL) {
continue;
}
/* look only at functions and objects */
#if defined(_LP64)
#else
#endif
if (sttype != STT_OBJECT)
continue;
}
if (!pflag)
} /* end for */
}
/* ========== get_scnfd =================================================== */
/*
* DESCRIPTION:
* Gets section descriptor for the associated string table
* and verifies that the type of the section pointed to is
* indeed of type STRTAB. Returns a valid section descriptor
* or NULL on error.
*/
/* ======================================================================== */
static Elf_Scn *
int shstrtab,
int SCN_TYPE)
{
#if defined(_LP64)
#else
#endif
return (NULL);
#if defined(_LP64)
#else
#endif
return (NULL);
return (scn_fd);
}
/* ========== print_symtab ================================================ */
/*
* DESCRIPTION:
* Outputs symbol bindings from symbol table to hash table.
*/
/* ======================================================================== */
static void
#if defined(_LP64)
Elf64_Ehdr * ehdr,
Elf64_Shdr * shdr,
#else
Elf32_Ehdr * ehdr,
Elf32_Shdr * shdr,
#endif
char *filename)
{
#if defined(_LP64)
#else
#endif
int count = 0;
obj_list *c;
if (sflag)
"%s - No symbol table data\n",
return;
}
#if defined(_LP64)
#else
#endif
return;
return;
if (sflag)
"%s: Problem reading symbol data\n",
return;
}
if (aflag)
(void) scan_archive_symbols(c,
ehdr);
else
(void) bind_symbols(c,
free(c);
}
/* ========== get_symtab ================================================== */
/*
* DESCRIPTION:
* Gets the symbol table. This function does not output the contents
* of the symbol table but sets up the parameters and then calls
* print_symtab() to output the symbol bindings.
*/
/* ======================================================================== */
static void
get_symtab(obj_list * c,
#if defined(_LP64)
Elf64_Ehdr * ehdr,
#else
Elf32_Ehdr * ehdr,
#endif
char *filename)
{
#if defined(_LP64)
#else
#endif
/* get section header string table */
if (sflag)
"%s: Could not get string table\n",
filename);
return;
}
if (sflag)
"%s: No data in string table\n",
filename);
return;
}
scn = 0;
#if defined(_LP64)
#else
#endif
{
if (sflag)
"%s: %s:\n",
elf_errmsg(-1));
return;
}
} /* end while */
}
/* ========== process ===================================================== */
/*
* DESCRIPTION:
* Gets the ELF header and, if it exists, call get_symtab() to begin
* processing of the file; otherwise, returns with a warning.
*/
/* ======================================================================== */
static void
char *filename)
{
#if defined(_LP64)
#else
#endif
#if defined(_LP64)
#else
#endif
{
if (sflag)
"%s: %s\n",
return;
}
}
/* ========== process_archive ============================================= */
/*
* DESCRIPTION:
* Processes member files of an archive. This function provides
* a loop through an archive equivalent the processing of each_file
* for individual object file.
*/
/* ======================================================================== */
static int
process_archive(obj_list * c)
{
if (sflag)
"%s: %s\n",
return (FAIL);
}
continue;
}
} else {
continue;
}
} /* end while */
return (SUCCEED);
}
/* ========== add_dtneeded ================================================ */
/*
* DESCRIPTION:
* Inserts a new node into the linked list. It is basically for
* generating a simple linked list of DT_NEEDED entries.
*/
/* ======================================================================== */
static dt_list *
add_dtneeded(dt_list * p,
{
if (!head)
else {
return (head);
}
return (head);
}
}
}
return (head);
}
/* ========== find_dtneeded =============================================== */
/*
* DESCRIPTION:
* Find the DT_NEEDED, DT_FILTER, and DT_AUXILIARY entries, and save
* them to link list.
*/
/* ======================================================================== */
static void
find_dtneeded(obj_list * c)
{
#if defined(_LP64)
#else
#endif
if (!dcurrent)
return;
/*
* If there are any DT_NEEDED
* entries, add them to the dt_needed list.
*/
}
dcurrent++;
}
}
/* ========= obj_elfcheck ================================================= */
/*
* DESCRIPTION:
* It checks the elf header and saves its pointer if succeeds.
* It checks the program header and saves its pointer if succeed.
* It checks the section header table and saves its pointer to
* section header table and section header string table if it
* succeeds. It finds dynsym symbol table and saves its pointer.
* It finds symtab and saves its pointers.
*/
/* ======================================================================== */
static int
obj_elfcheck(obj_list * c)
{
/* open the file and ELF descriptor */
obj_finis(c);
return (FAIL);
}
/* if it is an archive library */
if (process_archive(c) == SUCCEED)
return (SUCCEED);
else
return (FAIL);
}
/* get the ELF header information */
if (obj_elf_hdr(c) == FAIL) {
obj_finis(c);
return (FAIL);
}
/* get the program header for dynamic, etc. */
if (obj_prog_hdr(c) == FAIL) {
obj_finis(c);
return (FAIL);
}
/* find and save pointers to application symbol tables */
if (find_symtabs(c) == FAIL) {
obj_finis(c);
return (FAIL);
}
/* check the existence of application's symbol tables */
if (obj_app_symtab(c) == FAIL) {
obj_finis(c);
return (FAIL);
}
/* find and save pointers to the dynamic section */
if (find_dynamic_sect(c) == FAIL) {
obj_finis(c);
return (FAIL);
}
/*
* find the DT_NEEDED entries and save the name to dt_needed link
* list
*/
(void) find_dtneeded(c);
return (SUCCEED);
}
/* ========= analyze_dependency ========================================== */
/*
* DESCRIPTION:
* Read in an dependency object file and analyze it.
* INPUTS: dep_file - dependency object file name
*/
/* ======================================================================= */
static int
analyze_dependency(char *dep_file)
{
if (!dep_file)
return (SUCCEED);
return (FAIL);
return (SUCCEED);
}
/* ========= analyze_main =============================================== */
/*
* DESCRIPTION:
* Read in an object file and analyze it.
*/
/* ====================================================================== */
static void
analyze_main(obj_list * c)
{
int i;
if (obj_elfcheck(c) == FAIL)
exit(1);
scan_symbols(c,
scan_symbols(c,
c->obj->dsym_names);
return;
}
/* ========= analyze_args ================================================= */
/*
* DESCRIPTION:
* Analyze the command-line options.
*/
/* ======================================================================== */
static int
analyze_args(obj_list * c,
int argc,
char *argv[])
{
extern char *optarg;
extern int optind;
int option;
int i;
char *nameptr;
char slash = '/';
int errflg = 0;
nameptr++;
else
switch (option) {
case 'p': /* just do profiling; write to stdout */
pflag = 1;
break;
case 's': /* silent mode to turn off stderr messages */
sflag = 0;
break;
case 'o': /* redirects the output */
outputfile = optarg;
oflag = 1;
break;
case 'a': /* processes archive as input */
aflag = 1;
break;
case '?':
default:
errflg++;
} /* end switch */
} /* end while */
/* exit if there are no files to process */
errflg++;
if (errflg) {
"usage: %s [-p] [-s] [-o outputfile] ", nameptr);
"<archive>|<binary_executable>\n");
"\t\t [<archive>|<dynamic library>...]\n");
return (FALSE);
} /* end if */
/* compute number of files and save their pointers */
i = 0;
malloc(sizeof (char *) *
}
return (TRUE);
}
/* ======================================================================= */
/*
* Here starts the main ()
*/
/* ======================================================================= */
void
char **argv)
{
dt_list *q;
exit(1);
if (sflag)
"\nfopen failed to open <%s>...\n\n",
exit(1);
}
}
/* generates profile report if pflag is set */
if (pflag)
"#generated by %s\n",
argv[0]);
/* analyze the input file */
/* generates profile report */
if (!pflag)
/* close the library .so file descriptor and ELF descriptor */
/* de-allocates the dt_needed link list */
if (dt_needed) {
while (dt_needed) {
q = dt_needed;
free(q);
}
}
/* close the output redirect file descriptor */
if (oflag)
exit(0);
}