Beispiel #1
0
std::string get_embedded_repo() {
  GElf_Shdr shdr;
  size_t shstrndx;
  char *name;
  Elf_Scn *scn;

  if (elf_version(EV_CURRENT) == EV_NONE) return "";

  int fd = open("/proc/self/exe", O_RDONLY, 0);
  if (fd < 0) return "";
  Elf* e = elf_begin(fd, ELF_C_READ, nullptr);

  if (!e ||
      elf_kind(e) != ELF_K_ELF ||
      !elf_getshstrndx(e, &shstrndx)) {
    return "";
  }
  scn = nullptr;
  while ((scn = elf_nextscn(e, scn)) != nullptr) {
    if (gelf_getshdr(scn, &shdr) != &shdr ||
        !(name = elf_strptr(e, shstrndx , shdr.sh_name))) {
      return "";
    }
    if (!strcmp("repo", name)) {
      GElf_Shdr ghdr;
      if (gelf_getshdr(scn, &ghdr) != &ghdr) return "";
      char buf[512];
      sprintf(buf, "/proc/self/exe:%lu:%lu", ghdr.sh_offset, ghdr.sh_size);
      sqlite3_embedded_initialize(nullptr, true);
      return buf;
    }
  }
  return "";
}
Beispiel #2
0
static void
find_section_base(const char *exe, Elf *e, const char *section)
{
	Dwarf_Addr off;
	Elf_Scn *scn;
	GElf_Ehdr eh;
	GElf_Shdr sh;
	size_t shstrndx;
	int elferr;
	const char *name;

	if (gelf_getehdr(e, &eh) != &eh) {
		warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
		return;
	}

	if (!elf_getshstrndx(e, &shstrndx)) {
		warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
		return;
	}

	(void) elf_errno();
	off = 0;
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		if (gelf_getshdr(scn, &sh) == NULL) {
			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
			continue;
		}
		if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
			goto next;
		if (!strcmp(section, name)) {
			if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {
				/*
				 * For executables, section base is the virtual
				 * address of the specified section.
				 */
				section_base = sh.sh_addr;
			} else if (eh.e_type == ET_REL) {
				/*
				 * For relocatables, section base is the
				 * relative offset of the specified section
				 * to the start of the first section.
				 */
				section_base = off;
			} else
				warnx("unknown e_type %u", eh.e_type);
			return;
		}
	next:
		off += sh.sh_size;
	}
	elferr = elf_errno();
	if (elferr != 0)
		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));

	errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);
}
Beispiel #3
0
/*
  returns the *internal* offset of __start. (that's what
  the symbol table contains in any case)
  The absolute address is different, offset by the .vma field of the .text
  section (where __start resides)
  returns -1 on error
*/
long get_start_addr (Elf * elf)
{
    const char STARTSYM[] = "__start";

    Elf_Scn
	*temp_scn = NULL;
    
    Elf32_Shdr * shdr;

    size_t shstrndx;		/* not too sure what this means */

    if (elf_getshstrndx(elf, &shstrndx) == 0) {
	fprintf (stderr, "getshstrndx() failed: %s\n",
		 elf_errmsg(-1));
	goto error_egress;
    }

    /* iterate over the headers. */
    while ( (temp_scn = elf_nextscn(elf, temp_scn)) != NULL) {

	shdr = elf_getshdr (temp_scn);

	if (shdr == NULL) {
	    fprintf (stderr, "elf_getshdr() failed: %s\n",
		     elf_errmsg(-1));
	    goto error_egress;
	}

	if ( (name = elf_strptr(elf, shstrndx, shdr.sh_name) ) == NULL) {
	    fprintf (stderr, "elf_strptr() failed: %s\n",
		     elf_errmsg(-1));
	    goto error_egress;
	}

	if (strncmp (STARTSYM, name, sizeof(STARTSYM)) != 0) {
	    /* wrong name */
	    continue;
	}

	/* We got it! */
	
	
    }

 error_egress:
    
}
Beispiel #4
0
static int
dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
{
	const char *s;
	size_t shstrs;
	GElf_Shdr sh;
	Elf_Data *dp;
	Elf_Scn *sp;

	if (elf_getshstrndx(dmp->dm_elf, &shstrs) == 0)
		return (dt_set_errno(dtp, EDT_NOTLOADED));

	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
			continue; /* skip any malformed sections */

		if (sh.sh_type == ctsp->cts_type &&
		    sh.sh_entsize == ctsp->cts_entsize &&
		    strcmp(s, ctsp->cts_name) == 0)
			break; /* section matches specification */
	}

	/*
	 * If the section isn't found, return success but leave cts_data set
	 * to NULL and cts_size set to zero for our caller.
	 */
	if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL)
		return (0);

	ctsp->cts_data = dp->d_buf;
	ctsp->cts_size = dp->d_size;

	dt_dprintf("loaded %s [%s] (%lu bytes)\n",
	    dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size);

	return (0);
}
/* Search an ELF file for a ".gnu_debuglink" section.  */
static const char *
find_debuglink (Elf *elf, GElf_Word *crc)
{
  size_t shstrndx;
  if (elf_getshstrndx (elf, &shstrndx) < 0)
    return NULL;

  Elf_Scn *scn = NULL;
  while ((scn = elf_nextscn (elf, scn)) != NULL)
    {
      GElf_Shdr shdr_mem;
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
      if (shdr == NULL)
	return NULL;

      const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
      if (name == NULL)
	return NULL;

      if (!strcmp (name, ".gnu_debuglink"))
	break;
    }

  if (scn == NULL)
    return NULL;

  /* Found the .gnu_debuglink section.  Extract its contents.  */
  Elf_Data *rawdata = elf_rawdata (scn, NULL);
  if (rawdata == NULL)
    return NULL;

  Elf_Data crcdata =
    {
      .d_type = ELF_T_WORD,
      .d_buf = crc,
      .d_size = sizeof *crc,
      .d_version = EV_CURRENT,
    };
  Elf_Data conv =
    {
      .d_type = ELF_T_WORD,
      .d_buf = rawdata->d_buf + rawdata->d_size - sizeof *crc,
      .d_size = sizeof *crc,
      .d_version = EV_CURRENT,
    };

  GElf_Ehdr ehdr_mem;
  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
  if (ehdr == NULL)
    return NULL;

  Elf_Data *d = gelf_xlatetom (elf, &crcdata, &conv, ehdr->e_ident[EI_DATA]);
  if (d == NULL)
    return NULL;
  assert (d == &crcdata);

  return rawdata->d_buf;
}


/* Find the separate debuginfo file for this module and open libelf on it.
   When we return success, MOD->debug is set up.  */
static Dwfl_Error
find_debuginfo (Dwfl_Module *mod)
{
  if (mod->debug.elf != NULL)
    return DWFL_E_NOERROR;

  GElf_Word debuglink_crc = 0;
  const char *debuglink_file = find_debuglink (mod->main.elf, &debuglink_crc);

  mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
							   mod->main.name,
							   debuglink_file,
							   debuglink_crc,
							   &mod->debug.name);
  return open_elf (mod, &mod->debug);
}


/* Try to find a symbol table in FILE.
   Returns DWFL_E_NOERROR if a proper one is found.
   Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM.  */
static Dwfl_Error
load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
	     Elf_Scn **symscn, Elf_Scn **xndxscn,
	     size_t *syments, GElf_Word *strshndx)
{
  bool symtab = false;
  Elf_Scn *scn = NULL;
  while ((scn = elf_nextscn (file->elf, scn)) != NULL)
    {
      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
      if (shdr != NULL)
	switch (shdr->sh_type)
	  {
	  case SHT_SYMTAB:
	    symtab = true;
	    *symscn = scn;
	    *symfile = file;
	    *strshndx = shdr->sh_link;
	    *syments = shdr->sh_size / shdr->sh_entsize;
	    if (*xndxscn != NULL)
	      return DWFL_E_NOERROR;
	    break;

	  case SHT_DYNSYM:
	    if (symtab)
	      break;
	    /* Use this if need be, but keep looking for SHT_SYMTAB.  */
	    *symscn = scn;
	    *symfile = file;
	    *strshndx = shdr->sh_link;
	    *syments = shdr->sh_size / shdr->sh_entsize;
	    break;

	  case SHT_SYMTAB_SHNDX:
	    *xndxscn = scn;
	    if (symtab)
	      return DWFL_E_NOERROR;
	    break;

	  default:
	    break;
	  }
    }

  if (symtab)
    /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
    return DWFL_E_NOERROR;

  /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
     We might have found an SHT_DYNSYM and set *SYMSCN et al though.  */
  *xndxscn = NULL;
  return DWFL_E_NO_SYMTAB;
}


/* Translate addresses into file offsets.
   OFFS[*] start out zero and remain zero if unresolved.  */
