xref: /illumos-gate/usr/src/cmd/sgs/size/common/process.c (revision 8a16d130)
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
process(Elf * elf)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
process_phdr(Elf * elf,GElf_Half num)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 }
313