#define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include #include #include #include #include #include "elf.h" void *libelf_map(char *path, size_t *fsize); int libelf_iself(void *elf); char *libelf_soname(void *elf); int libelf_type(void *elf); Elf64_Ehdr *libelf_header(void *elf) { return elf; } #if 0 Elf64_Shdr *libelf_shdr(void *elf, int n) { return 0; } #endif Elf64_Shdr *libelf_sht_strtab(void *elf) { int i; Elf64_Ehdr *hdr; Elf64_Shdr *shdr; hdr = libelf_header(elf); for (i = 0; i < hdr->e_shnum; i++) { shdr = (Elf64_Shdr *)((char *)elf + hdr->e_shoff + i * hdr->e_shentsize); if (shdr->sh_type == SHT_STRTAB && i == hdr->e_shstrndx) { return shdr; } } return 0; } char *libelf_sectionname(Elf64_Shdr *section, Elf64_Shdr *strtab) { return (char *)strtab + section->sh_name; } Elf64_Shdr *libelf_section_n(void *elf, int n) { Elf64_Ehdr *hdr; hdr = libelf_header(elf); if (n > hdr->e_shnum) { return 0; } return (Elf64_Shdr *)((char *)elf + hdr->e_shoff + n * hdr->e_shentsize); } Elf64_Shdr *libelf_section(void *elf, unsigned int type) { int i; Elf64_Ehdr *hdr; Elf64_Shdr *shdr; hdr = libelf_header(elf); for (i = 0; i < hdr->e_shnum; i++) { shdr = (Elf64_Shdr *)((char *)elf + hdr->e_shoff + i * hdr->e_shentsize); if (shdr->sh_type == type) { return shdr; } } return 0; } int libelf_type(void *elf) { return libelf_iself(elf) ? libelf_header(elf)->e_type : 0; } int libelf_iself(void *elf) { Elf64_Ehdr *hdr; hdr = elf; if (hdr->e_ident[EI_MAG0] != ELFMAG0 || hdr->e_ident[EI_MAG1] != ELFMAG1 || hdr->e_ident[EI_MAG2] != ELFMAG2 || hdr->e_ident[EI_MAG3] != ELFMAG3 ) { return 0; } return 1; } void *libelf_map(char *path, size_t *fsize) { int elffd; struct stat sbuf; void *elfbase; errno = 0; elffd = open(path, O_RDONLY); if (elffd == -1) { perror("open"); return NULL; } if (fstat(elffd, &sbuf) == -1) { close(elffd); return NULL; } /* not a regular file? */ if (!S_ISREG(sbuf.st_mode)) { close(elffd); return NULL; } /* not at least the size of the elf header? */ if ((size_t)sbuf.st_size < sizeof(Elf64_Ehdr)) { close(elffd); return NULL; } elfbase = mmap(0, sbuf.st_size, PROT_READ,MAP_PRIVATE, elffd, 0); close(elffd); if (!elfbase) { return NULL; } if (!libelf_iself(elfbase)) { munmap(elfbase, sbuf.st_size); return NULL; } *fsize = sbuf.st_size; return elfbase; } char *libelf_soname(void *elfbase) { Elf64_Ehdr *hdr; int i; Elf64_Shdr *shdr; Elf64_Shdr *dynsect = 0; Elf64_Shdr *strtab = 0, *dyntab = 0; char *name, *dynname; Elf64_Dyn *dent; if (!libelf_iself(elfbase)) { return 0; } hdr = libelf_header(elfbase); /* only dynamic files will have an soname */ if (hdr->e_type != ET_DYN) { return 0; } switch (hdr->e_ident[EI_CLASS]) { case ELFCLASS64: case ELFCLASS32: case ELFCLASSNONE: break; default: return 0; break; } /* check endian ness */ switch (hdr->e_ident[EI_DATA]) { case ELFDATA2LSB: break; case ELFDATA2MSB: break; default: return 0; break; } /* find the section header table */ for (i = 0; i < hdr->e_shnum; i++) { shdr = (Elf64_Shdr *)((char *)elfbase + hdr->e_shoff + i * hdr->e_shentsize); if (shdr->sh_type == SHT_DYNAMIC) { dynsect = shdr; } else if (shdr->sh_type == SHT_STRTAB && i == hdr->e_shstrndx) { strtab = shdr; } } if (!strtab) { return 0; } if (!dynsect) { return 0; } name = (char *) elfbase + strtab->sh_offset; for (i = 0; i < hdr->e_shnum; i++) { shdr = (Elf64_Shdr *)((char *)elfbase + hdr->e_shoff + i * hdr->e_shentsize); if (shdr->sh_type == SHT_STRTAB && !strcmp(".dynstr", name+shdr->sh_name)) { dyntab = shdr; } } if (!dyntab) { return 0; } dynname = (char *) elfbase + dyntab->sh_offset; for (dent = (Elf64_Dyn *)((char *)elfbase + dynsect->sh_offset); dent->d_tag != DT_NULL; dent++) { if (dent->d_tag == DT_SONAME) { return dynname + dent->d_un.d_val; } } return 0; }