static void
find_offsets (Elf *elf, const GElf_Ehdr *ehdr, size_t n,
	      GElf_Addr addrs[n], GElf_Off offs[n])
{
  size_t unsolved = n;
  for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
    {
      GElf_Phdr phdr_mem;
      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
      if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
	for (size_t j = 0; j < n; ++j)
	  if (offs[j] == 0
	      && addrs[j] >= phdr->p_vaddr
	      && addrs[j] - phdr->p_vaddr < phdr->p_filesz)
	    {
	      offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset;
	      if (--unsolved == 0)
		break;
	    }
    }
}
Beispiel #6
0
/**
 * Look for a magic "flowlib" elf section and read it out, if it exists. Most of
 * this code adapted from hphp/util/embedded-data.cpp.
 */
CAMLprim value get_embedded_flowlib_data(value filename) {
  CAMLparam1(filename);
  CAMLlocal1(result);

  if (elf_version(EV_CURRENT) == EV_NONE) {
    goto fail_early;
  }

  int fd = open(String_val(filename), O_RDONLY);
  if (fd < 0) {
    goto fail_early;
  }

  Elf* e = elf_begin(fd, ELF_C_READ, 0);
  if (!e || elf_kind(e) != ELF_K_ELF) {
    goto fail_after_open;
  }

  size_t shstrndx = 0;
#ifdef HAVE_ELF_GETSHDRSTRNDX
  int stat = elf_getshdrstrndx(e, &shstrndx);
#else
  int stat = elf_getshstrndx(e, &shstrndx);
#endif
  if (stat < 0 || shstrndx == 0) {
    goto fail_after_elf_begin;
  }

  Elf_Scn *scn = NULL;
  while ((scn = elf_nextscn(e, scn))) {
    GElf_Shdr shdr;
    if (gelf_getshdr(scn, &shdr) != &shdr) {
      goto fail_after_elf_begin;
    }

    char *name = elf_strptr(e, shstrndx, shdr.sh_name);
    if (!name) {
      goto fail_after_elf_begin;
    }

    if (!strcmp("flowlib", name)) {
      GElf_Shdr ghdr;
      if (gelf_getshdr(scn, &ghdr) != &ghdr) {
        goto fail_after_elf_begin;
      }

      size_t offset = ghdr.sh_offset;
      size_t size = ghdr.sh_size;

      elf_end(e);

      lseek(fd, offset, SEEK_SET);
      result = caml_alloc_string(size);
      ssize_t ret = read(fd, String_val(result), size);
      if (ret != (ssize_t)size) {
        goto fail_after_elf_begin;
      }

      close(fd);
      CAMLreturn(SOME(result));
    }
  }

fail_after_elf_begin:
  elf_end(e);
fail_after_open:
  close(fd);
fail_early:
  CAMLreturn(NONE);
}
Beispiel #7
0
static int
build_file(Elf *src_elf, GElf_Ehdr *src_ehdr, Cmd_Info *cmd_info)
{
	Elf_Scn *src_scn;
	Elf_Scn *dst_scn;
	int	new_sh_name = 0;	/* to hold the offset for the new */
					/* section's name */
	Elf *dst_elf = 0;
	Elf_Data *elf_data;
	Elf_Data *data;
	int64_t scn_no, x;
	size_t no_of_symbols = 0;
	section_info_table *info;
	unsigned int    c = 0;
	int fdtmp;
	GElf_Shdr src_shdr;
	GElf_Shdr dst_shdr;
	GElf_Ehdr dst_ehdr;
	GElf_Off  new_offset = 0, r;
	size_t shnum, shstrndx;


	if (elf_getshnum(src_elf, &shnum) == NULL) {
		error_message(LIBELF_ERROR,
		LIBelf_ERROR, elf_errmsg(-1), prog);
		return (FAILURE);
	}
	if (elf_getshstrndx(src_elf, &shstrndx) == NULL) {
		error_message(LIBELF_ERROR,
		LIBelf_ERROR, elf_errmsg(-1), prog);
		return (FAILURE);
	}

	if ((fdtmp = open(elftmpfile, O_RDWR |
		O_TRUNC | O_CREAT, (mode_t)0666)) == -1) {
		error_message(OPEN_TEMP_ERROR,
		SYSTEM_ERROR, strerror(errno),
		prog, elftmpfile);
		return (FAILURE);
	}

	if ((dst_elf = elf_begin(fdtmp, ELF_C_WRITE, (Elf *) 0)) == NULL) {
		error_message(READ_ERROR,
		LIBelf_ERROR, elf_errmsg(-1),
		prog, elftmpfile);
		(void) close(fdtmp);
		return (FAILURE);
	}

	if (gelf_newehdr(dst_elf, gelf_getclass(src_elf)) == NULL) {
		error_message(LIBELF_ERROR,
		LIBelf_ERROR, elf_errmsg(-1), prog);
		return (FAILURE);
	}

	/* initialize dst_ehdr */
	(void) gelf_getehdr(dst_elf, &dst_ehdr);
	dst_ehdr = *src_ehdr;

	/*
	 * flush the changes to the ehdr so the
	 * ident array is filled in.
	 */
	(void) gelf_update_ehdr(dst_elf, &dst_ehdr);


	if (src_ehdr->e_phnum != 0) {
		(void) elf_flagelf(dst_elf, ELF_C_SET, ELF_F_LAYOUT);

		if (gelf_newphdr(dst_elf, src_ehdr->e_phnum) == NULL) {
			error_message(LIBELF_ERROR,
			LIBelf_ERROR, elf_errmsg(-1), prog);
			return (FAILURE);
		}

		for (x = 0; x < src_ehdr->e_phnum; ++x) {
			GElf_Phdr dst;
			GElf_Phdr src;

			/* LINTED */
			(void) gelf_getphdr(src_elf, (int)x, &src);
			/* LINTED */
			(void) gelf_getphdr(dst_elf, (int)x, &dst);
			(void) memcpy(&dst, &src, sizeof (GElf_Phdr));
			/* LINTED */
			(void) gelf_update_phdr(dst_elf, (int)x, &dst);
		}

		x = location(dst_ehdr.e_phoff, 0, src_elf);
		if (x == AFTER)
			new_offset = (GElf_Off)src_ehdr->e_ehsize;
	}

	scn_no = 1;
	while ((src_scn = sec_table[scn_no].scn) != (Elf_Scn *) -1) {
		info = &sec_table[scn_no];
		/*  If section should be copied to new file NOW */
		if ((info->secno != (GElf_Word)DELETED) &&
		    info->secno <= scn_no) {
			if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			(void) gelf_getshdr(dst_scn, &dst_shdr);
			(void) gelf_getshdr(info->scn, &src_shdr);
			(void) memcpy(&dst_shdr, &src_shdr, sizeof (GElf_Shdr));

			/*
			 * Update link and info fields
			 * The sh_link field may have special values so
			 * check them first.
			 */
			if ((src_shdr.sh_link >= shnum) ||
			    (src_shdr.sh_link == 0))
				dst_shdr.sh_link = src_shdr.sh_link;
			else if ((int)sec_table[src_shdr.sh_link].secno < 0)
				dst_shdr.sh_link = 0;
			else
				dst_shdr.sh_link =
				sec_table[src_shdr.sh_link].secno;

			if ((src_shdr.sh_type == SHT_REL) ||
			    (src_shdr.sh_type == SHT_RELA)) {
				if ((src_shdr.sh_info >= shnum) ||
				    ((int)sec_table[src_shdr.
				    sh_info].secno < 0))
					dst_shdr.sh_info = 0;
				else
					dst_shdr.sh_info =
					    sec_table[src_shdr.sh_info].secno;
			}

			data = sec_table[scn_no].data;
			if ((elf_data = elf_newdata(dst_scn)) == NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			*elf_data = *data;

			/* SHT_{DYNSYM, SYMTAB} might need some change */
			if (((src_shdr.sh_type == SHT_SYMTAB) ||
			    (src_shdr.sh_type == SHT_DYNSYM)) &&
			    src_shdr.sh_entsize != 0 &&
			    (cmd_info->no_of_delete != 0 ||
			    cmd_info->no_of_nulled != 0)) {
				char	*new_sym;

				no_of_symbols = src_shdr.sh_size /
				    src_shdr.sh_entsize;
				new_sym = malloc(no_of_symbols *
						src_shdr.sh_entsize);
				if (new_sym == NULL) {
					error_message(MALLOC_ERROR,
					PLAIN_ERROR, (char *)0, prog);
					mcs_exit(FAILURE);
				}

				/* CSTYLED */
				elf_data->d_buf = (void *) new_sym;
				for (c = 0; c < no_of_symbols; c++) {
					GElf_Sym csym;

					(void) gelf_getsym(data, c, &csym);

					if ((csym.st_shndx < SHN_LORESERVE) &&
					    (csym.st_shndx != SHN_UNDEF)) {
						section_info_table *i;
						i = &sec_table[csym.st_shndx];
						if (((int)i->secno !=
						    DELETED) &&
						    ((int)i->secno != NULLED))
							csym.st_shndx =
							    i->secno;
						else {
							if (src_shdr.sh_type ==
							    SHT_SYMTAB)
							/*
							 * The section which
							 * this * symbol relates
							 * to is removed.
							 * There is no way to
							 * specify this fact,
							 * just change the shndx
							 * to 1.
							 */
							    csym.st_shndx = 1;
							else {
							/*
							 * If this is in a
							 * .dynsym, NULL it out.
							 */
							    csym.st_shndx = 0;
							    csym.st_name = 0;
							    csym.st_value = 0;
							    csym.st_size = 0;
							    csym.st_info = 0;
							    csym.st_other = 0;
							    csym.st_shndx = 0;
							}
						}
					}

					(void) gelf_update_sym(elf_data, c,
					    &csym);
				}
			}

			/* update SHT_SYMTAB_SHNDX */
			if ((src_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
			    (src_shdr.sh_entsize != 0) &&
			    ((cmd_info->no_of_delete != 0) ||
			    (cmd_info->no_of_nulled != 0))) {
				GElf_Word	*oldshndx;
				GElf_Word	*newshndx;
				uint_t		entcnt;

				entcnt = src_shdr.sh_size /
				    src_shdr.sh_entsize;
				oldshndx = data->d_buf;
				newshndx = malloc(entcnt *
					src_shdr.sh_entsize);
				if (newshndx == NULL) {
					error_message(MALLOC_ERROR,
					PLAIN_ERROR, (char *)0, prog);
					mcs_exit(FAILURE);
				}
				elf_data->d_buf = (void *)newshndx;
				for (c = 0; c < entcnt; c++) {
					if (oldshndx[c] != SHN_UNDEF) {
						section_info_table *i;
						i = &sec_table[oldshndx[c]];
						if (((int)i->secno !=
						    DELETED) &&
						    ((int)i->secno != NULLED))
							newshndx[c] = i->secno;
						else
							newshndx[c] =
							    oldshndx[c];
					} else
							newshndx[c] =
							    oldshndx[c];
				}
			}

			/*
			 * If the section is to be updated,
			 * do so.
			 */
			if (ISCANDIDATE(info->flags)) {
				if ((GET_LOC(info->flags) == PRIOR) &&
				    (((int)info->secno == NULLED) ||
				    ((int)info->secno == EXPANDED) ||
				    ((int)info->secno == SHRUNK))) {
					/*
					 * The section is updated,
					 * but the position is not too
					 * good. Need to NULL this out.
					 */
					dst_shdr.sh_name = 0;
					dst_shdr.sh_type = SHT_PROGBITS;
					if ((int)info->secno != NULLED) {
						(cmd_info->no_of_moved)++;
						SET_MOVING(info->flags);
					}
				} else {
					/*
					 * The section is positioned AFTER,
					 * or there are no segments.
					 * It is safe to update this section.
					 */
					data = sec_table[scn_no].mdata;
					*elf_data = *data;
					dst_shdr.sh_size = elf_data->d_size;
				}
			}
			/* add new section name to shstrtab? */
			else if (!Sect_exists &&
			    (new_sec_string != NULL) &&
			    (scn_no == shstrndx) &&
			    (dst_shdr.sh_type == SHT_STRTAB) &&
			    ((src_ehdr->e_phnum == 0) ||
			    ((x = scn_location(dst_scn, dst_elf)) != IN) ||
			    (x != PRIOR))) {
				size_t sect_len;

				sect_len = strlen(SECT_NAME);
				if ((elf_data->d_buf =
				malloc((dst_shdr.sh_size +
				sect_len + 1))) == NULL) {
					error_message(MALLOC_ERROR,
					PLAIN_ERROR, (char *)0, prog);
					mcs_exit(FAILURE);
				}
				/* put original data plus new data in section */
				(void) memcpy(elf_data->d_buf,
					data->d_buf, data->d_size);
				(void) memcpy(&((char *)elf_data->d_buf)
					[data->d_size],
					SECT_NAME,
					sect_len + 1);
				/* LINTED */
				new_sh_name = (int)dst_shdr.sh_size;
				dst_shdr.sh_size += sect_len + 1;
				elf_data->d_size += sect_len + 1;
			}

			/*
			 * Compute offsets.
			 */
			if (src_ehdr->e_phnum != 0) {
				/*
				 * Compute section offset.
				 */
				if (off_table[scn_no] == 0) {
					if (dst_shdr.sh_addralign != 0) {
						r = new_offset %
						    dst_shdr.sh_addralign;
						if (r)
						    new_offset +=
						    dst_shdr.sh_addralign - r;
					}
					dst_shdr.sh_offset = new_offset;
					elf_data->d_off = 0;
				} else {
					if (nobits_table[scn_no] == 0)
						new_offset = off_table[scn_no];
				}
				if (nobits_table[scn_no] == 0)
					new_offset += dst_shdr.sh_size;
			}
		}

		(void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */
		scn_no++;
	}

	/*
	 * This is the real new section.
	 */
	if (!Sect_exists && new_sec_string != NULL) {
		size_t string_size;
		string_size = strlen(new_sec_string) + 1;
		if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
			error_message(LIBELF_ERROR,
			LIBelf_ERROR, elf_errmsg(-1), prog);
			return (FAILURE);
		}
		(void) gelf_getshdr(dst_scn, &dst_shdr);

		dst_shdr.sh_name = new_sh_name;
		dst_shdr.sh_type = SHT_PROGBITS;
		dst_shdr.sh_flags = 0;
		dst_shdr.sh_addr = 0;
		if (src_ehdr->e_phnum != NULL)
			dst_shdr.sh_offset = new_offset;
		else
			dst_shdr.sh_offset = 0;
		dst_shdr.sh_size = string_size + 1;
		dst_shdr.sh_link = 0;
		dst_shdr.sh_info = 0;
		dst_shdr.sh_addralign = 1;
		dst_shdr.sh_entsize = 0;
		(void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */

		if ((elf_data = elf_newdata(dst_scn)) == NULL) {
			error_message(LIBELF_ERROR,
			LIBelf_ERROR, elf_errmsg(-1), prog);
			return (FAILURE);
		}
		elf_data->d_size = string_size + 1;
		if ((elf_data->d_buf = (char *)
		    calloc(1, string_size + 1)) == NULL) {
			error_message(MALLOC_ERROR,
			PLAIN_ERROR, (char *)0,
			prog);
			mcs_exit(FAILURE);
		}
		(void) memcpy(&((char *)elf_data->d_buf)[1],
			new_sec_string, string_size);
		elf_data->d_align = 1;
		new_offset += string_size + 1;
	}

	/*
	 * If there are sections which needed to be moved,
	 * then do it here.
	 */
	if (cmd_info->no_of_moved != 0) {
		int cnt;
		info = &sec_table[0];

		for (cnt = 0; cnt < shnum; cnt++, info++) {
			if ((GET_MOVING(info->flags)) == 0)
				continue;

			if ((src_scn = elf_getscn(src_elf, info->osecno)) ==
			    NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			if (gelf_getshdr(src_scn, &src_shdr) == NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			if (gelf_getshdr(dst_scn, &dst_shdr) == NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			dst_shdr = src_shdr;

			data = info->mdata;

			dst_shdr.sh_offset = new_offset;  /* UPDATE fields */
			dst_shdr.sh_size = data->d_size;

			if ((shnum >= src_shdr.sh_link) ||
			    (src_shdr.sh_link == 0))
				dst_shdr.sh_link = src_shdr.sh_link;
			else
				dst_shdr.sh_link =
					sec_table[src_shdr.sh_link].osecno;

			if ((shnum >= src_shdr.sh_info) ||
			    (src_shdr.sh_info == 0))
				dst_shdr.sh_info = src_shdr.sh_info;
			else
				dst_shdr.sh_info =
					sec_table[src_shdr.sh_info].osecno;
			(void) gelf_update_shdr(dst_scn, &dst_shdr);
			if ((elf_data = elf_newdata(dst_scn)) == NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			(void) memcpy(elf_data, data, sizeof (Elf_Data));

			new_offset += data->d_size;
		}
	}

	/*
	 * In the event that the position of the sting table has changed,
	 * as a result of deleted sections, update the ehdr->e_shstrndx.
	 */
	if ((shstrndx > 0) && (shnum > 0) &&
	    (sec_table[shstrndx].secno < shnum)) {
		if (sec_table[shstrndx].secno < SHN_LORESERVE) {
			dst_ehdr.e_shstrndx =
				sec_table[dst_ehdr.e_shstrndx].secno;
		} else {
			Elf_Scn		*_scn;
			GElf_Shdr	shdr0;

			/*
			 * If shstrndx requires 'Extended ELF Sections'
			 * then it is stored in shdr[0].sh_link
			 */
			dst_ehdr.e_shstrndx = SHN_XINDEX;
			if ((_scn = elf_getscn(dst_elf, 0)) == NULL) {
				error_message(LIBELF_ERROR,
				LIBelf_ERROR, elf_errmsg(-1), prog);
				return (FAILURE);
			}
			(void) gelf_getshdr(_scn, &shdr0);
			shdr0.sh_link = sec_table[shstrndx].secno;
			(void) gelf_update_shdr(_scn, &shdr0);
		}
	}

	if (src_ehdr->e_phnum != 0) {
		size_t align = gelf_fsize(dst_elf, ELF_T_ADDR, 1, EV_CURRENT);

		/* UPDATE location of program header table */
		if (location(dst_ehdr.e_phoff, 0, dst_elf) == AFTER) {
			r = new_offset % align;
			if (r)
				new_offset += align - r;

			dst_ehdr.e_phoff = new_offset;
			new_offset += dst_ehdr.e_phnum
					* dst_ehdr.e_phentsize;
		}
		/* UPDATE location of section header table */
		if ((location(dst_ehdr.e_shoff, 0, src_elf) == AFTER) ||
		    ((location(dst_ehdr.e_shoff, 0, src_elf) == PRIOR) &&
		    (!Sect_exists && new_sec_string != NULL))) {
			r = new_offset % align;
			if (r)
				new_offset += align - r;

			dst_ehdr.e_shoff = new_offset;
		}
		free(b_e_seg_table);

		/*
		 * The NOTE segment is the one segment whos
		 * sections might get moved by mcs processing.
		 * Make sure that the NOTE segments offset points
		 * to the .note section.
		 */
		if ((notesegndx != -1) && (notesctndx != -1) &&
		    (sec_table[notesctndx].secno)) {
			Elf_Scn *	notescn;
			GElf_Shdr	nshdr;

			notescn = elf_getscn(dst_elf,
				sec_table[notesctndx].secno);
			(void) gelf_getshdr(notescn, &nshdr);

			if (gelf_getclass(dst_elf) == ELFCLASS32) {
				Elf32_Phdr * ph	= elf32_getphdr(dst_elf) +
				    notesegndx;
				/* LINTED */
				ph->p_offset	= (Elf32_Off)nshdr.sh_offset;
			} else {
				Elf64_Phdr * ph	= elf64_getphdr(dst_elf) +
				    notesegndx;
				ph->p_offset	= (Elf64_Off)nshdr.sh_offset;
			}
		}
	}

	/* copy ehdr changes back into real ehdr */
	(void) gelf_update_ehdr(dst_elf, &dst_ehdr);
	if (elf_update(dst_elf, ELF_C_WRITE) < 0) {
		error_message(LIBELF_ERROR,
		LIBelf_ERROR, elf_errmsg(-1), prog);
		return (FAILURE);
	}

	(void) elf_end(dst_elf);
	(void) close(fdtmp);
	return (SUCCESS);
}
Beispiel #8
0
static int
traverse_file(Elf *elf, GElf_Ehdr * ehdr, char *cur_file, Cmd_Info *cmd_info)
{
	Elf_Scn *	scn;
	Elf_Scn *	temp_scn;
	Elf_Data *	data;
	GElf_Shdr *	shdr;
	char 		*temp_name;
	section_info_table *	sinfo;
	GElf_Xword 	x;
	int 		ret = 0, SYM = 0;	/* used by strip command */
	int 		phnum = ehdr->e_phnum;
	unsigned 	int i, scn_index;
	size_t 		shstrndx, shnum;

	Sect_exists = 0;

	if (elf_getshnum(elf, &shnum) == NULL) {
		error_message(LIBELF_ERROR,
		LIBelf_ERROR, elf_errmsg(-1), prog);
		return (FAILURE);
	}
	if (elf_getshstrndx(elf, &shstrndx) == NULL) {
		error_message(LIBELF_ERROR,
		LIBelf_ERROR, elf_errmsg(-1), prog);
		return (FAILURE);
	}

	scn = 0;
	scn_index = 1;
	sinfo = &sec_table[scn_index];
	while ((scn = elf_nextscn(elf, scn)) != 0) {
		char *name;

		shdr = &(sinfo->shdr);
		if (gelf_getshdr(scn, shdr) == NULL) {
			error_message(NO_SECT_TABLE_ERROR,
			LIBelf_ERROR, elf_errmsg(-1),
			prog, cur_file);
			return (FAILURE);
		} else {
			name = elf_strptr(elf, shstrndx,
				(size_t)shdr->sh_name);
			if (name == NULL)
				name = "_@@@###";
		}

		sinfo->scn	= scn;
		sinfo->secno	= scn_index;
		sinfo->osecno	= scn_index;
		SET_ACTION(sinfo->flags, ACT_NOP);
		sinfo->name	= name;
		if (ehdr->e_phnum == 0)
			SET_LOC(sinfo->flags, NOSEG);
		else
			SET_LOC(sinfo->flags, scn_location(scn, elf));

		if (shdr->sh_type == SHT_GROUP) {
		    if (list_appendc(&cmd_info->sh_groups, sinfo) == 0) {
			error_message(MALLOC_ERROR,
				PLAIN_ERROR, (char *)0, prog);
			mcs_exit(FAILURE);
		    }
		}

		/*
		 * If the target section is pointed by a section
		 * holding relocation infomation, then the
		 * pointing section would be useless if the
		 * target section is removed.
		 */
		if ((shdr->sh_type == SHT_REL ||
		    shdr->sh_type == SHT_RELA) &&
		    (shdr->sh_info != SHN_UNDEF &&
		    (temp_scn = elf_getscn(elf, shdr->sh_info)) != 0)) {
			GElf_Shdr tmp_shdr;
			if (gelf_getshdr(temp_scn, &tmp_shdr) != NULL) {
				temp_name = elf_strptr(elf, shstrndx,
					(size_t)tmp_shdr.sh_name);
				sinfo->rel_name = temp_name;
				sinfo->rel_scn_index =
				    shdr->sh_info;
				if (phnum == 0)
					sinfo->rel_loc = NOSEG;
				    else
					sinfo->rel_loc =
						scn_location(temp_scn, elf);
			}
		}
		data = 0;
		if ((data = elf_getdata(scn, data)) == NULL) {
			error_message(LIBELF_ERROR,
			LIBelf_ERROR, elf_errmsg(-1), prog);
			return (FAILURE);
		}
		sinfo->data = data;

		/*
		 * Check if this section is a candidate for
		 * action to be processes.
		 */
		if (sectcmp(name) == 0) {
			SET_CANDIDATE(sinfo->flags);

			/*
			 * This flag just shows that there was a
			 * candidate.
			 */
			Sect_exists++;
		}

		/*
		 * Any of the following section types should
		 * also be removed (if possible) if invoked via
		 * the 'strip' command.
		 */
		if (CHK_OPT(cmd_info, I_AM_STRIP) &&
		    ((shdr->sh_type == SHT_SUNW_DEBUG) ||
		    (shdr->sh_type == SHT_SUNW_DEBUGSTR))) {
			SET_CANDIDATE(sinfo->flags);
			Sect_exists++;
		}


		/*
		 * Zap this file ?
		 */
		if ((cmd_info->flags & zFLAG) &&
		    (shdr->sh_type == SHT_PROGBITS)) {
			SET_CANDIDATE(sinfo->flags);
			Sect_exists++;
		}
		x = GET_LOC(sinfo->flags);

		/*
		 * Remeber the note sections index so that we can
		 * reset the NOTE segments offset to point to it.
		 *
		 * It may have been assigned a new location in the
		 * resulting output elf image.
		 */
		if (shdr->sh_type == SHT_NOTE)
			notesctndx = scn_index;

		if (x == IN || x == PRIOR)
			off_table[scn_index] =
				shdr->sh_offset;
		if (shdr->sh_type == SHT_NOBITS)
			nobits_table[scn_index] = 1;

		/*
		 * If this section satisfies the condition,
		 * apply the actions specified.
		 */
		if (ISCANDIDATE(sinfo->flags)) {
			ret += apply_action(sinfo, cur_file, cmd_info);
		}

		/*
		 * If I am strip command, determine if symtab can go or not.
		 */
		if (CHK_OPT(cmd_info, I_AM_STRIP) &&
		    (CHK_OPT(cmd_info, xFLAG) == 0) &&
		    (CHK_OPT(cmd_info, lFLAG) == 0)) {
			if (shdr->sh_type == SHT_SYMTAB &&
			    GET_LOC(sinfo->flags) == AFTER) {
				SYM = scn_index;
			}
		}
		scn_index++;
		sinfo++;
	}
	sinfo->scn	= (Elf_Scn *) -1;

	/*
	 * If there were any errors traversing the file,
	 * just return error.
	 */
	if (ret != 0)
		return (FAILURE);

	/*
	 * Remove symbol table if possible
	 */
	if (CHK_OPT(cmd_info, I_AM_STRIP) && SYM != 0) {
		GElf_Shdr tmp_shdr;

		(void) gelf_getshdr(sec_table[SYM].scn, &tmp_shdr);
		sec_table[SYM].secno = (GElf_Word)DELETED;
		++(cmd_info->no_of_nulled);
		if (Sect_exists == 0)
			++Sect_exists;
		SET_ACTION(sec_table[SYM].flags, ACT_DELETE);
		off_table[SYM] = 0;
		/*
		 * Can I remove section header
		 * string table ?
		 */
		if ((tmp_shdr.sh_link < shnum) &&
		    (tmp_shdr.sh_link != SHN_UNDEF) &&
		    (tmp_shdr.sh_link != shstrndx) &&
		    (GET_LOC(sec_table[tmp_shdr.sh_link].flags) == AFTER)) {
			sec_table[tmp_shdr.sh_link].secno = (GElf_Word)DELETED;
			++(cmd_info->no_of_nulled);
			if (Sect_exists == 0)
				++Sect_exists;
			SET_ACTION(sec_table[tmp_shdr.sh_link].flags,\
				ACT_DELETE);
			off_table[tmp_shdr.sh_link] = 0;
		}
	}

	/*
	 * If I only printed the contents, then
	 * just report so.
	 */
	if (CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, MIGHT_CHG))
		return (DONT_BUILD); /* don't bother creating a new file */
				/* since the file has not changed */

	/*
	 * I might need to add a new section. Check it.
	 */
	if (Sect_exists == 0 && CHK_OPT(cmd_info, aFLAG)) {
		int act = 0;
		new_sec_string = calloc(1, cmd_info->str_size + 1);
		if (new_sec_string == NULL)
			return (FAILURE);
		for (act = 0; act < actmax; act++) {
			if (Action[act].a_action == ACT_APPEND) {
				(void) strcat(new_sec_string,
					Action[act].a_string);
				(void) strcat(new_sec_string, "\n");
				cmd_info->no_of_append = 1;
			}
		}
	}

	/*
	 * If I did not append any new sections, and I did not
	 * modify/delete any sections, then just report so.
	 */
	if ((Sect_exists == 0 && cmd_info->no_of_append == 0) ||
	    !CHK_OPT(cmd_info, MIGHT_CHG))
		return (DONT_BUILD);

	/*
	 * Found at least one section which was processed.
	 *	Deleted or Appended or Compressed.
	 */
	if (Sect_exists) {
		/*
		 * First, handle the deleted sections.
		 */
		if (cmd_info->no_of_delete != 0 ||
		    cmd_info->no_of_nulled != 0) {
			int acc = 0;
			int rel_idx;

			/*
			 * Handle relocation/target
			 * sections.
			 */
			sinfo = &(sec_table[0]);
			for (i = 1; i < shnum; i++) {
				sinfo++;
				rel_idx = sinfo->rel_scn_index;
				if (rel_idx == 0)
					continue;

				/*
				 * If I am removed, then remove my
				 * target section.
				 */
				if (((sinfo->secno ==
				    (GElf_Word)DELETED) ||
				    (sinfo->secno ==
				    (GElf_Word)NULLED)) &&
				    sinfo->rel_loc != IN) {
					if (GET_LOC(sec_table[rel_idx].flags) ==
					    PRIOR)
						sec_table[rel_idx].secno =
							(GElf_Word)NULLED;
					else
						sec_table[rel_idx].secno =
							(GElf_Word)DELETED;
					SET_ACTION(sec_table[rel_idx].flags,\
						ACT_DELETE);
				}

				/*
				 * I am not removed. Check if my target is
				 * removed or nulled. If so, let me try to
				 * remove my self.
				 */
				if (((sec_table[rel_idx].secno ==
				    (GElf_Word)DELETED) ||
				    (sec_table[rel_idx].secno ==
				    (GElf_Word)NULLED)) &&
				    (GET_LOC(sinfo->flags) != IN)) {
					if (GET_LOC(sinfo->flags) ==
					    PRIOR)
						sinfo->secno =
							(GElf_Word)NULLED;
					else
						sinfo->secno =
							(GElf_Word)DELETED;
					SET_ACTION(sinfo->flags,\
						ACT_DELETE);
				}
			}

			/*
			 * Now, take care of DELETED sections
			 */
			sinfo = &(sec_table[1]);
			for (i = 1; i < shnum; i++) {
			    shdr = &(sinfo->shdr);
			    if (sinfo->secno == (GElf_Word)DELETED) {
				acc++;
				/*
				 * The SHT_GROUP section which this section
				 * is a member may be able to be removed.
				 * See post_process().
				 */
				if (shdr->sh_flags & SHF_GROUP)
				    cmd_info->flags |= SHF_GROUP_DEL;
			    } else {
				/*
				 * The data buffer of SHT_GROUP this section
				 * is a member needs to be updated.
				 * See post_process().
				 */
				sinfo->secno -= acc;
				if ((shdr->sh_flags &
				    SHF_GROUP) && (acc != 0))
				    cmd_info->flags |= SHF_GROUP_MOVE;
			    }
			    sinfo++;
			}
		}
	}

	/*
	 * I know that the file has been modified.
	 * A new file need to be created.
	 */
	return (SUCCESS);
}
Beispiel #9
0
/* Convert ELF object to Portable Executable (PE). */
void
create_pe(struct elfcopy *ecp, int ifd, int ofd)
{
	Elf *e;
	Elf_Scn *scn;
	Elf_Data *d;
	GElf_Ehdr eh;
	GElf_Shdr sh;
	PE *pe;
	PE_Scn *ps;
	PE_SecHdr psh;
	PE_CoffHdr pch;
	PE_OptHdr poh;
	PE_Object po;
	PE_Buffer *pb;
	const char *name;
	size_t indx;
	int elferr;

	if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64)
		po = PE_O_PE32P;
	else
		po = PE_O_PE32;

	if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
		errx(EXIT_FAILURE, "elf_begin() failed: %s",
		    elf_errmsg(-1));

	if (gelf_getehdr(e, &eh) == NULL)
		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
		    elf_errmsg(-1));

	if (elf_getshstrndx(ecp->ein, &indx) == 0)
		errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s",
		    elf_errmsg(-1));

	if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL)
		err(EXIT_FAILURE, "pe_init() failed");

	/* Setup PE COFF header. */
	memset(&pch, 0, sizeof(pch));
	switch (ecp->oem) {
	case EM_386:
		pch.ch_machine = IMAGE_FILE_MACHINE_I386;
		break;
	case EM_X86_64:
		pch.ch_machine = IMAGE_FILE_MACHINE_AMD64;
		break;
	default:
		pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN;
		break;
	}
	pch.ch_timestamp = (uint32_t) time(NULL);
	if (pe_update_coff_header(pe, &pch) < 0)
		err(EXIT_FAILURE, "pe_update_coff_header() failed");

	/* Setup PE optional header. */
	memset(&poh, 0, sizeof(poh));
	if (ecp->otf == ETF_EFI)
		poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
	poh.oh_entry = (uint32_t) eh.e_entry;

	/*
	 * Default section alignment and file alignment. (Here the
	 * section alignment is set to the default page size of the
	 * archs supported. We should use different section alignment
	 * for some arch. (e.g. IA64)
	 */
	poh.oh_secalign = 0x1000;
	poh.oh_filealign = 0x200;

	/* Copy sections. */
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {

		/*
		 * Read in ELF section.
		 */

		if (gelf_getshdr(scn, &sh) == NULL) {
			warnx("gelf_getshdr() failed: %s", elf_errmsg(-1));
			(void) elf_errno();
			continue;
		}
		if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) ==
		    NULL) {
			warnx("elf_strptr() failed: %s", elf_errmsg(-1));
			(void) elf_errno();
			continue;
		}

		/* Skip sections unneeded. */
		if (strcmp(name, ".shstrtab") == 0 ||
		    strcmp(name, ".symtab") == 0 ||
		    strcmp(name, ".strtab") == 0)
			continue;

		if ((d = elf_getdata(scn, NULL)) == NULL) {
			warnx("elf_getdata() failed: %s", elf_errmsg(-1));
			(void) elf_errno();
			continue;
		}

		if (strcmp(name, ".text") == 0) {
			poh.oh_textbase = (uint32_t) sh.sh_addr;
			poh.oh_textsize = (uint32_t) roundup(sh.sh_size,
			    poh.oh_filealign);
		} else {
			if (po == PE_O_PE32 && strcmp(name, ".data") == 0)
				poh.oh_database = sh.sh_addr;
			if (sh.sh_type == SHT_NOBITS)
				poh.oh_bsssize += (uint32_t)
				    roundup(sh.sh_size, poh.oh_filealign);
			else if (sh.sh_flags & SHF_ALLOC)
				poh.oh_datasize += (uint32_t)
				    roundup(sh.sh_size, poh.oh_filealign);
		}

		/*
		 * Create PE/COFF section.
		 */

		if ((ps = pe_newscn(pe)) == NULL) {
			warn("pe_newscn() failed");
			continue;
		}

		/*
		 * Setup PE/COFF section header. The section name is not
		 * NUL-terminated if its length happens to be 8. Long
		 * section name should be truncated for PE image according
		 * to the PE/COFF specification.
		 */
		memset(&psh, 0, sizeof(psh));
		strncpy(psh.sh_name, name, sizeof(psh.sh_name));
		psh.sh_addr = sh.sh_addr;
		psh.sh_virtsize = sh.sh_size;
		if (sh.sh_type != SHT_NOBITS)
			psh.sh_rawsize = roundup(sh.sh_size, poh.oh_filealign);
		else
			psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;

		/*
		 * Translate ELF section flags to PE/COFF section flags.
		 */
		psh.sh_char |= IMAGE_SCN_MEM_READ;
		if (sh.sh_flags & SHF_WRITE)
			psh.sh_char |= IMAGE_SCN_MEM_WRITE;
		if (sh.sh_flags & SHF_EXECINSTR)
			psh.sh_char |= IMAGE_SCN_MEM_EXECUTE |
			    IMAGE_SCN_CNT_CODE;
		if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0)
			psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA;

		/* Mark relocation section "discardable". */
		if (strcmp(name, ".reloc") == 0)
			psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE;

		if (pe_update_section_header(ps, &psh) < 0) {
			warn("pe_update_section_header() failed");
			continue;
		}

		/* Copy section content. */
		if ((pb = pe_newbuffer(ps)) == NULL) {
			warn("pe_newbuffer() failed");
			continue;
		}
		pb->pb_align = 1;
		pb->pb_off = 0;
		pb->pb_size = roundup(sh.sh_size, poh.oh_filealign);
		if ((pb->pb_buf = calloc(1, pb->pb_size)) == NULL) {
			warn("calloc failed");
			continue;
		}
		memcpy(pb->pb_buf, d->d_buf, sh.sh_size);
	}
	elferr = elf_errno();
	if (elferr != 0)
		warnx("elf_nextscn() failed: %s", elf_errmsg(elferr));

	/* Update PE optional header. */
	if (pe_update_opt_header(pe, &poh) < 0)
		err(EXIT_FAILURE, "pe_update_opt_header() failed");

	/* Write out PE/COFF object. */
	if (pe_update(pe) < 0)
		err(EXIT_FAILURE, "pe_update() failed");

	pe_finish(pe);
	elf_end(e);
}
Beispiel #10
0
/*
 * Update our module cache by adding an entry for the specified module 'name'.
 * We create the dt_module_t and populate it using /system/object/<name>/.
 */
