int gelf_getclass(Elf *elf) { if (elf && elf->e_kind == ELF_K_ELF && valid_class(elf->e_class)) { return elf->e_class; } return ELFCLASSNONE; }
GElf_Phdr* gelf_getphdr(Elf *elf, int ndx, GElf_Phdr *dst) { GElf_Phdr buf; char *tmp; size_t n; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getphdr(elf, elf->e_class); if (!tmp) { return NULL; } if (ndx < 0 || ndx >= elf->e_phnum) { seterr(ERROR_BADINDEX); return NULL; } n = _msize(elf->e_class, _elf_version, ELF_T_PHDR); if (n == 0) { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (!dst) { dst = &buf; } if (elf->e_class == ELFCLASS64) { *dst = *(Elf64_Phdr*)(tmp + ndx * n); } else if (elf->e_class == ELFCLASS32) { Elf32_Phdr *src = (Elf32_Phdr*)(tmp + ndx * n); check_and_copy(GElf_Word, dst, src, p_type, NULL); check_and_copy(GElf_Word, dst, src, p_flags, NULL); check_and_copy(GElf_Off, dst, src, p_offset, NULL); check_and_copy(GElf_Addr, dst, src, p_vaddr, NULL); check_and_copy(GElf_Addr, dst, src, p_paddr, NULL); check_and_copy(GElf_Xword, dst, src, p_filesz, NULL); check_and_copy(GElf_Xword, dst, src, p_memsz, NULL); check_and_copy(GElf_Xword, dst, src, p_align, NULL); } else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return NULL; } if (dst == &buf) { dst = (GElf_Phdr*)malloc(sizeof(GElf_Phdr)); if (!dst) { seterr(ERROR_MEM_PHDR); return NULL; } *dst = buf; } return dst; }
int gelf_update_shdr(Elf_Scn *scn, GElf_Shdr *src) { if (!scn || !src) { return 0; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf); elf_assert(scn->s_elf->e_magic == ELF_MAGIC); if (scn->s_elf->e_class == ELFCLASS64) { scn->s_shdr64 = *src; } else if (scn->s_elf->e_class == ELFCLASS32) { Elf32_Shdr *dst = &scn->s_shdr32; check_and_copy(Elf32_Word, dst, src, sh_name, 0); check_and_copy(Elf32_Word, dst, src, sh_type, 0); check_and_copy(Elf32_Word, dst, src, sh_flags, 0); check_and_copy(Elf32_Addr, dst, src, sh_addr, 0); check_and_copy(Elf32_Off, dst, src, sh_offset, 0); check_and_copy(Elf32_Word, dst, src, sh_size, 0); check_and_copy(Elf32_Word, dst, src, sh_link, 0); check_and_copy(Elf32_Word, dst, src, sh_info, 0); check_and_copy(Elf32_Word, dst, src, sh_addralign, 0); check_and_copy(Elf32_Word, dst, src, sh_entsize, 0); } else if (valid_class(scn->s_elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); return 0; } else { seterr(ERROR_UNKNOWN_CLASS); return 0; } return 1; }
/* * Extension: report memory size */ size_t gcgcef_msize(CGCEf *cgcef, CGCEf_Type type, size_t count, unsigned ver) { size_t n; if (cgcef) { if (cgcef->e_kind != CGCEF_K_CGCEF) { seterr(ERROR_NOTCGCEF); } else if (!valid_class(cgcef->e_class)) { seterr(ERROR_UNKNOWN_CLASS); } else if (!valid_version(ver)) { seterr(ERROR_UNKNOWN_VERSION); } else if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); } else if (!(n = _msize(cgcef->e_class, ver, type))) { seterr(ERROR_UNKNOWN_TYPE); } else { return count * n; } } return 0; }
/* * Extension: report memory size */ size_t gelf_msize(Elf *elf, Elf_Type type, size_t count, unsigned ver) { size_t n; if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (!valid_class(elf->e_class)) { seterr(ERROR_UNKNOWN_CLASS); } else if (!valid_version(ver)) { seterr(ERROR_UNKNOWN_VERSION); } else if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); } else if (!(n = _msize(elf->e_class, ver, type))) { seterr(ERROR_UNKNOWN_TYPE); } else { return count * n; } } return 0; }
unsigned long gcgcef_newphdr(CGCEf *cgcef, size_t phnum) { if (!valid_class(cgcef->e_class)) { seterr(ERROR_UNKNOWN_CLASS); return 0; } return (unsigned long)_cgcef_newphdr(cgcef, phnum, cgcef->e_class); }
unsigned long gelf_newphdr(Elf *elf, size_t phnum) { if (!valid_class(elf->e_class)) { seterr(ERROR_UNKNOWN_CLASS); return 0; } return (unsigned long)_elf_newphdr(elf, phnum, elf->e_class); }
int elf_getshstrndx(Elf *elf, size_t *resultp) { size_t num = 0; size_t dummy; Elf_Scn *scn; if (!elf) { return LIBELF_FAILURE; } elf_assert(elf->e_magic == ELF_MAGIC); if (resultp == NULL) { resultp = &dummy; /* handle NULL pointer gracefully */ } if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return LIBELF_FAILURE; } if (!elf->e_ehdr && !_elf_cook(elf)) { return LIBELF_FAILURE; } if (elf->e_class == ELFCLASS32) { num = ((Elf32_Ehdr*)elf->e_ehdr)->e_shstrndx; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { num = ((Elf64_Ehdr*)elf->e_ehdr)->e_shstrndx; } #endif /* __LIBELF64 */ else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return LIBELF_FAILURE; } if (num != SHN_XINDEX) { *resultp = num; return LIBELF_SUCCESS; } /* * look at first section header */ if (!(scn = elf->e_scn_1)) { seterr(ERROR_NOSUCHSCN); return LIBELF_FAILURE; } elf_assert(scn->s_magic == SCN_MAGIC); #if __LIBELF64 if (elf->e_class == ELFCLASS64) { *resultp = scn->s_shdr64.sh_link; return LIBELF_SUCCESS; } #endif /* __LIBELF64 */ *resultp = scn->s_shdr32.sh_link; return LIBELF_SUCCESS; }
unsigned long gelf_newehdr(Elf * elf, int cls) { if (!valid_class(cls) || !_msize(cls, _elf_version, ELF_T_EHDR)) { seterr(ERROR_UNKNOWN_CLASS); return 0; } return (unsigned long)_elf_newehdr(elf, cls); }
GElf_Ehdr* gelf_getehdr(Elf *elf, GElf_Ehdr *dst) { GElf_Ehdr buf; char *tmp; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getehdr(elf, elf->e_class); if (!tmp) { return NULL; } if (!dst) { dst = &buf; } if (elf->e_class == ELFCLASS64) { *dst = *(Elf64_Ehdr*)tmp; } else if (elf->e_class == ELFCLASS32) { Elf32_Ehdr *src = (Elf32_Ehdr*)tmp; memcpy(dst->e_ident, src->e_ident, EI_NIDENT); check_and_copy(GElf_Half, dst, src, e_type, NULL); check_and_copy(GElf_Half, dst, src, e_machine, NULL); check_and_copy(GElf_Word, dst, src, e_version, NULL); check_and_copy(GElf_Addr, dst, src, e_entry, NULL); check_and_copy(GElf_Off, dst, src, e_phoff, NULL); check_and_copy(GElf_Off, dst, src, e_shoff, NULL); check_and_copy(GElf_Word, dst, src, e_flags, NULL); check_and_copy(GElf_Half, dst, src, e_ehsize, NULL); check_and_copy(GElf_Half, dst, src, e_phentsize, NULL); check_and_copy(GElf_Half, dst, src, e_phnum, NULL); check_and_copy(GElf_Half, dst, src, e_shentsize, NULL); check_and_copy(GElf_Half, dst, src, e_shnum, NULL); check_and_copy(GElf_Half, dst, src, e_shstrndx, NULL); } else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); return NULL; } else { seterr(ERROR_UNKNOWN_CLASS); return NULL; } if (dst == &buf) { dst = (GElf_Ehdr*)malloc(sizeof(GElf_Ehdr)); if (!dst) { seterr(ERROR_MEM_EHDR); return NULL; } *dst = buf; } return dst; }
GElf_Shdr* gelf_getshdr(Elf_Scn *scn, GElf_Shdr *dst) { GElf_Shdr buf; if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf); elf_assert(scn->s_elf->e_magic == ELF_MAGIC); if (!dst) { dst = &buf; } if (scn->s_elf->e_class == ELFCLASS64) { *dst = scn->s_shdr64; } else if (scn->s_elf->e_class == ELFCLASS32) { Elf32_Shdr *src = &scn->s_shdr32; check_and_copy(GElf_Word, dst, src, sh_name, NULL); check_and_copy(GElf_Word, dst, src, sh_type, NULL); check_and_copy(GElf_Xword, dst, src, sh_flags, NULL); check_and_copy(GElf_Addr, dst, src, sh_addr, NULL); check_and_copy(GElf_Off, dst, src, sh_offset, NULL); check_and_copy(GElf_Xword, dst, src, sh_size, NULL); check_and_copy(GElf_Word, dst, src, sh_link, NULL); check_and_copy(GElf_Word, dst, src, sh_info, NULL); check_and_copy(GElf_Xword, dst, src, sh_addralign, NULL); check_and_copy(GElf_Xword, dst, src, sh_entsize, NULL); } else { if (valid_class(scn->s_elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return NULL; } if (dst == &buf) { dst = (GElf_Shdr*)malloc(sizeof(GElf_Shdr)); if (!dst) { seterr(ERROR_MEM_SHDR); return NULL; } *dst = buf; } return dst; }
size_t gelf_fsize(Elf *elf, Elf_Type type, size_t count, unsigned ver) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (valid_class(elf->e_class)) { return count * _elf_fsize(elf->e_class, type, ver); } else { seterr(ERROR_UNKNOWN_CLASS); } } return 0; }
size_t gcgcef_fsize(CGCEf *cgcef, CGCEf_Type type, size_t count, unsigned ver) { if (cgcef) { if (cgcef->e_kind != CGCEF_K_CGCEF) { seterr(ERROR_NOTCGCEF); } else if (valid_class(cgcef->e_class)) { return count * _cgcef_fsize(cgcef->e_class, type, ver); } else { seterr(ERROR_UNKNOWN_CLASS); } } return 0; }
int gelf_update_phdr(Elf *elf, int ndx, GElf_Phdr *src) { char *tmp; size_t n; if (!elf || !src) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getphdr(elf, elf->e_class); if (!tmp) { return 0; } if (ndx < 0 || ndx >= elf->e_phnum) { seterr(ERROR_BADINDEX); return 0; } n = _msize(elf->e_class, _elf_version, ELF_T_PHDR); if (n == 0) { seterr(ERROR_UNIMPLEMENTED); return 0; } if (elf->e_class == ELFCLASS64) { *(Elf64_Phdr*)(tmp + ndx * n) = *src; } else if (elf->e_class == ELFCLASS32) { Elf32_Phdr *dst = (Elf32_Phdr*)(tmp + ndx * n); check_and_copy(Elf32_Word, dst, src, p_type, 0); check_and_copy(Elf32_Off, dst, src, p_offset, 0); check_and_copy(Elf32_Addr, dst, src, p_vaddr, 0); check_and_copy(Elf32_Addr, dst, src, p_paddr, 0); check_and_copy(Elf32_Word, dst, src, p_filesz, 0); check_and_copy(Elf32_Word, dst, src, p_memsz, 0); check_and_copy(Elf32_Word, dst, src, p_flags, 0); check_and_copy(Elf32_Word, dst, src, p_align, 0); } else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return 0; } return 1; }
static char* get_addr_and_class(const Elf_Data *data, int ndx, Elf_Type type, unsigned *cls) { Scn_Data *sd = (Scn_Data*)data; Elf_Scn *scn; Elf *elf; size_t n; if (!sd) { return NULL; } elf_assert(sd->sd_magic == DATA_MAGIC); scn = sd->sd_scn; elf_assert(scn); elf_assert(scn->s_magic == SCN_MAGIC); elf = scn->s_elf; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return NULL; } if (!valid_class(elf->e_class)) { seterr(ERROR_UNKNOWN_CLASS); return NULL; } if (data->d_type != type) { seterr(ERROR_BADTYPE); return NULL; } n = _msize(elf->e_class, data->d_version, type); if (n == 0) { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (ndx < 0 || data->d_size < (ndx + 1) * n) { seterr(ERROR_BADINDEX); return NULL; } if (!data->d_buf) { seterr(ERROR_NULLBUF); return NULL; } if (cls) { *cls = elf->e_class; } return (char*)data->d_buf + n * ndx; }
int elfx_update_shstrndx(Elf *elf, size_t value) { size_t extvalue = 0; Elf_Scn *scn; if (!elf) { return LIBELF_FAILURE; } elf_assert(elf->e_magic == ELF_MAGIC); if (value >= SHN_LORESERVE) { extvalue = value; value = SHN_XINDEX; } if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return LIBELF_FAILURE; } if (!elf->e_ehdr && !_elf_cook(elf)) { return LIBELF_FAILURE; } if (!(scn = _elf_first_scn(elf))) { return LIBELF_FAILURE; } elf_assert(scn->s_magic == SCN_MAGIC); if (elf->e_class == ELFCLASS32) { ((Elf32_Ehdr*)elf->e_ehdr)->e_shstrndx = value; scn->s_shdr32.sh_link = extvalue; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { ((Elf64_Ehdr*)elf->e_ehdr)->e_shstrndx = value; scn->s_shdr64.sh_link = extvalue; } #endif /* __LIBELF64 */ else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return LIBELF_FAILURE; } elf->e_ehdr_flags |= ELF_F_DIRTY; scn->s_shdr_flags |= ELF_F_DIRTY; return LIBELF_SUCCESS; }
int gelf_update_ehdr(Elf *elf, GElf_Ehdr *src) { char *tmp; if (!elf || !src) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getehdr(elf, elf->e_class); if (!tmp) { return 0; } if (elf->e_class == ELFCLASS64) { *(Elf64_Ehdr*)tmp = *src; } else if (elf->e_class == ELFCLASS32) { Elf32_Ehdr *dst = (Elf32_Ehdr*)tmp; memcpy(dst->e_ident, src->e_ident, EI_NIDENT); check_and_copy(Elf32_Half, dst, src, e_type, 0); check_and_copy(Elf32_Half, dst, src, e_machine, 0); check_and_copy(Elf32_Word, dst, src, e_version, 0); check_and_copy(Elf32_Addr, dst, src, e_entry, 0); check_and_copy(Elf32_Off, dst, src, e_phoff, 0); check_and_copy(Elf32_Off, dst, src, e_shoff, 0); check_and_copy(Elf32_Word, dst, src, e_flags, 0); check_and_copy(Elf32_Half, dst, src, e_ehsize, 0); check_and_copy(Elf32_Half, dst, src, e_phentsize, 0); check_and_copy(Elf32_Half, dst, src, e_phnum, 0); check_and_copy(Elf32_Half, dst, src, e_shentsize, 0); check_and_copy(Elf32_Half, dst, src, e_shnum, 0); check_and_copy(Elf32_Half, dst, src, e_shstrndx, 0); } else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); return 0; } else { seterr(ERROR_UNKNOWN_CLASS); return 0; } return 1; }
Elf_Data* gelf_xlatetof(Elf *elf, Elf_Data *dst, const Elf_Data *src, unsigned encode) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class == ELFCLASS32) { return elf32_xlatetof(dst, src, encode); } else if (elf->e_class == ELFCLASS64) { return elf64_xlatetof(dst, src, encode); } else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } } return NULL; }
int _elf_update_shnum(Elf *elf, size_t shnum) { Elf_Scn *scn; if (elf->e_class == ELFCLASS32) { if (shnum >= SHN_LORESERVE) { scn = elf->e_scn_1; elf_assert(scn->s_index == 0); scn->s_shdr_flags |= ELF_F_DIRTY; scn->s_shdr32.sh_size = shnum; shnum = 0; } elf->e_ehdr_flags |= ELF_F_DIRTY; ((Elf32_Ehdr*)elf->e_ehdr)->e_shnum = shnum; return 0; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { if (shnum >= SHN_LORESERVE) { scn = elf->e_scn_1; elf_assert(scn->s_index == 0); scn->s_shdr_flags |= ELF_F_DIRTY; scn->s_shdr64.sh_size = shnum; shnum = 0; } elf->e_ehdr_flags |= ELF_F_DIRTY; ((Elf64_Ehdr*)elf->e_ehdr)->e_shnum = shnum; return 0; } #endif /* __LIBELF64 */ else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return -1; }
size_t elf_delscn(Elf * elf, Elf_Scn * scn) { Elf_Scn *pscn; Scn_Data *sd; Scn_Data *tmp; size_t index; if (!elf || !scn) { return SHN_UNDEF; } elf_assert(elf->e_magic == ELF_MAGIC); elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(elf->e_ehdr); if (scn->s_elf != elf) { seterr(ERROR_ELFSCNMISMATCH); return SHN_UNDEF; } elf_assert(elf->e_scn_1); if (scn == elf->e_scn_1) { seterr(ERROR_NULLSCN); return SHN_UNDEF; } /* * Find previous section. */ for (pscn = elf->e_scn_1; pscn->s_link; pscn = pscn->s_link) { if (pscn->s_link == scn) { break; } } if (pscn->s_link != scn) { seterr(ERROR_ELFSCNMISMATCH); return SHN_UNDEF; } /* * Unlink section. */ if (elf->e_scn_n == scn) { elf->e_scn_n = pscn; } pscn->s_link = scn->s_link; index = scn->s_index; /* * Free section descriptor and data. */ for (sd = scn->s_data_1; sd; sd = tmp) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); tmp = sd->sd_link; if (sd->sd_free_data && sd->sd_memdata) { free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if ((sd = scn->s_rawdata)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (sd->sd_free_data && sd->sd_memdata) { free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if (scn->s_freeme) { elf_assert(scn->s_index > 0); free(scn); } /* * Adjust section indices. */ for (scn = pscn->s_link; scn; scn = scn->s_link) { elf_assert(scn->s_index > index); scn->s_index--; } /* * Adjust ELF header and well-known section headers. */ if (elf->e_class == ELFCLASS32) { _elf32_update_shdr(elf, index); return index; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { _elf64_update_shdr(elf, index); return index; } #endif /* __LIBELF64 */ else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return SHN_UNDEF; }
char* elf_strptr(Elf *elf, size_t section, size_t offset) { Elf_Data *data; Elf_Scn *scn; size_t n; char *s; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (!(scn = elf_getscn(elf, section))) { return NULL; } if (scn->s_index == SHN_UNDEF) { seterr(ERROR_NOSTRTAB); return NULL; } /* * checking the section header is more appropriate */ if (elf->e_class == ELFCLASS32) { if (scn->s_shdr32.sh_type != SHT_STRTAB) { seterr(ERROR_NOSTRTAB); return NULL; } } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { if (scn->s_shdr64.sh_type != SHT_STRTAB) { seterr(ERROR_NOSTRTAB); return NULL; } } #endif /* __LIBELF64 */ else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); return NULL; } else { seterr(ERROR_UNKNOWN_CLASS); return NULL; } /* * Find matching buffer */ n = 0; data = NULL; if (elf->e_elf_flags & ELF_F_LAYOUT) { /* * Programmer is responsible for d_off * Note: buffers may be in any order! */ while ((data = elf_getdata(scn, data))) { n = data->d_off; if (offset >= n && offset - n < data->d_size) { /* * Found it */ break; } } } else { /* * Calculate offsets myself */ while ((data = elf_getdata(scn, data))) { if (data->d_align > 1) { n += data->d_align - 1; n -= n % data->d_align; } if (offset < n) { /* * Invalid offset: points into a hole */ seterr(ERROR_BADSTROFF); return NULL; } if (offset - n < data->d_size) { /* * Found it */ break; } n += data->d_size; } } if (data == NULL) { /* * Not found */ seterr(ERROR_BADSTROFF); return NULL; } if (data->d_buf == NULL) { /* * Buffer is NULL (usually the programmers' fault) */ seterr(ERROR_NULLBUF); return NULL; } offset -= n; s = (char*)data->d_buf; for (n = offset; n < data->d_size; n++) { if (s[n] == '\0') { /* * Return properly NUL terminated string */ return s + offset; } } /* * String is not NUL terminated * Return error to avoid SEGV in application */ seterr(ERROR_UNTERM); return NULL; }
static off_t scn_data_layout(Elf_Scn *scn, unsigned v, unsigned type, size_t *algn, unsigned *flag) { Elf *elf = scn->s_elf; Elf_Data *data; int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; size_t scn_align = 1; size_t len = 0; Scn_Data *sd; size_t fsize; if (!(sd = scn->s_data_1)) { /* no data in section */ *algn = scn_align; return (off_t)len; } /* load data from file, if any */ if (!(data = elf_getdata(scn, NULL))) { return (off_t)-1; } elf_assert(data == &sd->sd_data); for (; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (!valid_version(sd->sd_data.d_version)) { return (off_t)-1; } fsize = sd->sd_data.d_size; if (fsize && type != SHT_NOBITS && valid_type(sd->sd_data.d_type)) { if (elf->e_class == ELFCLASS32) { fsize = _elf32_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { fsize = _elf64_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); } #endif /* __LIBELF64 */ else { elf_assert(valid_class(elf->e_class)); seterr(ERROR_UNIMPLEMENTED); return (off_t)-1; } if (fsize == (size_t)-1) { return (off_t)-1; } } if (layout) { align(len, sd->sd_data.d_align); scn_align = max(scn_align, sd->sd_data.d_align); rewrite(sd->sd_data.d_off, (off_t)len, sd->sd_data_flags); len += fsize; } else { len = max(len, sd->sd_data.d_off + fsize); } *flag |= sd->sd_data_flags; } *algn = scn_align; return (off_t)len; }
static off_t _elf_output(Elf *elf, int fd, size_t len, off_t (*_elf_write)(Elf*, char*, size_t)) { char *buf; off_t err; elf_assert(len); #if HAVE_FTRUNCATE ftruncate(fd, 0); #endif /* HAVE_FTRUNCATE */ #if HAVE_MMAP /* * Make sure the file is (at least) len bytes long */ #if HAVE_FTRUNCATE if (ftruncate(fd, len)) { #else /* HAVE_FTRUNCATE */ { #endif /* HAVE_FTRUNCATE */ if (lseek(fd, (off_t)len - 1, SEEK_SET) != (off_t)len - 1) { seterr(ERROR_IO_SEEK); return -1; } if (write(fd, "", 1) != 1) { seterr(ERROR_IO_WRITE); return -1; } } buf = (void*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf != (char*)-1) { if ((char)_elf_fill && !(elf->e_elf_flags & ELF_F_LAYOUT)) { memset(buf, _elf_fill, len); } err = _elf_write(elf, buf, len); munmap(buf, len); return err; } #endif /* HAVE_MMAP */ if (!(buf = (char*)malloc(len))) { seterr(ERROR_MEM_OUTBUF); return -1; } memset(buf, _elf_fill, len); err = _elf_write(elf, buf, len); if (err != -1 && (size_t)err == len) { if (lseek(fd, (off_t)0, SEEK_SET)) { seterr(ERROR_IO_SEEK); err = -1; } else if (write(fd, buf, len) != len) { seterr(ERROR_IO_WRITE); err = -1; } } free(buf); return err; } off_t elf_update(Elf *elf, Elf_Cmd cmd) { unsigned flag; off_t len; if (!elf) { return -1; } elf_assert(elf->e_magic == ELF_MAGIC); if (cmd == ELF_C_WRITE) { if (!elf->e_writable) { seterr(ERROR_RDONLY); return -1; } if (elf->e_disabled) { seterr(ERROR_FDDISABLED); return -1; } } else if (cmd != ELF_C_NULL) { seterr(ERROR_INVALID_CMD); return -1; } if (!elf->e_ehdr) { seterr(ERROR_NOEHDR); } else if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class == ELFCLASS32) { len = _elf32_layout(elf, &flag); if (len != -1 && cmd == ELF_C_WRITE && (flag & ELF_F_DIRTY)) { len = _elf_output(elf, elf->e_fd, (size_t)len, _elf32_write); } return len; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { len = _elf64_layout(elf, &flag); if (len != -1 && cmd == ELF_C_WRITE && (flag & ELF_F_DIRTY)) { len = _elf_output(elf, elf->e_fd, (size_t)len, _elf64_write); } return len; } #endif /* __LIBELF64 */ else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return -1; }
static Elf_Data* _elf_cook_scn(Elf *elf, Elf_Scn *scn, Scn_Data *sd) { Elf_Data dst; Elf_Data src; int flag = 0; size_t dlen; elf_assert(elf->e_data); /* * Prepare source */ src = sd->sd_data; src.d_version = elf->e_version; if (elf->e_rawdata) { src.d_buf = elf->e_rawdata + scn->s_offset; } else { src.d_buf = elf->e_data + scn->s_offset; } /* * Prepare destination (needs prepared source!) */ dst = sd->sd_data; if (elf->e_class == ELFCLASS32) { dlen = _elf32_xltsize(&src, dst.d_version, elf->e_encoding, 0); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { dlen = _elf64_xltsize(&src, dst.d_version, elf->e_encoding, 0); } #endif /* __LIBELF64 */ else { elf_assert(valid_class(elf->e_class)); seterr(ERROR_UNIMPLEMENTED); return NULL; } if (dlen == (size_t)-1) { return NULL; } dst.d_size = dlen; if (elf->e_rawdata != elf->e_data && dst.d_size <= src.d_size) { dst.d_buf = elf->e_data + scn->s_offset; } else if (!(dst.d_buf = malloc(dst.d_size))) { seterr(ERROR_MEM_SCNDATA); return NULL; } else { flag = 1; } /* * Translate data */ if (_elf_xlatetom(elf, &dst, &src)) { sd->sd_memdata = (char*)dst.d_buf; sd->sd_data = dst; if (!(sd->sd_free_data = flag)) { elf->e_cooked = 1; } return &sd->sd_data; } if (flag) { free(dst.d_buf); } return NULL; }
Elf_Data* elf_getdata(Elf_Scn *scn, Elf_Data *data) { Scn_Data *sd; Elf *elf; if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); if (scn->s_index == SHN_UNDEF) { seterr(ERROR_NULLSCN); } else if (data) { for (sd = scn->s_data_1; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (data == &sd->sd_data) { /* * sd_link allocated by elf_newdata(). */ return &sd->sd_link->sd_data; } } seterr(ERROR_SCNDATAMISMATCH); } else if ((sd = scn->s_data_1)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); elf = scn->s_elf; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); if (sd->sd_freeme) { /* allocated by elf_newdata() */ return &sd->sd_data; } else if (scn->s_type == SHT_NULL) { seterr(ERROR_NULLSCN); } else if (sd->sd_memdata) { /* already cooked */ return &sd->sd_data; } else if (scn->s_offset < 0 || scn->s_offset > elf->e_size) { seterr(ERROR_OUTSIDE); } else if (scn->s_type == SHT_NOBITS || !scn->s_size) { /* no data to read */ return &sd->sd_data; } else if (scn->s_offset + scn->s_size > elf->e_size) { seterr(ERROR_TRUNC_SCN); } else if (valid_class(elf->e_class)) { return _elf_cook_scn(elf, scn, sd); } else { seterr(ERROR_UNKNOWN_CLASS); } } return NULL; }