Exemplo n.º 1
0
Elf_Scn *elf_utils_new_scn_with_name(Elf *e, const char *scn_name)
{
	Elf_Scn *scn;
	GElf_Shdr shdr;
	size_t shstrndx, index, namelen;
	Elf_Data *shstrdata;
	void *ptr;

	ELF_ASSERT(elf_getshdrstrndx(e, &shstrndx) == 0);

	ELF_ASSERT(scn = elf_getscn(e, shstrndx));
	ELF_ASSERT(shstrdata = elf_getdata(scn, NULL));

	namelen = strlen(scn_name) + 1;
	ELF_ASSERT(gelf_getshdr(scn, &shdr));
	if (!elf_utils_shift_contents(e, shdr.sh_offset + shdr.sh_size, namelen))
		goto failure;
	ASSERT(ptr = realloc(shstrdata->d_buf, shstrdata->d_size + namelen));
	index = shstrdata->d_size;
	strcpy(ptr+index, scn_name);
	shstrdata->d_buf = ptr;
	shstrdata->d_size += namelen;
	shdr.sh_size += namelen;
	ELF_ASSERT(gelf_update_shdr(scn, &shdr));

	ELF_ASSERT(scn = elf_newscn(e));
	ELF_ASSERT(gelf_getshdr(scn, &shdr));
	shdr.sh_name = index;
	ELF_ASSERT(gelf_update_shdr(scn, &shdr));
	
	return scn;
failure:
	return NULL;
}
Exemplo n.º 2
0
Elf_Scn *elf_utils_new_scn_with_data(Elf *e, const char *scn_name, void *buf, int len)
{
	Elf_Scn *scn;
	GElf_Ehdr ehdr;
	GElf_Shdr shdr;
	Elf_Data *data;
	int offset;

	scn = elf_utils_new_scn_with_name(e, scn_name);
	if (scn == NULL)
		goto failure;

	ELF_ASSERT(gelf_getehdr(e, &ehdr));
	offset = ehdr.e_shoff;
	if (!elf_utils_shift_contents(e, offset, len))
		goto failure;

	ELF_ASSERT(gelf_getshdr(scn, &shdr));
	shdr.sh_offset = offset;
	shdr.sh_size = len;
	shdr.sh_addralign = 1;
	ELF_ASSERT(gelf_update_shdr(scn, &shdr));

	ELF_ASSERT(data = elf_newdata(scn));
	data->d_buf = buf;
	data->d_type = ELF_T_BYTE;
	data->d_version = EV_CURRENT;
	data->d_size = len;
	data->d_off = 0;
	data->d_align = 1;

	return scn;
failure:
	return NULL;
}
Exemplo n.º 3
0
Dwfl_Error
internal_function
__libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
			  Elf32_Word shndx, GElf_Addr *value)
{
  assert (mod->e_type == ET_REL);

  Elf_Scn *refscn = elf_getscn (elf, shndx);
  GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
  if (refshdr == NULL)
    return DWFL_E_LIBELF;

  if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
    {
      /* This is a loaded section.  Find its actual
	 address and update the section header.  */

      if (*shstrndx == SHN_UNDEF
	  && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
	return DWFL_E_LIBELF;

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

      if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
						    name, shndx, refshdr,
						    &refshdr->sh_addr))
	return CBFAIL;

      if (refshdr->sh_addr == (Dwarf_Addr) -1l)
	/* The callback indicated this section wasn't really loaded but we
	   don't really care.  */
	refshdr->sh_addr = 0;	/* Make no adjustment below.  */

      /* Update the in-core file's section header to show the final
	 load address (or unloadedness).  This serves as a cache,
	 so we won't get here again for the same section.  */
      if (likely (refshdr->sh_addr != 0)
	  && unlikely (! gelf_update_shdr (refscn, refshdr)))
	return DWFL_E_LIBELF;
    }

  if (refshdr->sh_flags & SHF_ALLOC)
    /* Apply the adjustment.  */
    *value += dwfl_adjusted_address (mod, refshdr->sh_addr);

  return DWFL_E_NOERROR;
}
Exemplo n.º 4
0
int elf_utils_shift_contents(Elf *e, int start_offset, int shift_amount)
{
	GElf_Ehdr ehdr;
	Elf_Scn *scn;
	GElf_Shdr shdr;
	size_t segment_count = 0, segndx;
	GElf_Phdr phdr;
	int bottom_section_offset = 0;

	ELF_ASSERT(gelf_getehdr(e, &ehdr));
	if (ehdr.e_shoff >= start_offset) {
		ehdr.e_shoff += shift_amount;
		ELF_ASSERT(gelf_update_ehdr(e, &ehdr));
	}

	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		ELF_ASSERT(gelf_getshdr(scn, &shdr));
		if (shdr.sh_offset >= start_offset) {
			shdr.sh_offset += shift_amount;
			ELF_ASSERT(gelf_update_shdr(scn, &shdr));
		}
		if (shdr.sh_offset + shdr.sh_size > bottom_section_offset) {
			bottom_section_offset = shdr.sh_offset + shdr.sh_size;
		}
	}

	if (bottom_section_offset > ehdr.e_shoff) {
		ELF_ASSERT(gelf_getehdr(e, &ehdr));
		ehdr.e_shoff = bottom_section_offset;
		ELF_ASSERT(gelf_update_ehdr(e, &ehdr));
	}

	/* A bug in libelf means that getphdrnum will report failure in a new file.
	 * However, it will still set segment_count, so we'll use it. */
	ELF_ASSERT((elf_getphdrnum(e, &segment_count), segment_count > 0));

	for (segndx = 0; segndx < segment_count; segndx++) {
		ELF_ASSERT(gelf_getphdr(e, segndx, &phdr));
		if (phdr.p_offset >= start_offset) {
			phdr.p_offset += shift_amount;
			ELF_ASSERT(gelf_update_phdr(e, segndx, &phdr));
		}
	}
		
	return 1;