static void
dt_module_update(dtrace_hdl_t *dtp, const char *name)
{
	char fname[MAXPATHLEN];
	struct stat64 st;
	int fd, err, bits;

	dt_module_t *dmp;
	const char *s;
	size_t shstrs;
	GElf_Shdr sh;
	Elf_Data *dp;
	Elf_Scn *sp;

	unsigned read_cmd = ELF_C_READ;

	if (0 == strcmp("mach_kernel", name)) {
		if (dtrace_kernel_path(fname, sizeof(fname)) != 0) {
			dt_dprintf("failed to retrieve the kernel binary, the module cache will not be updated\n");
			return;
		}

		read_cmd = ELF_C_RDKERNTYPE;
	}

	if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
	    (dmp = dt_module_create(dtp, name)) == NULL) {
		dt_dprintf("failed to open %s: %s\n", fname, strerror(errno));
		(void) close(fd);
		return;
	}

	/*
	 * Since the module can unload out from under us (and /system/object
	 * will return ENOENT), tell libelf to cook the entire file now and
	 * then close the underlying file descriptor immediately.  If this
	 * succeeds, we know that we can continue safely using dmp->dm_elf.
	 */
	dmp->dm_elf = elf_begin(fd, read_cmd, NULL);
	err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD);
	(void) close(fd);

	if (dmp->dm_elf == NULL || err == -1 ||
	    elf_getshstrndx(dmp->dm_elf, &shstrs) == 0) {
		dt_dprintf("failed to load %s: %s\n",
		    fname, elf_errmsg(elf_errno()));
		dt_module_destroy(dtp, dmp);
		return;
	}

	switch (gelf_getclass(dmp->dm_elf)) {
	case ELFCLASS32:
		dmp->dm_ops = (dmp->dm_elf->ed_kind == ELF_K_MACHO ? &dt_modops_macho_32 : &dt_modops_32);
		bits = 32;
		break;
	case ELFCLASS64:
		dmp->dm_ops = (dmp->dm_elf->ed_kind == ELF_K_MACHO ? &dt_modops_macho_64 : &dt_modops_64);
		bits = 64;
		break;
	default:
		dt_dprintf("failed to load %s: unknown ELF class\n", fname);
		dt_module_destroy(dtp, dmp);
		return;
	}

	/*
	 * Iterate over the section headers locating various sections of
	 * interest and use their attributes to flesh out the dt_module_t.
	 */
	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
			continue; /* skip any malformed sections */

		if (strcmp(s, ".text") == 0) {
			dmp->dm_text_size = sh.sh_size;
			dmp->dm_text_va = sh.sh_addr;
		} else if (strcmp(s, ".data") == 0) {
			dmp->dm_data_size = sh.sh_size;
			dmp->dm_data_va = sh.sh_addr;
		} else if (strcmp(s, ".bss") == 0) {
			dmp->dm_bss_size = sh.sh_size;
			dmp->dm_bss_va = sh.sh_addr;
		} else if (strcmp(s, ".info") == 0 &&
		    (dp = elf_getdata(sp, NULL)) != NULL) {
			bcopy(dp->d_buf, &dmp->dm_info,
			    MIN(sh.sh_size, sizeof (dmp->dm_info)));
		} else if (strcmp(s, ".filename") == 0 &&
		    (dp = elf_getdata(sp, NULL)) != NULL) {
			(void) strlcpy(dmp->dm_file,
			    dp->d_buf, sizeof (dmp->dm_file));
		}
	}

	dmp->dm_flags |= DT_DM_KERNEL;
	dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);

	if (dmp->dm_info.objfs_info_primary)
		dmp->dm_flags |= DT_DM_PRIMARY;

	dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
	    bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
}
Beispiel #11
0
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 */

    unsigned 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;
    unsigned 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 %zd 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 (%zd) 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[shdr_info[cnt].shdr.sh_link].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 &&
                     (size_t)num_symbols != symdata->d_size / elsize,
                     "Length of dynsym filter (%d) must equal the number"
                     " of dynamic symbols (%zd)!\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 %zd).\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 %zd), "
				 "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);
}
Beispiel #12
0
int
main(int argc, char **argv)
{
	int		c, ndx;
	int		readonly;
	int		fd;
	const char	*file;
	const char	*runpath;
	Elf		*elf;
	GElf_Ehdr	ehdr;
	size_t		shstrndx, shnum;
	Elf_Scn		*scn;
	Elf_Data	*data;
	char		*shnames = NULL;
	Cache		*cache, *_cache;
	Cache		*dynsec, *strsec;
	GElf_Word	numdyn;
	dyn_elt_t	rpath_elt;
	dyn_elt_t	runpath_elt;
	dyn_elt_t	strpad_elt;
	dyn_elt_t	flags_1_elt;
	dyn_elt_t	null_elt;
	int		changed = 0;


	opterr = 0;
	while ((c = getopt(argc, argv, "dr")) != EOF) {
		switch (c) {
		case 'd':
			d_flg = 1;
			break;

		case 'r':
			r_flg = 1;
			break;

		case '?':
			msg_usage();
		}
	}

	/*
	 * The first plain argument is the file name, and is required.
	 * The second plain argument is the runpath, and is optional.
	 * If no runpath is given, we print the current runpath to stdout
	 * and exit. If it is present, we modify the ELF file to use it.
	 */
	argc = argc - optind;
	argv += optind;
	if ((argc < 1) || (argc > 2))
		msg_usage();
	if ((argc == 2) && r_flg)
		msg_usage();

	readonly = (argc == 1) && !r_flg;
	file = argv[0];
	if (!readonly)
		runpath = argv[1];

	if ((fd = open(file, readonly ? O_RDONLY : O_RDWR)) == -1)
		msg_fatal("unable to open file: %s: %s\n",
		    file, strerror(errno));

	(void) elf_version(EV_CURRENT);
	elf = elf_begin(fd, readonly ? ELF_C_READ : ELF_C_RDWR, NULL);
	if (elf == NULL)
		msg_elf("elf_begin");

	/* We only handle standalone ELF files */
	switch (elf_kind(elf)) {
	case ELF_K_AR:
		msg_fatal("unable to edit ELF archive: %s\n", file);
		break;
	case ELF_K_ELF:
		break;
	default:
		msg_fatal("unable to edit non-ELF file: %s\n", file);
		break;
	}

	if (gelf_getehdr(elf, &ehdr) == NULL)
		msg_elf("gelf_getehdr");

	if (elf_getshnum(elf, &shnum) == 0)
		msg_elf("elf_getshnum");

	if (elf_getshstrndx(elf, &shstrndx) == 0)
		msg_elf("elf_getshstrndx");

	/*
	 * Obtain the .shstrtab data buffer to provide the required section
	 * name strings.
	 */
	if ((scn = elf_getscn(elf, shstrndx)) == NULL)
		msg_elf("elf_getscn");
	if ((data = elf_getdata(scn, NULL)) == NULL)
		msg_elf("elf_getdata");
	shnames = data->d_buf;

	/*
	 * Allocate a cache to maintain a descriptor for each section.
	 */
	if ((cache = malloc(shnum * sizeof (Cache))) == NULL)
		msg_fatal("unable to allocate section cache: %s\n",
		    strerror(errno));
	bzero(cache, sizeof (cache[0]));
	cache->c_name = "";
	_cache = cache + 1;

	/*
	 * Fill in cache with information for each section, and
	 * locate the dynamic section.
	 */
	dynsec = strsec = NULL;
	for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn);
	    ndx++, _cache++) {
		_cache->c_ndx = ndx;
		if (gelf_getshdr(scn, &_cache->c_shdr) == NULL)
			msg_elf("gelf_getshdr");
		_cache->c_data = elf_getdata(scn, NULL);
		_cache->c_name = shnames + _cache->c_shdr.sh_name;
		if (_cache->c_shdr.sh_type == SHT_DYNAMIC) {
			dynsec = _cache;
			numdyn = dynsec->c_shdr.sh_size /
			    dynsec->c_shdr.sh_entsize;
			msg_debug("[%d]%s: dynamic section\n",
			    ndx, _cache->c_name);
		}
	}

	/*
	 * If we got a dynamic section, locate the string table.
	 * If not, we can't continue.
	 */
	if (dynsec == NULL)
		msg_fatal("file lacks a dynamic section: %s\n", file);
	strsec = &cache[dynsec->c_shdr.sh_link];
	msg_debug("[%d]%s: dynamic string table section\n",
	    strsec->c_ndx, strsec->c_name);

	/*
	 * History Lesson And Strategy:
	 *
	 * This routine handles both DT_RPATH and DT_RUNPATH entries, altering
	 * either or both if they are present.
	 *
	 * The original SYSV ABI only had DT_RPATH, and the runtime loader used
	 * it to search for things in the following order:
	 *
	 *	DT_RPATH, LD_LIBRARY_PATH, defaults
	 *
	 * Solaris did not follow this rule. Environment variables should
	 * supersede everything else, so we have always deviated from the
	 * ABI and and instead search in the order
	 *
	 *	LD_LIBRARY_PATH, DT_RPATH, defaults
	 *
	 * Other Unix variants initially followed the ABI, but in recent years
	 * realized that it was a mistake. Hence, DT_RUNPATH was invented,
	 * with the search order:
	 *
	 *	LD_LIBRARY_PATH, DT_RUNPATH, defaults
	 *
	 * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both
	 * are present (which does happen), we set them both to the new
	 * value. If either one is present, we set that one. If neither is
	 * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH.
	 */

	/*
	 * Examine the dynamic section to determine the index for
	 *	- DT_RPATH
	 *	- DT_RUNPATH
	 *	- DT_SUNW_STRPAD
	 *	- DT_NULL, and whether there are any extra DT_NULL slots
	 */
	dyn_elt_init(&rpath_elt);
	dyn_elt_init(&runpath_elt);
	dyn_elt_init(&strpad_elt);
	dyn_elt_init(&flags_1_elt);
	dyn_elt_init(&null_elt);
	for (ndx = 0; ndx < numdyn; ndx++) {
		GElf_Dyn	dyn;

		if (gelf_getdyn(dynsec->c_data, ndx, &dyn) == NULL)
			msg_elf("gelf_getdyn");

		switch (dyn.d_tag) {
		case DT_NULL:
			/*
			 * Remember the state of the first DT_NULL. If there
			 * are more than one (i.e. the first one is not
			 * in the final spot), and there is no runpath, then
			 * we will turn the first one into a DT_RUNPATH.
			 */
			if (!null_elt.seen) {
				dyn_elt_save(&null_elt, ndx, &dyn);
				msg_debug("[%d]%s[%d]: DT_NULL\n",
				    dynsec->c_ndx, dynsec->c_name, ndx);
			}
			break;

		case DT_RPATH:
			dyn_elt_save(&rpath_elt, ndx, &dyn);
			msg_debug("[%d]%s[%d]: DT_RPATH: %s\n",
			    dynsec->c_ndx, dynsec->c_name, ndx,
			    DYN_ELT_STRING(&rpath_elt, strsec));
			break;

		case DT_RUNPATH:
			dyn_elt_save(&runpath_elt, ndx, &dyn);
			msg_debug("[%d]%s[%d]: DT_RUNPATH: %s\n",
			    dynsec->c_ndx, dynsec->c_name, ndx,
			    DYN_ELT_STRING(&runpath_elt, strsec));
			break;

		case DT_SUNW_STRPAD:
			dyn_elt_save(&strpad_elt, ndx, &dyn);
			msg_debug("[%d]%s[%d]: DT_STRPAD: %d\n",
			    dynsec->c_ndx, dynsec->c_name, ndx,
			    (int)strpad_elt.dyn.d_un.d_val);
			break;

		case DT_FLAGS_1:
			dyn_elt_save(&flags_1_elt, ndx, &dyn);
			break;
		}
	}

	/*
	 * If this is a readonly session, then print the existing
	 * runpath and exit. DT_RPATH and DT_RUNPATH should have
	 * the same value, so we arbitrarily favor DT_RUNPATH.
	 */
	if (readonly) {
		if (runpath_elt.seen)
			(void) printf("%s\n",
			    DYN_ELT_STRING(&runpath_elt, strsec));
		else if (rpath_elt.seen)
			(void) printf("%s\n",
			    DYN_ELT_STRING(&rpath_elt, strsec));
		else
			msg_debug("ELF file does not have a runpath: %s\n",
			    file);
		return (0);
	}


	/* Edit the file, either to remove the runpath or to add/modify it */
	if (r_flg) {
		if (!(runpath_elt.seen || rpath_elt.seen))
			msg_debug("[%d]%s: no runpath found\n",
			    dynsec->c_ndx, dynsec->c_name);
		else
			changed = remove_runpath(dynsec, numdyn);
	} else {
		changed = new_runpath(runpath, dynsec, numdyn, strsec,
		    &rpath_elt, &runpath_elt, &strpad_elt, &null_elt);
	}

	if (changed) {
		/*
		 * If possible, set the DF_1_EDITED flag, indicating that
		 * this file has been edited after the fact.
		 */
		if (flags_1_elt.seen) {
			flags_1_elt.dyn.d_un.d_val |= DF_1_EDITED;
		} else if (null_elt.seen && (null_elt.ndx < (numdyn - 1))) {
			msg_debug("[%d]%s: No existing flags_1 entry to "
			    "modify. Will use extra DT_NULL in slot [%d] \n",
			    dynsec->c_ndx, dynsec->c_name, null_elt.ndx);
			flags_1_elt.seen = 1;
			flags_1_elt.ndx = null_elt.ndx;
			flags_1_elt.dyn.d_tag = DT_FLAGS_1;
			flags_1_elt.dyn.d_un.d_val = DF_1_EDITED;
		}
		if (flags_1_elt.seen) {
			msg_debug("[%d]%s[%d]: Set DF_1_EDITED flag\n",
			    dynsec->c_ndx, dynsec->c_name, flags_1_elt.ndx);
			if (gelf_update_dyn(dynsec->c_data, flags_1_elt.ndx,
			    &flags_1_elt.dyn) == 0)
				msg_elf("gelf_update_dyn");
		}

		/*
		 * Mark the data area as dirty so libelf will flush our
		 * changes to the dynamic section data.
		 */
		(void) elf_flagdata(dynsec->c_data, ELF_C_SET, ELF_F_DIRTY);

		/* Flush the file to disk */
		if (elf_update(elf, ELF_C_WRITE) == -1)
			msg_elf("elf_update");
		(void) close(fd);
		(void) elf_end(elf);
	}
	return (0);
}
Beispiel #13
0
/*
 * scan the ELF image to build table of global symbold and the image
 * regions where they can be found (BSS and DATA)
 */
