sstrip, nas support, mppe support, mac os x patches, syslogd on bootup, inittab corre...
[openwrt.git] / obsolete-buildroot / sources / openwrt / tools / sstrip.c
1 /* http://www.muppetlabs.com/~breadbox/software/elfkickers.html */
2
3 /* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU
4 * General Public License. No warranty. See COPYING for details.
5 */
6
7 #define __MIPSEL__ 1
8 #define _MIPS_SZLONG 32
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <elf.h>
17 #include <linux/bitops.h>
18
19 typedef signed char s8;
20 typedef unsigned char u8;
21
22 typedef signed short s16;
23 typedef unsigned short u16;
24
25 typedef signed int s32;
26 typedef unsigned int u32;
27
28 typedef signed long long s64;
29 typedef unsigned long long u64;
30
31 #include <asm/elf.h>
32
33 #ifndef TRUE
34 #define TRUE 1
35 #define FALSE 0
36 #endif
37
38 #if ELF_CLASS == ELFCLASS32
39 #define Elf_Ehdr Elf32_Ehdr
40 #define Elf_Phdr Elf32_Phdr
41 #else
42 #define Elf_Ehdr Elf64_Ehdr
43 #define Elf_Phdr Elf64_Phdr
44 #endif
45
46 /* The name of the program.
47 */
48 static char const *progname;
49
50 /* The name of the current file.
51 */
52 static char const *filename;
53
54
55 /* A simple error-handling function. FALSE is always returned for the
56 * convenience of the caller.
57 */
58 static int err(char const *errmsg)
59 {
60 fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
61 return FALSE;
62 }
63
64 /* A macro for I/O errors: The given error message is used only when
65 * errno is not set.
66 */
67 #define ferr(msg) (err(errno ? strerror(errno) : (msg)))
68
69 /* readelfheader() reads the ELF header into our global variable, and
70 * checks to make sure that this is in fact a file that we should be
71 * munging.
72 */
73 static int readelfheader(int fd, Elf_Ehdr *ehdr)
74 {
75 errno = 0;
76 if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
77 return ferr("missing or incomplete ELF header.");
78
79 /* Check the ELF signature.
80 */
81 if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
82 ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
83 ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
84 ehdr->e_ident[EI_MAG3] == ELFMAG3))
85 return err("missing ELF signature.");
86
87 /* Compare the file's class and endianness with the program's.
88 */
89 if (ehdr->e_ident[EI_DATA] != ELF_DATA)
90 return err("ELF file has different endianness.");
91 if (ehdr->e_ident[EI_CLASS] != ELF_CLASS)
92 return err("ELF file has different word size.");
93
94 /* Check the target architecture.
95 */
96 if (ehdr->e_machine != ELF_ARCH)
97 return err("ELF file created for different architecture.");
98 /* Verify the sizes of the ELF header and the program segment
99 * header table entries.
100 */
101 if (ehdr->e_ehsize != sizeof(Elf_Ehdr))
102 return err("unrecognized ELF header size.");
103 if (ehdr->e_phentsize != sizeof(Elf_Phdr))
104 return err("unrecognized program segment header size.");
105
106 /* Finally, check the file type.
107 */
108 if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
109 return err("not an executable or shared-object library.");
110
111 return TRUE;
112 }
113
114 /* readphdrtable() loads the program segment header table into memory.
115 */
116 static int readphdrtable(int fd, Elf_Ehdr const *ehdr, Elf_Phdr **phdrs)
117 {
118 size_t size;
119
120 if (!ehdr->e_phoff || !ehdr->e_phnum)
121 return err("ELF file has no program header table.");
122
123 size = ehdr->e_phnum * sizeof **phdrs;
124 if (!(*phdrs = malloc(size)))
125 return err("Out of memory!");
126
127 errno = 0;
128 if (read(fd, *phdrs, size) != (ssize_t)size)
129 return ferr("missing or incomplete program segment header table.");
130
131 return TRUE;
132 }
133
134 /* getmemorysize() determines the offset of the last byte of the file
135 * that is referenced by an entry in the program segment header table.
136 * (Anything in the file after that point is not used when the program
137 * is executing, and thus can be safely discarded.)
138 */
139 static int getmemorysize(Elf_Ehdr const *ehdr, Elf_Phdr const *phdrs,
140 unsigned long *newsize)
141 {
142 Elf32_Phdr const *phdr;
143 unsigned long size, n;
144 int i;
145
146 /* Start by setting the size to include the ELF header and the
147 * complete program segment header table.
148 */
149 size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs;
150 if (size < sizeof *ehdr)
151 size = sizeof *ehdr;
152
153 /* Then keep extending the size to include whatever data the
154 * program segment header table references.
155 */
156 for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
157 if (phdr->p_type != PT_NULL) {
158 n = phdr->p_offset + phdr->p_filesz;
159 if (n > size)
160 size = n;
161 }
162 }
163
164 *newsize = size;
165 return TRUE;
166 }
167
168 /* truncatezeros() examines the bytes at the end of the file's
169 * size-to-be, and reduces the size to exclude any trailing zero
170 * bytes.
171 */
172 static int truncatezeros(int fd, unsigned long *newsize)
173 {
174 unsigned char contents[1024];
175 unsigned long size, n;
176
177 size = *newsize;
178 do {
179 n = sizeof contents;
180 if (n > size)
181 n = size;
182 if (lseek(fd, size - n, SEEK_SET) == (off_t)-1)
183 return ferr("cannot seek in file.");
184 if (read(fd, contents, n) != (ssize_t)n)
185 return ferr("cannot read file contents");
186 while (n && !contents[--n])
187 --size;
188 } while (size && !n);
189
190 /* Sanity check.
191 */
192 if (!size)
193 return err("ELF file is completely blank!");
194
195 *newsize = size;
196 return TRUE;
197 }
198
199 /* modifyheaders() removes references to the section header table if
200 * it was stripped, and reduces program header table entries that
201 * included truncated bytes at the end of the file.
202 */
203 static int modifyheaders(Elf_Ehdr *ehdr, Elf_Phdr *phdrs,
204 unsigned long newsize)
205 {
206 Elf32_Phdr *phdr;
207 int i;
208
209 /* If the section header table is gone, then remove all references
210 * to it in the ELF header.
211 */
212 if (ehdr->e_shoff >= newsize) {
213 ehdr->e_shoff = 0;
214 ehdr->e_shnum = 0;
215 ehdr->e_shentsize = 0;
216 ehdr->e_shstrndx = 0;
217 }
218
219 /* The program adjusts the file size of any segment that was
220 * truncated. The case of a segment being completely stripped out
221 * is handled separately.
222 */
223 for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
224 if (phdr->p_offset >= newsize) {
225 phdr->p_offset = newsize;
226 phdr->p_filesz = 0;
227 } else if (phdr->p_offset + phdr->p_filesz > newsize) {
228 phdr->p_filesz = newsize - phdr->p_offset;
229 }
230 }
231
232 return TRUE;
233 }
234
235 /* commitchanges() writes the new headers back to the original file
236 * and sets the file to its new size.
237 */
238 static int commitchanges(int fd, Elf_Ehdr const *ehdr, Elf_Phdr *phdrs,
239 unsigned long newsize)
240 {
241 size_t n;
242
243 /* Save the changes to the ELF header, if any.
244 */
245 if (lseek(fd, 0, SEEK_SET))
246 return ferr("could not rewind file");
247 errno = 0;
248 if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
249 return err("could not modify file");
250
251 /* Save the changes to the program segment header table, if any.
252 */
253 if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) {
254 err("could not seek in file.");
255 goto warning;
256 }
257 n = ehdr->e_phnum * sizeof *phdrs;
258 if (write(fd, phdrs, n) != (ssize_t)n) {
259 err("could not write to file");
260 goto warning;
261 }
262
263 /* Eleventh-hour sanity check: don't truncate before the end of
264 * the program segment header table.
265 */
266 if (newsize < ehdr->e_phoff + n)
267 newsize = ehdr->e_phoff + n;
268
269 /* Chop off the end of the file.
270 */
271 if (ftruncate(fd, newsize)) {
272 err("could not resize file");
273 goto warning;
274 }
275
276 return TRUE;
277
278 warning:
279 return err("ELF file may have been corrupted!");
280 }
281
282 /* main() loops over the cmdline arguments, leaving all the real work
283 * to the other functions.
284 */
285 int main(int argc, char *argv[])
286 {
287 int fd;
288 Elf_Ehdr ehdr;
289 Elf_Phdr *phdrs;
290 unsigned long newsize;
291 char **arg;
292 int failures = 0;
293
294 if (argc < 2 || argv[1][0] == '-') {
295 printf("Usage: sstrip FILE...\n"
296 "sstrip discards all nonessential bytes from an executable.\n\n"
297 "Version 2.0 Copyright (C) 2000,2001 Brian Raiter.\n"
298 "This program is free software, licensed under the GNU\n"
299 "General Public License. There is absolutely no warranty.\n");
300 return EXIT_SUCCESS;
301 }
302
303 progname = argv[0];
304
305 for (arg = argv + 1 ; *arg != NULL ; ++arg) {
306 filename = *arg;
307
308 fd = open(*arg, O_RDWR);
309 if (fd < 0) {
310 ferr("can't open");
311 ++failures;
312 continue;
313 }
314
315 if (!(readelfheader(fd, &ehdr) &&
316 readphdrtable(fd, &ehdr, &phdrs) &&
317 getmemorysize(&ehdr, phdrs, &newsize) &&
318 truncatezeros(fd, &newsize) &&
319 modifyheaders(&ehdr, phdrs, newsize) &&
320 commitchanges(fd, &ehdr, phdrs, newsize)))
321 ++failures;
322
323 close(fd);
324 }
325
326 return failures ? EXIT_FAILURE : EXIT_SUCCESS;
327 }
This page took 0.058308 seconds and 5 git commands to generate.