xref: /illumos-gate/usr/src/cmd/sgs/size/common/process.c (revision 8883f1c2)
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 }
307