process.c revision 8a16d130bdea488abf40f6692135d3c5b462fda4
/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1988 AT&T */
/* Copyright (c) 1989 AT&T */
/* All Rights Reserved */
/* UNIX HEADER */
#include <stdio.h>
/* SIZE HEADERS */
#include "defs.h"
/* ELF HEADERS */
#include "gelf.h"
/* SIZE FUNCTIONS CALLED */
extern void error();
/* FORMAT STRINGS */
static const char *prusect[3] = {
"%llx",
"%llo",
"%lld"
};
static const char *prusum[3] = {
" = 0x%llx\n",
" = 0%llo\n",
" = %lld\n"
};
static const char *format[3] = {
"%llx + %llx + %llx = 0x%llx\n",
"%llo + %llo + %llo = 0%llo\n",
"%lld + %lld + %lld = %lld\n"
};
static void process_phdr(Elf *elf, GElf_Half num);
void
process(Elf * elf)
{
/* EXTERNAL VARIABLES USED */
extern int fflag; /* full format for sections */
extern int Fflag; /* full format for segments */
extern int nflag; /* include non-loadable segments or sections */
extern int numbase; /* hex, octal, or decimal */
extern char *fname;
extern char *archive;
extern int is_archive;
extern int oneflag;
/* LOCAL VARIABLES */
GElf_Xword size; /* total size in non-default case for sections */
/*
* size of first, second, third number and total size
* in default case for sections.
*/
GElf_Xword first;
GElf_Xword second;
GElf_Xword third;
GElf_Xword totsize;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
Elf_Scn *scn;
size_t ndx = 0, shnum = 0;
int numsect = 0;
int notfirst = 0;
int i;
char *name = 0;
/*
* If there is a program header and the -f flag requesting section infor-
* mation is not set, then process segments with the process_phdr function.
* Otherwise, process sections. For the default case, the first number
* shall be the size of all sections that are allocatable, nonwritable and
* not of type NOBITS; the second number shall be the size of all sections
* that are allocatable, writable, and not of type NOBITS; the third number
* is the size of all sections that are writable and not of type NOBITS.
* If -f is set, print the size of each allocatable section, followed by
* the section name in parentheses.
* If -n is set, print the size of all sections, followed by the section
* name in parentheses.
*/
if (gelf_getehdr(elf, &ehdr) == 0) {
error(fname, "invalid file type");
return;
}
if ((ehdr.e_phnum != 0) && !(fflag)) {
process_phdr(elf, ehdr.e_phnum);
return;
}
if (is_archive) {
(void) printf("%s[%s]: ", archive, fname);
} else if (!oneflag && !is_archive) {
(void) printf("%s: ", fname);
}
if (elf_getshdrstrndx(elf, &ndx) == -1)
error(fname, "no string table");
scn = 0;
size = 0;
first = second = third = totsize = 0;
if (elf_getshdrnum(elf, &shnum) == -1)
error(fname, "can't get number of sections");
if (shnum == 0)
error(fname, "no section data");
numsect = shnum;
for (i = 0; i < numsect; i++) {
if ((scn = elf_nextscn(elf, scn)) == 0) {
break;
}
if (gelf_getshdr(scn, &shdr) == 0) {
error(fname, "could not get section header");
break;
}
if ((Fflag) && !(fflag)) {
error(fname, "no segment data");
return;
} else if ((!(shdr.sh_flags & SHF_ALLOC)) &&
fflag && !(nflag)) {
continue;
} else if ((!(shdr.sh_flags & SHF_ALLOC)) && !(nflag)) {
continue;
} else if ((shdr.sh_flags & SHF_ALLOC) &&
(!(shdr.sh_flags & SHF_WRITE)) &&
(!(shdr.sh_type == SHT_NOBITS)) &&
!(fflag) && !(nflag)) {
first += shdr.sh_size;
} else if ((shdr.sh_flags & SHF_ALLOC) &&
(shdr.sh_flags & SHF_WRITE) &&
(!(shdr.sh_type == SHT_NOBITS)) &&
!(fflag) && !(nflag)) {
second += shdr.sh_size;
} else if ((shdr.sh_flags & SHF_WRITE) &&
(shdr.sh_type == SHT_NOBITS) &&
!(fflag) && !(nflag)) {
third += shdr.sh_size;
}
name = elf_strptr(elf, ndx, (size_t)shdr.sh_name);
if (fflag || nflag) {
size += shdr.sh_size;
if (notfirst) {
(void) printf(" + ");
}
(void) printf(prusect[numbase], shdr.sh_size);
(void) printf("(%s)", name);
}
notfirst++;
}
if ((fflag || nflag) && (numsect > 0)) {
(void) printf(prusum[numbase], size);
}
if (!fflag && !nflag) {
totsize = first + second + third;
(void) printf(format[numbase],
first, second, third, totsize);
}
if (Fflag) {
if (ehdr.e_phnum != 0) {
process_phdr(elf, ehdr.e_phnum);
return;
} else {
error(fname, "no segment data");
return;
}
}
}
/*
* If there is a program exection header, process segments. In the default
* case, the first number is the file size of all nonwritable segments
* of type PT_LOAD; the second number is the file size of all writable
* segments whose type is PT_LOAD; the third number is the memory size
* minus the file size of all writable segments of type PT_LOAD.
* If the -F flag is set, size will print the memory size of each loadable
* segment, followed by its permission flags.
* If -n is set, size will print the memory size of all loadable segments
* and the file size of all non-loadable segments, followed by their
* permission flags.
*/
static void
process_phdr(Elf * elf, GElf_Half num)
{
int i;
int notfirst = 0;
GElf_Phdr p;
GElf_Xword memsize;
GElf_Xword total;
GElf_Xword First;
GElf_Xword Second;
GElf_Xword Third;
GElf_Xword Totsize;
extern int Fflag;
extern int nflag;
extern int numbase;
extern char *fname;
extern char *archive;
extern int is_archive;
extern int oneflag;
memsize = total = 0;
First = Second = Third = Totsize = 0;
if (is_archive) {
(void) printf("%s[%s]: ", archive, fname);
} else if (!oneflag && !is_archive) {
(void) printf("%s: ", fname);
}
for (i = 0; i < (int)num; i++) {
if (gelf_getphdr(elf, i, &p) == NULL) {
error(fname, "no segment data");
return;
}
if ((!(p.p_flags & PF_W)) &&
(p.p_type == PT_LOAD) && !(Fflag)) {
First += p.p_filesz;
} else if ((p.p_flags & PF_W) &&
(p.p_type == PT_LOAD) && !(Fflag)) {
Second += p.p_filesz;
Third += p.p_memsz;
}
memsize += p.p_memsz;
if ((p.p_type == PT_LOAD) && nflag) {
if (notfirst) {
(void) printf(" + ");
}
(void) printf(prusect[numbase], p.p_memsz);
total += p.p_memsz;
notfirst++;
}
if (!(p.p_type == PT_LOAD) && nflag) {
if (notfirst) {
(void) printf(" + ");
}
(void) printf(prusect[numbase], p.p_filesz);
total += p.p_filesz;
notfirst++;
}
if ((p.p_type == PT_LOAD) && Fflag && !nflag) {
if (notfirst) {
(void) printf(" + ");
}
(void) printf(prusect[numbase], p.p_memsz);
notfirst++;
}
if ((Fflag) && !(nflag) && (!(p.p_type == PT_LOAD))) {
continue;
}
if (Fflag || nflag) {
switch (p.p_flags) {
case 0: (void) printf("(---)"); break;
case PF_X: (void) printf("(--x)"); break;
case PF_W: (void) printf("(-w-)"); break;
case PF_W+PF_X: (void) printf("(-wx)"); break;
case PF_R: (void) printf("(r--)"); break;
case PF_R+PF_X: (void) printf("(r-x)"); break;
case PF_R+PF_W: (void) printf("(rw-)"); break;
case PF_R+PF_W+PF_X: (void) printf("(rwx)"); break;
default: (void) printf("flags(%#x)", p.p_flags);
}
}
}
if (nflag) {
(void) printf(prusum[numbase], total);
}
if (Fflag && !nflag) {
(void) printf(prusum[numbase], memsize);
}
if (!Fflag && !nflag) {
Totsize = First + Second + (Third - Second);
(void) printf(format[numbase],
First, Second, Third - Second, Totsize);
}
}