auto import from //depot/cupcake/@135843
diff --git a/tools/soslim/soslim.c b/tools/soslim/soslim.c
new file mode 100644
index 0000000..4e59c24
--- /dev/null
+++ b/tools/soslim/soslim.c
@@ -0,0 +1,528 @@
+#include <stdio.h>
+//#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <libebl.h>
+#include <libebl_arm.h>
+#include <elf.h>
+#include <gelf.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+#include <prelink_info.h>
+#endif
+
+#include <elfcopy.h>
+
+void clone_elf(Elf *elf, Elf *newelf,
+               const char *elf_name,
+               const char *newelf_name,
+               bool *sym_filter, int num_symbols,
+               int shady
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+               , int *prelinked,
+               int *elf_little,
+               long *prelink_addr
+#endif
+               , bool rebuild_shstrtab,
+               bool strip_debug,
+               bool dry_run)
+{
+	GElf_Ehdr ehdr_mem, *ehdr; /* store ELF header of original library */
+	size_t shstrndx; /* section-strings-section index */
+	size_t shnum; /* number of sections in the original file */
+	/* string table for section headers in new file */
+	struct Ebl_Strtab *shst = NULL;
+    int dynamic_idx = -1; /* index in shdr_info[] of .dynamic section */
+    int dynsym_idx = -1; /* index in shdr_info[] of dynamic symbol table
+                            section */
+
+    int cnt;	  /* general-purpose counter */
+    /* This flag is true when at least one section is dropped or when the
+       relative order of sections has changed, so that section indices in
+       the resulting file will be different from those in the original. */
+    bool sections_dropped_or_rearranged;
+	Elf_Scn *scn; /* general-purpose section */
+	size_t idx;	  /* general-purporse section index */
+
+	shdr_info_t *shdr_info = NULL;
+    int shdr_info_len = 0;
+    GElf_Phdr *phdr_info = NULL;
+
+	/* Get the information from the old file. */
+	ehdr = gelf_getehdr (elf, &ehdr_mem);
+	FAILIF_LIBELF(NULL == ehdr, gelf_getehdr);
+
+	/* Create new program header for the elf file */
+	FAILIF(gelf_newehdr (newelf, gelf_getclass (elf)) == 0 ||
+		   (ehdr->e_type != ET_REL && gelf_newphdr (newelf,
+													ehdr->e_phnum) == 0),
+		   "Cannot create new file: %s", elf_errmsg (-1));
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+    ASSERT(prelinked);
+    ASSERT(prelink_addr);
+    ASSERT(elf_little);
+    *elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB);
+    *prelinked = check_prelinked(elf_name, *elf_little, prelink_addr);
+#endif
+
+    INFO("\n\nCALCULATING MODIFICATIONS\n\n");
+
+	/* Copy out the old program header: notice that if the ELF file does not
+	   have a program header, this loop won't execute.
+	*/
+	INFO("Copying ELF program header...\n");
+    phdr_info = (GElf_Phdr *)CALLOC(ehdr->e_phnum, sizeof(GElf_Phdr));
+	for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) {
+		INFO("\tRetrieving entry %d\n", cnt);
+		FAILIF_LIBELF(NULL == gelf_getphdr(elf, cnt, phdr_info + cnt),
+                      gelf_getphdr);
+        /* -- we update the header at the end
+        FAILIF_LIBELF(gelf_update_phdr (newelf, cnt, phdr_info + cnt) == 0,
+                      gelf_update_phdr);
+        */
+	}
+
+    /* Get the section-header strings section.  This section contains the
+	   strings used to name the other sections. */
+	FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0, elf_getshstrndx);
+
+	/* Get the number of sections. */
+	FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum);
+	INFO("Original ELF file has %d sections.\n", shnum);
+
+	/* Allocate the section-header-info buffer.  We allocate one more entry
+       for the section-strings section because we regenerate that one and
+       place it at the very end of the file.  Note that just because we create
+       an extra entry in the shdr_info array, it does not mean that we create
+       one more section the header.  We just mark the old section for removal
+       and create one as the last section.
+    */
+	INFO("Allocating section-header info structure (%d) bytes...\n",
+		 shnum*sizeof (shdr_info_t));
+    shdr_info_len = rebuild_shstrtab ? shnum + 1 : shnum;
+	shdr_info = (shdr_info_t *)CALLOC(shdr_info_len, sizeof (shdr_info_t));
+
+	/* Iterate over all the sections and initialize the internal section-info
+	   array...
+	*/
+	INFO("Initializing section-header info structure...\n");
+	/* Gather information about the sections in this file. */
+	scn = NULL;
+	cnt = 1;
+	while ((scn = elf_nextscn (elf, scn)) != NULL) {
+		ASSERT(elf_ndxscn(scn) == cnt);
+		shdr_info[cnt].scn = scn;
+		FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr_info[cnt].shdr),
+					  gelf_getshdr);
+
+		/* Get the name of the section. */
+		shdr_info[cnt].name = elf_strptr (elf, shstrndx,
+										  shdr_info[cnt].shdr.sh_name);
+
+		INFO("\tname: %s\n", shdr_info[cnt].name);
+		FAILIF(shdr_info[cnt].name == NULL,
+			   "Malformed file: section %d name is null\n",
+			   cnt);
+
+		/* Mark them as present but not yet investigated.  By "investigating"
+		   sections, we mean that we check to see if by stripping other
+		   sections, the sections under investigation will be compromised.  For
+		   example, if we are removing a section of code, then we want to make
+		   sure that the symbol table does not contain symbols that refer to
+		   this code, so we investigate the symbol table.  If we do find such
+		   symbols, we will not strip the code section.
+		*/
+		shdr_info[cnt].idx = 1;
+
+		/* Remember the shdr.sh_link value.  We need to remember this value
+		   for those sections that refer to other sections.  For example,
+		   we need to remember it for relocation-entry sections, because if
+		   we modify the symbol table that a relocation-entry section is
+		   relative to, then we need to patch the relocation section.  By the
+		   time we get to deciding whether we need to patch the relocation
+		   section, we will have overwritten its header's sh_link field with
+		   a new value.
+		*/
+		shdr_info[cnt].old_shdr = shdr_info[cnt].shdr;
+        INFO("\t\toriginal sh_link: %08d\n", shdr_info[cnt].old_shdr.sh_link);
+        INFO("\t\toriginal sh_addr: %lld\n", shdr_info[cnt].old_shdr.sh_addr);
+        INFO("\t\toriginal sh_offset: %lld\n",
+             shdr_info[cnt].old_shdr.sh_offset);
+        INFO("\t\toriginal sh_size: %lld\n", shdr_info[cnt].old_shdr.sh_size);
+
+        if (shdr_info[cnt].shdr.sh_type == SHT_DYNAMIC) {
+            INFO("\t\tthis is the SHT_DYNAMIC section [%s] at index %d\n",
+                 shdr_info[cnt].name,
+                 cnt);
+            dynamic_idx = cnt;
+        }
+        else if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) {
+            INFO("\t\tthis is the SHT_DYNSYM section [%s] at index %d\n",
+                 shdr_info[cnt].name,
+                 cnt);
+            dynsym_idx = cnt;
+        }
+
+		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX,
+			   "Cannot handle sh_type SHT_SYMTAB_SHNDX!\n");
+		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP,
+			   "Cannot handle sh_type SHT_GROUP!\n");
+		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym,
+			   "Cannot handle sh_type SHT_GNU_versym!\n");
+
+		/* Increment the counter. */
+		++cnt;
+	} /* while */
+
+	/* Get the EBL handling. */
+	Ebl *ebl = ebl_openbackend (elf);
+	FAILIF_LIBELF(NULL == ebl, ebl_openbackend);
+    FAILIF_LIBELF(0 != arm_init(elf, ehdr->e_machine, ebl, sizeof(Ebl)),
+                  arm_init);
+
+    if (strip_debug) {
+
+      /* This will actually strip more than just sections.  It will strip
+         anything not essential to running the image.
+      */
+
+      INFO("Finding debug sections to strip.\n");
+
+      /* Now determine which sections can go away.  The general rule is that
+         all sections which are not used at runtime are stripped out.  But
+         there are a few exceptions:
+
+         - special sections named ".comment" and ".note" are kept
+         - OS or architecture specific sections are kept since we might not
+		 know how to handle them
+         - if a section is referred to from a section which is not removed
+		 in the sh_link or sh_info element it cannot be removed either
+      */
+      for (cnt = 1; cnt < shnum; ++cnt) {
+		/* Check whether the section can be removed.  */
+		if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr,
+							 shdr_info[cnt].name,
+							 1,	 /* remove .comment sections */
+							 1	 /* remove all debug sections */) ||
+            /* The macro above is broken--check for .comment explicitly */
+            !strcmp(".comment", shdr_info[cnt].name)
+#ifdef ARM_SPECIFIC_HACKS
+            ||
+            /* We ignore this section, that's why we can remove it. */
+            !strcmp(".stack", shdr_info[cnt].name)
+#endif
+            )
+        {
+          /* For now assume this section will be removed.  */
+          INFO("Section [%s] will be stripped from image.\n",
+               shdr_info[cnt].name);
+          shdr_info[cnt].idx = 0;
+		}
+#ifdef STRIP_STATIC_SYMBOLS
+		else if (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) {
+          /* Mark the static symbol table for removal */
+          INFO("Section [%s] (static symbol table) will be stripped from image.\n",
+               shdr_info[cnt].name);
+          shdr_info[cnt].idx = 0;
+          if (shdr_info[shdr_info[cnt].shdr.sh_link].shdr.sh_type ==
+              SHT_STRTAB)
+          {
+            /* Mark the symbol table's string table for removal. */
+            INFO("Section [%s] (static symbol-string table) will be stripped from image.\n",
+                 shdr_info[cnt].name);
+            shdr_info[shdr_info[cnt].shdr.sh_link].idx = 0;
+          }
+          else {
+            ERROR("Expecting the sh_link field of a symbol table to point to"
+                  " associated symbol-strings table!  This is not mandated by"
+                  " the standard, but is a common practice and the only way "
+                  " to know for sure which strings table corresponds to which"
+                  " symbol table!\n");
+          }
+		}
+#endif
+      }
+
+      /* Mark the SHT_NULL section as handled. */
+      shdr_info[0].idx = 2;
+
+      /* Handle exceptions: section groups and cross-references.  We might have
+         to repeat this a few times since the resetting of the flag might
+         propagate.
+      */
+      int exceptions_pass = 0;
+      bool changes;
+      do {
+        changes = false;
+		INFO("\nHandling exceptions, pass %d\n\n", exceptions_pass++);
+		for (cnt = 1; cnt < shnum; ++cnt) {
+          if (shdr_info[cnt].idx == 0) {
+            /* If a relocation section is marked as being removed but the
+               section it is relocating is not, then do not remove the
+               relocation section.
+            */
+            if ((shdr_info[cnt].shdr.sh_type == SHT_REL
+                 || shdr_info[cnt].shdr.sh_type == SHT_RELA)
+                && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) {
+              PRINT("\tSection [%s] will not be removed because the "
+                    "section it is relocating (%s) stays.\n",
+                    shdr_info[cnt].name,
+                    shdr_info[shdr_info[cnt].shdr.sh_info].name);
+            }
+          }
+          if (shdr_info[cnt].idx == 1) {
+            INFO("Processing section [%s]...\n", shdr_info[cnt].name);
+
+            /* The content of symbol tables we don't remove must not
+               reference any section which we do remove.  Otherwise
+               we cannot remove the referred section.
+            */
+            if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM ||
+                shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
+            {
+              Elf_Data *symdata;
+              size_t elsize;
+
+              INFO("\tSection [%s] is a symbol table that's not being"
+                   " removed.\n\tChecking to make sure that no symbols"
+                   " refer to sections that are being removed.\n",
+                   shdr_info[cnt].name);
+
+              /* Make sure the data is loaded.  */
+              symdata = elf_getdata (shdr_info[cnt].scn, NULL);
+              FAILIF_LIBELF(NULL == symdata, elf_getdata);
+
+              /* Go through all symbols and make sure the section they
+                 reference is not removed.  */
+              elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version);
+
+              /* Check the length of the dynamic-symbol filter. */
+              FAILIF(sym_filter != NULL &&
+                     num_symbols != symdata->d_size / elsize,
+                     "Length of dynsym filter (%d) must equal the number"
+                     " of dynamic symbols (%d)!\n",
+                     num_symbols,
+                     symdata->d_size / elsize);
+
+              size_t inner;
+              for (inner = 0;
+                   inner < symdata->d_size / elsize;
+                   ++inner)
+              {
+                GElf_Sym sym_mem;
+                GElf_Sym *sym;
+                size_t scnidx;
+
+                sym = gelf_getsymshndx (symdata, NULL,
+                                        inner, &sym_mem, NULL);
+                FAILIF_LIBELF(sym == NULL, gelf_getsymshndx);
+
+                scnidx = sym->st_shndx;
+                FAILIF(scnidx == SHN_XINDEX,
+                       "Can't handle SHN_XINDEX!\n");
+                if (scnidx == SHN_UNDEF ||
+                    scnidx >= shnum ||
+                    (scnidx >= SHN_LORESERVE &&
+                     scnidx <= SHN_HIRESERVE) ||
+                    GELF_ST_TYPE (sym->st_info) == STT_SECTION)
+                {
+                  continue;
+                }
+
+                /* If the symbol is going to be thrown and it is a
+                   global or weak symbol that is defined (not imported),
+                   then continue.  Since the symbol is going away, we
+                   do not care  whether it refers to a section that is
+                   also going away.
+                */
+                if (sym_filter && !sym_filter[inner])
+                {
+                  bool global_or_weak =
+                      ELF32_ST_BIND(sym->st_info) == STB_GLOBAL ||
+                      ELF32_ST_BIND(sym->st_info) == STB_WEAK;
+                  if (!global_or_weak && sym->st_shndx != SHN_UNDEF)
+                    continue;
+                }
+
+                /* -- far too much output
+                   INFO("\t\t\tSymbol [%s] (%d)\n",
+                   elf_strptr(elf,
+                   shdr_info[cnt].shdr.sh_link,
+                   sym->st_name),
+                   shdr_info[cnt].shdr.sh_info);
+                */
+
+                if (shdr_info[scnidx].idx == 0)
+                {
+                  PRINT("\t\t\tSymbol [%s] refers to section [%s], "
+                        "which is being removed.  Will keep that "
+                        "section.\n",
+                        elf_strptr(elf,
+                                   shdr_info[cnt].shdr.sh_link,
+                                   sym->st_name),
+                        shdr_info[scnidx].name);
+                  /* Mark this section as used.  */
+                  shdr_info[scnidx].idx = 1;
+                  changes |= scnidx < cnt;
+                }
+              } /* for each symbol */
+            } /* section type is SHT_DYNSYM or SHT_SYMTAB */
+            /* Cross referencing happens:
+			   - for the cases the ELF specification says.  That are
+			   + SHT_DYNAMIC in sh_link to string table
+			   + SHT_HASH in sh_link to symbol table
+			   + SHT_REL and SHT_RELA in sh_link to symbol table
+			   + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table
+			   + SHT_GROUP in sh_link to symbol table
+			   + SHT_SYMTAB_SHNDX in sh_link to symbol table
+			   Other (OS or architecture-specific) sections might as
+			   well use this field so we process it unconditionally.
+			   - references inside section groups
+			   - specially marked references in sh_info if the SHF_INFO_LINK
+			   flag is set
+            */
+
+            if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) {
+              shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1;
+              changes |= shdr_info[cnt].shdr.sh_link < cnt;
+            }
+
+            /* Handle references through sh_info.  */
+            if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) &&
+                shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) {
+              PRINT("\tSection [%s] links to section [%s], which was "
+                    "marked for removal--it will not be removed.\n",
+                    shdr_info[cnt].name,
+                    shdr_info[shdr_info[cnt].shdr.sh_info].name);
+
+              shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
+              changes |= shdr_info[cnt].shdr.sh_info < cnt;
+            }
+
+            /* Mark the section as investigated.  */
+            shdr_info[cnt].idx = 2;
+          } /* if (shdr_info[cnt].idx == 1) */
+		} /* for (cnt = 1; cnt < shnum; ++cnt) */
+      } while (changes);
+    }
+    else {
+      INFO("Not stripping sections.\n");
+      /* Mark the SHT_NULL section as handled. */
+      shdr_info[0].idx = 2;
+    }
+
+	/* Mark the section header string table as unused, we will create
+	   a new one as the very last section in the new ELF file.
+	*/
+	shdr_info[shstrndx].idx = rebuild_shstrtab ? 0 : 2;
+
+	/* We need a string table for the section headers. */
+	FAILIF_LIBELF((shst = ebl_strtabinit (1	/* null-terminated */)) == NULL,
+				  ebl_strtabinit);
+
+	/* Assign new section numbers. */
+	INFO("Creating new sections...\n");
+	//shdr_info[0].idx = 0;
+	for (cnt = idx = 1; cnt < shnum; ++cnt) {
+		if (shdr_info[cnt].idx > 0) {
+			shdr_info[cnt].idx = idx++;
+
+			/* Create a new section. */
+			FAILIF_LIBELF((shdr_info[cnt].newscn =
+						   elf_newscn(newelf)) == NULL, elf_newscn);
+			ASSERT(elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
+
+			/* Add this name to the section header string table. */
+			shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0);
+
+			INFO("\tsection [%s]  (old offset %lld, old size %lld) will have index %d "
+				 "(was %d).\n",
+				 shdr_info[cnt].name,
+				 shdr_info[cnt].old_shdr.sh_offset,
+				 shdr_info[cnt].old_shdr.sh_size,
+				 shdr_info[cnt].idx,
+				 elf_ndxscn(shdr_info[cnt].scn));
+		} else {
+			INFO("\tIgnoring section [%s] (offset %lld, size %lld, index %d), "
+				 "it will be discarded.\n",
+				 shdr_info[cnt].name,
+				 shdr_info[cnt].shdr.sh_offset,
+				 shdr_info[cnt].shdr.sh_size,
+				 elf_ndxscn(shdr_info[cnt].scn));
+		}
+	} /* for */
+
+    sections_dropped_or_rearranged = idx != cnt;
+
+    Elf_Data *shstrtab_data = NULL;
+
+#if 0
+    /* Fail if sections are being dropped or rearranged (except for moving shstrtab) or the
+       symbol filter is not empty, AND the file is an executable.
+    */
+    FAILIF(((idx != cnt && !(cnt - idx == 1 && rebuild_shstrtab)) || sym_filter != NULL) &&
+           ehdr->e_type != ET_DYN,
+           "You may not rearrange sections or strip symbols on an executable file!\n");
+#endif
+
+    INFO("\n\nADJUSTING ELF FILE\n\n");
+
+    adjust_elf(elf, elf_name,
+               newelf, newelf_name,
+               ebl,
+               ehdr, /* store ELF header of original library */
+               sym_filter, num_symbols,
+               shdr_info, shdr_info_len,
+               phdr_info,
+               idx, /* highest_scn_num */
+               shnum,
+               shstrndx,
+               shst,
+               sections_dropped_or_rearranged,
+               dynamic_idx, /* index in shdr_info[] of .dynamic section */
+               dynsym_idx, /* index in shdr_info[] of dynamic symbol table */
+               shady,
+               &shstrtab_data,
+               ehdr->e_type == ET_DYN, /* adjust section ofsets only when the file is a shared library */
+               rebuild_shstrtab);
+
+    /* We have everything from the old file. */
+	FAILIF_LIBELF(elf_cntl(elf, ELF_C_FDDONE) != 0, elf_cntl);
+
+	/* The ELF library better follows our layout when this is not a
+	   relocatable object file. */
+	elf_flagelf (newelf,
+				 ELF_C_SET,
+				 (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0));
+
+	/* Finally write the file. */
+    FAILIF_LIBELF(!dry_run && elf_update(newelf, ELF_C_WRITE) == -1, elf_update);
+
+	if (shdr_info != NULL) {
+		/* For some sections we might have created an table to map symbol
+           table indices. */
+       for (cnt = 1; cnt < shdr_info_len; ++cnt) {
+            FREEIF(shdr_info[cnt].newsymidx);
+            FREEIF(shdr_info[cnt].symse);
+            if(shdr_info[cnt].dynsymst != NULL)
+                ebl_strtabfree (shdr_info[cnt].dynsymst);
+        }
+		/* Free the memory. */
+		FREE (shdr_info);
+	}
+    FREEIF(phdr_info);
+
+    ebl_closebackend(ebl);
+
+	/* Free other resources. */
+	if (shst != NULL) ebl_strtabfree (shst);
+    if (shstrtab_data != NULL)
+        FREEIF(shstrtab_data->d_buf);
+}