pvs.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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Analyze the versioning information within a file.
*
* -C demangle C++ symbol names.
*
* -d dump version definitions.
*
* -l print reduced (local) symbols.
*
* -n normalize any version definitions.
*
* -o dump output in one-line fashion (more suitable for grep'ing
* and diff'ing).
*
* -r dump the version requirements on library dependencies
*
* -s display the symbols associated with each version definition.
*
* -v verbose output. With the -r and -d options any WEAK attribute
* is displayed. With the -d option, any version inheritance,
* and the base version are displayed. With the -s option the
* version symbol is displayed.
*
* -N name only print the specifed `name'.
*/
#include <fcntl.h>
#include <stdio.h>
#include <libelf.h>
#include <link.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <errno.h>
#include "sgs.h"
#include "conv.h"
#include "debug.h"
#include "gelf.h"
#include "msg.h"
#define FLG_VER_AVAIL 0x10
typedef struct cache {
char *c_name;
} Cache;
typedef struct gver_desc {
const char *vd_name;
unsigned long vd_hash;
} GVer_desc;
static const char *cname;
static const char
* Format_ofil = "%s -",
* Format_tnco = "\t%s:\n",
* Format_tnse = "\t%s;\n",
* Format_bgnl = "\t%s (%s",
* Format_next = ", %s",
* Format_weak = " [WEAK]",
* Format_endl = ");\n";
#define DEF_DEFINED 1
#define USR_DEFINED 2
/*
* Determine whether a symbol name should be demangled.
*/
static const char *
{
if (Cflag)
return (Gelf_sym_dem(name));
else
return (name);
}
/*
* Define our own printing routine. We don't actually use this, but because
* we use liblddbg to demangle symbols we need to provide this to satisfy
* liblddbg's binding requirements.
*/
/*PRINTFLIKE1*/
void
{
}
/*
* Print any reduced symbols. The convention is that reduced symbols exist as
* LOCL entries in the .symtab, between the FILE symbol for the output file and
* the first FILE symbol for any input file used to build the output file.
*/
static void
{
/* LINTED */
/*
* Verify symtab[1] is the output file symbol.
*/
file);
return;
}
/*
* Scan the remaining symbols until the next file symbol is found.
*/
const char *name;
continue;
break;
/*
* Its possible that section symbols are followed immediately
* by globals. This is the case if an object (filter) is
* generated exclusively from mapfile symbol definitions.
*/
break;
if (oflag) {
} else {
if (found == 0) {
found = 1;
}
}
}
}
/*
* Print the files version needed sections.
*/
static int
{
char *strs;
int error = 0;
/*
* Verify the version revision. We only check the first version
* structure as it is assumed all other version structures in this
* data section will be of the same revision.
*/
/*
* Get the data buffer for the associated string table.
*/
/*
* Obtain the version name and determine if we need to process
* it further.
*/
continue;
error = 1;
/*
* If one-line ouput is called for display the filename being
* processed.
*/
if (oflag)
/*
* Determine the version name required from this file.
*/
if (cnt--)
else
(void) printf(Format_weak);
/*
* Extract any other version dependencies for this file
*/
/* CSTYLED */
(void) printf(Format_weak);
}
(void) printf(Format_endl);
}
return (error);
}
/*
* Append an item to the specified list, and return a pointer to the list
* node created.
*/
static Listnode *
{
exit(1);
}
else {
}
return (_lnp);
}
static GVer_desc *
{
continue;
return (vdp);
}
return (0);
}
static GVer_desc *
{
exit(1);
}
return (0);
}
return (vdp);
}
static GVer_desc *
const char *file)
{
return (0);
return (0);
return (vdp);
}
static void
{
int _symn;
const char *name;
continue;
/*
* For data symbols determine the size.
*/
/*
* Only output the version symbol when the verbose flag is used.
*/
continue;
}
if (oflag) {
if (size)
else
} else {
if (size)
else
}
}
}
static void
{
/*
* If the head of the list was a weak then we only clear out
* weak dependencies, but if the head of the list was 'strong'
* we clear the REFER bit on all dependencies.
*/
}
static void
{
if (!oflag)
}
}
/*
* Print the files version definition sections.
*/
static int
const char *name)
{
char *strs;
int symn;
int error = 0;
/*
* Verify the version revision. We only check the first version
* structure as it is assumed all other version structures in this
* data section will be of the same revision.
*/
}
/*
* Get the data buffer for the associated string table.
*/
/*
* Process the version definitions placing each on a version dependency
* list.
*/
const char *_name;
/*
* Determine the version name and any dependencies.
*/
file)) == 0)
return (0);
return (0);
}
/*
* Remember the base version for possible later use.
*/
if (ndx == VER_NDX_GLOBAL)
}
/*
* Normalize the dependency list if required.
*/
if (nflag) {
}
/*
* Always dereference the base version.
*/
if (bvdp)
}
/*
* Traverse the dependency list and print out the appropriate
* information.
*/
int count;
continue;
continue;
error = 1;
if (vflag) {
/*
* If the verbose flag is set determine if this version
* has a `weak' attribute, and print any version
* dependencies this version inherits.
*/
if (oflag)
(void) printf(Format_weak);
count = 1;
if (count++ == 1) {
if (oflag)
else
(void) printf(": \t{%s",
_name);
} else
}
if (count != 1)
(void) printf("}");
(void) printf(":\n");
else
(void) printf(";\n");
} else {
else if (!csym) {
if (oflag)
}
}
/*
* If we need to print symbols get the associated symbol table.
*/
if (csym) {
/* LINTED */
} else
continue;
/*
* If a specific version name has been specified then display
* any of its own symbols plus any inherited from other
* versions. Otherwise simply print out the symbols for this
* version.
*/
if (name) {
/*
* If the verbose flag is set add the base version as a
* dependency (unless it's the list we were asked to
* print in the first place).
*/
if (!oflag)
file);
}
}
}
return (error);
}
int
{
const char *name;
char *names;
int error = 0;
/*
* Check for a binary that better fits this architecture.
*/
/*
* Establish locale.
*/
opterr = 0;
switch (var) {
case 'C':
Cflag = USR_DEFINED;
break;
case 'd':
dflag = USR_DEFINED;
break;
case 'l':
lflag = USR_DEFINED;
break;
case 'n':
nflag = USR_DEFINED;
break;
case 'o':
oflag = USR_DEFINED;
break;
case 'r':
rflag = USR_DEFINED;
break;
case 's':
sflag = USR_DEFINED;
break;
case 'v':
vflag = USR_DEFINED;
break;
case 'N':
break;
case '?':
cname);
exit(1);
default:
break;
}
}
/*
* No files specified on the command line?
*/
exit(1);
}
/*
* By default print both version definitions and needed dependencies.
*/
/*
* Open the input file and initialize the elf interface.
*/
error = 1;
continue;
}
(void) elf_version(EV_CURRENT);
error = 1;
continue;
}
file);
error = 1;
continue;
}
error = 1;
continue;
}
/*
* Obtain the .shstrtab data buffer to provide the required
* section name strings.
*/
error = 1;
continue;
}
error = 1;
continue;
}
/*
* Fill in the cache descriptor with information for each
* section we might need. We probably only need to save
* read-only allocable sections as this is where the version
* structures and their associated symbols and strings live.
* However, God knows what someone can do with a mapfile, and
* as elf_begin has already gone through all the overhead we
* might as well set up the cache for every section.
*/
exit(1);
}
_cache++;
elf_errmsg(elf_errno()));
error = 1;
continue;
}
NULL) {
elf_errmsg(elf_errno()));
error = 1;
continue;
}
/*
* Remember the version sections and symbol table.
*/
_cache_def = _cache;
_cache_sym = _cache;
_cache_loc = _cache;
}
/*
* Before printing anything out determine if any warnings are
* necessary.
*/
if (lflag && (_cache_loc == 0)) {
}
/*
* If there is more than one input file, and we're not printing
* one-line output, display the filename being processed.
*/
/*
* Print the files version needed sections.
*/
if (_cache_need)
/*
* Print the files version definition sections.
*/
if (_cache_def)
/*
* Print any local symbol reductions.
*/
if (_cache_loc)
/*
* Determine the error return. There are three conditions that
* may produce an error (a non-zero return):
*
* o if the user specified -d and no version definitions
* were found.
*
* o if the user specified -r and no version requirements
* were found.
*
* o if the user specified neither -d or -r, (thus both are
* enabled by default), and no version definitions or
* version dependencies were found.
*/
error = 1;
}
return (error);
}
const char *
{
}