• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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