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 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 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