failure:
	return 0;
}
Exemplo n.º 5
0
static void remove_dyn(ElfCreator *ctor, size_t idx)
{
	size_t cnt;

	for (cnt = idx; cnt < ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize;
			cnt++) {
		GElf_Dyn *dyn, dyn_mem;

		if (cnt+1 == ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize) {
			memset(&dyn_mem, '\0', sizeof(dyn_mem));
			gelf_update_dyn(ctor->dyndata, cnt, &dyn_mem);
			break;
		}

		dyn = gelf_getdyn(ctor->dyndata, cnt+1, &dyn_mem);
		gelf_update_dyn(ctor->dyndata, cnt, dyn);
	}
	ctor->dynshdr->sh_size--;
	gelf_update_shdr(ctor->dynscn, ctor->dynshdr);
	update_dyn_cache(ctor);
}
Exemplo n.º 6
0
int elf_utils_copy(Elf *dest, Elf *source)
{
	GElf_Ehdr ehdr;
	Elf_Scn *dst_scn, *src_scn;
	GElf_Shdr shdr;
	Elf_Data *dst_data, *src_data;
	size_t segment_count, segndx;
	GElf_Phdr phdr;

	ELF_ASSERT(elf_flagelf(dest, ELF_C_SET, ELF_F_LAYOUT));

	ELF_ASSERT(gelf_getehdr(source, &ehdr));
	ELF_ASSERT(gelf_newehdr(dest, gelf_getclass(source)));
	ELF_ASSERT(gelf_update_ehdr(dest, &ehdr));

	src_scn = NULL;
	while ((src_scn = elf_nextscn(source, src_scn)) != NULL) {
		ELF_ASSERT(gelf_getshdr(src_scn, &shdr));
		ELF_ASSERT(dst_scn = elf_newscn(dest));
		ELF_ASSERT(gelf_update_shdr(dst_scn, &shdr));

		src_data = NULL;
		while ((src_data = elf_getdata(src_scn, src_data)) != NULL) {
			ELF_ASSERT(dst_data = elf_newdata(dst_scn));
			memcpy(dst_data, src_data, sizeof(Elf_Data));
		}
	}

	ELF_ASSERT(elf_getphdrnum(source, &segment_count) == 0);
	ELF_ASSERT(gelf_newphdr(dest, segment_count));

	for (segndx = 0; segndx < segment_count; segndx++) {
		ELF_ASSERT(gelf_getphdr(source, segndx, &phdr));
		ELF_ASSERT(gelf_update_phdr(dest, segndx, &phdr));
	}
		
	return 1;
failure:
	return 0;
}
Exemplo n.º 7
0
int
write_shdr(elf_data_t *elf, Elf_Scn *scn, GElf_Shdr *shdr, size_t sidx, char **err)
{
  off_t off;
  size_t n, shdr_size;
  void *shdr_buf;

  if(!gelf_update_shdr(scn, shdr)) {
    (*err) = "failed to update section header";
    return -1;
  }

  if(elf->bits == 32) {
    shdr_buf = elf32_getshdr(scn);
    shdr_size = sizeof(Elf32_Shdr);
  } else {
    shdr_buf = elf64_getshdr(scn);
    shdr_size = sizeof(Elf64_Shdr);
  }

  if(!shdr_buf) {
    (*err) = "failed to get section header";
    return -1;
  }

  off = lseek(elf->fd, elf->ehdr.e_shoff + sidx*elf->ehdr.e_shentsize, SEEK_SET);
  if(off < 0) {
    (*err) = "lseek failed";
    return -1;
  }
    
  n = write(elf->fd, shdr_buf, shdr_size);
  if(n != shdr_size) {
    (*err) = "write failed";
    return -1;
  }

  return 0;
}
Exemplo n.º 8
0
void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn)
{
	Elf_Scn *newscn;
	Elf_Data *indata, *outdata;
	GElf_Shdr *oldshdr, oldshdr_mem;
	GElf_Shdr *newshdr, newshdr_mem;

	newscn = elf_newscn(ctor->elf);
	newshdr = gelf_getshdr(newscn, &newshdr_mem);

	oldshdr = gelf_getshdr(scn, &oldshdr_mem);

	memmove(newshdr, oldshdr, sizeof(*newshdr));
	gelf_update_shdr(newscn, newshdr);

	indata = NULL;
	while ((indata = elf_getdata(scn, indata)) != NULL) {
		outdata = elf_newdata(newscn);
		*outdata = *indata;
	}
	if (newshdr->sh_type == SHT_DYNAMIC)
		update_dyn_cache(ctor);
}
Exemplo n.º 9
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);
}
Exemplo n.º 10
0
static int
ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
{
	GElf_Ehdr sehdr, dehdr;
	Elf_Scn *sscn, *dscn;
	Elf_Data *sdata, *ddata;
	GElf_Shdr shdr;
	int symtab_idx = -1;
	off_t new_offset = 0;
	off_t ctfnameoff = 0;
	int compress = (flags & CTF_ELFWRITE_F_COMPRESS);
	int *secxlate = NULL;
	int srcidx, dstidx, pad, i;
	int curnmoff = 0;
	int changing = 0;
	int ret;
	size_t nshdr, nphdr, strndx;
	void *strdatabuf = NULL, *symdatabuf = NULL;
	size_t strdatasz = 0, symdatasz = 0;

	void *cdata = NULL;
	size_t elfsize, asize;

	if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) {
		ret = ctf_set_errno(fp, EINVAL);
		goto out;
	}

	if (gelf_newehdr(dst, gelf_getclass(src)) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (gelf_getehdr(src, &sehdr) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	(void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
	if (gelf_update_ehdr(dst, &dehdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/*
	 * Use libelf to get the number of sections and the string section to
	 * deal with ELF files that may have a large number of sections. We just
	 * always use this to make our live easier.
	 */
	if (elf_getphdrnum(src, &nphdr) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_getshdrnum(src, &nshdr) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_getshdrstrndx(src, &strndx) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/*
	 * Neither the existing debug sections nor the SUNW_ctf sections (new or
	 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
	 * program headers.  As such, we can just blindly copy the program
	 * headers from the existing file to the new file.
	 */
	if (nphdr != 0) {
		(void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
		if (gelf_newphdr(dst, nphdr) == 0) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		for (i = 0; i < nphdr; i++) {
			GElf_Phdr phdr;

			if (gelf_getphdr(src, i, &phdr) == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			if (gelf_update_phdr(dst, i, &phdr) == 0) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
		}
	}

	secxlate = ctf_alloc(sizeof (int) * nshdr);
	for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) {
		Elf_Scn *scn = elf_getscn(src, srcidx);
		GElf_Shdr shdr;
		char *sname;

		if (gelf_getshdr(scn, &shdr) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		sname = elf_strptr(src, strndx, shdr.sh_name);
		if (sname == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
			secxlate[srcidx] = -1;
		} else {
			secxlate[srcidx] = dstidx++;
			curnmoff += strlen(sname) + 1;
		}

		new_offset = (off_t)dehdr.e_phoff;
	}

	for (srcidx = 1; srcidx < nshdr; srcidx++) {
		char *sname;

		sscn = elf_getscn(src, srcidx);
		if (gelf_getshdr(sscn, &shdr) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		if (secxlate[srcidx] == -1) {
			changing = 1;
			continue;
		}

		dscn = elf_newscn(dst);
		if (dscn == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		/*
		 * If this file has program headers, we need to explicitly lay
		 * out sections.  If none of the sections prior to this one have
		 * been removed, then we can just use the existing location.  If
		 * one or more sections have been changed, then we need to
		 * adjust this one to avoid holes.
		 */
		if (changing && nphdr != 0) {
			pad = new_offset % shdr.sh_addralign;

			if (pad != 0)
				new_offset += shdr.sh_addralign - pad;
			shdr.sh_offset = new_offset;
		}

		shdr.sh_link = secxlate[shdr.sh_link];

		if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
			shdr.sh_info = secxlate[shdr.sh_info];

		sname = elf_strptr(src, strndx, shdr.sh_name);
		if (sname == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		if ((sdata = elf_getdata(sscn, NULL)) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		if ((ddata = elf_newdata(dscn)) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		bcopy(sdata, ddata, sizeof (Elf_Data));

		if (srcidx == strndx) {
			char seclen = strlen(CTF_ELF_SCN_NAME);

			strdatasz = ddata->d_size + shdr.sh_size +
			    seclen + 1;
			ddata->d_buf = strdatabuf = ctf_alloc(strdatasz);
			if (ddata->d_buf == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
			(void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
			    CTF_ELF_SCN_NAME);
			ctfnameoff = (off_t)shdr.sh_size;
			shdr.sh_size += seclen + 1;
			ddata->d_size += seclen + 1;

			if (nphdr != 0)
				changing = 1;
		}

		if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
			int nsym = shdr.sh_size / shdr.sh_entsize;

			symtab_idx = secxlate[srcidx];

			symdatasz = shdr.sh_size;
			ddata->d_buf = symdatabuf = ctf_alloc(symdatasz);
			if (ddata->d_buf == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			(void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);

			for (i = 0; i < nsym; i++) {
				GElf_Sym sym;
				short newscn;

				(void) gelf_getsym(ddata, i, &sym);

				if (sym.st_shndx >= SHN_LORESERVE)
					continue;

				if ((newscn = secxlate[sym.st_shndx]) !=
				    sym.st_shndx) {
					sym.st_shndx =
					    (newscn == -1 ? 1 : newscn);

					if (gelf_update_sym(ddata, i, &sym) ==
					    0) {
						ret = ctf_set_errno(fp,
						    ECTF_ELF);
						goto out;
					}
				}
			}
		}

		if (gelf_update_shdr(dscn, &shdr) == 0) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		new_offset = (off_t)shdr.sh_offset;
		if (shdr.sh_type != SHT_NOBITS)
			new_offset += shdr.sh_size;
	}

	if (symtab_idx == -1) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/* Add the ctf section */
	if ((dscn = elf_newscn(dst)) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (gelf_getshdr(dscn, &shdr) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	shdr.sh_name = ctfnameoff;
	shdr.sh_type = SHT_PROGBITS;
	shdr.sh_size = fp->ctf_size;
	shdr.sh_link = symtab_idx;
	shdr.sh_addralign = 4;
	if (changing && nphdr != 0) {
		pad = new_offset % shdr.sh_addralign;

		if (pad)
			new_offset += shdr.sh_addralign - pad;

		shdr.sh_offset = new_offset;
		new_offset += shdr.sh_size;
	}

	if ((ddata = elf_newdata(dscn)) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	if (compress != 0) {
		int err;

		if (ctf_zopen(&err) == NULL) {
			ret = ctf_set_errno(fp, err);
			goto out;
		}

		if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) {
			ret = ctf_set_errno(fp, err);
			goto out;
		}
		ddata->d_buf = cdata;
		ddata->d_size = elfsize;
	} else {
		ddata->d_buf = (void *)fp->ctf_base;
		ddata->d_size = fp->ctf_size;
	}
	ddata->d_align = shdr.sh_addralign;

	if (gelf_update_shdr(dscn, &shdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/* update the section header location */
	if (nphdr != 0) {
		size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
		size_t r = new_offset % align;

		if (r)
			new_offset += align - r;

		dehdr.e_shoff = new_offset;
	}

	/* commit to disk */
	if (sehdr.e_shstrndx == SHN_XINDEX)
		dehdr.e_shstrndx = SHN_XINDEX;
	else
		dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
	if (gelf_update_ehdr(dst, &dehdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_update(dst, ELF_C_WRITE) < 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	ret = 0;

out:
	if (strdatabuf != NULL)
		ctf_free(strdatabuf, strdatasz);
	if (symdatabuf != NULL)
		ctf_free(symdatabuf, symdatasz);
	if (cdata != NULL)
		ctf_data_free(cdata, fp->ctf_size);
	if (secxlate != NULL)
		ctf_free(secxlate, sizeof (int) * nshdr);

	return (ret);
}
Exemplo n.º 11
0
int
main (int argc, char *argv[])
{
  if (argc < 3)
    error (EXIT_FAILURE, 0, "usage: %s FROMNAME TONAME", argv[0]);

  elf_version (EV_CURRENT);

  int infd = open (argv[1], O_RDONLY);
  if (infd == -1)
    error (EXIT_FAILURE, errno, "cannot open input file '%s'", argv[1]);

  Elf *inelf = elf_begin (infd, ELF_C_READ, NULL);
  if (inelf == NULL)
    error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s",
	   argv[1], elf_errmsg (-1));

  int outfd = creat (argv[2], 0666);
  if (outfd == -1)
    error (EXIT_FAILURE, errno, "cannot open output file '%s'", argv[2]);

  Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL);
  if (outelf == NULL)
    error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s",
	   argv[2], elf_errmsg (-1));

  gelf_newehdr (outelf, gelf_getclass (inelf));

  GElf_Ehdr ehdr_mem;
  GElf_Ehdr *ehdr;
  gelf_update_ehdr (outelf, (ehdr = gelf_getehdr (inelf, &ehdr_mem)));

  if (ehdr->e_phnum > 0)
    {
      int cnt;

      if (gelf_newphdr (outelf, ehdr->e_phnum) == 0)
	error (EXIT_FAILURE, 0, "cannot create program header: %s",
	       elf_errmsg (-1));

      for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
	{
	  GElf_Phdr phdr_mem;

	  gelf_update_phdr (outelf, cnt, gelf_getphdr (inelf, cnt, &phdr_mem));
	}
    }

  Elf_Scn *scn = NULL;
  while ((scn = elf_nextscn (inelf, scn)) != NULL)
    {
      Elf_Scn *newscn = elf_newscn (outelf);

      GElf_Shdr shdr_mem;
      gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem));

      *elf_newdata (newscn) = *elf_getdata (scn, NULL);
    }

  elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT);

  if (elf_update (outelf, ELF_C_WRITE) == -1)
    error (EXIT_FAILURE, 0, "elf_update failed: %s", elf_errmsg (-1));

  close (outfd);

  return 0;
}
Exemplo n.º 12
0
static Dwfl_Error
relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
		  size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
		  Elf_Scn *scn, GElf_Shdr *shdr,
		  Elf_Scn *tscn, bool debugscn, bool partial)
{
  /* First, fetch the name of the section these relocations apply to.  */
  GElf_Shdr tshdr_mem;
  GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
  const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
  if (tname == NULL)
    return DWFL_E_LIBELF;

  if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0))
    /* No contents to relocate.  */
    return DWFL_E_NOERROR;

  if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
    /* This relocation section is not for a debugging section.
       Nothing to do here.  */
    return DWFL_E_NOERROR;

  /* Fetch the section data that needs the relocations applied.  */
  Elf_Data *tdata = elf_rawdata (tscn, NULL);
  if (tdata == NULL)
    return DWFL_E_LIBELF;

  /* Apply one relocation.  Returns true for any invalid data.  */
  Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
		       int rtype, int symndx)
  {
    /* First see if this is a reloc we can handle.
       If we are skipping it, don't bother resolving the symbol.  */

    if (unlikely (rtype == 0))
      /* In some odd situations, the linker can leave R_*_NONE relocs
	 behind.  This is probably bogus ld -r behavior, but the only
	 cases it's known to appear in are harmless: DWARF data
	 referring to addresses in a section that has been discarded.
	 So we just pretend it's OK without further relocation.  */
      return DWFL_E_NOERROR;

    Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
    if (unlikely (type == ELF_T_NUM))
      return DWFL_E_BADRELTYPE;

    /* First, resolve the symbol to an absolute value.  */
    GElf_Addr value;

    if (symndx == STN_UNDEF)
      /* When strip removes a section symbol referring to a
	 section moved into the debuginfo file, it replaces
	 that symbol index in relocs with STN_UNDEF.  We
	 don't actually need the symbol, because those relocs
	 are always references relative to the nonallocated
	 debugging sections, which start at zero.  */
      value = 0;
    else
      {
	GElf_Sym sym;
	GElf_Word shndx;
	Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
					    symndx, &sym, &shndx);
	if (unlikely (error != DWFL_E_NOERROR))
	  return error;

	if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
	  {
	    /* Maybe we can figure it out anyway.  */
	    error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
	    if (error != DWFL_E_NOERROR
		&& !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
	      return error;
	  }

	value = sym.st_value;
      }

    /* These are the types we can relocate.  */
#define TYPES		DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);	\
    DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);			\
    DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
    size_t size;
    switch (type)
      {
#define DO_TYPE(NAME, Name)			\
	case ELF_T_##NAME:			\
	  size = sizeof (GElf_##Name);		\
	break
	TYPES;
#undef DO_TYPE
      default:
	return DWFL_E_BADRELTYPE;
      }

    if (offset + size > tdata->d_size)
      return DWFL_E_BADRELOFF;

#define DO_TYPE(NAME, Name) GElf_##Name Name;
    union { TYPES; } tmpbuf;
#undef DO_TYPE
    Elf_Data tmpdata =
      {
	.d_type = type,
	.d_buf = &tmpbuf,
	.d_size = size,
	.d_version = EV_CURRENT,
      };
    Elf_Data rdata =
      {
	.d_type = type,
	.d_buf = tdata->d_buf + offset,
	.d_size = size,
	.d_version = EV_CURRENT,
      };

    /* XXX check for overflow? */
    if (addend)
      {
	/* For the addend form, we have the value already.  */
	value += *addend;
	switch (type)
	  {
#define DO_TYPE(NAME, Name)			\
	    case ELF_T_##NAME:			\
	      tmpbuf.Name = value;		\
	    break
	    TYPES;
#undef DO_TYPE
	  default:
	    abort ();
	  }
      }
    else
      {
	/* Extract the original value and apply the reloc.  */
	Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
				     ehdr->e_ident[EI_DATA]);
	if (d == NULL)
	  return DWFL_E_LIBELF;
	assert (d == &tmpdata);
	switch (type)
	  {
#define DO_TYPE(NAME, Name)				\
	    case ELF_T_##NAME:				\
	      tmpbuf.Name += (GElf_##Name) value;	\
	    break
	    TYPES;
#undef DO_TYPE
	  default:
	    abort ();
	  }
      }

    /* Now convert the relocated datum back to the target
       format.  This will write into rdata.d_buf, which
       points into the raw section data being relocated.  */
    Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
				 ehdr->e_ident[EI_DATA]);
    if (s == NULL)
      return DWFL_E_LIBELF;
    assert (s == &rdata);

    /* We have applied this relocation!  */
    return DWFL_E_NOERROR;
  }

  /* Fetch the relocation section and apply each reloc in it.  */
  Elf_Data *reldata = elf_getdata (scn, NULL);
  if (reldata == NULL)
    return DWFL_E_LIBELF;

  Dwfl_Error result = DWFL_E_NOERROR;
  bool first_badreltype = true;
  inline void check_badreltype (void)
  {
    if (first_badreltype)
      {
	first_badreltype = false;
	if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
	  /* This might be because ebl_openbackend failed to find
	     any libebl_CPU.so library.  Diagnose that clearly.  */
	  result = DWFL_E_UNKNOWN_MACHINE;
      }
  }

  size_t nrels = shdr->sh_size / shdr->sh_entsize;
  size_t complete = 0;
  if (shdr->sh_type == SHT_REL)
    for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
      {
	GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
	if (r == NULL)
	  return DWFL_E_LIBELF;
	result = relocate (r->r_offset, NULL,
			   GELF_R_TYPE (r->r_info),
			   GELF_R_SYM (r->r_info));
	check_badreltype ();
	if (partial)
	  switch (result)
	    {
	    case DWFL_E_NOERROR:
	      /* We applied the relocation.  Elide it.  */
	      memset (&rel_mem, 0, sizeof rel_mem);
	      gelf_update_rel (reldata, relidx, &rel_mem);
	      ++complete;
	      break;
	    case DWFL_E_BADRELTYPE:
	    case DWFL_E_RELUNDEF:
	      /* We couldn't handle this relocation.  Skip it.  */
	      result = DWFL_E_NOERROR;
	      break;
	    default:
	      break;
	    }
      }
  else
    for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
      {
	GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
					       &rela_mem);
	if (r == NULL)
	  return DWFL_E_LIBELF;
	result = relocate (r->r_offset, &r->r_addend,
			   GELF_R_TYPE (r->r_info),
			   GELF_R_SYM (r->r_info));
	check_badreltype ();
	if (partial)
	  switch (result)
	    {
	    case DWFL_E_NOERROR:
	      /* We applied the relocation.  Elide it.  */
	      memset (&rela_mem, 0, sizeof rela_mem);
	      gelf_update_rela (reldata, relidx, &rela_mem);
	      ++complete;
	      break;
	    case DWFL_E_BADRELTYPE:
	    case DWFL_E_RELUNDEF:
	      /* We couldn't handle this relocation.  Skip it.  */
	      result = DWFL_E_NOERROR;
	      break;
	    default:
	      break;
	    }
      }

  if (likely (result == DWFL_E_NOERROR))
    {
      if (!partial || complete == nrels)
	/* Mark this relocation section as being empty now that we have
	   done its work.  This affects unstrip -R, so e.g. it emits an
	   empty .rela.debug_info along with a .debug_info that has
	   already been fully relocated.  */
	nrels = 0;
      else if (complete != 0)
	{
	  /* We handled some of the relocations but not all.
	     We've zeroed out the ones we processed.
	     Now remove them from the section.  */

	  size_t next = 0;
	  if (shdr->sh_type == SHT_REL)
	    for (size_t relidx = 0; relidx < nrels; ++relidx)
	      {
		GElf_Rel rel_mem;
		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
		if (r->r_info != 0 || r->r_offset != 0)
		  {
		    if (next != relidx)
		      gelf_update_rel (reldata, next, r);
		    ++next;
		  }
	      }
	  else
	    for (size_t relidx = 0; relidx < nrels; ++relidx)
	      {
		GElf_Rela rela_mem;
		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
		if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
		  {
		    if (next != relidx)
		      gelf_update_rela (reldata, next, r);
		    ++next;
		  }
	      }
	  nrels = next;
	}

      shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
      gelf_update_shdr (scn, shdr);
    }

  return result;
}

Dwfl_Error
internal_function
__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
{
  assert (mod->e_type == ET_REL);

  GElf_Ehdr ehdr_mem;
  const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
  if (ehdr == NULL)
    return DWFL_E_LIBELF;

  size_t d_shstrndx;
  if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
    return DWFL_E_LIBELF;

  RELOC_SYMTAB_CACHE (reloc_symtab);

  /* Look at each section in the debuginfo file, and process the
     relocation sections for debugging sections.  */
  Dwfl_Error result = DWFL_E_NOERROR;
  Elf_Scn *scn = NULL;
  while (result == DWFL_E_NOERROR
	 && (scn = elf_nextscn (debugfile, scn)) != NULL)
    {
      GElf_Shdr shdr_mem;
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);

      if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
	  && shdr->sh_size != 0)
	{
	  /* It's a relocation section.  */

	  Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
	  if (unlikely (tscn == NULL))
	    result = DWFL_E_LIBELF;
	  else
	    result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
				       &reloc_symtab, scn, shdr, tscn,
				       debug, !debug);
	}
    }

  return result;
}
Exemplo n.º 13
0
int main( int argc, char *argv[])
{
	int fd, cmd;
	char *scn_name;

	Elf *elf;
	GElf_Ehdr ehdr;
	Elf_Scn *scn;
	GElf_Shdr shdr;
	Elf_Data *data;
	GElf_Dyn dyn;

	if(argc != 3)
		error(EXIT_FAILURE, 0, "Usage: %s <elf> <ld.so>", argv[0]);

	if(elf_version(EV_CURRENT) == EV_NONE)
		error(EXIT_FAILURE, 0, "Library out of date.");

	if((fd = open(argv[1], O_RDWR)) == -1)
		error(EXIT_FAILURE, 0, "Failed open file.");

	if((elf = elf_begin(fd, ELF_C_RDWR_MMAP, elf)) != NULL)
	{
		if(gelf_getehdr(elf,&ehdr) != NULL)
		{
			scn = NULL;
			while((scn = elf_nextscn(elf, scn)) != NULL)
			{
				gelf_getshdr(scn, &shdr);
				scn_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);

				if(strcmp(scn_name, ".interp"))
					continue;

				printf("Section name: %s\n", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));

				if((data = elf_getdata(scn, data)) != NULL)
				{
					printf("Old ld.so: %s\n", (char *)data->d_buf);
					printf("Data size: %zu\n", data->d_size);
					/*
					printf( "Data:\t\t%s\nType:\t\t%d\nSize:\t\t%lu\n"
						"Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n",
						(char *)data->d_buf,
						data->d_type,
						data->d_size,
						data->d_off,
						data->d_align,
						data->d_version
					);
					*/

					if(data->d_size >= strlen(argv[2]))
					{
						memset(data->d_buf, 0, data->d_size);
						strncpy(data->d_buf, argv[2], data->d_size);

						if(!gelf_update_shdr(scn, &shdr))
						{
							elf_end(elf);
							close(fd);
							error(EXIT_FAILURE, 0, "\tELF ERROR: gelf_update_shdr(): %s", elf_errmsg(elf_errno()));
						}
					}
					else
					{
						elf_end(elf);
						close(fd);
						error(EXIT_FAILURE, 0, "\tld.so path too long: max=%zu", data->d_size);
					}

					printf( "New ld.so: %s\n", (char *)data->d_buf);
					/*
					printf( "Data:\t\t%s\nType:\t\t%d\nSize:\t\t%lu\n"
						"Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n",
						(char *)data->d_buf,
						data->d_type,
						data->d_size,
						data->d_off,
						data->d_align,
						data->d_version
					);
					*/
				}
			}
		}
	}

	elf_end(elf);
	close(fd);
}