1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1988 AT&T     */
  27 /*      Copyright (c) 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 
  31 /* UNIX HEADER */
  32 #include <stdio.h>
  33 
  34 /* SIZE HEADERS */
  35 #include "defs.h"
  36 
  37 /* ELF HEADERS */
  38 #include "gelf.h"
  39 
  40 
  41 /* SIZE FUNCTIONS CALLED */
  42 extern void     error();
  43 
  44 
  45 /* FORMAT STRINGS */
  46 
  47 static const char *prusect[3] = {
  48         "%llx",
  49         "%llo",
  50         "%lld"
  51 };
  52 
  53 static const char *prusum[3] = {
  54         " = 0x%llx\n",
  55         " = 0%llo\n",
  56         " = %lld\n"
  57 };
  58 
  59 static const char *format[3] = {
  60         "%llx + %llx + %llx = 0x%llx\n",
  61         "%llo + %llo + %llo = 0%llo\n",
  62         "%lld + %lld + %lld = %lld\n"
  63 };
  64 
  65 static void     process_phdr(Elf *elf, GElf_Half num);
  66 
  67 void
  68 process(Elf * elf)
  69 {
  70         /* EXTERNAL VARIABLES USED */
  71         extern int      fflag; /* full format for sections */
  72         extern int      Fflag; /* full format for segments */
  73         extern int      nflag; /* include non-loadable segments or sections */
  74         extern int      numbase; /* hex, octal, or decimal */
  75         extern char     *fname;
  76         extern char     *archive;
  77         extern int      is_archive;
  78         extern int      oneflag;
  79 
  80         /* LOCAL VARIABLES */
  81         GElf_Xword      size; /* total size in non-default case for sections */
  82         /*
  83          * size of first, second, third number and total size
  84          * in default case for sections.
  85          */
  86         GElf_Xword      first;
  87         GElf_Xword      second;
  88         GElf_Xword      third;
  89         GElf_Xword      totsize;
  90         GElf_Ehdr       ehdr;
  91         GElf_Shdr       shdr;
  92         Elf_Scn         *scn;
  93         size_t          ndx = 0, shnum = 0;
  94         int             numsect = 0;
  95         int             notfirst = 0;
  96         int             i;
  97         char            *name = 0;
  98 
  99 
 100 /*
 101  * If there is a program header and the -f flag requesting section infor-
 102  * mation is not set, then process segments with the process_phdr function.
 103  * Otherwise, process sections.  For the default case, the first number
 104  * shall be the size of all sections that are allocatable, nonwritable and
 105  * not of type NOBITS; the second number shall be the size of all sections
 106  * that are allocatable, writable, and not of type NOBITS; the third number
 107  * is the size of all sections that are writable and not of type NOBITS.
 108  * If -f is set, print the size of each allocatable section, followed by
 109  * the section name in parentheses.
 110  * If -n is set, print the size of all sections, followed by the section
 111  * name in parentheses.
 112  */
 113 
 114         if (gelf_getehdr(elf, &ehdr) == 0) {
 115                 error(fname, "invalid file type");
 116                 return;
 117         }
 118         if ((ehdr.e_phnum != 0) && !(fflag)) {
 119                 process_phdr(elf, ehdr.e_phnum);
 120                 return;
 121         }
 122 
 123         if (is_archive) {
 124                 (void) printf("%s[%s]: ", archive, fname);
 125         } else if (!oneflag && !is_archive) {
 126                 (void) printf("%s: ", fname);
 127         }
 128         if (elf_getshdrstrndx(elf, &ndx) == -1)
 129                 error(fname, "no string table");
 130         scn = 0;
 131         size = 0;
 132         first = second = third = totsize = 0;
 133 
 134         if (elf_getshdrnum(elf, &shnum) == -1)
 135                 error(fname, "can't get number of sections");
 136 
 137         if (shnum == 0)
 138                 error(fname, "no section data");
 139 
 140         numsect = shnum;
 141         for (i = 0; i < numsect; i++) {
 142                 if ((scn = elf_nextscn(elf, scn)) == 0) {
 143                         break;
 144                 }
 145                 if (gelf_getshdr(scn, &shdr) == 0) {
 146                         error(fname, "could not get section header");
 147                         break;
 148                 }
 149                 if ((Fflag) && !(fflag)) {
 150                         error(fname, "no segment data");
 151                         return;
 152                 } else if ((!(shdr.sh_flags & SHF_ALLOC)) &&
 153                     fflag && !(nflag)) {
 154                         continue;
 155                 } else if ((!(shdr.sh_flags & SHF_ALLOC)) && !(nflag)) {
 156                         continue;
 157                 } else if ((shdr.sh_flags & SHF_ALLOC) &&
 158                     (!(shdr.sh_flags & SHF_WRITE)) &&
 159                     (!(shdr.sh_type == SHT_NOBITS)) &&
 160                     !(fflag) && !(nflag)) {
 161                         first += shdr.sh_size;
 162                 } else if ((shdr.sh_flags & SHF_ALLOC) &&
 163                     (shdr.sh_flags & SHF_WRITE) &&
 164                     (!(shdr.sh_type == SHT_NOBITS)) &&
 165                     !(fflag) && !(nflag)) {
 166                         second += shdr.sh_size;
 167                 } else if ((shdr.sh_flags & SHF_WRITE) &&
 168                     (shdr.sh_type == SHT_NOBITS) &&
 169                     !(fflag) && !(nflag)) {
 170                         third += shdr.sh_size;
 171                 }
 172                 name = elf_strptr(elf, ndx, (size_t)shdr.sh_name);
 173 
 174                 if (fflag || nflag) {
 175                         size += shdr.sh_size;
 176                         if (notfirst) {
 177                                 (void) printf(" + ");
 178                         }
 179                         (void) printf(prusect[numbase], shdr.sh_size);
 180                         (void) printf("(%s)", name);
 181                 }
 182                 notfirst++;
 183         }
 184         if ((fflag || nflag) && (numsect > 0)) {
 185                 (void) printf(prusum[numbase], size);
 186         }
 187 
 188         if (!fflag && !nflag) {
 189                 totsize = first + second + third;
 190                 (void) printf(format[numbase],
 191                     first, second, third, totsize);
 192         }
 193 
 194         if (Fflag) {
 195                 if (ehdr.e_phnum != 0) {
 196                         process_phdr(elf, ehdr.e_phnum);
 197                         return;
 198                 } else {
 199                         error(fname, "no segment data");
 200                         return;
 201                 }
 202         }
 203 }
 204 
 205 /*
 206  * If there is a program exection header, process segments. In the default
 207  * case, the first number is the file size of all nonwritable segments
 208  * of type PT_LOAD; the second number is the file size of all writable
 209  * segments whose type is PT_LOAD; the third number is the memory size
 210  * minus the file size of all writable segments of type PT_LOAD.
 211  * If the -F flag is set, size will print the memory size of each loadable
 212  * segment, followed by its permission flags.
 213  * If -n is set, size will print the memory size of all loadable segments
 214  * and the file size of all non-loadable segments, followed by their
 215  * permission flags.
 216  */
 217 
 218 static void
 219 process_phdr(Elf * elf, GElf_Half num)
 220 {
 221         int             i;
 222         int             notfirst = 0;
 223         GElf_Phdr       p;
 224         GElf_Xword      memsize;
 225         GElf_Xword      total;
 226         GElf_Xword      First;
 227         GElf_Xword      Second;
 228         GElf_Xword      Third;
 229         GElf_Xword      Totsize;
 230         extern int Fflag;
 231         extern int nflag;
 232         extern int numbase;
 233         extern char *fname;
 234         extern char *archive;
 235         extern int is_archive;
 236         extern int oneflag;
 237 
 238         memsize = total = 0;
 239         First = Second = Third = Totsize = 0;
 240 
 241         if (is_archive) {
 242                 (void) printf("%s[%s]: ", archive, fname);
 243         } else if (!oneflag && !is_archive) {
 244                 (void) printf("%s: ", fname);
 245         }
 246 
 247         for (i = 0; i < (int)num; i++) {
 248                 if (gelf_getphdr(elf, i, &p) == NULL) {
 249                         error(fname, "no segment data");
 250                         return;
 251                 }
 252                 if ((!(p.p_flags & PF_W)) &&
 253                     (p.p_type == PT_LOAD) && !(Fflag)) {
 254                         First += p.p_filesz;
 255                 } else if ((p.p_flags & PF_W) &&
 256                     (p.p_type == PT_LOAD) && !(Fflag)) {
 257                         Second += p.p_filesz;
 258                         Third += p.p_memsz;
 259                 }
 260                 memsize += p.p_memsz;
 261                 if ((p.p_type == PT_LOAD) && nflag) {
 262                         if (notfirst) {
 263                                 (void) printf(" + ");
 264                         }
 265                         (void) printf(prusect[numbase], p.p_memsz);
 266                         total += p.p_memsz;
 267                         notfirst++;
 268                 }
 269                 if (!(p.p_type == PT_LOAD) && nflag) {
 270                         if (notfirst) {
 271                                 (void) printf(" + ");
 272                         }
 273                         (void) printf(prusect[numbase], p.p_filesz);
 274                         total += p.p_filesz;
 275                         notfirst++;
 276                 }
 277                 if ((p.p_type == PT_LOAD) && Fflag && !nflag) {
 278                         if (notfirst) {
 279                                 (void) printf(" + ");
 280                         }
 281                         (void) printf(prusect[numbase], p.p_memsz);
 282                         notfirst++;
 283                 }
 284                 if ((Fflag) && !(nflag) && (!(p.p_type == PT_LOAD))) {
 285                         continue;
 286                 }
 287                 if (Fflag || nflag) {
 288                         switch (p.p_flags) {
 289                         case 0: (void) printf("(---)"); break;
 290                         case PF_X: (void) printf("(--x)"); break;
 291                         case PF_W: (void) printf("(-w-)"); break;
 292                         case PF_W+PF_X: (void) printf("(-wx)"); break;
 293                         case PF_R: (void) printf("(r--)"); break;
 294                         case PF_R+PF_X: (void) printf("(r-x)"); break;
 295                         case PF_R+PF_W: (void) printf("(rw-)"); break;
 296                         case PF_R+PF_W+PF_X: (void) printf("(rwx)"); break;
 297                         default: (void) printf("flags(%#x)", p.p_flags);
 298                         }
 299                 }
 300         }
 301         if (nflag) {
 302                 (void) printf(prusum[numbase], total);
 303         }
 304         if (Fflag && !nflag) {
 305                 (void) printf(prusum[numbase], memsize);
 306         }
 307         if (!Fflag && !nflag) {
 308                 Totsize = First + Second + (Third - Second);
 309                 (void) printf(format[numbase],
 310                     First, Second, Third - Second, Totsize);
 311         }
 312 }