#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include "libelfP.h"
#include "common.h"
#ifndef LIBELFBITS
# define LIBELFBITS 32
#endif
ElfW2(LIBELFBITS,Phdr) *
__elfw2(LIBELFBITS,getphdr_wrlock) (Elf *elf)
{
ElfW2(LIBELFBITS,Phdr) *result;
result = elf->state.ELFW(elf,LIBELFBITS).phdr;
if (likely (result != NULL))
return result;
if (elf->class == 0)
elf->class = ELFW(ELFCLASS,LIBELFBITS);
else if (elf->class != ELFW(ELFCLASS,LIBELFBITS))
{
__libelf_seterrno (ELF_E_INVALID_CLASS);
result = NULL;
goto out;
}
if (likely (result == NULL))
{
ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
size_t phnum;
if (__elf_getphdrnum_rdlock (elf, &phnum) != 0)
goto out;
if (phnum == 0 || ehdr->e_phoff == 0)
{
__libelf_seterrno (ELF_E_NO_PHDR);
goto out;
}
size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr));
if (phnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))
|| ehdr->e_phoff > elf->maximum_size
|| elf->maximum_size - ehdr->e_phoff < size)
{
__libelf_seterrno (ELF_E_INVALID_DATA);
goto out;
}
if (elf->map_address != NULL)
{
if (unlikely (ehdr->e_phoff >= elf->maximum_size)
|| unlikely (elf->maximum_size - ehdr->e_phoff < size))
{
__libelf_seterrno (ELF_E_INVALID_PHDR);
goto out;
}
void *file_phdr = ((char *) elf->map_address
+ elf->start_offset + ehdr->e_phoff);
if (ehdr->e_ident[EI_DATA] == MY_ELFDATA
&& (ALLOW_UNALIGNED
|| ((uintptr_t) file_phdr
& (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0))
elf->state.ELFW(elf,LIBELFBITS).phdr = file_phdr;
else
{
ElfW2(LIBELFBITS,Phdr) *notcvt;
ElfW2(LIBELFBITS,Phdr) *phdr;
phdr = elf->state.ELFW(elf,LIBELFBITS).phdr =
(ElfW2(LIBELFBITS,Phdr) *) malloc (size);
if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
goto out;
}
elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
ELF_F_MALLOCED | ELF_F_DIRTY;
if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
{
assert (! ALLOW_UNALIGNED);
memcpy (phdr, file_phdr, size);
}
else
{
bool copy = ! (ALLOW_UNALIGNED
|| ((uintptr_t) file_phdr
& (__alignof__ (ElfW2(LIBELFBITS,Phdr))
- 1)) == 0);
if (! copy)
notcvt = file_phdr;
else
{
notcvt = (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
if (unlikely (notcvt == NULL))
{
__libelf_seterrno (ELF_E_NOMEM);
goto out;
}
memcpy (notcvt, file_phdr, size);
}
for (size_t cnt = 0; cnt < phnum; ++cnt)
{
CONVERT_TO (phdr[cnt].p_type, notcvt[cnt].p_type);
CONVERT_TO (phdr[cnt].p_offset, notcvt[cnt].p_offset);
CONVERT_TO (phdr[cnt].p_vaddr, notcvt[cnt].p_vaddr);
CONVERT_TO (phdr[cnt].p_paddr, notcvt[cnt].p_paddr);
CONVERT_TO (phdr[cnt].p_filesz, notcvt[cnt].p_filesz);
CONVERT_TO (phdr[cnt].p_memsz, notcvt[cnt].p_memsz);
CONVERT_TO (phdr[cnt].p_flags, notcvt[cnt].p_flags);
CONVERT_TO (phdr[cnt].p_align, notcvt[cnt].p_align);
}
if (copy)
free (notcvt);
}
}
}
else if (likely (elf->fildes != -1))
{
elf->state.ELFW(elf,LIBELFBITS).phdr =
(ElfW2(LIBELFBITS,Phdr) *) malloc (size);
if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
{
__libelf_seterrno (ELF_E_NOMEM);
goto out;
}
elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_MALLOCED;
ssize_t n = pread_retry (elf->fildes,
elf->state.ELFW(elf,LIBELFBITS).phdr, size,
elf->start_offset + ehdr->e_phoff);
if (unlikely ((size_t) n != size))
{
__libelf_seterrno (ELF_E_READ_ERROR);
free (elf->state.ELFW(elf,LIBELFBITS).phdr);
elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
goto out;
}
if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
{
ElfW2(LIBELFBITS,Phdr) *phdr
= elf->state.ELFW(elf,LIBELFBITS).phdr;
for (size_t cnt = 0; cnt < phnum; ++cnt)
{
CONVERT (phdr[cnt].p_type);
CONVERT (phdr[cnt].p_offset);
CONVERT (phdr[cnt].p_vaddr);
CONVERT (phdr[cnt].p_paddr);
CONVERT (phdr[cnt].p_filesz);
CONVERT (phdr[cnt].p_memsz);
CONVERT (phdr[cnt].p_flags);
CONVERT (phdr[cnt].p_align);
}
}
}
else
{
__libelf_seterrno (ELF_E_FD_DISABLED);
goto out;
}
result = elf->state.ELFW(elf,LIBELFBITS).phdr;
}
out:
return result;
}
ElfW2(LIBELFBITS,Phdr) *
elfw2(LIBELFBITS,getphdr) (Elf *elf)
{
ElfW2(LIBELFBITS,Phdr) *result;
if (elf == NULL)
return NULL;
if (unlikely (elf->kind != ELF_K_ELF))
{
__libelf_seterrno (ELF_E_INVALID_HANDLE);
return NULL;
}
result = elf->state.ELFW(elf,LIBELFBITS).phdr;
if (likely (result != NULL))
return result;
rwlock_wrlock (elf->lock);
result = __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
rwlock_unlock (elf->lock);
return result;
}
INTDEF(elfw2(LIBELFBITS,getphdr))