auto import from //depot/cupcake/@135843
diff --git a/tools/soslim/main.c b/tools/soslim/main.c
new file mode 100644
index 0000000..fa5a315
--- /dev/null
+++ b/tools/soslim/main.c
@@ -0,0 +1,360 @@
+/* TODO:
+ 1. check the ARM EABI version--this works for versions 1 and 2.
+ 2. use a more-intelligent approach to finding the symbol table, symbol-string
+ table, and the .dynamic section.
+ 3. fix the determination of the host and ELF-file endianness
+ 4. write the help screen
+*/
+
+#include <stdio.h>
+#include <common.h>
+#include <debug.h>
+#include <hash.h>
+#include <libelf.h>
+#include <elf.h>
+#include <gelf.h>
+#include <cmdline.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <soslim.h>
+#include <symfilter.h>
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+#include <prelink_info.h>
+#endif
+
+/* Flag set by --verbose. This variable is global as it is accessed by the
+ macro INFO() in multiple compilation unites. */
+int verbose_flag = 0;
+/* Flag set by --quiet. This variable is global as it is accessed by the
+ macro PRINT() in multiple compilation unites. */
+int quiet_flag = 0;
+static void print_dynamic_symbols(Elf *elf, const char *symtab_name);
+
+int main(int argc, char **argv)
+{
+ int elf_fd = -1, newelf_fd = -1;
+ Elf *elf = NULL, *newelf = NULL;
+ char *infile = NULL;
+ char *outfile = NULL;
+ char *symsfile_name = NULL;
+ int print_symtab = 0;
+ int shady = 0;
+ int dry_run = 0;
+ int strip_debug = 0;
+
+ /* Do not issue INFO() statements before you call get_options() to set
+ the verbose flag as necessary.
+ */
+
+ int first = get_options(argc, argv,
+ &outfile,
+ &symsfile_name,
+ &print_symtab,
+ &verbose_flag,
+ &quiet_flag,
+ &shady,
+ &dry_run,
+ &strip_debug);
+
+ if ((print_symtab && (first == argc)) ||
+ (!print_symtab && first + 1 != argc)) {
+ print_help();
+ FAILIF(1, "You must specify an input ELF file!\n");
+ }
+ FAILIF(print_symtab && (outfile || symsfile_name || shady),
+ "You cannot provide --print and --outfile, --filter options, or "
+ "--shady simultaneously!\n");
+ FAILIF(dry_run && outfile,
+ "You cannot have a dry run and output a file at the same time.");
+
+ /* Check to see whether the ELF library is current. */
+ FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n");
+
+ if (print_symtab) {
+
+ while (first < argc) {
+ infile = argv[first++];
+
+ INFO("Opening %s...\n", infile);
+ elf_fd = open(infile, O_RDONLY);
+ FAILIF(elf_fd < 0, "open(%s): %s (%d)\n",
+ infile,
+ strerror(errno),
+ errno);
+ INFO("Calling elf_begin(%s)...\n", infile);
+ elf = elf_begin(elf_fd, ELF_C_READ, NULL);
+ FAILIF_LIBELF(elf == NULL, elf_begin);
+
+ /* libelf can recognize COFF and A.OUT formats, but we handle only
+ ELF. */
+ FAILIF(elf_kind(elf) != ELF_K_ELF,
+ "Input file %s is not in ELF format!\n",
+ infile);
+
+ /* Make sure this is a shared library or an executable. */
+ {
+ GElf_Ehdr elf_hdr;
+ INFO("Making sure %s is a shared library or an executable.\n",
+ infile);
+ FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), gelf_getehdr);
+ FAILIF(elf_hdr.e_type != ET_DYN &&
+ elf_hdr.e_type != ET_EXEC,
+ "%s must be a shared library or an executable "
+ "(elf type is %d).\n",
+ infile,
+ elf_hdr.e_type);
+ }
+
+ print_dynamic_symbols(elf, infile);
+
+ FAILIF_LIBELF(elf_end(elf), elf_end);
+ FAILIF(close(elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
+ infile, strerror(errno), errno);
+ }
+ }
+ else {
+ int elf_fd = -1;
+ Elf *elf = NULL;
+ infile = argv[first];
+
+ INFO("Opening %s...\n", infile);
+ elf_fd = open(infile, ((outfile == NULL && dry_run == 0) ? O_RDWR : O_RDONLY));
+ FAILIF(elf_fd < 0, "open(%s): %s (%d)\n",
+ infile,
+ strerror(errno),
+ errno);
+ INFO("Calling elf_begin(%s)...\n", infile);
+ elf = elf_begin(elf_fd,
+ ((outfile == NULL && dry_run == 0) ? ELF_C_RDWR : ELF_C_READ),
+ NULL);
+ FAILIF_LIBELF(elf == NULL, elf_begin);
+
+ /* libelf can recognize COFF and A.OUT formats, but we handle only ELF. */
+ FAILIF(elf_kind(elf) != ELF_K_ELF,
+ "Input file %s is not in ELF format!\n",
+ infile);
+
+ /* We run a better check in adjust_elf() itself. It is permissible to call adjust_elf()
+ on an executable if we are only stripping sections from the executable, not rearranging
+ or moving sections.
+ */
+ if (0) {
+ /* Make sure this is a shared library. */
+ GElf_Ehdr elf_hdr;
+ INFO("Making sure %s is a shared library...\n", infile);
+ FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), gelf_getehdr);
+ FAILIF(elf_hdr.e_type != ET_DYN,
+ "%s must be a shared library (elf type is %d, expecting %d).\n",
+ infile,
+ elf_hdr.e_type,
+ ET_DYN);
+ }
+
+ if (outfile != NULL) {
+ ASSERT(!dry_run);
+ struct stat st;
+ FAILIF(fstat (elf_fd, &st) != 0,
+ "Cannot stat input file %s: %s (%d)!\n",
+ infile, strerror(errno), errno);
+ newelf_fd = open (outfile, O_RDWR | O_CREAT | O_TRUNC,
+ st.st_mode & ACCESSPERMS);
+ FAILIF(newelf_fd < 0, "Cannot create file %s: %s (%d)!\n",
+ outfile, strerror(errno), errno);
+ INFO("Output file is [%s].\n", outfile);
+ newelf = elf_begin(newelf_fd, ELF_C_WRITE_MMAP, NULL);
+ } else {
+ INFO("Modifying [%s] in-place.\n", infile);
+ newelf = elf_clone(elf, ELF_C_EMPTY);
+ }
+
+ symfilter_t symfilter;
+
+ symfilter.symbols_to_keep = NULL;
+ symfilter.num_symbols_to_keep = 0;
+ if (symsfile_name) {
+ /* Make sure that the file is not empty. */
+ struct stat s;
+ FAILIF(stat(symsfile_name, &s) < 0,
+ "Cannot stat file %s.\n", symsfile_name);
+ if (s.st_size) {
+ INFO("Building symbol filter.\n");
+ build_symfilter(symsfile_name, elf, &symfilter, s.st_size);
+ }
+ else INFO("Not building symbol filter, filter file is empty.\n");
+ }
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+ int prelinked = 0;
+ int elf_little; /* valid if prelinked != 0 */
+ long prelink_addr; /* valid if prelinked != 0 */
+#endif
+ clone_elf(elf, newelf,
+ infile, outfile,
+ symfilter.symbols_to_keep,
+ symfilter.num_symbols_to_keep,
+ shady
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+ , &prelinked,
+ &elf_little,
+ &prelink_addr
+#endif
+ ,
+ true, /* rebuild the section-header-strings table */
+ strip_debug,
+ dry_run);
+
+ if (symsfile_name && symfilter.symbols_to_keep != NULL) {
+ destroy_symfilter(&symfilter);
+ }
+
+ if (outfile != NULL) INFO("Closing %s...\n", outfile);
+ FAILIF_LIBELF(elf_end (newelf) != 0, elf_end);
+ FAILIF(newelf_fd >= 0 && close(newelf_fd) < 0,
+ "Could not close file %s: %s (%d)!\n",
+ outfile, strerror(errno), errno);
+
+ INFO("Closing %s...\n", infile);
+ FAILIF_LIBELF(elf_end(elf), elf_end);
+ FAILIF(close(elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
+ infile, strerror(errno), errno);
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+ if (prelinked) {
+ INFO("File is prelinked, putting prelink TAG back in place.\n");
+ setup_prelink_info(outfile != NULL ? outfile : infile,
+ elf_little,
+ prelink_addr);
+ }
+#endif
+ }
+
+ FREEIF(outfile);
+ return 0;
+}
+
+static void print_dynamic_symbols(Elf *elf, const char *file)
+{
+ Elf_Scn *scn = NULL;
+ GElf_Shdr shdr;
+
+ GElf_Ehdr ehdr;
+ FAILIF_LIBELF(0 == gelf_getehdr(elf, &ehdr), gelf_getehdr);
+ while ((scn = elf_nextscn (elf, scn)) != NULL) {
+ FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr), gelf_getshdr);
+ if (SHT_DYNSYM == shdr.sh_type) {
+ /* This failure is too restrictive. There is no reason why
+ the symbol table couldn't be called something else, but
+ there is a standard name, and chances are that if we don't
+ see it, there's something wrong.
+ */
+ size_t shstrndx;
+ FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0,
+ elf_getshstrndx);
+ /* Now print the symbols. */
+ {
+ Elf_Data *symdata;
+ size_t elsize;
+ symdata = elf_getdata (scn, NULL); /* get the symbol data */
+ FAILIF_LIBELF(NULL == symdata, elf_getdata);
+ /* Get the number of section. We need to compare agains this
+ value for symbols that have special info in their section
+ references */
+ size_t shnum;
+ FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum);
+ /* Retrieve the size of a symbol entry */
+ elsize = gelf_fsize(elf, ELF_T_SYM, 1, ehdr.e_version);
+
+ size_t index;
+ for (index = 0; index < symdata->d_size / elsize; index++) {
+ GElf_Sym sym_mem;
+ GElf_Sym *sym;
+ /* Get the symbol. */
+ sym = gelf_getsymshndx (symdata, NULL,
+ index, &sym_mem, NULL);
+ FAILIF_LIBELF(sym == NULL, gelf_getsymshndx);
+ /* Print the symbol. */
+ char bind = '?';
+ switch(ELF32_ST_BIND(sym->st_info))
+ {
+ case STB_LOCAL: bind = 'l'; break;
+ case STB_GLOBAL: bind = 'g'; break;
+ case STB_WEAK: bind = 'w'; break;
+ default: break;
+ }
+ char type = '?';
+ switch(ELF32_ST_TYPE(sym->st_info))
+ {
+ case STT_NOTYPE: /* Symbol type is unspecified */
+ type = '?';
+ break;
+ case STT_OBJECT: /* Symbol is a data object */
+ type = 'o';
+ break;
+ case STT_FUNC: /* Symbol is a code object */
+ type = 'f';
+ break;
+ case STT_SECTION:/* Symbol associated with a section */
+ type = 's';
+ break;
+ case STT_FILE: /* Symbol's name is file name */
+ type = 'f';
+ break;
+ case STT_COMMON: /* Symbol is a common data object */
+ type = 'c';
+ break;
+ case STT_TLS: /* Symbol is thread-local data object*/
+ type = 't';
+ break;
+ }
+ {
+ int till_lineno;
+ int lineno;
+ const char *section_name = "(unknown)";
+ FAILIF(sym->st_shndx == SHN_XINDEX,
+ "Can't handle symbol's st_shndx == SHN_XINDEX!\n");
+ if (sym->st_shndx != SHN_UNDEF &&
+ sym->st_shndx < shnum) {
+ Elf_Scn *symscn = elf_getscn(elf, sym->st_shndx);
+ FAILIF_LIBELF(NULL == symscn, elf_getscn);
+ GElf_Shdr symscn_shdr;
+ FAILIF_LIBELF(NULL == gelf_getshdr(symscn,
+ &symscn_shdr),
+ gelf_getshdr);
+ section_name = elf_strptr(elf, shstrndx,
+ symscn_shdr.sh_name);
+ }
+ else if (sym->st_shndx == SHN_ABS) {
+ section_name = "SHN_ABS";
+ }
+ else if (sym->st_shndx == SHN_COMMON) {
+ section_name = "SHN_COMMON";
+ }
+ else if (sym->st_shndx == SHN_UNDEF) {
+ section_name = "(undefined)";
+ }
+ /* value size binding type section symname */
+ PRINT("%-15s %8d: %08llx %08llx %c%c %5d %n%s%n",
+ file,
+ index,
+ sym->st_value, sym->st_size, bind, type,
+ sym->st_shndx,
+ &till_lineno,
+ section_name,
+ &lineno);
+ lineno -= till_lineno;
+ /* Create padding for section names of 15 chars.
+ This limit is somewhat arbitratry. */
+ while (lineno++ < 15) PRINT(" ");
+ PRINT("(%d) %s\n",
+ sym->st_name,
+ elf_strptr(elf, shdr.sh_link, sym->st_name));
+ }
+ }
+ }
+ } /* if (shdr.sh_type = SHT_DYNSYM) */
+ } /* while ((scn = elf_nextscn (elf, scn)) != NULL) */
+}