@ -4002,18 +4002,6 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
* Example for ARM target is provided in this file .
*/
/* An ELF note in memory */
struct memelfnote {
const char * name ;
size_t namesz ;
size_t namesz_rounded ;
int type ;
size_t datasz ;
size_t datasz_rounded ;
void * data ;
size_t notesz ;
} ;
struct target_elf_siginfo {
abi_int si_signo ; /* signal number */
abi_int si_code ; /* extra code */
@ -4053,40 +4041,6 @@ struct target_elf_prpsinfo {
char pr_psargs [ ELF_PRARGSZ ] ; /* initial part of arg list */
} ;
/* Here is the structure in which status of each thread is captured. */
struct elf_thread_status {
QTAILQ_ENTRY ( elf_thread_status ) ets_link ;
struct target_elf_prstatus prstatus ; /* NT_PRSTATUS */
#if 0
elf_fpregset_t fpu ; /* NT_PRFPREG */
struct task_struct * thread ;
elf_fpxregset_t xfpu ; /* ELF_CORE_XFPREG_TYPE */
# endif
struct memelfnote notes [ 1 ] ;
int num_notes ;
} ;
# define NUMNOTES 3
struct elf_note_info {
struct memelfnote notes [ NUMNOTES ] ;
struct target_elf_prstatus prstatus ; /* NT_PRSTATUS */
struct target_elf_prpsinfo psinfo ; /* NT_PRPSINFO */
QTAILQ_HEAD ( , elf_thread_status ) thread_list ;
#if 0
/*
* Current version of ELF coredump doesn ' t support
* dumping fp regs etc .
*/
elf_fpregset_t * fpu ;
elf_fpxregset_t * xfpu ;
int thread_status_size ;
# endif
int notes_size ;
int numnote ;
} ;
struct vm_area_struct {
target_ulong vma_start ; /* start vaddr of memory region */
target_ulong vma_end ; /* end vaddr of memory region */
@ -4110,22 +4064,6 @@ static abi_ulong vma_dump_size(const struct vm_area_struct *);
static int vma_walker ( void * priv , target_ulong start , target_ulong end ,
unsigned long flags ) ;
static void fill_elf_header ( struct elfhdr * , int , uint16_t , uint32_t ) ;
static void fill_note ( struct memelfnote * , const char * , int ,
unsigned int , void * ) ;
static void fill_prstatus ( struct target_elf_prstatus * , const TaskState * , int ) ;
static int fill_psinfo ( struct target_elf_prpsinfo * , const TaskState * ) ;
static void fill_auxv_note ( struct memelfnote * , const TaskState * ) ;
static void fill_elf_note_phdr ( struct elf_phdr * , int , off_t ) ;
static size_t note_size ( const struct memelfnote * ) ;
static void free_note_info ( struct elf_note_info * ) ;
static void fill_note_info ( struct elf_note_info * , int , const CPUArchState * ) ;
static void fill_thread_info ( struct elf_note_info * , const CPUArchState * ) ;
static int dump_write ( int , const void * , size_t ) ;
static int write_note ( struct memelfnote * , int ) ;
static int write_note_info ( struct elf_note_info * , int ) ;
# ifdef BSWAP_NEEDED
static void bswap_prstatus ( struct target_elf_prstatus * prstatus )
{
@ -4280,35 +4218,32 @@ static size_t size_note(const char *name, size_t datasz)
return sizeof ( struct elf_note ) + namesz + datasz ;
}
static void fill_note ( struct memelfnote * note , const char * name , int type ,
unsigned int sz , void * data )
static void * fill_note ( void * * pptr , int type , const char * name , size_t datasz )
{
unsigned int namesz ;
void * ptr = * pptr ;
struct elf_note * n = ptr ;
size_t namesz = strlen ( name ) + 1 ;
namesz = strlen ( name ) + 1 ;
note - > name = name ;
note - > namesz = namesz ;
note - > namesz_rounded = roundup ( namesz , sizeof ( int32_t ) ) ;
note - > type = type ;
note - > datasz = sz ;
note - > datasz_rounded = roundup ( sz , sizeof ( int32_t ) ) ;
n - > n_namesz = namesz ;
n - > n_descsz = datasz ;
n - > n_type = type ;
bswap_note ( n ) ;
note - > data = data ;
ptr + = sizeof ( * n ) ;
memcpy ( ptr , name , namesz ) ;
/*
* We calculate rounded up note size here as specified by
* ELF document .
*/
note - > notesz = sizeof ( struct elf_note ) +
note - > namesz_rounded + note - > datasz_rounded ;
namesz = ROUND_UP ( namesz , 4 ) ;
datasz = ROUND_UP ( datasz , 4 ) ;
* pptr = ptr + namesz + datasz ;
return ptr + namesz ;
}
static void fill_elf_header ( struct elfhdr * elf , int segs , uint16_t machine ,
uint32_t flags )
{
( void ) memset ( elf , 0 , sizeof ( * elf ) ) ;
memcpy ( elf - > e_ident , ELFMAG , SELFMAG ) ;
( void ) memcpy ( elf - > e_ident , ELFMAG , SELFMAG ) ;
elf - > e_ident [ EI_CLASS ] = ELF_CLASS ;
elf - > e_ident [ EI_DATA ] = ELF_DATA ;
elf - > e_ident [ EI_VERSION ] = EV_CURRENT ;
@ -4326,95 +4261,79 @@ static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
bswap_ehdr ( elf ) ;
}
static void fill_elf_note_phdr ( struct elf_phdr * phdr , in t sz , off_t offset )
static void fill_elf_note_phdr ( struct elf_phdr * phdr , size_ t sz , off_t offset )
{
phdr - > p_type = PT_NOTE ;
phdr - > p_offset = offset ;
phdr - > p_vaddr = 0 ;
phdr - > p_paddr = 0 ;
phdr - > p_filesz = sz ;
phdr - > p_memsz = 0 ;
phdr - > p_flags = 0 ;
phdr - > p_align = 0 ;
bswap_phdr ( phdr , 1 ) ;
}
static size_t note_size ( const struct memelfnote * note )
static void fill_prstatus_note ( void * data , const TaskState * ts ,
CPUState * cpu , int signr )
{
return ( note - > notesz ) ;
}
/*
* Because note memory is only aligned to 4 , and target_elf_prstatus
* may well have higher alignment requirements , fill locally and
* memcpy to the destination afterward .
*/
struct target_elf_prstatus prstatus = {
. pr_info . si_signo = signr ,
. pr_cursig = signr ,
. pr_pid = ts - > ts_tid ,
. pr_ppid = getppid ( ) ,
. pr_pgrp = getpgrp ( ) ,
. pr_sid = getsid ( 0 ) ,
} ;
static void fill_prstatus ( struct target_elf_prstatus * prstatus ,
const TaskState * ts , int signr )
{
( void ) memset ( prstatus , 0 , sizeof ( * prstatus ) ) ;
prstatus - > pr_info . si_signo = prstatus - > pr_cursig = signr ;
prstatus - > pr_pid = ts - > ts_tid ;
prstatus - > pr_ppid = getppid ( ) ;
prstatus - > pr_pgrp = getpgrp ( ) ;
prstatus - > pr_sid = getsid ( 0 ) ;
bswap_prstatus ( prstatus ) ;
elf_core_copy_regs ( & prstatus . pr_reg , cpu_env ( cpu ) ) ;
bswap_prstatus ( & prstatus ) ;
memcpy ( data , & prstatus , sizeof ( prstatus ) ) ;
}
static int fill_psinfo ( struct target_elf_prpsinfo * psinfo , const TaskState * ts )
static void fill_prpsinfo_note ( void * data , const TaskState * ts )
{
/*
* Because note memory is only aligned to 4 , and target_elf_prpsinfo
* may well have higher alignment requirements , fill locally and
* memcpy to the destination afterward .
*/
struct target_elf_prpsinfo psinfo ;
char * base_filename ;
unsigned int i , len ;
( void ) memset ( psinfo , 0 , sizeof ( * psinfo ) ) ;
size_t len ;
len = ts - > info - > env_strings - ts - > info - > arg_strings ;
if ( len > = ELF_PRARGSZ )
len = ELF_PRARGSZ - 1 ;
if ( copy_from_user ( & psinfo - > pr_psargs , ts - > info - > arg_strings , len ) ) {
return - EFAULT ;
}
for ( i = 0 ; i < len ; i + + )
if ( psinfo - > pr_psargs [ i ] = = 0 )
psinfo - > pr_psargs [ i ] = ' ' ;
psinfo - > pr_psargs [ len ] = 0 ;
psinfo - > pr_pid = getpid ( ) ;
psinfo - > pr_ppid = getppid ( ) ;
psinfo - > pr_pgrp = getpgrp ( ) ;
psinfo - > pr_sid = getsid ( 0 ) ;
psinfo - > pr_uid = getuid ( ) ;
psinfo - > pr_gid = getgid ( ) ;
len = MIN ( len , ELF_PRARGSZ ) ;
memcpy ( & psinfo . pr_psargs , g2h_untagged ( ts - > info - > arg_strings ) , len ) ;
for ( size_t i = 0 ; i < len ; i + + ) {
if ( psinfo . pr_psargs [ i ] = = 0 ) {
psinfo . pr_psargs [ i ] = ' ' ;
}
}
psinfo . pr_pid = getpid ( ) ;
psinfo . pr_ppid = getppid ( ) ;
psinfo . pr_pgrp = getpgrp ( ) ;
psinfo . pr_sid = getsid ( 0 ) ;
psinfo . pr_uid = getuid ( ) ;
psinfo . pr_gid = getgid ( ) ;
base_filename = g_path_get_basename ( ts - > bprm - > filename ) ;
/*
* Using strncpy here is fine : at max - length ,
* this field is not NUL - terminated .
*/
( void ) strncpy ( psinfo - > pr_fname , base_filename ,
sizeof ( psinfo - > pr_fname ) ) ;
strncpy ( psinfo . pr_fname , base_filename , sizeof ( psinfo . pr_fname ) ) ;
g_free ( base_filename ) ;
bswap_psinfo ( psinfo ) ;
return ( 0 ) ;
bswap_psinfo ( & psinfo ) ;
memcpy ( data , & psinfo , sizeof ( psinfo ) ) ;
}
static void fill_auxv_note ( struct memelfnote * note , const TaskState * ts )
static void fill_auxv_note ( void * data , const TaskState * ts )
{
elf_addr_t auxv = ( elf_addr_t ) ts - > info - > saved_auxv ;
elf_addr_t orig_auxv = auxv ;
void * ptr ;
int len = ts - > info - > auxv_len ;
/*
* Auxiliary vector is stored in target process stack . It contains
* { type , value } pairs that we need to dump into note . This is not
* strictly necessary but we do it here for sake of completeness .
*/
/* read in whole auxv vector and copy it to memelfnote */
ptr = lock_user ( VERIFY_READ , orig_auxv , len , 0 ) ;
if ( ptr ! = NULL ) {
fill_note ( note , " CORE " , NT_AUXV , len , ptr ) ;
unlock_user ( ptr , auxv , len ) ;
}
memcpy ( data , g2h_untagged ( ts - > info - > saved_auxv ) , ts - > info - > auxv_len ) ;
}
/*
@ -4462,111 +4381,6 @@ static int dump_write(int fd, const void *ptr, size_t size)
return ( 0 ) ;
}
static int write_note ( struct memelfnote * men , int fd )
{
struct elf_note en ;
en . n_namesz = men - > namesz ;
en . n_type = men - > type ;
en . n_descsz = men - > datasz ;
bswap_note ( & en ) ;
if ( dump_write ( fd , & en , sizeof ( en ) ) ! = 0 )
return ( - 1 ) ;
if ( dump_write ( fd , men - > name , men - > namesz_rounded ) ! = 0 )
return ( - 1 ) ;
if ( dump_write ( fd , men - > data , men - > datasz_rounded ) ! = 0 )
return ( - 1 ) ;
return ( 0 ) ;
}
static void fill_thread_info ( struct elf_note_info * info , const CPUArchState * env )
{
CPUState * cpu = env_cpu ( ( CPUArchState * ) env ) ;
TaskState * ts = ( TaskState * ) cpu - > opaque ;
struct elf_thread_status * ets ;
ets = g_malloc0 ( sizeof ( * ets ) ) ;
ets - > num_notes = 1 ; /* only prstatus is dumped */
fill_prstatus ( & ets - > prstatus , ts , 0 ) ;
elf_core_copy_regs ( & ets - > prstatus . pr_reg , env ) ;
fill_note ( & ets - > notes [ 0 ] , " CORE " , NT_PRSTATUS , sizeof ( ets - > prstatus ) ,
& ets - > prstatus ) ;
QTAILQ_INSERT_TAIL ( & info - > thread_list , ets , ets_link ) ;
info - > notes_size + = note_size ( & ets - > notes [ 0 ] ) ;
}
static void fill_note_info ( struct elf_note_info * info ,
int signr , const CPUArchState * env )
{
CPUState * cpu = env_cpu ( ( CPUArchState * ) env ) ;
TaskState * ts = ( TaskState * ) cpu - > opaque ;
memset ( info , 0 , sizeof ( * info ) ) ;
QTAILQ_INIT ( & info - > thread_list ) ;
/*
* First fill in status ( and registers ) of current thread
* including process info & aux vector .
*/
fill_prstatus ( & info - > prstatus , ts , signr ) ;
elf_core_copy_regs ( & info - > prstatus . pr_reg , env ) ;
fill_note ( & info - > notes [ 0 ] , " CORE " , NT_PRSTATUS ,
sizeof ( info - > prstatus ) , & info - > prstatus ) ;
fill_psinfo ( & info - > psinfo , ts ) ;
fill_note ( & info - > notes [ 1 ] , " CORE " , NT_PRPSINFO ,
sizeof ( info - > psinfo ) , & info - > psinfo ) ;
fill_auxv_note ( & info - > notes [ 2 ] , ts ) ;
info - > numnote = 3 ;
info - > notes_size = 0 ;
for ( int i = 0 ; i < info - > numnote ; i + + ) {
info - > notes_size + = note_size ( & info - > notes [ i ] ) ;
}
/* read and fill status of all threads */
CPU_FOREACH ( cpu ) {
if ( cpu = = thread_cpu ) {
continue ;
}
fill_thread_info ( info , cpu_env ( cpu ) ) ;
}
}
static void free_note_info ( struct elf_note_info * info )
{
struct elf_thread_status * ets ;
while ( ! QTAILQ_EMPTY ( & info - > thread_list ) ) {
ets = QTAILQ_FIRST ( & info - > thread_list ) ;
QTAILQ_REMOVE ( & info - > thread_list , ets , ets_link ) ;
g_free ( ets ) ;
}
}
static int write_note_info ( struct elf_note_info * info , int fd )
{
struct elf_thread_status * ets ;
int i , error = 0 ;
/* write prstatus, psinfo and auxv for current thread */
for ( i = 0 ; i < info - > numnote ; i + + )
if ( ( error = write_note ( & info - > notes [ i ] , fd ) ) ! = 0 )
return ( error ) ;
/* write prstatus for each thread */
QTAILQ_FOREACH ( ets , & info - > thread_list , ets_link ) {
if ( ( error = write_note ( & ets - > notes [ 0 ] , fd ) ) ! = 0 )
return ( error ) ;
}
return ( 0 ) ;
}
/*
* Write out ELF coredump .
*
@ -4615,14 +4429,13 @@ static int elf_core_dump(int signr, const CPUArchState *env)
const CPUState * cpu = env_cpu ( ( CPUArchState * ) env ) ;
const TaskState * ts = ( const TaskState * ) cpu - > opaque ;
struct vm_area_struct * vma ;
struct elf_note_info info ;
struct elfhdr elf ;
struct elf_phdr phdr ;
struct rlimit dumpsize ;
struct mm_struct mm ;
off_t offset , note_offset , data_offset ;
size_t note_size ;
int segs , cpus , ret ;
int fd = - 1 ;
CPUState * cpu_iter ;
if ( prctl ( PR_GET_DUMPABLE ) = = 0 ) {
return 0 ;
@ -4644,7 +4457,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
segs = vma_get_mapping_count ( & mm ) ;
cpus = 0 ;
CPU_FOREACH ( cpu ) {
CPU_FOREACH ( cpu_iter ) {
cpus + + ;
}
@ -4655,6 +4468,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
offset + = size_note ( " CORE " , ts - > info - > auxv_len ) ;
offset + = size_note ( " CORE " , sizeof ( struct target_elf_prpsinfo ) ) ;
offset + = size_note ( " CORE " , sizeof ( struct target_elf_prstatus ) ) * cpus ;
note_size = offset - note_offset ;
offset = ROUND_UP ( offset , ELF_EXEC_PAGESIZE ) ;
data_offset = offset ;
@ -4678,61 +4492,64 @@ static int elf_core_dump(int signr, const CPUArchState *env)
}
/*
* Construct valid coredump ELF header . We also
* add one more segment for notes .
* There is a fair amount of alignment padding within the notes
* as well as preceeding the process memory . Allocate a zeroed
* block to hold it all . Write all of the headers directly into
* this buffer and then write it out as a block .
*/
fill_elf_header ( & elf , segs + 1 , ELF_MACHINE , 0 ) ;
if ( dump_write ( fd , & elf , sizeof ( elf ) ) ! = 0 )
goto out ;
{
g_autofree void * header = g_malloc0 ( data_offset ) ;
void * hptr , * dptr ;
/* Create elf file header. */
hptr = header ;
fill_elf_header ( hptr , segs + 1 , ELF_MACHINE , 0 ) ;
hptr + = sizeof ( struct elfhdr ) ;
/* Create elf program headers. */
fill_elf_note_phdr ( hptr , note_size , note_offset ) ;
hptr + = sizeof ( struct elf_phdr ) ;
offset = data_offset ;
for ( vma = vma_first ( & mm ) ; vma ! = NULL ; vma = vma_next ( vma ) ) {
struct elf_phdr * phdr = hptr ;
phdr - > p_type = PT_LOAD ;
phdr - > p_offset = offset ;
phdr - > p_vaddr = vma - > vma_start ;
phdr - > p_paddr = 0 ;
phdr - > p_filesz = vma_dump_size ( vma ) ;
offset + = phdr - > p_filesz ;
phdr - > p_memsz = vma - > vma_end - vma - > vma_start ;
phdr - > p_flags = ( vma - > vma_flags & PROT_READ ? PF_R : 0 )
| ( vma - > vma_flags & PROT_WRITE ? PF_W : 0 )
| ( vma - > vma_flags & PROT_EXEC ? PF_X : 0 ) ;
phdr - > p_align = ELF_EXEC_PAGESIZE ;
bswap_phdr ( phdr , 1 ) ;
hptr + = sizeof ( struct elf_phdr ) ;
}
/* fill in the in-memory version of notes */
fill_note_info ( & info , signr , env ) ;
/* Create the notes. */
dptr = fill_note ( & hptr , NT_AUXV , " CORE " , ts - > info - > auxv_len ) ;
fill_auxv_note ( dptr , ts ) ;
/* write out notes program header */
fill_elf_note_phdr ( & phdr , info . notes_size , note_offset ) ;
dptr = fill_note ( & hptr , NT_PRPSINFO , " CORE " ,
sizeof ( struct target_elf_prpsinfo ) ) ;
fill_prpsinfo_note ( dptr , ts ) ;
if ( dump_write ( fd , & phdr , sizeof ( phdr ) ) ! = 0 )
goto out ;
CPU_FOREACH ( cpu_iter ) {
dptr = fill_note ( & hptr , NT_PRSTATUS , " CORE " ,
sizeof ( struct target_elf_prstatus ) ) ;
fill_prstatus_note ( dptr , ts , cpu_iter ,
cpu_iter = = cpu ? signr : 0 ) ;
}
/*
* Write program headers for memory regions mapped in
* the target process .
*/
offset = data_offset ;
for ( vma = vma_first ( & mm ) ; vma ! = NULL ; vma = vma_next ( vma ) ) {
( void ) memset ( & phdr , 0 , sizeof ( phdr ) ) ;
phdr . p_type = PT_LOAD ;
phdr . p_offset = offset ;
phdr . p_vaddr = vma - > vma_start ;
phdr . p_paddr = 0 ;
phdr . p_filesz = vma_dump_size ( vma ) ;
offset + = phdr . p_filesz ;
phdr . p_memsz = vma - > vma_end - vma - > vma_start ;
phdr . p_flags = vma - > vma_flags & PROT_READ ? PF_R : 0 ;
if ( vma - > vma_flags & PROT_WRITE )
phdr . p_flags | = PF_W ;
if ( vma - > vma_flags & PROT_EXEC )
phdr . p_flags | = PF_X ;
phdr . p_align = ELF_EXEC_PAGESIZE ;
bswap_phdr ( & phdr , 1 ) ;
if ( dump_write ( fd , & phdr , sizeof ( phdr ) ) ! = 0 ) {
if ( dump_write ( fd , header , data_offset ) < 0 ) {
goto out ;
}
}
/*
* Next we write notes just after program headers . No
* alignment needed here .
*/
if ( write_note_info ( & info , fd ) < 0 )
goto out ;
/* align data to page boundary */
if ( lseek ( fd , data_offset , SEEK_SET ) ! = data_offset )
goto out ;
/*
* Finally we can dump process memory into corefile as well .
*/
@ -4768,7 +4585,6 @@ static int elf_core_dump(int signr, const CPUArchState *env)
ret = - errno ;
mmap_unlock ( ) ;
cpu_list_unlock ( ) ;
free_note_info ( & info ) ;
vma_delete ( & mm ) ;
close ( fd ) ;
return ret ;