static inline int
table_init_helper (void)
{
    Elf *e = NULL;
    GElf_Ehdr ehdr;
    char *shstr_name = NULL;
    size_t shstrndx;
    Elf_Scn *scn = NULL;
    GElf_Shdr shdr;
    int ret = -1;
#if 0
    int (*getsi) ();            /* look up name of elf_get... routine */
#endif

    /* unrecognized format */
    if (elf_version (EV_CURRENT) == EV_NONE) {
        goto bail;
    }

    /* get the ELF object from already opened state */
    e = elf_begin (GET_STATE (exe_fd), ELF_C_READ, NULL);
    if (e == NULL) {
        goto bail;
    }

    /* do some sanity checks */
    if (elf_kind (e) != ELF_K_ELF) {
        goto bail;
    }
    if (gelf_getehdr (e, &ehdr) == NULL) {
        goto bail;
    }
    if (gelf_getclass (e) == ELFCLASSNONE) {
        goto bail;
    }

    /*
     * There are various elf_get* routines with different return values
     * in differnt libraries/versions - name of routine does not tell us
     * all we ned to know.  So let it go here, and we'll mop up any
     * problems later on.
     */

    /*
     * This routine is either "elf_getshdrstrndx" in newer ELF
     * libraries, or "elf_getshstrndx" in older ones.  Hard-code older
     * one for now since it is in the newer libraries, although marked as
     * deprecated.  This will be detected by autoconf later
     *
     * DEPRECATED
     */
    (void) elf_getshstrndx (e, &shstrndx);

    /* walk sections, look for RO/BSS/DATA and symbol table */
    scn = NULL;

    while ((scn = elf_nextscn (e, scn)) != NULL) {

        if (gelf_getshdr (scn, &shdr) != &shdr) {
            goto bail;
        }
        shstr_name = elf_strptr (e, shstrndx, shdr.sh_name);
        if (shstr_name == NULL) {
            goto bail;
        }

        /* found the read-only data */
        if (shdr.sh_type == SHT_PROGBITS && strcmp (shstr_name, ".rodata") == 0) {

            elfro.start = shdr.sh_addr;
            elfro.end = elfro.start + shdr.sh_size;

            shmemi_trace (SHMEM_LOG_SYMBOLS,
                          "ELF section .rodata for global variables = 0x%lX -> 0x%lX",
                          elfro.start, elfro.end);
            continue;           /* move to next scan */
        }

        /* found the uninitialized globals */
        if (shdr.sh_type == SHT_NOBITS && strcmp (shstr_name, ".bss") == 0) {

            elfbss.start = shdr.sh_addr;
            elfbss.end = elfbss.start + shdr.sh_size;

            shmemi_trace (SHMEM_LOG_SYMBOLS,
                          "ELF section .bss for global variables = 0x%lX -> 0x%lX",
                          elfbss.start, elfbss.end);
            continue;           /* move to next scan */
        }

        /* found the initialized globals */
        if (shdr.sh_type == SHT_PROGBITS && strcmp (shstr_name, ".data") == 0) {

            elfdata.start = shdr.sh_addr;
            elfdata.end = elfdata.start + shdr.sh_size;

            shmemi_trace (SHMEM_LOG_SYMBOLS,
                          "ELF section .data for global variables = 0x%lX -> 0x%lX",
                          elfdata.start, elfdata.end);
            continue;           /* move to next scan */
        }

        /* keep looking until we find the symbol table */
        if (shdr.sh_type == SHT_SYMTAB) {
            Elf_Data *data = NULL;
            while ((data = elf_getdata (scn, data)) != NULL) {
                GElf_Sym *es;
                GElf_Sym *last_es;

                es = (GElf_Sym *) data->d_buf;
                if (es == NULL) {
                    continue;
                }

                /* find out how many entries to look for */
                last_es = (GElf_Sym *) ((char *) data->d_buf + data->d_size);

                for (; es < last_es; es += 1) {
                    char *name;

                    /*
                     * need visible global or local (Fortran save) object with
                     * some kind of content
                     */
                    if (es->st_value == 0 || es->st_size == 0) {
                        continue;
                    }
                    /*
                     * this macro handles a symbol that is present
                     * in one libelf implementation but isn't in another
                     * (elfutils vs. libelf)
                     */
#ifndef GELF_ST_VISIBILITY
#define GELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o)
#endif
                    if (GELF_ST_TYPE (es->st_info) != STT_OBJECT &&
                        GELF_ST_VISIBILITY (es->st_info) != STV_DEFAULT) {
                        continue;
                    }
                    name = elf_strptr (e, shdr.sh_link, (size_t) es->st_name);
                    if (name == NULL || *name == '\0') {
                        continue;
                    }
                    /* put the symbol and info into the symbol hash table */
                    {
                        globalvar_t *gv = (globalvar_t *) malloc (sizeof (*gv));
                        if (gv == NULL) {
                            goto bail;
                        }
                        gv->name = strdup (name);
                        if (gv->name == NULL) {
                            free (gv);
                            goto bail;
                        }
                        gv->addr = (void *) es->st_value;
                        gv->size = es->st_size;
                        HASH_ADD_PTR (gvp, addr, gv);
                    }
                }
            }
            /*
             * pulled out all the global symbols => success,
             * don't need to scan further
             */
            ret = 0;
            break;
        }
    }

  bail:

    if (elf_end (e) != 0) {
        ret = -1;
    }

    return ret;
}
int
_dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error)
{
	Dwarf_Obj_Access_Interface *iface;
	Dwarf_Elf_Object *e;
	const char *name;
	GElf_Shdr sh;
	Elf_Scn *scn;
	Elf_Data *symtab_data;
	size_t symtab_ndx;
	int elferr, i, j, n, ret;

	ret = DW_DLE_NONE;

	if ((iface = calloc(1, sizeof(*iface))) == NULL) {
		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
		return (DW_DLE_MEMORY);
	}

	if ((e = calloc(1, sizeof(*e))) == NULL) {
		free(iface);
		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
		return (DW_DLE_MEMORY);
	}

	e->eo_elf = elf;
	e->eo_methods.get_section_info = _dwarf_elf_get_section_info;
	e->eo_methods.get_byte_order = _dwarf_elf_get_byte_order;
	e->eo_methods.get_length_size = _dwarf_elf_get_length_size;
	e->eo_methods.get_pointer_size = _dwarf_elf_get_pointer_size;
	e->eo_methods.get_section_count = _dwarf_elf_get_section_count;
	e->eo_methods.load_section = _dwarf_elf_load_section;

	iface->object = e;
	iface->methods = &e->eo_methods;

	dbg->dbg_iface = iface;

	if (gelf_getehdr(elf, &e->eo_ehdr) == NULL) {
		DWARF_SET_ELF_ERROR(dbg, error);
		ret = DW_DLE_ELF;
		goto fail_cleanup;
	}

	dbg->dbg_machine = e->eo_ehdr.e_machine;

	if (!elf_getshstrndx(elf, &e->eo_strndx)) {
		DWARF_SET_ELF_ERROR(dbg, error);
		ret = DW_DLE_ELF;
		goto fail_cleanup;
	}

	n = 0;
	symtab_ndx = 0;
	symtab_data = NULL;
	scn = NULL;
	(void) elf_errno();
	while ((scn = elf_nextscn(elf, scn)) != NULL) {
		if (gelf_getshdr(scn, &sh) == NULL) {
			DWARF_SET_ELF_ERROR(dbg, error);
			ret = DW_DLE_ELF;
			goto fail_cleanup;
		}

		if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) ==
		    NULL) {
			DWARF_SET_ELF_ERROR(dbg, error);
			ret = DW_DLE_ELF;
			goto fail_cleanup;
		}

		if (!strcmp(name, ".symtab")) {
			symtab_ndx = elf_ndxscn(scn);
			if ((symtab_data = elf_getdata(scn, NULL)) == NULL) {
				elferr = elf_errno();
				if (elferr != 0) {
					_DWARF_SET_ERROR(NULL, error,
					    DW_DLE_ELF, elferr);
					ret = DW_DLE_ELF;
					goto fail_cleanup;
				}
			}
			continue;
		}

		for (i = 0; debug_name[i] != NULL; i++) {
			if (!strcmp(name, debug_name[i]))
				n++;
		}
	}
	elferr = elf_errno();
	if (elferr != 0) {
		DWARF_SET_ELF_ERROR(dbg, error);
		return (DW_DLE_ELF);
	}

	e->eo_seccnt = n;

	if (n == 0)
		return (DW_DLE_NONE);

	if ((e->eo_data = calloc(n, sizeof(Dwarf_Elf_Data))) == NULL ||
	    (e->eo_shdr = calloc(n, sizeof(GElf_Shdr))) == NULL) {
		DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
		ret = DW_DLE_MEMORY;
		goto fail_cleanup;
	}

	scn = NULL;
	j = 0;
	while ((scn = elf_nextscn(elf, scn)) != NULL && j < n) {
		if (gelf_getshdr(scn, &sh) == NULL) {
			DWARF_SET_ELF_ERROR(dbg, error);
			ret = DW_DLE_ELF;
			goto fail_cleanup;
		}

		memcpy(&e->eo_shdr[j], &sh, sizeof(sh));

		if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) ==
		    NULL) {
			DWARF_SET_ELF_ERROR(dbg, error);
			ret = DW_DLE_ELF;
			goto fail_cleanup;
		}

		for (i = 0; debug_name[i] != NULL; i++) {
			if (strcmp(name, debug_name[i]))
				continue;

			(void) elf_errno();
			if ((e->eo_data[j].ed_data = elf_getdata(scn, NULL)) ==
			    NULL) {
				elferr = elf_errno();
				if (elferr != 0) {
					_DWARF_SET_ERROR(dbg, error,
					    DW_DLE_ELF, elferr);
					ret = DW_DLE_ELF;
					goto fail_cleanup;
				}
			}

			if (_libdwarf.applyrela) {
				if (_dwarf_elf_relocate(dbg, elf,
				    &e->eo_data[j], elf_ndxscn(scn), symtab_ndx,
				    symtab_data, error) != DW_DLE_NONE)
					goto fail_cleanup;
			}

			j++;
		}
	}

	assert(j == n);

	return (DW_DLE_NONE);

fail_cleanup:

	_dwarf_elf_deinit(dbg);

	return (ret);
}