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                         Fflag, /* full format for segments */
  73                         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                         first,
  87                         second,
  88                         third,
  89                         totsize;
  90         GElf_Ehdr       ehdr;
  91         GElf_Shdr       shdr;
  92         Elf_Scn         *scn;
  93         unsigned        ndx = 0;
  94         int             numsect = 0;
  95         int             notfirst = 0;
  96         int             i;
  97         char            *name = 0;
  98 
  99 /*
 100  * If there is a program header and the -f flag requesting section infor-
 101  * mation is not set, then process segments with the process_phdr function.
 102  * Otherwise, process sections.  For the default case, the first number
 103  * shall be the size of all sections that are allocatable, nonwritable and
 104  * not of type NOBITS; the second number shall be the size of all sections
 105  * that are allocatable, writable, and not of type NOBITS; the third number
 106  * is the size of all sections that are writable and not of type NOBITS.
 107  * If -f is set, print the size of each allocatable section, followed by
 108  * the section name in parentheses.
 109  * If -n is set, print the size of all sections, followed by the section
 110  * name in parentheses.
 111  */
 112 
 113         if (gelf_getehdr(elf, &ehdr) == 0) {
 114                 error(fname, "invalid file type");
 115                 return;
 116         }
 117         if ((ehdr.e_phnum != 0) && !(fflag)) {
 118                 process_phdr(elf, ehdr.e_phnum);
 119                 return;
 120         }
 121 
 122         if (is_archive) {
 123                 (void) printf("%s[%s]: ", archive, fname);
 124         } else if (!oneflag && !is_archive) {
 125                 (void) printf("%s: ", fname);
 126         }
 127         ndx = ehdr.e_shstrndx;
 128         scn = 0;
 129         size = 0;
 130         first = second = third = totsize = 0;
 131         if (ehdr.e_shnum == 0) {
 132                 error(fname, "no section data");
 133         }
 134         numsect = ehdr.e_shnum;
 135         for (i = 0; i < numsect; i++) {
 136                 if ((scn = elf_nextscn(elf, scn)) == 0) {
 137                         break;
 138                 }
 139                 if (gelf_getshdr(scn, &shdr) == 0) {
 140                         error(fname, "could not get section header");
 141                         break;
 142                 }
 143                 if ((Fflag) && !(fflag)) {
 144                         error(fname, "no segment data");
 145                         return;
 146                 } else if ((!(shdr.sh_flags & SHF_ALLOC)) &&
 147                         fflag && !(nflag)) {
 148                         continue;
 149                 } else if ((!(shdr.sh_flags & SHF_ALLOC)) && !(nflag)) {
 150                         continue;
 151                 } else if ((shdr.sh_flags & SHF_ALLOC) &&
 152                         (!(shdr.sh_flags & SHF_WRITE)) &&
 153                         (!(shdr.sh_type == SHT_NOBITS)) &&
 154                         !(fflag) && !(nflag)) {
 155                         first += shdr.sh_size;
 156                 } else if ((shdr.sh_flags & SHF_ALLOC) &&
 157                         (shdr.sh_flags & SHF_WRITE) &&
 158                         (!(shdr.sh_type == SHT_NOBITS)) &&
 159                         !(fflag) && !(nflag)) {
 160                         second += shdr.sh_size;
 161                 } else if ((shdr.sh_flags & SHF_WRITE) &&
 162                         (shdr.sh_type == SHT_NOBITS) &&
 163                         !(fflag) && !(nflag)) {
 164                         third += shdr.sh_size;
 165                 }
 166                 name = elf_strptr(elf, ndx, (size_t)shdr.sh_name);
 167 
 168                 if (fflag || nflag) {
 169                         size += shdr.sh_size;
 170                         if (notfirst) {
 171                                 (void) printf(" + ");
 172                         }
 173                         (void) printf(prusect[numbase], shdr.sh_size);
 174                         (void) printf("(%s)", name);
 175                 }
 176                 notfirst++;
 177         }
 178         if ((fflag || nflag) && (numsect > 0)) {
 179                 (void) printf(prusum[numbase], size);
 180         }
 181 
 182         if (!fflag && !nflag) {
 183                 totsize = first + second + third;
 184                 (void) printf(format[numbase],
 185                         first, second, third, totsize);
 186         }
 187 
 188         if (Fflag) {
 189                 if (ehdr.e_phnum != 0) {
 190                         process_phdr(elf, ehdr.e_phnum);
 191                         return;
 192                 } else {
 193                         error(fname, "no segment data");
 194                         return;
 195                 }
 196         }
 197 }
 198 
 199 /*
 200  * If there is a program exection header, process segments. In the default
 201  * case, the first number is the file size of all nonwritable segments
 202  * of type PT_LOAD; the second number is the file size of all writable
 203  * segments whose type is PT_LOAD; the third number is the memory size
 204  * minus the file size of all writable segments of type PT_LOAD.
 205  * If the -F flag is set, size will print the memory size of each loadable
 206  * segment, followed by its permission flags.
 207  * If -n is set, size will print the memory size of all loadable segments
 208  * and the file size of all non-loadable segments, followed by their
 209  * permission flags.
 210  */
 211 
 212 static void
 213 process_phdr(Elf * elf, GElf_Half num)
 214 {
 215         int             i;
 216         int             notfirst = 0;
 217         GElf_Phdr       p;
 218         GElf_Xword      memsize,
 219                         total,
 220                         First,
 221                         Second,
 222                         Third,
 223                         Totsize;
 224                 extern int Fflag;
 225                 extern int nflag;
 226                 extern int numbase;
 227                 extern char *fname;
 228                 extern char *archive;
 229                 extern int is_archive;
 230                 extern int oneflag;
 231 
 232         memsize = total = 0;
 233         First = Second = Third = Totsize = 0;
 234 
 235         if (is_archive) {
 236                 (void) printf("%s[%s]: ", archive, fname);
 237         } else if (!oneflag && !is_archive) {
 238                 (void) printf("%s: ", fname);
 239         }
 240 
 241         for (i = 0; i < (int)num; i++) {
 242                 if (gelf_getphdr(elf, i, &p) == NULL) {
 243                         error(fname, "no segment data");
 244                         return;
 245                 }
 246                 if ((!(p.p_flags & PF_W)) &&
 247                     (p.p_type == PT_LOAD) && !(Fflag)) {
 248                         First += p.p_filesz;
 249                 } else if ((p.p_flags & PF_W) &&
 250                     (p.p_type == PT_LOAD) && !(Fflag)) {
 251                         Second += p.p_filesz;
 252                         Third += p.p_memsz;
 253                 }
 254                 memsize += p.p_memsz;
 255                 if ((p.p_type == PT_LOAD) && nflag) {
 256                         if (notfirst) {
 257                                 (void) printf(" + ");
 258                         }
 259                         (void) printf(prusect[numbase], p.p_memsz);
 260                         total += p.p_memsz;
 261                         notfirst++;
 262                 }
 263                 if (!(p.p_type == PT_LOAD) && nflag) {
 264                         if (notfirst) {
 265                                 (void) printf(" + ");
 266                         }
 267                         (void) printf(prusect[numbase], p.p_filesz);
 268                         total += p.p_filesz;
 269                         notfirst++;
 270                 }
 271                 if ((p.p_type == PT_LOAD) && Fflag && !nflag) {
 272                         if (notfirst) {
 273                                 (void) printf(" + ");
 274                         }
 275                         (void) printf(prusect[numbase], p.p_memsz);
 276                         notfirst++;
 277                 }
 278                 if ((Fflag) && !(nflag) && (!(p.p_type == PT_LOAD))) {
 279                         continue;
 280                 }
 281                 if (Fflag || nflag) {
 282                         switch (p.p_flags) {
 283                         case 0: (void) printf("(---)"); break;
 284                         case PF_X: (void) printf("(--x)"); break;
 285                         case PF_W: (void) printf("(-w-)"); break;
 286                         case PF_W+PF_X: (void) printf("(-wx)"); break;
 287                         case PF_R: (void) printf("(r--)"); break;
 288                         case PF_R+PF_X: (void) printf("(r-x)"); break;
 289                         case PF_R+PF_W: (void) printf("(rw-)"); break;
 290                         case PF_R+PF_W+PF_X: (void) printf("(rwx)"); break;
 291                         default: (void) printf("flags(%#x)", p.p_flags);
 292                         }
 293                 }
 294         }
 295         if (nflag) {
 296                 (void) printf(prusum[numbase], total);
 297         }
 298         if (Fflag && !nflag) {
 299                 (void) printf(prusum[numbase], memsize);
 300         }
 301         if (!Fflag && !nflag) {
 302                 Totsize = First + Second + (Third - Second);
 303                 (void) printf(format[numbase],
 304                         First, Second, Third - Second, Totsize);
 305         }
 306 }