xref: /qemu/linux-user/elfload.c (revision ad1c7e0faac82eeb654cba7f99d4e6d88273e0f9)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
2edf8e2afSMika Westerberg #include <sys/time.h>
3edf8e2afSMika Westerberg #include <sys/param.h>
431e31b8aSbellard 
531e31b8aSbellard #include <stdio.h>
631e31b8aSbellard #include <sys/types.h>
731e31b8aSbellard #include <fcntl.h>
831e31b8aSbellard #include <errno.h>
931e31b8aSbellard #include <unistd.h>
1031e31b8aSbellard #include <sys/mman.h>
11edf8e2afSMika Westerberg #include <sys/resource.h>
1231e31b8aSbellard #include <stdlib.h>
1331e31b8aSbellard #include <string.h>
14edf8e2afSMika Westerberg #include <time.h>
1531e31b8aSbellard 
163ef693a0Sbellard #include "qemu.h"
1776cad711SPaolo Bonzini #include "disas/disas.h"
1831e31b8aSbellard 
19e58ffeb3Smalc #ifdef _ARCH_PPC64
20a6cc84f4Smalc #undef ARCH_DLINFO
21a6cc84f4Smalc #undef ELF_PLATFORM
22a6cc84f4Smalc #undef ELF_HWCAP
23a6cc84f4Smalc #undef ELF_CLASS
24a6cc84f4Smalc #undef ELF_DATA
25a6cc84f4Smalc #undef ELF_ARCH
26a6cc84f4Smalc #endif
27a6cc84f4Smalc 
28edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
29edf8e2afSMika Westerberg 
30cb33da57Sblueswir1 /* from personality.h */
31cb33da57Sblueswir1 
32cb33da57Sblueswir1 /*
33cb33da57Sblueswir1  * Flags for bug emulation.
34cb33da57Sblueswir1  *
35cb33da57Sblueswir1  * These occupy the top three bytes.
36cb33da57Sblueswir1  */
37cb33da57Sblueswir1 enum {
38cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
39d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
40d97ef72eSRichard Henderson                                            descriptors (signal handling) */
41cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
42cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
43cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
44cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
45cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
46cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
47cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
48cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
49cb33da57Sblueswir1 };
50cb33da57Sblueswir1 
51cb33da57Sblueswir1 /*
52cb33da57Sblueswir1  * Personality types.
53cb33da57Sblueswir1  *
54cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
55cb33da57Sblueswir1  * conflict with error returns.
56cb33da57Sblueswir1  */
57cb33da57Sblueswir1 enum {
58cb33da57Sblueswir1     PER_LINUX =         0x0000,
59cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
60cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
61cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
62cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
63d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
64cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
65cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
66cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
67cb33da57Sblueswir1     PER_BSD =           0x0006,
68cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
69cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
70cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
71cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
72cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
73cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
74cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
75cb33da57Sblueswir1     PER_RISCOS =        0x000c,
76cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
77cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
78cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
79cb33da57Sblueswir1     PER_HPUX =          0x0010,
80cb33da57Sblueswir1     PER_MASK =          0x00ff,
81cb33da57Sblueswir1 };
82cb33da57Sblueswir1 
83cb33da57Sblueswir1 /*
84cb33da57Sblueswir1  * Return the base personality without flags.
85cb33da57Sblueswir1  */
86cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
87cb33da57Sblueswir1 
8883fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
8983fb7adfSbellard #ifndef MAP_DENYWRITE
9083fb7adfSbellard #define MAP_DENYWRITE 0
9183fb7adfSbellard #endif
9283fb7adfSbellard 
9383fb7adfSbellard /* should probably go in elf.h */
9483fb7adfSbellard #ifndef ELIBBAD
9583fb7adfSbellard #define ELIBBAD 80
9683fb7adfSbellard #endif
9783fb7adfSbellard 
9828490231SRichard Henderson #ifdef TARGET_WORDS_BIGENDIAN
9928490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
10028490231SRichard Henderson #else
10128490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
10228490231SRichard Henderson #endif
10328490231SRichard Henderson 
104a29f998dSPaolo Bonzini #ifdef TARGET_ABI_MIPSN32
105918fc54cSPaolo Bonzini typedef abi_ullong      target_elf_greg_t;
106918fc54cSPaolo Bonzini #define tswapreg(ptr)   tswap64(ptr)
107a29f998dSPaolo Bonzini #else
108a29f998dSPaolo Bonzini typedef abi_ulong       target_elf_greg_t;
109a29f998dSPaolo Bonzini #define tswapreg(ptr)   tswapal(ptr)
110a29f998dSPaolo Bonzini #endif
111a29f998dSPaolo Bonzini 
11221e807faSNathan Froyd #ifdef USE_UID16
1131ddd592fSPaolo Bonzini typedef abi_ushort      target_uid_t;
1141ddd592fSPaolo Bonzini typedef abi_ushort      target_gid_t;
11521e807faSNathan Froyd #else
116f8fd4fc4SPaolo Bonzini typedef abi_uint        target_uid_t;
117f8fd4fc4SPaolo Bonzini typedef abi_uint        target_gid_t;
11821e807faSNathan Froyd #endif
119f8fd4fc4SPaolo Bonzini typedef abi_int         target_pid_t;
12021e807faSNathan Froyd 
12130ac07d4Sbellard #ifdef TARGET_I386
12230ac07d4Sbellard 
12315338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
12415338fd7Sbellard 
12515338fd7Sbellard static const char *get_elf_platform(void)
12615338fd7Sbellard {
12715338fd7Sbellard     static char elf_platform[] = "i386";
128a2247f8eSAndreas Färber     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
12915338fd7Sbellard     if (family > 6)
13015338fd7Sbellard         family = 6;
13115338fd7Sbellard     if (family >= 3)
13215338fd7Sbellard         elf_platform[1] = '0' + family;
13315338fd7Sbellard     return elf_platform;
13415338fd7Sbellard }
13515338fd7Sbellard 
13615338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
13715338fd7Sbellard 
13815338fd7Sbellard static uint32_t get_elf_hwcap(void)
13915338fd7Sbellard {
140a2247f8eSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
141a2247f8eSAndreas Färber 
142a2247f8eSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
14315338fd7Sbellard }
14415338fd7Sbellard 
14584409ddbSj_mayer #ifdef TARGET_X86_64
14684409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
14784409ddbSj_mayer #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
14884409ddbSj_mayer 
14984409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
15084409ddbSj_mayer #define ELF_ARCH       EM_X86_64
15184409ddbSj_mayer 
15284409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
15384409ddbSj_mayer {
15484409ddbSj_mayer     regs->rax = 0;
15584409ddbSj_mayer     regs->rsp = infop->start_stack;
15684409ddbSj_mayer     regs->rip = infop->entry;
15784409ddbSj_mayer }
15884409ddbSj_mayer 
1599edc5d79SMika Westerberg #define ELF_NREG    27
160c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1619edc5d79SMika Westerberg 
1629edc5d79SMika Westerberg /*
1639edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1649edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1659edc5d79SMika Westerberg  * those.
1669edc5d79SMika Westerberg  *
1679edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1689edc5d79SMika Westerberg  */
16905390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1709edc5d79SMika Westerberg {
1719edc5d79SMika Westerberg     (*regs)[0] = env->regs[15];
1729edc5d79SMika Westerberg     (*regs)[1] = env->regs[14];
1739edc5d79SMika Westerberg     (*regs)[2] = env->regs[13];
1749edc5d79SMika Westerberg     (*regs)[3] = env->regs[12];
1759edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EBP];
1769edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBX];
1779edc5d79SMika Westerberg     (*regs)[6] = env->regs[11];
1789edc5d79SMika Westerberg     (*regs)[7] = env->regs[10];
1799edc5d79SMika Westerberg     (*regs)[8] = env->regs[9];
1809edc5d79SMika Westerberg     (*regs)[9] = env->regs[8];
1819edc5d79SMika Westerberg     (*regs)[10] = env->regs[R_EAX];
1829edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_ECX];
1839edc5d79SMika Westerberg     (*regs)[12] = env->regs[R_EDX];
1849edc5d79SMika Westerberg     (*regs)[13] = env->regs[R_ESI];
1859edc5d79SMika Westerberg     (*regs)[14] = env->regs[R_EDI];
1869edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_EAX]; /* XXX */
1879edc5d79SMika Westerberg     (*regs)[16] = env->eip;
1889edc5d79SMika Westerberg     (*regs)[17] = env->segs[R_CS].selector & 0xffff;
1899edc5d79SMika Westerberg     (*regs)[18] = env->eflags;
1909edc5d79SMika Westerberg     (*regs)[19] = env->regs[R_ESP];
1919edc5d79SMika Westerberg     (*regs)[20] = env->segs[R_SS].selector & 0xffff;
1929edc5d79SMika Westerberg     (*regs)[21] = env->segs[R_FS].selector & 0xffff;
1939edc5d79SMika Westerberg     (*regs)[22] = env->segs[R_GS].selector & 0xffff;
1949edc5d79SMika Westerberg     (*regs)[23] = env->segs[R_DS].selector & 0xffff;
1959edc5d79SMika Westerberg     (*regs)[24] = env->segs[R_ES].selector & 0xffff;
1969edc5d79SMika Westerberg     (*regs)[25] = env->segs[R_FS].selector & 0xffff;
1979edc5d79SMika Westerberg     (*regs)[26] = env->segs[R_GS].selector & 0xffff;
1989edc5d79SMika Westerberg }
1999edc5d79SMika Westerberg 
20084409ddbSj_mayer #else
20184409ddbSj_mayer 
20230ac07d4Sbellard #define ELF_START_MMAP 0x80000000
20330ac07d4Sbellard 
20430ac07d4Sbellard /*
20530ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
20630ac07d4Sbellard  */
20730ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
20830ac07d4Sbellard 
20930ac07d4Sbellard /*
21030ac07d4Sbellard  * These are used to set parameters in the core dumps.
21130ac07d4Sbellard  */
21230ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
21330ac07d4Sbellard #define ELF_ARCH        EM_386
21430ac07d4Sbellard 
215d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
216d97ef72eSRichard Henderson                                struct image_info *infop)
217e5fe0c52Spbrook {
218e5fe0c52Spbrook     regs->esp = infop->start_stack;
219e5fe0c52Spbrook     regs->eip = infop->entry;
220e5fe0c52Spbrook 
22130ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
22230ac07d4Sbellard        starts %edx contains a pointer to a function which might be
22330ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
22430ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
22530ac07d4Sbellard        that have been loaded before the code runs.
22630ac07d4Sbellard 
22730ac07d4Sbellard        A value of 0 tells we have no such handler.  */
228e5fe0c52Spbrook     regs->edx = 0;
229b346ff46Sbellard }
2309edc5d79SMika Westerberg 
2319edc5d79SMika Westerberg #define ELF_NREG    17
232c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2339edc5d79SMika Westerberg 
2349edc5d79SMika Westerberg /*
2359edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2369edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2379edc5d79SMika Westerberg  * those.
2389edc5d79SMika Westerberg  *
2399edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2409edc5d79SMika Westerberg  */
24105390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2429edc5d79SMika Westerberg {
2439edc5d79SMika Westerberg     (*regs)[0] = env->regs[R_EBX];
2449edc5d79SMika Westerberg     (*regs)[1] = env->regs[R_ECX];
2459edc5d79SMika Westerberg     (*regs)[2] = env->regs[R_EDX];
2469edc5d79SMika Westerberg     (*regs)[3] = env->regs[R_ESI];
2479edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EDI];
2489edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBP];
2499edc5d79SMika Westerberg     (*regs)[6] = env->regs[R_EAX];
2509edc5d79SMika Westerberg     (*regs)[7] = env->segs[R_DS].selector & 0xffff;
2519edc5d79SMika Westerberg     (*regs)[8] = env->segs[R_ES].selector & 0xffff;
2529edc5d79SMika Westerberg     (*regs)[9] = env->segs[R_FS].selector & 0xffff;
2539edc5d79SMika Westerberg     (*regs)[10] = env->segs[R_GS].selector & 0xffff;
2549edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_EAX]; /* XXX */
2559edc5d79SMika Westerberg     (*regs)[12] = env->eip;
2569edc5d79SMika Westerberg     (*regs)[13] = env->segs[R_CS].selector & 0xffff;
2579edc5d79SMika Westerberg     (*regs)[14] = env->eflags;
2589edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_ESP];
2599edc5d79SMika Westerberg     (*regs)[16] = env->segs[R_SS].selector & 0xffff;
2609edc5d79SMika Westerberg }
26184409ddbSj_mayer #endif
262b346ff46Sbellard 
2639edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
264b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
265b346ff46Sbellard 
266b346ff46Sbellard #endif
267b346ff46Sbellard 
268b346ff46Sbellard #ifdef TARGET_ARM
269b346ff46Sbellard 
270b346ff46Sbellard #define ELF_START_MMAP 0x80000000
271b346ff46Sbellard 
27299033caeSAlexander Graf #define elf_check_arch(x) ((x) == ELF_MACHINE)
273b346ff46Sbellard 
27499033caeSAlexander Graf #define ELF_ARCH        ELF_MACHINE
27599033caeSAlexander Graf 
27699033caeSAlexander Graf #ifdef TARGET_AARCH64
27799033caeSAlexander Graf #define ELF_CLASS       ELFCLASS64
27899033caeSAlexander Graf #else
279b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
28099033caeSAlexander Graf #endif
281b346ff46Sbellard 
282d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
283d97ef72eSRichard Henderson                                struct image_info *infop)
284b346ff46Sbellard {
285992f48a0Sblueswir1     abi_long stack = infop->start_stack;
286b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
28799033caeSAlexander Graf 
28899033caeSAlexander Graf #ifdef TARGET_AARCH64
28999033caeSAlexander Graf     regs->pc = infop->entry & ~0x3ULL;
29099033caeSAlexander Graf     regs->sp = stack;
29199033caeSAlexander Graf #else
292b346ff46Sbellard     regs->ARM_cpsr = 0x10;
2930240ded8Spbrook     if (infop->entry & 1)
2940240ded8Spbrook         regs->ARM_cpsr |= CPSR_T;
2950240ded8Spbrook     regs->ARM_pc = infop->entry & 0xfffffffe;
296b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
2972f619698Sbellard     /* FIXME - what to for failure of get_user()? */
2982f619698Sbellard     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
2992f619698Sbellard     get_user_ual(regs->ARM_r1, stack + 4); /* envp */
300a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
301e5fe0c52Spbrook     regs->ARM_r0 = 0;
302e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
303863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
304e5fe0c52Spbrook     regs->ARM_r10 = infop->start_data;
30599033caeSAlexander Graf #endif
306b346ff46Sbellard }
307b346ff46Sbellard 
308edf8e2afSMika Westerberg #define ELF_NREG    18
309c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
310edf8e2afSMika Westerberg 
31105390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
312edf8e2afSMika Westerberg {
31386cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
31486cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
31586cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
31686cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
31786cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
31886cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
31986cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
32086cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
32186cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
32286cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
32386cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
32486cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
32586cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
32686cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
32786cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
32886cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
329edf8e2afSMika Westerberg 
33086cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
33186cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
332edf8e2afSMika Westerberg }
333edf8e2afSMika Westerberg 
33430ac07d4Sbellard #define USE_ELF_CORE_DUMP
33530ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
33630ac07d4Sbellard 
337afce2927Sbellard enum
338afce2927Sbellard {
339afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
340afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
341afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
342afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
343afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
344afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
345afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
346afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
347cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
348cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
349cf6de34aSRiku Voipio     ARM_HWCAP_ARM_THUMBEE   = 1 << 10,
350cf6de34aSRiku Voipio     ARM_HWCAP_ARM_NEON      = 1 << 11,
351cf6de34aSRiku Voipio     ARM_HWCAP_ARM_VFPv3     = 1 << 12,
352cf6de34aSRiku Voipio     ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
353afce2927Sbellard };
354afce2927Sbellard 
3556b1275ffSPeter Maydell #ifndef TARGET_AARCH64
3566b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
3576b1275ffSPeter Maydell 
358806d1021SMeador Inge #define TARGET_HAS_VALIDATE_GUEST_SPACE
359806d1021SMeador Inge /* Return 1 if the proposed guest space is suitable for the guest.
360806d1021SMeador Inge  * Return 0 if the proposed guest space isn't suitable, but another
361806d1021SMeador Inge  * address space should be tried.
362806d1021SMeador Inge  * Return -1 if there is no way the proposed guest space can be
363806d1021SMeador Inge  * valid regardless of the base.
364806d1021SMeador Inge  * The guest code may leave a page mapped and populate it if the
365806d1021SMeador Inge  * address is suitable.
366806d1021SMeador Inge  */
367806d1021SMeador Inge static int validate_guest_space(unsigned long guest_base,
368806d1021SMeador Inge                                 unsigned long guest_size)
36997cc7560SDr. David Alan Gilbert {
37097cc7560SDr. David Alan Gilbert     unsigned long real_start, test_page_addr;
37197cc7560SDr. David Alan Gilbert 
37297cc7560SDr. David Alan Gilbert     /* We need to check that we can force a fault on access to the
37397cc7560SDr. David Alan Gilbert      * commpage at 0xffff0fxx
37497cc7560SDr. David Alan Gilbert      */
37597cc7560SDr. David Alan Gilbert     test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
376806d1021SMeador Inge 
377806d1021SMeador Inge     /* If the commpage lies within the already allocated guest space,
378806d1021SMeador Inge      * then there is no way we can allocate it.
379806d1021SMeador Inge      */
380806d1021SMeador Inge     if (test_page_addr >= guest_base
381806d1021SMeador Inge         && test_page_addr <= (guest_base + guest_size)) {
382806d1021SMeador Inge         return -1;
383806d1021SMeador Inge     }
384806d1021SMeador Inge 
38597cc7560SDr. David Alan Gilbert     /* Note it needs to be writeable to let us initialise it */
38697cc7560SDr. David Alan Gilbert     real_start = (unsigned long)
38797cc7560SDr. David Alan Gilbert                  mmap((void *)test_page_addr, qemu_host_page_size,
38897cc7560SDr. David Alan Gilbert                      PROT_READ | PROT_WRITE,
38997cc7560SDr. David Alan Gilbert                      MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
39097cc7560SDr. David Alan Gilbert 
39197cc7560SDr. David Alan Gilbert     /* If we can't map it then try another address */
39297cc7560SDr. David Alan Gilbert     if (real_start == -1ul) {
39397cc7560SDr. David Alan Gilbert         return 0;
39497cc7560SDr. David Alan Gilbert     }
39597cc7560SDr. David Alan Gilbert 
39697cc7560SDr. David Alan Gilbert     if (real_start != test_page_addr) {
39797cc7560SDr. David Alan Gilbert         /* OS didn't put the page where we asked - unmap and reject */
39897cc7560SDr. David Alan Gilbert         munmap((void *)real_start, qemu_host_page_size);
39997cc7560SDr. David Alan Gilbert         return 0;
40097cc7560SDr. David Alan Gilbert     }
40197cc7560SDr. David Alan Gilbert 
40297cc7560SDr. David Alan Gilbert     /* Leave the page mapped
40397cc7560SDr. David Alan Gilbert      * Populate it (mmap should have left it all 0'd)
40497cc7560SDr. David Alan Gilbert      */
40597cc7560SDr. David Alan Gilbert 
40697cc7560SDr. David Alan Gilbert     /* Kernel helper versions */
40797cc7560SDr. David Alan Gilbert     __put_user(5, (uint32_t *)g2h(0xffff0ffcul));
40897cc7560SDr. David Alan Gilbert 
40997cc7560SDr. David Alan Gilbert     /* Now it's populated make it RO */
41097cc7560SDr. David Alan Gilbert     if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) {
41197cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
41297cc7560SDr. David Alan Gilbert         exit(-1);
41397cc7560SDr. David Alan Gilbert     }
41497cc7560SDr. David Alan Gilbert 
41597cc7560SDr. David Alan Gilbert     return 1; /* All good */
41697cc7560SDr. David Alan Gilbert }
4176b1275ffSPeter Maydell #endif
418adf050b1SBenoit Canet 
419adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
420adf050b1SBenoit Canet 
421adf050b1SBenoit Canet static uint32_t get_elf_hwcap(void)
422adf050b1SBenoit Canet {
423a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
424adf050b1SBenoit Canet     uint32_t hwcaps = 0;
425adf050b1SBenoit Canet 
426adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
427adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
428adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
429adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
430adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FPA;
431adf050b1SBenoit Canet 
432adf050b1SBenoit Canet     /* probe for the extra features */
433adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
434a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
435adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP);
436adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
437adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
438adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
439adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3);
440adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_VFP_FP16, ARM_HWCAP_ARM_VFPv3D16);
441adf050b1SBenoit Canet #undef GET_FEATURE
442adf050b1SBenoit Canet 
443adf050b1SBenoit Canet     return hwcaps;
444adf050b1SBenoit Canet }
445afce2927Sbellard 
44630ac07d4Sbellard #endif
44730ac07d4Sbellard 
448d2fbca94SGuan Xuetao #ifdef TARGET_UNICORE32
449d2fbca94SGuan Xuetao 
450d2fbca94SGuan Xuetao #define ELF_START_MMAP          0x80000000
451d2fbca94SGuan Xuetao 
452d2fbca94SGuan Xuetao #define elf_check_arch(x)       ((x) == EM_UNICORE32)
453d2fbca94SGuan Xuetao 
454d2fbca94SGuan Xuetao #define ELF_CLASS               ELFCLASS32
455d2fbca94SGuan Xuetao #define ELF_DATA                ELFDATA2LSB
456d2fbca94SGuan Xuetao #define ELF_ARCH                EM_UNICORE32
457d2fbca94SGuan Xuetao 
458d2fbca94SGuan Xuetao static inline void init_thread(struct target_pt_regs *regs,
459d2fbca94SGuan Xuetao         struct image_info *infop)
460d2fbca94SGuan Xuetao {
461d2fbca94SGuan Xuetao     abi_long stack = infop->start_stack;
462d2fbca94SGuan Xuetao     memset(regs, 0, sizeof(*regs));
463d2fbca94SGuan Xuetao     regs->UC32_REG_asr = 0x10;
464d2fbca94SGuan Xuetao     regs->UC32_REG_pc = infop->entry & 0xfffffffe;
465d2fbca94SGuan Xuetao     regs->UC32_REG_sp = infop->start_stack;
466d2fbca94SGuan Xuetao     /* FIXME - what to for failure of get_user()? */
467d2fbca94SGuan Xuetao     get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */
468d2fbca94SGuan Xuetao     get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */
469d2fbca94SGuan Xuetao     /* XXX: it seems that r0 is zeroed after ! */
470d2fbca94SGuan Xuetao     regs->UC32_REG_00 = 0;
471d2fbca94SGuan Xuetao }
472d2fbca94SGuan Xuetao 
473d2fbca94SGuan Xuetao #define ELF_NREG    34
474d2fbca94SGuan Xuetao typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
475d2fbca94SGuan Xuetao 
47605390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUUniCore32State *env)
477d2fbca94SGuan Xuetao {
478d2fbca94SGuan Xuetao     (*regs)[0] = env->regs[0];
479d2fbca94SGuan Xuetao     (*regs)[1] = env->regs[1];
480d2fbca94SGuan Xuetao     (*regs)[2] = env->regs[2];
481d2fbca94SGuan Xuetao     (*regs)[3] = env->regs[3];
482d2fbca94SGuan Xuetao     (*regs)[4] = env->regs[4];
483d2fbca94SGuan Xuetao     (*regs)[5] = env->regs[5];
484d2fbca94SGuan Xuetao     (*regs)[6] = env->regs[6];
485d2fbca94SGuan Xuetao     (*regs)[7] = env->regs[7];
486d2fbca94SGuan Xuetao     (*regs)[8] = env->regs[8];
487d2fbca94SGuan Xuetao     (*regs)[9] = env->regs[9];
488d2fbca94SGuan Xuetao     (*regs)[10] = env->regs[10];
489d2fbca94SGuan Xuetao     (*regs)[11] = env->regs[11];
490d2fbca94SGuan Xuetao     (*regs)[12] = env->regs[12];
491d2fbca94SGuan Xuetao     (*regs)[13] = env->regs[13];
492d2fbca94SGuan Xuetao     (*regs)[14] = env->regs[14];
493d2fbca94SGuan Xuetao     (*regs)[15] = env->regs[15];
494d2fbca94SGuan Xuetao     (*regs)[16] = env->regs[16];
495d2fbca94SGuan Xuetao     (*regs)[17] = env->regs[17];
496d2fbca94SGuan Xuetao     (*regs)[18] = env->regs[18];
497d2fbca94SGuan Xuetao     (*regs)[19] = env->regs[19];
498d2fbca94SGuan Xuetao     (*regs)[20] = env->regs[20];
499d2fbca94SGuan Xuetao     (*regs)[21] = env->regs[21];
500d2fbca94SGuan Xuetao     (*regs)[22] = env->regs[22];
501d2fbca94SGuan Xuetao     (*regs)[23] = env->regs[23];
502d2fbca94SGuan Xuetao     (*regs)[24] = env->regs[24];
503d2fbca94SGuan Xuetao     (*regs)[25] = env->regs[25];
504d2fbca94SGuan Xuetao     (*regs)[26] = env->regs[26];
505d2fbca94SGuan Xuetao     (*regs)[27] = env->regs[27];
506d2fbca94SGuan Xuetao     (*regs)[28] = env->regs[28];
507d2fbca94SGuan Xuetao     (*regs)[29] = env->regs[29];
508d2fbca94SGuan Xuetao     (*regs)[30] = env->regs[30];
509d2fbca94SGuan Xuetao     (*regs)[31] = env->regs[31];
510d2fbca94SGuan Xuetao 
51105390248SAndreas Färber     (*regs)[32] = cpu_asr_read((CPUUniCore32State *)env);
512d2fbca94SGuan Xuetao     (*regs)[33] = env->regs[0]; /* XXX */
513d2fbca94SGuan Xuetao }
514d2fbca94SGuan Xuetao 
515d2fbca94SGuan Xuetao #define USE_ELF_CORE_DUMP
516d2fbca94SGuan Xuetao #define ELF_EXEC_PAGESIZE               4096
517d2fbca94SGuan Xuetao 
518d2fbca94SGuan Xuetao #define ELF_HWCAP                       (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64)
519d2fbca94SGuan Xuetao 
520d2fbca94SGuan Xuetao #endif
521d2fbca94SGuan Xuetao 
522853d6f7aSbellard #ifdef TARGET_SPARC
523a315a145Sbellard #ifdef TARGET_SPARC64
524853d6f7aSbellard 
525853d6f7aSbellard #define ELF_START_MMAP 0x80000000
526cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
527cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
528992f48a0Sblueswir1 #ifndef TARGET_ABI32
529cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
530992f48a0Sblueswir1 #else
531992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
532992f48a0Sblueswir1 #endif
533853d6f7aSbellard 
534a315a145Sbellard #define ELF_CLASS   ELFCLASS64
5355ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
5365ef54116Sbellard 
5375ef54116Sbellard #define STACK_BIAS              2047
538a315a145Sbellard 
539d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
540d97ef72eSRichard Henderson                                struct image_info *infop)
541a315a145Sbellard {
542992f48a0Sblueswir1 #ifndef TARGET_ABI32
543a315a145Sbellard     regs->tstate = 0;
544992f48a0Sblueswir1 #endif
545a315a145Sbellard     regs->pc = infop->entry;
546a315a145Sbellard     regs->npc = regs->pc + 4;
547a315a145Sbellard     regs->y = 0;
548992f48a0Sblueswir1 #ifdef TARGET_ABI32
549992f48a0Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
550992f48a0Sblueswir1 #else
551cb33da57Sblueswir1     if (personality(infop->personality) == PER_LINUX32)
552cb33da57Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 4;
553cb33da57Sblueswir1     else
5545ef54116Sbellard         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
555992f48a0Sblueswir1 #endif
556a315a145Sbellard }
557a315a145Sbellard 
558a315a145Sbellard #else
559a315a145Sbellard #define ELF_START_MMAP 0x80000000
560cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
561cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV)
562a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
563a315a145Sbellard 
564853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
565853d6f7aSbellard #define ELF_ARCH    EM_SPARC
566853d6f7aSbellard 
567d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
568d97ef72eSRichard Henderson                                struct image_info *infop)
569853d6f7aSbellard {
570f5155289Sbellard     regs->psr = 0;
571f5155289Sbellard     regs->pc = infop->entry;
572f5155289Sbellard     regs->npc = regs->pc + 4;
573f5155289Sbellard     regs->y = 0;
574f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
575853d6f7aSbellard }
576853d6f7aSbellard 
577853d6f7aSbellard #endif
578a315a145Sbellard #endif
579853d6f7aSbellard 
58067867308Sbellard #ifdef TARGET_PPC
58167867308Sbellard 
58267867308Sbellard #define ELF_START_MMAP 0x80000000
58367867308Sbellard 
584e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
58584409ddbSj_mayer 
58684409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
58784409ddbSj_mayer 
58884409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
58984409ddbSj_mayer 
59084409ddbSj_mayer #else
59184409ddbSj_mayer 
59267867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
59367867308Sbellard 
59467867308Sbellard #define ELF_CLASS       ELFCLASS32
59584409ddbSj_mayer 
59684409ddbSj_mayer #endif
59784409ddbSj_mayer 
59867867308Sbellard #define ELF_ARCH        EM_PPC
59967867308Sbellard 
600df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
601df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
602df84e4f3SNathan Froyd enum {
6033efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
6043efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
6053efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
6063efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
6073efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
6083efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
6093efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
6103efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
6113efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
6123efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
6133efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
6143efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
6153efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
6163efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
6173efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
6183efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
6193efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
6203efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
6213efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
6223efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
6233efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
6243efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
6253efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
6263efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
6273efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
6283efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
629df84e4f3SNathan Froyd 
6303efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
6313efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
632df84e4f3SNathan Froyd };
633df84e4f3SNathan Froyd 
634df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
635df84e4f3SNathan Froyd 
636df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
637df84e4f3SNathan Froyd {
638a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
639df84e4f3SNathan Froyd     uint32_t features = 0;
640df84e4f3SNathan Froyd 
641df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
642df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
643df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
644a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
6453efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
6463efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
6473efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
6483efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
6493efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
6503efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
6513efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
6523efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
653df84e4f3SNathan Froyd #undef GET_FEATURE
654df84e4f3SNathan Froyd 
655df84e4f3SNathan Froyd     return features;
656df84e4f3SNathan Froyd }
657df84e4f3SNathan Froyd 
658f5155289Sbellard /*
659f5155289Sbellard  * The requirements here are:
660f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
661f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
662f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
663f5155289Sbellard  *   AT_IGNOREPPC is used for that.
664f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
665f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
666f5155289Sbellard  */
6670bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
668f5155289Sbellard #define ARCH_DLINFO                                     \
669f5155289Sbellard     do {                                                \
6700bccf03dSbellard         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);              \
6710bccf03dSbellard         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);              \
6720bccf03dSbellard         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
673f5155289Sbellard         /*                                              \
674f5155289Sbellard          * Now handle glibc compatibility.              \
675f5155289Sbellard          */                                             \
6760bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
6770bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
678f5155289Sbellard     } while (0)
679f5155289Sbellard 
68067867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
68167867308Sbellard {
68267867308Sbellard     _regs->gpr[1] = infop->start_stack;
683e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
6848e78064eSRichard Henderson     _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
6858e78064eSRichard Henderson     infop->entry = ldq_raw(infop->entry) + infop->load_bias;
68684409ddbSj_mayer #endif
68767867308Sbellard     _regs->nip = infop->entry;
68867867308Sbellard }
68967867308Sbellard 
690e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
691e2f3e741SNathan Froyd #define ELF_NREG 48
692e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
693e2f3e741SNathan Froyd 
69405390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
695e2f3e741SNathan Froyd {
696e2f3e741SNathan Froyd     int i;
697e2f3e741SNathan Froyd     target_ulong ccr = 0;
698e2f3e741SNathan Froyd 
699e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
70086cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
701e2f3e741SNathan Froyd     }
702e2f3e741SNathan Froyd 
70386cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
70486cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
70586cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
70686cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
70786cd7b2dSPaolo Bonzini     (*regs)[37] = tswapreg(env->xer);
708e2f3e741SNathan Froyd 
709e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
710e2f3e741SNathan Froyd         ccr |= env->crf[i] << (32 - ((i + 1) * 4));
711e2f3e741SNathan Froyd     }
71286cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
713e2f3e741SNathan Froyd }
714e2f3e741SNathan Froyd 
715e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
71667867308Sbellard #define ELF_EXEC_PAGESIZE       4096
71767867308Sbellard 
71867867308Sbellard #endif
71967867308Sbellard 
720048f6b4dSbellard #ifdef TARGET_MIPS
721048f6b4dSbellard 
722048f6b4dSbellard #define ELF_START_MMAP 0x80000000
723048f6b4dSbellard 
724048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS )
725048f6b4dSbellard 
726388bb21aSths #ifdef TARGET_MIPS64
727388bb21aSths #define ELF_CLASS   ELFCLASS64
728388bb21aSths #else
729048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
730388bb21aSths #endif
731048f6b4dSbellard #define ELF_ARCH    EM_MIPS
732048f6b4dSbellard 
733d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
734d97ef72eSRichard Henderson                                struct image_info *infop)
735048f6b4dSbellard {
736623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
737048f6b4dSbellard     regs->cp0_epc = infop->entry;
738048f6b4dSbellard     regs->regs[29] = infop->start_stack;
739048f6b4dSbellard }
740048f6b4dSbellard 
74151e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
74251e52606SNathan Froyd #define ELF_NREG 45
74351e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
74451e52606SNathan Froyd 
74551e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
74651e52606SNathan Froyd enum {
74751e52606SNathan Froyd #ifdef TARGET_MIPS64
74851e52606SNathan Froyd     TARGET_EF_R0 = 0,
74951e52606SNathan Froyd #else
75051e52606SNathan Froyd     TARGET_EF_R0 = 6,
75151e52606SNathan Froyd #endif
75251e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
75351e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
75451e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
75551e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
75651e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
75751e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
75851e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
75951e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
76051e52606SNathan Froyd };
76151e52606SNathan Froyd 
76251e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
76305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
76451e52606SNathan Froyd {
76551e52606SNathan Froyd     int i;
76651e52606SNathan Froyd 
76751e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
76851e52606SNathan Froyd         (*regs)[i] = 0;
76951e52606SNathan Froyd     }
77051e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
77151e52606SNathan Froyd 
77251e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
773a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
77451e52606SNathan Froyd     }
77551e52606SNathan Froyd 
77651e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
77751e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
778a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
779a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
780a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
781a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
782a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
783a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
78451e52606SNathan Froyd }
78551e52606SNathan Froyd 
78651e52606SNathan Froyd #define USE_ELF_CORE_DUMP
787388bb21aSths #define ELF_EXEC_PAGESIZE        4096
788388bb21aSths 
789048f6b4dSbellard #endif /* TARGET_MIPS */
790048f6b4dSbellard 
791b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
792b779e29eSEdgar E. Iglesias 
793b779e29eSEdgar E. Iglesias #define ELF_START_MMAP 0x80000000
794b779e29eSEdgar E. Iglesias 
7950d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
796b779e29eSEdgar E. Iglesias 
797b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
7980d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
799b779e29eSEdgar E. Iglesias 
800d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
801d97ef72eSRichard Henderson                                struct image_info *infop)
802b779e29eSEdgar E. Iglesias {
803b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
804b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
805b779e29eSEdgar E. Iglesias 
806b779e29eSEdgar E. Iglesias }
807b779e29eSEdgar E. Iglesias 
808b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
809b779e29eSEdgar E. Iglesias 
810e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
811e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
812e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
813e4cbd44dSEdgar E. Iglesias 
814e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
81505390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
816e4cbd44dSEdgar E. Iglesias {
817e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
818e4cbd44dSEdgar E. Iglesias 
819e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
82086cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
821e4cbd44dSEdgar E. Iglesias     }
822e4cbd44dSEdgar E. Iglesias 
823e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 6; i++) {
82486cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->sregs[i]);
825e4cbd44dSEdgar E. Iglesias     }
826e4cbd44dSEdgar E. Iglesias }
827e4cbd44dSEdgar E. Iglesias 
828b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
829b779e29eSEdgar E. Iglesias 
830d962783eSJia Liu #ifdef TARGET_OPENRISC
831d962783eSJia Liu 
832d962783eSJia Liu #define ELF_START_MMAP 0x08000000
833d962783eSJia Liu 
834d962783eSJia Liu #define elf_check_arch(x) ((x) == EM_OPENRISC)
835d962783eSJia Liu 
836d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
837d962783eSJia Liu #define ELF_CLASS ELFCLASS32
838d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
839d962783eSJia Liu 
840d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
841d962783eSJia Liu                                struct image_info *infop)
842d962783eSJia Liu {
843d962783eSJia Liu     regs->pc = infop->entry;
844d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
845d962783eSJia Liu }
846d962783eSJia Liu 
847d962783eSJia Liu #define USE_ELF_CORE_DUMP
848d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
849d962783eSJia Liu 
850d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
851d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
852d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
853d962783eSJia Liu 
854d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
855d962783eSJia Liu                                const CPUOpenRISCState *env)
856d962783eSJia Liu {
857d962783eSJia Liu     int i;
858d962783eSJia Liu 
859d962783eSJia Liu     for (i = 0; i < 32; i++) {
86086cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
861d962783eSJia Liu     }
862d962783eSJia Liu 
86386cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
86486cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->sr);
865d962783eSJia Liu }
866d962783eSJia Liu #define ELF_HWCAP 0
867d962783eSJia Liu #define ELF_PLATFORM NULL
868d962783eSJia Liu 
869d962783eSJia Liu #endif /* TARGET_OPENRISC */
870d962783eSJia Liu 
871fdf9b3e8Sbellard #ifdef TARGET_SH4
872fdf9b3e8Sbellard 
873fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
874fdf9b3e8Sbellard 
875fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH )
876fdf9b3e8Sbellard 
877fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
878fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
879fdf9b3e8Sbellard 
880d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
881d97ef72eSRichard Henderson                                struct image_info *infop)
882fdf9b3e8Sbellard {
883fdf9b3e8Sbellard     /* Check other registers XXXXX */
884fdf9b3e8Sbellard     regs->pc = infop->entry;
885072ae847Sths     regs->regs[15] = infop->start_stack;
886fdf9b3e8Sbellard }
887fdf9b3e8Sbellard 
8887631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
8897631c97eSNathan Froyd #define ELF_NREG 23
8907631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
8917631c97eSNathan Froyd 
8927631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
8937631c97eSNathan Froyd enum {
8947631c97eSNathan Froyd     TARGET_REG_PC = 16,
8957631c97eSNathan Froyd     TARGET_REG_PR = 17,
8967631c97eSNathan Froyd     TARGET_REG_SR = 18,
8977631c97eSNathan Froyd     TARGET_REG_GBR = 19,
8987631c97eSNathan Froyd     TARGET_REG_MACH = 20,
8997631c97eSNathan Froyd     TARGET_REG_MACL = 21,
9007631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
9017631c97eSNathan Froyd };
9027631c97eSNathan Froyd 
903d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
90405390248SAndreas Färber                                       const CPUSH4State *env)
9057631c97eSNathan Froyd {
9067631c97eSNathan Froyd     int i;
9077631c97eSNathan Froyd 
9087631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
90986cd7b2dSPaolo Bonzini         (*regs[i]) = tswapreg(env->gregs[i]);
9107631c97eSNathan Froyd     }
9117631c97eSNathan Froyd 
91286cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
91386cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
91486cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
91586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
91686cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
91786cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
9187631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
9197631c97eSNathan Froyd }
9207631c97eSNathan Froyd 
9217631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
922fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
923fdf9b3e8Sbellard 
924fdf9b3e8Sbellard #endif
925fdf9b3e8Sbellard 
92648733d19Sths #ifdef TARGET_CRIS
92748733d19Sths 
92848733d19Sths #define ELF_START_MMAP 0x80000000
92948733d19Sths 
93048733d19Sths #define elf_check_arch(x) ( (x) == EM_CRIS )
93148733d19Sths 
93248733d19Sths #define ELF_CLASS ELFCLASS32
93348733d19Sths #define ELF_ARCH  EM_CRIS
93448733d19Sths 
935d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
936d97ef72eSRichard Henderson                                struct image_info *infop)
93748733d19Sths {
93848733d19Sths     regs->erp = infop->entry;
93948733d19Sths }
94048733d19Sths 
94148733d19Sths #define ELF_EXEC_PAGESIZE        8192
94248733d19Sths 
94348733d19Sths #endif
94448733d19Sths 
945e6e5906bSpbrook #ifdef TARGET_M68K
946e6e5906bSpbrook 
947e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
948e6e5906bSpbrook 
949e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K )
950e6e5906bSpbrook 
951e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
952e6e5906bSpbrook #define ELF_ARCH        EM_68K
953e6e5906bSpbrook 
954e6e5906bSpbrook /* ??? Does this need to do anything?
955e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
956e6e5906bSpbrook 
957d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
958d97ef72eSRichard Henderson                                struct image_info *infop)
959e6e5906bSpbrook {
960e6e5906bSpbrook     regs->usp = infop->start_stack;
961e6e5906bSpbrook     regs->sr = 0;
962e6e5906bSpbrook     regs->pc = infop->entry;
963e6e5906bSpbrook }
964e6e5906bSpbrook 
9657a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
9667a93cc55SNathan Froyd #define ELF_NREG 20
9677a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
9687a93cc55SNathan Froyd 
96905390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
9707a93cc55SNathan Froyd {
97186cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
97286cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
97386cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
97486cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
97586cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
97686cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
97786cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
97886cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
97986cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
98086cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
98186cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
98286cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
98386cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
98486cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
98586cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
98686cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
98786cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
98886cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
98986cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
9907a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
9917a93cc55SNathan Froyd }
9927a93cc55SNathan Froyd 
9937a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
994e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
995e6e5906bSpbrook 
996e6e5906bSpbrook #endif
997e6e5906bSpbrook 
9987a3148a9Sj_mayer #ifdef TARGET_ALPHA
9997a3148a9Sj_mayer 
10007a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
10017a3148a9Sj_mayer 
10027a3148a9Sj_mayer #define elf_check_arch(x) ( (x) == ELF_ARCH )
10037a3148a9Sj_mayer 
10047a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
10057a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
10067a3148a9Sj_mayer 
1007d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1008d97ef72eSRichard Henderson                                struct image_info *infop)
10097a3148a9Sj_mayer {
10107a3148a9Sj_mayer     regs->pc = infop->entry;
10117a3148a9Sj_mayer     regs->ps = 8;
10127a3148a9Sj_mayer     regs->usp = infop->start_stack;
10137a3148a9Sj_mayer }
10147a3148a9Sj_mayer 
10157a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
10167a3148a9Sj_mayer 
10177a3148a9Sj_mayer #endif /* TARGET_ALPHA */
10187a3148a9Sj_mayer 
1019a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1020a4c075f1SUlrich Hecht 
1021a4c075f1SUlrich Hecht #define ELF_START_MMAP (0x20000000000ULL)
1022a4c075f1SUlrich Hecht 
1023a4c075f1SUlrich Hecht #define elf_check_arch(x) ( (x) == ELF_ARCH )
1024a4c075f1SUlrich Hecht 
1025a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1026a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1027a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1028a4c075f1SUlrich Hecht 
1029a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1030a4c075f1SUlrich Hecht {
1031a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
1032a4c075f1SUlrich Hecht     regs->psw.mask = PSW_MASK_64 | PSW_MASK_32;
1033a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1034a4c075f1SUlrich Hecht }
1035a4c075f1SUlrich Hecht 
1036a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1037a4c075f1SUlrich Hecht 
103815338fd7Sbellard #ifndef ELF_PLATFORM
103915338fd7Sbellard #define ELF_PLATFORM (NULL)
104015338fd7Sbellard #endif
104115338fd7Sbellard 
104215338fd7Sbellard #ifndef ELF_HWCAP
104315338fd7Sbellard #define ELF_HWCAP 0
104415338fd7Sbellard #endif
104515338fd7Sbellard 
1046992f48a0Sblueswir1 #ifdef TARGET_ABI32
1047cb33da57Sblueswir1 #undef ELF_CLASS
1048992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
1049cb33da57Sblueswir1 #undef bswaptls
1050cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
1051cb33da57Sblueswir1 #endif
1052cb33da57Sblueswir1 
105331e31b8aSbellard #include "elf.h"
105409bfb054Sbellard 
105509bfb054Sbellard struct exec
105609bfb054Sbellard {
105709bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
105809bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
105909bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
106009bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
106109bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
106209bfb054Sbellard     unsigned int a_entry;  /* start address */
106309bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
106409bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
106509bfb054Sbellard };
106609bfb054Sbellard 
106709bfb054Sbellard 
106809bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
106909bfb054Sbellard #define OMAGIC 0407
107009bfb054Sbellard #define NMAGIC 0410
107109bfb054Sbellard #define ZMAGIC 0413
107209bfb054Sbellard #define QMAGIC 0314
107309bfb054Sbellard 
107431e31b8aSbellard /* Necessary parameters */
107554936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
107654936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
107754936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
107831e31b8aSbellard 
1079*ad1c7e0fSJames Hogan #define DLINFO_ITEMS 14
108031e31b8aSbellard 
108109bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
108209bfb054Sbellard {
108309bfb054Sbellard     memcpy(to, from, n);
108409bfb054Sbellard }
108509bfb054Sbellard 
108631e31b8aSbellard #ifdef BSWAP_NEEDED
108792a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
108831e31b8aSbellard {
108931e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
109031e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
109131e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
109292a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
109392a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
109492a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
109531e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
109631e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
109731e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
109831e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
109931e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
110031e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
110131e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
110231e31b8aSbellard }
110331e31b8aSbellard 
1104991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
110531e31b8aSbellard {
1106991f8f0cSRichard Henderson     int i;
1107991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
110831e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
1109991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
111092a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
111192a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
111292a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
111392a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
111492a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
111592a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
111631e31b8aSbellard     }
1117991f8f0cSRichard Henderson }
1118689f936fSbellard 
1119991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
1120689f936fSbellard {
1121991f8f0cSRichard Henderson     int i;
1122991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
1123689f936fSbellard         bswap32s(&shdr->sh_name);
1124689f936fSbellard         bswap32s(&shdr->sh_type);
112592a31b1fSbellard         bswaptls(&shdr->sh_flags);
112692a31b1fSbellard         bswaptls(&shdr->sh_addr);
112792a31b1fSbellard         bswaptls(&shdr->sh_offset);
112892a31b1fSbellard         bswaptls(&shdr->sh_size);
1129689f936fSbellard         bswap32s(&shdr->sh_link);
1130689f936fSbellard         bswap32s(&shdr->sh_info);
113192a31b1fSbellard         bswaptls(&shdr->sh_addralign);
113292a31b1fSbellard         bswaptls(&shdr->sh_entsize);
1133689f936fSbellard     }
1134991f8f0cSRichard Henderson }
1135689f936fSbellard 
11367a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
1137689f936fSbellard {
1138689f936fSbellard     bswap32s(&sym->st_name);
11397a3148a9Sj_mayer     bswaptls(&sym->st_value);
11407a3148a9Sj_mayer     bswaptls(&sym->st_size);
1141689f936fSbellard     bswap16s(&sym->st_shndx);
1142689f936fSbellard }
1143991f8f0cSRichard Henderson #else
1144991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
1145991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
1146991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
1147991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
114831e31b8aSbellard #endif
114931e31b8aSbellard 
1150edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
11519349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
1152edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
1153682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
1154edf8e2afSMika Westerberg 
11559058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
11569058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
11579058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
11589058abddSRichard Henderson {
11599058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
11609058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
11619058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
11629058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
11639058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
11649058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
11659058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
11669058abddSRichard Henderson }
11679058abddSRichard Henderson 
11689058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
11699058abddSRichard Henderson    This has to wait until after bswapping the header.  */
11709058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
11719058abddSRichard Henderson {
11729058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
11739058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
11749058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
11759058abddSRichard Henderson             && ehdr->e_shentsize == sizeof(struct elf_shdr)
11769058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
11779058abddSRichard Henderson }
11789058abddSRichard Henderson 
117931e31b8aSbellard /*
1180e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
118131e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
118231e31b8aSbellard  * to be put directly into the top of new user memory.
118331e31b8aSbellard  *
118431e31b8aSbellard  */
1185992f48a0Sblueswir1 static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
1186992f48a0Sblueswir1                                   abi_ulong p)
118731e31b8aSbellard {
118831e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
118931e31b8aSbellard     int len, offset = 0;
119031e31b8aSbellard 
119131e31b8aSbellard     if (!p) {
119231e31b8aSbellard         return 0;       /* bullet-proofing */
119331e31b8aSbellard     }
119431e31b8aSbellard     while (argc-- > 0) {
1195edf779ffSbellard         tmp = argv[argc];
1196edf779ffSbellard         if (!tmp) {
119731e31b8aSbellard             fprintf(stderr, "VFS: argc is wrong");
119831e31b8aSbellard             exit(-1);
119931e31b8aSbellard         }
1200edf779ffSbellard         tmp1 = tmp;
1201edf779ffSbellard         while (*tmp++);
120231e31b8aSbellard         len = tmp - tmp1;
120331e31b8aSbellard         if (p < len) {  /* this shouldn't happen - 128kB */
120431e31b8aSbellard             return 0;
120531e31b8aSbellard         }
120631e31b8aSbellard         while (len) {
120731e31b8aSbellard             --p; --tmp; --len;
120831e31b8aSbellard             if (--offset < 0) {
120954936004Sbellard                 offset = p % TARGET_PAGE_SIZE;
121044a91caeSbellard                 pag = (char *)page[p/TARGET_PAGE_SIZE];
121144a91caeSbellard                 if (!pag) {
12127dd47667SPeter Maydell                     pag = g_try_malloc0(TARGET_PAGE_SIZE);
121353a5960aSpbrook                     page[p/TARGET_PAGE_SIZE] = pag;
121444a91caeSbellard                     if (!pag)
121531e31b8aSbellard                         return 0;
121631e31b8aSbellard                 }
121731e31b8aSbellard             }
121831e31b8aSbellard             if (len == 0 || offset == 0) {
1219edf779ffSbellard                 *(pag + offset) = *tmp;
122031e31b8aSbellard             }
122131e31b8aSbellard             else {
122231e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
122331e31b8aSbellard                 tmp -= bytes_to_copy;
122431e31b8aSbellard                 p -= bytes_to_copy;
122531e31b8aSbellard                 offset -= bytes_to_copy;
122631e31b8aSbellard                 len -= bytes_to_copy;
122731e31b8aSbellard                 memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
122831e31b8aSbellard             }
122931e31b8aSbellard         }
123031e31b8aSbellard     }
123131e31b8aSbellard     return p;
123231e31b8aSbellard }
123331e31b8aSbellard 
1234992f48a0Sblueswir1 static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
123531e31b8aSbellard                                  struct image_info *info)
123631e31b8aSbellard {
123760dcbcb5SRichard Henderson     abi_ulong stack_base, size, error, guard;
123831e31b8aSbellard     int i;
123931e31b8aSbellard 
124031e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
124160dcbcb5SRichard Henderson        it for args, we'll use it for something else.  */
1242703e0e89SRichard Henderson     size = guest_stack_size;
124360dcbcb5SRichard Henderson     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
124454936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
124560dcbcb5SRichard Henderson     }
124660dcbcb5SRichard Henderson     guard = TARGET_PAGE_SIZE;
124760dcbcb5SRichard Henderson     if (guard < qemu_real_host_page_size) {
124860dcbcb5SRichard Henderson         guard = qemu_real_host_page_size;
124960dcbcb5SRichard Henderson     }
125060dcbcb5SRichard Henderson 
125160dcbcb5SRichard Henderson     error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
125260dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
125309bfb054Sbellard     if (error == -1) {
125460dcbcb5SRichard Henderson         perror("mmap stack");
125531e31b8aSbellard         exit(-1);
125631e31b8aSbellard     }
125731e31b8aSbellard 
125860dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
125960dcbcb5SRichard Henderson     target_mprotect(error, guard, PROT_NONE);
126060dcbcb5SRichard Henderson 
126160dcbcb5SRichard Henderson     info->stack_limit = error + guard;
126260dcbcb5SRichard Henderson     stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
126309bfb054Sbellard     p += stack_base;
126409bfb054Sbellard 
126531e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
126631e31b8aSbellard         if (bprm->page[i]) {
126731e31b8aSbellard             info->rss++;
1268579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
126953a5960aSpbrook             memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
12707dd47667SPeter Maydell             g_free(bprm->page[i]);
127131e31b8aSbellard         }
127254936004Sbellard         stack_base += TARGET_PAGE_SIZE;
127331e31b8aSbellard     }
127431e31b8aSbellard     return p;
127531e31b8aSbellard }
127631e31b8aSbellard 
1277cf129f3aSRichard Henderson /* Map and zero the bss.  We need to explicitly zero any fractional pages
1278cf129f3aSRichard Henderson    after the data section (i.e. bss).  */
1279cf129f3aSRichard Henderson static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
128031e31b8aSbellard {
1281cf129f3aSRichard Henderson     uintptr_t host_start, host_map_start, host_end;
1282cf129f3aSRichard Henderson 
1283cf129f3aSRichard Henderson     last_bss = TARGET_PAGE_ALIGN(last_bss);
1284cf129f3aSRichard Henderson 
1285cf129f3aSRichard Henderson     /* ??? There is confusion between qemu_real_host_page_size and
1286cf129f3aSRichard Henderson        qemu_host_page_size here and elsewhere in target_mmap, which
1287cf129f3aSRichard Henderson        may lead to the end of the data section mapping from the file
1288cf129f3aSRichard Henderson        not being mapped.  At least there was an explicit test and
1289cf129f3aSRichard Henderson        comment for that here, suggesting that "the file size must
1290cf129f3aSRichard Henderson        be known".  The comment probably pre-dates the introduction
1291cf129f3aSRichard Henderson        of the fstat system call in target_mmap which does in fact
1292cf129f3aSRichard Henderson        find out the size.  What isn't clear is if the workaround
1293cf129f3aSRichard Henderson        here is still actually needed.  For now, continue with it,
1294cf129f3aSRichard Henderson        but merge it with the "normal" mmap that would allocate the bss.  */
1295cf129f3aSRichard Henderson 
1296cf129f3aSRichard Henderson     host_start = (uintptr_t) g2h(elf_bss);
1297cf129f3aSRichard Henderson     host_end = (uintptr_t) g2h(last_bss);
1298cf129f3aSRichard Henderson     host_map_start = (host_start + qemu_real_host_page_size - 1);
1299cf129f3aSRichard Henderson     host_map_start &= -qemu_real_host_page_size;
1300cf129f3aSRichard Henderson 
1301cf129f3aSRichard Henderson     if (host_map_start < host_end) {
1302cf129f3aSRichard Henderson         void *p = mmap((void *)host_map_start, host_end - host_map_start,
1303cf129f3aSRichard Henderson                        prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1304cf129f3aSRichard Henderson         if (p == MAP_FAILED) {
130531e31b8aSbellard             perror("cannot mmap brk");
130631e31b8aSbellard             exit(-1);
130731e31b8aSbellard         }
1308cf129f3aSRichard Henderson 
1309cf129f3aSRichard Henderson         /* Since we didn't use target_mmap, make sure to record
1310cf129f3aSRichard Henderson            the validity of the pages with qemu.  */
1311cf129f3aSRichard Henderson         page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);
131231e31b8aSbellard     }
131331e31b8aSbellard 
1314cf129f3aSRichard Henderson     if (host_start < host_map_start) {
1315cf129f3aSRichard Henderson         memset((void *)host_start, 0, host_map_start - host_start);
1316853d6f7aSbellard     }
1317853d6f7aSbellard }
1318853d6f7aSbellard 
13191af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
13201af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
13211af02e83SMike Frysinger {
13221af02e83SMike Frysinger     uint16_t n;
13231af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
13241af02e83SMike Frysinger 
13251af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
13261af02e83SMike Frysinger     n = info->nsegs;
13271af02e83SMike Frysinger     while (n--) {
13281af02e83SMike Frysinger         sp -= 12;
13291af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
13301af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
13311af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
13321af02e83SMike Frysinger     }
13331af02e83SMike Frysinger 
13341af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
13351af02e83SMike Frysinger     sp -= 4;
13361af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
13371af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
13381af02e83SMike Frysinger 
13391af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
13401af02e83SMike Frysinger     info->loadmap_addr = sp;
13411af02e83SMike Frysinger 
13421af02e83SMike Frysinger     return sp;
13431af02e83SMike Frysinger }
13441af02e83SMike Frysinger #endif
13451af02e83SMike Frysinger 
1346992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
134731e31b8aSbellard                                    struct elfhdr *exec,
13488e62a717SRichard Henderson                                    struct image_info *info,
13498e62a717SRichard Henderson                                    struct image_info *interp_info)
135031e31b8aSbellard {
1351992f48a0Sblueswir1     abi_ulong sp;
1352125b0f55SAlexander Graf     abi_ulong sp_auxv;
135353a5960aSpbrook     int size;
135414322badSLaurent ALFONSI     int i;
135514322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
135614322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
1357992f48a0Sblueswir1     abi_ulong u_platform;
135815338fd7Sbellard     const char *k_platform;
1359863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
136031e31b8aSbellard 
136153a5960aSpbrook     sp = p;
13621af02e83SMike Frysinger 
13631af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
13641af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
13651af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
13661af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
13671af02e83SMike Frysinger         sp &= ~3;
13681af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
13691af02e83SMike Frysinger         info->other_info = interp_info;
13701af02e83SMike Frysinger         if (interp_info) {
13711af02e83SMike Frysinger             interp_info->other_info = info;
13721af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
13731af02e83SMike Frysinger         }
13741af02e83SMike Frysinger     }
13751af02e83SMike Frysinger #endif
13761af02e83SMike Frysinger 
137753a5960aSpbrook     u_platform = 0;
137815338fd7Sbellard     k_platform = ELF_PLATFORM;
137915338fd7Sbellard     if (k_platform) {
138015338fd7Sbellard         size_t len = strlen(k_platform) + 1;
138153a5960aSpbrook         sp -= (len + n - 1) & ~(n - 1);
138253a5960aSpbrook         u_platform = sp;
1383579a97f7Sbellard         /* FIXME - check return value of memcpy_to_target() for failure */
138453a5960aSpbrook         memcpy_to_target(sp, k_platform, len);
138515338fd7Sbellard     }
138614322badSLaurent ALFONSI 
138714322badSLaurent ALFONSI     /*
138814322badSLaurent ALFONSI      * Generate 16 random bytes for userspace PRNG seeding (not
138914322badSLaurent ALFONSI      * cryptically secure but it's not the aim of QEMU).
139014322badSLaurent ALFONSI      */
139114322badSLaurent ALFONSI     srand((unsigned int) time(NULL));
139214322badSLaurent ALFONSI     for (i = 0; i < 16; i++) {
139314322badSLaurent ALFONSI         k_rand_bytes[i] = rand();
139414322badSLaurent ALFONSI     }
139514322badSLaurent ALFONSI     sp -= 16;
139614322badSLaurent ALFONSI     u_rand_bytes = sp;
139714322badSLaurent ALFONSI     /* FIXME - check return value of memcpy_to_target() for failure */
139814322badSLaurent ALFONSI     memcpy_to_target(sp, k_rand_bytes, 16);
139914322badSLaurent ALFONSI 
140053a5960aSpbrook     /*
140153a5960aSpbrook      * Force 16 byte _final_ alignment here for generality.
140253a5960aSpbrook      */
1403992f48a0Sblueswir1     sp = sp &~ (abi_ulong)15;
140453a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
140515338fd7Sbellard     if (k_platform)
140653a5960aSpbrook         size += 2;
1407f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
140853a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
1409f5155289Sbellard #endif
141053a5960aSpbrook     size += envc + argc + 2;
1411b9329d4bSRichard Henderson     size += 1;  /* argc itself */
141253a5960aSpbrook     size *= n;
141353a5960aSpbrook     if (size & 15)
141453a5960aSpbrook         sp -= 16 - (size & 15);
1415f5155289Sbellard 
1416863cf0b7Sj_mayer     /* This is correct because Linux defines
1417863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
1418863cf0b7Sj_mayer      */
141953a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
14202f619698Sbellard         sp -= n; put_user_ual(val, sp);         \
14212f619698Sbellard         sp -= n; put_user_ual(id, sp);          \
142253a5960aSpbrook     } while(0)
14232f619698Sbellard 
1424125b0f55SAlexander Graf     sp_auxv = sp;
14250bccf03dSbellard     NEW_AUX_ENT (AT_NULL, 0);
1426f5155289Sbellard 
14270bccf03dSbellard     /* There must be exactly DLINFO_ITEMS entries here.  */
14288e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
1429992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
1430992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
1431992f48a0Sblueswir1     NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
14328e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
1433992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
14348e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
1435992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
1436992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
1437992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
1438992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
1439992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
1440a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
144114322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
144214322badSLaurent ALFONSI 
144315338fd7Sbellard     if (k_platform)
144453a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
1445f5155289Sbellard #ifdef ARCH_DLINFO
1446f5155289Sbellard     /*
1447f5155289Sbellard      * ARCH_DLINFO must come last so platform specific code can enforce
1448f5155289Sbellard      * special alignment requirements on the AUXV if necessary (eg. PPC).
1449f5155289Sbellard      */
1450f5155289Sbellard     ARCH_DLINFO;
1451f5155289Sbellard #endif
1452f5155289Sbellard #undef NEW_AUX_ENT
1453f5155289Sbellard 
1454edf8e2afSMika Westerberg     info->saved_auxv = sp;
1455125b0f55SAlexander Graf     info->auxv_len = sp_auxv - sp;
1456edf8e2afSMika Westerberg 
1457b9329d4bSRichard Henderson     sp = loader_build_argptr(envc, argc, sp, p, 0);
145831e31b8aSbellard     return sp;
145931e31b8aSbellard }
146031e31b8aSbellard 
1461806d1021SMeador Inge #ifndef TARGET_HAS_VALIDATE_GUEST_SPACE
146297cc7560SDr. David Alan Gilbert /* If the guest doesn't have a validation function just agree */
1463806d1021SMeador Inge static int validate_guest_space(unsigned long guest_base,
1464806d1021SMeador Inge                                 unsigned long guest_size)
146597cc7560SDr. David Alan Gilbert {
146697cc7560SDr. David Alan Gilbert     return 1;
146797cc7560SDr. David Alan Gilbert }
146897cc7560SDr. David Alan Gilbert #endif
146997cc7560SDr. David Alan Gilbert 
1470dce10401SMeador Inge unsigned long init_guest_space(unsigned long host_start,
1471dce10401SMeador Inge                                unsigned long host_size,
1472dce10401SMeador Inge                                unsigned long guest_start,
1473dce10401SMeador Inge                                bool fixed)
1474dce10401SMeador Inge {
1475dce10401SMeador Inge     unsigned long current_start, real_start;
1476dce10401SMeador Inge     int flags;
1477dce10401SMeador Inge 
1478dce10401SMeador Inge     assert(host_start || host_size);
1479dce10401SMeador Inge 
1480dce10401SMeador Inge     /* If just a starting address is given, then just verify that
1481dce10401SMeador Inge      * address.  */
1482dce10401SMeador Inge     if (host_start && !host_size) {
1483806d1021SMeador Inge         if (validate_guest_space(host_start, host_size) == 1) {
1484dce10401SMeador Inge             return host_start;
1485dce10401SMeador Inge         } else {
1486dce10401SMeador Inge             return (unsigned long)-1;
1487dce10401SMeador Inge         }
1488dce10401SMeador Inge     }
1489dce10401SMeador Inge 
1490dce10401SMeador Inge     /* Setup the initial flags and start address.  */
1491dce10401SMeador Inge     current_start = host_start & qemu_host_page_mask;
1492dce10401SMeador Inge     flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
1493dce10401SMeador Inge     if (fixed) {
1494dce10401SMeador Inge         flags |= MAP_FIXED;
1495dce10401SMeador Inge     }
1496dce10401SMeador Inge 
1497dce10401SMeador Inge     /* Otherwise, a non-zero size region of memory needs to be mapped
1498dce10401SMeador Inge      * and validated.  */
1499dce10401SMeador Inge     while (1) {
1500806d1021SMeador Inge         unsigned long real_size = host_size;
1501806d1021SMeador Inge 
1502dce10401SMeador Inge         /* Do not use mmap_find_vma here because that is limited to the
1503dce10401SMeador Inge          * guest address space.  We are going to make the
1504dce10401SMeador Inge          * guest address space fit whatever we're given.
1505dce10401SMeador Inge          */
1506dce10401SMeador Inge         real_start = (unsigned long)
1507dce10401SMeador Inge             mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0);
1508dce10401SMeador Inge         if (real_start == (unsigned long)-1) {
1509dce10401SMeador Inge             return (unsigned long)-1;
1510dce10401SMeador Inge         }
1511dce10401SMeador Inge 
1512806d1021SMeador Inge         /* Ensure the address is properly aligned.  */
1513806d1021SMeador Inge         if (real_start & ~qemu_host_page_mask) {
1514806d1021SMeador Inge             munmap((void *)real_start, host_size);
1515806d1021SMeador Inge             real_size = host_size + qemu_host_page_size;
1516806d1021SMeador Inge             real_start = (unsigned long)
1517806d1021SMeador Inge                 mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0);
1518806d1021SMeador Inge             if (real_start == (unsigned long)-1) {
1519806d1021SMeador Inge                 return (unsigned long)-1;
1520806d1021SMeador Inge             }
1521806d1021SMeador Inge             real_start = HOST_PAGE_ALIGN(real_start);
1522806d1021SMeador Inge         }
1523806d1021SMeador Inge 
1524806d1021SMeador Inge         /* Check to see if the address is valid.  */
1525806d1021SMeador Inge         if (!host_start || real_start == current_start) {
1526806d1021SMeador Inge             int valid = validate_guest_space(real_start - guest_start,
1527806d1021SMeador Inge                                              real_size);
1528806d1021SMeador Inge             if (valid == 1) {
1529dce10401SMeador Inge                 break;
1530806d1021SMeador Inge             } else if (valid == -1) {
1531806d1021SMeador Inge                 return (unsigned long)-1;
1532806d1021SMeador Inge             }
1533806d1021SMeador Inge             /* valid == 0, so try again. */
1534dce10401SMeador Inge         }
1535dce10401SMeador Inge 
1536dce10401SMeador Inge         /* That address didn't work.  Unmap and try a different one.
1537dce10401SMeador Inge          * The address the host picked because is typically right at
1538dce10401SMeador Inge          * the top of the host address space and leaves the guest with
1539dce10401SMeador Inge          * no usable address space.  Resort to a linear search.  We
1540dce10401SMeador Inge          * already compensated for mmap_min_addr, so this should not
1541dce10401SMeador Inge          * happen often.  Probably means we got unlucky and host
1542dce10401SMeador Inge          * address space randomization put a shared library somewhere
1543dce10401SMeador Inge          * inconvenient.
1544dce10401SMeador Inge          */
1545dce10401SMeador Inge         munmap((void *)real_start, host_size);
1546dce10401SMeador Inge         current_start += qemu_host_page_size;
1547dce10401SMeador Inge         if (host_start == current_start) {
1548dce10401SMeador Inge             /* Theoretically possible if host doesn't have any suitably
1549dce10401SMeador Inge              * aligned areas.  Normally the first mmap will fail.
1550dce10401SMeador Inge              */
1551dce10401SMeador Inge             return (unsigned long)-1;
1552dce10401SMeador Inge         }
1553dce10401SMeador Inge     }
1554dce10401SMeador Inge 
1555806d1021SMeador Inge     qemu_log("Reserved 0x%lx bytes of guest address space\n", host_size);
1556806d1021SMeador Inge 
1557dce10401SMeador Inge     return real_start;
1558dce10401SMeador Inge }
1559dce10401SMeador Inge 
1560f3ed1f5dSPeter Maydell static void probe_guest_base(const char *image_name,
1561f3ed1f5dSPeter Maydell                              abi_ulong loaddr, abi_ulong hiaddr)
1562f3ed1f5dSPeter Maydell {
1563f3ed1f5dSPeter Maydell     /* Probe for a suitable guest base address, if the user has not set
1564f3ed1f5dSPeter Maydell      * it explicitly, and set guest_base appropriately.
1565f3ed1f5dSPeter Maydell      * In case of error we will print a suitable message and exit.
1566f3ed1f5dSPeter Maydell      */
1567f3ed1f5dSPeter Maydell #if defined(CONFIG_USE_GUEST_BASE)
1568f3ed1f5dSPeter Maydell     const char *errmsg;
1569f3ed1f5dSPeter Maydell     if (!have_guest_base && !reserved_va) {
1570f3ed1f5dSPeter Maydell         unsigned long host_start, real_start, host_size;
1571f3ed1f5dSPeter Maydell 
1572f3ed1f5dSPeter Maydell         /* Round addresses to page boundaries.  */
1573f3ed1f5dSPeter Maydell         loaddr &= qemu_host_page_mask;
1574f3ed1f5dSPeter Maydell         hiaddr = HOST_PAGE_ALIGN(hiaddr);
1575f3ed1f5dSPeter Maydell 
1576f3ed1f5dSPeter Maydell         if (loaddr < mmap_min_addr) {
1577f3ed1f5dSPeter Maydell             host_start = HOST_PAGE_ALIGN(mmap_min_addr);
1578f3ed1f5dSPeter Maydell         } else {
1579f3ed1f5dSPeter Maydell             host_start = loaddr;
1580f3ed1f5dSPeter Maydell             if (host_start != loaddr) {
1581f3ed1f5dSPeter Maydell                 errmsg = "Address overflow loading ELF binary";
1582f3ed1f5dSPeter Maydell                 goto exit_errmsg;
1583f3ed1f5dSPeter Maydell             }
1584f3ed1f5dSPeter Maydell         }
1585f3ed1f5dSPeter Maydell         host_size = hiaddr - loaddr;
1586dce10401SMeador Inge 
1587dce10401SMeador Inge         /* Setup the initial guest memory space with ranges gleaned from
1588dce10401SMeador Inge          * the ELF image that is being loaded.
1589dce10401SMeador Inge          */
1590dce10401SMeador Inge         real_start = init_guest_space(host_start, host_size, loaddr, false);
1591f3ed1f5dSPeter Maydell         if (real_start == (unsigned long)-1) {
1592f3ed1f5dSPeter Maydell             errmsg = "Unable to find space for application";
1593f3ed1f5dSPeter Maydell             goto exit_errmsg;
1594f3ed1f5dSPeter Maydell         }
1595dce10401SMeador Inge         guest_base = real_start - loaddr;
1596dce10401SMeador Inge 
1597f3ed1f5dSPeter Maydell         qemu_log("Relocating guest address space from 0x"
1598f3ed1f5dSPeter Maydell                  TARGET_ABI_FMT_lx " to 0x%lx\n",
1599f3ed1f5dSPeter Maydell                  loaddr, real_start);
1600f3ed1f5dSPeter Maydell     }
1601f3ed1f5dSPeter Maydell     return;
1602f3ed1f5dSPeter Maydell 
1603f3ed1f5dSPeter Maydell exit_errmsg:
1604f3ed1f5dSPeter Maydell     fprintf(stderr, "%s: %s\n", image_name, errmsg);
1605f3ed1f5dSPeter Maydell     exit(-1);
1606f3ed1f5dSPeter Maydell #endif
1607f3ed1f5dSPeter Maydell }
1608f3ed1f5dSPeter Maydell 
1609f3ed1f5dSPeter Maydell 
16108e62a717SRichard Henderson /* Load an ELF image into the address space.
161131e31b8aSbellard 
16128e62a717SRichard Henderson    IMAGE_NAME is the filename of the image, to use in error messages.
16138e62a717SRichard Henderson    IMAGE_FD is the open file descriptor for the image.
16148e62a717SRichard Henderson 
16158e62a717SRichard Henderson    BPRM_BUF is a copy of the beginning of the file; this of course
16168e62a717SRichard Henderson    contains the elf file header at offset 0.  It is assumed that this
16178e62a717SRichard Henderson    buffer is sufficiently aligned to present no problems to the host
16188e62a717SRichard Henderson    in accessing data at aligned offsets within the buffer.
16198e62a717SRichard Henderson 
16208e62a717SRichard Henderson    On return: INFO values will be filled in, as necessary or available.  */
16218e62a717SRichard Henderson 
16228e62a717SRichard Henderson static void load_elf_image(const char *image_name, int image_fd,
1623bf858897SRichard Henderson                            struct image_info *info, char **pinterp_name,
16249955ffacSRichard Henderson                            char bprm_buf[BPRM_BUF_SIZE])
162531e31b8aSbellard {
16268e62a717SRichard Henderson     struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
16278e62a717SRichard Henderson     struct elf_phdr *phdr;
16288e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
16298e62a717SRichard Henderson     int i, retval;
16308e62a717SRichard Henderson     const char *errmsg;
163131e31b8aSbellard 
16328e62a717SRichard Henderson     /* First of all, some simple consistency checks */
16338e62a717SRichard Henderson     errmsg = "Invalid ELF image for this architecture";
16348e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
16358e62a717SRichard Henderson         goto exit_errmsg;
16368e62a717SRichard Henderson     }
16378e62a717SRichard Henderson     bswap_ehdr(ehdr);
16388e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
16398e62a717SRichard Henderson         goto exit_errmsg;
164031e31b8aSbellard     }
164131e31b8aSbellard 
16428e62a717SRichard Henderson     i = ehdr->e_phnum * sizeof(struct elf_phdr);
16438e62a717SRichard Henderson     if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
16448e62a717SRichard Henderson         phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
16459955ffacSRichard Henderson     } else {
16468e62a717SRichard Henderson         phdr = (struct elf_phdr *) alloca(i);
16478e62a717SRichard Henderson         retval = pread(image_fd, phdr, i, ehdr->e_phoff);
16489955ffacSRichard Henderson         if (retval != i) {
16498e62a717SRichard Henderson             goto exit_read;
16509955ffacSRichard Henderson         }
165131e31b8aSbellard     }
16528e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
165309bfb054Sbellard 
16541af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
16551af02e83SMike Frysinger     info->nsegs = 0;
16561af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
16571af02e83SMike Frysinger #endif
16581af02e83SMike Frysinger 
1659682674b8SRichard Henderson     /* Find the maximum size of the image and allocate an appropriate
1660682674b8SRichard Henderson        amount of memory to handle that.  */
1661682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
16628e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
16638e62a717SRichard Henderson         if (phdr[i].p_type == PT_LOAD) {
16648e62a717SRichard Henderson             abi_ulong a = phdr[i].p_vaddr;
1665682674b8SRichard Henderson             if (a < loaddr) {
1666682674b8SRichard Henderson                 loaddr = a;
1667682674b8SRichard Henderson             }
16688e62a717SRichard Henderson             a += phdr[i].p_memsz;
1669682674b8SRichard Henderson             if (a > hiaddr) {
1670682674b8SRichard Henderson                 hiaddr = a;
1671682674b8SRichard Henderson             }
16721af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
16731af02e83SMike Frysinger             ++info->nsegs;
16741af02e83SMike Frysinger #endif
1675682674b8SRichard Henderson         }
1676682674b8SRichard Henderson     }
1677682674b8SRichard Henderson 
1678682674b8SRichard Henderson     load_addr = loaddr;
16798e62a717SRichard Henderson     if (ehdr->e_type == ET_DYN) {
1680682674b8SRichard Henderson         /* The image indicates that it can be loaded anywhere.  Find a
1681682674b8SRichard Henderson            location that can hold the memory space required.  If the
1682682674b8SRichard Henderson            image is pre-linked, LOADDR will be non-zero.  Since we do
1683682674b8SRichard Henderson            not supply MAP_FIXED here we'll use that address if and
1684682674b8SRichard Henderson            only if it remains available.  */
1685682674b8SRichard Henderson         load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
1686682674b8SRichard Henderson                                 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
168709bfb054Sbellard                                 -1, 0);
1688682674b8SRichard Henderson         if (load_addr == -1) {
16898e62a717SRichard Henderson             goto exit_perror;
169009bfb054Sbellard         }
1691bf858897SRichard Henderson     } else if (pinterp_name != NULL) {
1692bf858897SRichard Henderson         /* This is the main executable.  Make sure that the low
1693bf858897SRichard Henderson            address does not conflict with MMAP_MIN_ADDR or the
1694bf858897SRichard Henderson            QEMU application itself.  */
1695f3ed1f5dSPeter Maydell         probe_guest_base(image_name, loaddr, hiaddr);
169609bfb054Sbellard     }
1697682674b8SRichard Henderson     load_bias = load_addr - loaddr;
169809bfb054Sbellard 
16991af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
17001af02e83SMike Frysinger     {
17011af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
17027267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
17031af02e83SMike Frysinger 
17041af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
17051af02e83SMike Frysinger             switch (phdr[i].p_type) {
17061af02e83SMike Frysinger             case PT_DYNAMIC:
17071af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
17081af02e83SMike Frysinger                 break;
17091af02e83SMike Frysinger             case PT_LOAD:
17101af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
17111af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
17121af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
17131af02e83SMike Frysinger                 ++loadsegs;
17141af02e83SMike Frysinger                 break;
17151af02e83SMike Frysinger             }
17161af02e83SMike Frysinger         }
17171af02e83SMike Frysinger     }
17181af02e83SMike Frysinger #endif
17191af02e83SMike Frysinger 
17208e62a717SRichard Henderson     info->load_bias = load_bias;
17218e62a717SRichard Henderson     info->load_addr = load_addr;
17228e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
17238e62a717SRichard Henderson     info->start_code = -1;
17248e62a717SRichard Henderson     info->end_code = 0;
17258e62a717SRichard Henderson     info->start_data = -1;
17268e62a717SRichard Henderson     info->end_data = 0;
17278e62a717SRichard Henderson     info->brk = 0;
1728d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
17298e62a717SRichard Henderson 
17308e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
17318e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
173231e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
1733682674b8SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
173431e31b8aSbellard             int elf_prot = 0;
173531e31b8aSbellard 
173631e31b8aSbellard             if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
173731e31b8aSbellard             if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
173831e31b8aSbellard             if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
173931e31b8aSbellard 
1740682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
1741682674b8SRichard Henderson             vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
1742682674b8SRichard Henderson             vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
1743682674b8SRichard Henderson 
1744682674b8SRichard Henderson             error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
1745682674b8SRichard Henderson                                 elf_prot, MAP_PRIVATE | MAP_FIXED,
17468e62a717SRichard Henderson                                 image_fd, eppnt->p_offset - vaddr_po);
1747e89f07d3Spbrook             if (error == -1) {
17488e62a717SRichard Henderson                 goto exit_perror;
174931e31b8aSbellard             }
175031e31b8aSbellard 
1751682674b8SRichard Henderson             vaddr_ef = vaddr + eppnt->p_filesz;
1752682674b8SRichard Henderson             vaddr_em = vaddr + eppnt->p_memsz;
175331e31b8aSbellard 
1754cf129f3aSRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it.  */
1755682674b8SRichard Henderson             if (vaddr_ef < vaddr_em) {
1756682674b8SRichard Henderson                 zero_bss(vaddr_ef, vaddr_em, elf_prot);
1757682674b8SRichard Henderson             }
17588e62a717SRichard Henderson 
17598e62a717SRichard Henderson             /* Find the full program boundaries.  */
17608e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
17618e62a717SRichard Henderson                 if (vaddr < info->start_code) {
17628e62a717SRichard Henderson                     info->start_code = vaddr;
1763cf129f3aSRichard Henderson                 }
17648e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
17658e62a717SRichard Henderson                     info->end_code = vaddr_ef;
17668e62a717SRichard Henderson                 }
17678e62a717SRichard Henderson             }
17688e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
17698e62a717SRichard Henderson                 if (vaddr < info->start_data) {
17708e62a717SRichard Henderson                     info->start_data = vaddr;
17718e62a717SRichard Henderson                 }
17728e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
17738e62a717SRichard Henderson                     info->end_data = vaddr_ef;
17748e62a717SRichard Henderson                 }
17758e62a717SRichard Henderson                 if (vaddr_em > info->brk) {
17768e62a717SRichard Henderson                     info->brk = vaddr_em;
17778e62a717SRichard Henderson                 }
17788e62a717SRichard Henderson             }
1779bf858897SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
1780bf858897SRichard Henderson             char *interp_name;
1781bf858897SRichard Henderson 
1782bf858897SRichard Henderson             if (*pinterp_name) {
1783bf858897SRichard Henderson                 errmsg = "Multiple PT_INTERP entries";
1784bf858897SRichard Henderson                 goto exit_errmsg;
1785bf858897SRichard Henderson             }
1786bf858897SRichard Henderson             interp_name = malloc(eppnt->p_filesz);
1787bf858897SRichard Henderson             if (!interp_name) {
1788bf858897SRichard Henderson                 goto exit_perror;
1789bf858897SRichard Henderson             }
1790bf858897SRichard Henderson 
1791bf858897SRichard Henderson             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
1792bf858897SRichard Henderson                 memcpy(interp_name, bprm_buf + eppnt->p_offset,
1793bf858897SRichard Henderson                        eppnt->p_filesz);
1794bf858897SRichard Henderson             } else {
1795bf858897SRichard Henderson                 retval = pread(image_fd, interp_name, eppnt->p_filesz,
1796bf858897SRichard Henderson                                eppnt->p_offset);
1797bf858897SRichard Henderson                 if (retval != eppnt->p_filesz) {
1798bf858897SRichard Henderson                     goto exit_perror;
1799bf858897SRichard Henderson                 }
1800bf858897SRichard Henderson             }
1801bf858897SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
1802bf858897SRichard Henderson                 errmsg = "Invalid PT_INTERP entry";
1803bf858897SRichard Henderson                 goto exit_errmsg;
1804bf858897SRichard Henderson             }
1805bf858897SRichard Henderson             *pinterp_name = interp_name;
18068e62a717SRichard Henderson         }
18078e62a717SRichard Henderson     }
18088e62a717SRichard Henderson 
18098e62a717SRichard Henderson     if (info->end_data == 0) {
18108e62a717SRichard Henderson         info->start_data = info->end_code;
18118e62a717SRichard Henderson         info->end_data = info->end_code;
18128e62a717SRichard Henderson         info->brk = info->end_code;
181331e31b8aSbellard     }
181431e31b8aSbellard 
1815682674b8SRichard Henderson     if (qemu_log_enabled()) {
18168e62a717SRichard Henderson         load_symbols(ehdr, image_fd, load_bias);
1817682674b8SRichard Henderson     }
181831e31b8aSbellard 
18198e62a717SRichard Henderson     close(image_fd);
18208e62a717SRichard Henderson     return;
182131e31b8aSbellard 
18228e62a717SRichard Henderson  exit_read:
18238e62a717SRichard Henderson     if (retval >= 0) {
18248e62a717SRichard Henderson         errmsg = "Incomplete read of file header";
18258e62a717SRichard Henderson         goto exit_errmsg;
18268e62a717SRichard Henderson     }
18278e62a717SRichard Henderson  exit_perror:
18288e62a717SRichard Henderson     errmsg = strerror(errno);
18298e62a717SRichard Henderson  exit_errmsg:
18308e62a717SRichard Henderson     fprintf(stderr, "%s: %s\n", image_name, errmsg);
18318e62a717SRichard Henderson     exit(-1);
18328e62a717SRichard Henderson }
18338e62a717SRichard Henderson 
18348e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
18358e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
18368e62a717SRichard Henderson {
18378e62a717SRichard Henderson     int fd, retval;
18388e62a717SRichard Henderson 
18398e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
18408e62a717SRichard Henderson     if (fd < 0) {
18418e62a717SRichard Henderson         goto exit_perror;
18428e62a717SRichard Henderson     }
18438e62a717SRichard Henderson 
18448e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
18458e62a717SRichard Henderson     if (retval < 0) {
18468e62a717SRichard Henderson         goto exit_perror;
18478e62a717SRichard Henderson     }
18488e62a717SRichard Henderson     if (retval < BPRM_BUF_SIZE) {
18498e62a717SRichard Henderson         memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
18508e62a717SRichard Henderson     }
18518e62a717SRichard Henderson 
1852bf858897SRichard Henderson     load_elf_image(filename, fd, info, NULL, bprm_buf);
18538e62a717SRichard Henderson     return;
18548e62a717SRichard Henderson 
18558e62a717SRichard Henderson  exit_perror:
18568e62a717SRichard Henderson     fprintf(stderr, "%s: %s\n", filename, strerror(errno));
18578e62a717SRichard Henderson     exit(-1);
185831e31b8aSbellard }
185931e31b8aSbellard 
186049918a75Spbrook static int symfind(const void *s0, const void *s1)
186149918a75Spbrook {
1862c7c530cdSStefan Weil     target_ulong addr = *(target_ulong *)s0;
186349918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
186449918a75Spbrook     int result = 0;
1865c7c530cdSStefan Weil     if (addr < sym->st_value) {
186649918a75Spbrook         result = -1;
1867c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
186849918a75Spbrook         result = 1;
186949918a75Spbrook     }
187049918a75Spbrook     return result;
187149918a75Spbrook }
187249918a75Spbrook 
187349918a75Spbrook static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
187449918a75Spbrook {
187549918a75Spbrook #if ELF_CLASS == ELFCLASS32
187649918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
187749918a75Spbrook #else
187849918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
187949918a75Spbrook #endif
188049918a75Spbrook 
188149918a75Spbrook     // binary search
188249918a75Spbrook     struct elf_sym *sym;
188349918a75Spbrook 
1884c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
18857cba04f6SBlue Swirl     if (sym != NULL) {
188649918a75Spbrook         return s->disas_strtab + sym->st_name;
188749918a75Spbrook     }
188849918a75Spbrook 
188949918a75Spbrook     return "";
189049918a75Spbrook }
189149918a75Spbrook 
189249918a75Spbrook /* FIXME: This should use elf_ops.h  */
189349918a75Spbrook static int symcmp(const void *s0, const void *s1)
189449918a75Spbrook {
189549918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
189649918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
189749918a75Spbrook     return (sym0->st_value < sym1->st_value)
189849918a75Spbrook         ? -1
189949918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
190049918a75Spbrook }
190149918a75Spbrook 
1902689f936fSbellard /* Best attempt to load symbols from this ELF object. */
1903682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
1904689f936fSbellard {
1905682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
1906682674b8SRichard Henderson     struct elf_shdr *shdr;
1907b9475279SCédric VINCENT     char *strings = NULL;
1908b9475279SCédric VINCENT     struct syminfo *s = NULL;
1909b9475279SCédric VINCENT     struct elf_sym *new_syms, *syms = NULL;
191031e31b8aSbellard 
1911682674b8SRichard Henderson     shnum = hdr->e_shnum;
1912682674b8SRichard Henderson     i = shnum * sizeof(struct elf_shdr);
1913682674b8SRichard Henderson     shdr = (struct elf_shdr *)alloca(i);
1914682674b8SRichard Henderson     if (pread(fd, shdr, i, hdr->e_shoff) != i) {
1915689f936fSbellard         return;
1916682674b8SRichard Henderson     }
1917682674b8SRichard Henderson 
1918682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
1919682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
1920682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
1921682674b8SRichard Henderson             sym_idx = i;
1922682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
1923689f936fSbellard             goto found;
1924689f936fSbellard         }
1925689f936fSbellard     }
1926682674b8SRichard Henderson 
1927682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
1928682674b8SRichard Henderson     return;
1929689f936fSbellard 
1930689f936fSbellard  found:
1931689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
1932e80cfcfcSbellard     s = malloc(sizeof(*s));
1933682674b8SRichard Henderson     if (!s) {
1934b9475279SCédric VINCENT         goto give_up;
1935682674b8SRichard Henderson     }
1936682674b8SRichard Henderson 
1937682674b8SRichard Henderson     i = shdr[str_idx].sh_size;
1938682674b8SRichard Henderson     s->disas_strtab = strings = malloc(i);
1939682674b8SRichard Henderson     if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
1940b9475279SCédric VINCENT         goto give_up;
1941682674b8SRichard Henderson     }
1942689f936fSbellard 
1943682674b8SRichard Henderson     i = shdr[sym_idx].sh_size;
1944682674b8SRichard Henderson     syms = malloc(i);
1945682674b8SRichard Henderson     if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
1946b9475279SCédric VINCENT         goto give_up;
1947682674b8SRichard Henderson     }
1948689f936fSbellard 
1949682674b8SRichard Henderson     nsyms = i / sizeof(struct elf_sym);
1950682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
195149918a75Spbrook         bswap_sym(syms + i);
1952682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
1953682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
1954682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
1955682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
1956682674b8SRichard Henderson             if (i < --nsyms) {
195749918a75Spbrook                 syms[i] = syms[nsyms];
195849918a75Spbrook             }
1959682674b8SRichard Henderson         } else {
196049918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
196149918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
196249918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
196349918a75Spbrook #endif
1964682674b8SRichard Henderson             syms[i].st_value += load_bias;
196549918a75Spbrook             i++;
196649918a75Spbrook         }
1967682674b8SRichard Henderson     }
196849918a75Spbrook 
1969b9475279SCédric VINCENT     /* No "useful" symbol.  */
1970b9475279SCédric VINCENT     if (nsyms == 0) {
1971b9475279SCédric VINCENT         goto give_up;
1972b9475279SCédric VINCENT     }
1973b9475279SCédric VINCENT 
19745d5c9930SRichard Henderson     /* Attempt to free the storage associated with the local symbols
19755d5c9930SRichard Henderson        that we threw away.  Whether or not this has any effect on the
19765d5c9930SRichard Henderson        memory allocation depends on the malloc implementation and how
19775d5c9930SRichard Henderson        many symbols we managed to discard.  */
19788d79de6eSStefan Weil     new_syms = realloc(syms, nsyms * sizeof(*syms));
19798d79de6eSStefan Weil     if (new_syms == NULL) {
1980b9475279SCédric VINCENT         goto give_up;
19815d5c9930SRichard Henderson     }
19828d79de6eSStefan Weil     syms = new_syms;
19835d5c9930SRichard Henderson 
198449918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
198549918a75Spbrook 
198649918a75Spbrook     s->disas_num_syms = nsyms;
198749918a75Spbrook #if ELF_CLASS == ELFCLASS32
198849918a75Spbrook     s->disas_symtab.elf32 = syms;
198949918a75Spbrook #else
199049918a75Spbrook     s->disas_symtab.elf64 = syms;
199149918a75Spbrook #endif
1992682674b8SRichard Henderson     s->lookup_symbol = lookup_symbolxx;
1993e80cfcfcSbellard     s->next = syminfos;
1994e80cfcfcSbellard     syminfos = s;
1995b9475279SCédric VINCENT 
1996b9475279SCédric VINCENT     return;
1997b9475279SCédric VINCENT 
1998b9475279SCédric VINCENT give_up:
1999b9475279SCédric VINCENT     free(s);
2000b9475279SCédric VINCENT     free(strings);
2001b9475279SCédric VINCENT     free(syms);
2002689f936fSbellard }
200331e31b8aSbellard 
2004f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
200531e31b8aSbellard {
20068e62a717SRichard Henderson     struct image_info interp_info;
200731e31b8aSbellard     struct elfhdr elf_ex;
20088e62a717SRichard Henderson     char *elf_interpreter = NULL;
200931e31b8aSbellard 
2010bf858897SRichard Henderson     info->start_mmap = (abi_ulong)ELF_START_MMAP;
2011bf858897SRichard Henderson     info->mmap = 0;
2012bf858897SRichard Henderson     info->rss = 0;
201331e31b8aSbellard 
2014bf858897SRichard Henderson     load_elf_image(bprm->filename, bprm->fd, info,
2015bf858897SRichard Henderson                    &elf_interpreter, bprm->buf);
2016bf858897SRichard Henderson 
2017bf858897SRichard Henderson     /* ??? We need a copy of the elf header for passing to create_elf_tables.
2018bf858897SRichard Henderson        If we do nothing, we'll have overwritten this when we re-use bprm->buf
2019bf858897SRichard Henderson        when we load the interpreter.  */
2020bf858897SRichard Henderson     elf_ex = *(struct elfhdr *)bprm->buf;
202131e31b8aSbellard 
2022e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
2023e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
2024e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
2025e5fe0c52Spbrook     if (!bprm->p) {
2026bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
202731e31b8aSbellard         exit(-1);
20289955ffacSRichard Henderson     }
2029379f6698SPaul Brook 
203031e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
203131e31b8aSbellard        change some of these later */
203231e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
203331e31b8aSbellard 
20348e62a717SRichard Henderson     if (elf_interpreter) {
20358e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
203631e31b8aSbellard 
20378e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
20388e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
203931e31b8aSbellard 
20408e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
20418e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
20428e62a717SRichard Henderson             info->personality = PER_SVR4;
20438e62a717SRichard Henderson 
204431e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
20458e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
20468e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
20478e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
20488e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
204931e31b8aSbellard                         MAP_FIXED | MAP_PRIVATE, -1, 0);
205031e31b8aSbellard         }
20518e62a717SRichard Henderson     }
205231e31b8aSbellard 
20538e62a717SRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
20548e62a717SRichard Henderson                                 info, (elf_interpreter ? &interp_info : NULL));
20558e62a717SRichard Henderson     info->start_stack = bprm->p;
20568e62a717SRichard Henderson 
20578e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
20588e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
20598e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
20608e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
20618e62a717SRichard Henderson     if (elf_interpreter) {
20628e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
20638e62a717SRichard Henderson         info->entry = interp_info.entry;
2064bf858897SRichard Henderson         free(elf_interpreter);
20658e62a717SRichard Henderson     }
206631e31b8aSbellard 
2067edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
2068edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
2069edf8e2afSMika Westerberg #endif
2070edf8e2afSMika Westerberg 
207131e31b8aSbellard     return 0;
207231e31b8aSbellard }
207331e31b8aSbellard 
2074edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
2075edf8e2afSMika Westerberg /*
2076edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
2077a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
2078edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
2079edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
2080edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
2081edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
2082edf8e2afSMika Westerberg  *
2083edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
2084edf8e2afSMika Westerberg  * are marked with XXX.
2085edf8e2afSMika Westerberg  *
2086edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
2087edf8e2afSMika Westerberg  *
2088edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
2089dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
2090edf8e2afSMika Westerberg  * the target resides):
2091edf8e2afSMika Westerberg  *
2092edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
2093edf8e2afSMika Westerberg  *
2094edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
2095edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
2096edf8e2afSMika Westerberg  *
2097c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
2098edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
2099c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
2100edf8e2afSMika Westerberg  *
2101edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
2102edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
2103edf8e2afSMika Westerberg  *
2104c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
21059349b4f9SAndreas Färber  *                                const CPUArchState *env);
2106edf8e2afSMika Westerberg  *
2107edf8e2afSMika Westerberg  * Parameters:
2108edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
2109edf8e2afSMika Westerberg  *     env - copy registers from here
2110edf8e2afSMika Westerberg  *
2111edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
2112edf8e2afSMika Westerberg  */
2113edf8e2afSMika Westerberg 
2114edf8e2afSMika Westerberg /* An ELF note in memory */
2115edf8e2afSMika Westerberg struct memelfnote {
2116edf8e2afSMika Westerberg     const char *name;
2117edf8e2afSMika Westerberg     size_t     namesz;
2118edf8e2afSMika Westerberg     size_t     namesz_rounded;
2119edf8e2afSMika Westerberg     int        type;
2120edf8e2afSMika Westerberg     size_t     datasz;
212180f5ce75SLaurent Vivier     size_t     datasz_rounded;
2122edf8e2afSMika Westerberg     void       *data;
2123edf8e2afSMika Westerberg     size_t     notesz;
2124edf8e2afSMika Westerberg };
2125edf8e2afSMika Westerberg 
2126a2547a13SLaurent Desnogues struct target_elf_siginfo {
2127f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
2128f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
2129f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
2130edf8e2afSMika Westerberg };
2131edf8e2afSMika Westerberg 
2132a2547a13SLaurent Desnogues struct target_elf_prstatus {
2133a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
21341ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
2135ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
2136ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
2137c227f099SAnthony Liguori     target_pid_t       pr_pid;
2138c227f099SAnthony Liguori     target_pid_t       pr_ppid;
2139c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
2140c227f099SAnthony Liguori     target_pid_t       pr_sid;
2141edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
2142edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
2143edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
2144edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
2145c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
2146f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
2147edf8e2afSMika Westerberg };
2148edf8e2afSMika Westerberg 
2149edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
2150edf8e2afSMika Westerberg 
2151a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
2152edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
2153edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
2154edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
2155edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
2156ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
2157c227f099SAnthony Liguori     target_uid_t pr_uid;
2158c227f099SAnthony Liguori     target_gid_t pr_gid;
2159c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
2160edf8e2afSMika Westerberg     /* Lots missing */
2161edf8e2afSMika Westerberg     char    pr_fname[16];           /* filename of executable */
2162edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
2163edf8e2afSMika Westerberg };
2164edf8e2afSMika Westerberg 
2165edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
2166edf8e2afSMika Westerberg struct elf_thread_status {
216772cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
2168a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
2169edf8e2afSMika Westerberg #if 0
2170edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
2171edf8e2afSMika Westerberg     struct task_struct *thread;
2172edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
2173edf8e2afSMika Westerberg #endif
2174edf8e2afSMika Westerberg     struct memelfnote notes[1];
2175edf8e2afSMika Westerberg     int num_notes;
2176edf8e2afSMika Westerberg };
2177edf8e2afSMika Westerberg 
2178edf8e2afSMika Westerberg struct elf_note_info {
2179edf8e2afSMika Westerberg     struct memelfnote   *notes;
2180a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
2181a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
2182edf8e2afSMika Westerberg 
218372cf2d4fSBlue Swirl     QTAILQ_HEAD(thread_list_head, elf_thread_status) thread_list;
2184edf8e2afSMika Westerberg #if 0
2185edf8e2afSMika Westerberg     /*
2186edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
2187edf8e2afSMika Westerberg      * dumping fp regs etc.
2188edf8e2afSMika Westerberg      */
2189edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
2190edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
2191edf8e2afSMika Westerberg     int thread_status_size;
2192edf8e2afSMika Westerberg #endif
2193edf8e2afSMika Westerberg     int notes_size;
2194edf8e2afSMika Westerberg     int numnote;
2195edf8e2afSMika Westerberg };
2196edf8e2afSMika Westerberg 
2197edf8e2afSMika Westerberg struct vm_area_struct {
2198edf8e2afSMika Westerberg     abi_ulong   vma_start;  /* start vaddr of memory region */
2199edf8e2afSMika Westerberg     abi_ulong   vma_end;    /* end vaddr of memory region */
2200edf8e2afSMika Westerberg     abi_ulong   vma_flags;  /* protection etc. flags for the region */
220172cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
2202edf8e2afSMika Westerberg };
2203edf8e2afSMika Westerberg 
2204edf8e2afSMika Westerberg struct mm_struct {
220572cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
2206edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
2207edf8e2afSMika Westerberg };
2208edf8e2afSMika Westerberg 
2209edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
2210edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
2211edf8e2afSMika Westerberg static int vma_add_mapping(struct mm_struct *, abi_ulong,
2212edf8e2afSMika Westerberg                            abi_ulong, abi_ulong);
2213edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
2214edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
2215edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
2216edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
2217b480d9b7SPaul Brook static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
2218edf8e2afSMika Westerberg                       unsigned long flags);
2219edf8e2afSMika Westerberg 
2220edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
2221edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
2222edf8e2afSMika Westerberg                       unsigned int, void *);
2223a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
2224a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
2225edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
2226edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
2227edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
2228edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
22299349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
22309349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
2231edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *, char *, size_t);
2232edf8e2afSMika Westerberg 
2233edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
2234edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
2235edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
2236edf8e2afSMika Westerberg 
2237edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2238a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
2239edf8e2afSMika Westerberg {
2240ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
2241ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
2242ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
2243edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
2244ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
2245ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
2246edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
2247edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
2248edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
2249edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
2250edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
2251edf8e2afSMika Westerberg     /* regs should be in correct format already */
2252edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
2253edf8e2afSMika Westerberg }
2254edf8e2afSMika Westerberg 
2255a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
2256edf8e2afSMika Westerberg {
2257ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
2258edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
2259edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
2260edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
2261edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
2262edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
2263edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
2264edf8e2afSMika Westerberg }
2265991f8f0cSRichard Henderson 
2266991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
2267991f8f0cSRichard Henderson {
2268991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
2269991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
2270991f8f0cSRichard Henderson     bswap32s(&en->n_type);
2271991f8f0cSRichard Henderson }
2272991f8f0cSRichard Henderson #else
2273991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
2274991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
2275991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
2276edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
2277edf8e2afSMika Westerberg 
2278edf8e2afSMika Westerberg /*
2279edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
2280edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
2281edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
2282edf8e2afSMika Westerberg  * thread that received the signal is stopped.
2283edf8e2afSMika Westerberg  */
2284edf8e2afSMika Westerberg 
2285edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
2286edf8e2afSMika Westerberg {
2287edf8e2afSMika Westerberg     struct mm_struct *mm;
2288edf8e2afSMika Westerberg 
22897267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
2290edf8e2afSMika Westerberg         return (NULL);
2291edf8e2afSMika Westerberg 
2292edf8e2afSMika Westerberg     mm->mm_count = 0;
229372cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
2294edf8e2afSMika Westerberg 
2295edf8e2afSMika Westerberg     return (mm);
2296edf8e2afSMika Westerberg }
2297edf8e2afSMika Westerberg 
2298edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
2299edf8e2afSMika Westerberg {
2300edf8e2afSMika Westerberg     struct vm_area_struct *vma;
2301edf8e2afSMika Westerberg 
2302edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
230372cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
23047267c094SAnthony Liguori         g_free(vma);
2305edf8e2afSMika Westerberg     }
23067267c094SAnthony Liguori     g_free(mm);
2307edf8e2afSMika Westerberg }
2308edf8e2afSMika Westerberg 
2309edf8e2afSMika Westerberg static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
2310edf8e2afSMika Westerberg                            abi_ulong end, abi_ulong flags)
2311edf8e2afSMika Westerberg {
2312edf8e2afSMika Westerberg     struct vm_area_struct *vma;
2313edf8e2afSMika Westerberg 
23147267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
2315edf8e2afSMika Westerberg         return (-1);
2316edf8e2afSMika Westerberg 
2317edf8e2afSMika Westerberg     vma->vma_start = start;
2318edf8e2afSMika Westerberg     vma->vma_end = end;
2319edf8e2afSMika Westerberg     vma->vma_flags = flags;
2320edf8e2afSMika Westerberg 
232172cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
2322edf8e2afSMika Westerberg     mm->mm_count++;
2323edf8e2afSMika Westerberg 
2324edf8e2afSMika Westerberg     return (0);
2325edf8e2afSMika Westerberg }
2326edf8e2afSMika Westerberg 
2327edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
2328edf8e2afSMika Westerberg {
232972cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
2330edf8e2afSMika Westerberg }
2331edf8e2afSMika Westerberg 
2332edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
2333edf8e2afSMika Westerberg {
233472cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
2335edf8e2afSMika Westerberg }
2336edf8e2afSMika Westerberg 
2337edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
2338edf8e2afSMika Westerberg {
2339edf8e2afSMika Westerberg     return (mm->mm_count);
2340edf8e2afSMika Westerberg }
2341edf8e2afSMika Westerberg 
2342edf8e2afSMika Westerberg /*
2343edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
2344edf8e2afSMika Westerberg  */
2345edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
2346edf8e2afSMika Westerberg {
2347edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
2348edf8e2afSMika Westerberg     if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
2349edf8e2afSMika Westerberg         return (0);
2350edf8e2afSMika Westerberg 
2351edf8e2afSMika Westerberg     /*
2352edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
2353edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
2354edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
2355edf8e2afSMika Westerberg      * also executable so we read in first page of given region
2356edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
2357edf8e2afSMika Westerberg      * no elf header, we dump it.
2358edf8e2afSMika Westerberg      */
2359edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
2360edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
2361edf8e2afSMika Westerberg 
2362edf8e2afSMika Westerberg         copy_from_user(page, vma->vma_start, sizeof (page));
2363edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
2364edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
2365edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
2366edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
2367edf8e2afSMika Westerberg             /*
2368edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
2369edf8e2afSMika Westerberg              * them.
2370edf8e2afSMika Westerberg              */
2371edf8e2afSMika Westerberg             return (0);
2372edf8e2afSMika Westerberg         }
2373edf8e2afSMika Westerberg     }
2374edf8e2afSMika Westerberg 
2375edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
2376edf8e2afSMika Westerberg }
2377edf8e2afSMika Westerberg 
2378b480d9b7SPaul Brook static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
2379edf8e2afSMika Westerberg                       unsigned long flags)
2380edf8e2afSMika Westerberg {
2381edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
2382edf8e2afSMika Westerberg 
2383edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
2384edf8e2afSMika Westerberg     return (0);
2385edf8e2afSMika Westerberg }
2386edf8e2afSMika Westerberg 
2387edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
2388edf8e2afSMika Westerberg                       unsigned int sz, void *data)
2389edf8e2afSMika Westerberg {
2390edf8e2afSMika Westerberg     unsigned int namesz;
2391edf8e2afSMika Westerberg 
2392edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
2393edf8e2afSMika Westerberg     note->name = name;
2394edf8e2afSMika Westerberg     note->namesz = namesz;
2395edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
2396edf8e2afSMika Westerberg     note->type = type;
239780f5ce75SLaurent Vivier     note->datasz = sz;
239880f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
239980f5ce75SLaurent Vivier 
2400edf8e2afSMika Westerberg     note->data = data;
2401edf8e2afSMika Westerberg 
2402edf8e2afSMika Westerberg     /*
2403edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
2404edf8e2afSMika Westerberg      * ELF document.
2405edf8e2afSMika Westerberg      */
2406edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
240780f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
2408edf8e2afSMika Westerberg }
2409edf8e2afSMika Westerberg 
2410edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
2411edf8e2afSMika Westerberg                             uint32_t flags)
2412edf8e2afSMika Westerberg {
2413edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
2414edf8e2afSMika Westerberg 
2415edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
2416edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
2417edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
2418edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
2419edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
2420edf8e2afSMika Westerberg 
2421edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
2422edf8e2afSMika Westerberg     elf->e_machine = machine;
2423edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
2424edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
2425edf8e2afSMika Westerberg     elf->e_flags = flags;
2426edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
2427edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
2428edf8e2afSMika Westerberg     elf->e_phnum = segs;
2429edf8e2afSMika Westerberg 
2430edf8e2afSMika Westerberg     bswap_ehdr(elf);
2431edf8e2afSMika Westerberg }
2432edf8e2afSMika Westerberg 
2433edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
2434edf8e2afSMika Westerberg {
2435edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
2436edf8e2afSMika Westerberg     phdr->p_offset = offset;
2437edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
2438edf8e2afSMika Westerberg     phdr->p_paddr = 0;
2439edf8e2afSMika Westerberg     phdr->p_filesz = sz;
2440edf8e2afSMika Westerberg     phdr->p_memsz = 0;
2441edf8e2afSMika Westerberg     phdr->p_flags = 0;
2442edf8e2afSMika Westerberg     phdr->p_align = 0;
2443edf8e2afSMika Westerberg 
2444991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
2445edf8e2afSMika Westerberg }
2446edf8e2afSMika Westerberg 
2447edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
2448edf8e2afSMika Westerberg {
2449edf8e2afSMika Westerberg     return (note->notesz);
2450edf8e2afSMika Westerberg }
2451edf8e2afSMika Westerberg 
2452a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
2453edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
2454edf8e2afSMika Westerberg {
2455edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
2456edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
2457edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
2458edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
2459edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
2460edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
2461edf8e2afSMika Westerberg 
2462edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
2463edf8e2afSMika Westerberg }
2464edf8e2afSMika Westerberg 
2465a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
2466edf8e2afSMika Westerberg {
2467900cfbcaSJim Meyering     char *base_filename;
2468edf8e2afSMika Westerberg     unsigned int i, len;
2469edf8e2afSMika Westerberg 
2470edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
2471edf8e2afSMika Westerberg 
2472edf8e2afSMika Westerberg     len = ts->info->arg_end - ts->info->arg_start;
2473edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
2474edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
2475edf8e2afSMika Westerberg     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
2476edf8e2afSMika Westerberg         return -EFAULT;
2477edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
2478edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
2479edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
2480edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
2481edf8e2afSMika Westerberg 
2482edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
2483edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
2484edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
2485edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
2486edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
2487edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
2488edf8e2afSMika Westerberg 
2489900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
2490900cfbcaSJim Meyering     /*
2491900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
2492900cfbcaSJim Meyering      * this field is not NUL-terminated.
2493900cfbcaSJim Meyering      */
2494edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
2495edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
2496edf8e2afSMika Westerberg 
2497900cfbcaSJim Meyering     g_free(base_filename);
2498edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
2499edf8e2afSMika Westerberg     return (0);
2500edf8e2afSMika Westerberg }
2501edf8e2afSMika Westerberg 
2502edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
2503edf8e2afSMika Westerberg {
2504edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
2505edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
2506edf8e2afSMika Westerberg     void *ptr;
2507125b0f55SAlexander Graf     int len = ts->info->auxv_len;
2508edf8e2afSMika Westerberg 
2509edf8e2afSMika Westerberg     /*
2510edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
2511edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
2512edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
2513edf8e2afSMika Westerberg      */
2514edf8e2afSMika Westerberg 
2515edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
2516edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
2517edf8e2afSMika Westerberg     if (ptr != NULL) {
2518edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
2519edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
2520edf8e2afSMika Westerberg     }
2521edf8e2afSMika Westerberg }
2522edf8e2afSMika Westerberg 
2523edf8e2afSMika Westerberg /*
2524edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
2525edf8e2afSMika Westerberg  * for the name:
2526edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
2527edf8e2afSMika Westerberg  *
2528edf8e2afSMika Westerberg  * Returns 0 in case of success, -1 otherwise (errno is set).
2529edf8e2afSMika Westerberg  */
2530edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *ts, char *buf,
2531edf8e2afSMika Westerberg                               size_t bufsize)
2532edf8e2afSMika Westerberg {
2533edf8e2afSMika Westerberg     char timestamp[64];
2534edf8e2afSMika Westerberg     char *filename = NULL;
2535edf8e2afSMika Westerberg     char *base_filename = NULL;
2536edf8e2afSMika Westerberg     struct timeval tv;
2537edf8e2afSMika Westerberg     struct tm tm;
2538edf8e2afSMika Westerberg 
2539edf8e2afSMika Westerberg     assert(bufsize >= PATH_MAX);
2540edf8e2afSMika Westerberg 
2541edf8e2afSMika Westerberg     if (gettimeofday(&tv, NULL) < 0) {
2542edf8e2afSMika Westerberg         (void) fprintf(stderr, "unable to get current timestamp: %s",
2543edf8e2afSMika Westerberg                        strerror(errno));
2544edf8e2afSMika Westerberg         return (-1);
2545edf8e2afSMika Westerberg     }
2546edf8e2afSMika Westerberg 
2547edf8e2afSMika Westerberg     filename = strdup(ts->bprm->filename);
2548edf8e2afSMika Westerberg     base_filename = strdup(basename(filename));
2549edf8e2afSMika Westerberg     (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
2550edf8e2afSMika Westerberg                     localtime_r(&tv.tv_sec, &tm));
2551edf8e2afSMika Westerberg     (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
2552edf8e2afSMika Westerberg                     base_filename, timestamp, (int)getpid());
2553edf8e2afSMika Westerberg     free(base_filename);
2554edf8e2afSMika Westerberg     free(filename);
2555edf8e2afSMika Westerberg 
2556edf8e2afSMika Westerberg     return (0);
2557edf8e2afSMika Westerberg }
2558edf8e2afSMika Westerberg 
2559edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
2560edf8e2afSMika Westerberg {
2561edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
2562edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
2563edf8e2afSMika Westerberg     struct rlimit dumpsize;
2564edf8e2afSMika Westerberg     off_t pos;
2565edf8e2afSMika Westerberg 
2566edf8e2afSMika Westerberg     bytes_written = 0;
2567edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
2568edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
2569edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
2570edf8e2afSMika Westerberg             bytes_left = size;
2571edf8e2afSMika Westerberg         } else {
2572edf8e2afSMika Westerberg             return pos;
2573edf8e2afSMika Westerberg         }
2574edf8e2afSMika Westerberg     } else {
2575edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
2576edf8e2afSMika Westerberg             return -1;
2577edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
2578edf8e2afSMika Westerberg             bytes_left = size;
2579edf8e2afSMika Westerberg         } else {
2580edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
2581edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
2582edf8e2afSMika Westerberg         }
2583edf8e2afSMika Westerberg     }
2584edf8e2afSMika Westerberg 
2585edf8e2afSMika Westerberg     /*
2586edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
2587edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
2588edf8e2afSMika Westerberg      */
2589edf8e2afSMika Westerberg     do {
2590edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
2591edf8e2afSMika Westerberg         if (bytes_written < 0) {
2592edf8e2afSMika Westerberg             if (errno == EINTR)
2593edf8e2afSMika Westerberg                 continue;
2594edf8e2afSMika Westerberg             return (-1);
2595edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
2596edf8e2afSMika Westerberg             return (-1);
2597edf8e2afSMika Westerberg         }
2598edf8e2afSMika Westerberg         bufp += bytes_written;
2599edf8e2afSMika Westerberg         bytes_left -= bytes_written;
2600edf8e2afSMika Westerberg     } while (bytes_left > 0);
2601edf8e2afSMika Westerberg 
2602edf8e2afSMika Westerberg     return (0);
2603edf8e2afSMika Westerberg }
2604edf8e2afSMika Westerberg 
2605edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
2606edf8e2afSMika Westerberg {
2607edf8e2afSMika Westerberg     struct elf_note en;
2608edf8e2afSMika Westerberg 
2609edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
2610edf8e2afSMika Westerberg     en.n_type = men->type;
2611edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
2612edf8e2afSMika Westerberg 
2613edf8e2afSMika Westerberg     bswap_note(&en);
2614edf8e2afSMika Westerberg 
2615edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
2616edf8e2afSMika Westerberg         return (-1);
2617edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
2618edf8e2afSMika Westerberg         return (-1);
261980f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
2620edf8e2afSMika Westerberg         return (-1);
2621edf8e2afSMika Westerberg 
2622edf8e2afSMika Westerberg     return (0);
2623edf8e2afSMika Westerberg }
2624edf8e2afSMika Westerberg 
26259349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
2626edf8e2afSMika Westerberg {
26270429a971SAndreas Färber     CPUState *cpu = ENV_GET_CPU((CPUArchState *)env);
26280429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
2629edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2630edf8e2afSMika Westerberg 
26317267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
2632edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
2633edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
2634edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
2635edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
2636edf8e2afSMika Westerberg               &ets->prstatus);
2637edf8e2afSMika Westerberg 
263872cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
2639edf8e2afSMika Westerberg 
2640edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
2641edf8e2afSMika Westerberg }
2642edf8e2afSMika Westerberg 
26436afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
26446afafa86SPeter Maydell {
26456afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
26466afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
26476afafa86SPeter Maydell      * called before calling fill_note_info().
26486afafa86SPeter Maydell      */
26496afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
26506afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
26516afafa86SPeter Maydell }
26526afafa86SPeter Maydell 
2653edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
26549349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
2655edf8e2afSMika Westerberg {
2656edf8e2afSMika Westerberg #define NUMNOTES 3
26570429a971SAndreas Färber     CPUState *cpu = ENV_GET_CPU((CPUArchState *)env);
26580429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
2659edf8e2afSMika Westerberg     int i;
2660edf8e2afSMika Westerberg 
26617267c094SAnthony Liguori     info->notes = g_malloc0(NUMNOTES * sizeof (struct memelfnote));
2662edf8e2afSMika Westerberg     if (info->notes == NULL)
2663edf8e2afSMika Westerberg         return (-ENOMEM);
26647267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
2665edf8e2afSMika Westerberg     if (info->prstatus == NULL)
2666edf8e2afSMika Westerberg         return (-ENOMEM);
26677267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
2668edf8e2afSMika Westerberg     if (info->prstatus == NULL)
2669edf8e2afSMika Westerberg         return (-ENOMEM);
2670edf8e2afSMika Westerberg 
2671edf8e2afSMika Westerberg     /*
2672edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
2673edf8e2afSMika Westerberg      * including process info & aux vector.
2674edf8e2afSMika Westerberg      */
2675edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
2676edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
2677edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
2678edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
2679edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
2680edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
2681edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
2682edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
2683edf8e2afSMika Westerberg     info->numnote = 3;
2684edf8e2afSMika Westerberg 
2685edf8e2afSMika Westerberg     info->notes_size = 0;
2686edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
2687edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
2688edf8e2afSMika Westerberg 
2689edf8e2afSMika Westerberg     /* read and fill status of all threads */
2690edf8e2afSMika Westerberg     cpu_list_lock();
2691bdc44640SAndreas Färber     CPU_FOREACH(cpu) {
2692a2247f8eSAndreas Färber         if (cpu == thread_cpu) {
2693edf8e2afSMika Westerberg             continue;
2694182735efSAndreas Färber         }
2695182735efSAndreas Färber         fill_thread_info(info, (CPUArchState *)cpu->env_ptr);
2696edf8e2afSMika Westerberg     }
2697edf8e2afSMika Westerberg     cpu_list_unlock();
2698edf8e2afSMika Westerberg 
2699edf8e2afSMika Westerberg     return (0);
2700edf8e2afSMika Westerberg }
2701edf8e2afSMika Westerberg 
2702edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
2703edf8e2afSMika Westerberg {
2704edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2705edf8e2afSMika Westerberg 
270672cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
270772cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
270872cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
27097267c094SAnthony Liguori         g_free(ets);
2710edf8e2afSMika Westerberg     }
2711edf8e2afSMika Westerberg 
27127267c094SAnthony Liguori     g_free(info->prstatus);
27137267c094SAnthony Liguori     g_free(info->psinfo);
27147267c094SAnthony Liguori     g_free(info->notes);
2715edf8e2afSMika Westerberg }
2716edf8e2afSMika Westerberg 
2717edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
2718edf8e2afSMika Westerberg {
2719edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2720edf8e2afSMika Westerberg     int i, error = 0;
2721edf8e2afSMika Westerberg 
2722edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
2723edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
2724edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
2725edf8e2afSMika Westerberg             return (error);
2726edf8e2afSMika Westerberg 
2727edf8e2afSMika Westerberg     /* write prstatus for each thread */
2728edf8e2afSMika Westerberg     for (ets = info->thread_list.tqh_first; ets != NULL;
2729edf8e2afSMika Westerberg          ets = ets->ets_link.tqe_next) {
2730edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
2731edf8e2afSMika Westerberg             return (error);
2732edf8e2afSMika Westerberg     }
2733edf8e2afSMika Westerberg 
2734edf8e2afSMika Westerberg     return (0);
2735edf8e2afSMika Westerberg }
2736edf8e2afSMika Westerberg 
2737edf8e2afSMika Westerberg /*
2738edf8e2afSMika Westerberg  * Write out ELF coredump.
2739edf8e2afSMika Westerberg  *
2740edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
2741edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
2742edf8e2afSMika Westerberg  *
2743edf8e2afSMika Westerberg  * Coredump format in linux is following:
2744edf8e2afSMika Westerberg  *
2745edf8e2afSMika Westerberg  * 0   +----------------------+         \
2746edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
2747edf8e2afSMika Westerberg  *     +----------------------+          |
2748edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
2749edf8e2afSMika Westerberg  *     | - NOTE section       |          |
2750edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
2751edf8e2afSMika Westerberg  *     +----------------------+         /
2752edf8e2afSMika Westerberg  *     | NOTEs:               |
2753edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
2754edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
2755edf8e2afSMika Westerberg  *     | - NT_AUXV            |
2756edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
2757edf8e2afSMika Westerberg  *     | Process memory dump  |
2758edf8e2afSMika Westerberg  *     :                      :
2759edf8e2afSMika Westerberg  *     .                      .
2760edf8e2afSMika Westerberg  *     :                      :
2761edf8e2afSMika Westerberg  *     |                      |
2762edf8e2afSMika Westerberg  *     +----------------------+
2763edf8e2afSMika Westerberg  *
2764edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
2765edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
2766edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
2767edf8e2afSMika Westerberg  *
2768edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
2769edf8e2afSMika Westerberg  * version limitations are as follows:
2770edf8e2afSMika Westerberg  *     - no floating point registers are dumped
2771edf8e2afSMika Westerberg  *
2772edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
2773edf8e2afSMika Westerberg  *
2774edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
2775edf8e2afSMika Westerberg  * possible to force coredump from running process and then
2776edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
2777edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
2778edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
2779edf8e2afSMika Westerberg  */
27809349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
2781edf8e2afSMika Westerberg {
27820429a971SAndreas Färber     const CPUState *cpu = ENV_GET_CPU((CPUArchState *)env);
27830429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
2784edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
2785edf8e2afSMika Westerberg     char corefile[PATH_MAX];
2786edf8e2afSMika Westerberg     struct elf_note_info info;
2787edf8e2afSMika Westerberg     struct elfhdr elf;
2788edf8e2afSMika Westerberg     struct elf_phdr phdr;
2789edf8e2afSMika Westerberg     struct rlimit dumpsize;
2790edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
2791edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
2792edf8e2afSMika Westerberg     int segs = 0;
2793edf8e2afSMika Westerberg     int fd = -1;
2794edf8e2afSMika Westerberg 
27956afafa86SPeter Maydell     init_note_info(&info);
27966afafa86SPeter Maydell 
2797edf8e2afSMika Westerberg     errno = 0;
2798edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
2799edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
2800edf8e2afSMika Westerberg         return 0;
2801edf8e2afSMika Westerberg 
2802edf8e2afSMika Westerberg     if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
2803edf8e2afSMika Westerberg         return (-errno);
2804edf8e2afSMika Westerberg 
2805edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
2806edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
2807edf8e2afSMika Westerberg         return (-errno);
2808edf8e2afSMika Westerberg 
2809edf8e2afSMika Westerberg     /*
2810edf8e2afSMika Westerberg      * Walk through target process memory mappings and
2811edf8e2afSMika Westerberg      * set up structure containing this information.  After
2812edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
2813edf8e2afSMika Westerberg      */
2814edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
2815edf8e2afSMika Westerberg         goto out;
2816edf8e2afSMika Westerberg 
2817edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
2818edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
2819edf8e2afSMika Westerberg 
2820edf8e2afSMika Westerberg     /*
2821edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
2822edf8e2afSMika Westerberg      * add one more segment for notes.
2823edf8e2afSMika Westerberg      */
2824edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
2825edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
2826edf8e2afSMika Westerberg         goto out;
2827edf8e2afSMika Westerberg 
2828edf8e2afSMika Westerberg     /* fill in in-memory version of notes */
2829edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
2830edf8e2afSMika Westerberg         goto out;
2831edf8e2afSMika Westerberg 
2832edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
2833edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
2834edf8e2afSMika Westerberg 
2835edf8e2afSMika Westerberg     /* write out notes program header */
2836edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
2837edf8e2afSMika Westerberg 
2838edf8e2afSMika Westerberg     offset += info.notes_size;
2839edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
2840edf8e2afSMika Westerberg         goto out;
2841edf8e2afSMika Westerberg 
2842edf8e2afSMika Westerberg     /*
2843edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
2844edf8e2afSMika Westerberg      * we align it here.
2845edf8e2afSMika Westerberg      */
284680f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
2847edf8e2afSMika Westerberg 
2848edf8e2afSMika Westerberg     /*
2849edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
2850edf8e2afSMika Westerberg      * the target process.
2851edf8e2afSMika Westerberg      */
2852edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
2853edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
2854edf8e2afSMika Westerberg 
2855edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
2856edf8e2afSMika Westerberg         phdr.p_offset = offset;
2857edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
2858edf8e2afSMika Westerberg         phdr.p_paddr = 0;
2859edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
2860edf8e2afSMika Westerberg         offset += phdr.p_filesz;
2861edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
2862edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
2863edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
2864edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
2865edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
2866edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
2867edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
2868edf8e2afSMika Westerberg 
286980f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
2870edf8e2afSMika Westerberg         dump_write(fd, &phdr, sizeof (phdr));
2871edf8e2afSMika Westerberg     }
2872edf8e2afSMika Westerberg 
2873edf8e2afSMika Westerberg     /*
2874edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
2875edf8e2afSMika Westerberg      * alignment needed here.
2876edf8e2afSMika Westerberg      */
2877edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
2878edf8e2afSMika Westerberg         goto out;
2879edf8e2afSMika Westerberg 
2880edf8e2afSMika Westerberg     /* align data to page boundary */
2881edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
2882edf8e2afSMika Westerberg         goto out;
2883edf8e2afSMika Westerberg 
2884edf8e2afSMika Westerberg     /*
2885edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
2886edf8e2afSMika Westerberg      */
2887edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
2888edf8e2afSMika Westerberg         abi_ulong addr;
2889edf8e2afSMika Westerberg         abi_ulong end;
2890edf8e2afSMika Westerberg 
2891edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
2892edf8e2afSMika Westerberg 
2893edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
2894edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
2895edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
2896edf8e2afSMika Westerberg             int error;
2897edf8e2afSMika Westerberg 
2898edf8e2afSMika Westerberg             /*
2899edf8e2afSMika Westerberg              *  Read in page from target process memory and
2900edf8e2afSMika Westerberg              *  write it to coredump file.
2901edf8e2afSMika Westerberg              */
2902edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
2903edf8e2afSMika Westerberg             if (error != 0) {
290449995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
2905edf8e2afSMika Westerberg                                addr);
2906edf8e2afSMika Westerberg                 errno = -error;
2907edf8e2afSMika Westerberg                 goto out;
2908edf8e2afSMika Westerberg             }
2909edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
2910edf8e2afSMika Westerberg                 goto out;
2911edf8e2afSMika Westerberg         }
2912edf8e2afSMika Westerberg     }
2913edf8e2afSMika Westerberg 
2914edf8e2afSMika Westerberg  out:
2915edf8e2afSMika Westerberg     free_note_info(&info);
2916edf8e2afSMika Westerberg     if (mm != NULL)
2917edf8e2afSMika Westerberg         vma_delete(mm);
2918edf8e2afSMika Westerberg     (void) close(fd);
2919edf8e2afSMika Westerberg 
2920edf8e2afSMika Westerberg     if (errno != 0)
2921edf8e2afSMika Westerberg         return (-errno);
2922edf8e2afSMika Westerberg     return (0);
2923edf8e2afSMika Westerberg }
2924edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
2925edf8e2afSMika Westerberg 
2926e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
2927e5fe0c52Spbrook {
2928e5fe0c52Spbrook     init_thread(regs, infop);
2929e5fe0c52Spbrook }
2930