int elf_errno(void) { int old; old = LIBELF_PRIVATE(error); LIBELF_PRIVATE(error) = 0; return (old & LIBELF_ELF_ERROR_MASK); }
const char * elf_errmsg(int error) { int oserr; if (error == 0 && (error = LIBELF_PRIVATE(error)) == 0) return NULL; else if (error == -1) error = LIBELF_PRIVATE(error); oserr = error >> LIBELF_OS_ERROR_SHIFT; error &= LIBELF_ELF_ERROR_MASK; if (error < 0 || error >= ELF_E_NUM) return _libelf_errors[ELF_E_NUM]; if (oserr) { strlcpy(LIBELF_PRIVATE(msg), _libelf_errors[error], sizeof(LIBELF_PRIVATE(msg))); strlcat(LIBELF_PRIVATE(msg), ": ", sizeof(LIBELF_PRIVATE(msg))); strlcat(LIBELF_PRIVATE(msg), strerror(oserr), sizeof(LIBELF_PRIVATE(msg))); return (const char *)&LIBELF_PRIVATE(msg); } return _libelf_errors[error]; }
Elf * elf_begin(int fd, Elf_Cmd c, Elf *a) { Elf *e; e = NULL; if (LIBELF_PRIVATE(version) == EV_NONE) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } switch (c) { case ELF_C_NULL: return (NULL); case ELF_C_WRITE: /* * The ELF_C_WRITE command is required to ignore the * descriptor passed in. */ a = NULL; break; case ELF_C_RDWR: if (a != NULL) { /* not allowed for ar(1) archives. */ LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } /*FALLTHROUGH*/ case ELF_C_READ: /* * Descriptor `a' could be for a regular ELF file, or * for an ar(1) archive. If descriptor `a' was opened * using a valid file descriptor, we need to check if * the passed in `fd' value matches the original one. */ if (a && ((a->e_fd != -1 && a->e_fd != fd) || c != a->e_cmd)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } break; default: LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (a == NULL) e = _libelf_open_object(fd, c); else if (a->e_kind == ELF_K_AR) e = _libelf_ar_open_member(a->e_fd, c, a); else (e = a)->e_activations++; return (e); }
unsigned int elf_version(unsigned int v) { unsigned int old; if ((old = LIBELF_PRIVATE(version)) == EV_NONE) old = EV_CURRENT; if (v == EV_NONE) return old; if (v > EV_CURRENT) { LIBELF_SET_ERROR(VERSION, 0); return EV_NONE; } LIBELF_PRIVATE(version) = v; return (old); }
Elf * elf_memory(char *image, size_t sz) { Elf *e; if (LIBELF_PRIVATE(version) == EV_NONE) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } if (image == NULL || sz == 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if ((e = _libelf_allocate_elf()) == NULL) return (NULL); e->e_cmd = ELF_C_READ; e->e_rawfile = image; e->e_rawsize = sz; #undef LIBELF_IS_ELF #define LIBELF_IS_ELF(P) ((P)[EI_MAG0] == ELFMAG0 && \ (P)[EI_MAG1] == ELFMAG1 && (P)[EI_MAG2] == ELFMAG2 && \ (P)[EI_MAG3] == ELFMAG3) if (sz > EI_NIDENT && LIBELF_IS_ELF(image)) { _libelf_init_elf(e, ELF_K_ELF); e->e_class = image[EI_CLASS]; e->e_byteorder = image[EI_DATA]; e->e_version = image[EI_VERSION]; if (e->e_version > EV_CURRENT) { e = _libelf_release_elf(e); LIBELF_SET_ERROR(VERSION, 0); return (NULL); } if ((e->e_byteorder != ELFDATA2LSB && e->e_byteorder != ELFDATA2MSB) || (e->e_class != ELFCLASS32 && e->e_class != ELFCLASS64)) { e = _libelf_release_elf(e); LIBELF_SET_ERROR(HEADER, 0); return (NULL); } } else if (sz >= SARMAG && strncmp(image, ARMAG, (size_t) SARMAG) == 0) { _libelf_init_elf(e, ELF_K_AR); e = _libelf_ar_open(e); } else _libelf_init_elf(e, ELF_K_NONE); return (e); }
Elf * _libelf_memory(char *image, size_t sz, int reporterror) { Elf *e; int e_class; enum Elf_Error error; unsigned int e_byteorder, e_version; assert(image != NULL); assert(sz > 0); if ((e = _libelf_allocate_elf()) == NULL) return (NULL); e->e_cmd = ELF_C_READ; e->e_rawfile = image; e->e_rawsize = sz; #undef LIBELF_IS_ELF #define LIBELF_IS_ELF(P) ((P)[EI_MAG0] == ELFMAG0 && \ (P)[EI_MAG1] == ELFMAG1 && (P)[EI_MAG2] == ELFMAG2 && \ (P)[EI_MAG3] == ELFMAG3) if (sz > EI_NIDENT && LIBELF_IS_ELF(image)) { e_byteorder = image[EI_DATA]; e_class = image[EI_CLASS]; e_version = image[EI_VERSION]; error = ELF_E_NONE; if (e_version > EV_CURRENT) error = ELF_E_VERSION; else if ((e_byteorder != ELFDATA2LSB && e_byteorder != ELFDATA2MSB) || (e_class != ELFCLASS32 && e_class != ELFCLASS64)) error = ELF_E_HEADER; if (error != ELF_E_NONE) { if (reporterror) { LIBELF_PRIVATE(error) = LIBELF_ERROR(error, 0); (void) _libelf_release_elf(e); return (NULL); } } else { _libelf_init_elf(e, ELF_K_ELF); e->e_byteorder = e_byteorder; e->e_class = e_class; e->e_version = e_version; } } else if (sz >= SARMAG && strncmp(image, ARMAG, (size_t) SARMAG) == 0) return (_libelf_ar_open(e, reporterror)); return (e); }
Elf * elf_memory(char *image, size_t sz) { if (LIBELF_PRIVATE(version) == EV_NONE) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } if (image == NULL || sz == 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } return (_libelf_memory(image, sz, 1)); }
const char * elf_errmsg(int error) { int oserr; if (error == ELF_E_NONE && (error = LIBELF_PRIVATE(error)) == 0) return NULL; else if (error == -1) error = LIBELF_PRIVATE(error); oserr = error >> LIBELF_OS_ERROR_SHIFT; error &= LIBELF_ELF_ERROR_MASK; if (error < ELF_E_NONE || error >= ELF_E_NUM) return _libelf_errors[ELF_E_NUM]; if (oserr) { (void) snprintf(LIBELF_PRIVATE(msg), sizeof(LIBELF_PRIVATE(msg)), "%s: %s", _libelf_errors[error], strerror(oserr)); return (const char *)&LIBELF_PRIVATE(msg); } return _libelf_errors[error]; }
/* * Retrieve counts for sections, phdrs and the section string table index * from section header #0 of the ELF object. */ static int _libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum, uint16_t strndx) { Elf_Scn *scn; size_t fsz; int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, size_t _c, int _swap); uint32_t shtype; assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn)); fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1); assert(fsz > 0); if (e->e_rawsize < shoff + fsz) { /* raw file too small */ LIBELF_SET_ERROR(HEADER, 0); return (0); } if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL) return (0); xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); (*xlator)((unsigned char *) &scn->s_shdr, sizeof(scn->s_shdr), (unsigned char *) e->e_rawfile + shoff, (size_t) 1, e->e_byteorder != LIBELF_PRIVATE(byteorder)); #define GET_SHDR_MEMBER(M) ((ec == ELFCLASS32) ? scn->s_shdr.s_shdr32.M : \ scn->s_shdr.s_shdr64.M) if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) { LIBELF_SET_ERROR(SECTION, 0); return (0); } e->e_u.e_elf.e_nscn = (size_t) GET_SHDR_MEMBER(sh_size); e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum : GET_SHDR_MEMBER(sh_info); e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx : GET_SHDR_MEMBER(sh_link); #undef GET_SHDR_MEMBER return (1); }
Elf_Data * elf_newdata(Elf_Scn *s) { Elf *e; Elf_Data *d; if (s == NULL || (e = s->s_elf) == NULL || e->e_kind != ELF_K_ELF) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } /* * elf_newdata() has to append a data descriptor, so * bring in existing section data if not already present. */ if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) if (elf_getdata(s, NULL) == NULL) return (NULL); if ((d = malloc(sizeof(Elf_Data))) == NULL) { LIBELF_SET_ERROR(RESOURCE, errno); return (NULL); } STAILQ_INSERT_TAIL(&s->s_data, d, d_next); d->d_flags = 0; d->d_scn = s; d->d_align = 1; d->d_buf = NULL; d->d_off = (uint64_t) ~0; d->d_size = 0; d->d_type = ELF_T_BYTE; d->d_version = LIBELF_PRIVATE(version); (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); return (d); }
Elf_Data * elf_newdata(Elf_Scn *s) { Elf *e; struct _Libelf_Data *d; if (s == NULL || (e = s->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert(e->e_kind == ELF_K_ELF); /* * elf_newdata() has to append a data descriptor, so * bring in existing section data if not already present. */ if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) if (elf_getdata(s, NULL) == NULL) return (NULL); if ((d = _libelf_allocate_data(s)) == NULL) return (NULL); STAILQ_INSERT_TAIL(&s->s_data, d, d_next); d->d_data.d_align = 1; d->d_data.d_buf = NULL; d->d_data.d_off = (uint64_t) ~0; d->d_data.d_size = 0; d->d_data.d_type = ELF_T_BYTE; d->d_data.d_version = LIBELF_PRIVATE(version); (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); return (&d->d_data); }
void elf_fill(int fill) { LIBELF_PRIVATE(fillchar) = fill; }
Elf_Data * elf_getdata(Elf_Scn *s, Elf_Data *ed) { Elf *e; unsigned int sh_type; int elfclass, elftype; size_t fsz, msz, count; struct _Libelf_Data *d; uint64_t sh_align, sh_offset, sh_size; int (*xlate)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); d = (struct _Libelf_Data *) ed; if (s == NULL || (e = s->s_elf) == NULL || (d != NULL && s != d->d_scn)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert(e->e_kind == ELF_K_ELF); if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) return (&d->d_data); if (d != NULL) return (&STAILQ_NEXT(d, d_next)->d_data); if (e->e_rawfile == NULL) { /* * In the ELF_C_WRITE case, there is no source that * can provide data for the section. */ LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } elfclass = e->e_class; assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); if (elfclass == ELFCLASS32) { sh_type = s->s_shdr.s_shdr32.sh_type; sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; } else { sh_type = s->s_shdr.s_shdr64.sh_type; sh_offset = s->s_shdr.s_shdr64.sh_offset; sh_size = s->s_shdr.s_shdr64.sh_size; sh_align = s->s_shdr.s_shdr64.sh_addralign; } if (sh_type == SHT_NULL) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || elftype > ELF_T_LAST || (sh_type != SHT_NOBITS && sh_offset + sh_size > (uint64_t) e->e_rawsize)) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) (elftype, (size_t) 1, e->e_version)) == 0) { LIBELF_SET_ERROR(UNIMPL, 0); return (NULL); } if (sh_size % fsz) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } count = sh_size / fsz; msz = _libelf_msize(elftype, elfclass, e->e_version); assert(msz > 0); if ((d = _libelf_allocate_data(s)) == NULL) return (NULL); d->d_data.d_buf = NULL; d->d_data.d_off = 0; d->d_data.d_align = sh_align; d->d_data.d_size = msz * count; d->d_data.d_type = elftype; d->d_data.d_version = e->e_version; if (sh_type == SHT_NOBITS || sh_size == 0) { STAILQ_INSERT_TAIL(&s->s_data, d, d_next); return (&d->d_data); } if ((d->d_data.d_buf = malloc(msz*count)) == NULL) { (void) _libelf_release_data(d); LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } d->d_flags |= LIBELF_F_DATA_MALLOCED; xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); if (!(*xlate)(d->d_data.d_buf, d->d_data.d_size, e->e_rawfile + sh_offset, count, e->e_byteorder != LIBELF_PRIVATE(byteorder))) { _libelf_release_data(d); LIBELF_SET_ERROR(DATA, 0); return (NULL); } STAILQ_INSERT_TAIL(&s->s_data, d, d_next); return (&d->d_data); }
Elf_Data * _libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding, int elfclass, int direction) { int byteswap; size_t cnt, dsz, fsz, msz; uintptr_t sb, se, db, de; if (encoding == ELFDATANONE) encoding = LIBELF_PRIVATE(byteorder); if ((encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) || dst == NULL || src == NULL || dst == src) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY); if (dst->d_version != src->d_version) { LIBELF_SET_ERROR(UNIMPL, 0); return (NULL); } if (src->d_buf == NULL || dst->d_buf == NULL) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if ((int) src->d_type < 0 || src->d_type >= ELF_T_NUM) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) (src->d_type, (size_t) 1, src->d_version)) == 0) return (NULL); msz = _libelf_msize(src->d_type, elfclass, src->d_version); assert(msz > 0); if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } /* * Determine the number of objects that need to be converted, and * the space required for the converted objects in the destination * buffer. */ if (direction == ELF_TOMEMORY) { cnt = src->d_size / fsz; dsz = cnt * msz; } else { cnt = src->d_size / msz; dsz = cnt * fsz; } if (dst->d_size < dsz) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } sb = (uintptr_t) src->d_buf; se = sb + src->d_size; db = (uintptr_t) dst->d_buf; de = db + dst->d_size; /* * Check for overlapping buffers. Note that db == sb is * allowed. */ if (db != sb && de > sb && se > db) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if ((direction == ELF_TOMEMORY ? db : sb) % _libelf_malign(src->d_type, elfclass)) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } dst->d_type = src->d_type; dst->d_size = dsz; byteswap = encoding != LIBELF_PRIVATE(byteorder); if (src->d_size == 0 || (db == sb && !byteswap && fsz == msz)) return (dst); /* nothing more to do */ if (!(_libelf_get_translator(src->d_type, direction, elfclass)) (dst->d_buf, dsz, src->d_buf, cnt, byteswap)) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } return (dst); }
Elf * elf_begin(int fd, Elf_Cmd c, Elf *a) { Elf *e; e = NULL; if (LIBELF_PRIVATE(version) == EV_NONE) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } switch (c) { case ELF_C_NULL: return (NULL); case ELF_C_WRITE: if (a != NULL) { /* not allowed for ar(1) archives. */ LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } /* * Check writeability of `fd' immediately and fail if * not writeable. */ if (ftruncate(fd, (off_t) 0) < 0) { LIBELF_SET_ERROR(IO, errno); return (NULL); } if ((e = _libelf_allocate_elf()) != NULL) { _libelf_init_elf(e, ELF_K_ELF); e->e_byteorder = LIBELF_PRIVATE(byteorder); e->e_fd = fd; e->e_cmd = c; } return (e); case ELF_C_RDWR: if (a != NULL) { /* not allowed for ar(1) archives. */ LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } /*FALLTHROUGH*/ case ELF_C_READ: /* * Descriptor `a' could be for a regular ELF file, or * for an ar(1) archive. */ if (a && (a->e_fd != fd || c != a->e_cmd)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } break; default: LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (a == NULL) e = _libelf_open_object(fd, c); else if (a->e_kind == ELF_K_AR) e = _libelf_ar_open_member(fd, c, a); else (e = a)->e_activations++; return (e); }
Elf * _libelf_open_object(int fd, Elf_Cmd c, int reporterror) { Elf *e; void *m; mode_t mode; size_t fsize; struct stat sb; unsigned int flags; assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE); if (fstat(fd, &sb) < 0) { LIBELF_SET_ERROR(IO, errno); return (NULL); } mode = sb.st_mode; fsize = (size_t) sb.st_size; /* * Reject unsupported file types. */ if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) && !S_ISSOCK(mode)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } /* * For ELF_C_WRITE mode, allocate and return a descriptor. */ if (c == ELF_C_WRITE) { if ((e = _libelf_allocate_elf()) != NULL) { _libelf_init_elf(e, ELF_K_ELF); e->e_byteorder = LIBELF_PRIVATE(byteorder); e->e_fd = fd; e->e_cmd = c; if (!S_ISREG(mode)) e->e_flags |= LIBELF_F_SPECIAL_FILE; } return (e); } /* * ELF_C_READ and ELF_C_RDWR mode. */ m = NULL; flags = 0; if (S_ISREG(mode)) { /* * Reject zero length files. */ if (fsize == 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } #if ELFTC_HAVE_MMAP /* * Always map regular files in with 'PROT_READ' * permissions. * * For objects opened in ELF_C_RDWR mode, when * elf_update(3) is called, we remove this mapping, * write file data out using write(2), and map the new * contents back. */ m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, (off_t) 0); if (m == MAP_FAILED) m = NULL; else flags = LIBELF_F_RAWFILE_MMAP; #endif /* * Fallback to a read() if the call to mmap() failed, * or if mmap() is not available. */ if (m == NULL) { if ((m = malloc(fsize)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if (read(fd, m, fsize) != (ssize_t) fsize) { LIBELF_SET_ERROR(IO, errno); free(m); return (NULL); } flags = LIBELF_F_RAWFILE_MALLOC; } } else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL) flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE; else return (NULL); if ((e = _libelf_memory(m, fsize, reporterror)) == NULL) { assert((flags & LIBELF_F_RAWFILE_MALLOC) || (flags & LIBELF_F_RAWFILE_MMAP)); if (flags & LIBELF_F_RAWFILE_MALLOC) free(m); #if ELFTC_HAVE_MMAP else (void) munmap(m, fsize); #endif return (NULL); } /* ar(1) archives aren't supported in RDWR mode. */ if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) { (void) elf_end(e); LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } e->e_flags |= flags; e->e_fd = fd; e->e_cmd = c; return (e); }
void _libelf_set_error(int error) { LIBELF_PRIVATE(error) = error; }
void * _libelf_getphdr(Elf *e, int ec) { size_t phnum; size_t fsz, msz; uint64_t phoff; Elf32_Ehdr *eh32; Elf64_Ehdr *eh64; void *ehdr, *phdr; int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, size_t _c, int _swap); assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (e == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if ((phdr = (ec == ELFCLASS32 ? (void *) e->e_u.e_elf.e_phdr.e_phdr32 : (void *) e->e_u.e_elf.e_phdr.e_phdr64)) != NULL) return (phdr); /* * Check the PHDR related fields in the EHDR for sanity. */ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) return (NULL); phnum = e->e_u.e_elf.e_nphdr; if (ec == ELFCLASS32) { eh32 = (Elf32_Ehdr *) ehdr; phoff = (uint64_t) eh32->e_phoff; } else { eh64 = (Elf64_Ehdr *) ehdr; phoff = (uint64_t) eh64->e_phoff; } fsz = gelf_fsize(e, ELF_T_PHDR, phnum, e->e_version); assert(fsz > 0); if ((uint64_t) e->e_rawsize < (phoff + fsz)) { LIBELF_SET_ERROR(HEADER, 0); return (NULL); } msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT); assert(msz > 0); if ((phdr = calloc(phnum, msz)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if (ec == ELFCLASS32) e->e_u.e_elf.e_phdr.e_phdr32 = phdr; else e->e_u.e_elf.e_phdr.e_phdr64 = phdr; xlator = _libelf_get_translator(ELF_T_PHDR, ELF_TOMEMORY, ec); (*xlator)(phdr, phnum * msz, e->e_rawfile + phoff, phnum, e->e_byteorder != LIBELF_PRIVATE(byteorder)); return (phdr); }
/* * Load an ELF section table and create a list of Elf_Scn structures. */ static int _libelf_load_scn(Elf *e, void *ehdr) { int ec, swapbytes; size_t fsz, i, shnum; uint64_t shoff; char *src; Elf32_Ehdr *eh32; Elf64_Ehdr *eh64; Elf_Scn *scn; void (*xlator)(char *_d, char *_s, size_t _c, int _swap); assert(e != NULL); assert(ehdr != NULL); assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0); #define CHECK_EHDR(E,EH) do { \ if (fsz != (EH)->e_shentsize || \ shoff + fsz * shnum > e->e_rawsize) { \ LIBELF_SET_ERROR(HEADER, 0); \ return (0); \ } \ } while (0) ec = e->e_class; fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); assert(fsz > 0); shnum = e->e_u.e_elf.e_nscn; if (ec == ELFCLASS32) { eh32 = (Elf32_Ehdr *) ehdr; shoff = (uint64_t) eh32->e_shoff; CHECK_EHDR(e, eh32); } else { eh64 = (Elf64_Ehdr *) ehdr; shoff = eh64->e_shoff; CHECK_EHDR(e, eh64); } xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder); src = e->e_rawfile + shoff; /* * If the file is using extended numbering then section #0 * would have already been read in. */ i = 0; if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) { assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) == STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next)); i = 1; src += fsz; } for (; i < shnum; i++, src += fsz) { if ((scn = _libelf_allocate_scn(e, i)) == NULL) return (0); (*xlator)((char *) &scn->s_shdr, src, (size_t) 1, swapbytes); if (ec == ELFCLASS32) { scn->s_offset = scn->s_rawoff = scn->s_shdr.s_shdr32.sh_offset; scn->s_size = scn->s_shdr.s_shdr32.sh_size; } else { scn->s_offset = scn->s_rawoff = scn->s_shdr.s_shdr64.sh_offset; scn->s_size = scn->s_shdr.s_shdr64.sh_size; } } e->e_flags |= LIBELF_F_SHDRS_LOADED; return (1); }
void * _libelf_ehdr(Elf *e, int ec, int allocate) { void *ehdr; size_t fsz, msz; uint16_t phnum, shnum, strndx; uint64_t shoff; int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, size_t _c, int _swap); assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (e == NULL || e->e_kind != ELF_K_ELF) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (e->e_class != ELFCLASSNONE && e->e_class != ec) { LIBELF_SET_ERROR(CLASS, 0); return (NULL); } if (e->e_version != EV_CURRENT) { LIBELF_SET_ERROR(VERSION, 0); return (NULL); } if (e->e_class == ELFCLASSNONE) e->e_class = ec; if (ec == ELFCLASS32) ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr32; else ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr64; if (ehdr != NULL) /* already have a translated ehdr */ return (ehdr); fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); assert(fsz > 0); if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) { LIBELF_SET_ERROR(HEADER, 0); return (NULL); } msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT); assert(msz > 0); if ((ehdr = calloc((size_t) 1, msz)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if (ec == ELFCLASS32) { e->e_u.e_elf.e_ehdr.e_ehdr32 = ehdr; EHDR_INIT(ehdr,32); } else { e->e_u.e_elf.e_ehdr.e_ehdr64 = ehdr; EHDR_INIT(ehdr,64); } if (allocate) e->e_flags |= ELF_F_DIRTY; if (e->e_cmd == ELF_C_WRITE) return (ehdr); xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec); (*xlator)((unsigned char*) ehdr, msz, e->e_rawfile, (size_t) 1, e->e_byteorder != LIBELF_PRIVATE(byteorder)); if (ec == ELFCLASS32) { phnum = ((Elf32_Ehdr *) ehdr)->e_phnum; shnum = ((Elf32_Ehdr *) ehdr)->e_shnum; shoff = ((Elf32_Ehdr *) ehdr)->e_shoff; strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx; } else { phnum = ((Elf64_Ehdr *) ehdr)->e_phnum; shnum = ((Elf64_Ehdr *) ehdr)->e_shnum; shoff = ((Elf64_Ehdr *) ehdr)->e_shoff; strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx; } if (shnum >= SHN_LORESERVE || (shoff == 0LL && (shnum != 0 || phnum == PN_XNUM || strndx == SHN_XINDEX))) { LIBELF_SET_ERROR(HEADER, 0); return (NULL); } /* * If extended numbering is being used, read the correct * number of sections and program header entries. */ if ((shnum == 0 && shoff != 0) || phnum == PN_XNUM || strndx == SHN_XINDEX) { if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0) return (NULL); } else { /* not using extended numbering */ e->e_u.e_elf.e_nphdr = phnum; e->e_u.e_elf.e_nscn = shnum; e->e_u.e_elf.e_strndx = strndx; } return (ehdr); }
Elf_Data * elf_getdata(Elf_Scn *s, Elf_Data *d) { Elf *e; char *dst; size_t fsz, msz, count; int elfclass, elftype; unsigned int sh_type; uint64_t sh_align, sh_offset, sh_size; void (*xlate)(char *_d, char *_s, size_t _c, int _swap); if (s == NULL || (e = s->s_elf) == NULL || e->e_kind != ELF_K_ELF || (d != NULL && s != d->d_scn)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) return (d); if (d != NULL) return (STAILQ_NEXT(d, d_next)); if (e->e_rawfile == NULL) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } elfclass = e->e_class; assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); if (elfclass == ELFCLASS32) { sh_type = s->s_shdr.s_shdr32.sh_type; sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; } else { sh_type = s->s_shdr.s_shdr64.sh_type; sh_offset = s->s_shdr.s_shdr64.sh_offset; sh_size = s->s_shdr.s_shdr64.sh_size; sh_align = s->s_shdr.s_shdr64.sh_addralign; } if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || elftype > ELF_T_LAST || sh_offset + sh_size > (uint64_t) e->e_rawsize) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)(elftype, (size_t) 1, e->e_version)) == 0) { LIBELF_SET_ERROR(UNIMPL, 0); return (NULL); } if (sh_size % fsz) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } count = sh_size / fsz; msz = _libelf_msize(elftype, elfclass, e->e_version); assert(msz > 0); if ((dst = malloc(msz*count)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if ((d = _libelf_allocate_data(s)) == NULL) return (NULL); d->d_buf = dst; d->d_off = 0; d->d_align = sh_align; d->d_size = msz * count; d->d_type = elftype; d->d_version = e->e_version; d->d_flags |= LIBELF_F_MALLOCED; STAILQ_INSERT_TAIL(&s->s_data, d, d_next); xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); (*xlate)(d->d_buf, e->e_rawfile + sh_offset, count, e->e_byteorder != LIBELF_PRIVATE(byteorder)); return (d); }