linux-user: Fix guest signal remapping after adjusting SIGABRT
linux-user: Implement VDSOs -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmVAHMsdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/GSgf/SiaCzl7FV2NsxA2h zHrgSYEf/4dyqjbgNhE9XSrIJ/cPEY47JrpMqJ0cK4BGc/d2IppUU0Zz3qZltXck CkTIPPXEWDvex+PSe5NXarxQtOazi21C+EySGFtFcCQ32C/LsdJBtNzrB+G/Tl/t QvPJBztXvS6FAdVci2TGBNk62nFq3NS/Uz477SD6Q/uSlczQQ5b1fu3YgZcCqM9D ncncHbuExUu+NMK02h8vyWwpxaTvUBSdRxx/6jnyctwVpWyMaIOfsrMooz0gBfoD Z7MqXhvtBYOnm4OjcQs4Nj1JBOdYoQS/y6dJ7ZP0kg10VSEwr48pduXZSvIypxbw hsaa8w== =wcWF -----END PGP SIGNATURE----- Merge tag 'pull-lu-20231030' of https://gitlab.com/rth7680/qemu into staging linux-user: Fix guest signal remapping after adjusting SIGABRT linux-user: Implement VDSOs * tag 'pull-lu-20231030' of https://gitlab.com/rth7680/qemu: (21 commits) build: Add update-linux-vdso makefile rule linux-user: Show vdso address in /proc/pid/maps linux-user/s390x: Add vdso linux-user/s390x: Rename __SIGNAL_FRAMESIZE to STACK_FRAME_OVERHEAD linux-user/ppc: Add vdso linux-user/loongarch64: Add vdso linux-user/riscv: Add vdso linux-user/hppa: Add vdso linux-user/arm: Add vdso linux-user/aarch64: Add vdso linux-user/x86_64: Add vdso linux-user/i386: Add vdso linux-user: Add gen-vdso tool linux-user: Load vdso image if available linux-user: Replace bprm->fd with bprm->src.fd linux-user: Use ImageSource in load_symbols linux-user: Use ImageSource in load_elf_image linux-user: Do not clobber bprm_buf swapping ehdr linux-user: Tidy loader_exec linux-user: Introduce imgsrc_read, imgsrc_read_alloc ... Conflicts: linux-user/arm/signal.c Fix an #include context conflict. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
516fffc993
76 changed files with 3286 additions and 219 deletions
|
|
@ -37,6 +37,19 @@
|
|||
#undef ELF_ARCH
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_ARCH_HAS_SIGTRAMP_PAGE
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *image;
|
||||
const uint32_t *relocs;
|
||||
unsigned image_size;
|
||||
unsigned reloc_count;
|
||||
unsigned sigreturn_ofs;
|
||||
unsigned rt_sigreturn_ofs;
|
||||
} VdsoImageInfo;
|
||||
|
||||
#define ELF_OSABI ELFOSABI_SYSV
|
||||
|
||||
/* from personality.h */
|
||||
|
|
@ -296,12 +309,27 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en
|
|||
(*regs)[15] = tswapreg(env->regs[R_ESP]);
|
||||
(*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* i386 is the only target which supplies AT_SYSINFO for the vdso.
|
||||
* All others only supply AT_SYSINFO_EHDR.
|
||||
*/
|
||||
#define DLINFO_ARCH_ITEMS (vdso_info != NULL)
|
||||
#define ARCH_DLINFO \
|
||||
do { \
|
||||
if (vdso_info) { \
|
||||
NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* TARGET_X86_64 */
|
||||
|
||||
#define VDSO_HEADER "vdso.c.inc"
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#endif
|
||||
#endif /* TARGET_I386 */
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
|
|
@ -921,6 +949,13 @@ const char *elf_hwcap2_str(uint32_t bit)
|
|||
#undef GET_FEATURE_ID
|
||||
|
||||
#endif /* not TARGET_AARCH64 */
|
||||
|
||||
#if TARGET_BIG_ENDIAN
|
||||
# define VDSO_HEADER "vdso-be.c.inc"
|
||||
#else
|
||||
# define VDSO_HEADER "vdso-le.c.inc"
|
||||
#endif
|
||||
|
||||
#endif /* TARGET_ARM */
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
|
@ -1156,6 +1191,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en
|
|||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#ifndef TARGET_PPC64
|
||||
# define VDSO_HEADER "vdso-32.c.inc"
|
||||
#elif TARGET_BIG_ENDIAN
|
||||
# define VDSO_HEADER "vdso-64.c.inc"
|
||||
#else
|
||||
# define VDSO_HEADER "vdso-64le.c.inc"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_LOONGARCH64
|
||||
|
|
@ -1166,6 +1209,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en
|
|||
|
||||
#define elf_check_arch(x) ((x) == EM_LOONGARCH)
|
||||
|
||||
#define VDSO_HEADER "vdso.c.inc"
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs,
|
||||
struct image_info *infop)
|
||||
{
|
||||
|
|
@ -1853,6 +1898,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
|
|||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#define VDSO_HEADER "vdso.c.inc"
|
||||
|
||||
#endif /* TARGET_S390X */
|
||||
|
||||
#ifdef TARGET_RISCV
|
||||
|
|
@ -1861,8 +1908,10 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
|
|||
|
||||
#ifdef TARGET_RISCV32
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define VDSO_HEADER "vdso-32.c.inc"
|
||||
#else
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define VDSO_HEADER "vdso-64.c.inc"
|
||||
#endif
|
||||
|
||||
#define ELF_HWCAP get_elf_hwcap()
|
||||
|
|
@ -1898,6 +1947,8 @@ static inline void init_thread(struct target_pt_regs *regs,
|
|||
#define STACK_GROWS_DOWN 0
|
||||
#define STACK_ALIGNMENT 64
|
||||
|
||||
#define VDSO_HEADER "vdso.c.inc"
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs,
|
||||
struct image_info *infop)
|
||||
{
|
||||
|
|
@ -2205,7 +2256,8 @@ static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
|
|||
#ifdef USE_ELF_CORE_DUMP
|
||||
static int elf_core_dump(int, const CPUArchState *);
|
||||
#endif /* USE_ELF_CORE_DUMP */
|
||||
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
|
||||
static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
|
||||
abi_ulong load_bias);
|
||||
|
||||
/* Verify the portions of EHDR within E_IDENT for the target.
|
||||
This can be performed before bswapping the entire header. */
|
||||
|
|
@ -2474,7 +2526,8 @@ static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong s
|
|||
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||
struct elfhdr *exec,
|
||||
struct image_info *info,
|
||||
struct image_info *interp_info)
|
||||
struct image_info *interp_info,
|
||||
struct image_info *vdso_info)
|
||||
{
|
||||
abi_ulong sp;
|
||||
abi_ulong u_argc, u_argv, u_envp, u_auxv;
|
||||
|
|
@ -2562,10 +2615,15 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
|||
}
|
||||
|
||||
size = (DLINFO_ITEMS + 1) * 2;
|
||||
if (k_base_platform)
|
||||
if (k_base_platform) {
|
||||
size += 2;
|
||||
if (k_platform)
|
||||
}
|
||||
if (k_platform) {
|
||||
size += 2;
|
||||
}
|
||||
if (vdso_info) {
|
||||
size += 2;
|
||||
}
|
||||
#ifdef DLINFO_ARCH_ITEMS
|
||||
size += DLINFO_ARCH_ITEMS * 2;
|
||||
#endif
|
||||
|
|
@ -2647,6 +2705,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
|||
if (u_platform) {
|
||||
NEW_AUX_ENT(AT_PLATFORM, u_platform);
|
||||
}
|
||||
if (vdso_info) {
|
||||
NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
|
||||
}
|
||||
NEW_AUX_ENT (AT_NULL, 0);
|
||||
#undef NEW_AUX_ENT
|
||||
|
||||
|
|
@ -3106,10 +3167,9 @@ static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
|
|||
}
|
||||
|
||||
/* Process NT_GNU_PROPERTY_TYPE_0. */
|
||||
static bool parse_elf_properties(int image_fd,
|
||||
static bool parse_elf_properties(const ImageSource *src,
|
||||
struct image_info *info,
|
||||
const struct elf_phdr *phdr,
|
||||
char bprm_buf[BPRM_BUF_SIZE],
|
||||
Error **errp)
|
||||
{
|
||||
union {
|
||||
|
|
@ -3137,14 +3197,8 @@ static bool parse_elf_properties(int image_fd,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
|
||||
memcpy(¬e, bprm_buf + phdr->p_offset, n);
|
||||
} else {
|
||||
ssize_t len = pread(image_fd, ¬e, n, phdr->p_offset);
|
||||
if (len != n) {
|
||||
error_setg_errno(errp, errno, "Error reading file header");
|
||||
return false;
|
||||
}
|
||||
if (!imgsrc_read(¬e, phdr->p_offset, n, src, errp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3190,29 +3244,34 @@ static bool parse_elf_properties(int image_fd,
|
|||
}
|
||||
}
|
||||
|
||||
/* Load an ELF image into the address space.
|
||||
/**
|
||||
* load_elf_image: Load an ELF image into the address space.
|
||||
* @image_name: the filename of the image, to use in error messages.
|
||||
* @src: the ImageSource from which to read.
|
||||
* @info: info collected from the loaded image.
|
||||
* @ehdr: the ELF header, not yet bswapped.
|
||||
* @pinterp_name: record any PT_INTERP string found.
|
||||
*
|
||||
* On return: @info values will be filled in, as necessary or available.
|
||||
*/
|
||||
|
||||
IMAGE_NAME is the filename of the image, to use in error messages.
|
||||
IMAGE_FD is the open file descriptor for the image.
|
||||
|
||||
BPRM_BUF is a copy of the beginning of the file; this of course
|
||||
contains the elf file header at offset 0. It is assumed that this
|
||||
buffer is sufficiently aligned to present no problems to the host
|
||||
in accessing data at aligned offsets within the buffer.
|
||||
|
||||
On return: INFO values will be filled in, as necessary or available. */
|
||||
|
||||
static void load_elf_image(const char *image_name, int image_fd,
|
||||
struct image_info *info, char **pinterp_name,
|
||||
char bprm_buf[BPRM_BUF_SIZE])
|
||||
static void load_elf_image(const char *image_name, const ImageSource *src,
|
||||
struct image_info *info, struct elfhdr *ehdr,
|
||||
char **pinterp_name)
|
||||
{
|
||||
struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
|
||||
struct elf_phdr *phdr;
|
||||
g_autofree struct elf_phdr *phdr = NULL;
|
||||
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
|
||||
int i, retval, prot_exec;
|
||||
int i, prot_exec;
|
||||
Error *err = NULL;
|
||||
|
||||
/* First of all, some simple consistency checks */
|
||||
/*
|
||||
* First of all, some simple consistency checks.
|
||||
* Note that we rely on the bswapped ehdr staying in bprm_buf,
|
||||
* for later use by load_elf_binary and create_elf_tables.
|
||||
*/
|
||||
if (!imgsrc_read(ehdr, 0, sizeof(*ehdr), src, &err)) {
|
||||
goto exit_errmsg;
|
||||
}
|
||||
if (!elf_check_ident(ehdr)) {
|
||||
error_setg(&err, "Invalid ELF image for this architecture");
|
||||
goto exit_errmsg;
|
||||
|
|
@ -3223,15 +3282,11 @@ static void load_elf_image(const char *image_name, int image_fd,
|
|||
goto exit_errmsg;
|
||||
}
|
||||
|
||||
i = ehdr->e_phnum * sizeof(struct elf_phdr);
|
||||
if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
|
||||
phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
|
||||
} else {
|
||||
phdr = (struct elf_phdr *) alloca(i);
|
||||
retval = pread(image_fd, phdr, i, ehdr->e_phoff);
|
||||
if (retval != i) {
|
||||
goto exit_read;
|
||||
}
|
||||
phdr = imgsrc_read_alloc(ehdr->e_phoff,
|
||||
ehdr->e_phnum * sizeof(struct elf_phdr),
|
||||
src, &err);
|
||||
if (phdr == NULL) {
|
||||
goto exit_errmsg;
|
||||
}
|
||||
bswap_phdr(phdr, ehdr->e_phnum);
|
||||
|
||||
|
|
@ -3268,17 +3323,10 @@ static void load_elf_image(const char *image_name, int image_fd,
|
|||
goto exit_errmsg;
|
||||
}
|
||||
|
||||
interp_name = g_malloc(eppnt->p_filesz);
|
||||
|
||||
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
|
||||
memcpy(interp_name, bprm_buf + eppnt->p_offset,
|
||||
eppnt->p_filesz);
|
||||
} else {
|
||||
retval = pread(image_fd, interp_name, eppnt->p_filesz,
|
||||
eppnt->p_offset);
|
||||
if (retval != eppnt->p_filesz) {
|
||||
goto exit_read;
|
||||
}
|
||||
interp_name = imgsrc_read_alloc(eppnt->p_offset, eppnt->p_filesz,
|
||||
src, &err);
|
||||
if (interp_name == NULL) {
|
||||
goto exit_errmsg;
|
||||
}
|
||||
if (interp_name[eppnt->p_filesz - 1] != 0) {
|
||||
error_setg(&err, "Invalid PT_INTERP entry");
|
||||
|
|
@ -3286,7 +3334,7 @@ static void load_elf_image(const char *image_name, int image_fd,
|
|||
}
|
||||
*pinterp_name = g_steal_pointer(&interp_name);
|
||||
} else if (eppnt->p_type == PT_GNU_PROPERTY) {
|
||||
if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
|
||||
if (!parse_elf_properties(src, info, eppnt, &err)) {
|
||||
goto exit_errmsg;
|
||||
}
|
||||
} else if (eppnt->p_type == PT_GNU_STACK) {
|
||||
|
|
@ -3439,9 +3487,9 @@ static void load_elf_image(const char *image_name, int image_fd,
|
|||
* but no backing file segment.
|
||||
*/
|
||||
if (eppnt->p_filesz != 0) {
|
||||
error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
|
||||
error = imgsrc_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
|
||||
elf_prot, MAP_PRIVATE | MAP_FIXED,
|
||||
image_fd, eppnt->p_offset - vaddr_po);
|
||||
src, eppnt->p_offset - vaddr_po);
|
||||
if (error == -1) {
|
||||
goto exit_mmap;
|
||||
}
|
||||
|
|
@ -3473,20 +3521,11 @@ static void load_elf_image(const char *image_name, int image_fd,
|
|||
#ifdef TARGET_MIPS
|
||||
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
|
||||
Mips_elf_abiflags_v0 abiflags;
|
||||
if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
|
||||
error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
|
||||
|
||||
if (!imgsrc_read(&abiflags, eppnt->p_offset, sizeof(abiflags),
|
||||
src, &err)) {
|
||||
goto exit_errmsg;
|
||||
}
|
||||
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
|
||||
memcpy(&abiflags, bprm_buf + eppnt->p_offset,
|
||||
sizeof(Mips_elf_abiflags_v0));
|
||||
} else {
|
||||
retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
|
||||
eppnt->p_offset);
|
||||
if (retval != sizeof(Mips_elf_abiflags_v0)) {
|
||||
goto exit_read;
|
||||
}
|
||||
}
|
||||
bswap_mips_abiflags(&abiflags);
|
||||
info->fp_abi = abiflags.fp_abi;
|
||||
#endif
|
||||
|
|
@ -3499,23 +3538,16 @@ static void load_elf_image(const char *image_name, int image_fd,
|
|||
}
|
||||
|
||||
if (qemu_log_enabled()) {
|
||||
load_symbols(ehdr, image_fd, load_bias);
|
||||
load_symbols(ehdr, src, load_bias);
|
||||
}
|
||||
|
||||
debuginfo_report_elf(image_name, image_fd, load_bias);
|
||||
debuginfo_report_elf(image_name, src->fd, load_bias);
|
||||
|
||||
mmap_unlock();
|
||||
|
||||
close(image_fd);
|
||||
close(src->fd);
|
||||
return;
|
||||
|
||||
exit_read:
|
||||
if (retval >= 0) {
|
||||
error_setg(&err, "Incomplete read of file header");
|
||||
} else {
|
||||
error_setg_errno(&err, errno, "Error reading file header");
|
||||
}
|
||||
goto exit_errmsg;
|
||||
exit_mmap:
|
||||
error_setg_errno(&err, errno, "Error mapping file");
|
||||
goto exit_errmsg;
|
||||
|
|
@ -3527,6 +3559,8 @@ static void load_elf_image(const char *image_name, int image_fd,
|
|||
static void load_elf_interp(const char *filename, struct image_info *info,
|
||||
char bprm_buf[BPRM_BUF_SIZE])
|
||||
{
|
||||
struct elfhdr ehdr;
|
||||
ImageSource src;
|
||||
int fd, retval;
|
||||
Error *err = NULL;
|
||||
|
||||
|
|
@ -3544,11 +3578,57 @@ static void load_elf_interp(const char *filename, struct image_info *info,
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (retval < BPRM_BUF_SIZE) {
|
||||
memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
|
||||
src.fd = fd;
|
||||
src.cache = bprm_buf;
|
||||
src.cache_size = retval;
|
||||
|
||||
load_elf_image(filename, &src, info, &ehdr, NULL);
|
||||
}
|
||||
|
||||
#ifdef VDSO_HEADER
|
||||
#include VDSO_HEADER
|
||||
#define vdso_image_info() &vdso_image_info
|
||||
#else
|
||||
#define vdso_image_info() NULL
|
||||
#endif
|
||||
|
||||
static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
|
||||
{
|
||||
ImageSource src;
|
||||
struct elfhdr ehdr;
|
||||
abi_ulong load_bias, load_addr;
|
||||
|
||||
src.fd = -1;
|
||||
src.cache = vdso->image;
|
||||
src.cache_size = vdso->image_size;
|
||||
|
||||
load_elf_image("<internal-vdso>", &src, info, &ehdr, NULL);
|
||||
load_addr = info->load_addr;
|
||||
load_bias = info->load_bias;
|
||||
|
||||
/*
|
||||
* We need to relocate the VDSO image. The one built into the kernel
|
||||
* is built for a fixed address. The one built for QEMU is not, since
|
||||
* that requires close control of the guest address space.
|
||||
* We pre-processed the image to locate all of the addresses that need
|
||||
* to be updated.
|
||||
*/
|
||||
for (unsigned i = 0, n = vdso->reloc_count; i < n; i++) {
|
||||
abi_ulong *addr = g2h_untagged(load_addr + vdso->relocs[i]);
|
||||
*addr = tswapal(tswapal(*addr) + load_bias);
|
||||
}
|
||||
|
||||
load_elf_image(filename, fd, info, NULL, bprm_buf);
|
||||
/* Install signal trampolines, if present. */
|
||||
if (vdso->sigreturn_ofs) {
|
||||
default_sigreturn = load_addr + vdso->sigreturn_ofs;
|
||||
}
|
||||
if (vdso->rt_sigreturn_ofs) {
|
||||
default_rt_sigreturn = load_addr + vdso->rt_sigreturn_ofs;
|
||||
}
|
||||
|
||||
/* Remove write from VDSO segment. */
|
||||
target_mprotect(info->start_data, info->end_data - info->start_data,
|
||||
PROT_READ | PROT_EXEC);
|
||||
}
|
||||
|
||||
static int symfind(const void *s0, const void *s1)
|
||||
|
|
@ -3595,19 +3675,20 @@ static int symcmp(const void *s0, const void *s1)
|
|||
}
|
||||
|
||||
/* Best attempt to load symbols from this ELF object. */
|
||||
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
||||
static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
|
||||
abi_ulong load_bias)
|
||||
{
|
||||
int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
|
||||
uint64_t segsz;
|
||||
struct elf_shdr *shdr;
|
||||
g_autofree struct elf_shdr *shdr = NULL;
|
||||
char *strings = NULL;
|
||||
struct syminfo *s = NULL;
|
||||
struct elf_sym *new_syms, *syms = NULL;
|
||||
struct elf_sym *syms = NULL;
|
||||
struct elf_sym *new_syms;
|
||||
uint64_t segsz;
|
||||
|
||||
shnum = hdr->e_shnum;
|
||||
i = shnum * sizeof(struct elf_shdr);
|
||||
shdr = (struct elf_shdr *)alloca(i);
|
||||
if (pread(fd, shdr, i, hdr->e_shoff) != i) {
|
||||
shdr = imgsrc_read_alloc(hdr->e_shoff, shnum * sizeof(struct elf_shdr),
|
||||
src, NULL);
|
||||
if (shdr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3625,31 +3706,33 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
|||
|
||||
found:
|
||||
/* Now know where the strtab and symtab are. Snarf them. */
|
||||
s = g_try_new(struct syminfo, 1);
|
||||
if (!s) {
|
||||
goto give_up;
|
||||
}
|
||||
|
||||
segsz = shdr[str_idx].sh_size;
|
||||
s->disas_strtab = strings = g_try_malloc(segsz);
|
||||
if (!strings ||
|
||||
pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
|
||||
strings = g_try_malloc(segsz);
|
||||
if (!strings) {
|
||||
goto give_up;
|
||||
}
|
||||
if (!imgsrc_read(strings, shdr[str_idx].sh_offset, segsz, src, NULL)) {
|
||||
goto give_up;
|
||||
}
|
||||
|
||||
segsz = shdr[sym_idx].sh_size;
|
||||
syms = g_try_malloc(segsz);
|
||||
if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
|
||||
goto give_up;
|
||||
}
|
||||
|
||||
if (segsz / sizeof(struct elf_sym) > INT_MAX) {
|
||||
/* Implausibly large symbol table: give up rather than ploughing
|
||||
* on with the number of symbols calculation overflowing
|
||||
/*
|
||||
* Implausibly large symbol table: give up rather than ploughing
|
||||
* on with the number of symbols calculation overflowing.
|
||||
*/
|
||||
goto give_up;
|
||||
}
|
||||
nsyms = segsz / sizeof(struct elf_sym);
|
||||
syms = g_try_malloc(segsz);
|
||||
if (!syms) {
|
||||
goto give_up;
|
||||
}
|
||||
if (!imgsrc_read(syms, shdr[sym_idx].sh_offset, segsz, src, NULL)) {
|
||||
goto give_up;
|
||||
}
|
||||
|
||||
for (i = 0; i < nsyms; ) {
|
||||
bswap_sym(syms + i);
|
||||
/* Throw away entries which we do not need. */
|
||||
|
|
@ -3674,10 +3757,12 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
|||
goto give_up;
|
||||
}
|
||||
|
||||
/* Attempt to free the storage associated with the local symbols
|
||||
that we threw away. Whether or not this has any effect on the
|
||||
memory allocation depends on the malloc implementation and how
|
||||
many symbols we managed to discard. */
|
||||
/*
|
||||
* Attempt to free the storage associated with the local symbols
|
||||
* that we threw away. Whether or not this has any effect on the
|
||||
* memory allocation depends on the malloc implementation and how
|
||||
* many symbols we managed to discard.
|
||||
*/
|
||||
new_syms = g_try_renew(struct elf_sym, syms, nsyms);
|
||||
if (new_syms == NULL) {
|
||||
goto give_up;
|
||||
|
|
@ -3686,20 +3771,23 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
|||
|
||||
qsort(syms, nsyms, sizeof(*syms), symcmp);
|
||||
|
||||
s->disas_num_syms = nsyms;
|
||||
#if ELF_CLASS == ELFCLASS32
|
||||
s->disas_symtab.elf32 = syms;
|
||||
#else
|
||||
s->disas_symtab.elf64 = syms;
|
||||
#endif
|
||||
s->lookup_symbol = lookup_symbolxx;
|
||||
s->next = syminfos;
|
||||
syminfos = s;
|
||||
{
|
||||
struct syminfo *s = g_new(struct syminfo, 1);
|
||||
|
||||
s->disas_strtab = strings;
|
||||
s->disas_num_syms = nsyms;
|
||||
#if ELF_CLASS == ELFCLASS32
|
||||
s->disas_symtab.elf32 = syms;
|
||||
#else
|
||||
s->disas_symtab.elf64 = syms;
|
||||
#endif
|
||||
s->lookup_symbol = lookup_symbolxx;
|
||||
s->next = syminfos;
|
||||
syminfos = s;
|
||||
}
|
||||
return;
|
||||
|
||||
give_up:
|
||||
g_free(s);
|
||||
give_up:
|
||||
g_free(strings);
|
||||
g_free(syms);
|
||||
}
|
||||
|
|
@ -3741,8 +3829,14 @@ uint32_t get_elf_eflags(int fd)
|
|||
|
||||
int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
||||
{
|
||||
struct image_info interp_info;
|
||||
struct elfhdr elf_ex;
|
||||
/*
|
||||
* We need a copy of the elf header for passing to create_elf_tables.
|
||||
* We will have overwritten the original when we re-use bprm->buf
|
||||
* while loading the interpreter. Allocate the storage for this now
|
||||
* and let elf_load_image do any swapping that may be required.
|
||||
*/
|
||||
struct elfhdr ehdr;
|
||||
struct image_info interp_info, vdso_info;
|
||||
char *elf_interpreter = NULL;
|
||||
char *scratch;
|
||||
|
||||
|
|
@ -3751,13 +3845,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
|||
interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
|
||||
#endif
|
||||
|
||||
load_elf_image(bprm->filename, bprm->fd, info,
|
||||
&elf_interpreter, bprm->buf);
|
||||
|
||||
/* ??? We need a copy of the elf header for passing to create_elf_tables.
|
||||
If we do nothing, we'll have overwritten this when we re-use bprm->buf
|
||||
when we load the interpreter. */
|
||||
elf_ex = *(struct elfhdr *)bprm->buf;
|
||||
load_elf_image(bprm->filename, &bprm->src, info, &ehdr, &elf_interpreter);
|
||||
|
||||
/* Do this so that we can load the interpreter, if need be. We will
|
||||
change some of these later */
|
||||
|
|
@ -3829,10 +3917,14 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
|||
}
|
||||
|
||||
/*
|
||||
* TODO: load a vdso, which would also contain the signal trampolines.
|
||||
* Otherwise, allocate a private page to hold them.
|
||||
* Load a vdso if available, which will amongst other things contain the
|
||||
* signal trampolines. Otherwise, allocate a separate page for them.
|
||||
*/
|
||||
if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
|
||||
const VdsoImageInfo *vdso = vdso_image_info();
|
||||
if (vdso) {
|
||||
load_elf_vdso(&vdso_info, vdso);
|
||||
info->vdso = vdso_info.load_bias;
|
||||
} else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
|
||||
abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
|
|
@ -3844,8 +3936,9 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
|||
target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
|
||||
}
|
||||
|
||||
bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
|
||||
info, (elf_interpreter ? &interp_info : NULL));
|
||||
bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr, info,
|
||||
elf_interpreter ? &interp_info : NULL,
|
||||
vdso ? &vdso_info : NULL);
|
||||
info->start_stack = bprm->p;
|
||||
|
||||
/* If we have an interpreter, set that as the program's entry point.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue