1 /* TODO:
2 1. check the ARM EABI version--this works for versions 1 and 2.
3 2. use a more-intelligent approach to finding the symbol table, symbol-string
4 table, and the .dynamic section.
5 3. fix the determination of the host and ELF-file endianness
6 4. write the help screen
7 */
8
9 #include <stdio.h>
10 #include <common.h>
11 #include <debug.h>
12 #include <hash.h>
13 #include <libelf.h>
14 #include <elf.h>
15 #include <gelf.h>
16 #include <cmdline.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <soslim.h>
25 #include <symfilter.h>
26 #ifdef SUPPORT_ANDROID_PRELINK_TAGS
27 #include <prelink_info.h>
28 #endif
29
30 /* Flag set by --verbose. This variable is global as it is accessed by the
31 macro INFO() in multiple compilation unites. */
32 int verbose_flag = 0;
33 /* Flag set by --quiet. This variable is global as it is accessed by the
34 macro PRINT() in multiple compilation unites. */
35 int quiet_flag = 0;
36 static void print_dynamic_symbols(Elf *elf, const char *symtab_name);
37
main(int argc,char ** argv)38 int main(int argc, char **argv)
39 {
40 int elf_fd = -1, newelf_fd = -1;
41 Elf *elf = NULL, *newelf = NULL;
42 char *infile = NULL;
43 char *outfile = NULL;
44 char *symsfile_name = NULL;
45 int print_symtab = 0;
46 int shady = 0;
47 int dry_run = 0;
48 int strip_debug = 0;
49
50 /* Do not issue INFO() statements before you call get_options() to set
51 the verbose flag as necessary.
52 */
53
54 int first = get_options(argc, argv,
55 &outfile,
56 &symsfile_name,
57 &print_symtab,
58 &verbose_flag,
59 &quiet_flag,
60 &shady,
61 &dry_run,
62 &strip_debug);
63
64 if ((print_symtab && (first == argc)) ||
65 (!print_symtab && first + 1 != argc)) {
66 print_help();
67 FAILIF(1, "You must specify an input ELF file!\n");
68 }
69 FAILIF(print_symtab && (outfile || symsfile_name || shady),
70 "You cannot provide --print and --outfile, --filter options, or "
71 "--shady simultaneously!\n");
72 FAILIF(dry_run && outfile,
73 "You cannot have a dry run and output a file at the same time.");
74
75 /* Check to see whether the ELF library is current. */
76 FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n");
77
78 if (print_symtab) {
79
80 while (first < argc) {
81 infile = argv[first++];
82
83 INFO("Opening %s...\n", infile);
84 elf_fd = open(infile, O_RDONLY);
85 FAILIF(elf_fd < 0, "open(%s): %s (%d)\n",
86 infile,
87 strerror(errno),
88 errno);
89 INFO("Calling elf_begin(%s)...\n", infile);
90 elf = elf_begin(elf_fd, ELF_C_READ, NULL);
91 FAILIF_LIBELF(elf == NULL, elf_begin);
92
93 /* libelf can recognize COFF and A.OUT formats, but we handle only
94 ELF. */
95 FAILIF(elf_kind(elf) != ELF_K_ELF,
96 "Input file %s is not in ELF format!\n",
97 infile);
98
99 /* Make sure this is a shared library or an executable. */
100 {
101 GElf_Ehdr elf_hdr;
102 INFO("Making sure %s is a shared library or an executable.\n",
103 infile);
104 FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), gelf_getehdr);
105 FAILIF(elf_hdr.e_type != ET_DYN &&
106 elf_hdr.e_type != ET_EXEC,
107 "%s must be a shared library or an executable "
108 "(elf type is %d).\n",
109 infile,
110 elf_hdr.e_type);
111 }
112
113 print_dynamic_symbols(elf, infile);
114
115 FAILIF_LIBELF(elf_end(elf), elf_end);
116 FAILIF(close(elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
117 infile, strerror(errno), errno);
118 }
119 }
120 else {
121 int elf_fd = -1;
122 Elf *elf = NULL;
123 infile = argv[first];
124
125 INFO("Opening %s...\n", infile);
126 elf_fd = open(infile, ((outfile == NULL && dry_run == 0) ? O_RDWR : O_RDONLY));
127 FAILIF(elf_fd < 0, "open(%s): %s (%d)\n",
128 infile,
129 strerror(errno),
130 errno);
131 INFO("Calling elf_begin(%s)...\n", infile);
132 elf = elf_begin(elf_fd,
133 ((outfile == NULL && dry_run == 0) ? ELF_C_RDWR : ELF_C_READ),
134 NULL);
135 FAILIF_LIBELF(elf == NULL, elf_begin);
136
137 /* libelf can recognize COFF and A.OUT formats, but we handle only ELF. */
138 FAILIF(elf_kind(elf) != ELF_K_ELF,
139 "Input file %s is not in ELF format!\n",
140 infile);
141
142 /* We run a better check in adjust_elf() itself. It is permissible to call adjust_elf()
143 on an executable if we are only stripping sections from the executable, not rearranging
144 or moving sections.
145 */
146 if (0) {
147 /* Make sure this is a shared library. */
148 GElf_Ehdr elf_hdr;
149 INFO("Making sure %s is a shared library...\n", infile);
150 FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), gelf_getehdr);
151 FAILIF(elf_hdr.e_type != ET_DYN,
152 "%s must be a shared library (elf type is %d, expecting %d).\n",
153 infile,
154 elf_hdr.e_type,
155 ET_DYN);
156 }
157
158 if (outfile != NULL) {
159 ASSERT(!dry_run);
160 struct stat st;
161 FAILIF(fstat (elf_fd, &st) != 0,
162 "Cannot stat input file %s: %s (%d)!\n",
163 infile, strerror(errno), errno);
164 newelf_fd = open (outfile, O_RDWR | O_CREAT | O_TRUNC,
165 st.st_mode & ACCESSPERMS);
166 FAILIF(newelf_fd < 0, "Cannot create file %s: %s (%d)!\n",
167 outfile, strerror(errno), errno);
168 INFO("Output file is [%s].\n", outfile);
169 newelf = elf_begin(newelf_fd, ELF_C_WRITE_MMAP, NULL);
170 } else {
171 INFO("Modifying [%s] in-place.\n", infile);
172 newelf = elf_clone(elf, ELF_C_EMPTY);
173 }
174
175 symfilter_t symfilter;
176
177 symfilter.symbols_to_keep = NULL;
178 symfilter.num_symbols_to_keep = 0;
179 if (symsfile_name) {
180 /* Make sure that the file is not empty. */
181 struct stat s;
182 FAILIF(stat(symsfile_name, &s) < 0,
183 "Cannot stat file %s.\n", symsfile_name);
184 if (s.st_size) {
185 INFO("Building symbol filter.\n");
186 build_symfilter(symsfile_name, elf, &symfilter, s.st_size);
187 }
188 else INFO("Not building symbol filter, filter file is empty.\n");
189 }
190 #ifdef SUPPORT_ANDROID_PRELINK_TAGS
191 int prelinked = 0;
192 int elf_little; /* valid if prelinked != 0 */
193 long prelink_addr; /* valid if prelinked != 0 */
194 #endif
195 clone_elf(elf, newelf,
196 infile, outfile,
197 symfilter.symbols_to_keep,
198 symfilter.num_symbols_to_keep,
199 shady
200 #ifdef SUPPORT_ANDROID_PRELINK_TAGS
201 , &prelinked,
202 &elf_little,
203 &prelink_addr
204 #endif
205 ,
206 true, /* rebuild the section-header-strings table */
207 strip_debug,
208 dry_run);
209
210 if (symsfile_name && symfilter.symbols_to_keep != NULL) {
211 destroy_symfilter(&symfilter);
212 }
213
214 if (outfile != NULL) INFO("Closing %s...\n", outfile);
215 FAILIF_LIBELF(elf_end (newelf) != 0, elf_end);
216 FAILIF(newelf_fd >= 0 && close(newelf_fd) < 0,
217 "Could not close file %s: %s (%d)!\n",
218 outfile, strerror(errno), errno);
219
220 INFO("Closing %s...\n", infile);
221 FAILIF_LIBELF(elf_end(elf), elf_end);
222 FAILIF(close(elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
223 infile, strerror(errno), errno);
224
225 #ifdef SUPPORT_ANDROID_PRELINK_TAGS
226 if (prelinked) {
227 INFO("File is prelinked, putting prelink TAG back in place.\n");
228 setup_prelink_info(outfile != NULL ? outfile : infile,
229 elf_little,
230 prelink_addr);
231 }
232 #endif
233 }
234
235 FREEIF(outfile);
236 return 0;
237 }
238
print_dynamic_symbols(Elf * elf,const char * file)239 static void print_dynamic_symbols(Elf *elf, const char *file)
240 {
241 Elf_Scn *scn = NULL;
242 GElf_Shdr shdr;
243
244 GElf_Ehdr ehdr;
245 FAILIF_LIBELF(0 == gelf_getehdr(elf, &ehdr), gelf_getehdr);
246 while ((scn = elf_nextscn (elf, scn)) != NULL) {
247 FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr), gelf_getshdr);
248 if (SHT_DYNSYM == shdr.sh_type) {
249 /* This failure is too restrictive. There is no reason why
250 the symbol table couldn't be called something else, but
251 there is a standard name, and chances are that if we don't
252 see it, there's something wrong.
253 */
254 size_t shstrndx;
255 FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0,
256 elf_getshstrndx);
257 /* Now print the symbols. */
258 {
259 Elf_Data *symdata;
260 size_t elsize;
261 symdata = elf_getdata (scn, NULL); /* get the symbol data */
262 FAILIF_LIBELF(NULL == symdata, elf_getdata);
263 /* Get the number of section. We need to compare agains this
264 value for symbols that have special info in their section
265 references */
266 size_t shnum;
267 FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum);
268 /* Retrieve the size of a symbol entry */
269 elsize = gelf_fsize(elf, ELF_T_SYM, 1, ehdr.e_version);
270
271 size_t index;
272 for (index = 0; index < symdata->d_size / elsize; index++) {
273 GElf_Sym sym_mem;
274 GElf_Sym *sym;
275 /* Get the symbol. */
276 sym = gelf_getsymshndx (symdata, NULL,
277 index, &sym_mem, NULL);
278 FAILIF_LIBELF(sym == NULL, gelf_getsymshndx);
279 /* Print the symbol. */
280 char bind = '?';
281 switch(ELF32_ST_BIND(sym->st_info))
282 {
283 case STB_LOCAL: bind = 'l'; break;
284 case STB_GLOBAL: bind = 'g'; break;
285 case STB_WEAK: bind = 'w'; break;
286 default: break;
287 }
288 char type = '?';
289 switch(ELF32_ST_TYPE(sym->st_info))
290 {
291 case STT_NOTYPE: /* Symbol type is unspecified */
292 type = '?';
293 break;
294 case STT_OBJECT: /* Symbol is a data object */
295 type = 'o';
296 break;
297 case STT_FUNC: /* Symbol is a code object */
298 type = 'f';
299 break;
300 case STT_SECTION:/* Symbol associated with a section */
301 type = 's';
302 break;
303 case STT_FILE: /* Symbol's name is file name */
304 type = 'f';
305 break;
306 case STT_COMMON: /* Symbol is a common data object */
307 type = 'c';
308 break;
309 case STT_TLS: /* Symbol is thread-local data object*/
310 type = 't';
311 break;
312 }
313 {
314 int till_lineno;
315 int lineno;
316 const char *section_name = "(unknown)";
317 FAILIF(sym->st_shndx == SHN_XINDEX,
318 "Can't handle symbol's st_shndx == SHN_XINDEX!\n");
319 if (sym->st_shndx != SHN_UNDEF &&
320 sym->st_shndx < shnum) {
321 Elf_Scn *symscn = elf_getscn(elf, sym->st_shndx);
322 FAILIF_LIBELF(NULL == symscn, elf_getscn);
323 GElf_Shdr symscn_shdr;
324 FAILIF_LIBELF(NULL == gelf_getshdr(symscn,
325 &symscn_shdr),
326 gelf_getshdr);
327 section_name = elf_strptr(elf, shstrndx,
328 symscn_shdr.sh_name);
329 }
330 else if (sym->st_shndx == SHN_ABS) {
331 section_name = "SHN_ABS";
332 }
333 else if (sym->st_shndx == SHN_COMMON) {
334 section_name = "SHN_COMMON";
335 }
336 else if (sym->st_shndx == SHN_UNDEF) {
337 section_name = "(undefined)";
338 }
339 /* value size binding type section symname */
340 PRINT("%-15s %8zd: %08llx %08llx %c%c %5d %n%s%n",
341 file,
342 index,
343 sym->st_value, sym->st_size, bind, type,
344 sym->st_shndx,
345 &till_lineno,
346 section_name,
347 &lineno);
348 lineno -= till_lineno;
349 /* Create padding for section names of 15 chars.
350 This limit is somewhat arbitratry. */
351 while (lineno++ < 15) PRINT(" ");
352 PRINT("(%d) %s\n",
353 sym->st_name,
354 elf_strptr(elf, shdr.sh_link, sym->st_name));
355 }
356 }
357 }
358 } /* if (shdr.sh_type = SHT_DYNSYM) */
359 } /* while ((scn = elf_nextscn (elf, scn)) != NULL) */
360 }
361